/** * 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.rtc; struct idt { /* IRQ 0 is interrupt 32 (0x20). */ public static enum ulong INT_RTC = 0x28u; /* IRQ 8 */ public static enum ulong INT_LAPIC_TIMER = 0x70u; public static enum ulong INT_LAPIC_LINT0 = 0x71u; public static enum ulong INT_LAPIC_LINT1 = 0x72u; 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 mov $$", isr, ", %rdi " ~ (isr_has_error_code(isr) ? "mov 0x18(%rsp), %rsi" : "") ~ " movabs $$isr, %rax callq *%rax 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) { switch (vector) { case idt.INT_RTC: rtc.isr(); break; case idt.INT_LAPIC_TIMER: case idt.INT_LAPIC_LINT0: case idt.INT_LAPIC_LINT1: apic.isr(vector); break; default: console.clear(); fb.clear(0xFF8000u); klog.writefln("ISR %u, 0x%x", vector, arg); __asm("cli", ""); for (;;) { __asm("hlt", ""); } } }