diff options
| -rw-r--r-- | arch/x86_64/include/arch/cpu/interrupts.hpp | 46 | ||||
| -rw-r--r-- | arch/x86_64/kapi/cpu.cpp | 21 | ||||
| -rw-r--r-- | arch/x86_64/kapi/system.cpp | 10 | ||||
| -rw-r--r-- | arch/x86_64/src/cpu/interrupts.cpp | 125 | ||||
| -rw-r--r-- | kapi/include/kapi/cpu.hpp | 7 | ||||
| -rw-r--r-- | kapi/include/kapi/cpu/exception.hpp | 60 | ||||
| -rw-r--r-- | kernel/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | kernel/include/kernel/cpu.hpp | 14 | ||||
| -rw-r--r-- | kernel/kapi/cpu.cpp | 30 | ||||
| -rw-r--r-- | kernel/src/cpu.cpp | 46 | ||||
| -rw-r--r-- | kernel/src/main.cpp | 5 |
11 files changed, 301 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(); } } diff --git a/kapi/include/kapi/cpu.hpp b/kapi/include/kapi/cpu.hpp index 05b84b7..1dd7cfe 100644 --- a/kapi/include/kapi/cpu.hpp +++ b/kapi/include/kapi/cpu.hpp @@ -1,6 +1,8 @@ #ifndef TEACHOS_KAPI_CPU_HPP #define TEACHOS_KAPI_CPU_HPP +#include "kapi/cpu/exception.hpp" + namespace kapi::cpu { //! @qualifier platform-defined @@ -8,6 +10,11 @@ namespace kapi::cpu //! //! This function terminates execution of the kernel. [[noreturn]] auto halt() -> void; + + //! @qualifier platform-defined + //! Perform early CPU initialization. + auto init() -> void; + } // namespace kapi::cpu #endif diff --git a/kapi/include/kapi/cpu/exception.hpp b/kapi/include/kapi/cpu/exception.hpp new file mode 100644 index 0000000..09e15a7 --- /dev/null +++ b/kapi/include/kapi/cpu/exception.hpp @@ -0,0 +1,60 @@ +#ifndef TEACHOS_KAPI_CPU_EXCEPTION_HPP +#define TEACHOS_KAPI_CPU_EXCEPTION_HPP + +// IWYU pragma: private, include "kapi/cpu.hpp" + +#include "kapi/memory.hpp" + +#include <cstdint> + +namespace kapi::cpu +{ + + struct exception + { + enum class type : std::uint8_t + { + unknown, + page_fault, + alignment_fault, + memory_access_fault, + illegal_instruction, + privilege_violation, + arithmetic_error, + breakpoint, + single_step, + }; + + //! The type of exception. + type type{}; + + //! The instruction pointer at the time of the exception. + kapi::memory::linear_address instruction_pointer{}; + + //! The memory address that caused the exception. + kapi::memory::linear_address access_address{}; + + //! Whether the page was present at the time of the exception. + bool is_present{}; + + //! Whether the exception was caused by a write access. + bool is_write_access{}; + + //! Whether the exception was caused by a user mode access. + bool is_user_mode{}; + }; + + struct exception_handler + { + virtual ~exception_handler() = default; + + virtual auto handle(exception const & context) -> bool = 0; + }; + + auto get_exception_handler() -> exception_handler &; + + auto set_exception_handler(exception_handler & handler) -> void; + +} // namespace kapi::cpu + +#endif
\ No newline at end of file diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 398022c..d9a5c75 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -2,6 +2,7 @@ add_executable("kernel" # Platform-independent KAPI implementation "kapi/boot_modules.cpp" "kapi/cio.cpp" + "kapi/cpu.cpp" "kapi/memory.cpp" "kapi/system.cpp" @@ -10,6 +11,7 @@ add_executable("kernel" "kstd/print.cpp" # Kernel Implementation + "src/cpu.cpp" "src/main.cpp" "src/memory/bitmap_allocator.cpp" "src/memory/block_list_allocator.cpp" diff --git a/kernel/include/kernel/cpu.hpp b/kernel/include/kernel/cpu.hpp new file mode 100644 index 0000000..d4e1ced --- /dev/null +++ b/kernel/include/kernel/cpu.hpp @@ -0,0 +1,14 @@ +#ifndef TEACHOS_KERNEL_CPU_HPP +#define TEACHOS_KERNEL_CPU_HPP + +namespace kernel::cpu +{ + + //! Initialize the kernel heap. + auto init() -> void; + + //! + +} // namespace kernel::cpu + +#endif
\ No newline at end of file diff --git a/kernel/kapi/cpu.cpp b/kernel/kapi/cpu.cpp new file mode 100644 index 0000000..2089098 --- /dev/null +++ b/kernel/kapi/cpu.cpp @@ -0,0 +1,30 @@ +#include "kapi/cpu.hpp" + +namespace kapi::cpu +{ + + namespace + { + struct null_exception_handler : exception_handler + { + auto handle(exception const &) -> bool override + { + return false; + } + } static constinit default_exception_handler; + + exception_handler * current_handler = &default_exception_handler; + + } // namespace + + auto get_exception_handler() -> exception_handler & + { + return *current_handler; + } + + auto set_exception_handler(exception_handler & handler) -> void + { + current_handler = &handler; + } + +} // namespace kapi::cpu
\ No newline at end of file diff --git a/kernel/src/cpu.cpp b/kernel/src/cpu.cpp new file mode 100644 index 0000000..fc460c9 --- /dev/null +++ b/kernel/src/cpu.cpp @@ -0,0 +1,46 @@ +#include "kernel/cpu.hpp" + +#include "kapi/cpu.hpp" +#include "kapi/system.hpp" + +#include <kstd/print> + +namespace kernel::cpu +{ + + namespace + { + struct exception_handler : kapi::cpu::exception_handler + { + auto handle(kapi::cpu::exception const & context) -> bool override + { + switch (context.type) + { + case kapi::cpu::exception::type::page_fault: + return handle_page_fault(context); + default: + return false; + } + } + + private: + auto handle_page_fault(kapi::cpu::exception const & context) -> bool + { + kstd::println(kstd::print_sink::stderr, "[OS:CPU] PAGE FAULT!"); + kstd::println(kstd::print_sink::stderr, "\tFault address: {:#018x}", context.access_address); + kstd::println(kstd::print_sink::stderr, "\tPresent: {}", context.is_present); + kstd::println(kstd::print_sink::stderr, "\tWrite: {}", context.is_write_access); + kstd::println(kstd::print_sink::stderr, "\tUser: {}", context.is_user_mode); + kstd::println(kstd::print_sink::stderr, "\tRIP: {:#018x}", context.instruction_pointer); + + kapi::system::panic("Halting the system due to an unrecoverable page fault."); + } + } static constinit handler; + } // namespace + + auto init() -> void + { + kapi::cpu::set_exception_handler(handler); + } + +} // namespace kernel::cpu
\ No newline at end of file diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index eb59402..0416ee9 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -1,8 +1,10 @@ #include "kapi/boot_modules.hpp" #include "kapi/cio.hpp" +#include "kapi/cpu.hpp" #include "kapi/memory.hpp" #include "kapi/system.hpp" +#include "kernel/cpu.hpp" #include "kernel/devices/storage/storage_management.hpp" #include "kernel/filesystem/device_file.hpp" #include "kernel/filesystem/file_descriptor_table.hpp" @@ -90,6 +92,9 @@ auto main() -> int kapi::cio::init(); kstd::println("[OS] IO subsystem initialized."); + kapi::cpu::init(); + kernel::cpu::init(); + kapi::memory::init(); kernel::memory::init_heap(kapi::memory::heap_base); kstd::println("[OS] Memory subsystem initialized."); |
