19 uint16_t handler_high;
20 uint32_t handler_highest;
22 } __attribute__((packed));
25 void set_idt_entry(struct idt_entry *entry, uintptr_t handler, uint16_t selector,
26 uint8_t flags, uint8_t ist);
27 void load_idt(struct idt_entry *table, size_t length);
29 #define NUM_KNOWN_EXCEPTIONS 20
31 const char *exception_names[] = {
32 "Divide by zero", /* 0, 0x0 */
34 "Non maskable interrupt", /* 2, 0x2 */
35 "Breakpoint", /* 3, 0x3 */
36 "Into detected overflow", /* 4, 0x4 */
37 "Out of bounds", /* 5, 0x5 */
38 "Invalid opcode", /* 6, 0x6 */
39 "No coprocessor", /* 7, 0x7 */
40 "Double fault", /* 8, 0x8 */
41 "Coprocessor segment overrun", /* 9, 0x9 */
42 "Bad TSS", /* 10, 0xA */
43 "Segment not present", /* 11, 0xB */
44 "Stack fault", /* 12, 0xC */
45 "General protection fault", /* 13, 0xD */
46 "Page fault", /* 14, 0xE */
47 "Unknown interrupt", /* 15, 0xF */
48 "Coprocessor fault", /* 16, 0x10 */
49 "Alignment check", /* 17, 0x11 */
50 "Machine check", /* 18, 0x12 */
51 "SIMD Floating-Point", /* 19, 0x13 */
54 #define NUM_INTERRUPTS 256
56 static struct idt_entry interrupt_table[NUM_INTERRUPTS];
57 static struct interrupt_handler *handlers[NUM_INTERRUPTS];
59 /* index is the interrupt number */
60 void interrupt_add_handler(unsigned int index, struct interrupt_handler *handler) {
61 struct interrupt_handler *h;
64 /* assert(index < NUM_INTERRUPTS); */
65 klog(0,"registering handler %llx\n", (uint64_t)handler->handler);
69 enabled = interrupts_set(0);
78 /* TODO assembly xor eax,eax; lock cmpxchg [rdi], rsi */
82 handlers[index] = handler;
84 interrupts_set(enabled);
87 void interrupt_remove_handler(unsigned int index, struct interrupt_handler *handler) {
88 /* assert(index < NUM_INTERRUPTS); */
89 int was_enabled = interrupts_set(0);
92 handler->prev->next = handler->next;
94 handlers[index] = handler->next;
98 handler->next->prev = handler->prev;
101 interrupts_set(was_enabled);
105 #define IDTFLAGS(type, rpl) ( (1 << 7) | type << 0 | rpl << 5 )
106 static void set_table_entry(unsigned int num, void (*handler)(void), int user,
108 uint8_t ist = 0, type, rpl;
112 /* TODO what is the actual difference between these */
113 /* an interrupt clears the interrupt flag, a trap leaves it alone
114 * thus a trap could be further interrupted
116 type = trap ? 0xF : 0xE;
118 /* 0x10 == kernel code segment */
119 set_idt_entry(&interrupt_table[num], (uintptr_t)handler, 0x10, IDTFLAGS(type,rpl), ist);
122 void init_interrupts() {
125 /* Initialize the pic and remap the IRQ table */
129 /* Initialize the interrupt table entries to the null interrupt handler. */
130 memset(&interrupt_table, 0, sizeof interrupt_table);
131 for (i = 0; i < NUM_INTERRUPTS; i++) {
132 set_table_entry(i, interrupt_handler_null, 0, 0);
135 /* cpu internal handlers */
136 set_table_entry(0, isr0, 0, 0);
137 set_table_entry(1, isr1, 0, 0);
138 set_table_entry(2, isr2, 0, 0);
139 set_table_entry(3, isr3, 0, 0);
140 set_table_entry(4, isr4, 0, 0);
141 set_table_entry(5, isr5, 0, 0);
142 set_table_entry(6, isr6, 0, 0);
143 set_table_entry(7, isr7, 0, 0);
144 set_table_entry(8, isr8, 0, 0);
145 set_table_entry(9, isr9, 0, 0);
146 set_table_entry(10, isr10, 0, 0);
147 set_table_entry(11, isr11, 0, 0);
148 set_table_entry(12, isr12, 0, 0);
149 set_table_entry(13, isr13, 0, 0);
150 set_table_entry(14, isr14, 0, 0);
151 set_table_entry(15, isr15, 0, 0);
152 set_table_entry(16, isr16, 0, 0);
153 set_table_entry(17, isr17, 0, 0);
154 set_table_entry(18, isr18, 0, 0);
155 set_table_entry(19, isr19, 0, 0);
156 set_table_entry(20, isr20, 0, 0);
157 set_table_entry(21, isr21, 0, 0);
158 set_table_entry(22, isr22, 0, 0);
159 set_table_entry(23, isr23, 0, 0);
160 set_table_entry(24, isr24, 0, 0);
161 set_table_entry(25, isr25, 0, 0);
162 set_table_entry(26, isr26, 0, 0);
163 set_table_entry(27, isr27, 0, 0);
164 set_table_entry(28, isr28, 0, 0);
165 set_table_entry(29, isr29, 0, 0);
166 set_table_entry(30, isr30, 0, 0);
167 set_table_entry(31, isr31, 0, 0);
169 /* hardware interrupts from the pic */
170 set_table_entry(32, irq0, 0, 0);
171 set_table_entry(33, irq1, 0, 0);
172 set_table_entry(34, irq2, 0, 0);
173 set_table_entry(35, irq3, 0, 0);
174 set_table_entry(36, irq4, 0, 0);
175 set_table_entry(37, irq5, 0, 0);
176 set_table_entry(38, irq6, 0, 0);
177 set_table_entry(39, irq7, 0, 0);
178 set_table_entry(40, irq8, 0, 0);
179 set_table_entry(41, irq9, 0, 0);
180 set_table_entry(42, irq10, 0, 0);
181 set_table_entry(43, irq11, 0, 0);
182 set_table_entry(44, irq12, 0, 0);
183 set_table_entry(45, irq13, 0, 0);
184 set_table_entry(46, irq14, 0, 0);
185 set_table_entry(47, irq15, 0, 0);
187 /* software interrupt, could be used to force a schedule */
188 set_table_entry(128, isr128, 1, 0);
189 set_table_entry(129, interrupt_handler_null, 0, 1);
191 load_idt(interrupt_table, NUM_INTERRUPTS);
193 printk("interrupts enabled\n");
196 const char *exceptionstr(int i) {
197 if (i < NUM_KNOWN_EXCEPTIONS) {
198 return exception_names[i];
203 void interrupt_handler(struct interrupt_context *intctx) {
206 struct interrupt_handler *h;
208 unsigned int int_no = intctx->int_no;
210 /* Ignore spurious IRQ 7 and 15 */
211 if ( int_no == IRQ7 && !(pic.readisr() & (1 << 7)) )
213 if ( int_no == IRQ15 && !(pic.readisr() & (1 << 15)) ) {
218 in_kernel = (intctx->cs & 0x3) == 0;
219 crash = int_no < 32 && int_no != 7; /* I think 7 and 9 can't happen */
221 if (crash && in_kernel) {
222 panic("kernel crash '%s' int %u, rip %llx, cr2 %llx, error %llx, rflags %llx\n",
223 exceptionstr(intctx->int_no),
224 intctx->int_no, intctx->rip, intctx->cr2, intctx->err_code,
227 if (crash && !in_kernel) {
228 panic("user mode crash: interrupt %u\n", int_no);
231 /* run registered handlers */
232 for (h = handlers[int_no]; h; h = h->next ) {
233 h->handler(intctx, h->context);
236 /* Send an end of interrupt signal to the PICs if we got an IRQ */
237 if (int_no >= IRQ0 && int_no <= IRQ15) {
238 pic.eoi(int_no - IRQ0);
241 if (need_schedule()) {
246 int interrupts_set(int is_enabled) {
247 int wasenabled = interrupts_enabled();
251 disable_interrupts();