Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Enoch/i386/libsa/interrupts.c

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
87static
88uint8_t const PicPorts[2][2] = { { 0x20U, 0x21U }, { 0xA0U, 0xA1U } };
89
90#pragma mark -
91#pragma mark Assembly Stubs
92#pragma mark -
93
94static
95__attribute__((naked, noreturn))
96void 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
112static
113__attribute__((naked, noreturn))
114void 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 */
139static
140__attribute__((naked, noreturn, weakref("ExceptionNoCodeStub")))
141void ExceptionNoCodeStubAlias(void);
142
143static
144__attribute__((/* naked, */noinline, regparm(1), section("__INIT,__text")))
145void 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
156static
157__attribute__((noreturn, noinline, section("__INIT,__text")))
158void 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
186static inline
187uint32_t ReadLapic(uint32_t offset)
188{
189return *(uint32_t const volatile*) (lapic_base + offset);
190}
191
192static inline
193void WriteLapic(uint32_t offset, uint32_t value)
194{
195*(uint32_t volatile*) (lapic_base + offset) = value;
196}
197
198static inline
199uint8_t ReadPic(int pic, int index)
200{
201uint8_t value;
202__asm__ volatile ("inb %1, %0" : "=a"(value) : "N"(PicPorts[pic][index]));
203return value;
204}
205
206static inline
207void 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
216static
217int IdentifyInterruptSource(uint8_t vector, uint32_t eip)
218{
219if (lapic_base)
220{
221uint32_t value = ReadLapic(LAPIC_ISR_OFFSET + ((vector & 0xE0U) >> 1));
222if (value & (1U << (vector & 31U)))
223return IS_APIC;
224}
225if (vector >= 8U && vector < 16U)
226{
227uint8_t value;
228WritePic(0, PIC_PORT0, PIC_READ_ISR_COMMAND);
229value = ReadPic(0, PIC_PORT0);
230if (value & (1U << (vector & 7U)))
231return IS_PIC0;
232}
233if (vector >= 0x70U && vector < 0x78U)
234{
235uint8_t value;
236WritePic(1, PIC_PORT0, PIC_READ_ISR_COMMAND);
237value = ReadPic(1, PIC_PORT0);
238if (value & (1U << (vector & 7U)))
239return IS_PIC1;
240}
241if (eip)
242{
243uint8_t const volatile* pInstruction = (uint8_t const volatile*) (eip - 2U);
244if ((*pInstruction) == 0xCDU && pInstruction[1] == vector)
245return 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}
254return IS_Unknown;
255}
256
257static
258void SignalEOI(int source)
259{
260switch (source)
261{
262case IS_APIC:
263if (lapic_base)
264WriteLapic(LAPIC_EOI_OFFSET, 0U);
265break;
266case IS_PIC1:
267WritePic(1, PIC_PORT0, PIC_EOI_COMMAND);
268case IS_PIC0:
269WritePic(0, PIC_PORT0, PIC_EOI_COMMAND);
270default:
271break;
272}
273}
274
275static
276void HandleIRQ(int source, uint8_t vector)
277{
278if (source == IS_PIC0 && vector == 8U)
279{
280uint32_t* pTickCount = (uint32_t*) BDA_TICK_COUNT;
281if (++(*pTickCount) == BDA_24HR_TURNOVER)
282{
283*pTickCount = 0U;
284++(*(uint8_t*)BDA_MIDNIGHT_FLAG);
285}
286SignalEOI(source);
287return;
288}
289/*
290 * Default Approach: send to bios
291 */
292DispatchBiosVector(vector);
293}
294
295static
296__attribute__((used))
297void ExceptionHandler(struct ExceptionFrame* pFrame)
298{
299uint8_t vector;
300int interruptSource;
301char* errorString;
302
303/*
304 * FIXME: Should check if 0x10000U <= ESP <= 0x1FFFF0 here and switch stacks if not.
305 */
306if (!pFrame)
307{
308return;
309}
310vector = (uint8_t) pFrame->index;
311if (counters)
312++counters[vector];
313interruptSource = IdentifyInterruptSource(vector, pFrame->eip);
314switch (interruptSource)
315{
316case IS_APIC:
317case IS_PIC0:
318case IS_PIC1:
319HandleIRQ(interruptSource, vector);
320case IS_Software:
321return;
322default:
323break;
324}
325errorString = (char*) 0x6000U;
326switch (vector)
327{
328case 0U:
329strcpy(errorString, "Division By Zero Exception");
330break;
331case 1U:
332strcpy(errorString, "Debug Exception");
333break;
334case 2U:
335strcpy(errorString, "NMI Interrupt");
336break;
337case 3U:
338strcpy(errorString, "Debug Breakpoint");
339break;
340case 4U:
341strcpy(errorString, "Overflow Exception");
342break;
343case 5U:
344strcpy(errorString, "BOUND Range Exception");
345break;
346case 6U:
347strcpy(errorString, "Invalid Opcode Exception");
348break;
349case 7U:
350strcpy(errorString, "Math Coprocessor Unavailable Exception");
351break;
352case 8U:
353strcpy(errorString, "Double Fault");
354break;
355case 9U:
356strcpy(errorString, "Coprocessor Segment Overrun Exception");
357break;
358case 10U:
359strcpy(errorString, "Invalid TSS Exception");
360break;
361case 11U:
362strcpy(errorString, "Segment Not Present Exception");
363break;
364case 12U:
365strcpy(errorString, "Stack-Segment Fault");
366break;
367case 13U:
368strcpy(errorString, "General Protection Fault");
369break;
370case 14U:
371strcpy(errorString, "Page Fault");
372break;
373case 16U:
374strcpy(errorString, "x87 FPU Floating-Point Error");
375break;
376case 17U:
377strcpy(errorString, "Alignment Check Exception");
378break;
379case 18U:
380strcpy(errorString, "Machine Check Exception");
381break;
382case 19U:
383strcpy(errorString, "SIMD Floating-Point Exception");
384break;
385case 20U:
386strcpy(errorString, "Virtualization Exception");
387break;
388default:
389sprintf(errorString, "Unknown Exception Vector %d", (int) vector);
390break;
391}
392errorString += strlen(errorString);
393
394errorString += sprintf(errorString, "\r\nEDI 0x%x, ESI 0x%x, EBP 0x%x, ESP 0x%x",
395 pFrame->edi, pFrame->esi, pFrame->ebp, pFrame->esp);
396errorString += sprintf(errorString, "\r\nEBX 0x%x, EDX 0x%x, ECX 0x%x, EAX 0x%x",
397 pFrame->ebx, pFrame->edx, pFrame->ecx, pFrame->eax);
398errorString += 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);
400DisplayErrorAndStop();
401}
402
403static
404__attribute__((used))
405void InterruptHandler(struct InterruptFrame* pFrame)
406{
407uint8_t vector;
408int interruptSource;
409
410if (!pFrame)
411{
412return;
413}
414vector = (uint8_t) pFrame->index;
415if (counters)
416++counters[vector];
417interruptSource = IdentifyInterruptSource(vector, pFrame->eip);
418switch (interruptSource)
419{
420case IS_APIC:
421case IS_PIC0:
422case IS_PIC1:
423HandleIRQ(interruptSource, vector);
424default:
425break;
426}
427}
428
429#if UNUSED
430void dumpMasks(void)
431{
432int idx;
433uint8_t port_val;
434uint8_t volatile* apic_index;
435uint32_t const volatile* apic_data;
436
437port_val = ReadPic(0, 1);
438DBG("pic0 Masks 0x%x\n", port_val);
439port_val = ReadPic(1, 1);
440DBG("pic1 Masks 0x%x\n", port_val);
441getchar();
442DBG("IOAPIC vectors\n");
443apic_index = (uint8_t volatile*) 0xFEC00000U;
444apic_data = (uint32_t const volatile*) 0xFEC00010U;
445for (idx = 0; idx != 24; ++idx)
446{
447uint32_t v1, v2;
448*apic_index = (uint8_t) (16U + 2U * (unsigned) idx);
449v1 = *apic_data;
450if (v1 & 0x10000U)
451continue;
452*apic_index = (uint8_t) (16U + 2U * (unsigned) idx + 1U);
453v2 = *apic_data;
454DBG("index %d vector 0x%x%08x\n", idx, v2, v1);
455}
456getchar();
457if (!lapic_base)
458return;
459DBG("LAPIC vectors\n");
460for (idx = 0; idx != 7; ++idx)
461{
462uint32_t offs, v;
463if (!idx)
464offs = 0x2F0U;
465else
466offs = 0x320U + 16U * (unsigned) (idx - 1);
467v = ReadLapic(offs);
468if (v & 0x10000U)
469continue;
470DBG("index %d vector 0x%x\n", idx, v);
471}
472}
473#endif
474
475void ShowInterruptCounters(void)
476{
477int j;
478
479if (!counters)
480return;
481msglog("Interrupt Counters\n");
482for (j = 0; j != 256; ++j)
483if (counters[j])
484msglog("counters[%d] == %d\n", j, counters[j]);
485}
486
487int SetupInterrupts(void)
488{
489int idx;
490uint32_t stub_address;
491uint64_t ia32_apic_base;
492size_t const total = 2048U + 2048U + 1024U;
493uint8_t* workArea = (uint8_t*) malloc(total);
494if (!workArea)
495{
496msglog("%s: Memory Allocation Failed\n", __FUNCTION__);
497return 0;
498}
499counters = (uint32_t*) (workArea + 4096);
500bzero(counters, 1024U);
501for (idx = 0; idx != 256; ++idx)
502{
503struct InterruptGate* gate = (struct InterruptGate*) (workArea + idx * sizeof(struct InterruptGate));
504uint8_t* thunk = workArea + 2048 + idx * 8;
505gate->offset_0_15 = ((uint32_t) thunk) & 0xFFFFU;
506gate->selector = CODE_SEGMENT_SELECTOR;
507gate->flags = 0x8E00U; // Interrupt Gate, Present, DPL 0, 32-bit
508gate->offset_16_31 = (((uint32_t) thunk) >> 16) & 0xFFFFU;
509thunk[0] = 0x6AU;// push byte
510thunk[1] = (uint8_t) idx;
511thunk[2] = 0xE9U;// jmp rel32
512if (idx >= 32)
513stub_address = (uint32_t) &InterruptStub;
514else if ((1U << idx) & CODED_EXCEPTION_MASK)
515stub_address = (uint32_t) &ExceptionWithCodeStub;
516else
517stub_address = (uint32_t) &ExceptionNoCodeStubAlias;
518*(uint32_t*) (&thunk[3]) = stub_address - (uint32_t) &thunk[7];
519thunk[7] = 0x90U;// nop
520}
521Idtr_prot[0] = 0x7FFU;
522Idtr_prot[1] = ((uint32_t) workArea) & 0xFFFFU;
523Idtr_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));
526if ((ia32_apic_base & LAPIC_WANTED_FLAGS) == LAPIC_WANTED_FLAGS &&
527!((ia32_apic_base >> 32) & 255U))
528lapic_base = ((uint32_t) ia32_apic_base) & ~0xFFFU;
529DBG("%s: Work Area 0x%x, lapic_base 0x%x\n", __FUNCTION__, (uint32_t) workArea, lapic_base);
530return 1;
531}
532#endif
533

Archive Download this file

Revision: 2585