diff --git a/kernel-src/arch/x86-64/idt.c b/kernel-src/arch/x86-64/idt.c new file mode 100644 index 00000000..82b04002 --- /dev/null +++ b/kernel-src/arch/x86-64/idt.c @@ -0,0 +1,41 @@ +#include +#include +#include + +typedef struct { + uint16_t size; + uint64_t offset; +} __attribute__((packed)) idtr_t; + +typedef struct { + uint16_t offset; + uint16_t segment; + uint8_t ist; + uint8_t flags; + uint16_t offset2; + uint32_t offset3; +} __attribute__((packed)) idtentry_t; + +static idtentry_t idt[256]; + +static idtr_t idtr = { + .size = sizeof(idt) - 1, + .offset = (uint64_t)idt +}; + +extern const uint64_t isr_table[256]; + +void arch_idt_setup() { + for (int i = 0; i < 256; ++i) { + idt[i].offset = isr_table[i] & 0xffff; + idt[i].segment = 0x8; + idt[i].ist = 0; + idt[i].flags = 0x8e; + idt[i].offset2 = (isr_table[i] >> 16) & 0xffff; + idt[i].offset3 = (isr_table[i] >> 32) & 0xffffffff; + } +} + +void arch_idt_reload() { + asm volatile("lidt (%%rax)" : : "a"(&idtr)); +} diff --git a/kernel-src/arch/x86-64/isr.asm b/kernel-src/arch/x86-64/isr.asm new file mode 100644 index 00000000..a10dce67 --- /dev/null +++ b/kernel-src/arch/x86-64/isr.asm @@ -0,0 +1,89 @@ +section .text +%assign i 0 +%rep 256 +isr_%+ i: + ; push an error code if the cpu did not + %if (i == 8 || i == 10 || i == 11 || i == 12 || i == 13 || i == 14) == 0 + push qword 0 + %endif + + ; check if swapgs is needed + + cmp qword [rsp+16], 0x18 + jne .notneeded1 + swapgs + .notneeded1: + + ; push context + push rsi + push rdi + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rdx + push rcx + push rbx + push rax + mov rax, ds + push rax + mov rax, es + push rax + mov rax, fs + push rax + mov rax, gs + push rax + mov rdi,cr2 + push rdi + + ; save ctx pointer and interrupt vector number + mov rdi, i + mov rsi, rsp + + cld + extern interrupt_isr + call interrupt_isr + + ; pop context + add rsp, 24 ; cr2 gs and fs are not popped. + pop rax + mov es,rax + pop rax + mov ds,rax + pop rax + pop rbx + pop rcx + pop rdx + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + pop rdi + pop rsi + pop rbp + add rsp,8 ; remove error code + + ; check if swapgs is needed + cmp qword [rsp+8], 0x18 + jne .notneeded2 + swapgs + .notneeded2: + iret +%assign i i+1 +%endrep + +section .rodata +global isr_table +isr_table: + %assign i 0 + %rep 256 + dq isr_%+ i + %endrep diff --git a/kernel-src/arch/x86-64/main.c b/kernel-src/arch/x86-64/main.c index 0a8a64fb..6184279e 100644 --- a/kernel-src/arch/x86-64/main.c +++ b/kernel-src/arch/x86-64/main.c @@ -2,6 +2,7 @@ #include #include #include +#include static cpu_t bsp_cpu; @@ -9,5 +10,7 @@ void kernel_entry() { cpu_set(&bsp_cpu); logging_sethook(arch_e9_putc); arch_gdt_reload(); + arch_idt_setup(); + arch_idt_reload(); __assert(!"kernel entry end"); } diff --git a/kernel-src/include/kernel/interrupt.h b/kernel-src/include/kernel/interrupt.h index 9db5eff4..e7a57edb 100644 --- a/kernel-src/include/kernel/interrupt.h +++ b/kernel-src/include/kernel/interrupt.h @@ -3,6 +3,8 @@ #include +#include + #ifdef __x86_64__ #define MAX_ISR_COUNT 256 #else @@ -11,15 +13,15 @@ struct _isr_t; typedef struct _isr_t { - void (*func)(struct _isr_t *self); // TODO pass register context as argument as well. + void (*func)(struct _isr_t *self, context_t *ctx); void (*eoi)(struct _isr_t *self); long id; long priority; bool pending; } isr_t; -void interrupt_register(int vector, void (*func)(isr_t *self), void (*eoi)(isr_t *self), long priority); // TODO pass register context as well. -isr_t *interrupt_allocate(void (*func)(isr_t *self), void (*eoi)(isr_t *self), long priority); // TODO pass register context as well. +void interrupt_register(int vector, void (*func)(isr_t *self, context_t *ctx), void (*eoi)(isr_t *self), long priority); +isr_t *interrupt_allocate(void (*func)(isr_t *self, context_t *ctx), void (*eoi)(isr_t *self), long priority); void interrupt_raiseipl(long newipl); void interrupt_loweripl(long newipl); diff --git a/kernel-src/include/x86-64/arch/idt.h b/kernel-src/include/x86-64/arch/idt.h new file mode 100644 index 00000000..c8783540 --- /dev/null +++ b/kernel-src/include/x86-64/arch/idt.h @@ -0,0 +1,7 @@ +#ifndef _IDT_H +#define _IDT_h + +void arch_idt_reload(); +void arch_idt_setup(); + +#endif diff --git a/kernel-src/sys/interrupt.c b/kernel-src/sys/interrupt.c index a9dc3add..2a6dc900 100644 --- a/kernel-src/sys/interrupt.c +++ b/kernel-src/sys/interrupt.c @@ -1,19 +1,19 @@ #include #include #include +#include -// TODO pass register context as well -void interrupt_isr(int vec) { +void interrupt_isr(int vec, context_t *ctx) { isr_t *isr = &_cpu()->isr[vec]; + __assert(isr->func); // TODO ipl check - isr->func(isr); // TODO pass context + isr->func(isr, ctx); if (isr->eoi) isr->eoi(isr); } -// TODO pass register context as well. -void interrupt_register(int vector, void (*func)(isr_t *self), void (*eoi)(isr_t *self), long priority) { +void interrupt_register(int vector, void (*func)(isr_t *self, context_t *ctx), void (*eoi)(isr_t *self), long priority) { isr_t *isr = &_cpu()->isr[vector]; isr->func = func; isr->eoi = eoi; @@ -21,8 +21,7 @@ void interrupt_register(int vector, void (*func)(isr_t *self), void (*eoi)(isr_t isr->priority = priority; } -// TODO pass register context as well. -isr_t *interrupt_allocate(void (*func)(isr_t *self), void (*eoi)(isr_t *self), long priority) { +isr_t *interrupt_allocate(void (*func)(isr_t *self, context_t *ctx), void (*eoi)(isr_t *self), long priority) { isr_t *isr = NULL; for (int i = 0; i < MAX_ISR_COUNT; ++i) {