aboutsummaryrefslogtreecommitdiff
path: root/arch/x86_64/src/cpu/interrupts.cpp
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-03-21 09:06:25 +0100
committerFelix Morgner <felix.morgner@ost.ch>2026-03-21 09:06:25 +0100
commitfcf0cd73b0978c2db3e719542cf81d7d2c0fe24e (patch)
tree134b41bf36ea6b207ebccf6b6924f50c6405dda9 /arch/x86_64/src/cpu/interrupts.cpp
parent96f1511dbe2e80223732bcbef8068c3d5a330cee (diff)
parentcceaf717405059e8b02132d7c33f9fe3b2645b56 (diff)
downloadteachos-fcf0cd73b0978c2db3e719542cf81d7d2c0fe24e.tar.xz
teachos-fcf0cd73b0978c2db3e719542cf81d7d2c0fe24e.zip
Merge branch 'fmorgner/develop-BA-FS26/gdt_idt' into develop-BA-FS26
This patchset enables the use of interrupts. Specifically, it simplifies debugging by printing the fault address in case of a page fault.
Diffstat (limited to 'arch/x86_64/src/cpu/interrupts.cpp')
-rw-r--r--arch/x86_64/src/cpu/interrupts.cpp120
1 files changed, 120 insertions, 0 deletions
diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp
new file mode 100644
index 0000000..466389d
--- /dev/null
+++ b/arch/x86_64/src/cpu/interrupts.cpp
@@ -0,0 +1,120 @@
+#include "arch/cpu/interrupts.hpp"
+
+#include "kapi/cpu.hpp"
+
+#include "arch/cpu/segment_selector.hpp"
+
+#include <kstd/print>
+
+#include <cstdint>
+
+namespace arch::cpu
+{
+
+ namespace
+ {
+ 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
+ {
+ 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: {:#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);
+ 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();
+ }
+
+ auto handle_legacy_interrupt(interrupt_frame * frame) -> void
+ {
+ kstd::println("[x86_64:SYS] Ignoring 8259 legacy interrupt {:#04x}", frame->interrupt.number);
+ }
+ } // namespace
+
+ extern "C"
+ {
+ extern std::uintptr_t const isr_stub_table[256];
+
+ 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_number_page_fault:
+ handle_page_fault(frame);
+ break;
+ default:
+ 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();
+ }
+ }
+ }
+
+ interrupt_descriptor_table::interrupt_descriptor_table() noexcept
+ {
+ for (auto i = 0uz; i < 256; ++i)
+ {
+ m_descriptors[i] = gate_descriptor{
+ .offset_low = static_cast<std::uint16_t>(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<std::uint16_t>((isr_stub_table[i] >> 16) & 0xffff), // NOLINT(readability-magic-numbers)
+ .offset_high =
+ static_cast<std::uint32_t>((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;
+ }
+
+ auto enable_interrupts() -> void
+ {
+ asm volatile("sti");
+ }
+
+ auto disable_interrupts() -> void
+ {
+ asm volatile("cli");
+ }
+
+} // namespace arch::cpu \ No newline at end of file