diff options
Diffstat (limited to 'arch/x86_64/src/cpu/interrupts.cpp')
| -rw-r--r-- | arch/x86_64/src/cpu/interrupts.cpp | 177 |
1 files changed, 128 insertions, 49 deletions
diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 048c461..907f289 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -1,6 +1,8 @@ #include "arch/cpu/interrupts.hpp" #include "kapi/cpu.hpp" +#include "kapi/interrupts.hpp" +#include "kapi/memory.hpp" #include "arch/cpu/legacy_pic.hpp" #include "arch/cpu/segment_selector.hpp" @@ -14,38 +16,113 @@ 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; + enum struct exception + { + divide_error, + debug_exception, + non_maskable_interrupt, + breakpoint, + overflow, + bound_range_exceeded, + invalid_opcode, + device_not_available, + double_fault, + coprocessor_segment_overrun, + invalid_tss, + segment_not_present, + stack_segment_fault, + general_protection_fault, + page_fault, + x87_fpu_floating_point_error = 16, + alignment_check, + machine_check, + simd_floating_point_error, + virtualization_exception, + control_protection_exception, + hypervisor_injection_exception = 28, + vmm_communication_exception, + security_exception, + }; + + constexpr auto number_of_exception_vectors = 32u; + + 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 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::page_fault: + return kapi::cpu::exception::type::page_fault; + case exception::alignment_check: + return kapi::cpu::exception::type::alignment_fault; + default: + return kapi::cpu::exception::type::unknown; + } + } - auto handle_page_fault(interrupt_frame * frame) -> void + constexpr auto has_error_code(exception e) { - 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(); + switch (e) + { + case exception::double_fault: + case exception::invalid_tss: + case exception::segment_not_present: + case exception::stack_segment_fault: + case exception::general_protection_fault: + case exception::page_fault: + case exception::alignment_check: + case exception::control_protection_exception: + case exception::security_exception: + return true; + default: + return false; + } } - auto handle_legacy_interrupt(interrupt_frame * frame) -> void + auto dispatch_exception(interrupt_frame * frame) -> bool { - kstd::println("[x86_64:SYS] Ignoring 8259 legacy interrupt {:#04x}", frame->interrupt.number); + 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; + + 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::dispatch({type, instruction_pointer, fault_address, present, write, user}); + } + default: + return kapi::cpu::dispatch({type, instruction_pointer}); + } + } + auto acknowledge_pic_interrupt(interrupt_frame * frame) -> void + { + 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,22 +132,34 @@ 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 < number_of_exception_vectors) { - handle_legacy_interrupt(frame); - return; + if (!dispatch_exception(frame)) + { + if (has_error_code(static_cast<exception>(number))) + { + kstd::println(kstd::print_sink::stderr, + "[x86_64:CPU] Unhandled exception number {:#04x} received with code {:#04x}", number, code); + } + else + { + kstd::println(kstd::print_sink::stderr, "[x86_64:CPU] Unhandled exception number {:#04x} received", number); + } + } } - - switch (frame->interrupt.number) + else { - 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(); + auto irq_number = number - number_of_exception_vectors; + + if (kapi::interrupts::dispatch(irq_number) == kapi::interrupts::status::unhandled) + { + kstd::println(kstd::print_sink::stderr, "[x86_64:CPU] Unhandled interrupt {:#04x} (IRQ{})", number, + irq_number); + } + + acknowledge_pic_interrupt(frame); } } } @@ -83,7 +172,7 @@ namespace arch::cpu .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, + .gate_type = (i < 32 && i != 2) ? gate_type::trap_gate : gate_type::interrupt_gate, .descriptor_privilege_level = 0, .present = true, .offset_middle = @@ -111,14 +200,4 @@ 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 |
