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