aboutsummaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/x86_64/include/arch/cpu/interrupts.hpp46
-rw-r--r--arch/x86_64/kapi/cpu.cpp21
-rw-r--r--arch/x86_64/kapi/system.cpp10
-rw-r--r--arch/x86_64/src/cpu/interrupts.cpp125
4 files changed, 137 insertions, 65 deletions
diff --git a/arch/x86_64/include/arch/cpu/interrupts.hpp b/arch/x86_64/include/arch/cpu/interrupts.hpp
index 8f156a4..08ecd9c 100644
--- a/arch/x86_64/include/arch/cpu/interrupts.hpp
+++ b/arch/x86_64/include/arch/cpu/interrupts.hpp
@@ -1,6 +1,8 @@
#ifndef TEACHOS_X86_64_CPU_INTERRUPTS_HPP
#define TEACHOS_X86_64_CPU_INTERRUPTS_HPP
+#include "kapi/memory.hpp"
+
#include "arch/cpu/segment_selector.hpp"
#include <array>
@@ -57,36 +59,36 @@ namespace arch::cpu
{
struct
{
- std::uint64_t r15;
- std::uint64_t r14;
- std::uint64_t r13;
- std::uint64_t r12;
- std::uint64_t r11;
- std::uint64_t r10;
- std::uint64_t r9;
- std::uint64_t r8;
- std::uint64_t rdi;
- std::uint64_t rsi;
- std::uint64_t rbp;
- std::uint64_t rdx;
- std::uint64_t rcx;
- std::uint64_t rbx;
- std::uint64_t rax;
+ std::uint64_t r15{};
+ std::uint64_t r14{};
+ std::uint64_t r13{};
+ std::uint64_t r12{};
+ std::uint64_t r11{};
+ std::uint64_t r10{};
+ std::uint64_t r9{};
+ std::uint64_t r8{};
+ std::uint64_t rdi{};
+ std::uint64_t rsi{};
+ std::uint64_t rbp{};
+ std::uint64_t rdx{};
+ std::uint64_t rcx{};
+ std::uint64_t rbx{};
+ std::uint64_t rax{};
} handler_saved;
struct
{
- std::uint64_t number;
- std::uint64_t error_code;
+ std::uint64_t number{};
+ std::uint64_t error_code{};
} interrupt;
struct
{
- std::uint64_t rip;
- std::uint64_t cs;
- std::uint64_t rflags;
- std::uint64_t rsp;
- std::uint64_t ss;
+ kapi::memory::linear_address rip{};
+ std::uint64_t cs{};
+ std::uint64_t rflags{};
+ kapi::memory::linear_address rsp{};
+ std::uint64_t ss{};
} cpu_saved;
};
diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp
index 2a0f8f7..693d328 100644
--- a/arch/x86_64/kapi/cpu.cpp
+++ b/arch/x86_64/kapi/cpu.cpp
@@ -1,8 +1,29 @@
#include "kapi/cpu.hpp"
+#include "kapi/system.hpp"
+
+#include "arch/cpu/initialization.hpp"
+#include "arch/cpu/interrupts.hpp"
+
+#include <atomic>
+
namespace kapi::cpu
{
+ auto init() -> void
+ {
+ auto static constinit is_initialized = std::atomic_flag{};
+
+ if (is_initialized.test_and_set())
+ {
+ system::panic("[x86_64] CPU has already been initialized.");
+ }
+
+ arch::cpu::initialize_descriptors();
+ arch::cpu::initialize_legacy_interrupts();
+ arch::cpu::enable_interrupts();
+ }
+
auto halt() -> void
{
asm volatile("1: hlt\njmp 1b");
diff --git a/arch/x86_64/kapi/system.cpp b/arch/x86_64/kapi/system.cpp
index 301169f..09c7152 100644
--- a/arch/x86_64/kapi/system.cpp
+++ b/arch/x86_64/kapi/system.cpp
@@ -1,16 +1,8 @@
#include "kapi/system.hpp"
-#include "arch/cpu/initialization.hpp"
-#include "arch/cpu/interrupts.hpp"
-
namespace kapi::system
{
- auto memory_initialized() -> void
- {
- arch::cpu::initialize_descriptors();
- arch::cpu::initialize_legacy_interrupts();
- arch::cpu::enable_interrupts();
- }
+ auto memory_initialized() -> void {}
} // namespace kapi::system \ No newline at end of file
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();
}
}