1 | #ifdef __i386__␊ |
2 | ␊ |
3 | #include "libsa.h"␊ |
4 | #include "saio_internal.h"␊ |
5 | ␊ |
6 | #ifdef DEBUG_INTERRUPTS␊ |
7 | #define DBG(x...) printf(x)␊ |
8 | #else␊ |
9 | #define DBG(x...)␊ |
10 | #endif␊ |
11 | ␊ |
12 | #define CODE_SEGMENT_SELECTOR 0x28U␊ |
13 | #define CODED_EXCEPTION_MASK 0x27D00U␊ |
14 | #define IA32_APIC_BASE 27U␊ |
15 | #define IA32_APIC_BASE_BSP 0x100U␊ |
16 | #define IA32_APIC_BASE_EN 0x800U␊ |
17 | #define LAPIC_WANTED_FLAGS (IA32_APIC_BASE_EN | IA32_APIC_BASE_BSP)␊ |
18 | #define LAPIC_EOI_OFFSET 0xB0U␊ |
19 | #define LAPIC_ISR_OFFSET 0x100U␊ |
20 | #define PIC_READ_ISR_COMMAND 11U␊ |
21 | #define PIC_EOI_COMMAND 0x20U␊ |
22 | #define PIC_PORT0 0␊ |
23 | #define PIC_PORT1 1␊ |
24 | ␊ |
25 | #define BDA_TICK_COUNT 0x46CU␉␉// DWORD␊ |
26 | #define BDA_MIDNIGHT_FLAG 0x470U␉␉// BYTE␊ |
27 | #define BDA_24HR_TURNOVER 0x1800B0U␊ |
28 | ␊ |
29 | enum InterruptSources␊ |
30 | {␊ |
31 | ␉IS_Unknown = 0,␊ |
32 | ␉IS_APIC = 1,␉// Covers both LAPIC and IOAPIC␊ |
33 | ␉IS_PIC0 = 2,␊ |
34 | ␉IS_PIC1 = 3,␊ |
35 | ␉IS_Software = 4␊ |
36 | };␊ |
37 | ␊ |
38 | struct InterruptFrame␊ |
39 | {␊ |
40 | ␉uint32_t edx;␊ |
41 | ␉uint32_t ecx;␊ |
42 | ␉uint32_t eax;␊ |
43 | ␉uint32_t index;␊ |
44 | ␉uint32_t eip;␊ |
45 | ␉uint32_t cs;␊ |
46 | ␉uint32_t eflags;␊ |
47 | };␊ |
48 | ␊ |
49 | struct ExceptionFrame␊ |
50 | {␊ |
51 | ␉uint32_t edi;␊ |
52 | ␉uint32_t esi;␊ |
53 | ␉uint32_t ebp;␊ |
54 | ␉uint32_t esp;␊ |
55 | ␉uint32_t ebx;␊ |
56 | ␉uint32_t edx;␊ |
57 | ␉uint32_t ecx;␊ |
58 | ␉uint32_t eax;␊ |
59 | ␉uint32_t index;␊ |
60 | ␉uint32_t exception_code;␊ |
61 | ␉uint32_t eip;␊ |
62 | ␉uint32_t cs;␊ |
63 | ␉uint32_t eflags;␊ |
64 | };␊ |
65 | ␊ |
66 | struct InterruptGate␊ |
67 | {␊ |
68 | ␉uint16_t offset_0_15;␊ |
69 | ␉uint16_t selector;␊ |
70 | ␉uint16_t flags;␊ |
71 | ␉uint16_t offset_16_31;␊ |
72 | };␊ |
73 | ␊ |
74 | #pragma mark -␊ |
75 | #pragma mark Global Data␊ |
76 | #pragma mark -␊ |
77 | ␊ |
78 | extern␊ |
79 | uint16_t Idtr_prot[];␊ |
80 | ␊ |
81 | static␊ |
82 | uint32_t* counters = NULL;␊ |
83 | ␊ |
84 | static␊ |
85 | uint32_t lapic_base = 0U;␊ |
86 | ␊ |
87 | static␊ |
88 | uint8_t const PicPorts[2][2] = { { 0x20U, 0x21U }, { 0xA0U, 0xA1U } };␊ |
89 | ␊ |
90 | #pragma mark -␊ |
91 | #pragma mark Assembly Stubs␊ |
92 | #pragma mark -␊ |
93 | ␊ |
94 | static␊ |
95 | __attribute__((naked, noreturn))␊ |
96 | void InterruptStub(void)␊ |
97 | {␊ |
98 | ␉__asm__ volatile ("pushl %%eax\n\t"␊ |
99 | ␉␉␉␉␉ "pushl %%ecx\n\t"␊ |
100 | ␉␉␉␉␉ "pushl %%edx\n\t"␊ |
101 | ␉␉␉␉␉ "pushl %%esp\n\t"␊ |
102 | ␉␉␉␉␉ "calll _InterruptHandler\n\t"␊ |
103 | ␉␉␉␉␉ "addl $4, %%esp\n\t"␊ |
104 | ␉␉␉␉␉ "popl %%edx\n\t"␊ |
105 | ␉␉␉␉␉ "popl %%ecx\n\t"␊ |
106 | ␉␉␉␉␉ "popl %%eax\n\t"␊ |
107 | ␉␉␉␉␉ "addl $4, %%esp\n\t"␊ |
108 | ␉␉␉␉␉ "iretl"␊ |
109 | ␉␉␉␉␉ :);␊ |
110 | }␊ |
111 | ␊ |
112 | static␊ |
113 | __attribute__((naked, noreturn))␊ |
114 | void ExceptionWithCodeStub(void)␊ |
115 | {␊ |
116 | ␉__asm__ volatile("testl $-57, 8(%%esp)\n\t"␊ |
117 | ␉␉␉␉␉ "je 0f\n\t"␊ |
118 | ␉␉␉␉␉ "pushal\n\t"␊ |
119 | ␉␉␉␉␉ "jmp 1f\n"␊ |
120 | ␉␉␉␉␉ "_ExceptionNoCodeStub:\n"␊ |
121 | ␉␉␉␉␉ "0:\tsub $4, %%esp\n\t"␊ |
122 | ␉␉␉␉␉ "pushal\n\t"␊ |
123 | ␉␉␉␉␉ "xorl %%eax, %%eax\n\t"␊ |
124 | ␉␉␉␉␉ "xchgl %%eax, 36(%%esp)\n\t"␊ |
125 | ␉␉␉␉␉ "movl %%eax, 32(%%esp)\n"␊ |
126 | ␉␉␉␉␉ "1:\taddl $20, 12(%%esp)\n\t"␊ |
127 | ␉␉␉␉␉ "pushl %%esp\n\t"␊ |
128 | ␉␉␉␉␉ "calll _ExceptionHandler\n\t"␊ |
129 | ␉␉␉␉␉ "addl $4, %%esp\n\t"␊ |
130 | ␉␉␉␉␉ "popal\n\t"␊ |
131 | ␉␉␉␉␉ "addl $8, %%esp\n\t"␊ |
132 | ␉␉␉␉␉ "iretl"␊ |
133 | ␉␉␉␉␉ :);␊ |
134 | }␊ |
135 | ␊ |
136 | /*␊ |
137 | * Make _ExceptionNoCodeStub accessible to C␊ |
138 | */␊ |
139 | static␊ |
140 | __attribute__((naked, noreturn, weakref("ExceptionNoCodeStub")))␊ |
141 | void ExceptionNoCodeStubAlias(void);␊ |
142 | ␊ |
143 | static␊ |
144 | __attribute__((/* naked, */noinline, regparm(1), section("__INIT,__text")))␊ |
145 | void DispatchBiosVector(uint8_t vector)␊ |
146 | {␊ |
147 | ␉__asm__ volatile ("movb %0, 0f + 1\n\t"␊ |
148 | ␉␉␉␉␉ "calll __prot_to_real\n\t"␊ |
149 | ␉␉␉␉␉ ".code16\n"␊ |
150 | ␉␉␉␉␉ "0:\tint $0\n\t"␊ |
151 | ␉␉␉␉␉ "calll __real_to_prot\n\t"␊ |
152 | ␉␉␉␉␉ ".code32"␊ |
153 | ␉␉␉␉␉ : : "r"(vector));␊ |
154 | }␊ |
155 | ␊ |
156 | static␊ |
157 | __attribute__((noreturn, noinline, section("__INIT,__text")))␊ |
158 | void DisplayErrorAndStop(void)␊ |
159 | {␊ |
160 | ␉__asm__ volatile ("calll __prot_to_real\n\t"␊ |
161 | ␉␉␉␉␉ ".code16\n\t"␊ |
162 | ␉␉␉␉␉ "movw $2, %%ax\n\t"␊ |
163 | ␉␉␉␉␉ "int $0x10\n\t"␊ |
164 | ␉␉␉␉␉ "xorw %%ax, %%ax\n\t"␊ |
165 | ␉␉␉␉␉ "movw %%ax, %%ds\n\t"␊ |
166 | ␉␉␉␉␉ "movw $0x6000, %%si\n\t"␊ |
167 | ␉␉␉␉␉ "cld\n"␊ |
168 | ␉␉␉␉␉ "0:\tlodsb\n\t"␊ |
169 | ␉␉␉␉␉ "testb %%al, %%al\n\t"␊ |
170 | ␉␉␉␉␉ "je 1f\n\t"␊ |
171 | ␉␉␉␉␉ "movb $0xE, %%ah\n\t"␊ |
172 | ␉␉␉␉␉ "movw $0xFF, %%bx\n\t"␊ |
173 | ␉␉␉␉␉ "int $0x10\n\t"␊ |
174 | ␉␉␉␉␉ "jmp 0b\n"␊ |
175 | ␉␉␉␉␉ "1:\thlt\n\t"␊ |
176 | ␉␉␉␉␉ "jmp 1b\n\t"␊ |
177 | ␉␉␉␉␉ ".code32"␊ |
178 | ␉␉␉␉␉ :);␊ |
179 | ␉__builtin_unreachable();␊ |
180 | }␊ |
181 | ␊ |
182 | #pragma mark -␊ |
183 | #pragma mark Other Inline Assembly␊ |
184 | #pragma mark -␊ |
185 | ␊ |
186 | static inline␊ |
187 | uint32_t ReadLapic(uint32_t offset)␊ |
188 | {␊ |
189 | ␉return *(uint32_t const volatile*) (lapic_base + offset);␊ |
190 | }␊ |
191 | ␊ |
192 | static inline␊ |
193 | void WriteLapic(uint32_t offset, uint32_t value)␊ |
194 | {␊ |
195 | ␉*(uint32_t volatile*) (lapic_base + offset) = value;␊ |
196 | }␊ |
197 | ␊ |
198 | static inline␊ |
199 | uint8_t ReadPic(int pic, int index)␊ |
200 | {␊ |
201 | ␉uint8_t value;␊ |
202 | ␉__asm__ volatile ("inb %1, %0" : "=a"(value) : "N"(PicPorts[pic][index]));␊ |
203 | ␉return value;␊ |
204 | }␊ |
205 | ␊ |
206 | static inline␊ |
207 | void WritePic(int pic, int index, uint8_t value)␊ |
208 | {␊ |
209 | ␉__asm__ volatile ("outb %0, %1" : : "a"(value), "N"(PicPorts[pic][index]));␊ |
210 | }␊ |
211 | ␊ |
212 | #pragma mark -␊ |
213 | #pragma mark Main Code␊ |
214 | #pragma mark -␊ |
215 | ␊ |
216 | static␊ |
217 | int IdentifyInterruptSource(uint8_t vector, uint32_t eip)␊ |
218 | {␊ |
219 | ␉if (lapic_base)␊ |
220 | ␉{␊ |
221 | ␉␉uint32_t value = ReadLapic(LAPIC_ISR_OFFSET + ((vector & 0xE0U) >> 1));␊ |
222 | ␉␉if (value & (1U << (vector & 31U)))␊ |
223 | ␉␉␉return IS_APIC;␊ |
224 | ␉}␊ |
225 | ␉if (vector >= 8U && vector < 16U)␊ |
226 | ␉{␊ |
227 | ␉␉uint8_t value;␊ |
228 | ␉␉WritePic(0, PIC_PORT0, PIC_READ_ISR_COMMAND);␊ |
229 | ␉␉value = ReadPic(0, PIC_PORT0);␊ |
230 | ␉␉if (value & (1U << (vector & 7U)))␊ |
231 | ␉␉␉return IS_PIC0;␊ |
232 | ␉}␊ |
233 | ␉if (vector >= 0x70U && vector < 0x78U)␊ |
234 | ␉{␊ |
235 | ␉␉uint8_t value;␊ |
236 | ␉␉WritePic(1, PIC_PORT0, PIC_READ_ISR_COMMAND);␊ |
237 | ␉␉value = ReadPic(1, PIC_PORT0);␊ |
238 | ␉␉if (value & (1U << (vector & 7U)))␊ |
239 | ␉␉␉return IS_PIC1;␊ |
240 | ␉}␊ |
241 | ␉if (eip)␊ |
242 | ␉{␊ |
243 | ␉␉uint8_t const volatile* pInstruction = (uint8_t const volatile*) (eip - 2U);␊ |
244 | ␉␉if ((*pInstruction) == 0xCDU && pInstruction[1] == vector)␊ |
245 | ␉␉␉return IS_Software;␊ |
246 | ␉␉/*␊ |
247 | ␉␉ * There are other software interrupt opcodes␊ |
248 | ␉␉ * debug breakpoint 0xCC␊ |
249 | ␉␉ * interrupt on overflow 0xCE␊ |
250 | ␉␉ * bound instruction 0x62␊ |
251 | ␉␉ * but those all trigger specific vectors, so are handled as exceptions.␊ |
252 | ␉␉ */␊ |
253 | ␉}␊ |
254 | ␉return IS_Unknown;␊ |
255 | }␊ |
256 | ␊ |
257 | static␊ |
258 | void SignalEOI(int source)␊ |
259 | {␊ |
260 | ␉switch (source)␊ |
261 | ␉{␊ |
262 | ␉␉case IS_APIC:␊ |
263 | ␉␉␉if (lapic_base)␊ |
264 | ␉␉␉␉WriteLapic(LAPIC_EOI_OFFSET, 0U);␊ |
265 | ␉␉␉break;␊ |
266 | ␉␉case IS_PIC1:␊ |
267 | ␉␉␉WritePic(1, PIC_PORT0, PIC_EOI_COMMAND);␊ |
268 | ␉␉case IS_PIC0:␊ |
269 | ␉␉␉WritePic(0, PIC_PORT0, PIC_EOI_COMMAND);␊ |
270 | ␉␉default:␊ |
271 | ␉␉␉break;␊ |
272 | ␉}␊ |
273 | }␊ |
274 | ␊ |
275 | static␊ |
276 | void HandleIRQ(int source, uint8_t vector)␊ |
277 | {␊ |
278 | ␉if (source == IS_PIC0 && vector == 8U)␊ |
279 | ␉{␊ |
280 | ␉␉uint32_t* pTickCount = (uint32_t*) BDA_TICK_COUNT;␊ |
281 | ␉␉if (++(*pTickCount) == BDA_24HR_TURNOVER)␊ |
282 | ␉␉{␊ |
283 | ␉␉␉*pTickCount = 0U;␊ |
284 | ␉␉␉++(*(uint8_t*)BDA_MIDNIGHT_FLAG);␊ |
285 | ␉␉}␊ |
286 | ␉␉SignalEOI(source);␊ |
287 | ␉␉return;␊ |
288 | ␉}␊ |
289 | ␉/*␊ |
290 | ␉ * Default Approach: send to bios␊ |
291 | ␉ */␊ |
292 | ␉DispatchBiosVector(vector);␊ |
293 | }␊ |
294 | ␊ |
295 | static␊ |
296 | __attribute__((used))␊ |
297 | void ExceptionHandler(struct ExceptionFrame* pFrame)␊ |
298 | {␊ |
299 | ␉uint8_t vector;␊ |
300 | ␉int interruptSource;␊ |
301 | ␉char* errorString;␊ |
302 | ␊ |
303 | ␉/*␊ |
304 | ␉ * FIXME: Should check if 0x10000U <= ESP <= 0x1FFFF0 here and switch stacks if not.␊ |
305 | ␉ */␊ |
306 | ␉if (!pFrame)␊ |
307 | ␉{␊ |
308 | ␉␉return;␊ |
309 | ␉}␊ |
310 | ␉vector = (uint8_t) pFrame->index;␊ |
311 | ␉if (counters)␊ |
312 | ␉␉++counters[vector];␊ |
313 | ␉interruptSource = IdentifyInterruptSource(vector, pFrame->eip);␊ |
314 | ␉switch (interruptSource)␊ |
315 | ␉{␊ |
316 | ␉␉case IS_APIC:␊ |
317 | ␉␉case IS_PIC0:␊ |
318 | ␉␉case IS_PIC1:␊ |
319 | ␉␉␉HandleIRQ(interruptSource, vector);␊ |
320 | ␉␉case IS_Software:␊ |
321 | ␉␉␉return;␊ |
322 | ␉␉default:␊ |
323 | ␉␉␉break;␊ |
324 | ␉}␊ |
325 | ␉errorString = (char*) 0x6000U;␊ |
326 | ␉switch (vector)␊ |
327 | ␉{␊ |
328 | ␉␉case 0U:␊ |
329 | ␉␉␉strcpy(errorString, "Division By Zero Exception");␊ |
330 | ␉␉␉break;␊ |
331 | ␉␉case 1U:␊ |
332 | ␉␉␉strcpy(errorString, "Debug Exception");␊ |
333 | ␉␉␉break;␊ |
334 | ␉␉case 2U:␊ |
335 | ␉␉␉strcpy(errorString, "NMI Interrupt");␊ |
336 | ␉␉␉break;␊ |
337 | ␉␉case 3U:␊ |
338 | ␉␉␉strcpy(errorString, "Debug Breakpoint");␊ |
339 | ␉␉␉break;␊ |
340 | ␉␉case 4U:␊ |
341 | ␉␉␉strcpy(errorString, "Overflow Exception");␊ |
342 | ␉␉␉break;␊ |
343 | ␉␉case 5U:␊ |
344 | ␉␉␉strcpy(errorString, "BOUND Range Exception");␊ |
345 | ␉␉␉break;␊ |
346 | ␉␉case 6U:␊ |
347 | ␉␉␉strcpy(errorString, "Invalid Opcode Exception");␊ |
348 | ␉␉␉break;␊ |
349 | ␉␉case 7U:␊ |
350 | ␉␉␉strcpy(errorString, "Math Coprocessor Unavailable Exception");␊ |
351 | ␉␉␉break;␊ |
352 | ␉␉case 8U:␊ |
353 | ␉␉␉strcpy(errorString, "Double Fault");␊ |
354 | ␉␉␉break;␊ |
355 | ␉␉case 9U:␊ |
356 | ␉␉␉strcpy(errorString, "Coprocessor Segment Overrun Exception");␊ |
357 | ␉␉␉break;␊ |
358 | ␉␉case 10U:␊ |
359 | ␉␉␉strcpy(errorString, "Invalid TSS Exception");␊ |
360 | ␉␉␉break;␊ |
361 | ␉␉case 11U:␊ |
362 | ␉␉␉strcpy(errorString, "Segment Not Present Exception");␊ |
363 | ␉␉␉break;␊ |
364 | ␉␉case 12U:␊ |
365 | ␉␉␉strcpy(errorString, "Stack-Segment Fault");␊ |
366 | ␉␉␉break;␊ |
367 | ␉␉case 13U:␊ |
368 | ␉␉␉strcpy(errorString, "General Protection Fault");␊ |
369 | ␉␉␉break;␊ |
370 | ␉␉case 14U:␊ |
371 | ␉␉␉strcpy(errorString, "Page Fault");␊ |
372 | ␉␉␉break;␊ |
373 | ␉␉case 16U:␊ |
374 | ␉␉␉strcpy(errorString, "x87 FPU Floating-Point Error");␊ |
375 | ␉␉␉break;␊ |
376 | ␉␉case 17U:␊ |
377 | ␉␉␉strcpy(errorString, "Alignment Check Exception");␊ |
378 | ␉␉␉break;␊ |
379 | ␉␉case 18U:␊ |
380 | ␉␉␉strcpy(errorString, "Machine Check Exception");␊ |
381 | ␉␉␉break;␊ |
382 | ␉␉case 19U:␊ |
383 | ␉␉␉strcpy(errorString, "SIMD Floating-Point Exception");␊ |
384 | ␉␉␉break;␊ |
385 | ␉␉case 20U:␊ |
386 | ␉␉␉strcpy(errorString, "Virtualization Exception");␊ |
387 | ␉␉␉break;␊ |
388 | ␉␉default:␊ |
389 | ␉␉␉sprintf(errorString, "Unknown Exception Vector %d", (int) vector);␊ |
390 | ␉␉␉break;␊ |
391 | ␉}␊ |
392 | ␉errorString += strlen(errorString);␊ |
393 | ␊ |
394 | ␉errorString += sprintf(errorString, "\r\nEDI 0x%x, ESI 0x%x, EBP 0x%x, ESP 0x%x",␊ |
395 | ␉␉␉␉␉␉ pFrame->edi, pFrame->esi, pFrame->ebp, pFrame->esp);␊ |
396 | ␉errorString += sprintf(errorString, "\r\nEBX 0x%x, EDX 0x%x, ECX 0x%x, EAX 0x%x",␊ |
397 | ␉␉␉␉␉␉ pFrame->ebx, pFrame->edx, pFrame->ecx, pFrame->eax);␊ |
398 | ␉errorString += sprintf(errorString, "\r\nException Code 0x%x, EIP 0x%x, CS 0x%x, EFLAGS 0x%x\r\nSystem Halted\r\n",␊ |
399 | ␉␉␉␉␉␉ pFrame->exception_code, pFrame->eip, pFrame->cs, pFrame->eflags);␊ |
400 | ␉DisplayErrorAndStop();␊ |
401 | }␊ |
402 | ␊ |
403 | static␊ |
404 | __attribute__((used))␊ |
405 | void InterruptHandler(struct InterruptFrame* pFrame)␊ |
406 | {␊ |
407 | ␉uint8_t vector;␊ |
408 | ␉int interruptSource;␊ |
409 | ␊ |
410 | ␉if (!pFrame)␊ |
411 | ␉{␊ |
412 | ␉␉return;␊ |
413 | ␉}␊ |
414 | ␉vector = (uint8_t) pFrame->index;␊ |
415 | ␉if (counters)␊ |
416 | ␉␉++counters[vector];␊ |
417 | ␉interruptSource = IdentifyInterruptSource(vector, pFrame->eip);␊ |
418 | ␉switch (interruptSource)␊ |
419 | ␉{␊ |
420 | ␉␉case IS_APIC:␊ |
421 | ␉␉case IS_PIC0:␊ |
422 | ␉␉case IS_PIC1:␊ |
423 | ␉␉␉HandleIRQ(interruptSource, vector);␊ |
424 | ␉␉default:␊ |
425 | ␉␉␉break;␊ |
426 | ␉}␊ |
427 | }␊ |
428 | ␊ |
429 | #if UNUSED␊ |
430 | void dumpMasks(void)␊ |
431 | {␊ |
432 | ␉int idx;␊ |
433 | ␉uint8_t port_val;␊ |
434 | ␉uint8_t volatile* apic_index;␊ |
435 | ␉uint32_t const volatile* apic_data;␊ |
436 | ␊ |
437 | ␉port_val = ReadPic(0, 1);␊ |
438 | ␉DBG("pic0 Masks 0x%x\n", port_val);␊ |
439 | ␉port_val = ReadPic(1, 1);␊ |
440 | ␉DBG("pic1 Masks 0x%x\n", port_val);␊ |
441 | ␉getchar();␊ |
442 | ␉DBG("IOAPIC vectors\n");␊ |
443 | ␉apic_index = (uint8_t volatile*) 0xFEC00000U;␊ |
444 | ␉apic_data = (uint32_t const volatile*) 0xFEC00010U;␊ |
445 | ␉for (idx = 0; idx != 24; ++idx)␊ |
446 | ␉{␊ |
447 | ␉␉uint32_t v1, v2;␊ |
448 | ␉␉*apic_index = (uint8_t) (16U + 2U * (unsigned) idx);␊ |
449 | ␉␉v1 = *apic_data;␊ |
450 | ␉␉if (v1 & 0x10000U)␊ |
451 | ␉␉␉continue;␊ |
452 | ␉␉*apic_index = (uint8_t) (16U + 2U * (unsigned) idx + 1U);␊ |
453 | ␉␉v2 = *apic_data;␊ |
454 | ␉␉DBG("index %d vector 0x%x%08x\n", idx, v2, v1);␊ |
455 | ␉}␊ |
456 | ␉getchar();␊ |
457 | ␉if (!lapic_base)␊ |
458 | ␉␉return;␊ |
459 | ␉DBG("LAPIC vectors\n");␊ |
460 | ␉for (idx = 0; idx != 7; ++idx)␊ |
461 | ␉{␊ |
462 | ␉␉uint32_t offs, v;␊ |
463 | ␉␉if (!idx)␊ |
464 | ␉␉␉offs = 0x2F0U;␊ |
465 | ␉␉else␊ |
466 | ␉␉␉offs = 0x320U + 16U * (unsigned) (idx - 1);␊ |
467 | ␉␉v = ReadLapic(offs);␊ |
468 | ␉␉if (v & 0x10000U)␊ |
469 | ␉␉␉continue;␊ |
470 | ␉␉DBG("index %d vector 0x%x\n", idx, v);␊ |
471 | ␉}␊ |
472 | }␊ |
473 | #endif␊ |
474 | ␊ |
475 | void ShowInterruptCounters(void)␊ |
476 | {␊ |
477 | ␉int j;␊ |
478 | ␊ |
479 | ␉if (!counters)␊ |
480 | ␉␉return;␊ |
481 | ␉msglog("Interrupt Counters\n");␊ |
482 | ␉for (j = 0; j != 256; ++j)␊ |
483 | ␉␉if (counters[j])␊ |
484 | ␉␉␉msglog("counters[%d] == %d\n", j, counters[j]);␊ |
485 | }␊ |
486 | ␊ |
487 | int SetupInterrupts(void)␊ |
488 | {␊ |
489 | ␉int idx;␊ |
490 | ␉uint32_t stub_address;␊ |
491 | ␉uint64_t ia32_apic_base;␊ |
492 | ␉size_t const total = 2048U + 2048U + 1024U;␊ |
493 | ␉uint8_t* workArea = (uint8_t*) malloc(total);␊ |
494 | ␉if (!workArea)␊ |
495 | ␉{␊ |
496 | ␉␉msglog("%s: Memory Allocation Failed\n", __FUNCTION__);␊ |
497 | ␉␉return 0;␊ |
498 | ␉}␊ |
499 | ␉counters = (uint32_t*) (workArea + 4096);␊ |
500 | ␉bzero(counters, 1024U);␊ |
501 | ␉for (idx = 0; idx != 256; ++idx)␊ |
502 | ␉{␊ |
503 | ␉␉struct InterruptGate* gate = (struct InterruptGate*) (workArea + idx * sizeof(struct InterruptGate));␊ |
504 | ␉␉uint8_t* thunk = workArea + 2048 + idx * 8;␊ |
505 | ␉␉gate->offset_0_15 = ((uint32_t) thunk) & 0xFFFFU;␊ |
506 | ␉␉gate->selector = CODE_SEGMENT_SELECTOR;␊ |
507 | ␉␉gate->flags = 0x8E00U; // Interrupt Gate, Present, DPL 0, 32-bit␊ |
508 | ␉␉gate->offset_16_31 = (((uint32_t) thunk) >> 16) & 0xFFFFU;␊ |
509 | ␉␉thunk[0] = 0x6AU;␉// push byte␊ |
510 | ␉␉thunk[1] = (uint8_t) idx;␊ |
511 | ␉␉thunk[2] = 0xE9U;␉// jmp rel32␊ |
512 | ␉␉if (idx >= 32)␊ |
513 | ␉␉␉stub_address = (uint32_t) &InterruptStub;␊ |
514 | ␉␉else if ((1U << idx) & CODED_EXCEPTION_MASK)␊ |
515 | ␉␉␉stub_address = (uint32_t) &ExceptionWithCodeStub;␊ |
516 | ␉␉else␊ |
517 | ␉␉␉stub_address = (uint32_t) &ExceptionNoCodeStubAlias;␊ |
518 | ␉␉*(uint32_t*) (&thunk[3]) = stub_address - (uint32_t) &thunk[7];␊ |
519 | ␉␉thunk[7] = 0x90U;␉// nop␊ |
520 | ␉}␊ |
521 | ␉Idtr_prot[0] = 0x7FFU;␊ |
522 | ␉Idtr_prot[1] = ((uint32_t) workArea) & 0xFFFFU;␊ |
523 | ␉Idtr_prot[2] = (((uint32_t) workArea) >> 16) & 0xFFFFU;␊ |
524 | ␉__asm__ volatile ("lidt %0" : : "m"(Idtr_prot[0]));␊ |
525 | ␉__asm__ volatile ("rdmsr" : "=A"(ia32_apic_base) : "c"((uint32_t) IA32_APIC_BASE));␊ |
526 | ␉if ((ia32_apic_base & LAPIC_WANTED_FLAGS) == LAPIC_WANTED_FLAGS &&␊ |
527 | ␉␉!((ia32_apic_base >> 32) & 255U))␊ |
528 | ␉␉lapic_base = ((uint32_t) ia32_apic_base) & ~0xFFFU;␊ |
529 | ␉DBG("%s: Work Area 0x%x, lapic_base 0x%x\n", __FUNCTION__, (uint32_t) workArea, lapic_base);␊ |
530 | ␉return 1;␊ |
531 | }␊ |
532 | #endif␊ |
533 | |