Commonize ISR handling as much as possible

This commit is contained in:
Josh Holtrop 2023-11-30 20:32:06 -05:00
parent edc9b2c3ff
commit 0efe8af5aa

View File

@ -13,6 +13,27 @@ import hulk.cpu;
import hulk.kfont; import hulk.kfont;
import hulk.thread; 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 struct Idt
{ {
/** Interrupt stack frame indices. */ /** Interrupt stack frame indices. */
@ -65,18 +86,43 @@ struct Idt
"SS", "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). */ /* 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 enum ulong INT_APIC_BASE = 0x40u; /* IRQ 0 */
public static enum ulong INT_APIC_COUNT = 24u; public enum ulong INT_APIC_COUNT = 24u;
public static enum ulong INT_APIC_TIMER = 0x70u; public enum ulong INT_APIC_TIMER = 0x70u;
public static enum ulong INT_APIC_LINT0 = 0x71u; public enum ulong INT_APIC_LINT0 = 0x71u;
public static enum ulong INT_APIC_LINT1 = 0x72u; public enum ulong INT_APIC_LINT1 = 0x72u;
public static enum ulong INT_KERNEL_SWINT = 0x80u; public enum ulong INT_KERNEL_SWINT = 0x80u;
public static enum ulong INT_APIC_SPURIOUS = 0xFFu; 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 struct idtr_t
{ {
ushort limit; ushort limit;
@ -84,11 +130,9 @@ struct Idt
} }
static assert(idtr_t.sizeof == 10u); static assert(idtr_t.sizeof == 10u);
alias descriptor_t = ulong[2]; private static __gshared idtr_t idtr;
private static __gshared align(0x10) descriptor_t[N_ISRS] idt;
static __gshared align(0x10) descriptor_t[256] idt; static assert(idt.sizeof == (N_ISRS * 16u));
static assert(idt.sizeof == (256u * 16u));
static __gshared idtr_t idtr;
public static void initialize() public static void initialize()
{ {
@ -103,87 +147,80 @@ struct Idt
__asm("lidt $0", "*m", 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() private static void set_isrs()
{ {
ulong isr_address; static bool isr_has_error_code(size_t isr)
static foreach(isr; 0 .. 256)
{ {
mixin("isr_address = __asm!ulong(` return (isr == 8) ||
movabs $$1f, %rax ((10 <= isr) && (isr <= 14)) ||
jmp 2f (isr == 17) ||
1: (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") ~ " " ~ (isr_has_error_code(isr) ? "" : "pushq $$0") ~ "
pushq %rax pushq %rax
pushq %rbx mov $$", isr, ", %rax
pushq %rcx jmp isr_common`, ``);");
pushq %rdx }
pushq %rsi
pushq %rdi __asm(`isr_common:
pushq %r8 pushq %rbx
pushq %r9 pushq %rcx
pushq %r10 pushq %rdx
pushq %r11 pushq %rsi
pushq %r12 pushq %rdi
pushq %r13 pushq %r8
pushq %r14 pushq %r9
pushq %r15 pushq %r10
pushq %rbp pushq %r11
mov %rsp, %rbp pushq %r12
mov %rsp, %rsi pushq %r13
and $$0xFFFFFFFFFFFFFFF0, %rsp pushq %r14
mov $$", isr, ", %rdi pushq %r15
movabs $$isr, %rax pushq %rbp
callq *%rax mov %rsp, %rbp
mov %rax, %rsp mov %rsp, %rsi
popq %rbp and $$0xFFFFFFFFFFFFFFF0, %rsp
popq %r15 mov %rax, %rdi
popq %r14 movabs $$isr, %rax
popq %r13 callq *%rax
popq %r12 mov %rax, %rsp
popq %r11 popq %rbp
popq %r10 popq %r15
popq %r9 popq %r14
popq %r8 popq %r13
popq %rdi popq %r12
popq %rsi popq %r11
popq %rdx popq %r10
popq %rcx popq %r9
popq %rbx popq %r8
popq %rax popq %rdi
add $$8, %rsp popq %rsi
iretq popq %rdx
2:`, `={rax}`);"); popq %rcx
mixin("set_descriptor(", isr, ", 0u, " ~ popq %rbx
(isr_is_trap(isr) ? "true" : "false") ~ ", isr_address);"); 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;
}
} }
/** /**