aboutsummaryrefslogtreecommitdiff
path: root/arch/x86_64/src/cpu/interrupts.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/src/cpu/interrupts.cpp')
-rw-r--r--arch/x86_64/src/cpu/interrupts.cpp94
1 files changed, 94 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..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 <kstd/print>
+
+#include <cstdint>
+
+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<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;
+ }
+
+} // namespace arch::cpu \ No newline at end of file