hos/src/hulk/idt.d

269 lines
6.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;
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. */
public static enum
{
ISF_RBP,
ISF_R15,
ISF_R14,
ISF_R13,
ISF_R12,
ISF_R11,
ISF_R10,
ISF_R9,
ISF_R8,
ISF_RDI,
ISF_RSI,
ISF_RDX,
ISF_RCX,
ISF_RBX,
ISF_RAX,
ISF_ERROR_CODE,
ISF_RIP,
ISF_CS,
ISF_RFLAGS,
ISF_RSP,
ISF_SS,
ISF_COUNT,
}
private static __gshared string[ISF_COUNT] ISF_NAMES = [
"RBP",
"R15",
"R14",
"R13",
"R12",
"R11",
"R10",
"R9",
"R8",
"RDI",
"RSI",
"RDX",
"RCX",
"RBX",
"RAX",
"Error Code",
"RIP",
"CS",
"RFLAGS",
"RSP",
"SS",
];
public enum ulong EXC_PAGE_FAULT = 14;
/* The I/O APIC is configured to map IRQ 0 to interrupt 64 (0x40). */
public enum ulong INT_APIC_BASE = 0x40u; /* IRQ 0 */
public enum ulong INT_APIC_COUNT = 24u;
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;
align(2) ulong offset;
}
static assert(idtr_t.sizeof == 10u);
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()
{
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 void set_isrs()
{
static bool isr_has_error_code(size_t isr)
{
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
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]);
}
}
}
/**
* Interrupt service routine.
*
* This function returns the stack pointer of the thread to execute when
* returning from this function.
*/
public extern(C) ulong * isr(ulong vector, ulong * stack_frame)
{
Thread.current_thread.stack_pointer = 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:
Fb.rect(0, 0, Fb.width, Kfont.line_height, 0xCC0000u);
Klog.writefln("\n **** Unhandled ISR %u ****", vector);
for (size_t i = 0u; i < Idt.ISF_COUNT; i++)
{
Klog.writef(Idt.ISF_NAMES[i]);
Klog.writefln(" = 0x%x", stack_frame[i]);
}
Klog.writefln("CR2 = 0x%p", read_cr2());
__asm("cli", "");
for (;;)
{
__asm("hlt", "");
}
}
}
Thread.current_thread = Thread.current_thread.list_next;
return Thread.current_thread.stack_pointer;
}