Chameleon

Chameleon Svn Source Tree

Root/tags/2.3/i386/libsa/interrupts.c

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

Archive Download this file

Revision: 2862