From dd2dc3ef9a5318a0f7c7c35be59759ab08adc3dc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 20 Mar 2026 21:48:30 +0100 Subject: x86_64/cpu: implement basic interrupt handling --- arch/x86_64/src/cpu/interrupts.cpp | 94 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 arch/x86_64/src/cpu/interrupts.cpp (limited to 'arch/x86_64/src/cpu/interrupts.cpp') diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp new file mode 100644 index 0000000..08469c0 --- /dev/null +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -0,0 +1,94 @@ +#include "arch/cpu/interrupts.hpp" + +#include "kapi/cpu.hpp" + +#include "arch/cpu/segment_selector.hpp" + +#include + +#include + +namespace arch::cpu +{ + + namespace + { + constexpr auto isr_code_PF = 14; + + auto handle_page_fault(interrupt_frame * frame) -> void + { + auto fault_address = std::uintptr_t{}; + asm volatile("mov %%cr2, %0" : "=r"(fault_address)); + + auto const present = (frame->interrupt.error_code & 0x1) != 0; + auto const write = (frame->interrupt.error_code & 0x2) != 0; + auto const user = (frame->interrupt.error_code & 0x4) != 0; + + kstd::println(kstd::print_sink::stderr, "[x86_64:MMU] PAGE FAULT!"); + kstd::println(kstd::print_sink::stderr, "\tFault address: 0x{:x}", fault_address); + kstd::println(kstd::print_sink::stderr, "\tPresent: {}", present); + kstd::println(kstd::print_sink::stderr, "\tWrite: {}", write); + kstd::println(kstd::print_sink::stderr, "\tUser: {}", user); + kstd::println(kstd::print_sink::stderr, "\tRIP: {:#018x}", frame->cpu_saved.rip); + kstd::println(kstd::print_sink::stderr, "\tHalting the system now!"); + + kapi::cpu::halt(); + } + } // namespace + + extern "C" + { + extern std::uintptr_t const isr_stub_table[256]; + + auto interrupt_dispatch(interrupt_frame * frame) -> void + { + switch (frame->interrupt.number) + { + case isr_code_PF: + handle_page_fault(frame); + break; + default: + kstd::println(kstd::print_sink::stderr, "[x86_64:SYS] Unhandled interrupt {} received with code {}", + frame->interrupt.number, frame->interrupt.error_code); + kapi::cpu::halt(); + } + } + } + + interrupt_descriptor_table::interrupt_descriptor_table() noexcept + { + for (auto i = 0uz; i < 256; ++i) + { + m_descriptors[i] = gate_descriptor{ + .offset_low = static_cast(isr_stub_table[i] & 0xffff), // NOLINT(readability-magic-numbers) + .m_code_segment = segment_selector{0, false, 1}, + .interrupt_stack_table_selector = 0, + .gate_type = gate_type::interrupt_gate, + .descriptor_privilege_level = 0, + .present = true, + .offset_middle = + static_cast((isr_stub_table[i] >> 16) & 0xffff), // NOLINT(readability-magic-numbers) + .offset_high = + static_cast((isr_stub_table[i] >> 32) & 0xffff'ffff), // NOLINT(readability-magic-numbers) + }; + } + } + + auto interrupt_descriptor_table::load() const -> void + { + interrupt_descriptor_table_register{.limit = sizeof(m_descriptors) - 1, .base = m_descriptors.data()}.load(); + } + + auto interrupt_descriptor_table_register::load() const -> void + { + asm volatile("lidt %0" : : "m"(*this)); + } + + auto interrupt_descriptor_table_register::read() -> interrupt_descriptor_table_register + { + interrupt_descriptor_table_register idtr{}; + asm volatile("sidt %0" : : "m"(idtr)); + return idtr; + } + +} // namespace arch::cpu \ No newline at end of file -- cgit v1.2.3 From eb8074e9003034ef2186b62fc66b1073455be5de Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 21 Mar 2026 08:48:26 +0100 Subject: x86_64/cpu: fixup 8259 interrupts --- arch/x86_64/src/cpu/interrupts.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'arch/x86_64/src/cpu/interrupts.cpp') diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 08469c0..19cf6f4 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -91,4 +91,14 @@ namespace arch::cpu return idtr; } + auto enable_interrupts() -> void + { + asm volatile("sti"); + } + + auto disable_interrupts() -> void + { + asm volatile("cli"); + } + } // namespace arch::cpu \ No newline at end of file -- cgit v1.2.3 From 6a392e8e40f163470d7fb12e0846f2ec7bdee61a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 21 Mar 2026 09:02:12 +0100 Subject: x86_64/cpu: ignore 8259 interrupts --- arch/x86_64/src/cpu/interrupts.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src/cpu/interrupts.cpp') diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 19cf6f4..2eec026 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -13,7 +13,11 @@ namespace arch::cpu namespace { - constexpr auto isr_code_PF = 14; + constexpr auto isr_number_page_fault = 0x0e; + constexpr auto isr_number_legacy_start = 0x20; + constexpr auto isr_number_legacy_end = 0x29; + constexpr auto isr_number_cascade_start = 0x2c; + constexpr auto isr_number_cascade_end = 0x2f; auto handle_page_fault(interrupt_frame * frame) -> void { @@ -34,6 +38,11 @@ namespace arch::cpu kapi::cpu::halt(); } + + auto handle_legacy_interrupt(interrupt_frame * frame) -> void + { + kstd::println("[x86_64:SYS] Ignoring 8259 legacy interrupt {}", frame->interrupt.number); + } } // namespace extern "C" @@ -42,9 +51,16 @@ namespace arch::cpu auto interrupt_dispatch(interrupt_frame * frame) -> void { + if ((frame->interrupt.number >= isr_number_legacy_start && frame->interrupt.number <= isr_number_legacy_end) || + (frame->interrupt.number >= isr_number_cascade_start && frame->interrupt.number <= isr_number_cascade_end)) + { + handle_legacy_interrupt(frame); + return; + } + switch (frame->interrupt.number) { - case isr_code_PF: + case isr_number_page_fault: handle_page_fault(frame); break; default: -- cgit v1.2.3 From cceaf717405059e8b02132d7c33f9fe3b2645b56 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 21 Mar 2026 09:06:05 +0100 Subject: x86_64/cpu: log interrupt data in hex --- arch/x86_64/src/cpu/interrupts.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src/cpu/interrupts.cpp') diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 2eec026..466389d 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -29,7 +29,7 @@ namespace arch::cpu auto const user = (frame->interrupt.error_code & 0x4) != 0; kstd::println(kstd::print_sink::stderr, "[x86_64:MMU] PAGE FAULT!"); - kstd::println(kstd::print_sink::stderr, "\tFault address: 0x{:x}", fault_address); + kstd::println(kstd::print_sink::stderr, "\tFault address: {:#018x}", fault_address); kstd::println(kstd::print_sink::stderr, "\tPresent: {}", present); kstd::println(kstd::print_sink::stderr, "\tWrite: {}", write); kstd::println(kstd::print_sink::stderr, "\tUser: {}", user); @@ -41,7 +41,7 @@ namespace arch::cpu auto handle_legacy_interrupt(interrupt_frame * frame) -> void { - kstd::println("[x86_64:SYS] Ignoring 8259 legacy interrupt {}", frame->interrupt.number); + kstd::println("[x86_64:SYS] Ignoring 8259 legacy interrupt {:#04x}", frame->interrupt.number); } } // namespace @@ -64,7 +64,7 @@ namespace arch::cpu handle_page_fault(frame); break; default: - kstd::println(kstd::print_sink::stderr, "[x86_64:SYS] Unhandled interrupt {} received with code {}", + kstd::println(kstd::print_sink::stderr, "[x86_64:SYS] Unhandled interrupt {:#04x} received with code {:#04x}", frame->interrupt.number, frame->interrupt.error_code); kapi::cpu::halt(); } -- cgit v1.2.3