From 25262960d980d04882b0c79e19b5c276fd49e84e Mon Sep 17 00:00:00 2001 From: Quinten Kock Date: Mon, 14 Dec 2020 23:10:58 +0100 Subject: [PATCH] add basic interrupt support --- kernel/src/arch/x86_64/entry-stivale2.c | 4 ++- kernel/src/arch/x86_64/idt.c | 26 +++++++++++++++++ kernel/src/arch/x86_64/idt.h | 22 ++++++++++++++ kernel/src/arch/x86_64/idt.nasm | 20 +++++++++++++ kernel/src/arch/x86_64/interrupt.c | 39 +++++++++++++++++++++++++ kernel/src/arch/x86_64/interrupt.h | 1 + 6 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 kernel/src/arch/x86_64/idt.c create mode 100644 kernel/src/arch/x86_64/idt.h create mode 100644 kernel/src/arch/x86_64/idt.nasm create mode 100644 kernel/src/arch/x86_64/interrupt.c create mode 100644 kernel/src/arch/x86_64/interrupt.h diff --git a/kernel/src/arch/x86_64/entry-stivale2.c b/kernel/src/arch/x86_64/entry-stivale2.c index 584176c..8f8f1f2 100644 --- a/kernel/src/arch/x86_64/entry-stivale2.c +++ b/kernel/src/arch/x86_64/entry-stivale2.c @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -46,6 +47,7 @@ void stivale2_main(struct stivale2_struct *info) { loadgdt(); print_gdt(); - asmpanic(); + setup_ints(); + kmain(); } diff --git a/kernel/src/arch/x86_64/idt.c b/kernel/src/arch/x86_64/idt.c new file mode 100644 index 0000000..adef57b --- /dev/null +++ b/kernel/src/arch/x86_64/idt.c @@ -0,0 +1,26 @@ +#include "idt.h" + +struct IDTInfo { + uint16_t size; + uint64_t offset; +} __attribute__((packed)); + +struct IDTDescr IDT[256]; +static struct IDTInfo idt_info; + +void set_idt_ent(uint8_t index, uint64_t offset, uint8_t ist, uint8_t min_priv_level, enum GateType type) { + IDT[index].offset_1 = offset & 0xFFFF; + IDT[index].offset_2 = (offset >> 16) & 0xFFFF; + IDT[index].offset_3 = (offset >> 32) & 0xFFFFFFFF; + IDT[index].ist = ist; + IDT[index].selector = 8; // assume for now that it's always in-kernel + IDT[index].zero = 0; + IDT[index].type_attr = type | (min_priv_level << 5) | 0x80; +} + +void* get_idt_fn(uint8_t index) { + struct IDTDescr* i = &IDT[index]; + return (uintptr_t)( ((uint64_t)i->offset_3 << 32) | ((uint64_t)i->offset_2 << 16) | (uint64_t)i->offset_1); +} + +void clear_idt_ent(uint8_t index); diff --git a/kernel/src/arch/x86_64/idt.h b/kernel/src/arch/x86_64/idt.h new file mode 100644 index 0000000..8dae756 --- /dev/null +++ b/kernel/src/arch/x86_64/idt.h @@ -0,0 +1,22 @@ +#include + +struct IDTDescr { + uint16_t offset_1; // offset bits 0..15 + uint16_t selector; // a code segment selector in GDT or LDT + uint8_t ist; // bits 0..2 holds Interrupt Stack Table offset, rest of bits zero. + uint8_t type_attr; // type and attributes + uint16_t offset_2; // offset bits 16..31 + uint32_t offset_3; // offset bits 32..63 + uint32_t zero; // reserved +}; + +enum GateType { + CALL64 = 0xC, + INT64 = 0xE, + TRAP64 = 0xF, +}; + +void init_idt(); +void set_idt_ent(uint8_t index, uint64_t offset, uint8_t ist, uint8_t min_priv_level, enum GateType type); +void* get_idt_fn(uint8_t index); +void clear_idt_ent(uint8_t index); diff --git a/kernel/src/arch/x86_64/idt.nasm b/kernel/src/arch/x86_64/idt.nasm new file mode 100644 index 0000000..cbe5f97 --- /dev/null +++ b/kernel/src/arch/x86_64/idt.nasm @@ -0,0 +1,20 @@ +extern IDT; + +section .rodata +align 8 +idtpointer: + dw (256*16) - 1 + dq IDT + +section .text +global init_idt +init_idt: + lidt [idtpointer] + ret + +global isr_wrapper +extern interrupt_handler +align 8 +isr_wrapper: + call interrupt_handler + iretq \ No newline at end of file diff --git a/kernel/src/arch/x86_64/interrupt.c b/kernel/src/arch/x86_64/interrupt.c new file mode 100644 index 0000000..faa9c92 --- /dev/null +++ b/kernel/src/arch/x86_64/interrupt.c @@ -0,0 +1,39 @@ +#include + +#include "idt.h" +#include "interrupt.h" + +typedef uint64_t uword_t; + +extern void isr_wrapper(); + +struct interrupt_frame +{ + uword_t ip; + uword_t cs; + uword_t flags; + uword_t sp; + uword_t ss; +}; + +void interrupt_handler() +{ + printf("interrupted\n"); + // panic("ee"); +} + + +void setup_ints() { + set_idt_ent(0x80, (uint64_t)&isr_wrapper, 0, 0, INT64); + init_idt(); + + typedef void (*MyFunctionType)(void); + MyFunctionType handler_0x80 = get_idt_fn(0x80); + printf("interrupt handler: %x\n", handler_0x80); + // interrupt_handler(0); + + + __asm__ volatile("int $0x80"); + + printf("interrupt handled!\n"); +} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/interrupt.h b/kernel/src/arch/x86_64/interrupt.h new file mode 100644 index 0000000..18972a5 --- /dev/null +++ b/kernel/src/arch/x86_64/interrupt.h @@ -0,0 +1 @@ +void setup_ints(); \ No newline at end of file