idt.c (4543B)
1 #include "extern.h" 2 #include "idt.h" 3 #include "port.h" 4 5 #define N_INT 256 6 #define KERN_CODESEG 0x08 7 8 static void idt_set_gate(uint8_t, uint32_t); 9 10 static struct idt_gate idt[N_INT]; 11 static void *isr[16] = {NULL}; 12 /* Exception messages for the first 32 interrupts. */ 13 static const char *except[] = { 14 "Division By Zero Exception", 15 "Debug Exception", 16 "Non Maskable Interrupt Exception", 17 "Breakpoint Exception", 18 "Into Detected Overflow Exception", 19 "Out of Bounds Exception", 20 "Invalid Opcode Exception", 21 "No Coprocessor Exception", 22 "Double Fault Exception", 23 "Coprocessor Segment Overrun Exception", 24 "Bad TSS Exception", 25 "Segment Not Present Exception", 26 "Stack Fault Exception", 27 "General Protection Fault Exception", 28 "Page Fault Exception", 29 "Unknown Interrupt Exception", 30 "Coprocessor Fault Exception", 31 "Alignment Check Exception (486+)", 32 "Machine Check Exception (Pentium/586+)", 33 "Reserved Exception", 34 "Reserved Exception", 35 "Reserved Exception", 36 "Reserved Exception", 37 "Reserved Exception", 38 "Reserved Exception", 39 "Reserved Exception", 40 "Reserved Exception", 41 "Reserved Exception", 42 "Reserved Exception", 43 "Reserved Exception", 44 "Reserved Exception", 45 "Reserved Exception", 46 }; 47 48 static void 49 idt_set_gate(uint8_t n, uint32_t ptr) 50 { 51 idt[n].off_lo = ptr & 0xffff; 52 idt[n].sel = KERN_CODESEG; 53 idt[n].zero = 0; 54 /* The gate is present and is running in kernel mode. */ 55 idt[n].flags = 0x8e; 56 idt[n].off_hi = (ptr >> 16) & 0xffff; 57 } 58 59 void 60 idt_init(void) 61 { 62 struct idt_reg { 63 uint16_t limit; /* IDT size in bytes. */ 64 uint32_t base; /* Points at `idt[0]`. */ 65 } __attribute__((packed)) idtr; 66 67 (void)memset(&idt, 0, sizeof(idt)); 68 69 /* Set up exception interrupts. */ 70 idt_set_gate(0, (uint32_t)ex0); 71 idt_set_gate(1, (uint32_t)ex1); 72 idt_set_gate(2, (uint32_t)ex2); 73 idt_set_gate(3, (uint32_t)ex3); 74 idt_set_gate(4, (uint32_t)ex4); 75 idt_set_gate(5, (uint32_t)ex5); 76 idt_set_gate(6, (uint32_t)ex6); 77 idt_set_gate(7, (uint32_t)ex7); 78 idt_set_gate(8, (uint32_t)ex8); 79 idt_set_gate(9, (uint32_t)ex9); 80 idt_set_gate(10, (uint32_t)ex10); 81 idt_set_gate(11, (uint32_t)ex11); 82 idt_set_gate(12, (uint32_t)ex12); 83 idt_set_gate(13, (uint32_t)ex13); 84 idt_set_gate(14, (uint32_t)ex14); 85 idt_set_gate(15, (uint32_t)ex15); 86 idt_set_gate(16, (uint32_t)ex16); 87 idt_set_gate(17, (uint32_t)ex17); 88 idt_set_gate(18, (uint32_t)ex18); 89 idt_set_gate(19, (uint32_t)ex19); 90 idt_set_gate(20, (uint32_t)ex20); 91 idt_set_gate(21, (uint32_t)ex21); 92 idt_set_gate(22, (uint32_t)ex22); 93 idt_set_gate(23, (uint32_t)ex23); 94 idt_set_gate(24, (uint32_t)ex24); 95 idt_set_gate(25, (uint32_t)ex25); 96 idt_set_gate(26, (uint32_t)ex26); 97 idt_set_gate(27, (uint32_t)ex27); 98 idt_set_gate(28, (uint32_t)ex28); 99 idt_set_gate(29, (uint32_t)ex29); 100 idt_set_gate(30, (uint32_t)ex30); 101 idt_set_gate(31, (uint32_t)ex31); 102 103 /* Remap the PIC */ 104 /* TODO: explain.*/ 105 outb(P_PIC1_CMD, 0x11); 106 outb(P_PIC2_CMD, 0x11); 107 outb(P_PIC1_DATA, 0x20); 108 outb(P_PIC2_DATA, 0x28); 109 outb(P_PIC1_DATA, 0x04); 110 outb(P_PIC2_DATA, 0x02); 111 outb(P_PIC1_DATA, 0x01); 112 outb(P_PIC2_DATA, 0x01); 113 outb(P_PIC1_DATA, 0x00); 114 outb(P_PIC2_DATA, 0x00); 115 116 /* Set up IRQs */ 117 idt_set_gate(32, (uint32_t)irq0); 118 idt_set_gate(33, (uint32_t)irq1); 119 idt_set_gate(34, (uint32_t)irq2); 120 idt_set_gate(35, (uint32_t)irq3); 121 idt_set_gate(36, (uint32_t)irq4); 122 idt_set_gate(37, (uint32_t)irq5); 123 idt_set_gate(38, (uint32_t)irq6); 124 idt_set_gate(39, (uint32_t)irq7); 125 idt_set_gate(40, (uint32_t)irq8); 126 idt_set_gate(41, (uint32_t)irq9); 127 idt_set_gate(42, (uint32_t)irq10); 128 idt_set_gate(43, (uint32_t)irq11); 129 idt_set_gate(44, (uint32_t)irq12); 130 idt_set_gate(45, (uint32_t)irq13); 131 idt_set_gate(46, (uint32_t)irq14); 132 idt_set_gate(47, (uint32_t)irq15); 133 134 /* https://wiki.osdev.org/Interrupt_Descriptor_Table#Location_and_Size */ 135 idtr.base = (uint32_t)&idt; 136 idtr.limit = N_INT * sizeof(struct idt_gate) - 1; 137 __asm__ __volatile__ ("lidtl (%0)" : : "r" (&idtr)); 138 } 139 140 void 141 int_handler(struct reg *r) 142 { 143 void (*handler)(struct reg *); 144 145 /* 146 * We'll call the handler only if the interrupt number is > 32, 147 * which means that we're dealing with an IRQ and not an exception. 148 */ 149 if (r->intno >= 32 && (handler = isr[r->intno - 32]) != NULL) 150 handler(r); 151 /* Entries below index 32 in the IDT are exceptions, we need to hang. */ 152 else if (r->intno < 32) { 153 tty_write(except[r->intno]); 154 tty_write(". System halted...\n"); 155 __asm__ __volatile__ ("hlt"); 156 } 157 if (r->intno >= 40) 158 outb(P_PIC2_CMD, 0x20); 159 outb(P_PIC1_CMD, 0x20); 160 } 161 162 void 163 int_add_handler(uint8_t intno, void (*handler)(struct reg *r)) 164 { 165 isr[intno] = handler; 166 }