From e32c889764b56aa0ed5373c07d0225c95ed502bb Mon Sep 17 00:00:00 2001 From: "marcel.braun" Date: Tue, 17 Feb 2026 19:20:03 +0100 Subject: Add information request to multiboot.s --- arch/x86_64/src/boot/multiboot.s | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/multiboot.s b/arch/x86_64/src/boot/multiboot.s index 7ccca56..37d8afe 100644 --- a/arch/x86_64/src/boot/multiboot.s +++ b/arch/x86_64/src/boot/multiboot.s @@ -18,6 +18,13 @@ multiboot_header_start: .long 3 .Lflags_end: .align 8 +.Linformation_request_start: + .word 1 + .word 0 + .long .Linformation_request_end - .Linformation_request_start + .long 3 +.Linformation_request_end: +.align 8 .Lend_start: .word 0 .word 0 -- cgit v1.2.3 From a20045fb209edc1e338039c28634c942e3113ea4 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Mon, 16 Mar 2026 21:06:12 +0100 Subject: Protect boot modules in region_allocator --- arch/x86_64/src/memory/region_allocator.cpp | 43 +++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 11 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index facb1f2..2690a7c 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -35,7 +35,7 @@ namespace arch::memory , m_kernel_end{kapi::memory::frame::containing(mem_info.image_range.second)} , m_multiboot_start{kapi::memory::frame::containing(mem_info.mbi_range.first)} , m_multiboot_end{kapi::memory::frame::containing(mem_info.mbi_range.second)} - // TODO BA-FS26: Protect MB2 boot modules + , m_multiboot_information{mem_info.mbi} { choose_next_region(); } @@ -76,19 +76,40 @@ namespace arch::memory } } - if (falls_within(m_next_frame, m_kernel_start, m_kernel_end)) + auto advanced = true; + while (advanced) { - m_next_frame = m_kernel_end + 1; - } + advanced = false; - if (falls_within(m_next_frame, m_multiboot_start, m_multiboot_end)) - { - m_next_frame = m_multiboot_end + 1; - } + if (falls_within(m_next_frame, m_kernel_start, m_kernel_end)) + { + m_next_frame = m_kernel_end + 1; + advanced = true; + break; + } - if (falls_within(m_next_frame, m_kernel_start, m_kernel_end)) - { - m_next_frame = m_kernel_end + 1; + if (falls_within(m_next_frame, m_multiboot_start, m_multiboot_end)) + { + m_next_frame = m_multiboot_end + 1; + advanced = true; + break; + } + + if (m_multiboot_information) + { + for (auto const & module : m_multiboot_information->modules()) + { + auto module_start = kapi::memory::frame::containing(kapi::memory::physical_address{module.start_address}); + auto module_end = kapi::memory::frame::containing(kapi::memory::physical_address{module.end_address}); + + if (falls_within(m_next_frame, module_start, module_end)) + { + m_next_frame = module_end + 1; + advanced = true; + break; + } + } + } } if (m_next_frame > last_frame(*m_current_region)) -- cgit v1.2.3 From 1f8cc6683f4e2ef2e311078f48a1b4477dadaaec Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 17 Mar 2026 22:21:33 +0100 Subject: x86_64/memory: fix region allocator logic --- arch/x86_64/src/memory/region_allocator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index 2690a7c..4ee3ca4 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -85,14 +85,14 @@ namespace arch::memory { m_next_frame = m_kernel_end + 1; advanced = true; - break; + continue; } if (falls_within(m_next_frame, m_multiboot_start, m_multiboot_end)) { m_next_frame = m_multiboot_end + 1; advanced = true; - break; + continue; } if (m_multiboot_information) -- cgit v1.2.3 From 12c0586ee15cadfa178e6982dc0f76b047cb2df9 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 18 Mar 2026 15:24:26 +0100 Subject: kapi/memory: remove page/frame size macros --- arch/x86_64/src/memory/kernel_mapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp index 08c32c5..e5bb7f8 100644 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -71,7 +71,7 @@ namespace arch::memory auto kernel_mapper::map_section(section_header_type const & section, std::string_view name, kapi::memory::page_mapper & mapper) -> void { - auto number_of_pages = (section.size + (PLATFORM_PAGE_SIZE - 1)) / PLATFORM_PAGE_SIZE; + auto number_of_pages = (section.size + (kapi::memory::page::size - 1)) / kapi::memory::page::size; auto linear_start_address = kapi::memory::linear_address{section.virtual_load_address}; auto physical_start_address = kapi::memory::physical_address{section.virtual_load_address & ~m_kernel_load_base}; -- cgit v1.2.3 From e7ccb96aecae7b231fb05818d7e45a767aebc31d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 18 Mar 2026 17:18:37 +0100 Subject: kstd: introduce strong type for memory amounts --- arch/x86_64/src/memory/kernel_mapper.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp index e5bb7f8..ced8a14 100644 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -6,6 +6,7 @@ #include "arch/boot/ld.hpp" #include +#include #include #include @@ -19,13 +20,14 @@ #include #include +using namespace std::string_view_literals; +using namespace kstd::units_literals; + namespace arch::memory { namespace { - using namespace std::string_view_literals; - constexpr auto static ignored_section_prefixes = std::array{ ".boot_"sv, }; @@ -71,7 +73,8 @@ namespace arch::memory auto kernel_mapper::map_section(section_header_type const & section, std::string_view name, kapi::memory::page_mapper & mapper) -> void { - auto number_of_pages = (section.size + (kapi::memory::page::size - 1)) / kapi::memory::page::size; + auto number_of_pages = + (kstd::units::bytes{section.size} + (kapi::memory::page::size - 1_B)) / kapi::memory::page::size; auto linear_start_address = kapi::memory::linear_address{section.virtual_load_address}; auto physical_start_address = kapi::memory::physical_address{section.virtual_load_address & ~m_kernel_load_base}; -- cgit v1.2.3 From 69b8b89542530eb7360dddd0875610f4cca9268b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 20 Mar 2026 17:34:56 +0100 Subject: x86_64/cpu: move gdt initialization code --- arch/x86_64/src/cpu/initialization.cpp | 122 +++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 arch/x86_64/src/cpu/initialization.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/initialization.cpp b/arch/x86_64/src/cpu/initialization.cpp new file mode 100644 index 0000000..aae4f1f --- /dev/null +++ b/arch/x86_64/src/cpu/initialization.cpp @@ -0,0 +1,122 @@ +#include "arch/cpu/initialization.hpp" + +#include "arch/cpu/global_descriptor_table.hpp" +#include "arch/cpu/segment_descriptor.hpp" +#include "arch/cpu/task_state_segment.hpp" + +#include + +#include +#include + +namespace arch::cpu +{ + + namespace + { + constexpr auto gdt_null_descriptor = segment_descriptor{}; + + constexpr auto gdt_kernel_code_descriptor = segment_descriptor{ + .limit_low = 0xffff, + .base_low = 0, + .accessed = false, + .read_write = false, + .direction_or_conforming = false, + .executable = true, + .type = segment_type::code_or_data, + .privilege_level = 0, + .present = true, + .limit_high = 0xf, + .long_mode = true, + .protected_mode = false, + .granularity = segment_granularity::page, + .base_high = 0, + }; + + constexpr auto gdt_kernel_data_descriptor = segment_descriptor{ + .limit_low = 0xffff, + .base_low = 0, + .accessed = false, + .read_write = true, + .direction_or_conforming = false, + .executable = false, + .type = segment_type::code_or_data, + .privilege_level = 0, + .present = true, + .limit_high = 0xf, + .long_mode = false, + .protected_mode = true, + .granularity = segment_granularity::page, + .base_high = 0, + }; + + constexpr auto gdt_user_code_descriptor = segment_descriptor{ + .limit_low = 0xffff, + .base_low = 0, + .accessed = false, + .read_write = false, + .direction_or_conforming = false, + .executable = true, + .type = segment_type::code_or_data, + .privilege_level = 3, + .present = true, + .limit_high = 0xf, + .long_mode = true, + .protected_mode = false, + .granularity = segment_granularity::page, + .base_high = 0, + }; + + constexpr auto gdt_user_data_descriptor = segment_descriptor{ + .limit_low = 0xffff, + .base_low = 0, + .accessed = false, + .read_write = true, + .direction_or_conforming = false, + .executable = false, + .type = segment_type::code_or_data, + .privilege_level = 3, + .present = true, + .limit_high = 0xf, + .long_mode = false, + .protected_mode = false, + .granularity = segment_granularity::page, + .base_high = 0, + }; + } // namespace + + auto initialize_descriptors() -> void + { + auto static tss = task_state_segment{}; + auto static tss_descriptor = system_segment_descriptor{ + { + .limit_low = (sizeof(tss) - 1) & 0xffff, // NOLINT(readability-magic-numbers) + .base_low = std::bit_cast(&tss) & 0xffffff, // NOLINT(readability-magic-numbers) + .accessed = false, + .read_write = false, + .direction_or_conforming = false, + .executable = false, + .type = segment_type::system, + .privilege_level = 0, + .present = true, + .limit_high = ((sizeof(tss) - 1) >> 16) & 0xf, // NOLINT(readability-magic-numbers) + .long_mode = false, + .protected_mode = false, + .granularity = segment_granularity::byte, + .base_high = (std::bit_cast(&tss) >> 24) & 0xff, // NOLINT(readability-magic-numbers) + }, + (std::bit_cast(&tss) >> 32) & 0xffff'ffff, // NOLINT(readability-magic-numbers) + }; + + auto static gdt = global_descriptor_table{ + gdt_null_descriptor, gdt_kernel_code_descriptor, gdt_kernel_data_descriptor, + gdt_user_code_descriptor, gdt_user_data_descriptor, tss_descriptor, + }; + + kstd::println("[x86_64:SYS] Reloading Global Descriptor Table."); + gdt.load(1, 2); + + kstd::println("[x86_64:SYS] TODO: initialize Interrupt Descriptor Table."); + } + +} // namespace arch::cpu -- cgit v1.2.3 From dd2dc3ef9a5318a0f7c7c35be59759ab08adc3dc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 20 Mar 2026 21:48:30 +0100 Subject: x86_64/cpu: implement basic interrupt handling --- arch/x86_64/src/cpu/initialization.cpp | 51 +++++++++------ arch/x86_64/src/cpu/interrupt_stubs.S | 112 +++++++++++++++++++++++++++++++++ arch/x86_64/src/cpu/interrupts.cpp | 94 +++++++++++++++++++++++++++ 3 files changed, 237 insertions(+), 20 deletions(-) create mode 100644 arch/x86_64/src/cpu/interrupt_stubs.S create mode 100644 arch/x86_64/src/cpu/interrupts.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/initialization.cpp b/arch/x86_64/src/cpu/initialization.cpp index aae4f1f..214687c 100644 --- a/arch/x86_64/src/cpu/initialization.cpp +++ b/arch/x86_64/src/cpu/initialization.cpp @@ -1,6 +1,7 @@ #include "arch/cpu/initialization.hpp" #include "arch/cpu/global_descriptor_table.hpp" +#include "arch/cpu/interrupts.hpp" #include "arch/cpu/segment_descriptor.hpp" #include "arch/cpu/task_state_segment.hpp" @@ -83,30 +84,38 @@ namespace arch::cpu .granularity = segment_granularity::page, .base_high = 0, }; + + constexpr auto make_tss_descriptor(task_state_segment const * tss_ptr) -> system_segment_descriptor + { + auto const address = std::bit_cast(tss_ptr); + auto const limit = sizeof(task_state_segment) - 1; + + return system_segment_descriptor{ + { + .limit_low = limit & 0xffff, // NOLINT(readability-magic-numbers) + .base_low = address & 0xffffff, // NOLINT(readability-magic-numbers) + .accessed = false, + .read_write = false, + .direction_or_conforming = false, + .executable = false, + .type = segment_type::system, + .privilege_level = 0, + .present = true, + .limit_high = (limit >> 16) & 0xf, // NOLINT(readability-magic-numbers) + .long_mode = false, + .protected_mode = false, + .granularity = segment_granularity::byte, + .base_high = (address >> 24) & 0xff, // NOLINT(readability-magic-numbers) + }, + (address >> 32) & 0xffff'ffff, // NOLINT(readability-magic-numbers) + }; + } } // namespace auto initialize_descriptors() -> void { auto static tss = task_state_segment{}; - auto static tss_descriptor = system_segment_descriptor{ - { - .limit_low = (sizeof(tss) - 1) & 0xffff, // NOLINT(readability-magic-numbers) - .base_low = std::bit_cast(&tss) & 0xffffff, // NOLINT(readability-magic-numbers) - .accessed = false, - .read_write = false, - .direction_or_conforming = false, - .executable = false, - .type = segment_type::system, - .privilege_level = 0, - .present = true, - .limit_high = ((sizeof(tss) - 1) >> 16) & 0xf, // NOLINT(readability-magic-numbers) - .long_mode = false, - .protected_mode = false, - .granularity = segment_granularity::byte, - .base_high = (std::bit_cast(&tss) >> 24) & 0xff, // NOLINT(readability-magic-numbers) - }, - (std::bit_cast(&tss) >> 32) & 0xffff'ffff, // NOLINT(readability-magic-numbers) - }; + auto static tss_descriptor = make_tss_descriptor(&tss); auto static gdt = global_descriptor_table{ gdt_null_descriptor, gdt_kernel_code_descriptor, gdt_kernel_data_descriptor, @@ -116,7 +125,9 @@ namespace arch::cpu kstd::println("[x86_64:SYS] Reloading Global Descriptor Table."); gdt.load(1, 2); - kstd::println("[x86_64:SYS] TODO: initialize Interrupt Descriptor Table."); + kstd::println("[x86_64:SYS] Initializing Interrupt Descriptor Table."); + auto static idt = interrupt_descriptor_table{}; + idt.load(); } } // namespace arch::cpu diff --git a/arch/x86_64/src/cpu/interrupt_stubs.S b/arch/x86_64/src/cpu/interrupt_stubs.S new file mode 100644 index 0000000..e59bdd2 --- /dev/null +++ b/arch/x86_64/src/cpu/interrupt_stubs.S @@ -0,0 +1,112 @@ +.altmacro + +.macro ISR_WITHOUT_ERROR_CODE vector + .global isr\vector + isr\vector: + pushq $0 + pushq $\vector + jmp common_interrupt_handler +.endm + +.macro ISR_WITH_ERROR_CODE vector + .global isr\vector + isr\vector: + pushq $\vector + jmp common_interrupt_handler +.endm + +.macro ISR_TABLE_ENTRY vector + .quad isr\vector +.endm + +.section .rodata +.global isr_stub_table +.align 16 + +isr_stub_table: +.set i, 0 +.rept 256 + ISR_TABLE_ENTRY %i + .set i, i + 1 +.endr + + +.section .text + +common_interrupt_handler: + push %rax + push %rbx + push %rcx + push %rdx + push %rbp + push %rsi + push %rdi + push %r8 + push %r9 + push %r10 + push %r11 + push %r12 + push %r13 + push %r14 + push %r15 + + mov %rsp, %rdi + call interrupt_dispatch + + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rdi + pop %rsi + pop %rbp + pop %rdx + pop %rcx + pop %rbx + pop %rax + + add $16, %rsp + iretq + +ISR_WITHOUT_ERROR_CODE 0 +ISR_WITHOUT_ERROR_CODE 1 +ISR_WITHOUT_ERROR_CODE 2 +ISR_WITHOUT_ERROR_CODE 3 +ISR_WITHOUT_ERROR_CODE 4 +ISR_WITHOUT_ERROR_CODE 5 +ISR_WITHOUT_ERROR_CODE 6 +ISR_WITHOUT_ERROR_CODE 7 +ISR_WITH_ERROR_CODE 8 +ISR_WITHOUT_ERROR_CODE 9 +ISR_WITH_ERROR_CODE 10 +ISR_WITH_ERROR_CODE 11 +ISR_WITH_ERROR_CODE 12 +ISR_WITH_ERROR_CODE 13 +ISR_WITH_ERROR_CODE 14 +ISR_WITHOUT_ERROR_CODE 15 +ISR_WITHOUT_ERROR_CODE 16 +ISR_WITH_ERROR_CODE 17 +ISR_WITHOUT_ERROR_CODE 18 +ISR_WITHOUT_ERROR_CODE 19 +ISR_WITHOUT_ERROR_CODE 20 +ISR_WITH_ERROR_CODE 21 +ISR_WITHOUT_ERROR_CODE 22 +ISR_WITHOUT_ERROR_CODE 23 +ISR_WITHOUT_ERROR_CODE 24 +ISR_WITHOUT_ERROR_CODE 25 +ISR_WITHOUT_ERROR_CODE 26 +ISR_WITHOUT_ERROR_CODE 27 +ISR_WITHOUT_ERROR_CODE 28 +ISR_WITH_ERROR_CODE 29 +ISR_WITH_ERROR_CODE 30 +ISR_WITHOUT_ERROR_CODE 31 + +.set i, 32 +.rept 256 - 32 + ISR_WITHOUT_ERROR_CODE %i + .set i, i + 1 +.endr diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp new file mode 100644 index 0000000..08469c0 --- /dev/null +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -0,0 +1,94 @@ +#include "arch/cpu/interrupts.hpp" + +#include "kapi/cpu.hpp" + +#include "arch/cpu/segment_selector.hpp" + +#include + +#include + +namespace arch::cpu +{ + + namespace + { + constexpr auto isr_code_PF = 14; + + auto handle_page_fault(interrupt_frame * frame) -> void + { + 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: 0x{:x}", 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(); + } + } // namespace + + extern "C" + { + extern std::uintptr_t const isr_stub_table[256]; + + auto interrupt_dispatch(interrupt_frame * frame) -> void + { + switch (frame->interrupt.number) + { + case isr_code_PF: + handle_page_fault(frame); + break; + default: + kstd::println(kstd::print_sink::stderr, "[x86_64:SYS] Unhandled interrupt {} received with code {}", + frame->interrupt.number, frame->interrupt.error_code); + kapi::cpu::halt(); + } + } + } + + interrupt_descriptor_table::interrupt_descriptor_table() noexcept + { + for (auto i = 0uz; i < 256; ++i) + { + m_descriptors[i] = gate_descriptor{ + .offset_low = static_cast(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, + .descriptor_privilege_level = 0, + .present = true, + .offset_middle = + static_cast((isr_stub_table[i] >> 16) & 0xffff), // NOLINT(readability-magic-numbers) + .offset_high = + static_cast((isr_stub_table[i] >> 32) & 0xffff'ffff), // NOLINT(readability-magic-numbers) + }; + } + } + + auto interrupt_descriptor_table::load() const -> void + { + interrupt_descriptor_table_register{.limit = sizeof(m_descriptors) - 1, .base = m_descriptors.data()}.load(); + } + + auto interrupt_descriptor_table_register::load() const -> void + { + asm volatile("lidt %0" : : "m"(*this)); + } + + auto interrupt_descriptor_table_register::read() -> interrupt_descriptor_table_register + { + interrupt_descriptor_table_register idtr{}; + asm volatile("sidt %0" : : "m"(idtr)); + return idtr; + } + +} // namespace arch::cpu \ No newline at end of file -- cgit v1.2.3 From eb8074e9003034ef2186b62fc66b1073455be5de Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 21 Mar 2026 08:48:26 +0100 Subject: x86_64/cpu: fixup 8259 interrupts --- arch/x86_64/src/cpu/initialization.cpp | 37 ++++++++++++++++++++++++++++++++++ arch/x86_64/src/cpu/interrupts.cpp | 10 +++++++++ 2 files changed, 47 insertions(+) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/initialization.cpp b/arch/x86_64/src/cpu/initialization.cpp index 214687c..85da38d 100644 --- a/arch/x86_64/src/cpu/initialization.cpp +++ b/arch/x86_64/src/cpu/initialization.cpp @@ -4,6 +4,7 @@ #include "arch/cpu/interrupts.hpp" #include "arch/cpu/segment_descriptor.hpp" #include "arch/cpu/task_state_segment.hpp" +#include "arch/device_io/port_io.hpp" #include @@ -130,4 +131,40 @@ namespace arch::cpu idt.load(); } + auto initialize_legacy_interrupts() -> void + { + using pic_master_control_port = io::port<0x20, std::uint8_t, io::port_read, io::port_write>; + using pic_master_data_port = io::port<0x21, std::uint8_t, io::port_read, io::port_write>; + using pic_slave_control_port = io::port<0xa0, std::uint8_t, io::port_read, io::port_write>; + using pic_slave_data_port = io::port<0xa1, std::uint8_t, io::port_read, io::port_write>; + + constexpr auto pic_init_command = std::uint8_t{0x11}; + constexpr auto pic_master_offset = std::uint8_t{0x20}; + constexpr auto pic_slave_offset = std::uint8_t{0x28}; + constexpr auto pic_cascade_address = std::uint8_t{0x04}; + constexpr auto pic_cascade_slave_identity = std::uint8_t{0x02}; + constexpr auto pic_use_8086_mode = std::uint8_t{0x01}; + constexpr auto pic_master_mask = std::uint8_t{0xfb}; + constexpr auto pic_slave_mask = std::uint8_t{0xff}; + constexpr auto pic_timer_mask = std::uint8_t{0x01}; + + pic_master_control_port::write(pic_init_command); + pic_slave_control_port::write(pic_init_command); + + pic_master_data_port::write(pic_master_offset); + pic_slave_data_port::write(pic_slave_offset); + + pic_master_data_port::write(pic_cascade_address); + pic_slave_data_port::write(pic_cascade_slave_identity); + + pic_master_data_port::write(pic_use_8086_mode); + pic_slave_data_port::write(pic_use_8086_mode); + + pic_master_data_port::write(pic_master_mask); + pic_slave_data_port::write(pic_slave_mask); + + auto const current_master_mask = pic_master_data_port::read(); + pic_master_data_port::write(current_master_mask | pic_timer_mask); + } + } // namespace arch::cpu diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 08469c0..19cf6f4 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -91,4 +91,14 @@ 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 -- cgit v1.2.3 From 6a392e8e40f163470d7fb12e0846f2ec7bdee61a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 21 Mar 2026 09:02:12 +0100 Subject: x86_64/cpu: ignore 8259 interrupts --- arch/x86_64/src/cpu/initialization.cpp | 8 ++------ arch/x86_64/src/cpu/interrupts.cpp | 20 ++++++++++++++++++-- 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/initialization.cpp b/arch/x86_64/src/cpu/initialization.cpp index 85da38d..5f4703d 100644 --- a/arch/x86_64/src/cpu/initialization.cpp +++ b/arch/x86_64/src/cpu/initialization.cpp @@ -144,9 +144,8 @@ namespace arch::cpu constexpr auto pic_cascade_address = std::uint8_t{0x04}; constexpr auto pic_cascade_slave_identity = std::uint8_t{0x02}; constexpr auto pic_use_8086_mode = std::uint8_t{0x01}; - constexpr auto pic_master_mask = std::uint8_t{0xfb}; - constexpr auto pic_slave_mask = std::uint8_t{0xff}; - constexpr auto pic_timer_mask = std::uint8_t{0x01}; + constexpr auto pic_master_mask = std::uint8_t{0x00}; + constexpr auto pic_slave_mask = std::uint8_t{0x00}; pic_master_control_port::write(pic_init_command); pic_slave_control_port::write(pic_init_command); @@ -162,9 +161,6 @@ namespace arch::cpu pic_master_data_port::write(pic_master_mask); pic_slave_data_port::write(pic_slave_mask); - - auto const current_master_mask = pic_master_data_port::read(); - pic_master_data_port::write(current_master_mask | pic_timer_mask); } } // namespace arch::cpu diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 19cf6f4..2eec026 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -13,7 +13,11 @@ namespace arch::cpu namespace { - constexpr auto isr_code_PF = 14; + 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 { @@ -34,6 +38,11 @@ namespace arch::cpu kapi::cpu::halt(); } + + auto handle_legacy_interrupt(interrupt_frame * frame) -> void + { + kstd::println("[x86_64:SYS] Ignoring 8259 legacy interrupt {}", frame->interrupt.number); + } } // namespace extern "C" @@ -42,9 +51,16 @@ 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)) + { + handle_legacy_interrupt(frame); + return; + } + switch (frame->interrupt.number) { - case isr_code_PF: + case isr_number_page_fault: handle_page_fault(frame); break; default: -- cgit v1.2.3 From cceaf717405059e8b02132d7c33f9fe3b2645b56 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 21 Mar 2026 09:06:05 +0100 Subject: x86_64/cpu: log interrupt data in hex --- arch/x86_64/src/cpu/interrupts.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 2eec026..466389d 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -29,7 +29,7 @@ namespace arch::cpu 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: 0x{:x}", fault_address); + 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); @@ -41,7 +41,7 @@ namespace arch::cpu auto handle_legacy_interrupt(interrupt_frame * frame) -> void { - kstd::println("[x86_64:SYS] Ignoring 8259 legacy interrupt {}", frame->interrupt.number); + kstd::println("[x86_64:SYS] Ignoring 8259 legacy interrupt {:#04x}", frame->interrupt.number); } } // namespace @@ -64,7 +64,7 @@ namespace arch::cpu handle_page_fault(frame); break; default: - kstd::println(kstd::print_sink::stderr, "[x86_64:SYS] Unhandled interrupt {} received with code {}", + 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(); } -- cgit v1.2.3 From c9ce8625dd80f701e280f90cb30c30f8663473e9 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sat, 21 Mar 2026 10:13:17 +0100 Subject: x86_64/cpu: fixup 8259 interrupt handling We now mask the timer interrupt and ensure we are informing the PIC about us having handled the interrupt. --- arch/x86_64/src/cpu/initialization.cpp | 12 +++++------- arch/x86_64/src/cpu/interrupts.cpp | 4 ++++ 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/initialization.cpp b/arch/x86_64/src/cpu/initialization.cpp index 5f4703d..878fa07 100644 --- a/arch/x86_64/src/cpu/initialization.cpp +++ b/arch/x86_64/src/cpu/initialization.cpp @@ -2,9 +2,9 @@ #include "arch/cpu/global_descriptor_table.hpp" #include "arch/cpu/interrupts.hpp" +#include "arch/cpu/legacy_pic.hpp" #include "arch/cpu/segment_descriptor.hpp" #include "arch/cpu/task_state_segment.hpp" -#include "arch/device_io/port_io.hpp" #include @@ -133,18 +133,13 @@ namespace arch::cpu auto initialize_legacy_interrupts() -> void { - using pic_master_control_port = io::port<0x20, std::uint8_t, io::port_read, io::port_write>; - using pic_master_data_port = io::port<0x21, std::uint8_t, io::port_read, io::port_write>; - using pic_slave_control_port = io::port<0xa0, std::uint8_t, io::port_read, io::port_write>; - using pic_slave_data_port = io::port<0xa1, std::uint8_t, io::port_read, io::port_write>; - constexpr auto pic_init_command = std::uint8_t{0x11}; constexpr auto pic_master_offset = std::uint8_t{0x20}; constexpr auto pic_slave_offset = std::uint8_t{0x28}; constexpr auto pic_cascade_address = std::uint8_t{0x04}; constexpr auto pic_cascade_slave_identity = std::uint8_t{0x02}; constexpr auto pic_use_8086_mode = std::uint8_t{0x01}; - constexpr auto pic_master_mask = std::uint8_t{0x00}; + constexpr auto pic_master_mask = std::uint8_t{0x01}; constexpr auto pic_slave_mask = std::uint8_t{0x00}; pic_master_control_port::write(pic_init_command); @@ -161,6 +156,9 @@ namespace arch::cpu pic_master_data_port::write(pic_master_mask); pic_slave_data_port::write(pic_slave_mask); + + pic_master_data_port::write(pic_master_mask); + pic_slave_data_port::write(pic_slave_mask); } } // namespace arch::cpu diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 466389d..048c461 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -2,6 +2,7 @@ #include "kapi/cpu.hpp" +#include "arch/cpu/legacy_pic.hpp" #include "arch/cpu/segment_selector.hpp" #include @@ -42,6 +43,9 @@ namespace arch::cpu auto handle_legacy_interrupt(interrupt_frame * frame) -> void { kstd::println("[x86_64:SYS] Ignoring 8259 legacy interrupt {:#04x}", frame->interrupt.number); + + pic_master_control_port::write(pic_end_of_interrupt); + pic_slave_control_port::write(pic_end_of_interrupt); } } // namespace -- cgit v1.2.3 From cb60cdebdc36dd2358fe1ce06eec197e213af491 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 24 Mar 2026 17:35:54 +0100 Subject: kapi/cpu: introduce CPU API --- arch/x86_64/src/cpu/interrupts.cpp | 125 +++++++++++++++++++++++++++---------- 1 file changed, 91 insertions(+), 34 deletions(-) (limited to 'arch/x86_64/src') 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(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(); } } -- cgit v1.2.3 From 42895684b631380c8aca94f82209297ac0c0e5f2 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 24 Mar 2026 17:44:21 +0100 Subject: kapi: extract interrupt enablement --- arch/x86_64/src/cpu/interrupts.cpp | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 6f66bbd..dc236e6 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -168,14 +168,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 -- cgit v1.2.3 From 363a6d701d4998137fcc123059f9749098ac7d75 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 25 Mar 2026 08:12:49 +0100 Subject: x86_64/cpu: fix exception enum --- arch/x86_64/src/cpu/interrupts.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index dc236e6..e578aa2 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -28,15 +28,17 @@ namespace arch::cpu double_fault, coprocessor_segment_overrun, invalid_tss, + segment_not_present, stack_segment_fault, general_protection_fault, page_fault, - x87_fpu_floating_point_error, + 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, }; @@ -62,6 +64,8 @@ namespace arch::cpu 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: -- cgit v1.2.3 From a82416648d148152338dc612c25bf8dff428e773 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 25 Mar 2026 16:39:13 +0100 Subject: kapi: introduce cpu::interrupt_handler --- arch/x86_64/src/cpu/interrupts.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index e578aa2..1f65336 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -46,7 +46,6 @@ namespace arch::cpu 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) { @@ -96,10 +95,8 @@ namespace arch::cpu } } - auto handle_legacy_interrupt(interrupt_frame * frame) -> void + auto acknowledge_pic_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); @@ -120,19 +117,13 @@ namespace arch::cpu { kstd::println(kstd::print_sink::stderr, "[x86_64:CPU] Unhandled exception number {:#04x} received with code {:#04x}", number, code); - kapi::cpu::halt(); } - - if ((number >= pic_master_irq_start && number < pic_master_irq_end) || - (number >= pic_slave_irq_start && number < pic_slave_irq_end)) + else if (number >= pic_master_irq_start && kapi::cpu::dispatch_interrupt(number) == kapi::cpu::status::unhandled) { - handle_legacy_interrupt(frame); - return; + kstd::println(kstd::print_sink::stderr, "[x86_64:CPU] Unhandled interrupt {:#04x}", number); } - 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(); + acknowledge_pic_interrupt(frame); } } -- cgit v1.2.3 From 953768ed7af8692818f742566864bfd264a824a2 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 25 Mar 2026 18:37:55 +0100 Subject: x86_64/cpu: fix interrupt gate types --- arch/x86_64/src/cpu/interrupts.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 1f65336..1f12898 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -135,7 +135,7 @@ namespace arch::cpu .offset_low = static_cast(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 = -- cgit v1.2.3 From 6a1addc7663bfae3306abb8800d3e387b3f66e82 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 25 Mar 2026 18:46:20 +0100 Subject: x86_64/cpu: improve exception logging --- arch/x86_64/src/cpu/interrupts.cpp | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 1f12898..4e52d71 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -43,6 +43,8 @@ namespace arch::cpu 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; @@ -72,6 +74,25 @@ namespace arch::cpu } } + constexpr auto has_error_code(exception e) + { + 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 dispatch_exception(interrupt_frame * frame) -> bool { auto type = to_exception_type(static_cast(frame->interrupt.number)); @@ -113,12 +134,20 @@ namespace arch::cpu { auto [number, code] = frame->interrupt; - if (number < pic_master_irq_start && !dispatch_exception(frame)) + if (number < number_of_exception_vectors && !dispatch_exception(frame)) { - kstd::println(kstd::print_sink::stderr, - "[x86_64:CPU] Unhandled exception number {:#04x} received with code {:#04x}", number, code); + if (has_error_code(static_cast(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); + } } - else if (number >= pic_master_irq_start && kapi::cpu::dispatch_interrupt(number) == kapi::cpu::status::unhandled) + else if (number >= number_of_exception_vectors && + kapi::cpu::dispatch_interrupt(number) == kapi::cpu::status::unhandled) { kstd::println(kstd::print_sink::stderr, "[x86_64:CPU] Unhandled interrupt {:#04x}", number); } -- cgit v1.2.3 From 8d06763f47e7b7c93af2a55f6bd2dbc4aa9abfa2 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 26 Mar 2026 16:10:50 +0100 Subject: kapi/cpu: simplify exception handling --- arch/x86_64/src/cpu/interrupts.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 4e52d71..9ee3ce8 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -108,11 +108,10 @@ namespace arch::cpu 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}); + return kapi::cpu::dispatch({type, instruction_pointer, fault_address, present, write, user}); } default: - return kapi::cpu::get_exception_handler().handle({type, instruction_pointer}); + return kapi::cpu::dispatch({type, instruction_pointer}); } } -- cgit v1.2.3 From 00a77644192642e06462c11479a5c0e9bd859e9a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 26 Mar 2026 16:35:32 +0100 Subject: kapi: extract interrupts API --- arch/x86_64/src/cpu/interrupts.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 9ee3ce8..2f23f07 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/interrupts.hpp" #include "kapi/memory.hpp" #include "arch/cpu/legacy_pic.hpp" @@ -146,7 +147,7 @@ namespace arch::cpu } } else if (number >= number_of_exception_vectors && - kapi::cpu::dispatch_interrupt(number) == kapi::cpu::status::unhandled) + kapi::interrupts::dispatch(number) == kapi::interrupts::status::unhandled) { kstd::println(kstd::print_sink::stderr, "[x86_64:CPU] Unhandled interrupt {:#04x}", number); } -- cgit v1.2.3 From aa68f53d2502e0ea81c8e9c95e37d9847cb6cb16 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 26 Mar 2026 17:15:26 +0100 Subject: arch/cpu: fix interrupt dispatch --- arch/x86_64/src/cpu/interrupts.cpp | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 2f23f07..907f289 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -134,25 +134,33 @@ namespace arch::cpu { auto [number, code] = frame->interrupt; - if (number < number_of_exception_vectors && !dispatch_exception(frame)) + if (number < number_of_exception_vectors) { - if (has_error_code(static_cast(number))) + if (!dispatch_exception(frame)) { - 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); + if (has_error_code(static_cast(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); + } } } - else if (number >= number_of_exception_vectors && - kapi::interrupts::dispatch(number) == kapi::interrupts::status::unhandled) + else { - kstd::println(kstd::print_sink::stderr, "[x86_64:CPU] Unhandled interrupt {:#04x}", number); - } + auto irq_number = number - number_of_exception_vectors; - acknowledge_pic_interrupt(frame); + 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); + } } } -- cgit v1.2.3 From b84c4c9d8c90f3d3fd5a60de282278912fad2f04 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 2 Apr 2026 13:59:27 +0200 Subject: x86_64/devices: implement ISA bus stub --- arch/x86_64/src/bus/isa.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 arch/x86_64/src/bus/isa.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/bus/isa.cpp b/arch/x86_64/src/bus/isa.cpp new file mode 100644 index 0000000..3fe4f6f --- /dev/null +++ b/arch/x86_64/src/bus/isa.cpp @@ -0,0 +1,56 @@ +#include "arch/bus/isa.hpp" + +#include "kapi/devices.hpp" +#include "kapi/devices/device.hpp" +#include "kapi/system.hpp" + +#include +#include +#include + +#include +#include + +namespace arch::bus +{ + + isa::isa() + : kapi::devices::bus(kapi::devices::allocate_major_number(), 0, "isa") + {} + + auto isa::add_child(kstd::unique_ptr child) -> void + { + auto observer = m_observers.emplace_back(child.get()); + m_devices.push_back(std::move(child)); + + if (m_initialized) + { + kstd::println("[bus:{}} Initializing child device '{}'", name(), observer->name()); + if (!observer->init()) + { + kapi::system::panic("[x86_64:devices] Failed to initialize child device"); + } + } + } + + auto isa::children() const -> kstd::vector> const & + { + return m_observers; + } + + auto isa::init() -> bool + { + if (m_initialized) + { + kapi::system::panic("[x86_64:devices] ISA bus already initialized!"); + } + + m_initialized = std::ranges::fold_left(m_devices, true, [](bool acc, auto & child) -> bool { + kstd::println("[x86_64:devices] Initializing child device '{}'", child->name()); + return acc && child->init(); + }); + + return m_initialized; + } + +} // namespace arch::bus \ No newline at end of file -- cgit v1.2.3 From 66ffd2ad8c793c4eea1527848fe4772e42595718 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 2 Apr 2026 14:24:52 +0200 Subject: kapi: extract common bus code --- arch/x86_64/src/bus/isa.cpp | 44 -------------------------------------------- 1 file changed, 44 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/bus/isa.cpp b/arch/x86_64/src/bus/isa.cpp index 3fe4f6f..2ad4d21 100644 --- a/arch/x86_64/src/bus/isa.cpp +++ b/arch/x86_64/src/bus/isa.cpp @@ -1,15 +1,6 @@ #include "arch/bus/isa.hpp" #include "kapi/devices.hpp" -#include "kapi/devices/device.hpp" -#include "kapi/system.hpp" - -#include -#include -#include - -#include -#include namespace arch::bus { @@ -18,39 +9,4 @@ namespace arch::bus : kapi::devices::bus(kapi::devices::allocate_major_number(), 0, "isa") {} - auto isa::add_child(kstd::unique_ptr child) -> void - { - auto observer = m_observers.emplace_back(child.get()); - m_devices.push_back(std::move(child)); - - if (m_initialized) - { - kstd::println("[bus:{}} Initializing child device '{}'", name(), observer->name()); - if (!observer->init()) - { - kapi::system::panic("[x86_64:devices] Failed to initialize child device"); - } - } - } - - auto isa::children() const -> kstd::vector> const & - { - return m_observers; - } - - auto isa::init() -> bool - { - if (m_initialized) - { - kapi::system::panic("[x86_64:devices] ISA bus already initialized!"); - } - - m_initialized = std::ranges::fold_left(m_devices, true, [](bool acc, auto & child) -> bool { - kstd::println("[x86_64:devices] Initializing child device '{}'", child->name()); - return acc && child->init(); - }); - - return m_initialized; - } - } // namespace arch::bus \ No newline at end of file -- cgit v1.2.3 From ab4c59912c526d515e6e72188c08a7f92e5573e8 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 2 Apr 2026 15:07:54 +0200 Subject: x86_64: implement legacy PIT driver --- arch/x86_64/src/cpu/initialization.cpp | 2 +- arch/x86_64/src/devices/legacy_pit.cpp | 54 ++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 arch/x86_64/src/devices/legacy_pit.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/initialization.cpp b/arch/x86_64/src/cpu/initialization.cpp index 878fa07..b808c76 100644 --- a/arch/x86_64/src/cpu/initialization.cpp +++ b/arch/x86_64/src/cpu/initialization.cpp @@ -139,7 +139,7 @@ namespace arch::cpu constexpr auto pic_cascade_address = std::uint8_t{0x04}; constexpr auto pic_cascade_slave_identity = std::uint8_t{0x02}; constexpr auto pic_use_8086_mode = std::uint8_t{0x01}; - constexpr auto pic_master_mask = std::uint8_t{0x01}; + constexpr auto pic_master_mask = std::uint8_t{0x00}; constexpr auto pic_slave_mask = std::uint8_t{0x00}; pic_master_control_port::write(pic_init_command); diff --git a/arch/x86_64/src/devices/legacy_pit.cpp b/arch/x86_64/src/devices/legacy_pit.cpp new file mode 100644 index 0000000..f2fb70e --- /dev/null +++ b/arch/x86_64/src/devices/legacy_pit.cpp @@ -0,0 +1,54 @@ +#include "arch/devices/legacy_pit.hpp" + +#include "kapi/devices.hpp" +#include "kapi/devices/device.hpp" +#include "kapi/interrupts.hpp" + +#include "arch/device_io/port_io.hpp" + +#include + +namespace arch::devices +{ + + namespace + { + using command_port = io::port<0x43, std::uint8_t, io::port_write>; + using channel_0_port = io::port<0x40, std::uint8_t, io::port_write>; + using channel_1_port = io::port<0x41, std::uint8_t, io::port_write>; + using channel_2_port = io::port<0x42, std::uint8_t, io::port_write>; + } // namespace + + legacy_pit::legacy_pit(std::uint32_t frequency_in_hz) + : kapi::devices::device{kapi::devices::allocate_major_number(), 0, "legacy_pit"} + , m_irq_number{0} + , m_frequency_in_hz{frequency_in_hz} + {} + + auto legacy_pit::init() -> bool + { + constexpr auto base_frequency = 1'193'182u; + auto divisor = static_cast(base_frequency / m_frequency_in_hz); + + kapi::interrupts::register_handler(m_irq_number, *this); + + command_port::write(0x36); // NOLINT + channel_0_port::write(divisor & 0xff); // NOLINT + channel_0_port::write(divisor >> 8 & 0xff); // NOLINT + + return true; + } + + auto legacy_pit::handle_interrupt(std::uint32_t irq_number) -> kapi::interrupts::status + { + if (irq_number != m_irq_number) + { + return kapi::interrupts::status::unhandled; + } + + ++m_ticks; + + return kapi::interrupts::status::handled; + } + +} // namespace arch::devices \ No newline at end of file -- cgit v1.2.3 From 21489576381d827871e7cdf060929c5d7f3d4e9f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 2 Apr 2026 15:49:14 +0200 Subject: devices: don't automatically allocate major numbers in ctors --- arch/x86_64/src/bus/isa.cpp | 6 ++++-- arch/x86_64/src/devices/legacy_pit.cpp | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/bus/isa.cpp b/arch/x86_64/src/bus/isa.cpp index 2ad4d21..ff4ad71 100644 --- a/arch/x86_64/src/bus/isa.cpp +++ b/arch/x86_64/src/bus/isa.cpp @@ -2,11 +2,13 @@ #include "kapi/devices.hpp" +#include + namespace arch::bus { - isa::isa() - : kapi::devices::bus(kapi::devices::allocate_major_number(), 0, "isa") + isa::isa(std::size_t major) + : kapi::devices::bus{major, 0, "isa"} {} } // namespace arch::bus \ No newline at end of file diff --git a/arch/x86_64/src/devices/legacy_pit.cpp b/arch/x86_64/src/devices/legacy_pit.cpp index f2fb70e..970f538 100644 --- a/arch/x86_64/src/devices/legacy_pit.cpp +++ b/arch/x86_64/src/devices/legacy_pit.cpp @@ -6,6 +6,7 @@ #include "arch/device_io/port_io.hpp" +#include #include namespace arch::devices @@ -19,8 +20,8 @@ namespace arch::devices using channel_2_port = io::port<0x42, std::uint8_t, io::port_write>; } // namespace - legacy_pit::legacy_pit(std::uint32_t frequency_in_hz) - : kapi::devices::device{kapi::devices::allocate_major_number(), 0, "legacy_pit"} + legacy_pit::legacy_pit(std::size_t major, std::uint32_t frequency_in_hz) + : kapi::devices::device{major, 0, "legacy_pit"} , m_irq_number{0} , m_frequency_in_hz{frequency_in_hz} {} -- cgit v1.2.3 From c5afb5c1ce1c084c840dbb58d73af6fe2b235ec7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 2 Apr 2026 15:55:47 +0200 Subject: x86_64: ensure PIT is not overwhelmed on config --- arch/x86_64/src/devices/legacy_pit.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/devices/legacy_pit.cpp b/arch/x86_64/src/devices/legacy_pit.cpp index 970f538..a8df3c3 100644 --- a/arch/x86_64/src/devices/legacy_pit.cpp +++ b/arch/x86_64/src/devices/legacy_pit.cpp @@ -18,6 +18,9 @@ namespace arch::devices using channel_0_port = io::port<0x40, std::uint8_t, io::port_write>; using channel_1_port = io::port<0x41, std::uint8_t, io::port_write>; using channel_2_port = io::port<0x42, std::uint8_t, io::port_write>; + + constexpr auto base_frequency = 1'193'182u; + constexpr auto square_wave_mode = 0x36; } // namespace legacy_pit::legacy_pit(std::size_t major, std::uint32_t frequency_in_hz) @@ -28,14 +31,16 @@ namespace arch::devices auto legacy_pit::init() -> bool { - constexpr auto base_frequency = 1'193'182u; auto divisor = static_cast(base_frequency / m_frequency_in_hz); kapi::interrupts::register_handler(m_irq_number, *this); - command_port::write(0x36); // NOLINT - channel_0_port::write(divisor & 0xff); // NOLINT - channel_0_port::write(divisor >> 8 & 0xff); // NOLINT + command_port::write(square_wave_mode); + io::wait(); + channel_0_port::write(divisor & 0xff); + io::wait(); + channel_0_port::write(divisor >> 8 & 0xff); + io::wait(); return true; } -- cgit v1.2.3 From c18feddd51d1a1398d1245229c5f889dd40554b3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 6 Apr 2026 15:54:21 +0200 Subject: x86_64/devices: extract initialization code --- arch/x86_64/src/devices/init.cpp | 69 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 arch/x86_64/src/devices/init.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/devices/init.cpp b/arch/x86_64/src/devices/init.cpp new file mode 100644 index 0000000..1099ad6 --- /dev/null +++ b/arch/x86_64/src/devices/init.cpp @@ -0,0 +1,69 @@ +#include "arch/devices/init.hpp" + +#include "kapi/acpi.hpp" +#include "kapi/boot.hpp" +#include "kapi/devices.hpp" + +#include "arch/boot/boot.hpp" +#include "arch/bus/isa.hpp" +#include "arch/devices/legacy_pit.hpp" + +#include +#include + +#include +#include + +namespace arch::devices +{ + + namespace + { + constexpr auto pit_frequency_in_hz = std::uint32_t{100u}; + } + + auto init_acpi_devices() -> void + { + auto const & mbi = kapi::boot::bootstrap_information.mbi; + auto system_description_pointer = static_cast(nullptr); + + if (auto const & xsdp = mbi->maybe_acpi_xsdp()) + { + auto data = xsdp->pointer().data(); + system_description_pointer = reinterpret_cast(data); + } + else if (auto const & rsdp = mbi->maybe_acpi_rsdp()) + { + auto data = rsdp->pointer().data(); + system_description_pointer = reinterpret_cast(data); + } + + if (system_description_pointer) + { + if (!kapi::acpi::init(*system_description_pointer)) + { + kstd::println(kstd::print_sink::stderr, "[x86_64:DEV] ACPI initialization failed. No tables loaded."); + } + } + else + { + kstd::println(kstd::print_sink::stderr, "[x86_64:DEV] No ACPI RSDP found. Most devices will not be available."); + } + } + + auto init_legacy_devices() -> void + { + kstd::println("[x86_64:DEV] Initializing ISA bus..."); + + auto isa_major_number = kapi::devices::allocate_major_number(); + auto isa_bus = kstd::make_unique(isa_major_number); + + auto pit_major_number = kapi::devices::allocate_major_number(); + auto pit = kstd::make_unique(pit_major_number, pit_frequency_in_hz); + isa_bus->add_child(std::move(pit)); + + auto & root_bus = kapi::devices::get_root_bus(); + root_bus.add_child(std::move(isa_bus)); + } + +} // namespace arch::devices -- cgit v1.2.3 From f456f1674d48932846eb7b5ec1df630ad67e7e3d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 6 Apr 2026 17:24:36 +0200 Subject: kernel/acpi: discover local interrupt controllers --- arch/x86_64/src/devices/init.cpp | 32 +------------------------------- arch/x86_64/src/devices/local_apic.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 31 deletions(-) create mode 100644 arch/x86_64/src/devices/local_apic.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/devices/init.cpp b/arch/x86_64/src/devices/init.cpp index 1099ad6..6cba986 100644 --- a/arch/x86_64/src/devices/init.cpp +++ b/arch/x86_64/src/devices/init.cpp @@ -1,10 +1,7 @@ #include "arch/devices/init.hpp" -#include "kapi/acpi.hpp" -#include "kapi/boot.hpp" #include "kapi/devices.hpp" -#include "arch/boot/boot.hpp" #include "arch/bus/isa.hpp" #include "arch/devices/legacy_pit.hpp" @@ -22,34 +19,7 @@ namespace arch::devices constexpr auto pit_frequency_in_hz = std::uint32_t{100u}; } - auto init_acpi_devices() -> void - { - auto const & mbi = kapi::boot::bootstrap_information.mbi; - auto system_description_pointer = static_cast(nullptr); - - if (auto const & xsdp = mbi->maybe_acpi_xsdp()) - { - auto data = xsdp->pointer().data(); - system_description_pointer = reinterpret_cast(data); - } - else if (auto const & rsdp = mbi->maybe_acpi_rsdp()) - { - auto data = rsdp->pointer().data(); - system_description_pointer = reinterpret_cast(data); - } - - if (system_description_pointer) - { - if (!kapi::acpi::init(*system_description_pointer)) - { - kstd::println(kstd::print_sink::stderr, "[x86_64:DEV] ACPI initialization failed. No tables loaded."); - } - } - else - { - kstd::println(kstd::print_sink::stderr, "[x86_64:DEV] No ACPI RSDP found. Most devices will not be available."); - } - } + auto init_acpi_devices() -> void {} auto init_legacy_devices() -> void { diff --git a/arch/x86_64/src/devices/local_apic.cpp b/arch/x86_64/src/devices/local_apic.cpp new file mode 100644 index 0000000..beb75ef --- /dev/null +++ b/arch/x86_64/src/devices/local_apic.cpp @@ -0,0 +1,28 @@ +#include "arch/devices/local_apic.hpp" + +#include "kapi/devices.hpp" +#include "kapi/memory.hpp" + +#include + +#include +#include + +namespace arch::devices +{ + + local_apic::local_apic(std::size_t major, std::size_t minor, std::uint64_t hardware_id, + kapi::memory::physical_address base) + : kapi::devices::device{major, minor, "lapic"} + , m_hardware_id{hardware_id} + , m_base{base} + {} + + auto local_apic::init() -> bool + { + kstd::println("[x86_64:DEV] Initializing local APIC on core {}", m_hardware_id); + + return true; + } + +} // namespace arch::devices \ No newline at end of file -- cgit v1.2.3 From ce47b93e8834bb4811e788737ae1a6ea750af79c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 8 Apr 2026 14:20:48 +0200 Subject: x86_64: implement LAPIC initialization --- arch/x86_64/src/devices/local_apic.cpp | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/devices/local_apic.cpp b/arch/x86_64/src/devices/local_apic.cpp index beb75ef..91e907a 100644 --- a/arch/x86_64/src/devices/local_apic.cpp +++ b/arch/x86_64/src/devices/local_apic.cpp @@ -11,6 +11,14 @@ namespace arch::devices { + namespace + { + constexpr auto lapic_sivr_register = 0x00F0uz; + + constexpr auto lapic_enable_bit = 0x100u; + constexpr auto spurious_interrupt_vector = 0xFFu; + } // namespace + local_apic::local_apic(std::size_t major, std::size_t minor, std::uint64_t hardware_id, kapi::memory::physical_address base) : kapi::devices::device{major, minor, "lapic"} @@ -20,9 +28,30 @@ namespace arch::devices auto local_apic::init() -> bool { - kstd::println("[x86_64:DEV] Initializing local APIC on core {}", m_hardware_id); + m_virtual_base = kapi::memory::allocate_mmio_region(1); + if (!kapi::memory::map_mmio_region(m_virtual_base, m_base, kapi::memory::page_mapper::flags::writable)) + { + kstd::println("[x86_64:DEV] LAPIC {} MMIO mapping failed!", m_hardware_id); + return false; + } + + write_register(lapic_sivr_register, lapic_enable_bit | spurious_interrupt_vector); + + kstd::println("[x86_64:DEV] LAPIC {} initialized. {:#018x}@{:#018x}", m_hardware_id, m_base, m_virtual_base); return true; } -} // namespace arch::devices \ No newline at end of file + auto local_apic::read_register(std::size_t offset) const -> std::uint32_t + { + auto reg = static_cast(m_virtual_base + offset); + return *reg; + } + + auto local_apic::write_register(std::size_t offset, std::uint32_t value) -> void + { + auto reg = static_cast(m_virtual_base + offset); + *reg = value; + } + +} // namespace arch::devices -- cgit v1.2.3 From 2ed34cc51a534171f0fe08808634834bc22cf84d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 8 Apr 2026 14:55:18 +0200 Subject: x86_64: only initialize BSP LAPIC --- arch/x86_64/src/devices/local_apic.cpp | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/devices/local_apic.cpp b/arch/x86_64/src/devices/local_apic.cpp index 91e907a..e24e1d4 100644 --- a/arch/x86_64/src/devices/local_apic.cpp +++ b/arch/x86_64/src/devices/local_apic.cpp @@ -20,24 +20,40 @@ namespace arch::devices } // namespace local_apic::local_apic(std::size_t major, std::size_t minor, std::uint64_t hardware_id, - kapi::memory::physical_address base) + kapi::memory::physical_address base, bool is_bsp) : kapi::devices::device{major, minor, "lapic"} , m_hardware_id{hardware_id} , m_base{base} + , m_is_bsp{is_bsp} {} auto local_apic::init() -> bool { - m_virtual_base = kapi::memory::allocate_mmio_region(1); - if (!kapi::memory::map_mmio_region(m_virtual_base, m_base, kapi::memory::page_mapper::flags::writable)) + auto static shared_virtual_base = kapi::memory::allocate_mmio_region(1); + auto static is_mapped = false; + + if (!is_mapped) { - kstd::println("[x86_64:DEV] LAPIC {} MMIO mapping failed!", m_hardware_id); - return false; + if (!kapi::memory::map_mmio_region(shared_virtual_base, m_base, kapi::memory::page_mapper::flags::writable)) + { + kstd::println("[x86_64:DEV] LAPIC {} MMIO mapping failed!", m_hardware_id); + return false; + } + is_mapped = true; } - write_register(lapic_sivr_register, lapic_enable_bit | spurious_interrupt_vector); + m_virtual_base = shared_virtual_base; + + if (m_is_bsp) + { + write_register(lapic_sivr_register, lapic_enable_bit | spurious_interrupt_vector); - kstd::println("[x86_64:DEV] LAPIC {} initialized. {:#018x}@{:#018x}", m_hardware_id, m_base, m_virtual_base); + kstd::println("[x86_64:DEV] LAPIC {} initialized. {:#018x}@{:#018x}", m_hardware_id, m_base, m_virtual_base); + } + else + { + kstd::println("[x86_64:DEV] LAPIC {} is not on the BSP, deferring intialization.", m_hardware_id); + } return true; } -- cgit v1.2.3 From 1ecc0c223a1bacfa1aee183a3573f57c265318df Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 8 Apr 2026 17:07:27 +0200 Subject: x86_64: extend LAPIC initialization --- arch/x86_64/src/devices/local_apic.cpp | 77 ++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 8 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/devices/local_apic.cpp b/arch/x86_64/src/devices/local_apic.cpp index e24e1d4..54d87a6 100644 --- a/arch/x86_64/src/devices/local_apic.cpp +++ b/arch/x86_64/src/devices/local_apic.cpp @@ -7,18 +7,73 @@ #include #include +#include namespace arch::devices { namespace { - constexpr auto lapic_sivr_register = 0x00F0uz; - constexpr auto lapic_enable_bit = 0x100u; constexpr auto spurious_interrupt_vector = 0xFFu; + + constexpr auto offset_of_version = 0u; + constexpr auto offset_of_max_lvt_entry = 16u; + constexpr auto offset_of_eoi_suppression = 24u; + } // namespace + enum struct local_apic::registers : std::ptrdiff_t + { + id = 0x020, + version = 0x030, + task_priority = 0x080, + arbitration_priority = 0x090, + processor_priority = 0x0a0, + eoi = 0x0b0, + remote_read = 0x0c0, + logical_destination = 0x0d0, + destination_format = 0x0e0, + spurious_interrupt_vector = 0x0f0, + in_service_0 = 0x100, + in_service_1 = 0x110, + in_service_2 = 0x120, + in_service_3 = 0x130, + in_service_4 = 0x140, + in_service_5 = 0x150, + in_service_6 = 0x160, + in_service_7 = 0x170, + trigger_mode_0 = 0x180, + trigger_mode_1 = 0x190, + trigger_mode_2 = 0x1a0, + trigger_mode_3 = 0x1b0, + trigger_mode_4 = 0x1c0, + trigger_mode_5 = 0x1d0, + trigger_mode_6 = 0x1e0, + trigger_mode_7 = 0x1f0, + interrupt_request_0 = 0x200, + interrupt_request_1 = 0x210, + interrupt_request_2 = 0x220, + interrupt_request_3 = 0x230, + interrupt_request_4 = 0x240, + interrupt_request_5 = 0x250, + interrupt_request_6 = 0x260, + interrupt_request_7 = 0x270, + error_status = 0x280, + lvt_corrected_machine_check_interrupt = 0x2f0, + interrupt_command_0 = 0x300, + interrupt_command_1 = 0x310, + lvt_timer = 0x320, + lvt_thermal_sensors = 0x330, + lvt_performance_monitoring_counters = 0x340, + lvt_local_interrupt_0 = 0x350, + lvt_local_interrupt_1 = 0x360, + lvt_error = 0x370, + initial_count = 0x380, + current_count = 0x390, + divide_configuration = 0x3e0, + }; + local_apic::local_apic(std::size_t major, std::size_t minor, std::uint64_t hardware_id, kapi::memory::physical_address base, bool is_bsp) : kapi::devices::device{major, minor, "lapic"} @@ -46,9 +101,15 @@ namespace arch::devices if (m_is_bsp) { - write_register(lapic_sivr_register, lapic_enable_bit | spurious_interrupt_vector); + auto raw_version = read_register(registers::version); + m_version = (raw_version >> offset_of_version) & 0xff; + m_highest_lvt_entry_index = (raw_version >> offset_of_max_lvt_entry) & 0xff; + m_supports_eoi_broadcast_suppression = (raw_version >> offset_of_eoi_suppression) & 0x1; + + write_register(registers::spurious_interrupt_vector, lapic_enable_bit | spurious_interrupt_vector); - kstd::println("[x86_64:DEV] LAPIC {} initialized. {:#018x}@{:#018x}", m_hardware_id, m_base, m_virtual_base); + kstd::println("[x86_64:DEV] LAPIC initialized. version: {#x} | max_lvt_entry: {} | eoi_suppresion: {:s}", + m_version, m_highest_lvt_entry_index, m_supports_eoi_broadcast_suppression); } else { @@ -58,15 +119,15 @@ namespace arch::devices return true; } - auto local_apic::read_register(std::size_t offset) const -> std::uint32_t + auto local_apic::read_register(registers id) const -> std::uint32_t { - auto reg = static_cast(m_virtual_base + offset); + auto reg = static_cast(m_virtual_base + std::to_underlying(id)); return *reg; } - auto local_apic::write_register(std::size_t offset, std::uint32_t value) -> void + auto local_apic::write_register(registers id, std::uint32_t value) -> void { - auto reg = static_cast(m_virtual_base + offset); + auto reg = static_cast(m_virtual_base + std::to_underlying(id)); *reg = value; } -- cgit v1.2.3 From aa208226f992523865328d4612ae4a7679f57a04 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 8 Apr 2026 17:17:11 +0200 Subject: kapi: return region pair for MMIO allocation --- arch/x86_64/src/devices/local_apic.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/devices/local_apic.cpp b/arch/x86_64/src/devices/local_apic.cpp index 54d87a6..4a81de8 100644 --- a/arch/x86_64/src/devices/local_apic.cpp +++ b/arch/x86_64/src/devices/local_apic.cpp @@ -97,7 +97,7 @@ namespace arch::devices is_mapped = true; } - m_virtual_base = shared_virtual_base; + m_mapped_region = shared_virtual_base; if (m_is_bsp) { @@ -108,12 +108,12 @@ namespace arch::devices write_register(registers::spurious_interrupt_vector, lapic_enable_bit | spurious_interrupt_vector); - kstd::println("[x86_64:DEV] LAPIC initialized. version: {#x} | max_lvt_entry: {} | eoi_suppresion: {:s}", + kstd::println("[x86_64:DEV] LAPIC initialized. version: {#x} | max_lvt_entry: {} | eoi_suppression: {:s}", m_version, m_highest_lvt_entry_index, m_supports_eoi_broadcast_suppression); } else { - kstd::println("[x86_64:DEV] LAPIC {} is not on the BSP, deferring intialization.", m_hardware_id); + kstd::println("[x86_64:DEV] LAPIC {} is not on the BSP, deferring initialization.", m_hardware_id); } return true; @@ -121,13 +121,13 @@ namespace arch::devices auto local_apic::read_register(registers id) const -> std::uint32_t { - auto reg = static_cast(m_virtual_base + std::to_underlying(id)); + auto reg = static_cast(m_mapped_region.first + std::to_underlying(id)); return *reg; } auto local_apic::write_register(registers id, std::uint32_t value) -> void { - auto reg = static_cast(m_virtual_base + std::to_underlying(id)); + auto reg = static_cast(m_mapped_region.first + std::to_underlying(id)); *reg = value; } -- cgit v1.2.3 From 21fd1281cf19572e202d583689b99c33ec68da50 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 10 Apr 2026 17:49:40 +0200 Subject: kernel: let arch initialize the ACPI manager --- arch/x86_64/src/devices/init.cpp | 41 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/devices/init.cpp b/arch/x86_64/src/devices/init.cpp index 6cba986..7f0faa4 100644 --- a/arch/x86_64/src/devices/init.cpp +++ b/arch/x86_64/src/devices/init.cpp @@ -1,13 +1,18 @@ #include "arch/devices/init.hpp" +#include "kapi/acpi.hpp" +#include "kapi/cpu.hpp" #include "kapi/devices.hpp" +#include "arch/boot/boot.hpp" #include "arch/bus/isa.hpp" #include "arch/devices/legacy_pit.hpp" #include #include +#include + #include #include @@ -17,9 +22,41 @@ namespace arch::devices namespace { constexpr auto pit_frequency_in_hz = std::uint32_t{100u}; - } - auto init_acpi_devices() -> void {} + auto get_acpi_root_pointer() -> kstd::observer_ptr<::acpi::rsdp const> + { + auto const & mbi = kapi::boot::bootstrap_information.mbi; + auto system_description_pointer = static_cast<::acpi::rsdp const *>(nullptr); + + if (auto const & xsdp = mbi->maybe_acpi_xsdp()) + { + auto data = xsdp->pointer().data(); + + system_description_pointer = reinterpret_cast<::acpi::xsdp const *>(data); + } + else if (auto const & rsdp = mbi->maybe_acpi_rsdp()) + { + auto data = rsdp->pointer().data(); + system_description_pointer = reinterpret_cast<::acpi::rsdp const *>(data); + } + + return kstd::make_observer(system_description_pointer); + } + } // namespace + + auto init_acpi_devices() -> void + { + auto acpi_root_pointer = get_acpi_root_pointer(); + if (acpi_root_pointer && acpi_root_pointer->validate()) + { + if (kapi::acpi::init(*acpi_root_pointer)) + { + kstd::println("[x86_64:DEV] ACPI subsystem initialized."); + } + } + + kapi::cpu::discover_topology(); + } auto init_legacy_devices() -> void { -- cgit v1.2.3 From 2d8fed40bd0d0f8144783b6b344dc79944291b72 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 23 Apr 2026 13:31:17 +0200 Subject: chore: organize includes --- arch/x86_64/src/cpu/interrupts.cpp | 6 +++--- arch/x86_64/src/devices/init.cpp | 10 +++++----- arch/x86_64/src/devices/legacy_pit.cpp | 4 ++-- arch/x86_64/src/memory/higher_half_mapper.cpp | 6 +++--- arch/x86_64/src/memory/kernel_mapper.cpp | 7 ++++--- arch/x86_64/src/memory/mmu.cpp | 4 ++-- arch/x86_64/src/vga/text/device.cpp | 4 ++-- 7 files changed, 21 insertions(+), 20 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 907f289..f58b851 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -1,12 +1,12 @@ #include "arch/cpu/interrupts.hpp" +#include "arch/cpu/legacy_pic.hpp" +#include "arch/cpu/segment_selector.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" - #include #include diff --git a/arch/x86_64/src/devices/init.cpp b/arch/x86_64/src/devices/init.cpp index 7f0faa4..8c96b38 100644 --- a/arch/x86_64/src/devices/init.cpp +++ b/arch/x86_64/src/devices/init.cpp @@ -1,18 +1,18 @@ #include "arch/devices/init.hpp" +#include "arch/boot/boot.hpp" +#include "arch/bus/isa.hpp" +#include "arch/devices/legacy_pit.hpp" + #include "kapi/acpi.hpp" #include "kapi/cpu.hpp" #include "kapi/devices.hpp" -#include "arch/boot/boot.hpp" -#include "arch/bus/isa.hpp" -#include "arch/devices/legacy_pit.hpp" +#include #include #include -#include - #include #include diff --git a/arch/x86_64/src/devices/legacy_pit.cpp b/arch/x86_64/src/devices/legacy_pit.cpp index a8df3c3..44ff499 100644 --- a/arch/x86_64/src/devices/legacy_pit.cpp +++ b/arch/x86_64/src/devices/legacy_pit.cpp @@ -1,11 +1,11 @@ #include "arch/devices/legacy_pit.hpp" +#include "arch/device_io/port_io.hpp" + #include "kapi/devices.hpp" #include "kapi/devices/device.hpp" #include "kapi/interrupts.hpp" -#include "arch/device_io/port_io.hpp" - #include #include diff --git a/arch/x86_64/src/memory/higher_half_mapper.cpp b/arch/x86_64/src/memory/higher_half_mapper.cpp index abb54a3..b0d1995 100644 --- a/arch/x86_64/src/memory/higher_half_mapper.cpp +++ b/arch/x86_64/src/memory/higher_half_mapper.cpp @@ -1,11 +1,11 @@ #include "arch/memory/higher_half_mapper.hpp" -#include "kapi/memory.hpp" -#include "kapi/system.hpp" - #include "arch/memory/page_table.hpp" #include "arch/memory/page_utilities.hpp" +#include "kapi/memory.hpp" +#include "kapi/system.hpp" + #include #include #include diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp index ced8a14..46d4dca 100644 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -1,15 +1,16 @@ #include "arch/memory/kernel_mapper.hpp" +#include "arch/boot/ld.hpp" + #include "kapi/memory.hpp" #include "kapi/system.hpp" -#include "arch/boot/ld.hpp" +#include +#include #include #include -#include -#include #include #include diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp index ea23278..6d185a0 100644 --- a/arch/x86_64/src/memory/mmu.cpp +++ b/arch/x86_64/src/memory/mmu.cpp @@ -1,9 +1,9 @@ #include "arch/memory/mmu.hpp" -#include "kapi/memory.hpp" - #include "arch/cpu/registers.hpp" +#include "kapi/memory.hpp" + namespace arch::memory { auto tlb_flush(kapi::memory::linear_address address) -> void diff --git a/arch/x86_64/src/vga/text/device.cpp b/arch/x86_64/src/vga/text/device.cpp index dcacd8c..0ecbef9 100644 --- a/arch/x86_64/src/vga/text/device.cpp +++ b/arch/x86_64/src/vga/text/device.cpp @@ -1,10 +1,10 @@ -#include "kapi/cio.hpp" - #include "arch/boot/boot.hpp" #include "arch/boot/ld.hpp" #include "arch/vga/crtc.hpp" #include "arch/vga/text.hpp" +#include "kapi/cio.hpp" + #include #include #include -- cgit v1.2.3 From f6f10575f75ac23d06e1d94f7861611503daa7af Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 23 Apr 2026 14:03:28 +0200 Subject: chore: banish relative includes --- arch/x86_64/src/boot/boot32.S | 2 +- arch/x86_64/src/bus/isa.cpp | 4 ++-- arch/x86_64/src/cpu/initialization.cpp | 12 ++++++------ arch/x86_64/src/cpu/interrupts.cpp | 12 ++++++------ arch/x86_64/src/debug/qemu_output.cpp | 4 ++-- arch/x86_64/src/devices/init.cpp | 14 +++++++------- arch/x86_64/src/devices/legacy_pit.cpp | 10 +++++----- arch/x86_64/src/devices/local_apic.cpp | 6 +++--- arch/x86_64/src/memory/higher_half_mapper.cpp | 10 +++++----- arch/x86_64/src/memory/kernel_mapper.cpp | 8 ++++---- arch/x86_64/src/memory/mmu.cpp | 6 +++--- arch/x86_64/src/memory/page_table.cpp | 4 ++-- arch/x86_64/src/memory/region_allocator.cpp | 6 +++--- arch/x86_64/src/vga/text/buffer.cpp | 4 ++-- arch/x86_64/src/vga/text/device.cpp | 10 +++++----- 15 files changed, 56 insertions(+), 56 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot32.S b/arch/x86_64/src/boot/boot32.S index 1c2fdaf..e6fcd85 100644 --- a/arch/x86_64/src/boot/boot32.S +++ b/arch/x86_64/src/boot/boot32.S @@ -1,4 +1,4 @@ -#include "arch/boot/boot.hpp" +#include /** * @brief Uninitialized data for the bootstrapping process. diff --git a/arch/x86_64/src/bus/isa.cpp b/arch/x86_64/src/bus/isa.cpp index ff4ad71..f6cc72d 100644 --- a/arch/x86_64/src/bus/isa.cpp +++ b/arch/x86_64/src/bus/isa.cpp @@ -1,6 +1,6 @@ -#include "arch/bus/isa.hpp" +#include -#include "kapi/devices.hpp" +#include #include diff --git a/arch/x86_64/src/cpu/initialization.cpp b/arch/x86_64/src/cpu/initialization.cpp index b808c76..1be9c82 100644 --- a/arch/x86_64/src/cpu/initialization.cpp +++ b/arch/x86_64/src/cpu/initialization.cpp @@ -1,10 +1,10 @@ -#include "arch/cpu/initialization.hpp" +#include -#include "arch/cpu/global_descriptor_table.hpp" -#include "arch/cpu/interrupts.hpp" -#include "arch/cpu/legacy_pic.hpp" -#include "arch/cpu/segment_descriptor.hpp" -#include "arch/cpu/task_state_segment.hpp" +#include +#include +#include +#include +#include #include diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index f58b851..f40422f 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -1,11 +1,11 @@ -#include "arch/cpu/interrupts.hpp" +#include -#include "arch/cpu/legacy_pic.hpp" -#include "arch/cpu/segment_selector.hpp" +#include +#include -#include "kapi/cpu.hpp" -#include "kapi/interrupts.hpp" -#include "kapi/memory.hpp" +#include +#include +#include #include diff --git a/arch/x86_64/src/debug/qemu_output.cpp b/arch/x86_64/src/debug/qemu_output.cpp index 535017d..71acede 100644 --- a/arch/x86_64/src/debug/qemu_output.cpp +++ b/arch/x86_64/src/debug/qemu_output.cpp @@ -1,6 +1,6 @@ -#include "arch/debug/qemu_output.hpp" +#include -#include "kapi/cio.hpp" +#include #include #include diff --git a/arch/x86_64/src/devices/init.cpp b/arch/x86_64/src/devices/init.cpp index 8c96b38..c30e8cf 100644 --- a/arch/x86_64/src/devices/init.cpp +++ b/arch/x86_64/src/devices/init.cpp @@ -1,12 +1,12 @@ -#include "arch/devices/init.hpp" +#include -#include "arch/boot/boot.hpp" -#include "arch/bus/isa.hpp" -#include "arch/devices/legacy_pit.hpp" +#include +#include +#include -#include "kapi/acpi.hpp" -#include "kapi/cpu.hpp" -#include "kapi/devices.hpp" +#include +#include +#include #include diff --git a/arch/x86_64/src/devices/legacy_pit.cpp b/arch/x86_64/src/devices/legacy_pit.cpp index 44ff499..d542d47 100644 --- a/arch/x86_64/src/devices/legacy_pit.cpp +++ b/arch/x86_64/src/devices/legacy_pit.cpp @@ -1,10 +1,10 @@ -#include "arch/devices/legacy_pit.hpp" +#include -#include "arch/device_io/port_io.hpp" +#include -#include "kapi/devices.hpp" -#include "kapi/devices/device.hpp" -#include "kapi/interrupts.hpp" +#include +#include +#include #include #include diff --git a/arch/x86_64/src/devices/local_apic.cpp b/arch/x86_64/src/devices/local_apic.cpp index 4a81de8..660921b 100644 --- a/arch/x86_64/src/devices/local_apic.cpp +++ b/arch/x86_64/src/devices/local_apic.cpp @@ -1,7 +1,7 @@ -#include "arch/devices/local_apic.hpp" +#include -#include "kapi/devices.hpp" -#include "kapi/memory.hpp" +#include +#include #include diff --git a/arch/x86_64/src/memory/higher_half_mapper.cpp b/arch/x86_64/src/memory/higher_half_mapper.cpp index b0d1995..75adb3c 100644 --- a/arch/x86_64/src/memory/higher_half_mapper.cpp +++ b/arch/x86_64/src/memory/higher_half_mapper.cpp @@ -1,10 +1,10 @@ -#include "arch/memory/higher_half_mapper.hpp" +#include -#include "arch/memory/page_table.hpp" -#include "arch/memory/page_utilities.hpp" +#include +#include -#include "kapi/memory.hpp" -#include "kapi/system.hpp" +#include +#include #include #include diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp index 46d4dca..74272a0 100644 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -1,9 +1,9 @@ -#include "arch/memory/kernel_mapper.hpp" +#include -#include "arch/boot/ld.hpp" +#include -#include "kapi/memory.hpp" -#include "kapi/system.hpp" +#include +#include #include #include diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp index 6d185a0..2b53fa4 100644 --- a/arch/x86_64/src/memory/mmu.cpp +++ b/arch/x86_64/src/memory/mmu.cpp @@ -1,8 +1,8 @@ -#include "arch/memory/mmu.hpp" +#include -#include "arch/cpu/registers.hpp" +#include -#include "kapi/memory.hpp" +#include namespace arch::memory { diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index 26cdd29..2180420 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -1,6 +1,6 @@ -#include "arch/memory/page_table.hpp" +#include -#include "kapi/memory.hpp" +#include #include #include diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index 4ee3ca4..4086a10 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -1,7 +1,7 @@ -#include "arch/memory/region_allocator.hpp" +#include -#include "kapi/memory/address.hpp" -#include "kapi/memory/frame.hpp" +#include +#include #include diff --git a/arch/x86_64/src/vga/text/buffer.cpp b/arch/x86_64/src/vga/text/buffer.cpp index 7112573..498b9a3 100644 --- a/arch/x86_64/src/vga/text/buffer.cpp +++ b/arch/x86_64/src/vga/text/buffer.cpp @@ -1,6 +1,6 @@ -#include "arch/vga/text/buffer.hpp" +#include -#include "arch/vga/text/attribute.hpp" +#include #include #include diff --git a/arch/x86_64/src/vga/text/device.cpp b/arch/x86_64/src/vga/text/device.cpp index 0ecbef9..8468358 100644 --- a/arch/x86_64/src/vga/text/device.cpp +++ b/arch/x86_64/src/vga/text/device.cpp @@ -1,9 +1,9 @@ -#include "arch/boot/boot.hpp" -#include "arch/boot/ld.hpp" -#include "arch/vga/crtc.hpp" -#include "arch/vga/text.hpp" +#include +#include +#include +#include -#include "kapi/cio.hpp" +#include #include #include -- cgit v1.2.3 From 1b964278762dde86b0b737bd9a34fec569339f54 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 16 Apr 2026 10:29:30 +0200 Subject: x86_64: use p1204 project layout --- arch/x86_64/src/boot/boot32.S | 443 -------------------------- arch/x86_64/src/boot/entry64.s | 62 ---- arch/x86_64/src/boot/initialize_runtime.cpp | 22 -- arch/x86_64/src/boot/multiboot.s | 33 -- arch/x86_64/src/bus/isa.cpp | 14 - arch/x86_64/src/cpu/initialization.cpp | 164 ---------- arch/x86_64/src/cpu/interrupt_stubs.S | 112 ------- arch/x86_64/src/cpu/interrupts.cpp | 203 ------------ arch/x86_64/src/debug/qemu_output.cpp | 25 -- arch/x86_64/src/devices/init.cpp | 76 ----- arch/x86_64/src/devices/legacy_pit.cpp | 60 ---- arch/x86_64/src/devices/local_apic.cpp | 134 -------- arch/x86_64/src/memory/higher_half_mapper.cpp | 119 ------- arch/x86_64/src/memory/kernel_mapper.cpp | 117 ------- arch/x86_64/src/memory/mmu.cpp | 19 -- arch/x86_64/src/memory/page_table.cpp | 82 ----- arch/x86_64/src/memory/region_allocator.cpp | 165 ---------- arch/x86_64/src/vga/text/buffer.cpp | 101 ------ arch/x86_64/src/vga/text/device.cpp | 60 ---- 19 files changed, 2011 deletions(-) delete mode 100644 arch/x86_64/src/boot/boot32.S delete mode 100644 arch/x86_64/src/boot/entry64.s delete mode 100644 arch/x86_64/src/boot/initialize_runtime.cpp delete mode 100644 arch/x86_64/src/boot/multiboot.s delete mode 100644 arch/x86_64/src/bus/isa.cpp delete mode 100644 arch/x86_64/src/cpu/initialization.cpp delete mode 100644 arch/x86_64/src/cpu/interrupt_stubs.S delete mode 100644 arch/x86_64/src/cpu/interrupts.cpp delete mode 100644 arch/x86_64/src/debug/qemu_output.cpp delete mode 100644 arch/x86_64/src/devices/init.cpp delete mode 100644 arch/x86_64/src/devices/legacy_pit.cpp delete mode 100644 arch/x86_64/src/devices/local_apic.cpp delete mode 100644 arch/x86_64/src/memory/higher_half_mapper.cpp delete mode 100644 arch/x86_64/src/memory/kernel_mapper.cpp delete mode 100644 arch/x86_64/src/memory/mmu.cpp delete mode 100644 arch/x86_64/src/memory/page_table.cpp delete mode 100644 arch/x86_64/src/memory/region_allocator.cpp delete mode 100644 arch/x86_64/src/vga/text/buffer.cpp delete mode 100644 arch/x86_64/src/vga/text/device.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot32.S b/arch/x86_64/src/boot/boot32.S deleted file mode 100644 index e6fcd85..0000000 --- a/arch/x86_64/src/boot/boot32.S +++ /dev/null @@ -1,443 +0,0 @@ -#include - -/** - * @brief Uninitialized data for the bootstrapping process. - */ -.section .boot_bss, "aw", @nobits - -page_maps_start: -page_map_level_4: .skip 512 * 8 -page_map_level_3_high: .skip 512 * 8 -page_map_level_3_low: .skip 512 * 8 -page_map_level_2: .skip 512 * 8 -page_maps_end = . -page_maps_size = page_maps_end - page_maps_start - -/** - * @brief Storage for the multiboot2 information pointer. - */ -.global multiboot_information_pointer -multiboot_information_pointer: .skip 8 - -/** - * @brief Storage for the bootstrap stack. - */ -.section .boot_stack, "aw", @nobits -.align 16 - -early_stack_bottom: .skip 1 << 8 -early_stack_top: -early_stack_size = early_stack_top - early_stack_bottom - -/** - * @brief Constants for the bootstrapping process. - */ -.section .boot_rodata, "a", @progbits - -.global global_descriptor_table_data - -/** - * @brief A basic GDT for long mode. - */ -global_descriptor_table: -global_descriptor_table_null = . - global_descriptor_table -.quad 0 -global_descriptor_table_code = . - global_descriptor_table -.quad GDT_READ_WRITE | GDT_EXECUTABLE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | GDT_LONG_MODE | (1 << 55) -global_descriptor_table_data = . - global_descriptor_table -.quad GDT_READ_WRITE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | (1 << 54) | (1 << 55) -global_descriptor_table_end: - -message_prefix_panic: .string "Panic: " -message_not_loaded_by_multiboot2: .string "The operating system was not loaded by a Multiboot 2 loader." -message_cpuid_instruction_no_supported: .string "The 'cpuid' instruction is not supported on this platform." -message_long_mode_not_supported: .string "Long mode is not supported by this platform." -message_return_from_kernel_main: .string "Execution returned from kernel main." - -/** - * @brief Initialized data for the bootstrapping process. - */ -.section .boot_data, "aw", @progbits - -/** - * @brief A pointer to the current position within the VGA text buffer. - */ -.global vga_buffer_pointer -vga_buffer_pointer: .quad 0xb8000 - -/** - * @brief Code for the bootstrapping process. - */ -.section .boot_text, "ax", @progbits -.align 16 -.code32 - -.macro pie_base - push %esi - call 0f - 0: - pop %esi -.endm - -.macro function_start - push %ebp - mov %esp, %ebp -.endm - -.macro function_end - leave - ret -.endm - -.macro pie_function_start - function_start - pie_base -.endm - -.macro pie_function_end - pop %esi - function_end -.endm - -/** - * @brief Prepare the environment and start the kernel. - * - * This function performs all necessary checks to ensure the system was loaded - * by the expected loader and supports all features required to run the kernel. - * If successful, it prepares the system by setting up memory virtualization - * and then start the kernel proper. - * - * @param %eax The Multiboot 2 magic marker. - * @param %ebx The Multiboot 2 information pointer. - * @return void This function does not return. - */ -.global _start -_start: - call 0f -0: - pop %esi - - lea (early_stack_top - 0b)(%esi), %ecx - - mov %ecx, %esp - mov %esp, %ebp - - call _assert_loaded_by_multiboot2_loader - call _save_multiboot_information_pointer - - call _assert_cpuid_instruction_is_supported - call _assert_cpu_supports_long_mode - - push $HUGE_PAGES_TO_MAP - call _prepare_page_maps - add $4, %esp - - call _enable_paging - call _enable_sse - call _reload_gdt - - lea (_entry64 - 0b)(%esi), %eax - pushl $global_descriptor_table_code - pushl %eax - lret - -/** - * @brief Halt the system. - * - * This function will instruct the CPU to halt. It will try to keep the CPU - * halted, even if interrupts occur. - * - * @return This function never returns. - */ -_halt: - function_start - -1: - hlt - jmp 1b - - function_end - -/** - * @brief Print a message via the VGA text buffer. - * - * @param ebp+12 The message to print. - * @param ebp+8 The color to print the message in. - */ -_print: - pie_function_start - - push %edi - push %ebx - - mov 8(%ebp), %al - mov 12(%ebp), %edx - mov $0, %ecx - lea (vga_buffer_pointer - 0b)(%esi), %edi - mov (%edi), %edi - -1: - mov (%edx, %ecx), %bl - test %bl, %bl - je 2f - mov %bl, (%edi, %ecx, 2) - mov %al, 1(%edi, %ecx, 2) - inc %ecx - jmp 1b - -2: - shl $1, %ecx - add %ecx, %edi - lea (vga_buffer_pointer - 0b)(%esi), %ecx - mov %edi, (%ecx) - - pop %ebx - pop %edi - - pie_function_end - -/** - * @brief Print a given panic message and then halt the machine as if by calling ::halt() - * - * @param ebp+4 A message to print. - * @return This function does not return. - */ -_panic: - pie_function_start - - lea (message_prefix_panic - 0b)(%esi), %eax - - push %eax - push $0x4f - call _print - - mov 8(%ebp), %eax - mov %eax, 4(%esp) - call _print - add $8, %esp - - call _halt - - pie_function_end - -/** - * Assert that we were loaded by a Multiboot 2 compliant bootloader. - * - * This assertion will panic the system if the magic signature was not found. - * If we were loaded my an appropriate bootloader, this function also saves - * the provided MBI pointer to `multiboot_information_pointer`. - */ -_assert_loaded_by_multiboot2_loader: - pie_function_start - - cmp $MULTIBOOT2_MAGIC, %eax - je 1f - lea (message_not_loaded_by_multiboot2 - 0b)(%esi), %eax - push %eax - call _panic -1: - pie_function_end - -/** - * @brief Store the multiboot 2 information pointer in the global memory. - * - * @return void - */ -_save_multiboot_information_pointer: - pie_function_start - - lea (multiboot_information_pointer - 0b)(%esi), %eax - mov %ebx, (%eax) - - pie_function_end - -/** - * @brief Assert that the CPU supports the CPUID instruction. - * - * The primary way to check for support of the instruction is to flip the ID - * bin in EFLAGS and then check if this changed was accepted. If so, the CPU - * supports the CPUID instruction, otherwise it most-likely doesn't. - */ -_assert_cpuid_instruction_is_supported: - pie_function_start - - pushfl - pop %eax - mov %eax, %ecx - - xor $(1 << 21), %eax /* Flip the ID bit */ - push %eax /* Move the new bitset on the stack for loading */ - popfl /* Load the flags with ID set back into EFLAGS */ - pushfl /* Copy the flags back onto the stack */ - pop %eax /* Load the flags for further checking */ - - push %ecx - popfl - - cmp %ecx, %eax - jne 1f - lea (message_cpuid_instruction_no_supported - 0b)(%esi), %eax - push %eax - call _panic - -1: - pie_function_end - -/** - * @brief Assert that the CPU supports going into long mode. - */ -_assert_cpu_supports_long_mode: - pie_function_start - - mov $0x80000000, %eax - cpuid - cmp $0x80000001, %eax - jb 1f - - mov $0x80000001, %eax - cpuid - test $(1 << 29), %edx - jnz 2f -1: - lea (message_long_mode_not_supported - 0b)(%esi), %eax - push %eax - call _panic -2: - pie_function_end - -/** - * @brief Prepare a basic page map hierarchy - * - * @param ebp+8 The number of huge pages to map - * @return void - */ -_prepare_page_maps: - pie_function_start - - push %edi - - call _clear_page_map_memory - - lea (page_map_level_4 - 0b)(%esi), %edi - lea (page_map_level_3_low - 0b)(%esi), %eax - or $0b11, %eax - mov %eax, (%edi) - - lea (page_map_level_3_high - 0b)(%esi), %eax - or $0b11, %eax - mov %eax, (511 * 8)(%edi) - - lea (page_map_level_3_low - 0b)(%esi), %edi - lea (page_map_level_2 - 0b)(%esi), %eax - or $0b11, %eax - mov %eax, (%edi) - - lea (page_map_level_3_high - 0b)(%esi), %edi - lea (page_map_level_2 - 0b)(%esi), %eax - or $0b11, %eax - mov %eax, (510 * 8)(%edi) - - lea (page_map_level_2 - 0b)(%esi), %edi - mov 8(%ebp), %ecx - -1: - dec %ecx - mov $(1 << 21), %eax - mul %ecx - or $0b10000011, %eax - mov %eax, (%edi, %ecx, 8) - - test %ecx, %ecx - jnz 1b - - pop %edi - - pie_function_end - -/** - * @brief Clear all page map memory by filling it with 0s. - * - * @return void - */ -_clear_page_map_memory: - pie_function_start - - push %edi - - xor %eax, %eax - mov $page_maps_size, %ecx - shr $2, %ecx - lea (page_maps_start - 0b)(%esi), %edi - rep stosl - - pop %edi - - pie_function_end - -/** - * @p Enable memory virtualization via paging. - * - * Note: This routine expects for there to be a valid set of page maps already - * set up for use. - * - * @return void - */ -_enable_paging: - pie_function_start - - lea (page_map_level_4 - 0b)(%esi), %eax - mov %eax, %cr3 - - /* Enable Physical Address Extension */ - mov %cr4, %eax - or $(1 << 5), %eax - mov %eax, %cr4 - - /* Enable long mode support */ - mov $0xC0000080, %ecx - rdmsr - or $(1 << 8), %eax - wrmsr - - /* Enable paging */ - mov %cr0, %eax - or $(1 << 31), %eax - mov %eax, %cr0 - - pie_function_end - -/** - * @brief Enable use of SSE instructions. - */ -_enable_sse: - function_start - - mov %cr0, %eax - and $0xfffffffb, %eax - or $0x00000002, %eax - mov %eax, %cr0 - - mov %cr4, %eax - or $(3 << 9), %eax - mov %eax, %cr4 - - function_end - -/** - * @brief Prepare a new GTD and load make it active. - * - * @return void - */ -_reload_gdt: - pie_function_start - - sub $10, %esp - lea (global_descriptor_table - 0b)(%esi), %eax - movw $(global_descriptor_table_end - global_descriptor_table -1), (%esp) - mov %eax, 2(%esp) - movl $0, 6(%esp) - - lgdt (%esp) - add $10, %esp - - pie_function_end diff --git a/arch/x86_64/src/boot/entry64.s b/arch/x86_64/src/boot/entry64.s deleted file mode 100644 index 29fb778..0000000 --- a/arch/x86_64/src/boot/entry64.s +++ /dev/null @@ -1,62 +0,0 @@ -.section .stack, "aw", @nobits - -.align 16 -.global stack_top -stack_bottom: .skip 1 << 20 -stack_top: -stack_size = stack_top - stack_bottom - -.section .bss, "aw", @nobits - -//! A structure containing information gathered during the bootstrap process. -//! Expected layout (as described by teachos::boot::information): -//! -//! struct -//! { -//! multiboot2::information_view const * mbi; -//! std::size_t vga_buffer_index; -//! } -.global bootstrap_information -bootstrap_information: .skip 16 - -.section .boot_text, "ax", @progbits -.code64 - -.global _entry64 -_entry64: - mov $global_descriptor_table_data, %rax - mov %rax, %ss - mov %rax, %ds - mov %rax, %es - mov %rax, %fs - mov %rax, %gs - - mov $stack_top, %rsp - mov %rsp, %rbp - - mov multiboot_information_pointer, %rax - or $TEACHOS_VMA, %rax - mov vga_buffer_pointer, %rdx - sub $0xb8000, %rdx - mov %rax, (bootstrap_information) - mov %rdx, (bootstrap_information + 8) - - call invoke_global_constructors - - xor %rax, %rax - mov %rax, %rbp - mov %rax, %rdx - mov %rax, %rsi - - mov $stack_size, %rcx - shr $3, %rcx - lea (stack_bottom), %rdi - rep stosq - - mov %rax, %rdi - - call main - -1: - hlt - jmp 1b diff --git a/arch/x86_64/src/boot/initialize_runtime.cpp b/arch/x86_64/src/boot/initialize_runtime.cpp deleted file mode 100644 index b08c13c..0000000 --- a/arch/x86_64/src/boot/initialize_runtime.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include - -namespace arch::boot -{ - - extern "C" - { - using global_initializer = auto (*)() -> void; - - extern global_initializer __init_array_start; - extern global_initializer __init_array_end; - - auto invoke_global_constructors() -> void - { - auto initializers = std::span{&__init_array_start, &__init_array_end}; - std::ranges::for_each(initializers, [](auto invokable) { std::invoke(invokable); }); - } - } - -} // namespace arch::boot \ No newline at end of file diff --git a/arch/x86_64/src/boot/multiboot.s b/arch/x86_64/src/boot/multiboot.s deleted file mode 100644 index 37d8afe..0000000 --- a/arch/x86_64/src/boot/multiboot.s +++ /dev/null @@ -1,33 +0,0 @@ -.section .boot_mbh, "a" -.align 8 - -multiboot_header_start: -.Lmagic: - .long 0xe85250d6 -.Larch: - .long 0 -.Llength: - .long multiboot_header_end - multiboot_header_start -.Lchecksum: - .long 0x100000000 - (0xe85250d6 + 0 + (multiboot_header_end - multiboot_header_start)) -.align 8 -.Lflags_start: - .word 4 - .word 1 - .long .Lflags_end - .Lflags_start - .long 3 -.Lflags_end: -.align 8 -.Linformation_request_start: - .word 1 - .word 0 - .long .Linformation_request_end - .Linformation_request_start - .long 3 -.Linformation_request_end: -.align 8 -.Lend_start: - .word 0 - .word 0 - .long .Lend_end - .Lend_start -.Lend_end: -multiboot_header_end: diff --git a/arch/x86_64/src/bus/isa.cpp b/arch/x86_64/src/bus/isa.cpp deleted file mode 100644 index f6cc72d..0000000 --- a/arch/x86_64/src/bus/isa.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include - -#include - -#include - -namespace arch::bus -{ - - isa::isa(std::size_t major) - : kapi::devices::bus{major, 0, "isa"} - {} - -} // namespace arch::bus \ No newline at end of file diff --git a/arch/x86_64/src/cpu/initialization.cpp b/arch/x86_64/src/cpu/initialization.cpp deleted file mode 100644 index 1be9c82..0000000 --- a/arch/x86_64/src/cpu/initialization.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include - -namespace arch::cpu -{ - - namespace - { - constexpr auto gdt_null_descriptor = segment_descriptor{}; - - constexpr auto gdt_kernel_code_descriptor = segment_descriptor{ - .limit_low = 0xffff, - .base_low = 0, - .accessed = false, - .read_write = false, - .direction_or_conforming = false, - .executable = true, - .type = segment_type::code_or_data, - .privilege_level = 0, - .present = true, - .limit_high = 0xf, - .long_mode = true, - .protected_mode = false, - .granularity = segment_granularity::page, - .base_high = 0, - }; - - constexpr auto gdt_kernel_data_descriptor = segment_descriptor{ - .limit_low = 0xffff, - .base_low = 0, - .accessed = false, - .read_write = true, - .direction_or_conforming = false, - .executable = false, - .type = segment_type::code_or_data, - .privilege_level = 0, - .present = true, - .limit_high = 0xf, - .long_mode = false, - .protected_mode = true, - .granularity = segment_granularity::page, - .base_high = 0, - }; - - constexpr auto gdt_user_code_descriptor = segment_descriptor{ - .limit_low = 0xffff, - .base_low = 0, - .accessed = false, - .read_write = false, - .direction_or_conforming = false, - .executable = true, - .type = segment_type::code_or_data, - .privilege_level = 3, - .present = true, - .limit_high = 0xf, - .long_mode = true, - .protected_mode = false, - .granularity = segment_granularity::page, - .base_high = 0, - }; - - constexpr auto gdt_user_data_descriptor = segment_descriptor{ - .limit_low = 0xffff, - .base_low = 0, - .accessed = false, - .read_write = true, - .direction_or_conforming = false, - .executable = false, - .type = segment_type::code_or_data, - .privilege_level = 3, - .present = true, - .limit_high = 0xf, - .long_mode = false, - .protected_mode = false, - .granularity = segment_granularity::page, - .base_high = 0, - }; - - constexpr auto make_tss_descriptor(task_state_segment const * tss_ptr) -> system_segment_descriptor - { - auto const address = std::bit_cast(tss_ptr); - auto const limit = sizeof(task_state_segment) - 1; - - return system_segment_descriptor{ - { - .limit_low = limit & 0xffff, // NOLINT(readability-magic-numbers) - .base_low = address & 0xffffff, // NOLINT(readability-magic-numbers) - .accessed = false, - .read_write = false, - .direction_or_conforming = false, - .executable = false, - .type = segment_type::system, - .privilege_level = 0, - .present = true, - .limit_high = (limit >> 16) & 0xf, // NOLINT(readability-magic-numbers) - .long_mode = false, - .protected_mode = false, - .granularity = segment_granularity::byte, - .base_high = (address >> 24) & 0xff, // NOLINT(readability-magic-numbers) - }, - (address >> 32) & 0xffff'ffff, // NOLINT(readability-magic-numbers) - }; - } - } // namespace - - auto initialize_descriptors() -> void - { - auto static tss = task_state_segment{}; - auto static tss_descriptor = make_tss_descriptor(&tss); - - auto static gdt = global_descriptor_table{ - gdt_null_descriptor, gdt_kernel_code_descriptor, gdt_kernel_data_descriptor, - gdt_user_code_descriptor, gdt_user_data_descriptor, tss_descriptor, - }; - - kstd::println("[x86_64:SYS] Reloading Global Descriptor Table."); - gdt.load(1, 2); - - kstd::println("[x86_64:SYS] Initializing Interrupt Descriptor Table."); - auto static idt = interrupt_descriptor_table{}; - idt.load(); - } - - auto initialize_legacy_interrupts() -> void - { - constexpr auto pic_init_command = std::uint8_t{0x11}; - constexpr auto pic_master_offset = std::uint8_t{0x20}; - constexpr auto pic_slave_offset = std::uint8_t{0x28}; - constexpr auto pic_cascade_address = std::uint8_t{0x04}; - constexpr auto pic_cascade_slave_identity = std::uint8_t{0x02}; - constexpr auto pic_use_8086_mode = std::uint8_t{0x01}; - constexpr auto pic_master_mask = std::uint8_t{0x00}; - constexpr auto pic_slave_mask = std::uint8_t{0x00}; - - pic_master_control_port::write(pic_init_command); - pic_slave_control_port::write(pic_init_command); - - pic_master_data_port::write(pic_master_offset); - pic_slave_data_port::write(pic_slave_offset); - - pic_master_data_port::write(pic_cascade_address); - pic_slave_data_port::write(pic_cascade_slave_identity); - - pic_master_data_port::write(pic_use_8086_mode); - pic_slave_data_port::write(pic_use_8086_mode); - - pic_master_data_port::write(pic_master_mask); - pic_slave_data_port::write(pic_slave_mask); - - pic_master_data_port::write(pic_master_mask); - pic_slave_data_port::write(pic_slave_mask); - } - -} // namespace arch::cpu diff --git a/arch/x86_64/src/cpu/interrupt_stubs.S b/arch/x86_64/src/cpu/interrupt_stubs.S deleted file mode 100644 index e59bdd2..0000000 --- a/arch/x86_64/src/cpu/interrupt_stubs.S +++ /dev/null @@ -1,112 +0,0 @@ -.altmacro - -.macro ISR_WITHOUT_ERROR_CODE vector - .global isr\vector - isr\vector: - pushq $0 - pushq $\vector - jmp common_interrupt_handler -.endm - -.macro ISR_WITH_ERROR_CODE vector - .global isr\vector - isr\vector: - pushq $\vector - jmp common_interrupt_handler -.endm - -.macro ISR_TABLE_ENTRY vector - .quad isr\vector -.endm - -.section .rodata -.global isr_stub_table -.align 16 - -isr_stub_table: -.set i, 0 -.rept 256 - ISR_TABLE_ENTRY %i - .set i, i + 1 -.endr - - -.section .text - -common_interrupt_handler: - push %rax - push %rbx - push %rcx - push %rdx - push %rbp - push %rsi - push %rdi - push %r8 - push %r9 - push %r10 - push %r11 - push %r12 - push %r13 - push %r14 - push %r15 - - mov %rsp, %rdi - call interrupt_dispatch - - pop %r15 - pop %r14 - pop %r13 - pop %r12 - pop %r11 - pop %r10 - pop %r9 - pop %r8 - pop %rdi - pop %rsi - pop %rbp - pop %rdx - pop %rcx - pop %rbx - pop %rax - - add $16, %rsp - iretq - -ISR_WITHOUT_ERROR_CODE 0 -ISR_WITHOUT_ERROR_CODE 1 -ISR_WITHOUT_ERROR_CODE 2 -ISR_WITHOUT_ERROR_CODE 3 -ISR_WITHOUT_ERROR_CODE 4 -ISR_WITHOUT_ERROR_CODE 5 -ISR_WITHOUT_ERROR_CODE 6 -ISR_WITHOUT_ERROR_CODE 7 -ISR_WITH_ERROR_CODE 8 -ISR_WITHOUT_ERROR_CODE 9 -ISR_WITH_ERROR_CODE 10 -ISR_WITH_ERROR_CODE 11 -ISR_WITH_ERROR_CODE 12 -ISR_WITH_ERROR_CODE 13 -ISR_WITH_ERROR_CODE 14 -ISR_WITHOUT_ERROR_CODE 15 -ISR_WITHOUT_ERROR_CODE 16 -ISR_WITH_ERROR_CODE 17 -ISR_WITHOUT_ERROR_CODE 18 -ISR_WITHOUT_ERROR_CODE 19 -ISR_WITHOUT_ERROR_CODE 20 -ISR_WITH_ERROR_CODE 21 -ISR_WITHOUT_ERROR_CODE 22 -ISR_WITHOUT_ERROR_CODE 23 -ISR_WITHOUT_ERROR_CODE 24 -ISR_WITHOUT_ERROR_CODE 25 -ISR_WITHOUT_ERROR_CODE 26 -ISR_WITHOUT_ERROR_CODE 27 -ISR_WITHOUT_ERROR_CODE 28 -ISR_WITH_ERROR_CODE 29 -ISR_WITH_ERROR_CODE 30 -ISR_WITHOUT_ERROR_CODE 31 - -.set i, 32 -.rept 256 - 32 - ISR_WITHOUT_ERROR_CODE %i - .set i, i + 1 -.endr diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp deleted file mode 100644 index f40422f..0000000 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ /dev/null @@ -1,203 +0,0 @@ -#include - -#include -#include - -#include -#include -#include - -#include - -#include - -namespace arch::cpu -{ - - namespace - { - 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; - } - } - - constexpr auto has_error_code(exception e) - { - 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 dispatch_exception(interrupt_frame * frame) -> bool - { - auto type = to_exception_type(static_cast(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); - } - } // namespace - - extern "C" - { - extern std::uintptr_t const isr_stub_table[256]; - - auto interrupt_dispatch(interrupt_frame * frame) -> void - { - auto [number, code] = frame->interrupt; - - if (number < number_of_exception_vectors) - { - if (!dispatch_exception(frame)) - { - if (has_error_code(static_cast(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); - } - } - } - else - { - 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); - } - } - } - - interrupt_descriptor_table::interrupt_descriptor_table() noexcept - { - for (auto i = 0uz; i < 256; ++i) - { - m_descriptors[i] = gate_descriptor{ - .offset_low = static_cast(isr_stub_table[i] & 0xffff), // NOLINT(readability-magic-numbers) - .m_code_segment = segment_selector{0, false, 1}, - .interrupt_stack_table_selector = 0, - .gate_type = (i < 32 && i != 2) ? gate_type::trap_gate : gate_type::interrupt_gate, - .descriptor_privilege_level = 0, - .present = true, - .offset_middle = - static_cast((isr_stub_table[i] >> 16) & 0xffff), // NOLINT(readability-magic-numbers) - .offset_high = - static_cast((isr_stub_table[i] >> 32) & 0xffff'ffff), // NOLINT(readability-magic-numbers) - }; - } - } - - auto interrupt_descriptor_table::load() const -> void - { - interrupt_descriptor_table_register{.limit = sizeof(m_descriptors) - 1, .base = m_descriptors.data()}.load(); - } - - auto interrupt_descriptor_table_register::load() const -> void - { - asm volatile("lidt %0" : : "m"(*this)); - } - - auto interrupt_descriptor_table_register::read() -> interrupt_descriptor_table_register - { - interrupt_descriptor_table_register idtr{}; - asm volatile("sidt %0" : : "m"(idtr)); - return idtr; - } - -} // namespace arch::cpu \ No newline at end of file diff --git a/arch/x86_64/src/debug/qemu_output.cpp b/arch/x86_64/src/debug/qemu_output.cpp deleted file mode 100644 index 71acede..0000000 --- a/arch/x86_64/src/debug/qemu_output.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include - -#include - -#include -#include - -namespace arch::debug -{ - - qemu_output::qemu_output(output_device & lower) - : m_lower{lower} - , m_present{port::read() == port::address} - {} - - auto qemu_output::write(kapi::cio::output_stream stream, std::string_view text) -> void - { - if (m_present) - { - std::ranges::for_each(text, port::write); - } - m_lower.write(stream, text); - } - -} // namespace arch::debug diff --git a/arch/x86_64/src/devices/init.cpp b/arch/x86_64/src/devices/init.cpp deleted file mode 100644 index c30e8cf..0000000 --- a/arch/x86_64/src/devices/init.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include - -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include - -#include -#include - -namespace arch::devices -{ - - namespace - { - constexpr auto pit_frequency_in_hz = std::uint32_t{100u}; - - auto get_acpi_root_pointer() -> kstd::observer_ptr<::acpi::rsdp const> - { - auto const & mbi = kapi::boot::bootstrap_information.mbi; - auto system_description_pointer = static_cast<::acpi::rsdp const *>(nullptr); - - if (auto const & xsdp = mbi->maybe_acpi_xsdp()) - { - auto data = xsdp->pointer().data(); - - system_description_pointer = reinterpret_cast<::acpi::xsdp const *>(data); - } - else if (auto const & rsdp = mbi->maybe_acpi_rsdp()) - { - auto data = rsdp->pointer().data(); - system_description_pointer = reinterpret_cast<::acpi::rsdp const *>(data); - } - - return kstd::make_observer(system_description_pointer); - } - } // namespace - - auto init_acpi_devices() -> void - { - auto acpi_root_pointer = get_acpi_root_pointer(); - if (acpi_root_pointer && acpi_root_pointer->validate()) - { - if (kapi::acpi::init(*acpi_root_pointer)) - { - kstd::println("[x86_64:DEV] ACPI subsystem initialized."); - } - } - - kapi::cpu::discover_topology(); - } - - auto init_legacy_devices() -> void - { - kstd::println("[x86_64:DEV] Initializing ISA bus..."); - - auto isa_major_number = kapi::devices::allocate_major_number(); - auto isa_bus = kstd::make_unique(isa_major_number); - - auto pit_major_number = kapi::devices::allocate_major_number(); - auto pit = kstd::make_unique(pit_major_number, pit_frequency_in_hz); - isa_bus->add_child(std::move(pit)); - - auto & root_bus = kapi::devices::get_root_bus(); - root_bus.add_child(std::move(isa_bus)); - } - -} // namespace arch::devices diff --git a/arch/x86_64/src/devices/legacy_pit.cpp b/arch/x86_64/src/devices/legacy_pit.cpp deleted file mode 100644 index d542d47..0000000 --- a/arch/x86_64/src/devices/legacy_pit.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include - -#include - -#include -#include -#include - -#include -#include - -namespace arch::devices -{ - - namespace - { - using command_port = io::port<0x43, std::uint8_t, io::port_write>; - using channel_0_port = io::port<0x40, std::uint8_t, io::port_write>; - using channel_1_port = io::port<0x41, std::uint8_t, io::port_write>; - using channel_2_port = io::port<0x42, std::uint8_t, io::port_write>; - - constexpr auto base_frequency = 1'193'182u; - constexpr auto square_wave_mode = 0x36; - } // namespace - - legacy_pit::legacy_pit(std::size_t major, std::uint32_t frequency_in_hz) - : kapi::devices::device{major, 0, "legacy_pit"} - , m_irq_number{0} - , m_frequency_in_hz{frequency_in_hz} - {} - - auto legacy_pit::init() -> bool - { - auto divisor = static_cast(base_frequency / m_frequency_in_hz); - - kapi::interrupts::register_handler(m_irq_number, *this); - - command_port::write(square_wave_mode); - io::wait(); - channel_0_port::write(divisor & 0xff); - io::wait(); - channel_0_port::write(divisor >> 8 & 0xff); - io::wait(); - - return true; - } - - auto legacy_pit::handle_interrupt(std::uint32_t irq_number) -> kapi::interrupts::status - { - if (irq_number != m_irq_number) - { - return kapi::interrupts::status::unhandled; - } - - ++m_ticks; - - return kapi::interrupts::status::handled; - } - -} // namespace arch::devices \ No newline at end of file diff --git a/arch/x86_64/src/devices/local_apic.cpp b/arch/x86_64/src/devices/local_apic.cpp deleted file mode 100644 index 660921b..0000000 --- a/arch/x86_64/src/devices/local_apic.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include - -#include -#include - -#include - -#include -#include -#include - -namespace arch::devices -{ - - namespace - { - constexpr auto lapic_enable_bit = 0x100u; - constexpr auto spurious_interrupt_vector = 0xFFu; - - constexpr auto offset_of_version = 0u; - constexpr auto offset_of_max_lvt_entry = 16u; - constexpr auto offset_of_eoi_suppression = 24u; - - } // namespace - - enum struct local_apic::registers : std::ptrdiff_t - { - id = 0x020, - version = 0x030, - task_priority = 0x080, - arbitration_priority = 0x090, - processor_priority = 0x0a0, - eoi = 0x0b0, - remote_read = 0x0c0, - logical_destination = 0x0d0, - destination_format = 0x0e0, - spurious_interrupt_vector = 0x0f0, - in_service_0 = 0x100, - in_service_1 = 0x110, - in_service_2 = 0x120, - in_service_3 = 0x130, - in_service_4 = 0x140, - in_service_5 = 0x150, - in_service_6 = 0x160, - in_service_7 = 0x170, - trigger_mode_0 = 0x180, - trigger_mode_1 = 0x190, - trigger_mode_2 = 0x1a0, - trigger_mode_3 = 0x1b0, - trigger_mode_4 = 0x1c0, - trigger_mode_5 = 0x1d0, - trigger_mode_6 = 0x1e0, - trigger_mode_7 = 0x1f0, - interrupt_request_0 = 0x200, - interrupt_request_1 = 0x210, - interrupt_request_2 = 0x220, - interrupt_request_3 = 0x230, - interrupt_request_4 = 0x240, - interrupt_request_5 = 0x250, - interrupt_request_6 = 0x260, - interrupt_request_7 = 0x270, - error_status = 0x280, - lvt_corrected_machine_check_interrupt = 0x2f0, - interrupt_command_0 = 0x300, - interrupt_command_1 = 0x310, - lvt_timer = 0x320, - lvt_thermal_sensors = 0x330, - lvt_performance_monitoring_counters = 0x340, - lvt_local_interrupt_0 = 0x350, - lvt_local_interrupt_1 = 0x360, - lvt_error = 0x370, - initial_count = 0x380, - current_count = 0x390, - divide_configuration = 0x3e0, - }; - - local_apic::local_apic(std::size_t major, std::size_t minor, std::uint64_t hardware_id, - kapi::memory::physical_address base, bool is_bsp) - : kapi::devices::device{major, minor, "lapic"} - , m_hardware_id{hardware_id} - , m_base{base} - , m_is_bsp{is_bsp} - {} - - auto local_apic::init() -> bool - { - auto static shared_virtual_base = kapi::memory::allocate_mmio_region(1); - auto static is_mapped = false; - - if (!is_mapped) - { - if (!kapi::memory::map_mmio_region(shared_virtual_base, m_base, kapi::memory::page_mapper::flags::writable)) - { - kstd::println("[x86_64:DEV] LAPIC {} MMIO mapping failed!", m_hardware_id); - return false; - } - is_mapped = true; - } - - m_mapped_region = shared_virtual_base; - - if (m_is_bsp) - { - auto raw_version = read_register(registers::version); - m_version = (raw_version >> offset_of_version) & 0xff; - m_highest_lvt_entry_index = (raw_version >> offset_of_max_lvt_entry) & 0xff; - m_supports_eoi_broadcast_suppression = (raw_version >> offset_of_eoi_suppression) & 0x1; - - write_register(registers::spurious_interrupt_vector, lapic_enable_bit | spurious_interrupt_vector); - - kstd::println("[x86_64:DEV] LAPIC initialized. version: {#x} | max_lvt_entry: {} | eoi_suppression: {:s}", - m_version, m_highest_lvt_entry_index, m_supports_eoi_broadcast_suppression); - } - else - { - kstd::println("[x86_64:DEV] LAPIC {} is not on the BSP, deferring initialization.", m_hardware_id); - } - - return true; - } - - auto local_apic::read_register(registers id) const -> std::uint32_t - { - auto reg = static_cast(m_mapped_region.first + std::to_underlying(id)); - return *reg; - } - - auto local_apic::write_register(registers id, std::uint32_t value) -> void - { - auto reg = static_cast(m_mapped_region.first + std::to_underlying(id)); - *reg = value; - } - -} // namespace arch::devices diff --git a/arch/x86_64/src/memory/higher_half_mapper.cpp b/arch/x86_64/src/memory/higher_half_mapper.cpp deleted file mode 100644 index 75adb3c..0000000 --- a/arch/x86_64/src/memory/higher_half_mapper.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace arch::memory -{ - - higher_half_mapper::higher_half_mapper(page_table * root) - : m_root{root} - {} - - auto higher_half_mapper::map(kapi::memory::page page, kapi::memory::frame frame, flags flags) -> std::byte * - { - auto table = get_or_create_page_table(page); - if (!table) - { - return nullptr; - } - - auto const index = pml_index(1, page); - auto & entry = (*table)[index]; - - if (entry.present()) - { - kapi::system::panic("[x86_64:MEM] Tried to map a page that is already mapped!"); - } - - entry.frame(frame, to_table_flags(flags) | page_table::entry::flags::present); - - return static_cast(page.start_address()); - } - - auto higher_half_mapper::unmap(kapi::memory::page page) -> void - { - if (!try_unmap(page)) - { - kapi::system::panic("[x86_64:MEM] Tried to unmap a page that is not mapped!"); - } - } - - auto higher_half_mapper::try_unmap(kapi::memory::page page) noexcept -> bool - { - auto table_path = std::array, 4>{}; - table_path[0] = std::pair{m_root, pml_index(4, page)}; - - for (auto level = 4uz; level > 1uz; --level) - { - auto [table, index] = table_path[4 - level]; - auto & entry = (*table)[index]; - - if (!entry.present()) - { - return false; - } - - auto next_table = to_higher_half_pointer(entry.frame()->start_address()); - auto next_index = pml_index(4 - level - 1, page); - table_path[4 - level - 1] = std::pair{next_table, next_index}; - } - - std::ranges::for_each(std::views::reverse(table_path), [previous_was_empty = true](auto & step) mutable { - auto [table, index] = step; - auto & entry = (*table)[index]; - auto frame = entry.frame(); - - if (previous_was_empty) - { - entry.clear(); - previous_was_empty = table->empty(); - kapi::memory::get_frame_allocator().release(*frame); - } - }); - - return true; - } - - auto higher_half_mapper::get_or_create_page_table(kapi::memory::page page) noexcept -> page_table * - { - auto table = m_root; - - for (auto level = 4uz; level > 1uz; --level) - { - auto index = pml_index(level, page); - auto & entry = (*table)[index]; - - if (!entry.present()) - { - auto table_frame = kapi::memory::allocate_frame(); - if (!table_frame) - { - return nullptr; - } - - auto new_table = to_higher_half_pointer(table_frame->start_address()); - std::construct_at(new_table); - - auto const flags = page_table::entry::flags::present | page_table::entry::flags::writable | - page_table::entry::flags::user_accessible; - entry.frame(*table_frame, flags); - } - - table = to_higher_half_pointer(entry.frame()->start_address()); - } - - return table; - } - -} // namespace arch::memory \ No newline at end of file diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp deleted file mode 100644 index 74272a0..0000000 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include - -#include - -#include -#include - -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -using namespace std::string_view_literals; -using namespace kstd::units_literals; - -namespace arch::memory -{ - - namespace - { - constexpr auto static ignored_section_prefixes = std::array{ - ".boot_"sv, - }; - - constexpr auto static user_accessible_prefixes = std::array{ - ".user"sv, - ".stl"sv, - }; - - } // namespace - - kernel_mapper::kernel_mapper(multiboot2::information_view const * mbi) - : m_mbi{std::move(mbi)} - , m_kernel_load_base{std::bit_cast(&arch::boot::TEACHOS_VMA)} - {} - - auto kernel_mapper::remap_kernel(kapi::memory::page_mapper & mapper) -> void - { - auto elf_information = m_mbi->maybe_elf_symbols(); - if (!elf_information) - { - kapi::system::panic("[x86_64:MEM] ELF section information is not available."); - } - - auto sections = *elf_information; - auto allocated_sections = - std::views::all(sections) | std::views::filter(&elf::section_header::allocated) | - std::views::filter([&](auto const & section) -> auto { - auto name = sections.name(section); - return !std::ranges::any_of(ignored_section_prefixes, - [&](auto const & prefix) -> auto { return name.starts_with(prefix); }); - }); - - if (allocated_sections.empty()) - { - kapi::system::panic("[x86_64:MEM] No allocated ELF sections were found."); - } - - std::ranges::for_each(allocated_sections, - [&](auto const & section) -> auto { map_section(section, sections.name(section), mapper); }); - } - - auto kernel_mapper::map_section(section_header_type const & section, std::string_view name, - kapi::memory::page_mapper & mapper) -> void - { - auto number_of_pages = - (kstd::units::bytes{section.size} + (kapi::memory::page::size - 1_B)) / kapi::memory::page::size; - auto linear_start_address = kapi::memory::linear_address{section.virtual_load_address}; - auto physical_start_address = kapi::memory::physical_address{section.virtual_load_address & ~m_kernel_load_base}; - - kstd::println("[x86_64:MEM] mapping {}" - "\n {} bytes -> page count: {}" - "\n {} @ {}", - name, section.size, number_of_pages, linear_start_address, physical_start_address); - - auto first_page = kapi::memory::page::containing(linear_start_address); - auto first_frame = kapi::memory::frame::containing(physical_start_address); - - auto page_flags = kapi::memory::page_mapper::flags::empty; - - if (section.writable()) - { - page_flags |= kapi::memory::page_mapper::flags::writable; - } - - if (section.executable()) - { - page_flags |= kapi::memory::page_mapper::flags::executable; - } - - auto is_prefix_of_name = [=](auto prefix) -> bool { - return name.starts_with(prefix); - }; - - if (!std::ranges::any_of(user_accessible_prefixes, is_prefix_of_name)) - { - page_flags |= kapi::memory::page_mapper::flags::supervisor_only; - } - - for (auto i = 0uz; i < number_of_pages; ++i) - { - mapper.map(first_page + i, first_frame + i, page_flags); - } - } - -} // namespace arch::memory \ No newline at end of file diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp deleted file mode 100644 index 2b53fa4..0000000 --- a/arch/x86_64/src/memory/mmu.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include - -#include - -#include - -namespace arch::memory -{ - auto tlb_flush(kapi::memory::linear_address address) -> void - { - asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); - } - - auto tlb_flush_all() -> void - { - auto paging_root = cpu::cr3::read(); - cpu::cr3::write(paging_root); - } -} // namespace arch::memory diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp deleted file mode 100644 index 2180420..0000000 --- a/arch/x86_64/src/memory/page_table.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include - -#include - -#include -#include -#include -#include -#include -#include - -namespace arch::memory -{ - - auto page_table::entry::clear() noexcept -> void - { - m_raw = 0; - } - - auto page_table::entry::present() const noexcept -> bool - { - return (all_flags() & flags::present) != flags::empty; - } - - auto page_table::entry::huge() const noexcept -> bool - { - return (all_flags() & flags::huge_page) != flags::empty; - } - - auto page_table::entry::all_flags() const noexcept -> flags - { - return std::bit_cast(m_raw & ~frame_number_mask); - } - - auto page_table::entry::all_flags(flags flags) noexcept -> void - { - m_raw = (m_raw & ~frame_number_mask) | std::to_underlying(flags); - } - - auto page_table::entry::operator|=(flags rhs) noexcept -> page_table::entry & - { - auto raw_flags = std::to_underlying(rhs) & ~frame_number_mask; - m_raw |= raw_flags; - return *this; - } - - auto page_table::entry::frame() const noexcept -> std::optional - { - if (present()) - { - return kapi::memory::frame::containing(kapi::memory::physical_address{m_raw & frame_number_mask}); - } - return std::nullopt; - } - - auto page_table::entry::frame(kapi::memory::frame frame, flags flags) noexcept -> void - { - m_raw = (frame.start_address().raw() | static_cast(flags)); - }; - - auto page_table::operator[](std::size_t index) -> entry & - { - return m_entries.at(index); - } - - auto page_table::operator[](std::size_t index) const -> entry const & - { - return m_entries.at(index); - } - - auto page_table::clear() noexcept -> void - { - std::ranges::for_each(m_entries, &page_table::entry::clear); - } - - auto page_table::empty() const noexcept -> bool - { - return std::ranges::all_of(m_entries, - [](auto const & entry) -> auto { return entry.all_flags() == entry::flags::empty; }); - } - -} // namespace arch::memory diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp deleted file mode 100644 index 4086a10..0000000 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include - -namespace arch::memory -{ - namespace - { - constexpr auto last_frame(multiboot2::memory_map::region const & region) - { - return kapi::memory::frame::containing(kapi::memory::physical_address{region.base + region.size_in_B - 1}); - } - - constexpr auto falls_within(kapi::memory::frame const & candidate, kapi::memory::frame const & start, - kapi::memory::frame const & end) - { - return candidate >= start && candidate <= end; - } - } // namespace - - region_allocator::region_allocator(memory_information const & mem_info) - : m_next_frame{} - , m_current_region{} - , m_memory_map{mem_info.memory_map} - , m_kernel_start{kapi::memory::frame::containing(mem_info.image_range.first)} - , m_kernel_end{kapi::memory::frame::containing(mem_info.image_range.second)} - , m_multiboot_start{kapi::memory::frame::containing(mem_info.mbi_range.first)} - , m_multiboot_end{kapi::memory::frame::containing(mem_info.mbi_range.second)} - , m_multiboot_information{mem_info.mbi} - { - choose_next_region(); - } - - auto region_allocator::choose_next_region() -> void - { - m_current_region.reset(); - - auto remaining_regions = - m_memory_map | // - std::views::filter(&multiboot2::memory_map::region::available) | - std::views::filter([this](auto const & region) -> bool { return last_frame(region) >= m_next_frame; }); - - auto lowest_region = - std::ranges::min_element(remaining_regions, [](auto lhs, auto rhs) -> bool { return lhs.base < rhs.base; }); - - if (lowest_region == remaining_regions.end()) - { - return; - } - - m_current_region = *lowest_region; - if (auto start_of_region = kapi::memory::frame::containing(kapi::memory::physical_address{m_current_region->base}); - start_of_region > m_next_frame) - { - m_next_frame = start_of_region; - } - } - - auto region_allocator::find_next_frame() -> std::optional - { - if (!m_current_region || m_next_frame > last_frame(*m_current_region)) - { - choose_next_region(); - if (!m_current_region) - { - return std::nullopt; - } - } - - auto advanced = true; - while (advanced) - { - advanced = false; - - if (falls_within(m_next_frame, m_kernel_start, m_kernel_end)) - { - m_next_frame = m_kernel_end + 1; - advanced = true; - continue; - } - - if (falls_within(m_next_frame, m_multiboot_start, m_multiboot_end)) - { - m_next_frame = m_multiboot_end + 1; - advanced = true; - continue; - } - - if (m_multiboot_information) - { - for (auto const & module : m_multiboot_information->modules()) - { - auto module_start = kapi::memory::frame::containing(kapi::memory::physical_address{module.start_address}); - auto module_end = kapi::memory::frame::containing(kapi::memory::physical_address{module.end_address}); - - if (falls_within(m_next_frame, module_start, module_end)) - { - m_next_frame = module_end + 1; - advanced = true; - break; - } - } - } - } - - if (m_next_frame > last_frame(*m_current_region)) - { - choose_next_region(); - } - - return m_current_region.transform([this](auto) -> auto { return m_next_frame; }); - } - - auto region_allocator::allocate_many(std::size_t count) noexcept - -> std::optional> - { - while (m_current_region) - { - auto result = find_next_frame(); - - if (result) - { - auto region_end = last_frame(*m_current_region); - if ((region_end.number() - result->number()) >= count) - { - m_next_frame = m_next_frame + count; - return std::make_pair(*result, count); - } - else - { - m_next_frame = region_end + 1; - choose_next_region(); - } - } - } - - return std::nullopt; - } - - auto region_allocator::mark_used(kapi::memory::frame frame) -> void - { - if (frame < m_next_frame) - { - m_next_frame = frame; - find_next_frame(); - } - } - - auto region_allocator::release_many(std::pair) -> void {} - - auto region_allocator::next_free_frame() noexcept -> std::optional - { - return find_next_frame(); - } - -} // namespace arch::memory diff --git a/arch/x86_64/src/vga/text/buffer.cpp b/arch/x86_64/src/vga/text/buffer.cpp deleted file mode 100644 index 498b9a3..0000000 --- a/arch/x86_64/src/vga/text/buffer.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include - -#include - -#include -#include -#include -#include -#include -#include - -namespace arch::vga::text -{ - buffer::buffer(std::size_t width, std::size_t height, cell * start, std::size_t position) - : m_width{width} - , m_height{height} - , m_buffer{start, m_width * m_height} - , m_position{position} - {} - - auto buffer::clear() -> void - { - m_position = 0; - std::ranges::fill(m_buffer, std::pair{'\0', static_cast(0x00)}); - } - - auto buffer::write(std::string_view code_points, attribute attribute) -> void - { - std::ranges::for_each(code_points, [&](auto code_point) -> void { write(code_point, attribute); }); - } - - auto buffer::write(char code_point, attribute attribute) -> void - { - if (m_position + 1 > m_height * m_width) - { - scroll(); - } - - if (!handle_special_code_point(code_point, attribute)) - { - do_write(code_point, attribute); - } - }; - - auto buffer::newline() -> void - { - auto free_glyphs_in_line = m_width - column(); - m_position += free_glyphs_in_line; - } - - auto buffer::scroll(std::size_t nof_lines) -> void - { - auto scroll_count = std::min(nof_lines, m_height); - - auto scroll_start = m_buffer.begin() + (scroll_count * m_width); - std::ranges::move(scroll_start, m_buffer.end(), m_buffer.begin()); - - auto clear_start = m_buffer.begin() + (m_height - scroll_count) * m_width; - std::ranges::fill(clear_start, m_buffer.end(), cell{}); - - m_position = (line() - scroll_count) * m_width; - } - - auto buffer::column() const noexcept -> std::ptrdiff_t - { - return m_position % m_width; - } - - auto buffer::line() const noexcept -> std::ptrdiff_t - { - return m_position / m_width; - } - auto buffer::handle_special_code_point(char code_point, attribute attribute) -> bool - { - switch (code_point) - { - case '\n': - newline(); - return true; - case '\r': - m_position -= column(); - return true; - case '\t': - do_write(" ", attribute); - return true; - default: - return false; - } - } - - auto buffer::do_write(std::string_view code_points, attribute attribute) -> void - { - std::ranges::for_each(code_points, [&](auto code_point) -> void { do_write(code_point, attribute); }); - } - - auto buffer::do_write(char code_point, attribute attribute) -> void - { - m_buffer[m_position++] = std::pair{code_point, std::bit_cast(attribute)}; - } - -} // namespace arch::vga::text diff --git a/arch/x86_64/src/vga/text/device.cpp b/arch/x86_64/src/vga/text/device.cpp deleted file mode 100644 index 8468358..0000000 --- a/arch/x86_64/src/vga/text/device.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -namespace arch::vga::text -{ - namespace - { - constexpr auto default_buffer_address = std::uintptr_t{0xb8000}; - constexpr auto default_buffer_width = 80z; - constexpr auto default_buffer_height = 25z; - - constexpr auto bit_cursor_enabled = 5U; - } // namespace - - device::device() - : m_buffer{ - default_buffer_width, default_buffer_height, - std::bit_cast(default_buffer_address + std::bit_cast(&boot::TEACHOS_VMA)), - kapi::boot::bootstrap_information.vga_buffer_index} - { - clear(); - } - - auto device::clear() -> void - { - m_buffer.clear(); - } - - auto device::cursor(bool enabled) -> void - { - auto cursor_disable_byte = std::byte{!enabled} << bit_cursor_enabled; - - crtc::address::write(crtc::registers::cursor_start); - crtc::data::write(crtc::data::read() | cursor_disable_byte); - } - - auto device::write(kapi::cio::output_stream stream, std::string_view text) -> void - { - auto attributes = [&] -> attribute { - switch (stream) - { - case kapi::cio::output_stream::stderr: - return red_on_black; - default: - return green_on_black; - } - }(); - m_buffer.write(text, attributes); - } - -} // namespace arch::vga::text -- cgit v1.2.3