/* *----------------------------------------------------------------------------- * * interrupt.c -- * * Interrupt handler routines. * *----------------------------------------------------------------------------- */ #include volatile int interrupt_received = 0; struct gate { unsigned short offset_low; /* address[15:0] */ unsigned short segment; /* segment selector */ unsigned rsvd0:5; /* 00000 */ unsigned zero1:3; /* always 0 */ unsigned type:3; /* 110: interrupt, 111: trap */ unsigned D:1; /* size of gate (1 is 32 bit) */ unsigned zero0:1; /* always 0 */ unsigned DPL:2; /* descriptor privilege level */ unsigned P:1; /* present */ unsigned short offset_high; /* address[31:16] */ } __attribute__ ((packed)); struct { unsigned short length; unsigned long address; } __attribute__ ((packed)) idtp = { 256 * 8, IDT }; /* *----------------------------------------------------------------------------- * * Assembly stub interrupt handlers. These save the CPU state and call the * real interrupt routine with the requisite info. * *----------------------------------------------------------------------------- */ extern void divide_error_stub (void); extern void nmi_stub (void); extern void breakpoint_stub (void); extern void overflow_stub (void); extern void bound_range_stub (void); extern void ud_stub (void); extern void no_math_stub (void); extern void df_stub (void); extern void invalid_tss_stub (void); extern void segment_np_stub (void); extern void stack_fault_stub (void); extern void gp_stub (void); extern void pf_stub (void); extern void math_fault_stub (void); extern void alignment_check_stub (void); extern void simd_stub (void); #define REGISTERS unsigned long edi, \ unsigned long esi, \ unsigned long ebp, \ unsigned long esp, \ unsigned long ebx, \ unsigned long edx, \ unsigned long ecx, \ unsigned long eax #define REGISTER_NAMES edi, esi, ebp, esp, ebx, edx, ecx, eax /* * Send EOI to the 8259. */ void acknowledge_irq (void) { outb (0x20, 0x20); outb (0x20, 0xa0); } static void remap_irqs (void) { /* * Initialize 8259s. */ /* ICW1 */ outb (0x11, 0x20); outb (0x11, 0xa0); /* ICW2 */ outb (0x20, 0x21); outb (0x28, 0xa1); /* ICW3 */ outb (0x04, 0x21); outb (0x02, 0xa1); /* ICW4 */ outb (0x01, 0x21); outb (0x01, 0xa1); /* * Mask external interrupts. */ outb (0xff, 0x21); outb (0xff, 0xa1); } void print_interrupt (char name[], int id, REGISTERS, unsigned long eip, unsigned long cs, unsigned long eflags, unsigned long error_code) { unsigned long cr0, cr2, cr3, cr4; asm ("movl %%cr0, %%eax\n\t" "movl %%eax, %[cr0]\n\t" "movl %%cr2, %%eax\n\t" "movl %%eax, %[cr2]\n\t" "movl %%cr3, %%eax\n\t" "movl %%eax, %[cr3]\n\t" "movl %%cr4, %%eax\n\t" "movl %%eax, %[cr4]\n\t" : [cr0] "=m" (cr0), [cr2] "=m" (cr2), [cr3] "=m" (cr3), [cr4] "=m" (cr4) :); logging = 0; /* can't use printf as it calls malloc and this may be called from #PF */ print_str (name); putchar ('('); print_hex32 (id); print_str (") at "); print_hex32 (cs); putchar (':'); print_hex32 (eip); print_str (" Error code: "); print_hex32 (error_code); putchar ('\n'); print_str ("EAX: "); print_hex32 (eax); print_str (" EBX: "); print_hex32 (ebx); print_str (" ECX: "); print_hex32 (ecx); print_str (" EDX: "); print_hex32 (edx); putchar ('\n'); print_str ("ESP: "); print_hex32 (esp + 12); print_str (" EBP: "); print_hex32 (ebp); print_str (" ESI: "); print_hex32 (esi); print_str (" EDI: "); print_hex32 (edi); putchar ('\n'); print_str ("EFLAGS: "); print_hex32 (eflags); putchar ('\n'); print_str ("CR0: "); print_hex32 (cr0); print_str (" CR2: "); print_hex32 (cr2); print_str (" CR3: "); print_hex32 (cr3); print_str (" CR4: "); print_hex32 (cr4); putchar ('\n'); logging = 1; } void terminate (void) { logging = 0; print_str ("!!!!!! Your computer will now be terminated !!!!!!"); cli (); halt (); /* should maybe actually shut down here */ } void divide_error (REGISTERS, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("#DE", 0, REGISTER_NAMES, eip, cs, eflags, 0); } void nmi (REGISTERS, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("NMI", 2, REGISTER_NAMES, eip, cs, eflags, 0); terminate (); } void breakpoint (REGISTERS, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("#BP", 3, REGISTER_NAMES, eip, cs, eflags, 0); } void overflow (REGISTERS, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("#OF", 4, REGISTER_NAMES, eip, cs, eflags, 0); } void bound_range (REGISTERS, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("#BR", 5, REGISTER_NAMES, eip, cs, eflags, 0); } void ud (REGISTERS, unsigned long eip, unsigned long cs, unsigned long eflags) { char *text = (char *)eip; int k; print_str ("#UD(06) at "); print_hex16 (cs); putchar (':'); print_hex32 (eip); putchar ('\n'); for (k = 0; k < 16; k++) { print_hex8 (text[k]); putchar (' '); } putchar ('\n'); terminate (); } void no_math (REGISTERS, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("#NM", 7, REGISTER_NAMES, eip, cs, eflags, 0); } void df (REGISTERS, unsigned long error_code, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("#DF", 8, REGISTER_NAMES, eip, cs, eflags, error_code); terminate (); } void invalid_tss (REGISTERS, unsigned long error_code, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("#TS", 10, REGISTER_NAMES, eip, cs, eflags, error_code); terminate (); } void segment_np (REGISTERS, unsigned long error_code, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("#NP", 11, REGISTER_NAMES, eip, cs, eflags, error_code); terminate (); } void stack_fault (REGISTERS, unsigned long error_code, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("#SS", 12, REGISTER_NAMES, eip, cs, eflags, error_code); terminate (); } void gp (REGISTERS, unsigned long error_code, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("#GP", 13, REGISTER_NAMES, eip, cs, eflags, error_code); terminate (); } void pf (REGISTERS, unsigned long error_code, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("#PF", 14, REGISTER_NAMES, eip, cs, eflags, error_code); terminate (); } void math_fault (REGISTERS, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("#MF", 16, REGISTER_NAMES, eip, cs, eflags, 0); } void alignment_check (REGISTERS, unsigned long error_code, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("#AC", 17, REGISTER_NAMES, eip, cs, eflags, error_code); terminate (); } void simd (REGISTERS, unsigned long eip, unsigned long cs, unsigned long eflags) { print_interrupt ("#XF", 19, REGISTER_NAMES, eip, cs, eflags, 0); } void install_iv (unsigned long n, void (*handler)(), enum vector_type type) { struct gate *gate = (struct gate *)(IDT + n * 8); unsigned long handler_addr = (unsigned long)handler; gate->offset_high = (unsigned short)((handler_addr >> 16) & 0xffff); gate->P = 1; gate->DPL = 0; gate->zero0 = 0; gate->D = 1; gate->type = type; gate->zero1 = 0; gate->rsvd0 = 0; gate->segment = CS; gate->offset_low = (unsigned short)(handler_addr & 0xffff); } void install_null_iv (unsigned long n) { struct gate *gate = (struct gate *)(IDT + n * 8); memset ((void *)gate, 0, sizeof (struct gate)); } void create_idt (void) { unsigned long n; remap_irqs (); install_iv (0, ÷_error_stub, TRAP); install_null_iv (1); /* 1 (debug) is reserved */ install_iv (2, &nmi_stub, INTERRUPT); install_iv (3, &breakpoint_stub, TRAP); install_iv (4, &overflow_stub, TRAP); install_iv (5, &bound_range_stub, TRAP); install_iv (6, &ud_stub, TRAP); install_iv (7, &no_math_stub, TRAP); install_iv (8, &df_stub, TRAP); install_null_iv (9); /* 9 (coprocessor segment overrun) is null */ install_iv (10, &invalid_tss_stub, TRAP); install_iv (11, &segment_np_stub, TRAP); install_iv (12, &stack_fault_stub, TRAP); install_iv (13, &gp_stub, TRAP); install_iv (14, &pf_stub, TRAP); install_null_iv (15); /* 15 is null */ install_iv (16, &math_fault_stub, TRAP); install_iv (17, &alignment_check_stub, TRAP); install_null_iv (18); /* MCE is not enabled */ install_iv (19, &simd_stub, TRAP); /* * 20-31 are reserved by the processor * 32-47 are mapped to IRQ0-15 - individual routines will be installed later * 48-255 are user defined and will be null * */ for (n = 20; n <= 255; n++) { install_null_iv (n); } asm ("lidt %0\n" :: "m" (idtp)); }