From 4573bd84471845f36e485d8d7bdc9dbade943e7b Mon Sep 17 00:00:00 2001 From: Viktor Popp Date: Sun, 21 Jun 2026 15:17:01 +0200 Subject: [PATCH 1/2] kernel: Implement IDT --- .clang-format | 1 + kernel/Makefile | 1 + kernel/arch/x86/gdt.cpp | 2 +- kernel/arch/x86/idt.cpp | 35 +++++++++++++++++++ kernel/arch/x86/include/arch-private/gdt.hpp | 2 +- kernel/arch/x86/include/arch-private/idt.hpp | 36 ++++++++++++++++++++ kernel/arch/x86/system.cpp | 7 ++-- 7 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 kernel/arch/x86/idt.cpp create mode 100644 kernel/arch/x86/include/arch-private/idt.hpp diff --git a/.clang-format b/.clang-format index 5144b32..a59a8ca 100644 --- a/.clang-format +++ b/.clang-format @@ -9,6 +9,7 @@ AlignConsecutiveMacros: Enabled: true AllowShortEnumsOnASingleLine: false AllowShortFunctionsOnASingleLine: None +SpaceBeforeCpp11BracedList: true AllowShortLambdasOnASingleLine: None IndentWidth: 4 ContinuationIndentWidth: 4 diff --git a/kernel/Makefile b/kernel/Makefile index 936f353..31b15ef 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -11,6 +11,7 @@ include ../scripts/defaults.mk SRC := \ arch/x86/entry.asm \ arch/x86/gdt.cpp \ + arch/x86/idt.cpp \ arch/x86/system.cpp \ generic/boot.cpp \ generic/libc.c \ diff --git a/kernel/arch/x86/gdt.cpp b/kernel/arch/x86/gdt.cpp index 38a0a00..7ce3695 100644 --- a/kernel/arch/x86/gdt.cpp +++ b/kernel/arch/x86/gdt.cpp @@ -3,6 +3,6 @@ namespace arch { -Gdt gdt{}; +Gdt gdt {}; } // namespace arch diff --git a/kernel/arch/x86/idt.cpp b/kernel/arch/x86/idt.cpp new file mode 100644 index 0000000..2c911de --- /dev/null +++ b/kernel/arch/x86/idt.cpp @@ -0,0 +1,35 @@ +#include "arch-private/idt.hpp" +#include "log.hpp" +#include + +namespace arch +{ + +constinit Idt idt {}; + +void Idt::set_gate(uint8_t index, uintptr_t offset, uint8_t attributes) +{ + IdtEntry *entry = &table[index]; + + entry->offset_low = offset; + entry->segment_selector = 0x8; + entry->ist = 0; + entry->attributes = attributes; + entry->offset_mid = offset >> 16; + entry->offset_high = offset >> 32; + entry->reserved = 0; +}; + +void Idt::load() +{ + Idtr idtr { + .limit = sizeof(IdtEntry) * 255, + .offset = (uint64_t)&table, + }; + + __asm__ volatile("lidt %0" ::"m"(idtr) : "memory"); + + log::debug("Loaded IDT"); +} + +} // namespace arch diff --git a/kernel/arch/x86/include/arch-private/gdt.hpp b/kernel/arch/x86/include/arch-private/gdt.hpp index e8bc60c..1e454c1 100644 --- a/kernel/arch/x86/include/arch-private/gdt.hpp +++ b/kernel/arch/x86/include/arch-private/gdt.hpp @@ -63,7 +63,7 @@ struct __attribute__((packed)) Gdt void load() { - Gdtr gdtr{ + Gdtr gdtr { .limit = sizeof(Gdt) - 1, .base = reinterpret_cast(this), }; diff --git a/kernel/arch/x86/include/arch-private/idt.hpp b/kernel/arch/x86/include/arch-private/idt.hpp new file mode 100644 index 0000000..3e7ce2c --- /dev/null +++ b/kernel/arch/x86/include/arch-private/idt.hpp @@ -0,0 +1,36 @@ +#pragma once +#include + +namespace arch +{ + +struct __attribute__((packed)) IdtEntry +{ + uint16_t offset_low; + uint16_t segment_selector; + uint8_t ist; // Only bits 0..2 + uint8_t attributes; + uint16_t offset_mid; + uint32_t offset_high; + uint32_t reserved; +}; + +struct __attribute__((packed)) Idt +{ + constexpr Idt() {}; + + void set_gate(uint8_t index, uintptr_t offset, uint8_t attributes); + void load(); + + IdtEntry table[256] {}; +}; + +struct __attribute__((packed)) Idtr +{ + uint16_t limit; + uint64_t offset; +}; + +extern Idt idt; + +} // namespace arch diff --git a/kernel/arch/x86/system.cpp b/kernel/arch/x86/system.cpp index 0a7a3ef..9f5dd15 100644 --- a/kernel/arch/x86/system.cpp +++ b/kernel/arch/x86/system.cpp @@ -1,7 +1,6 @@ -#define LOG_MODULE "arch" - #include "arch/system.hpp" #include "arch-private/gdt.hpp" +#include "arch-private/idt.hpp" #include "log.hpp" #include "uart/uart.hpp" @@ -20,7 +19,7 @@ void uart_log_fn(const char *const message, std::size_t len) uart_logger); } -log::Sink uart_sink = log::Sink{nullptr, uart_log_fn}; +log::Sink uart_sink = log::Sink {nullptr, uart_log_fn}; } // namespace @@ -30,4 +29,6 @@ void arch::initialize() log::register_sink(&uart_sink); gdt.load(); + + idt.load(); } From e0b18bec9cc533b2326e2f4f17a122d723be52d7 Mon Sep 17 00:00:00 2001 From: Viktor Popp Date: Sun, 21 Jun 2026 17:06:10 +0200 Subject: [PATCH 2/2] kernel: Implement ISRs --- kernel/Makefile | 2 + kernel/arch/x86/idt.cpp | 21 ++++ kernel/arch/x86/include/arch-private/idt.hpp | 3 + kernel/arch/x86/include/arch-private/isr.hpp | 45 ++++++++ kernel/arch/x86/isr.asm | 106 +++++++++++++++++++ kernel/arch/x86/isr.cpp | 45 ++++++++ kernel/arch/x86/system.cpp | 4 +- kernel/generic/include/bits.hpp | 3 + 8 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 kernel/arch/x86/include/arch-private/isr.hpp create mode 100644 kernel/arch/x86/isr.asm create mode 100644 kernel/arch/x86/isr.cpp diff --git a/kernel/Makefile b/kernel/Makefile index 31b15ef..670e897 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -12,6 +12,8 @@ SRC := \ arch/x86/entry.asm \ arch/x86/gdt.cpp \ arch/x86/idt.cpp \ + arch/x86/isr.asm \ + arch/x86/isr.cpp \ arch/x86/system.cpp \ generic/boot.cpp \ generic/libc.c \ diff --git a/kernel/arch/x86/idt.cpp b/kernel/arch/x86/idt.cpp index 2c911de..a190d16 100644 --- a/kernel/arch/x86/idt.cpp +++ b/kernel/arch/x86/idt.cpp @@ -1,4 +1,6 @@ #include "arch-private/idt.hpp" +#include "arch-private/isr.hpp" +#include "bits.hpp" #include "log.hpp" #include @@ -32,4 +34,23 @@ void Idt::load() log::debug("Loaded IDT"); } +void Idt::init() +{ + int i = 0; + for (; i <= 31; i++) + set_gate(i, isr_stub_table[i], 0b10001111); // Present + Trap Gate + for (; i <= 255; i++) + set_gate(i, isr_stub_table[i], 0b10001110); // Present + Interrupt Gate +} + +void Idt::enable_gate(uint8_t idx) +{ + FLAG_SET(table[idx].attributes, 0b10000000); +} + +void Idt::disable_gate(uint8_t idx) +{ + FLAG_UNSET(table[idx].attributes, 0b10000000); +} + } // namespace arch diff --git a/kernel/arch/x86/include/arch-private/idt.hpp b/kernel/arch/x86/include/arch-private/idt.hpp index 3e7ce2c..7fde085 100644 --- a/kernel/arch/x86/include/arch-private/idt.hpp +++ b/kernel/arch/x86/include/arch-private/idt.hpp @@ -20,7 +20,10 @@ struct __attribute__((packed)) Idt constexpr Idt() {}; void set_gate(uint8_t index, uintptr_t offset, uint8_t attributes); + void init(); void load(); + void enable_gate(uint8_t index); + void disable_gate(uint8_t index); IdtEntry table[256] {}; }; diff --git a/kernel/arch/x86/include/arch-private/isr.hpp b/kernel/arch/x86/include/arch-private/isr.hpp new file mode 100644 index 0000000..a3203a3 --- /dev/null +++ b/kernel/arch/x86/include/arch-private/isr.hpp @@ -0,0 +1,45 @@ +#pragma once +#include + +namespace arch +{ + +struct __attribute__((packed)) InterruptFrame +{ + // Pushed by isr_commom + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rbp; + uint64_t rdi; + uint64_t rsi; + uint64_t rdx; + uint64_t rcx; + uint64_t rbx; + uint64_t rax; + + // Pushed by isr stub + uint64_t interrupt; + uint64_t error; // Sometimes pushed by CPU + + // Pushed by CPU + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; +}; + +using Isr = void (*)(InterruptFrame *frame); + +extern "C" uintptr_t isr_stub_table[]; + +void isr_init(); +void isr_register(uint8_t index, Isr handler); + +} // namespace arch diff --git a/kernel/arch/x86/isr.asm b/kernel/arch/x86/isr.asm new file mode 100644 index 0000000..beb7b89 --- /dev/null +++ b/kernel/arch/x86/isr.asm @@ -0,0 +1,106 @@ +extern isr_handler + +isr_common: + push rax + push rbx + push rcx + push rdx + push rsi + push rdi + push rbp + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + + ; puts pointer to the InterruptFrame in argument 1 + mov rdi, rsp + call isr_handler + + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rbp + pop rdi + pop rsi + pop rdx + pop rcx + pop rbx + pop rax + + ; pops the error code and interrupt number + add rsp, 16 + iretq + +; %1: replaced with the first argument +; %+: glues it together with the text before + +%macro isr_err_stub 1 +global isr_stub_%+%1 +isr_stub_%+%1: + push %1 + jmp isr_common +%endmacro + +%macro isr_no_err_stub 1 +global isr_stub_%+%1 +isr_stub_%+%1: + push 0 + push %1 + jmp isr_common +%endmacro + +isr_no_err_stub 0 +isr_no_err_stub 1 +isr_no_err_stub 2 +isr_no_err_stub 3 +isr_no_err_stub 4 +isr_no_err_stub 5 +isr_no_err_stub 6 +isr_no_err_stub 7 +isr_err_stub 8 +isr_no_err_stub 9 +isr_err_stub 10 +isr_err_stub 11 +isr_err_stub 12 +isr_err_stub 13 +isr_err_stub 14 +isr_no_err_stub 15 +isr_no_err_stub 16 +isr_err_stub 17 +isr_no_err_stub 18 +isr_no_err_stub 19 +isr_no_err_stub 20 +isr_err_stub 21 +isr_no_err_stub 22 +isr_no_err_stub 23 +isr_no_err_stub 24 +isr_no_err_stub 25 +isr_no_err_stub 26 +isr_no_err_stub 27 +isr_no_err_stub 28 +isr_err_stub 29 +isr_err_stub 30 +isr_no_err_stub 31 +%assign i 32 +%rep 224 + isr_no_err_stub %[i] +%assign i i+1 +%endrep + +global isr_stub_table +isr_stub_table: +%assign i 0 +%rep 256 + dq isr_stub_%+i +%assign i i+1 +%endrep diff --git a/kernel/arch/x86/isr.cpp b/kernel/arch/x86/isr.cpp new file mode 100644 index 0000000..8dcf3f1 --- /dev/null +++ b/kernel/arch/x86/isr.cpp @@ -0,0 +1,45 @@ +#include "arch-private/isr.hpp" +#include "arch-private/idt.hpp" +#include "arch/interrupts.hpp" +#include "log.hpp" +#include + +namespace arch +{ + +Isr isr_handlers[256] {}; + +extern "C" void isr_handler(InterruptFrame *regs) +{ + if (isr_handlers[regs->interrupt] != NULL) + { + isr_handlers[regs->interrupt](regs); + } + else if (regs->interrupt >= 32) + { + log::warn("Unhandled interrupt: %i", regs->interrupt); + } + else + { + log::error("unhandled exception: 0x%x", regs->interrupt); + halt(); + } +} + +void isr_init() +{ + uint8_t i = 0; + do + { + idt.enable_gate(i); + } while (i++ != 255); + log::debug("Enabled all IDT gates"); +} + +void isr_register(uint8_t index, Isr handler) +{ + isr_handlers[index] = handler; + log::debug("ISR handler registered for interrupt 0x%02X", index); +} + +} // namespace arch diff --git a/kernel/arch/x86/system.cpp b/kernel/arch/x86/system.cpp index 9f5dd15..6ea030c 100644 --- a/kernel/arch/x86/system.cpp +++ b/kernel/arch/x86/system.cpp @@ -1,6 +1,7 @@ #include "arch/system.hpp" #include "arch-private/gdt.hpp" #include "arch-private/idt.hpp" +#include "arch-private/isr.hpp" #include "log.hpp" #include "uart/uart.hpp" @@ -29,6 +30,7 @@ void arch::initialize() log::register_sink(&uart_sink); gdt.load(); - + idt.init(); idt.load(); + isr_init(); } diff --git a/kernel/generic/include/bits.hpp b/kernel/generic/include/bits.hpp index ff6cbf4..a906a5e 100644 --- a/kernel/generic/include/bits.hpp +++ b/kernel/generic/include/bits.hpp @@ -28,3 +28,6 @@ template class Bitfield int shift_; B mask_; }; + +#define FLAG_SET(x, flag) x |= (flag) +#define FLAG_UNSET(x, flag) x &= ~(flag)