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.cpp177
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