/** * IDT (Interrupt Descriptor Table) functionality. */ module hulk.idt; import hulk.gdt; import ldc.llvmasm; import hulk.fb; import hulk.console; import hulk.klog; import hulk.apic; import hulk.cpu; struct Idt { static struct ExceptionStackFrame { ulong rip; ulong cs; ulong rflags; ulong rsp; ulong ss; } public static enum ulong EXC_PAGE_FAULT = 14; /* The I/O APIC is configured to map IRQ 0 to interrupt 64 (0x40). */ public static enum ulong INT_APIC_BASE = 0x40u; /* IRQ 0 */ public static enum ulong INT_APIC_COUNT = 24u; public static enum ulong INT_APIC_TIMER = 0x70u; public static enum ulong INT_APIC_LINT0 = 0x71u; public static enum ulong INT_APIC_LINT1 = 0x72u; public static enum ulong INT_APIC_SPURIOUS = 0xFFu; struct idtr_t { ushort limit; align(2) ulong offset; } static assert(idtr_t.sizeof == 10u); alias descriptor_t = ulong[2]; static __gshared align(0x10) descriptor_t[256] idt; static assert(idt.sizeof == (256u * 16u)); static __gshared idtr_t idtr; public static void initialize() { set_isrs(); idtr.limit = idt.sizeof - 1u; idtr.offset = cast(ulong)&idt; lidt(&idtr); } private static void lidt(idtr_t * idtr) { __asm("lidt $0", "*m", idtr); } private static bool isr_has_error_code(size_t isr) { return (isr == 8) || ((10 <= isr) && (isr <= 14)) || (isr == 17) || (isr == 21) || (isr == 29) || (isr == 30); } private static bool isr_is_trap(size_t isr) { return (isr < 32u) && (isr != 2u); } private static void set_isrs() { ulong isr_address; static foreach(isr; 0 .. 256) { mixin("isr_address = __asm!ulong(` movabs $$1f, %rax jmp 2f 1: pushq %rdi pushq %rsi pushq %rax pushq %rdx mov $$", isr, ", %rdi " ~ (isr_has_error_code(isr) ? "mov 0x20(%rsp), %rsi" : "") ~ " " ~ (isr_has_error_code(isr) ? "lea 0x28(%rsp), %rdx" : "lea 0x20(%rsp), %rdx") ~ " movabs $$isr, %rax callq *%rax popq %rdx popq %rax popq %rsi popq %rdi " ~ (isr_has_error_code(isr) ? "add $$8, %rsp" : "") ~ " iretq 2:`, `={rax}`);"); mixin("set_descriptor(", isr, ", 0u, " ~ (isr_is_trap(isr) ? "true" : "false") ~ ", isr_address);"); } } private static void set_descriptor(size_t index, ulong dpl, bool trap, ulong offset) { idt[index][0] = 0x0000_8E_00_0000_0000u | ((offset & 0xFFFF_0000u) << 32u) | (dpl << 45u) | ((trap ? 1uL : 0uL) << 40u) | (Gdt.SELECTOR_KERNEL_CODE << 16u) | (offset & 0xFFFFu); idt[index][1] = offset >> 32u; } } public extern(C) void isr(ulong vector, ulong arg, Idt.ExceptionStackFrame * stack_frame) { if ((vector >= Idt.INT_APIC_BASE) && (vector < (Idt.INT_APIC_BASE + Idt.INT_APIC_COUNT))) { Apic.isr(vector); } else { switch (vector) { case Idt.INT_APIC_TIMER: case Idt.INT_APIC_LINT0: case Idt.INT_APIC_LINT1: case Idt.INT_APIC_SPURIOUS: Apic.isr(vector); break; default: Console.clear(); Fb.clear(0xFF8000u); Klog.writefln("ISR %u, error code 0x%x", vector, arg); Klog.writefln("RIP = 0x%p", stack_frame.rip); Klog.writefln("CS = 0x%x", stack_frame.cs); Klog.writefln("RFLAGS = 0x%x", stack_frame.rflags); Klog.writefln("RSP = 0x%x", stack_frame.rsp); Klog.writefln("SS = 0x%x", stack_frame.ss); Klog.writefln("CR2 = 0x%p", read_cr2()); __asm("cli", ""); for (;;) { __asm("hlt", ""); } } } }