155 lines
4.1 KiB
D
155 lines
4.1 KiB
D
/**
|
|
* 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", "");
|
|
}
|
|
}
|
|
}
|
|
}
|