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.cpp125
1 files changed, 91 insertions, 34 deletions
diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp
index 048c461..6f66bbd 100644
--- a/arch/x86_64/src/cpu/interrupts.cpp
+++ b/arch/x86_64/src/cpu/interrupts.cpp
@@ -1,6 +1,7 @@
#include "arch/cpu/interrupts.hpp"
#include "kapi/cpu.hpp"
+#include "kapi/memory.hpp"
#include "arch/cpu/legacy_pic.hpp"
#include "arch/cpu/segment_selector.hpp"
@@ -14,38 +15,92 @@ 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
+ enum struct exception
{
- 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;
+ divide_error,
+ debug_exception,
+ non_maskable_interrupt,
+ breakpoint,
+ overflow,
+ bound_range_exceeded,
+ invalid_opcode,
+ device_not_available,
+ double_fault,
+ coprocessor_segment_overrun,
+ invalid_tss,
+ stack_segment_fault,
+ general_protection_fault,
+ page_fault,
+ x87_fpu_floating_point_error,
+ alignment_check,
+ machine_check,
+ simd_floating_point_error,
+ virtualization_exception,
+ control_protection_exception,
+ vmm_communication_exception,
+ security_exception,
+ };
+
+ constexpr auto pic_master_irq_start = 0x20;
+ constexpr auto pic_master_irq_end = pic_master_irq_start + 8;
+ constexpr auto pic_slave_irq_start = pic_master_irq_end;
+ constexpr auto pic_slave_irq_end = pic_slave_irq_start + 8;
+
+ constexpr auto to_exception_type(exception e)
+ {
+ switch (e)
+ {
+ case exception::divide_error:
+ case exception::x87_fpu_floating_point_error:
+ case exception::simd_floating_point_error:
+ return kapi::cpu::exception::type::arithmetic_error;
+ case exception::breakpoint:
+ return kapi::cpu::exception::type::breakpoint;
+ case exception::invalid_opcode:
+ return kapi::cpu::exception::type::illegal_instruction;
+ case exception::stack_segment_fault:
+ return kapi::cpu::exception::type::memory_access_fault;
+ case exception::general_protection_fault:
+ return kapi::cpu::exception::type::privilege_violation;
+ case exception::alignment_check:
+ return kapi::cpu::exception::type::alignment_fault;
+ default:
+ return kapi::cpu::exception::type::unknown;
+ }
+ }
- 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!");
+ auto dispatch_exception(interrupt_frame * frame) -> bool
+ {
+ auto type = to_exception_type(static_cast<exception>(frame->interrupt.number));
+ auto fault_address = kapi::memory::linear_address{};
+ auto instruction_pointer = frame->cpu_saved.rip;
- kapi::cpu::halt();
+ switch (type)
+ {
+ case kapi::cpu::exception::type::page_fault:
+ {
+ asm volatile("mov %%cr2, %0" : "=r"(fault_address));
+ auto present = (frame->interrupt.error_code & 0x1) != 0;
+ auto write = (frame->interrupt.error_code & 0x2) != 0;
+ auto user = (frame->interrupt.error_code & 0x4) != 0;
+
+ return kapi::cpu::get_exception_handler().handle(
+ {type, instruction_pointer, fault_address, present, write, user});
+ }
+ default:
+ return kapi::cpu::get_exception_handler().handle({type, instruction_pointer});
+ }
}
auto handle_legacy_interrupt(interrupt_frame * frame) -> void
{
kstd::println("[x86_64:SYS] Ignoring 8259 legacy interrupt {:#04x}", frame->interrupt.number);
+ if (frame->interrupt.number >= pic_slave_irq_start)
+ {
+ pic_slave_control_port::write(pic_end_of_interrupt);
+ }
pic_master_control_port::write(pic_end_of_interrupt);
- pic_slave_control_port::write(pic_end_of_interrupt);
}
} // namespace
@@ -55,23 +110,25 @@ 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))
+ auto [number, code] = frame->interrupt;
+
+ if (number < pic_master_irq_start && !dispatch_exception(frame))
{
- handle_legacy_interrupt(frame);
- return;
+ kstd::println(kstd::print_sink::stderr,
+ "[x86_64:CPU] Unhandled exception number {:#04x} received with code {:#04x}", number, code);
+ kapi::cpu::halt();
}
- switch (frame->interrupt.number)
+ if ((number >= pic_master_irq_start && number < pic_master_irq_end) ||
+ (number >= pic_slave_irq_start && number < pic_slave_irq_end))
{
- 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();
+ handle_legacy_interrupt(frame);
+ return;
}
+
+ kstd::println(kstd::print_sink::stderr, "[x86_64:CPU] Unhandled interrupt {:#04x} received with code {:#04x}",
+ frame->interrupt.number, frame->interrupt.error_code);
+ kapi::cpu::halt();
}
}