diff --git a/src/hulk/idt.d b/src/hulk/idt.d index 23b6422..2f0feee 100644 --- a/src/hulk/idt.d +++ b/src/hulk/idt.d @@ -13,6 +13,27 @@ import hulk.cpu; import hulk.kfont; import hulk.thread; +static foreach(isr; 0 .. Idt.N_ISRS) +{ + mixin(`private extern(C) void isr_`, isr, `();`); +} + +private string isrs_list(int index = 0)() +{ + static if (index < 256) + { + return "&isr_" ~ index.stringof ~ ",\n" ~ isrs_list!(index + 1)(); + } + else + { + return ""; + } +} + +mixin(`private static __gshared extern(C) void function()[Idt.N_ISRS] isrs = [`, + isrs_list(), + `];`); + struct Idt { /** Interrupt stack frame indices. */ @@ -65,18 +86,43 @@ struct Idt "SS", ]; - public static enum ulong EXC_PAGE_FAULT = 14; + public 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 enum ulong INT_APIC_BASE = 0x40u; /* IRQ 0 */ + public 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_KERNEL_SWINT = 0x80u; - public static enum ulong INT_APIC_SPURIOUS = 0xFFu; + public enum ulong INT_APIC_TIMER = 0x70u; + public enum ulong INT_APIC_LINT0 = 0x71u; + public enum ulong INT_APIC_LINT1 = 0x72u; + public enum ulong INT_KERNEL_SWINT = 0x80u; + public enum ulong INT_APIC_SPURIOUS = 0xFFu; + private enum N_ISRS = 256; + + /** + * IDT descriptor entry type. + */ + struct descriptor_t + { + ulong[2] descriptor; + + this(T)(size_t index, ulong dpl, bool trap, T offset) + { + descriptor[0] = + 0x0000_8E_00_0000_0000u | + ((cast(ulong)offset & 0xFFFF_0000u) << 32u) | + (dpl << 45u) | + ((trap ? 1uL : 0uL) << 40u) | + (Gdt.SELECTOR_KERNEL_CODE << 16u) | + (cast(ulong)offset & 0xFFFFu); + descriptor[1] = cast(ulong)offset >> 32u; + } + } + + /** + * IDTR register format. + */ struct idtr_t { ushort limit; @@ -84,11 +130,9 @@ struct Idt } 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; + private static __gshared idtr_t idtr; + private static __gshared align(0x10) descriptor_t[N_ISRS] idt; + static assert(idt.sizeof == (N_ISRS * 16u)); public static void initialize() { @@ -103,87 +147,80 @@ struct Idt __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) + static bool isr_has_error_code(size_t isr) { - mixin("isr_address = __asm!ulong(` - movabs $$1f, %rax - jmp 2f - 1: + return (isr == 8) || + ((10 <= isr) && (isr <= 14)) || + (isr == 17) || + (isr == 21) || + (isr == 29) || + (isr == 30); + } + + static bool isr_is_trap(size_t isr) + { + return (isr < 32u) && (isr != 2u); + } + + __asm("jmp 1f", ""); + static foreach(isr; 0 .. N_ISRS) + { + mixin("__asm(`isr_", isr, ": " ~ (isr_has_error_code(isr) ? "" : "pushq $$0") ~ " pushq %rax - pushq %rbx - pushq %rcx - pushq %rdx - pushq %rsi - pushq %rdi - pushq %r8 - pushq %r9 - pushq %r10 - pushq %r11 - pushq %r12 - pushq %r13 - pushq %r14 - pushq %r15 - pushq %rbp - mov %rsp, %rbp - mov %rsp, %rsi - and $$0xFFFFFFFFFFFFFFF0, %rsp - mov $$", isr, ", %rdi - movabs $$isr, %rax - callq *%rax - mov %rax, %rsp - popq %rbp - popq %r15 - popq %r14 - popq %r13 - popq %r12 - popq %r11 - popq %r10 - popq %r9 - popq %r8 - popq %rdi - popq %rsi - popq %rdx - popq %rcx - popq %rbx - popq %rax - add $$8, %rsp - iretq - 2:`, `={rax}`);"); - mixin("set_descriptor(", isr, ", 0u, " ~ - (isr_is_trap(isr) ? "true" : "false") ~ ", isr_address);"); + mov $$", isr, ", %rax + jmp isr_common`, ``);"); + } + + __asm(`isr_common: + pushq %rbx + pushq %rcx + pushq %rdx + pushq %rsi + pushq %rdi + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + pushq %rbp + mov %rsp, %rbp + mov %rsp, %rsi + and $$0xFFFFFFFFFFFFFFF0, %rsp + mov %rax, %rdi + movabs $$isr, %rax + callq *%rax + mov %rax, %rsp + popq %rbp + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rdi + popq %rsi + popq %rdx + popq %rcx + popq %rbx + popq %rax + add $$8, %rsp + iretq + 1:`, ``); + + for (size_t isr = 0; isr < N_ISRS; isr++) + { + idt[isr] = descriptor_t(isr, 0u, isr_is_trap(isr), isrs[isr]); } } - 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; - } } /**