From fefc9a138f4d4f26e6b676c4cdca77b3140e4206 Mon Sep 17 00:00:00 2001 From: "marcel.braun" Date: Tue, 17 Feb 2026 17:41:10 +0100 Subject: Save WIP --- arch/x86_64/support/grub.cfg.in | 1 + arch/x86_64/support/modules/test.img | Bin 0 -> 2097152 bytes 2 files changed, 1 insertion(+) create mode 100644 arch/x86_64/support/modules/test.img (limited to 'arch') diff --git a/arch/x86_64/support/grub.cfg.in b/arch/x86_64/support/grub.cfg.in index 49f19ce..b29fc36 100644 --- a/arch/x86_64/support/grub.cfg.in +++ b/arch/x86_64/support/grub.cfg.in @@ -3,5 +3,6 @@ default=0 menuentry "TeachOS" { multiboot2 /$ + module2 isofs/modules/test.img boot } \ No newline at end of file diff --git a/arch/x86_64/support/modules/test.img b/arch/x86_64/support/modules/test.img new file mode 100644 index 0000000..914fa7f Binary files /dev/null and b/arch/x86_64/support/modules/test.img differ -- cgit v1.2.3 From bbbf8c9032a54da4115d57d2897f8bb0a698895b Mon Sep 17 00:00:00 2001 From: "marcel.braun" Date: Tue, 17 Feb 2026 18:41:25 +0100 Subject: Copy modules to isofs folder --- arch/x86_64/support/grub.cfg.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/support/grub.cfg.in b/arch/x86_64/support/grub.cfg.in index b29fc36..09d2ace 100644 --- a/arch/x86_64/support/grub.cfg.in +++ b/arch/x86_64/support/grub.cfg.in @@ -3,6 +3,6 @@ default=0 menuentry "TeachOS" { multiboot2 /$ - module2 isofs/modules/test.img + module2 /modules/test.img boot } \ No newline at end of file -- cgit v1.2.3 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') 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 01549be5c53f74df3df1d7f9de3e702ffb906088 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Wed, 18 Feb 2026 10:35:30 +0100 Subject: add multiboot2 module tag, all modules can be iterated --- arch/x86_64/support/grub.cfg.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/support/grub.cfg.in b/arch/x86_64/support/grub.cfg.in index 09d2ace..834345a 100644 --- a/arch/x86_64/support/grub.cfg.in +++ b/arch/x86_64/support/grub.cfg.in @@ -3,6 +3,7 @@ default=0 menuentry "TeachOS" { multiboot2 /$ - module2 /modules/test.img + module2 /modules/test.img bbbbbbb + module2 /modules/test.img aaaa boot } \ No newline at end of file -- cgit v1.2.3 From ea8172296fa5b56137f97c01650b8d392bdb897f Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Thu, 26 Feb 2026 11:21:18 +0100 Subject: implemented remapping of bootloader modules --- arch/x86_64/kapi/memory.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'arch') diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index a9e1216..3a2d66b 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -118,6 +118,27 @@ namespace kapi::memory mapper.map(page, frame, page_mapper::flags::supervisor_only); } } + + [[maybe_unused]] auto remap_bootloader_modules(page_mapper & mapper) -> void + { + auto modules = boot::bootstrap_information.mbi->modules(); + + for (auto module : modules) + { + auto module_physical_start = physical_address{module.start_address}; + auto module_virtual_start = + linear_address{module.start_address + std::bit_cast(&arch::boot::TEACHOS_VMA)}; + auto module_size = module.end_address - module.start_address; + auto module_block_count = (module_size + PLATFORM_FRAME_SIZE - 1) / PLATFORM_FRAME_SIZE; + + for (auto i = 0uz; i < module_block_count; ++i) + { + auto page = page::containing(module_virtual_start) + i; + auto frame = frame::containing(module_physical_start) + i; + mapper.map(page, frame, page_mapper::flags::empty); // TODO BA-FS26 make writable? + } + } + } [[maybe_unused]] auto handoff_to_kernel_pmm(frame_allocator & new_allocator) -> void { @@ -196,6 +217,7 @@ namespace kapi::memory remap_kernel(*higher_half_mapper); remap_vga_text_mode_buffer(*higher_half_mapper); remap_multiboot_information(*higher_half_mapper); + remap_bootloader_modules(*recursive_page_mapper); auto current_cr3 = arch::cpu::cr3::read(); auto old_pml4 = static_cast(current_cr3.address()); -- cgit v1.2.3 From 035c8d6e38fd901e6769a81f67b8d9e1e3fcea20 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Thu, 26 Feb 2026 11:24:27 +0100 Subject: implemented boot_modules and boot_module_registry, init boot_modules in kernel main --- arch/x86_64/CMakeLists.txt | 1 + arch/x86_64/kapi/boot_modules.cpp | 51 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 arch/x86_64/kapi/boot_modules.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 41932c9..4ae09ff 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -12,6 +12,7 @@ target_link_libraries("x86_64" PUBLIC target_sources("x86_64" PRIVATE # Platform-dependent KAPI implementation + "kapi/boot_modules.cpp" "kapi/cio.cpp" "kapi/cpu.cpp" "kapi/memory.cpp" diff --git a/arch/x86_64/kapi/boot_modules.cpp b/arch/x86_64/kapi/boot_modules.cpp new file mode 100644 index 0000000..5d06eb5 --- /dev/null +++ b/arch/x86_64/kapi/boot_modules.cpp @@ -0,0 +1,51 @@ +#include "kapi/boot_modules.hpp" + +#include "kapi/boot.hpp" +#include "kapi/boot_module/boot_module.hpp" +#include "kapi/boot_module/boot_module_registry.hpp" +#include "kapi/system.hpp" + +#include "arch/boot/boot.hpp" +#include "arch/boot/ld.hpp" + +#include + +#include + +#include +#include +#include +#include +#include + +namespace kapi::boot_modules +{ + namespace + { + auto constinit registry = std::optional{}; + } // namespace + + auto init() -> void + { + auto static constinit is_initialized = std::atomic_flag{}; + if (is_initialized.test_and_set()) + { + system::panic("[x86_64] Boot module registry has already been initialized."); + } + + kstd::println("[x86_64:BOOT_MODULES] Initializing boot module registry."); + + registry.emplace(kapi::boot_modules::boot_module_registry{}); + + auto modules = boot::bootstrap_information.mbi->modules(); + std::ranges::for_each(modules, [](auto const & module) { + registry->add_boot_module(kapi::boot_modules::boot_module{ + .name = module.string(), + .start_address = module.start_address + std::bit_cast(&arch::boot::TEACHOS_VMA), + .size = module.end_address - module.start_address, + }); + }); + + set_boot_module_registry(*registry); + } +} // namespace kapi::boot_modules \ No newline at end of file -- cgit v1.2.3 From e84c7fbf336847d3ff62aac10ed8f6d04a06cbe8 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Fri, 27 Feb 2026 19:27:41 +0100 Subject: use linear_address instead of size_t --- arch/x86_64/kapi/boot_modules.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/boot_modules.cpp b/arch/x86_64/kapi/boot_modules.cpp index 5d06eb5..ba01285 100644 --- a/arch/x86_64/kapi/boot_modules.cpp +++ b/arch/x86_64/kapi/boot_modules.cpp @@ -3,6 +3,7 @@ #include "kapi/boot.hpp" #include "kapi/boot_module/boot_module.hpp" #include "kapi/boot_module/boot_module_registry.hpp" +#include "kapi/memory.hpp" #include "kapi/system.hpp" #include "arch/boot/boot.hpp" @@ -41,7 +42,8 @@ namespace kapi::boot_modules std::ranges::for_each(modules, [](auto const & module) { registry->add_boot_module(kapi::boot_modules::boot_module{ .name = module.string(), - .start_address = module.start_address + std::bit_cast(&arch::boot::TEACHOS_VMA), + .start_address = + memory::linear_address{module.start_address + std::bit_cast(&arch::boot::TEACHOS_VMA)}, .size = module.end_address - module.start_address, }); }); -- cgit v1.2.3 From 09e16896dfcd87c289be18b13867e64441efcaf5 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Tue, 3 Mar 2026 11:18:16 +0100 Subject: make module pages writable --- arch/x86_64/kapi/memory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index 3a2d66b..d6c0ad5 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -135,7 +135,7 @@ namespace kapi::memory { auto page = page::containing(module_virtual_start) + i; auto frame = frame::containing(module_physical_start) + i; - mapper.map(page, frame, page_mapper::flags::empty); // TODO BA-FS26 make writable? + mapper.map(page, frame, page_mapper::flags::writable); } } } -- cgit v1.2.3 From 3733baef9603581d6de2d35fda4535d37b6826b0 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Mon, 16 Mar 2026 19:51:53 +0100 Subject: protect multiboot2 boot modules --- arch/x86_64/kapi/memory.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index d6c0ad5..d9fbe28 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -174,9 +174,19 @@ namespace kapi::memory auto mbi_start = frame::containing(mbi_address); auto mbi_end = frame::containing(mbi_address + mbi_size) + 1; - // TODO BA-FS26: Protect MB2 boot modules - std::ranges::for_each(std::views::iota(mbi_start, mbi_end), [&](auto frame) { new_allocator.mark_used(frame); }); + + auto modules = boot::bootstrap_information.mbi->modules(); + for (auto module : modules) + { + auto module_physical_start = physical_address{module.start_address}; + auto module_size = module.end_address - module.start_address; + auto module_start = frame::containing(module_physical_start); + auto module_end = frame::containing(module_physical_start + module_size) + 1; + + std::ranges::for_each(std::views::iota(module_start, module_end), + [&](auto frame) { new_allocator.mark_used(frame); }); + } } } // namespace -- cgit v1.2.3 From 292c5ff7c0c0ae89cfed7124c3ad931b9f555d19 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Mon, 16 Mar 2026 19:58:15 +0100 Subject: refactoring --- arch/x86_64/kapi/memory.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index d9fbe28..f29afe8 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -121,10 +121,7 @@ namespace kapi::memory [[maybe_unused]] auto remap_bootloader_modules(page_mapper & mapper) -> void { - auto modules = boot::bootstrap_information.mbi->modules(); - - for (auto module : modules) - { + std::ranges::for_each(boot::bootstrap_information.mbi->modules(), [&mapper](auto const & module) { auto module_physical_start = physical_address{module.start_address}; auto module_virtual_start = linear_address{module.start_address + std::bit_cast(&arch::boot::TEACHOS_VMA)}; @@ -135,9 +132,9 @@ namespace kapi::memory { auto page = page::containing(module_virtual_start) + i; auto frame = frame::containing(module_physical_start) + i; - mapper.map(page, frame, page_mapper::flags::writable); + mapper.map(page, frame, page_mapper::flags::writable | page_mapper::flags::supervisor_only); } - } + }); } [[maybe_unused]] auto handoff_to_kernel_pmm(frame_allocator & new_allocator) -> void @@ -176,9 +173,7 @@ namespace kapi::memory std::ranges::for_each(std::views::iota(mbi_start, mbi_end), [&](auto frame) { new_allocator.mark_used(frame); }); - auto modules = boot::bootstrap_information.mbi->modules(); - for (auto module : modules) - { + std::ranges::for_each(boot::bootstrap_information.mbi->modules(), [&](auto const & module) { auto module_physical_start = physical_address{module.start_address}; auto module_size = module.end_address - module.start_address; auto module_start = frame::containing(module_physical_start); @@ -186,7 +181,7 @@ namespace kapi::memory std::ranges::for_each(std::views::iota(module_start, module_end), [&](auto frame) { new_allocator.mark_used(frame); }); - } + }); } } // namespace -- 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 --- .../include/arch/memory/region_allocator.hpp | 6 +++ arch/x86_64/kapi/memory.cpp | 1 + arch/x86_64/src/memory/region_allocator.cpp | 43 ++++++++++++++++------ 3 files changed, 39 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/memory/region_allocator.hpp b/arch/x86_64/include/arch/memory/region_allocator.hpp index 1c5885e..c7a836f 100644 --- a/arch/x86_64/include/arch/memory/region_allocator.hpp +++ b/arch/x86_64/include/arch/memory/region_allocator.hpp @@ -42,6 +42,11 @@ namespace arch::memory //! These include available, unavailable, and reclaimable regions. In general, only frames that are located in //! non-reserved (as in available) regions should be allocated for page storage. multiboot2::memory_map memory_map; + + //! The loader supplied Multiboot2 information structure. + //! + //! This is used to query boot module ranges so these frames can be excluded from early allocations. + multiboot2::information_view const * mbi; }; using region = multiboot2::memory_map::region; @@ -80,6 +85,7 @@ namespace arch::memory kapi::memory::frame m_kernel_end; //!< The end of the kernel image in physical memory. kapi::memory::frame m_multiboot_start; //!< The start of the Multiboot2 information in physical memory. kapi::memory::frame m_multiboot_end; //!< The end of the Multiboot2 information in physical memory. + multiboot2::information_view const * m_multiboot_information; //!< Source of Multiboot2 module ranges. }; } // namespace arch::memory diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index f29afe8..a354576 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -53,6 +53,7 @@ namespace kapi::memory .image_range = std::make_pair(physical_address{&image_span.front()}, physical_address{&image_span.back()}), .mbi_range = std::make_pair(physical_address{&mbi_span.front()}, physical_address{&mbi_span.back()}), .memory_map = *memory_map, + .mbi = mbi, }; } 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 59504cfd677dd3e9d9ddb0deea4df7614efedb84 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Tue, 17 Mar 2026 16:48:26 +0100 Subject: fix rebase (use higher_half_mapper not recursive_page_mapper) --- arch/x86_64/kapi/memory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index a354576..547d359 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -119,7 +119,7 @@ namespace kapi::memory mapper.map(page, frame, page_mapper::flags::supervisor_only); } } - + [[maybe_unused]] auto remap_bootloader_modules(page_mapper & mapper) -> void { std::ranges::for_each(boot::bootstrap_information.mbi->modules(), [&mapper](auto const & module) { @@ -223,7 +223,7 @@ namespace kapi::memory remap_kernel(*higher_half_mapper); remap_vga_text_mode_buffer(*higher_half_mapper); remap_multiboot_information(*higher_half_mapper); - remap_bootloader_modules(*recursive_page_mapper); + remap_bootloader_modules(*higher_half_mapper); auto current_cr3 = arch::cpu::cr3::read(); auto old_pml4 = static_cast(current_cr3.address()); -- 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') 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/kapi/memory.cpp | 4 ++-- arch/x86_64/src/memory/kernel_mapper.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index 547d359..07e7465 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -110,7 +110,7 @@ namespace kapi::memory auto mbi_size = boot::bootstrap_information.mbi->size_bytes(); auto mbi_physical_start = physical_address{mbi_base & ~std::bit_cast(&arch::boot::TEACHOS_VMA)}; auto mbi_virtual_start = linear_address{mbi_base}; - auto mbi_block_count = (mbi_size + PLATFORM_FRAME_SIZE - 1) / PLATFORM_FRAME_SIZE; + auto mbi_block_count = (mbi_size + frame::size - 1) / frame::size; for (auto i = 0uz; i < mbi_block_count; ++i) { @@ -127,7 +127,7 @@ namespace kapi::memory auto module_virtual_start = linear_address{module.start_address + std::bit_cast(&arch::boot::TEACHOS_VMA)}; auto module_size = module.end_address - module.start_address; - auto module_block_count = (module_size + PLATFORM_FRAME_SIZE - 1) / PLATFORM_FRAME_SIZE; + auto module_block_count = (module_size + frame::size - 1) / frame::size; for (auto i = 0uz; i < module_block_count; ++i) { 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/include/arch/memory/page_table.hpp | 3 ++- arch/x86_64/kapi/memory.cpp | 17 ++++++++++------- arch/x86_64/src/memory/kernel_mapper.cpp | 9 ++++++--- 3 files changed, 18 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/memory/page_table.hpp b/arch/x86_64/include/arch/memory/page_table.hpp index 2889d38..3cbb0af 100644 --- a/arch/x86_64/include/arch/memory/page_table.hpp +++ b/arch/x86_64/include/arch/memory/page_table.hpp @@ -4,6 +4,7 @@ #include "kapi/memory.hpp" #include +#include #include #include @@ -116,7 +117,7 @@ namespace arch::memory }; //! The maximum number of entries in this table. - constexpr auto static entry_count{kapi::memory::page::size / sizeof(entry)}; + constexpr auto static entry_count{kapi::memory::page::size / kstd::units::bytes{sizeof(entry)}}; //! Get the entry at the given index. //! diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index 07e7465..5f12e5c 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -13,6 +13,7 @@ #include "arch/memory/region_allocator.hpp" #include +#include #include #include @@ -28,6 +29,8 @@ #include #include +using namespace kstd::units_literals; + namespace kapi::memory { @@ -46,7 +49,7 @@ namespace kapi::memory } auto const & mbi = boot::bootstrap_information.mbi; - auto mbi_span = std::span{std::bit_cast(mbi), mbi->size_bytes()}; + auto mbi_span = std::span{std::bit_cast(mbi), static_cast(mbi->size())}; auto image_span = std::span{&arch::boot::_start_physical, &arch::boot::_end_physical}; return arch::memory::region_allocator::memory_information{ @@ -107,10 +110,10 @@ namespace kapi::memory [[maybe_unused]] auto remap_multiboot_information(page_mapper & mapper) -> void { auto mbi_base = std::bit_cast(boot::bootstrap_information.mbi); - auto mbi_size = boot::bootstrap_information.mbi->size_bytes(); + auto mbi_size = boot::bootstrap_information.mbi->size(); auto mbi_physical_start = physical_address{mbi_base & ~std::bit_cast(&arch::boot::TEACHOS_VMA)}; auto mbi_virtual_start = linear_address{mbi_base}; - auto mbi_block_count = (mbi_size + frame::size - 1) / frame::size; + auto mbi_block_count = (mbi_size + frame::size - 1_B) / frame::size; for (auto i = 0uz; i < mbi_block_count; ++i) { @@ -126,8 +129,8 @@ namespace kapi::memory auto module_physical_start = physical_address{module.start_address}; auto module_virtual_start = linear_address{module.start_address + std::bit_cast(&arch::boot::TEACHOS_VMA)}; - auto module_size = module.end_address - module.start_address; - auto module_block_count = (module_size + frame::size - 1) / frame::size; + auto module_size = static_cast(module.end_address - module.start_address); + auto module_block_count = (module_size + frame::size - 1_B) / frame::size; for (auto i = 0uz; i < module_block_count; ++i) { @@ -147,7 +150,7 @@ namespace kapi::memory })) { auto start = frame::containing(physical_address{region.base}); - auto count = region.size_in_B / page::size; + auto count = kstd::units::bytes{region.size_in_B} / page::size; new_allocator.release_many({start, count}); } @@ -167,7 +170,7 @@ namespace kapi::memory [&](auto frame) { new_allocator.mark_used(frame); }); auto mbi_base = std::bit_cast(boot::bootstrap_information.mbi); - auto mbi_size = boot::bootstrap_information.mbi->size_bytes(); + auto mbi_size = boot::bootstrap_information.mbi->size(); auto mbi_address = physical_address{mbi_base & ~std::bit_cast(&arch::boot::TEACHOS_VMA)}; auto mbi_start = frame::containing(mbi_address); auto mbi_end = frame::containing(mbi_address + mbi_size) + 1; 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/CMakeLists.txt | 3 + arch/x86_64/include/arch/cpu/initialization.hpp | 6 ++ arch/x86_64/kapi/system.cpp | 113 +--------------------- arch/x86_64/src/cpu/initialization.cpp | 122 ++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 111 deletions(-) create mode 100644 arch/x86_64/include/arch/cpu/initialization.hpp create mode 100644 arch/x86_64/src/cpu/initialization.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 4ae09ff..f053982 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -18,6 +18,9 @@ target_sources("x86_64" PRIVATE "kapi/memory.cpp" "kapi/system.cpp" + # CPU Initialization + "src/cpu/initialization.cpp" + # Low-level bootstrap "src/boot/boot32.S" "src/boot/entry64.s" diff --git a/arch/x86_64/include/arch/cpu/initialization.hpp b/arch/x86_64/include/arch/cpu/initialization.hpp new file mode 100644 index 0000000..b2ce864 --- /dev/null +++ b/arch/x86_64/include/arch/cpu/initialization.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace arch::cpu +{ + auto initialize_descriptors() -> void; +} // namespace arch::cpu diff --git a/arch/x86_64/kapi/system.cpp b/arch/x86_64/kapi/system.cpp index ca4418e..ffb6a46 100644 --- a/arch/x86_64/kapi/system.cpp +++ b/arch/x86_64/kapi/system.cpp @@ -1,122 +1,13 @@ #include "kapi/system.hpp" -#include "arch/cpu/global_descriptor_table.hpp" -#include "arch/cpu/segment_descriptor.hpp" -#include "arch/cpu/task_state_segment.hpp" - -#include - -#include -#include +#include "arch/cpu/initialization.hpp" namespace kapi::system { - namespace - { - constexpr auto gdt_null_descriptor = arch::cpu::segment_descriptor{}; - - constexpr auto gdt_kernel_code_descriptor = arch::cpu::segment_descriptor{ - .limit_low = 0xffff, - .base_low = 0, - .accessed = false, - .read_write = false, - .direction_or_conforming = false, - .executable = true, - .type = arch::cpu::segment_type::code_or_data, - .privilege_level = 0, - .present = true, - .limit_high = 0xf, - .long_mode = true, - .protected_mode = false, - .granularity = arch::cpu::segment_granularity::page, - .base_high = 0, - }; - - constexpr auto gdt_kernel_data_descriptor = arch::cpu::segment_descriptor{ - .limit_low = 0xffff, - .base_low = 0, - .accessed = false, - .read_write = true, - .direction_or_conforming = false, - .executable = false, - .type = arch::cpu::segment_type::code_or_data, - .privilege_level = 0, - .present = true, - .limit_high = 0xf, - .long_mode = false, - .protected_mode = true, - .granularity = arch::cpu::segment_granularity::page, - .base_high = 0, - }; - - constexpr auto gdt_user_code_descriptor = arch::cpu::segment_descriptor{ - .limit_low = 0xffff, - .base_low = 0, - .accessed = false, - .read_write = false, - .direction_or_conforming = false, - .executable = true, - .type = arch::cpu::segment_type::code_or_data, - .privilege_level = 3, - .present = true, - .limit_high = 0xf, - .long_mode = true, - .protected_mode = false, - .granularity = arch::cpu::segment_granularity::page, - .base_high = 0, - }; - - constexpr auto gdt_user_data_descriptor = arch::cpu::segment_descriptor{ - .limit_low = 0xffff, - .base_low = 0, - .accessed = false, - .read_write = true, - .direction_or_conforming = false, - .executable = false, - .type = arch::cpu::segment_type::code_or_data, - .privilege_level = 3, - .present = true, - .limit_high = 0xf, - .long_mode = false, - .protected_mode = false, - .granularity = arch::cpu::segment_granularity::page, - .base_high = 0, - }; - } // namespace - auto memory_initialized() -> void { - auto static tss = arch::cpu::task_state_segment{}; - auto static tss_descriptor = arch::cpu::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 = arch::cpu::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 = arch::cpu::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 = arch::cpu::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."); + arch::cpu::initialize_descriptors(); } } // namespace kapi::system \ No newline at end of file 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/CMakeLists.txt | 2 + arch/x86_64/include/arch/cpu/interrupts.hpp | 57 +++++++++++++- 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 +++++++++++++++++++++++ 5 files changed, 294 insertions(+), 22 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') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index f053982..89d9bc0 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -20,6 +20,8 @@ target_sources("x86_64" PRIVATE # CPU Initialization "src/cpu/initialization.cpp" + "src/cpu/interrupts.cpp" + "src/cpu/interrupt_stubs.S" # Low-level bootstrap "src/boot/boot32.S" diff --git a/arch/x86_64/include/arch/cpu/interrupts.hpp b/arch/x86_64/include/arch/cpu/interrupts.hpp index 92c5824..19358ac 100644 --- a/arch/x86_64/include/arch/cpu/interrupts.hpp +++ b/arch/x86_64/include/arch/cpu/interrupts.hpp @@ -30,7 +30,7 @@ namespace arch::cpu //! Reserved std::uint8_t : 5; //! The type of this gate. - gate_type gate_type : 4; + enum gate_type gate_type : 4; //! Reserved std::uint8_t : 1; //! The privilege level required to enter through this gate. @@ -48,14 +48,67 @@ namespace arch::cpu static_assert(sizeof(gate_descriptor) == 2 * sizeof(std::uint64_t)); static_assert(std::is_aggregate_v); + //! The stack frame as established by the low-level assembly interrupt stubs. + //! + //! @note The layout of this struct is reverse than what would reasonably be expected. The reason for this reversal is + //! that fact that it represents a stack frame. Stack frames on x86_64 grow towards lower addresses, meaning the first + //! item on the stack is the last item in C++ memory layout order. + struct interrupt_frame + { + struct + { + std::uint64_t r15; + std::uint64_t r14; + std::uint64_t r13; + std::uint64_t r12; + std::uint64_t r11; + std::uint64_t r10; + std::uint64_t r9; + std::uint64_t r8; + std::uint64_t rdi; + std::uint64_t rsi; + std::uint64_t rbp; + std::uint64_t rdx; + std::uint64_t rcx; + std::uint64_t rbx; + std::uint64_t rax; + } handler_saved; + + struct + { + std::uint64_t number; + std::uint64_t error_code; + } interrupt; + + struct + { + std::uint64_t rip; + std::uint64_t cs; + std::uint64_t rflags; + std::uint64_t rsp; + std::uint64_t ss; + } cpu_saved; + }; + struct interrupt_descriptor_table { - interrupt_descriptor_table(); + interrupt_descriptor_table() noexcept; + + auto load() const -> void; private: std::array m_descriptors{}; }; + struct [[gnu::packed]] interrupt_descriptor_table_register + { + std::uint16_t limit; + gate_descriptor const * base; + + auto load() const -> void; + auto static read() -> interrupt_descriptor_table_register; + }; + } // namespace arch::cpu #endif \ No newline at end of file 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/include/arch/cpu/initialization.hpp | 3 ++ arch/x86_64/include/arch/cpu/interrupts.hpp | 3 ++ arch/x86_64/kapi/system.cpp | 3 ++ arch/x86_64/src/cpu/initialization.cpp | 37 +++++++++++++++++++++++++ arch/x86_64/src/cpu/interrupts.cpp | 10 +++++++ 5 files changed, 56 insertions(+) (limited to 'arch') diff --git a/arch/x86_64/include/arch/cpu/initialization.hpp b/arch/x86_64/include/arch/cpu/initialization.hpp index b2ce864..71186d4 100644 --- a/arch/x86_64/include/arch/cpu/initialization.hpp +++ b/arch/x86_64/include/arch/cpu/initialization.hpp @@ -3,4 +3,7 @@ namespace arch::cpu { auto initialize_descriptors() -> void; + + auto initialize_legacy_interrupts() -> void; + } // namespace arch::cpu diff --git a/arch/x86_64/include/arch/cpu/interrupts.hpp b/arch/x86_64/include/arch/cpu/interrupts.hpp index 19358ac..8f156a4 100644 --- a/arch/x86_64/include/arch/cpu/interrupts.hpp +++ b/arch/x86_64/include/arch/cpu/interrupts.hpp @@ -109,6 +109,9 @@ namespace arch::cpu auto static read() -> interrupt_descriptor_table_register; }; + auto enable_interrupts() -> void; + auto disable_interrupts() -> void; + } // namespace arch::cpu #endif \ No newline at end of file diff --git a/arch/x86_64/kapi/system.cpp b/arch/x86_64/kapi/system.cpp index ffb6a46..301169f 100644 --- a/arch/x86_64/kapi/system.cpp +++ b/arch/x86_64/kapi/system.cpp @@ -1,6 +1,7 @@ #include "kapi/system.hpp" #include "arch/cpu/initialization.hpp" +#include "arch/cpu/interrupts.hpp" namespace kapi::system { @@ -8,6 +9,8 @@ namespace kapi::system auto memory_initialized() -> void { arch::cpu::initialize_descriptors(); + arch::cpu::initialize_legacy_interrupts(); + arch::cpu::enable_interrupts(); } } // namespace kapi::system \ No newline at end of file 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') 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') 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/include/arch/cpu/legacy_pic.hpp | 19 +++++++++++++++++++ arch/x86_64/src/cpu/initialization.cpp | 12 +++++------- arch/x86_64/src/cpu/interrupts.cpp | 4 ++++ 3 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 arch/x86_64/include/arch/cpu/legacy_pic.hpp (limited to 'arch') diff --git a/arch/x86_64/include/arch/cpu/legacy_pic.hpp b/arch/x86_64/include/arch/cpu/legacy_pic.hpp new file mode 100644 index 0000000..9f53d86 --- /dev/null +++ b/arch/x86_64/include/arch/cpu/legacy_pic.hpp @@ -0,0 +1,19 @@ +#ifndef TEACHOS_X86_64_CPU_LEGACY_PIC_HPP +#define TEACHOS_X86_64_CPU_LEGACY_PIC_HPP + +#include "arch/device_io/port_io.hpp" + +#include + +namespace arch::cpu +{ + 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_end_of_interrupt = std::uint8_t{0x20}; + +} // namespace arch::cpu + +#endif \ No newline at end of file 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 05269b10e50a80f557c2be475904ff15dc1bbec4 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 27 Mar 2026 06:58:18 +0100 Subject: x86_64/port_io: fix assembly templates --- arch/x86_64/include/arch/device_io/port_io.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/device_io/port_io.hpp b/arch/x86_64/include/arch/device_io/port_io.hpp index 65e58e3..70773dd 100644 --- a/arch/x86_64/include/arch/device_io/port_io.hpp +++ b/arch/x86_64/include/arch/device_io/port_io.hpp @@ -69,9 +69,9 @@ namespace arch::io //! The assembly templates used for writing to an I/O port. constexpr auto static code = std::array{ - std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%al, %%dx"}, - std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%ax, %%dx"}, - std::string_view{"mov %[port], %%dx\nmov %%dx, %[data]\nout %%eax, %%dx"}, + std::string_view{"mov %[port], %%dx\nmov %[data], %%al\nout %%al, %%dx"}, + std::string_view{"mov %[port], %%dx\nmov %[data], %%ax\nout %%ax, %%dx"}, + std::string_view{"mov %[port], %%dx\nmov %[data], %%eax\nout %%eax, %%dx"}, }; }; -- 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/include/arch/cpu/interrupts.hpp | 46 +++++----- arch/x86_64/kapi/cpu.cpp | 21 +++++ arch/x86_64/kapi/system.cpp | 10 +-- arch/x86_64/src/cpu/interrupts.cpp | 125 ++++++++++++++++++++-------- 4 files changed, 137 insertions(+), 65 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/cpu/interrupts.hpp b/arch/x86_64/include/arch/cpu/interrupts.hpp index 8f156a4..08ecd9c 100644 --- a/arch/x86_64/include/arch/cpu/interrupts.hpp +++ b/arch/x86_64/include/arch/cpu/interrupts.hpp @@ -1,6 +1,8 @@ #ifndef TEACHOS_X86_64_CPU_INTERRUPTS_HPP #define TEACHOS_X86_64_CPU_INTERRUPTS_HPP +#include "kapi/memory.hpp" + #include "arch/cpu/segment_selector.hpp" #include @@ -57,36 +59,36 @@ namespace arch::cpu { struct { - std::uint64_t r15; - std::uint64_t r14; - std::uint64_t r13; - std::uint64_t r12; - std::uint64_t r11; - std::uint64_t r10; - std::uint64_t r9; - std::uint64_t r8; - std::uint64_t rdi; - std::uint64_t rsi; - std::uint64_t rbp; - std::uint64_t rdx; - std::uint64_t rcx; - std::uint64_t rbx; - std::uint64_t rax; + std::uint64_t r15{}; + std::uint64_t r14{}; + std::uint64_t r13{}; + std::uint64_t r12{}; + std::uint64_t r11{}; + std::uint64_t r10{}; + std::uint64_t r9{}; + std::uint64_t r8{}; + std::uint64_t rdi{}; + std::uint64_t rsi{}; + std::uint64_t rbp{}; + std::uint64_t rdx{}; + std::uint64_t rcx{}; + std::uint64_t rbx{}; + std::uint64_t rax{}; } handler_saved; struct { - std::uint64_t number; - std::uint64_t error_code; + std::uint64_t number{}; + std::uint64_t error_code{}; } interrupt; struct { - std::uint64_t rip; - std::uint64_t cs; - std::uint64_t rflags; - std::uint64_t rsp; - std::uint64_t ss; + kapi::memory::linear_address rip{}; + std::uint64_t cs{}; + std::uint64_t rflags{}; + kapi::memory::linear_address rsp{}; + std::uint64_t ss{}; } cpu_saved; }; diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index 2a0f8f7..693d328 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -1,8 +1,29 @@ #include "kapi/cpu.hpp" +#include "kapi/system.hpp" + +#include "arch/cpu/initialization.hpp" +#include "arch/cpu/interrupts.hpp" + +#include + namespace kapi::cpu { + auto init() -> void + { + auto static constinit is_initialized = std::atomic_flag{}; + + if (is_initialized.test_and_set()) + { + system::panic("[x86_64] CPU has already been initialized."); + } + + arch::cpu::initialize_descriptors(); + arch::cpu::initialize_legacy_interrupts(); + arch::cpu::enable_interrupts(); + } + auto halt() -> void { asm volatile("1: hlt\njmp 1b"); diff --git a/arch/x86_64/kapi/system.cpp b/arch/x86_64/kapi/system.cpp index 301169f..09c7152 100644 --- a/arch/x86_64/kapi/system.cpp +++ b/arch/x86_64/kapi/system.cpp @@ -1,16 +1,8 @@ #include "kapi/system.hpp" -#include "arch/cpu/initialization.hpp" -#include "arch/cpu/interrupts.hpp" - namespace kapi::system { - auto memory_initialized() -> void - { - arch::cpu::initialize_descriptors(); - arch::cpu::initialize_legacy_interrupts(); - arch::cpu::enable_interrupts(); - } + auto memory_initialized() -> void {} } // namespace kapi::system \ No newline at end of file diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 048c461..6f66bbd 100644 --- a/arch/x86_64/src/cpu/interrupts.cpp +++ b/arch/x86_64/src/cpu/interrupts.cpp @@ -1,6 +1,7 @@ #include "arch/cpu/interrupts.hpp" #include "kapi/cpu.hpp" +#include "kapi/memory.hpp" #include "arch/cpu/legacy_pic.hpp" #include "arch/cpu/segment_selector.hpp" @@ -14,38 +15,92 @@ namespace arch::cpu namespace { - constexpr auto isr_number_page_fault = 0x0e; - constexpr auto isr_number_legacy_start = 0x20; - constexpr auto isr_number_legacy_end = 0x29; - constexpr auto isr_number_cascade_start = 0x2c; - constexpr auto isr_number_cascade_end = 0x2f; - - auto handle_page_fault(interrupt_frame * frame) -> void + enum struct exception { - auto fault_address = std::uintptr_t{}; - asm volatile("mov %%cr2, %0" : "=r"(fault_address)); - - auto const present = (frame->interrupt.error_code & 0x1) != 0; - auto const write = (frame->interrupt.error_code & 0x2) != 0; - auto const user = (frame->interrupt.error_code & 0x4) != 0; + divide_error, + debug_exception, + non_maskable_interrupt, + breakpoint, + overflow, + bound_range_exceeded, + invalid_opcode, + device_not_available, + double_fault, + coprocessor_segment_overrun, + invalid_tss, + stack_segment_fault, + general_protection_fault, + page_fault, + x87_fpu_floating_point_error, + alignment_check, + machine_check, + simd_floating_point_error, + virtualization_exception, + control_protection_exception, + vmm_communication_exception, + security_exception, + }; + + constexpr auto pic_master_irq_start = 0x20; + constexpr auto pic_master_irq_end = pic_master_irq_start + 8; + constexpr auto pic_slave_irq_start = pic_master_irq_end; + constexpr auto pic_slave_irq_end = pic_slave_irq_start + 8; + + constexpr auto to_exception_type(exception e) + { + switch (e) + { + case exception::divide_error: + case exception::x87_fpu_floating_point_error: + case exception::simd_floating_point_error: + return kapi::cpu::exception::type::arithmetic_error; + case exception::breakpoint: + return kapi::cpu::exception::type::breakpoint; + case exception::invalid_opcode: + return kapi::cpu::exception::type::illegal_instruction; + case exception::stack_segment_fault: + return kapi::cpu::exception::type::memory_access_fault; + case exception::general_protection_fault: + return kapi::cpu::exception::type::privilege_violation; + case exception::alignment_check: + return kapi::cpu::exception::type::alignment_fault; + default: + return kapi::cpu::exception::type::unknown; + } + } - kstd::println(kstd::print_sink::stderr, "[x86_64:MMU] PAGE FAULT!"); - kstd::println(kstd::print_sink::stderr, "\tFault address: {:#018x}", fault_address); - kstd::println(kstd::print_sink::stderr, "\tPresent: {}", present); - kstd::println(kstd::print_sink::stderr, "\tWrite: {}", write); - kstd::println(kstd::print_sink::stderr, "\tUser: {}", user); - kstd::println(kstd::print_sink::stderr, "\tRIP: {:#018x}", frame->cpu_saved.rip); - kstd::println(kstd::print_sink::stderr, "\tHalting the system now!"); + auto dispatch_exception(interrupt_frame * frame) -> bool + { + auto type = to_exception_type(static_cast(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 3888a111be2e6b2a53b10752de36d58f18fc8874 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 24 Mar 2026 17:39:33 +0100 Subject: x86_64: remove stale source code --- .../interrupt_descriptor_table/gate_descriptor.hpp | 69 -------------- .../interrupt_descriptor_table/idt_flags.hpp | 81 ---------------- .../interrupt_descriptor_table.hpp | 24 ----- .../interrupt_descriptor_table_pointer.hpp | 40 -------- .../interrupt_descriptor_table/ist_offset.hpp | 45 --------- .../segment_selector.hpp | 105 --------------------- .../generic_interrupt_handler.hpp | 34 ------- arch/x86_64/pre/include/arch/kernel/cpu/call.hpp | 30 ------ arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp | 27 ------ arch/x86_64/pre/include/arch/kernel/cpu/if.hpp | 21 ----- arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp | 64 ------------- arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp | 24 ----- .../interrupt_descriptor_table/gate_descriptor.cpp | 24 ----- .../interrupt_descriptor_table/idt_flags.cpp | 20 ---- .../interrupt_descriptor_table.cpp | 53 ----------- .../interrupt_descriptor_table_pointer.cpp | 13 --- .../interrupt_descriptor_table/ist_offset.cpp | 10 -- .../segment_selector.cpp | 24 ----- .../generic_interrupt_handler.cpp | 13 --- arch/x86_64/pre/src/kernel/cpu/call.cpp | 9 -- arch/x86_64/pre/src/kernel/cpu/idtr.cpp | 18 ---- arch/x86_64/pre/src/kernel/cpu/if.cpp | 13 --- arch/x86_64/pre/src/kernel/cpu/tr.cpp | 16 ---- 23 files changed, 777 deletions(-) delete mode 100644 arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp delete mode 100644 arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp delete mode 100644 arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp delete mode 100644 arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp delete mode 100644 arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp delete mode 100644 arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp delete mode 100644 arch/x86_64/pre/include/arch/interrupt_handling/generic_interrupt_handler.hpp delete mode 100644 arch/x86_64/pre/include/arch/kernel/cpu/call.hpp delete mode 100644 arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp delete mode 100644 arch/x86_64/pre/include/arch/kernel/cpu/if.hpp delete mode 100644 arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp delete mode 100644 arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp delete mode 100644 arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp delete mode 100644 arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/idt_flags.cpp delete mode 100644 arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp delete mode 100644 arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp delete mode 100644 arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/ist_offset.cpp delete mode 100644 arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/segment_selector.cpp delete mode 100644 arch/x86_64/pre/src/interrupt_handling/generic_interrupt_handler.cpp delete mode 100644 arch/x86_64/pre/src/kernel/cpu/call.cpp delete mode 100644 arch/x86_64/pre/src/kernel/cpu/idtr.cpp delete mode 100644 arch/x86_64/pre/src/kernel/cpu/if.cpp delete mode 100644 arch/x86_64/pre/src/kernel/cpu/tr.cpp (limited to 'arch') diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp deleted file mode 100644 index 07110c8..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP - -#include "arch/context_switching/interrupt_descriptor_table/idt_flags.hpp" -#include "arch/context_switching/interrupt_descriptor_table/ist_offset.hpp" -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" - -#include -#include - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - __extension__ typedef __int128 int128_t; - __extension__ typedef unsigned __int128 uint128_t; - - /** - * @brief Defines helper function for all states and the actual data the gate descriptor can have. - */ - struct [[gnu::packed]] gate_descriptor - { - /** - * @brief Default Constructor. - */ - gate_descriptor() = default; - - /** - * @brief Constructor. - * - * @note Created gate descriptor copies the given bytes into these components ending with a 32 bit reserved - * field that has to be used, because the 64-bit gate descriptor needs to be big enough for two 32-bit gate - * descriptor. - * - 16 bit Segment Selector - * - 3 bit Interrupt Stack Table Offset - * - 8 bit Type and Flags - * - 64 bit Offset - * - * @param flags Copies the bits set from the given data into the individual components of a gate - * descriptor. - */ - explicit gate_descriptor(uint128_t flags); - - /** - * @brief Constructor. - * - * @param selector, ist, flags, offset Copies the bits set from the given data into the individual components of - * a gate descriptor. - */ - gate_descriptor(segment_selector selector, ist_offset ist, idt_flags flags, uint64_t offset); - - /** - * @brief Allows to compare the underlying bits of two instances. - * - * @param other Other instance that we want to compare with. - * @return Whether the underlying set bits of both types are the same. - */ - auto operator==(gate_descriptor const & other) const -> bool = default; - - private: - // The order in private variables starts for the first variable being the rightmost bit. - uint16_t _offset_1 = {}; ///< Lower 16 bits of handler function address (0 - 15) - segment_selector _selector = {}; ///< Segment selector (16 - 31) - ist_offset _ist = {}; ///< Interrupt Stack Table offset (32 - 39) - idt_flags _flags = {}; ///< Gate Type and Flags (40 - 47) - uint64_t _offset_2 : 48 = {}; ///< Upper 48 bits of handler function address (48 - 95) - uint32_t : 32; ///< Reserved field used to ensure this struct is 128 bits big (96 - 127) - }; -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_GATE_DESCRIPTOR_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp deleted file mode 100644 index 5104c36..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/idt_flags.hpp +++ /dev/null @@ -1,81 +0,0 @@ - -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP - -#include -#include - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - /** - * @brief Defines helper function for all states that the access byte field of a segment descriptor can - * have. - */ - struct [[gnu::packed]] idt_flags - { - /** - * @brief Possible set bits in our underlying bits and the meaning when they are set. - */ - enum bitset : uint8_t - { - INTERRUPT_GATE = 0b01110, ///< The actual type of gate segment is a interrupt gate. - TRAP_GATE = 0b01111, ///< The actual type of gate segment is a trap gate. - DESCRIPTOR_LEVEL_KERNEL = - 0U << 5U, ///< Highest privileged level used by the kernel to allow for full access of resources. - DESCRIPTOR_LEVEL_ADMIN = - 1U << 5U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more - ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. - DESCRIPTOR_LEVEL_PRIVILEGED_USER = - 2U << 5U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more - ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. - DESCRIPTOR_LEVEL_USER = 3U << 5U, ///< Restricts access to only application and their specific memory. - PRESENT = 1U << 7U, ///< Present bit; Allows an entry to refer to a valid segment. - ///< Must be set (1) for any valid segment. - }; - - /** - * @brief Default Constructor. - */ - idt_flags() = default; - - /** - * @brief Constructor. - * - * @param flags Allows to set flags for the access byte field using the unscoped enum contained in this class, used - * to allow for direct integer conversion. This value is saved and can later be used to check whether certain flags - * are enabled or not using contains_flags method. - */ - idt_flags(uint8_t flags); - - /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. - * - * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng - * data. Any additional bits that are set are not relevant. - * - * @param other Flags that we want to compare against and check if the underlying data has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying data. - */ - auto contains_flags(std::bitset<8U> other) const -> bool; - - /** - * @brief Allows to compare the underlying bits of two instances. - * - * @param other Other instance that we want to compare with. - * @return Whether the underlying set bits of both types are the same. - */ - auto operator==(idt_flags const & other) const -> bool = default; - - /** - * @brief Combines all bits that are set in the std::bitset flags with the bits already set in the underlying data. - * - * @param other Additional bits that should be set. - */ - auto operator|=(std::bitset<8U> other) -> void; - - private: - uint8_t _flags = {}; ///< Underlying bits used to read the flags from. - }; -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IDT_FLAGS_HPP \ No newline at end of file diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp deleted file mode 100644 index b388e0e..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP - -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - /** - * @brief Updates the IDTR with the created interrupt descriptor table. If it has not been created yet this - * method will create it. - */ - auto update_interrupt_descriptor_table_register() -> void; - - /** - * @brief Creates the interrupt descriptor table, with the minimum required configuration. If this method is called - * more than once, the previously created instance is returned instead. - * - * @return Reference to the created interrupt_descriptor_table. - */ - auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table &; - -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp deleted file mode 100644 index 7fe933b..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP - -#include "arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp" -#include "arch/stl/vector.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - using interrupt_descriptor_table = stl::vector; - - /** - * @brief Represents a pointer to the Interrupt Descriptor Table (IDT). - * - * This structure is used to store the base address and length of the IDT. - */ - struct [[gnu::packed]] interrupt_descriptor_table_pointer - { - /** - * @brief Default constructor. - */ - interrupt_descriptor_table_pointer() = default; - - /** - * @brief Constructor. - */ - interrupt_descriptor_table_pointer(uint16_t table_length, gate_descriptor * address); - - /** - * @brief Defaulted three-way comparsion operator. - */ - auto operator<=>(interrupt_descriptor_table_pointer const & other) const -> std::strong_ordering = default; - - private: - uint16_t table_length = {}; ///< The amount of segment descriptor entries in the global descriptor table - 1. - gate_descriptor * address = {}; ///< Non-owning pointer to the IDT base address. - }; - -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_INTERRUPT_DESCRIPTOR_TABLE_POINTER_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp deleted file mode 100644 index e45bcf4..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/ist_offset.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IST_OFFSET_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IST_OFFSET_HPP - -#include -#include - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - /** - * @brief Defines helper function for all states that the interrupt stack table offset field of a gate descriptor can - * have. Is automatically increased to one byte in size, to include the following 5 reserved bits in the gate - * descriptor. - */ - struct [[gnu::packed]] ist_offset - { - /** - * @brief Default Constructor. - */ - ist_offset() = default; - - /** - * @brief Constructor. - * - * @param offset Offset into the interrupt stack table. A value of of 0 means we do not switch stacks, whereas 1 - 7 - * mean we switch to the n-th stack in the Interrupt Stack Table, contained in the TSS if the gate descriptor that - * contains this field is called. - */ - ist_offset(uint8_t offset); - - /** - * @brief Allows to compare the underlying set bits of two instances. - * - * @param other Other instance that we want to compare with. - * @return Whether the underlying set bits of both types are the same. - */ - auto operator==(ist_offset const & other) const -> bool = default; - - private: - uint8_t _ist : 3 = {}; ///< Offset into the interrupt stack table. A value of of 0 means we do not switch stacks, - ///< whereas 1 - 7 mean we switch to the n-th stack in the Interrupt Stack Table, contained - ///< in the TSS if the gate descriptor that contains this field is called. - }; -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_IST_OFFSET_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp b/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp deleted file mode 100644 index ea8c145..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/interrupt_descriptor_table/segment_selector.hpp +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP - -#include -#include - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - /** - * @brief Represents a segment selector in the x86_64 architecture, which points to a valid code segment in the global - * descriptor table. - * - * A segment selector is a 16-bit identifier used to select a segment descriptor - * from the Global Descriptor Table (GDT) or the Local Descriptor Table (LDT). - * It contains an index, a table indicator (TI), and a requested privilege level (RPL). - */ - struct [[gnu::packed]] segment_selector - { - /** - * @brief Possible set bits in our underlying bits and the meaning when they are set. - */ - enum bitset : uint8_t - { - REQUEST_LEVEL_KERNEL = - 0U << 0U, ///< Highest privileged level used by the kernel to allow for full access of resources. - REQUEST_LEVEL_ADMIN = - 1U << 0U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more - ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. - REQUEST_LEVEL_PRIVILEGED_USER = - 2U << 0U, ///< Restricts access to own application and thoose of lower privilege. Should only be used if more - ///< than two privilege levels are required, otherwise using Level 3 and Level 0 is recommended. - REQUEST_LEVEL_USER = 3U << 0U, ///< Restricts access to only application and their specific memory. - LOCAL_DESCRIPTOR_TABLE = 1U << 2U, ///< Wheter the index referes to an entry in the local or global descriptor - ///< table. If enabled the index points to a local descriptor table, if it is - ///< cleared it referes to a global descriptor table instead. - }; - - /** - * @brief Default constructor. - */ - segment_selector() = default; - - /** - * @brief Constructor. - * - * @param index Index into the local or global descriptor table. Processor multiplies the index value by 8 (number - * of bytes in 32-bit segment descriptor) and adds the result to the base GDT or LDT address. - * @param flags Allows to set flags for the flags field using the unscoped enum contained in this class, used to - * allow for direct integer conversion. - */ - constexpr segment_selector(uint16_t index, uint8_t flags) - : _flags(flags) - , _index(index) - { - // Nothing to do. - } - - /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying data. - * - * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng - * data. Any additional bits that are set are not relevant. - * - * @param other Flags that we want to compare against and check if the underlying data has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying data. - */ - auto contains_flags(std::bitset<3U> other) const -> bool; - - /** - * @brief Gets the index into the global descriptor table or the local descriptor table this segment selector is - * pointing too. - * - * @return Underlying value of the index field, bit 3 - 16. - */ - [[gnu::section(".user_text")]] - auto get_index() const -> uint16_t; - - /** - * @brief Defaulted three-way comparsion operator. - */ - auto operator<=>(segment_selector const & other) const -> std::strong_ordering = default; - - /** - * @brief Combines all bits that are set in the std::bitset flags with the bits already set in the underlying data. - * - * @param other Additional bits that should be set. - */ - auto operator|=(std::bitset<3U> other) -> void; - - /** - * @brief Cast the underlying data into a combined 16-bit form, that contains all data. - * - * @return Underlying value combined into it's full size. - */ - operator uint16_t() const; - - private: - uint8_t _flags : 3 = {}; ///< Underlying bits used to read the flags from. - uint16_t _index - : 13 = {}; ///< Index into the local or global descriptor table. Processor multiplies the index value by 16 - ///< (number of bytes in segment descriptor) and adds the result to the base address. - }; -} // namespace teachos::arch::context_switching::interrupt_descriptor_table - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_INTERRUPT_DESCRIPTOR_TABLE_SEGMENT_SELECTOR_HPP diff --git a/arch/x86_64/pre/include/arch/interrupt_handling/generic_interrupt_handler.hpp b/arch/x86_64/pre/include/arch/interrupt_handling/generic_interrupt_handler.hpp deleted file mode 100644 index 15b35c1..0000000 --- a/arch/x86_64/pre/include/arch/interrupt_handling/generic_interrupt_handler.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_INTERRUPT_HANDLING_GENERIC_INTERRUPT_HANDLER_HPP -#define TEACHOS_ARCH_X86_64_INTERRUPT_HANDLING_GENERIC_INTERRUPT_HANDLER_HPP - -#include - -namespace teachos::arch::interrupt_handling -{ - /** - * @brief Represents the CPU state during an interrupt. - * - * Some interrupts push an error code, while others do not. The full list - * of which vector number contains the error code can be found here: https://wiki.osdev.org/Exceptions - */ - struct [[gnu::packed]] interrupt_frame - { - // uint64_t error_code; ///< Error code only pushed by some exceptions, therefore it is commented out. - uint64_t ip; ///< Instruction pointer at the time of the interrupt. - uint64_t cs; ///< Code segment selector indicating privilege level. - uint64_t flags; ///< CPU flags (RFLAGS) storing processor state. - uint64_t sp; ///< Stack pointer at the time of the interrupt. - uint64_t ss; ///< Stack segment selector, usually unused in 64-bit mode. - }; - - /** - * @brief Generic interrupt handler function. - * - * @param frame Pointer to the interrupt frame containing CPU state. - */ - [[gnu::interrupt]] - auto generic_interrupt_handler(interrupt_frame * frame) -> void; - -} // namespace teachos::arch::interrupt_handling - -#endif // TEACHOS_ARCH_X86_64_INTERRUPT_HANDLING_GENERIC_INTERRUPT_HANDLER_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/call.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/call.hpp deleted file mode 100644 index 3c43304..0000000 --- a/arch/x86_64/pre/include/arch/kernel/cpu/call.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP - -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" - -#include - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Far Pointer. Address to function located in another code segment. - */ - struct far_pointer - { - void (*function)(); ///< Address of the function we want to call. (0-63) - context_switching::interrupt_descriptor_table::segment_selector - selector; ///< Segment selector pointing to the GDT entry we want to load into register CS. (64-79) - }; - - /** - * @brief Far call - A call to an instruction located in a different segment than the current code segment but at the - * same privilege level. - * - * @param pointer 64-bit operand size far pointer that we want to call. - */ - auto call(far_pointer pointer) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_JMP_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp deleted file mode 100644 index cb800d0..0000000 --- a/arch/x86_64/pre/include/arch/kernel/cpu/idtr.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP - -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" - -#include -#include - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Returns the value in the IDTR register. - * - * @return Value of IDTR register. - */ - auto store_interrupt_descriptor_table() - -> context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer; - - /** - * @brief Loads the interrupt_descriptor_table_pointer into the interrupt descriptor table register (IDTR). - */ - auto load_interrupt_descriptor_table( - context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_IDTR_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/if.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/if.hpp deleted file mode 100644 index 48707dc..0000000 --- a/arch/x86_64/pre/include/arch/kernel/cpu/if.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Sets the interrupt flag (IF) in the EFLAGS register. - * This allows the processor to respond to maskable hardware interrupts. - */ - auto set_interrupt_flag() -> void; - - /** - * @brief Clears the interrupt flag (IF) in the EFLAGS register. - * This will stop the processor to respond to maskable hardware interrupts and needs to be done before changing the - * Interrupt Descriptor Table with lidt. - */ - auto clear_interrupt_flag() -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_IF_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp deleted file mode 100644 index 99d6378..0000000 --- a/arch/x86_64/pre/include/arch/kernel/cpu/msr.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP - -#include -#include - -namespace teachos::arch::kernel::cpu -{ - /** - * @brief Important flags that can be writen into the Extended Feature Enable Register (EFER). - * - * @note EFER is a model-specific register allowing to configure CPU extensions. Only the most important extensions - * are listed below, the rest are excluded for brevity. See https://en.wikipedia.org/wiki/Control_register#EFER for - * more information. - */ - enum class efer_flags : uint64_t - { - SCE = 1UL << 0UL, ///< System Call Extensions. - LME = 1UL << 8UL, ///< Long Mode Enabled. - LMA = 1UL << 10UL, ///< Long Mode Active. - NXE = 1UL << 11UL, ///< No-Execute Enable. - SVME = 1UL << 12UL, ///< Secure Virtual Machine Enable. - LMSLE = 1UL << 13UL, ///< Long Mode Segment Limit Enable. - FFXSR = 1UL << 14UL, ///< Fast FXSAVE/FXSTOR. - TCE = 1UL << 15UL, ///< Translation Cache Extension. - }; - - /** - * @brief Reads a 64-bit from the Model-Specific Register (MSR). - * - * @note This function reads the value of an MSR specified by the given address. It combines the lower and upper - * 32-bits of the MSR value read using the 'rdmsr' instruction and returns it as a 64-bit unsigned integer. - * - * @param msr The address of the MSR to read. - * @return The 64-bit value read from the MSR. - */ - auto read_msr(uint32_t msr) -> uint64_t; - - /** - * @brief Writes a 64-bit value to a Model-Specific Register (MSR). - * - * @note This function writes a 64-bit value to the MSR specified by the given address. - * It splits the 64-bit value into two 32-bit parts and writes them using the - * `wrmsr` instruction. - * - * @param msr The address of the MSR to write to. - * @param new_value The 64-bit value to write to the MSR. - */ - auto write_msr(uint32_t msr, uint64_t new_value) -> void; - - /** - * @brief Sets a specific bit in the Extended Feature Enable Register (EFER), which is a Model-Specific Register - * (MSR). - * - * @note This function reads the current value of the EFER register, ORs the specified - * bit with the current value, and writes the updated value back to the EFER register. - * - * @param flag The flag to set in the EFER register. - */ - auto set_efer_bit(efer_flags flag) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_NXE_HPP \ No newline at end of file diff --git a/arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp b/arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp deleted file mode 100644 index 7c856f1..0000000 --- a/arch/x86_64/pre/include/arch/kernel/cpu/tr.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP - -#include -#include - -namespace teachos::arch::kernel::cpu -{ - - /** - * @brief Returns the value in the LTR register. - * - * @return Value of LTR register. - */ - auto store_task_register() -> uint16_t; - - /** - * @brief Loads the gdt offset to the tss segment descriptor into the task register (TR). - */ - auto load_task_register(uint16_t gdt_offset) -> void; - -} // namespace teachos::arch::kernel::cpu - -#endif // TEACHOS_ARCH_X86_64_KERNEL_CPU_TR_HPP diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp deleted file mode 100644 index 28f289c..0000000 --- a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/gate_descriptor.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - gate_descriptor::gate_descriptor(uint128_t flags) - : _offset_1(flags) - , _selector(flags >> 19U, flags >> 16U) - , _ist(flags >> 32U) - , _flags(flags >> 40U) - , _offset_2(flags >> 48U) - { - // Nothing to do. - } - - gate_descriptor::gate_descriptor(segment_selector selector, ist_offset ist, idt_flags flags, uint64_t offset) - : _offset_1(offset) - , _selector(selector) - , _ist(ist) - , _flags(flags) - , _offset_2(offset >> 16U) - { - // Nothing to do. - } -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/idt_flags.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/idt_flags.cpp deleted file mode 100644 index f3b9d5e..0000000 --- a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/idt_flags.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/idt_flags.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - idt_flags::idt_flags(uint8_t flags) - : _flags(flags) - { - // Nothing to do. - } - - auto idt_flags::contains_flags(std::bitset<8U> other) const -> bool - { - return (std::bitset<8U>{_flags} & other) == other; - } - - auto idt_flags::operator|=(std::bitset<8U> other) -> void - { - _flags |= other.to_ulong(); - } -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp deleted file mode 100644 index 8640385..0000000 --- a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" - -#include "arch/exception_handling/assert.hpp" -#include "arch/interrupt_handling/generic_interrupt_handler.hpp" -#include "arch/kernel/cpu/idtr.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - namespace - { - /// @brief Amount of currently reserved interrupt indicies. - /// See https://wiki.osdev.org/Interrupt_Descriptor_Table#IDT_items for more information. - constexpr uint16_t RESERVED_INTERRUPT_COUNT = 256U; - - auto create_interrupt_descriptor_table() -> interrupt_descriptor_table - { - interrupt_descriptor_table interrupt_descriptor_table{RESERVED_INTERRUPT_COUNT}; - - uint64_t offset = reinterpret_cast(interrupt_handling::generic_interrupt_handler); - segment_selector selector{1U, segment_selector::REQUEST_LEVEL_KERNEL}; - ist_offset ist{0U}; - idt_flags flags{idt_flags::DESCRIPTOR_LEVEL_KERNEL | idt_flags::INTERRUPT_GATE | idt_flags::PRESENT}; - - for (std::size_t i = 0; i < interrupt_descriptor_table.size(); i++) - { - interrupt_descriptor_table.at(i) = {selector, ist, flags, offset}; - } - - return interrupt_descriptor_table; - } - } // namespace - - auto get_or_create_interrupt_descriptor_table() -> interrupt_descriptor_table & - { - // Interrupt Descriptor Table needs to be kept alive - interrupt_descriptor_table static idt = create_interrupt_descriptor_table(); - return idt; - } - - auto update_interrupt_descriptor_table_register() -> void - { - decltype(auto) idt = get_or_create_interrupt_descriptor_table(); - - interrupt_descriptor_table_pointer idt_pointer{static_cast((idt.size() * sizeof(gate_descriptor)) - 1), - idt.data()}; - kernel::cpu::load_interrupt_descriptor_table(idt_pointer); - - auto const stored_gdt_pointer = kernel::cpu::store_interrupt_descriptor_table(); - arch::exception_handling::assert( - idt_pointer == stored_gdt_pointer, - "[Interrupt Descriptor Table] Loaded IDTR value is not the same as the stored value."); - } -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp deleted file mode 100644 index 7bcbae6..0000000 --- a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - interrupt_descriptor_table_pointer::interrupt_descriptor_table_pointer(uint16_t table_length, - gate_descriptor * address) - : table_length(table_length) - , address(address) - { - // Nothing to do. - } - -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/ist_offset.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/ist_offset.cpp deleted file mode 100644 index a70e75d..0000000 --- a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/ist_offset.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/ist_offset.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - ist_offset::ist_offset(uint8_t index) - : _ist(index) - { - // Nothing to do. - } -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/segment_selector.cpp b/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/segment_selector.cpp deleted file mode 100644 index 25ba859..0000000 --- a/arch/x86_64/pre/src/context_switching/interrupt_descriptor_table/segment_selector.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" - -namespace teachos::arch::context_switching::interrupt_descriptor_table -{ - auto segment_selector::contains_flags(std::bitset<3U> other) const -> bool - { - return (std::bitset<3U>{_flags} & other) == other; - } - - auto segment_selector::get_index() const -> uint16_t - { - return _index; - } - - auto segment_selector::operator|=(std::bitset<3U> other) -> void - { - _flags |= other.to_ulong(); - } - - segment_selector::operator uint16_t() const - { - return *reinterpret_cast(this); - } -} // namespace teachos::arch::context_switching::interrupt_descriptor_table diff --git a/arch/x86_64/pre/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/pre/src/interrupt_handling/generic_interrupt_handler.cpp deleted file mode 100644 index 9d061a8..0000000 --- a/arch/x86_64/pre/src/interrupt_handling/generic_interrupt_handler.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "arch/interrupt_handling/generic_interrupt_handler.hpp" - -#include "arch/video/vga/text.hpp" - -namespace teachos::arch::interrupt_handling -{ - auto generic_interrupt_handler(interrupt_frame * frame) -> void - { - (void)frame; - video::vga::text::write("An Interrupt occurred.", video::vga::text::common_attributes::green_on_black); - video::vga::text::newline(); - } -} // namespace teachos::arch::interrupt_handling diff --git a/arch/x86_64/pre/src/kernel/cpu/call.cpp b/arch/x86_64/pre/src/kernel/cpu/call.cpp deleted file mode 100644 index 98fa248..0000000 --- a/arch/x86_64/pre/src/kernel/cpu/call.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "arch/kernel/cpu/call.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto call(far_pointer pointer) -> void - { - asm volatile("rex64 lcall *%[input]" : /* no output from call */ : [input] "m"(pointer)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/pre/src/kernel/cpu/idtr.cpp b/arch/x86_64/pre/src/kernel/cpu/idtr.cpp deleted file mode 100644 index 7aa20c1..0000000 --- a/arch/x86_64/pre/src/kernel/cpu/idtr.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "arch/kernel/cpu/idtr.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto store_interrupt_descriptor_table() - -> context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer - { - context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer current_value{}; - asm("sidt %[output]" : [output] "=m"(current_value)); - return current_value; - } - - auto load_interrupt_descriptor_table( - context_switching::interrupt_descriptor_table::interrupt_descriptor_table_pointer const & idt_pointer) -> void - { - asm volatile("lidt %[input]" : /* no output from call */ : [input] "m"(idt_pointer)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/pre/src/kernel/cpu/if.cpp b/arch/x86_64/pre/src/kernel/cpu/if.cpp deleted file mode 100644 index 5d056fc..0000000 --- a/arch/x86_64/pre/src/kernel/cpu/if.cpp +++ /dev/null @@ -1,13 +0,0 @@ -namespace teachos::arch::kernel::cpu -{ - auto set_interrupt_flag() -> void - { - asm volatile("sti"); - } - - auto clear_interrupt_flag() -> void - { - asm volatile("cli"); - } - -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/pre/src/kernel/cpu/tr.cpp b/arch/x86_64/pre/src/kernel/cpu/tr.cpp deleted file mode 100644 index a435540..0000000 --- a/arch/x86_64/pre/src/kernel/cpu/tr.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "arch/kernel/cpu/tr.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto store_task_register() -> uint16_t - { - uint16_t current_value{}; - asm("str %[output]" : [output] "=r"(current_value)); - return current_value; - } - - auto load_task_register(uint16_t gdt_offset) -> void - { - asm volatile("ltr %[input]" : /* no output from call */ : [input] "m"(gdt_offset)); - } -} // namespace teachos::arch::kernel::cpu -- 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/include/arch/cpu/interrupts.hpp | 3 --- arch/x86_64/kapi/cpu.cpp | 12 ++++++++++-- arch/x86_64/src/cpu/interrupts.cpp | 10 ---------- 3 files changed, 10 insertions(+), 15 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/cpu/interrupts.hpp b/arch/x86_64/include/arch/cpu/interrupts.hpp index 08ecd9c..b9adb6e 100644 --- a/arch/x86_64/include/arch/cpu/interrupts.hpp +++ b/arch/x86_64/include/arch/cpu/interrupts.hpp @@ -111,9 +111,6 @@ namespace arch::cpu auto static read() -> interrupt_descriptor_table_register; }; - auto enable_interrupts() -> void; - auto disable_interrupts() -> void; - } // namespace arch::cpu #endif \ No newline at end of file diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index 693d328..8ca3847 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -3,7 +3,6 @@ #include "kapi/system.hpp" #include "arch/cpu/initialization.hpp" -#include "arch/cpu/interrupts.hpp" #include @@ -21,7 +20,6 @@ namespace kapi::cpu arch::cpu::initialize_descriptors(); arch::cpu::initialize_legacy_interrupts(); - arch::cpu::enable_interrupts(); } auto halt() -> void @@ -30,4 +28,14 @@ namespace kapi::cpu __builtin_unreachable(); } + auto enable_interrupts() -> void + { + asm volatile("sti"); + } + + auto disable_interrupts() -> void + { + asm volatile("cli"); + } + } // namespace kapi::cpu 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') 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/kapi/cpu.cpp | 49 ++++++++++++++++++++++++++++++++++++++ arch/x86_64/src/cpu/interrupts.cpp | 17 ++++--------- 2 files changed, 53 insertions(+), 13 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index 8ca3847..b19ba21 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -4,11 +4,22 @@ #include "arch/cpu/initialization.hpp" +#include +#include + +#include #include +#include namespace kapi::cpu { + namespace + { + constexpr auto irq_offset = 32uz; + auto constinit interrupt_handlers = std::array, 256 - irq_offset>{}; + } // namespace + auto init() -> void { auto static constinit is_initialized = std::atomic_flag{}; @@ -38,4 +49,42 @@ namespace kapi::cpu asm volatile("cli"); } + auto register_interrupt_handler(std::uint32_t irq_number, interrupt_handler & handler) -> void + { + if (irq_number < irq_offset) + { + system::panic("[x86_64:CPU] IRQ number must be in range [32, 255]."); + } + + interrupt_handlers[irq_number - irq_offset].push_back(&handler); + } + + auto unregister_interrupt_handler(std::uint32_t irq_number, [[maybe_unused]] interrupt_handler & handler) -> void + { + if (irq_number < irq_offset) + { + system::panic("[x86_64:CPU] IRQ number must be in range [32, 255]."); + } + + kstd::println("[x86_64:CPU] TODO: support erasure from vector."); + } + + auto dispatch_interrupt(std::uint32_t irq_number) -> status + { + if (irq_number < irq_offset) + { + return status::unhandled; + } + + for (auto handler : interrupt_handlers[irq_number - irq_offset]) + { + if (handler && handler->handle_interrupt(irq_number) == status::handled) + { + return status::handled; + } + } + + return status::unhandled; + } + } // namespace kapi::cpu 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') 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') 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 d56700342ea0266a6e49f9515eb83279f66b4fcf Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 26 Mar 2026 15:28:41 +0100 Subject: x86_64: split kapi::cpu implementation --- arch/x86_64/CMakeLists.txt | 1 + arch/x86_64/kapi/cpu.cpp | 59 -------------------------------- arch/x86_64/kapi/cpu/interrupts.cpp | 67 +++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 59 deletions(-) create mode 100644 arch/x86_64/kapi/cpu/interrupts.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 89d9bc0..8ff81d8 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -15,6 +15,7 @@ target_sources("x86_64" PRIVATE "kapi/boot_modules.cpp" "kapi/cio.cpp" "kapi/cpu.cpp" + "kapi/cpu/interrupts.cpp" "kapi/memory.cpp" "kapi/system.cpp" diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index b19ba21..12edb0f 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -4,22 +4,11 @@ #include "arch/cpu/initialization.hpp" -#include -#include - -#include #include -#include namespace kapi::cpu { - namespace - { - constexpr auto irq_offset = 32uz; - auto constinit interrupt_handlers = std::array, 256 - irq_offset>{}; - } // namespace - auto init() -> void { auto static constinit is_initialized = std::atomic_flag{}; @@ -39,52 +28,4 @@ namespace kapi::cpu __builtin_unreachable(); } - auto enable_interrupts() -> void - { - asm volatile("sti"); - } - - auto disable_interrupts() -> void - { - asm volatile("cli"); - } - - auto register_interrupt_handler(std::uint32_t irq_number, interrupt_handler & handler) -> void - { - if (irq_number < irq_offset) - { - system::panic("[x86_64:CPU] IRQ number must be in range [32, 255]."); - } - - interrupt_handlers[irq_number - irq_offset].push_back(&handler); - } - - auto unregister_interrupt_handler(std::uint32_t irq_number, [[maybe_unused]] interrupt_handler & handler) -> void - { - if (irq_number < irq_offset) - { - system::panic("[x86_64:CPU] IRQ number must be in range [32, 255]."); - } - - kstd::println("[x86_64:CPU] TODO: support erasure from vector."); - } - - auto dispatch_interrupt(std::uint32_t irq_number) -> status - { - if (irq_number < irq_offset) - { - return status::unhandled; - } - - for (auto handler : interrupt_handlers[irq_number - irq_offset]) - { - if (handler && handler->handle_interrupt(irq_number) == status::handled) - { - return status::handled; - } - } - - return status::unhandled; - } - } // namespace kapi::cpu diff --git a/arch/x86_64/kapi/cpu/interrupts.cpp b/arch/x86_64/kapi/cpu/interrupts.cpp new file mode 100644 index 0000000..b98595c --- /dev/null +++ b/arch/x86_64/kapi/cpu/interrupts.cpp @@ -0,0 +1,67 @@ +#include "kapi/cpu.hpp" +#include "kapi/system.hpp" + +#include +#include + +#include +#include + +namespace kapi::cpu +{ + + namespace + { + constexpr auto irq_offset = 32uz; + auto constinit interrupt_handlers = std::array, 256 - irq_offset>{}; + } // namespace + + auto enable_interrupts() -> void + { + asm volatile("sti"); + } + + auto disable_interrupts() -> void + { + asm volatile("cli"); + } + + auto register_interrupt_handler(std::uint32_t irq_number, interrupt_handler & handler) -> void + { + if (irq_number < irq_offset) + { + system::panic("[x86_64:CPU] IRQ number must be in range [32, 255]."); + } + + interrupt_handlers[irq_number - irq_offset].push_back(&handler); + } + + auto unregister_interrupt_handler(std::uint32_t irq_number, [[maybe_unused]] interrupt_handler & handler) -> void + { + if (irq_number < irq_offset) + { + system::panic("[x86_64:CPU] IRQ number must be in range [32, 255]."); + } + + kstd::println("[x86_64:CPU] TODO: support erasure from vector."); + } + + auto dispatch_interrupt(std::uint32_t irq_number) -> status + { + if (irq_number < irq_offset) + { + return status::unhandled; + } + + for (auto handler : interrupt_handlers[irq_number - irq_offset]) + { + if (handler && handler->handle_interrupt(irq_number) == status::handled) + { + return status::handled; + } + } + + return status::unhandled; + } + +} // namespace kapi::cpu \ No newline at end of file -- 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') 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/CMakeLists.txt | 2 +- arch/x86_64/kapi/cpu/interrupts.cpp | 67 ------------------------------------ arch/x86_64/kapi/interrupts.cpp | 68 +++++++++++++++++++++++++++++++++++++ arch/x86_64/src/cpu/interrupts.cpp | 3 +- 4 files changed, 71 insertions(+), 69 deletions(-) delete mode 100644 arch/x86_64/kapi/cpu/interrupts.cpp create mode 100644 arch/x86_64/kapi/interrupts.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 8ff81d8..4427e4c 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -15,7 +15,7 @@ target_sources("x86_64" PRIVATE "kapi/boot_modules.cpp" "kapi/cio.cpp" "kapi/cpu.cpp" - "kapi/cpu/interrupts.cpp" + "kapi/interrupts.cpp" "kapi/memory.cpp" "kapi/system.cpp" diff --git a/arch/x86_64/kapi/cpu/interrupts.cpp b/arch/x86_64/kapi/cpu/interrupts.cpp deleted file mode 100644 index b98595c..0000000 --- a/arch/x86_64/kapi/cpu/interrupts.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "kapi/cpu.hpp" -#include "kapi/system.hpp" - -#include -#include - -#include -#include - -namespace kapi::cpu -{ - - namespace - { - constexpr auto irq_offset = 32uz; - auto constinit interrupt_handlers = std::array, 256 - irq_offset>{}; - } // namespace - - auto enable_interrupts() -> void - { - asm volatile("sti"); - } - - auto disable_interrupts() -> void - { - asm volatile("cli"); - } - - auto register_interrupt_handler(std::uint32_t irq_number, interrupt_handler & handler) -> void - { - if (irq_number < irq_offset) - { - system::panic("[x86_64:CPU] IRQ number must be in range [32, 255]."); - } - - interrupt_handlers[irq_number - irq_offset].push_back(&handler); - } - - auto unregister_interrupt_handler(std::uint32_t irq_number, [[maybe_unused]] interrupt_handler & handler) -> void - { - if (irq_number < irq_offset) - { - system::panic("[x86_64:CPU] IRQ number must be in range [32, 255]."); - } - - kstd::println("[x86_64:CPU] TODO: support erasure from vector."); - } - - auto dispatch_interrupt(std::uint32_t irq_number) -> status - { - if (irq_number < irq_offset) - { - return status::unhandled; - } - - for (auto handler : interrupt_handlers[irq_number - irq_offset]) - { - if (handler && handler->handle_interrupt(irq_number) == status::handled) - { - return status::handled; - } - } - - return status::unhandled; - } - -} // namespace kapi::cpu \ No newline at end of file diff --git a/arch/x86_64/kapi/interrupts.cpp b/arch/x86_64/kapi/interrupts.cpp new file mode 100644 index 0000000..babc926 --- /dev/null +++ b/arch/x86_64/kapi/interrupts.cpp @@ -0,0 +1,68 @@ +#include "kapi/interrupts.hpp" + +#include "kapi/system.hpp" + +#include +#include + +#include +#include + +namespace kapi::interrupts +{ + + namespace + { + constexpr auto irq_offset = 32uz; + auto constinit handlers = std::array, 256 - irq_offset>{}; + } // namespace + + auto enable() -> void + { + asm volatile("sti"); + } + + auto disable() -> void + { + asm volatile("cli"); + } + + auto register_handler(std::uint32_t irq_number, handler & handler) -> void + { + if (irq_number < irq_offset) + { + system::panic("[x86_64:CPU] IRQ number must be in range [32, 255]."); + } + + handlers[irq_number - irq_offset].push_back(&handler); + } + + auto unregister_handler(std::uint32_t irq_number, [[maybe_unused]] handler & handler) -> void + { + if (irq_number < irq_offset) + { + system::panic("[x86_64:CPU] IRQ number must be in range [32, 255]."); + } + + kstd::println("[x86_64:CPU] TODO: support erasure from vector."); + } + + auto dispatch(std::uint32_t irq_number) -> status + { + if (irq_number < irq_offset) + { + return status::unhandled; + } + + for (auto handler : handlers[irq_number - irq_offset]) + { + if (handler && handler->handle_interrupt(irq_number) == status::handled) + { + return status::handled; + } + } + + return status::unhandled; + } + +} // namespace kapi::interrupts \ No newline at end of file diff --git a/arch/x86_64/src/cpu/interrupts.cpp b/arch/x86_64/src/cpu/interrupts.cpp index 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 f4dc64976049761a6f56dd55d9d0b651f1e9475f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 26 Mar 2026 16:47:41 +0100 Subject: kapi: move interrupt handling to kernel --- arch/x86_64/kapi/interrupts.cpp | 52 ----------------------------------------- 1 file changed, 52 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/interrupts.cpp b/arch/x86_64/kapi/interrupts.cpp index babc926..cf1defa 100644 --- a/arch/x86_64/kapi/interrupts.cpp +++ b/arch/x86_64/kapi/interrupts.cpp @@ -1,22 +1,8 @@ #include "kapi/interrupts.hpp" -#include "kapi/system.hpp" - -#include -#include - -#include -#include - namespace kapi::interrupts { - namespace - { - constexpr auto irq_offset = 32uz; - auto constinit handlers = std::array, 256 - irq_offset>{}; - } // namespace - auto enable() -> void { asm volatile("sti"); @@ -27,42 +13,4 @@ namespace kapi::interrupts asm volatile("cli"); } - auto register_handler(std::uint32_t irq_number, handler & handler) -> void - { - if (irq_number < irq_offset) - { - system::panic("[x86_64:CPU] IRQ number must be in range [32, 255]."); - } - - handlers[irq_number - irq_offset].push_back(&handler); - } - - auto unregister_handler(std::uint32_t irq_number, [[maybe_unused]] handler & handler) -> void - { - if (irq_number < irq_offset) - { - system::panic("[x86_64:CPU] IRQ number must be in range [32, 255]."); - } - - kstd::println("[x86_64:CPU] TODO: support erasure from vector."); - } - - auto dispatch(std::uint32_t irq_number) -> status - { - if (irq_number < irq_offset) - { - return status::unhandled; - } - - for (auto handler : handlers[irq_number - irq_offset]) - { - if (handler && handler->handle_interrupt(irq_number) == status::handled) - { - return status::handled; - } - } - - return status::unhandled; - } - } // namespace kapi::interrupts \ No newline at end of file -- 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') 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/CMakeLists.txt | 4 +++ arch/x86_64/include/arch/bus/isa.hpp | 31 ++++++++++++++++++++ arch/x86_64/kapi/devices.cpp | 22 ++++++++++++++ arch/x86_64/src/bus/isa.cpp | 56 ++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 arch/x86_64/include/arch/bus/isa.hpp create mode 100644 arch/x86_64/kapi/devices.cpp create mode 100644 arch/x86_64/src/bus/isa.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 4427e4c..21dceef 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -15,6 +15,7 @@ target_sources("x86_64" PRIVATE "kapi/boot_modules.cpp" "kapi/cio.cpp" "kapi/cpu.cpp" + "kapi/devices.cpp" "kapi/interrupts.cpp" "kapi/memory.cpp" "kapi/system.cpp" @@ -24,6 +25,9 @@ target_sources("x86_64" PRIVATE "src/cpu/interrupts.cpp" "src/cpu/interrupt_stubs.S" + # Bus Initialization + "src/bus/isa.cpp" + # Low-level bootstrap "src/boot/boot32.S" "src/boot/entry64.s" diff --git a/arch/x86_64/include/arch/bus/isa.hpp b/arch/x86_64/include/arch/bus/isa.hpp new file mode 100644 index 0000000..41dda93 --- /dev/null +++ b/arch/x86_64/include/arch/bus/isa.hpp @@ -0,0 +1,31 @@ +#ifndef TEACHOS_X86_64_BUS_ISA_HPP +#define TEACHOS_X86_64_BUS_ISA_HPP + +#include "kapi/devices/bus.hpp" +#include "kapi/devices/device.hpp" + +#include +#include + +namespace arch::bus +{ + + struct isa final : public kapi::devices::bus + { + isa(); + + auto add_child(kstd::unique_ptr child) -> void override; + + [[nodiscard]] auto children() const -> kstd::vector> const & override; + + auto init() -> bool override; + + private: + kstd::vector> m_devices{}; + kstd::vector> m_observers{}; + bool m_initialized{}; + }; + +} // namespace arch::bus + +#endif // TEACHOS_X86_64_BUS_ISA_HPP diff --git a/arch/x86_64/kapi/devices.cpp b/arch/x86_64/kapi/devices.cpp new file mode 100644 index 0000000..25185d6 --- /dev/null +++ b/arch/x86_64/kapi/devices.cpp @@ -0,0 +1,22 @@ +#include "kapi/devices.hpp" + +#include "arch/bus/isa.hpp" + +#include +#include + +#include + +namespace kapi::devices +{ + + auto init_platform_devices() -> void + { + kstd::println("[x86_64:devices] Initializing ISA bus..."); + auto isa_bus = kstd::make_unique(); + + auto & root_bus = get_root_bus(); + root_bus.add_child(std::move(isa_bus)); + } + +} // namespace kapi::devices \ No newline at end of file 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/include/arch/bus/isa.hpp | 15 ------------ arch/x86_64/src/bus/isa.cpp | 44 ------------------------------------ 2 files changed, 59 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/bus/isa.hpp b/arch/x86_64/include/arch/bus/isa.hpp index 41dda93..bd92b2e 100644 --- a/arch/x86_64/include/arch/bus/isa.hpp +++ b/arch/x86_64/include/arch/bus/isa.hpp @@ -2,10 +2,6 @@ #define TEACHOS_X86_64_BUS_ISA_HPP #include "kapi/devices/bus.hpp" -#include "kapi/devices/device.hpp" - -#include -#include namespace arch::bus { @@ -13,17 +9,6 @@ namespace arch::bus struct isa final : public kapi::devices::bus { isa(); - - auto add_child(kstd::unique_ptr child) -> void override; - - [[nodiscard]] auto children() const -> kstd::vector> const & override; - - auto init() -> bool override; - - private: - kstd::vector> m_devices{}; - kstd::vector> m_observers{}; - bool m_initialized{}; }; } // namespace arch::bus 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/CMakeLists.txt | 3 ++ arch/x86_64/include/arch/devices/legacy_pit.hpp | 28 +++++++++++++ arch/x86_64/kapi/devices.cpp | 11 +++++ arch/x86_64/src/cpu/initialization.cpp | 2 +- arch/x86_64/src/devices/legacy_pit.cpp | 54 +++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 arch/x86_64/include/arch/devices/legacy_pit.hpp create mode 100644 arch/x86_64/src/devices/legacy_pit.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 21dceef..83cae0b 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -37,6 +37,9 @@ target_sources("x86_64" PRIVATE # Debug interfaces "src/debug/qemu_output.cpp" + # Devices + "src/devices/legacy_pit.cpp" + # Memory management "src/memory/kernel_mapper.cpp" "src/memory/higher_half_mapper.cpp" diff --git a/arch/x86_64/include/arch/devices/legacy_pit.hpp b/arch/x86_64/include/arch/devices/legacy_pit.hpp new file mode 100644 index 0000000..d28e4d6 --- /dev/null +++ b/arch/x86_64/include/arch/devices/legacy_pit.hpp @@ -0,0 +1,28 @@ +#ifndef TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP +#define TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP + +#include "kapi/devices/device.hpp" +#include "kapi/interrupts.hpp" + +#include + +namespace arch::devices +{ + + struct legacy_pit : kapi::devices::device, kapi::interrupts::handler + { + explicit legacy_pit(std::uint32_t frequency_in_hz); + + auto init() -> bool override; + + auto handle_interrupt(std::uint32_t irq_number) -> kapi::interrupts::status override; + + private: + std::uint32_t m_irq_number{}; + std::uint32_t m_frequency_in_hz{}; + std::uint64_t m_ticks{}; + }; + +} // namespace arch::devices + +#endif \ No newline at end of file diff --git a/arch/x86_64/kapi/devices.cpp b/arch/x86_64/kapi/devices.cpp index 25185d6..7aa7090 100644 --- a/arch/x86_64/kapi/devices.cpp +++ b/arch/x86_64/kapi/devices.cpp @@ -1,20 +1,31 @@ #include "kapi/devices.hpp" #include "arch/bus/isa.hpp" +#include "arch/devices/legacy_pit.hpp" #include #include +#include #include namespace kapi::devices { + namespace + { + constexpr auto pit_frequency_in_hz = std::uint32_t{100u}; + } + auto init_platform_devices() -> void { kstd::println("[x86_64:devices] Initializing ISA bus..."); + auto isa_bus = kstd::make_unique(); + auto pit = kstd::make_unique(pit_frequency_in_hz); + isa_bus->add_child(std::move(pit)); + auto & root_bus = get_root_bus(); root_bus.add_child(std::move(isa_bus)); } 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/include/arch/bus/isa.hpp | 4 +++- arch/x86_64/include/arch/devices/legacy_pit.hpp | 3 ++- arch/x86_64/kapi/devices.cpp | 6 ++++-- arch/x86_64/src/bus/isa.cpp | 6 ++++-- arch/x86_64/src/devices/legacy_pit.cpp | 5 +++-- 5 files changed, 16 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/bus/isa.hpp b/arch/x86_64/include/arch/bus/isa.hpp index bd92b2e..5deed25 100644 --- a/arch/x86_64/include/arch/bus/isa.hpp +++ b/arch/x86_64/include/arch/bus/isa.hpp @@ -3,12 +3,14 @@ #include "kapi/devices/bus.hpp" +#include + namespace arch::bus { struct isa final : public kapi::devices::bus { - isa(); + isa(std::size_t major); }; } // namespace arch::bus diff --git a/arch/x86_64/include/arch/devices/legacy_pit.hpp b/arch/x86_64/include/arch/devices/legacy_pit.hpp index d28e4d6..de742ae 100644 --- a/arch/x86_64/include/arch/devices/legacy_pit.hpp +++ b/arch/x86_64/include/arch/devices/legacy_pit.hpp @@ -4,6 +4,7 @@ #include "kapi/devices/device.hpp" #include "kapi/interrupts.hpp" +#include #include namespace arch::devices @@ -11,7 +12,7 @@ namespace arch::devices struct legacy_pit : kapi::devices::device, kapi::interrupts::handler { - explicit legacy_pit(std::uint32_t frequency_in_hz); + legacy_pit(std::size_t major, std::uint32_t frequency_in_hz); auto init() -> bool override; diff --git a/arch/x86_64/kapi/devices.cpp b/arch/x86_64/kapi/devices.cpp index 7aa7090..b15503d 100644 --- a/arch/x86_64/kapi/devices.cpp +++ b/arch/x86_64/kapi/devices.cpp @@ -21,9 +21,11 @@ namespace kapi::devices { kstd::println("[x86_64:devices] Initializing ISA bus..."); - auto isa_bus = kstd::make_unique(); + auto isa_major_number = kapi::devices::allocate_major_number(); + auto isa_bus = kstd::make_unique(isa_major_number); - auto pit = kstd::make_unique(pit_frequency_in_hz); + 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 = get_root_bus(); 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/include/arch/device_io/port_io.hpp | 5 +++++ arch/x86_64/src/devices/legacy_pit.cpp | 13 +++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/device_io/port_io.hpp b/arch/x86_64/include/arch/device_io/port_io.hpp index 70773dd..4c8d66a 100644 --- a/arch/x86_64/include/arch/device_io/port_io.hpp +++ b/arch/x86_64/include/arch/device_io/port_io.hpp @@ -102,6 +102,11 @@ namespace arch::io : std::string_view{"eax"}; }; + auto inline wait() -> void + { + port<0x80, std::uint8_t, port_write>::write(0); + } + } // namespace arch::io #endif \ 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 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 3dcd14a0570fef3bcc68d7df42fe3ff4cd496f93 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 6 Apr 2026 14:47:37 +0200 Subject: kapi: hook ACPI initialization up to boot process --- arch/x86_64/kapi/devices.cpp | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/devices.cpp b/arch/x86_64/kapi/devices.cpp index b15503d..e1773e7 100644 --- a/arch/x86_64/kapi/devices.cpp +++ b/arch/x86_64/kapi/devices.cpp @@ -1,5 +1,9 @@ #include "kapi/devices.hpp" +#include "kapi/acpi.hpp" +#include "kapi/boot.hpp" + +#include "arch/boot/boot.hpp" #include "arch/bus/isa.hpp" #include "arch/devices/legacy_pit.hpp" @@ -19,7 +23,33 @@ namespace kapi::devices auto init_platform_devices() -> void { - kstd::println("[x86_64:devices] Initializing ISA bus..."); + auto const & mbi = 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."); + } + + 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); -- 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/CMakeLists.txt | 1 + arch/x86_64/include/arch/devices/init.hpp | 12 ++++++ arch/x86_64/kapi/devices.cpp | 57 ++----------------------- arch/x86_64/src/devices/init.cpp | 69 +++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 54 deletions(-) create mode 100644 arch/x86_64/include/arch/devices/init.hpp create mode 100644 arch/x86_64/src/devices/init.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 83cae0b..f77eec5 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -38,6 +38,7 @@ target_sources("x86_64" PRIVATE "src/debug/qemu_output.cpp" # Devices + "src/devices/init.cpp" "src/devices/legacy_pit.cpp" # Memory management diff --git a/arch/x86_64/include/arch/devices/init.hpp b/arch/x86_64/include/arch/devices/init.hpp new file mode 100644 index 0000000..c5fbf37 --- /dev/null +++ b/arch/x86_64/include/arch/devices/init.hpp @@ -0,0 +1,12 @@ +#ifndef TEACHOS_ARCH_X86_64_DEVICES_INIT_HPP +#define TEACHOS_ARCH_X86_64_DEVICES_INIT_HPP + +namespace arch::devices +{ + + auto init_acpi_devices() -> void; + auto init_legacy_devices() -> void; + +} // namespace arch::devices + +#endif \ No newline at end of file diff --git a/arch/x86_64/kapi/devices.cpp b/arch/x86_64/kapi/devices.cpp index e1773e7..47c7f8c 100644 --- a/arch/x86_64/kapi/devices.cpp +++ b/arch/x86_64/kapi/devices.cpp @@ -1,65 +1,14 @@ #include "kapi/devices.hpp" -#include "kapi/acpi.hpp" -#include "kapi/boot.hpp" - -#include "arch/boot/boot.hpp" -#include "arch/bus/isa.hpp" -#include "arch/devices/legacy_pit.hpp" - -#include -#include - -#include -#include +#include "arch/devices/init.hpp" namespace kapi::devices { - namespace - { - constexpr auto pit_frequency_in_hz = std::uint32_t{100u}; - } - auto init_platform_devices() -> void { - auto const & mbi = 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."); - } - - 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 = get_root_bus(); - root_bus.add_child(std::move(isa_bus)); + arch::devices::init_acpi_devices(); + arch::devices::init_legacy_devices(); } } // namespace kapi::devices \ No newline at end of file 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/CMakeLists.txt | 2 ++ arch/x86_64/include/arch/devices/local_apic.hpp | 26 +++++++++++++++ arch/x86_64/kapi/acpi.cpp | 43 +++++++++++++++++++++++++ arch/x86_64/src/devices/init.cpp | 32 +----------------- arch/x86_64/src/devices/local_apic.cpp | 28 ++++++++++++++++ 5 files changed, 100 insertions(+), 31 deletions(-) create mode 100644 arch/x86_64/include/arch/devices/local_apic.hpp create mode 100644 arch/x86_64/kapi/acpi.cpp create mode 100644 arch/x86_64/src/devices/local_apic.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index f77eec5..62a2aad 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -12,6 +12,7 @@ target_link_libraries("x86_64" PUBLIC target_sources("x86_64" PRIVATE # Platform-dependent KAPI implementation + "kapi/acpi.cpp" "kapi/boot_modules.cpp" "kapi/cio.cpp" "kapi/cpu.cpp" @@ -40,6 +41,7 @@ target_sources("x86_64" PRIVATE # Devices "src/devices/init.cpp" "src/devices/legacy_pit.cpp" + "src/devices/local_apic.cpp" # Memory management "src/memory/kernel_mapper.cpp" diff --git a/arch/x86_64/include/arch/devices/local_apic.hpp b/arch/x86_64/include/arch/devices/local_apic.hpp new file mode 100644 index 0000000..71e9758 --- /dev/null +++ b/arch/x86_64/include/arch/devices/local_apic.hpp @@ -0,0 +1,26 @@ +#ifndef TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP +#define TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP + +#include "kapi/devices/device.hpp" +#include "kapi/memory.hpp" + +#include +#include + +namespace arch::devices +{ + + struct local_apic : kapi::devices::device + { + local_apic(std::size_t major, std::size_t minor, std::uint64_t hardware_id, kapi::memory::physical_address base); + + auto init() -> bool override; + + private: + std::uint64_t m_hardware_id{}; + kapi::memory::physical_address m_base{}; + }; + +} // namespace arch::devices + +#endif \ No newline at end of file diff --git a/arch/x86_64/kapi/acpi.cpp b/arch/x86_64/kapi/acpi.cpp new file mode 100644 index 0000000..9766154 --- /dev/null +++ b/arch/x86_64/kapi/acpi.cpp @@ -0,0 +1,43 @@ +#include "kapi/acpi.hpp" + +#include "kapi/devices.hpp" +#include "kapi/memory.hpp" + +#include "arch/boot/boot.hpp" +#include "arch/devices/local_apic.hpp" + +#include + +#include +#include + +namespace kapi::acpi +{ + + auto get_root_pointer() -> kstd::observer_ptr + { + 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); + } + + return kstd::make_observer(system_description_pointer); + } + + auto create_local_interrupt_controller(std::size_t major, std::size_t minor, std::uint64_t hardware_id, + memory::physical_address address) -> kstd::unique_ptr + { + return kstd::make_unique(major, minor, hardware_id, address); + } + +} // namespace kapi::acpi \ No newline at end of file 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 f50815110789a0f8f6e5ca66ffd49b26578791a9 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 6 Apr 2026 18:43:28 +0200 Subject: kernel: generalize CPU discovery --- arch/x86_64/CMakeLists.txt | 1 + arch/x86_64/kapi/acpi.cpp | 13 -------- arch/x86_64/kapi/platform.cpp | 70 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 arch/x86_64/kapi/platform.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 62a2aad..87cb98c 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -19,6 +19,7 @@ target_sources("x86_64" PRIVATE "kapi/devices.cpp" "kapi/interrupts.cpp" "kapi/memory.cpp" + "kapi/platform.cpp" "kapi/system.cpp" # CPU Initialization diff --git a/arch/x86_64/kapi/acpi.cpp b/arch/x86_64/kapi/acpi.cpp index 9766154..ec38aee 100644 --- a/arch/x86_64/kapi/acpi.cpp +++ b/arch/x86_64/kapi/acpi.cpp @@ -1,16 +1,9 @@ #include "kapi/acpi.hpp" -#include "kapi/devices.hpp" -#include "kapi/memory.hpp" - #include "arch/boot/boot.hpp" -#include "arch/devices/local_apic.hpp" #include -#include -#include - namespace kapi::acpi { @@ -34,10 +27,4 @@ namespace kapi::acpi return kstd::make_observer(system_description_pointer); } - auto create_local_interrupt_controller(std::size_t major, std::size_t minor, std::uint64_t hardware_id, - memory::physical_address address) -> kstd::unique_ptr - { - return kstd::make_unique(major, minor, hardware_id, address); - } - } // namespace kapi::acpi \ No newline at end of file diff --git a/arch/x86_64/kapi/platform.cpp b/arch/x86_64/kapi/platform.cpp new file mode 100644 index 0000000..2e7c7e4 --- /dev/null +++ b/arch/x86_64/kapi/platform.cpp @@ -0,0 +1,70 @@ +#include "kapi/platform.hpp" + +#include "kapi/acpi.hpp" +#include "kapi/devices.hpp" +#include "kapi/memory.hpp" + +#include "arch/devices/local_apic.hpp" + +#include +#include + +#include +#include + +namespace kapi::platform +{ + + namespace + { + constexpr auto default_lapic_address = kapi::memory::physical_address{0xFEE0'0000}; + } + + auto discover_cpu_topology(kapi::devices::bus & bus) -> bool + { + auto madt = kapi::acpi::get_table("APIC"); + if (!madt) + { + kstd::println("[x86_64:PLT] Failed to find ACPI APIC table"); + return false; + } + + auto const * current = reinterpret_cast(madt.get()) + sizeof(kapi::acpi::madt_header); + auto const * end = reinterpret_cast(madt.get()) + madt->length(); + + auto bsp_found = false; + auto core_count = 0uz; + + while (current < end) + { + auto const * sub_table = reinterpret_cast(current); + if (sub_table->type() == 0) + { + auto const * local_apic = reinterpret_cast(sub_table); + if (local_apic->flags() & 0b11) + { + auto is_bsp = !bsp_found; + bsp_found = true; + + if (kapi::platform::cpu_detected(bus, local_apic->processor_id(), is_bsp)) + { + ++core_count; + } + } + } + + current += sub_table->length(); + } + + kstd::println("[x86_64:PLT] Found {} CPU cores", core_count); + + return core_count > 0; + } + + auto create_core_interrupt_controller(std::size_t major, std::size_t minor, std::uint64_t hardware_id) + -> kstd::unique_ptr + { + return kstd::make_unique(major, minor, hardware_id, default_lapic_address); + } + +} // namespace kapi::platform \ No newline at end of file -- cgit v1.2.3 From d5c2e101d62f6b4b69c45c127e7a729d246da566 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 6 Apr 2026 19:04:16 +0200 Subject: kapi/platform: invert discovery dependencies --- arch/x86_64/kapi/platform.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/platform.cpp b/arch/x86_64/kapi/platform.cpp index 2e7c7e4..380fc66 100644 --- a/arch/x86_64/kapi/platform.cpp +++ b/arch/x86_64/kapi/platform.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include namespace kapi::platform { @@ -22,6 +22,10 @@ namespace kapi::platform auto discover_cpu_topology(kapi::devices::bus & bus) -> bool { + auto static const core_major = kapi::devices::allocate_major_number(); + auto static const interrupt_controller_major = kapi::devices::allocate_major_number(); + auto static core_index = 0uz; + auto madt = kapi::acpi::get_table("APIC"); if (!madt) { @@ -46,7 +50,10 @@ namespace kapi::platform auto is_bsp = !bsp_found; bsp_found = true; - if (kapi::platform::cpu_detected(bus, local_apic->processor_id(), is_bsp)) + auto lapic = kstd::make_unique(interrupt_controller_major, core_index, + local_apic->apic_id(), default_lapic_address); + if (kapi::platform::cpu_detected(bus, core_major, core_index, local_apic->processor_id(), is_bsp, + std::move(lapic))) { ++core_count; } @@ -61,10 +68,4 @@ namespace kapi::platform return core_count > 0; } - auto create_core_interrupt_controller(std::size_t major, std::size_t minor, std::uint64_t hardware_id) - -> kstd::unique_ptr - { - return kstd::make_unique(major, minor, hardware_id, default_lapic_address); - } - } // namespace kapi::platform \ No newline at end of file -- cgit v1.2.3 From 878852c94c4d56f303366cec177b3edef9b3b9c5 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 8 Apr 2026 13:54:52 +0200 Subject: kapi: add basic support for MMIO mapping --- arch/x86_64/include/arch/memory/page_table.hpp | 6 +++--- arch/x86_64/kapi/memory.cpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/memory/page_table.hpp b/arch/x86_64/include/arch/memory/page_table.hpp index 3cbb0af..c75ccaf 100644 --- a/arch/x86_64/include/arch/memory/page_table.hpp +++ b/arch/x86_64/include/arch/memory/page_table.hpp @@ -174,7 +174,7 @@ namespace arch::memory result |= mapper_flags::writable; } - if ((flags & table_flags::disable_cache) != table_flags::empty) + if ((flags & (table_flags::disable_cache | table_flags::write_through)) != table_flags::empty) { result |= mapper_flags::uncached; } @@ -211,7 +211,7 @@ namespace arch::memory if ((flags & mapper_flags::uncached) != mapper_flags::empty) { - result |= table_flags::disable_cache; + result |= (table_flags::disable_cache | table_flags::write_through); } if ((flags & mapper_flags::supervisor_only) == mapper_flags::empty) @@ -229,4 +229,4 @@ namespace arch::memory } // namespace arch::memory -#endif \ No newline at end of file +#endif diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index 5f12e5c..853639c 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -245,6 +245,7 @@ namespace kapi::memory [](auto const & region) { return region.base + region.size_in_B; })); init_pmm(frame::containing(physical_address{highest_byte}).number() + 1, handoff_to_kernel_pmm); + init_mmio(mmio_base, 1_GiB / page::size); kstd::println("[x86_64:MEM] Releasing bootstrap memory allocators."); region_based_allocator.reset(); -- cgit v1.2.3 From 1c52a859d105f6b0f8afb16565b10435fa728882 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 8 Apr 2026 14:15:56 +0200 Subject: kapi: fix mmio initialization --- arch/x86_64/kapi/memory.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index 853639c..5f12e5c 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -245,7 +245,6 @@ namespace kapi::memory [](auto const & region) { return region.base + region.size_in_B; })); init_pmm(frame::containing(physical_address{highest_byte}).number() + 1, handoff_to_kernel_pmm); - init_mmio(mmio_base, 1_GiB / page::size); kstd::println("[x86_64:MEM] Releasing bootstrap memory allocators."); region_based_allocator.reset(); -- 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/include/arch/devices/local_apic.hpp | 6 ++++- arch/x86_64/src/devices/local_apic.cpp | 33 +++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/devices/local_apic.hpp b/arch/x86_64/include/arch/devices/local_apic.hpp index 71e9758..7f125c3 100644 --- a/arch/x86_64/include/arch/devices/local_apic.hpp +++ b/arch/x86_64/include/arch/devices/local_apic.hpp @@ -17,10 +17,14 @@ namespace arch::devices auto init() -> bool override; private: + [[nodiscard]] auto read_register(std::size_t offset) const -> std::uint32_t; + auto write_register(std::size_t offset, std::uint32_t value) -> void; + std::uint64_t m_hardware_id{}; kapi::memory::physical_address m_base{}; + kapi::memory::linear_address m_virtual_base{}; }; } // namespace arch::devices -#endif \ No newline at end of file +#endif 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 296742bfa509524dc8effc3dcae4b6231d37705f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 8 Apr 2026 14:30:53 +0200 Subject: x86_64: don't hardcode the LAPIC address --- arch/x86_64/kapi/platform.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/platform.cpp b/arch/x86_64/kapi/platform.cpp index 380fc66..c6e41d2 100644 --- a/arch/x86_64/kapi/platform.cpp +++ b/arch/x86_64/kapi/platform.cpp @@ -2,7 +2,6 @@ #include "kapi/acpi.hpp" #include "kapi/devices.hpp" -#include "kapi/memory.hpp" #include "arch/devices/local_apic.hpp" @@ -15,11 +14,6 @@ namespace kapi::platform { - namespace - { - constexpr auto default_lapic_address = kapi::memory::physical_address{0xFEE0'0000}; - } - auto discover_cpu_topology(kapi::devices::bus & bus) -> bool { auto static const core_major = kapi::devices::allocate_major_number(); @@ -33,8 +27,9 @@ namespace kapi::platform return false; } - auto const * current = reinterpret_cast(madt.get()) + sizeof(kapi::acpi::madt_header); - auto const * end = reinterpret_cast(madt.get()) + madt->length(); + auto real_madt = static_cast(madt.get()); + auto current = reinterpret_cast(madt.get()) + sizeof(kapi::acpi::madt_header); + auto end = reinterpret_cast(madt.get()) + madt->length(); auto bsp_found = false; auto core_count = 0uz; @@ -49,9 +44,9 @@ namespace kapi::platform { auto is_bsp = !bsp_found; bsp_found = true; - auto lapic = kstd::make_unique(interrupt_controller_major, core_index, - local_apic->apic_id(), default_lapic_address); + local_apic->apic_id(), + real_madt->local_interrupt_controller_address()); if (kapi::platform::cpu_detected(bus, core_major, core_index, local_apic->processor_id(), is_bsp, std::move(lapic))) { @@ -68,4 +63,4 @@ namespace kapi::platform return core_count > 0; } -} // namespace kapi::platform \ No newline at end of file +} // namespace kapi::platform -- 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/include/arch/devices/local_apic.hpp | 4 +++- arch/x86_64/kapi/platform.cpp | 6 ++--- arch/x86_64/src/devices/local_apic.cpp | 30 +++++++++++++++++++------ 3 files changed, 29 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/devices/local_apic.hpp b/arch/x86_64/include/arch/devices/local_apic.hpp index 7f125c3..7ae0a02 100644 --- a/arch/x86_64/include/arch/devices/local_apic.hpp +++ b/arch/x86_64/include/arch/devices/local_apic.hpp @@ -12,7 +12,8 @@ namespace arch::devices struct local_apic : kapi::devices::device { - local_apic(std::size_t major, std::size_t minor, std::uint64_t hardware_id, kapi::memory::physical_address base); + local_apic(std::size_t major, std::size_t minor, std::uint64_t hardware_id, kapi::memory::physical_address base, + bool is_bsp); auto init() -> bool override; @@ -23,6 +24,7 @@ namespace arch::devices std::uint64_t m_hardware_id{}; kapi::memory::physical_address m_base{}; kapi::memory::linear_address m_virtual_base{}; + bool m_is_bsp{}; }; } // namespace arch::devices diff --git a/arch/x86_64/kapi/platform.cpp b/arch/x86_64/kapi/platform.cpp index c6e41d2..d881f8a 100644 --- a/arch/x86_64/kapi/platform.cpp +++ b/arch/x86_64/kapi/platform.cpp @@ -44,9 +44,9 @@ namespace kapi::platform { auto is_bsp = !bsp_found; bsp_found = true; - auto lapic = kstd::make_unique(interrupt_controller_major, core_index, - local_apic->apic_id(), - real_madt->local_interrupt_controller_address()); + auto lapic = kstd::make_unique( + interrupt_controller_major, core_index, local_apic->apic_id(), + real_madt->local_interrupt_controller_address(), is_bsp); if (kapi::platform::cpu_detected(bus, core_major, core_index, local_apic->processor_id(), is_bsp, std::move(lapic))) { 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 f36cbd54bb6319050404165e8a3280ccbda05cf3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 8 Apr 2026 15:51:04 +0200 Subject: x86_64: fix CPU enumeration --- arch/x86_64/kapi/platform.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/platform.cpp b/arch/x86_64/kapi/platform.cpp index d881f8a..4ee35c7 100644 --- a/arch/x86_64/kapi/platform.cpp +++ b/arch/x86_64/kapi/platform.cpp @@ -18,7 +18,6 @@ namespace kapi::platform { auto static const core_major = kapi::devices::allocate_major_number(); auto static const interrupt_controller_major = kapi::devices::allocate_major_number(); - auto static core_index = 0uz; auto madt = kapi::acpi::get_table("APIC"); if (!madt) @@ -45,9 +44,9 @@ namespace kapi::platform auto is_bsp = !bsp_found; bsp_found = true; auto lapic = kstd::make_unique( - interrupt_controller_major, core_index, local_apic->apic_id(), + interrupt_controller_major, core_count, local_apic->apic_id(), real_madt->local_interrupt_controller_address(), is_bsp); - if (kapi::platform::cpu_detected(bus, core_major, core_index, local_apic->processor_id(), is_bsp, + if (kapi::platform::cpu_detected(bus, core_major, core_count, local_apic->processor_id(), is_bsp, std::move(lapic))) { ++core_count; -- 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/include/arch/devices/local_apic.hpp | 9 ++- arch/x86_64/src/devices/local_apic.cpp | 77 ++++++++++++++++++++++--- 2 files changed, 76 insertions(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/devices/local_apic.hpp b/arch/x86_64/include/arch/devices/local_apic.hpp index 7ae0a02..946e4af 100644 --- a/arch/x86_64/include/arch/devices/local_apic.hpp +++ b/arch/x86_64/include/arch/devices/local_apic.hpp @@ -18,13 +18,18 @@ namespace arch::devices auto init() -> bool override; private: - [[nodiscard]] auto read_register(std::size_t offset) const -> std::uint32_t; - auto write_register(std::size_t offset, std::uint32_t value) -> void; + enum struct registers : std::ptrdiff_t; + + [[nodiscard]] auto read_register(registers id) const -> std::uint32_t; + auto write_register(registers id, std::uint32_t value) -> void; std::uint64_t m_hardware_id{}; kapi::memory::physical_address m_base{}; kapi::memory::linear_address m_virtual_base{}; bool m_is_bsp{}; + std::uint8_t m_version{}; + std::uint8_t m_highest_lvt_entry_index{}; + bool m_supports_eoi_broadcast_suppression{}; }; } // namespace arch::devices 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/include/arch/devices/local_apic.hpp | 2 +- arch/x86_64/src/devices/local_apic.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/devices/local_apic.hpp b/arch/x86_64/include/arch/devices/local_apic.hpp index 946e4af..ee1073f 100644 --- a/arch/x86_64/include/arch/devices/local_apic.hpp +++ b/arch/x86_64/include/arch/devices/local_apic.hpp @@ -25,7 +25,7 @@ namespace arch::devices std::uint64_t m_hardware_id{}; kapi::memory::physical_address m_base{}; - kapi::memory::linear_address m_virtual_base{}; + kapi::memory::mmio_region m_mapped_region{}; bool m_is_bsp{}; std::uint8_t m_version{}; std::uint8_t m_highest_lvt_entry_index{}; 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 f6bea6a5f1939f3261392633f6caca186befd555 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 9 Apr 2026 15:54:04 +0200 Subject: kapi: restructure ACPI implementation --- arch/x86_64/kapi/platform.cpp | 49 ++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 26 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/platform.cpp b/arch/x86_64/kapi/platform.cpp index 4ee35c7..fb27329 100644 --- a/arch/x86_64/kapi/platform.cpp +++ b/arch/x86_64/kapi/platform.cpp @@ -8,57 +8,54 @@ #include #include -#include +#include #include namespace kapi::platform { + namespace + { + constexpr auto candidate_flags = acpi::processor_local_apic::flags::processor_enabled // + | acpi::processor_local_apic::flags::online_capable; + } auto discover_cpu_topology(kapi::devices::bus & bus) -> bool { auto static const core_major = kapi::devices::allocate_major_number(); auto static const interrupt_controller_major = kapi::devices::allocate_major_number(); - auto madt = kapi::acpi::get_table("APIC"); + auto madt = kapi::acpi::get_table(); if (!madt) { kstd::println("[x86_64:PLT] Failed to find ACPI APIC table"); return false; } - auto real_madt = static_cast(madt.get()); - auto current = reinterpret_cast(madt.get()) + sizeof(kapi::acpi::madt_header); - auto end = reinterpret_cast(madt.get()) + madt->length(); - auto bsp_found = false; auto core_count = 0uz; + auto local_apic_address = madt->local_interrupt_controller_address(); - while (current < end) + auto lapic_entries = *madt | std::views::filter([](auto const & entry) { + return entry.type() == acpi::multiple_apic_description_table_entry::types::processor_local_apic; + }) | std::views::transform([](auto const & entry) { + return static_cast(entry); + }) | std::views::filter([](auto const & entry) { + return static_cast(entry.active_flags() & candidate_flags); + }); + + for (auto const & apic : lapic_entries) { - auto const * sub_table = reinterpret_cast(current); - if (sub_table->type() == 0) + auto is_bsp = !bsp_found; + bsp_found = true; + auto instance = kstd::make_unique(interrupt_controller_major, core_count, + apic.apic_id(), local_apic_address, is_bsp); + if (kapi::platform::cpu_detected(bus, core_major, core_count, apic.processor_id(), is_bsp, std::move(instance))) { - auto const * local_apic = reinterpret_cast(sub_table); - if (local_apic->flags() & 0b11) - { - auto is_bsp = !bsp_found; - bsp_found = true; - auto lapic = kstd::make_unique( - interrupt_controller_major, core_count, local_apic->apic_id(), - real_madt->local_interrupt_controller_address(), is_bsp); - if (kapi::platform::cpu_detected(bus, core_major, core_count, local_apic->processor_id(), is_bsp, - std::move(lapic))) - { - ++core_count; - } - } + ++core_count; } - - current += sub_table->length(); } kstd::println("[x86_64:PLT] Found {} CPU cores", core_count); - return core_count > 0; } -- cgit v1.2.3 From 3ad230fab8dc17758559aac3c20ba67a8c619878 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 10 Apr 2026 09:01:59 +0200 Subject: kapi: move platform functions to CPU --- arch/x86_64/CMakeLists.txt | 1 - arch/x86_64/kapi/cpu.cpp | 54 +++++++++++++++++++++++++++++++++++++ arch/x86_64/kapi/platform.cpp | 62 ------------------------------------------- 3 files changed, 54 insertions(+), 63 deletions(-) delete mode 100644 arch/x86_64/kapi/platform.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 87cb98c..62a2aad 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -19,7 +19,6 @@ target_sources("x86_64" PRIVATE "kapi/devices.cpp" "kapi/interrupts.cpp" "kapi/memory.cpp" - "kapi/platform.cpp" "kapi/system.cpp" # CPU Initialization diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index 12edb0f..1382e08 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -1,14 +1,28 @@ #include "kapi/cpu.hpp" +#include "kapi/acpi.hpp" +#include "kapi/devices.hpp" #include "kapi/system.hpp" #include "arch/cpu/initialization.hpp" +#include "arch/devices/local_apic.hpp" + +#include +#include #include +#include +#include namespace kapi::cpu { + namespace + { + constexpr auto candidate_flags = acpi::processor_local_apic::flags::processor_enabled // + | acpi::processor_local_apic::flags::online_capable; + } + auto init() -> void { auto static constinit is_initialized = std::atomic_flag{}; @@ -28,4 +42,44 @@ namespace kapi::cpu __builtin_unreachable(); } + auto discover_topology(kapi::devices::bus & bus) -> bool + { + auto static const core_major = kapi::devices::allocate_major_number(); + auto static const interrupt_controller_major = kapi::devices::allocate_major_number(); + + auto madt = kapi::acpi::get_table(); + if (!madt) + { + kstd::println("[x86_64:PLT] Failed to find ACPI APIC table"); + return false; + } + + auto bsp_found = false; + auto core_count = 0uz; + auto local_apic_address = madt->local_interrupt_controller_address(); + + auto lapic_entries = *madt | std::views::filter([](auto const & entry) { + return entry.type() == acpi::multiple_apic_description_table_entry::types::processor_local_apic; + }) | std::views::transform([](auto const & entry) { + return static_cast(entry); + }) | std::views::filter([](auto const & entry) { + return static_cast(entry.active_flags() & candidate_flags); + }); + + for (auto const & apic : lapic_entries) + { + auto is_bsp = !bsp_found; + bsp_found = true; + auto instance = kstd::make_unique(interrupt_controller_major, core_count, + apic.apic_id(), local_apic_address, is_bsp); + if (core_detected(bus, core_major, core_count, apic.processor_id(), is_bsp, std::move(instance))) + { + ++core_count; + } + } + + kstd::println("[x86_64:PLT] Found {} CPU cores", core_count); + return core_count > 0; + } + } // namespace kapi::cpu diff --git a/arch/x86_64/kapi/platform.cpp b/arch/x86_64/kapi/platform.cpp deleted file mode 100644 index fb27329..0000000 --- a/arch/x86_64/kapi/platform.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "kapi/platform.hpp" - -#include "kapi/acpi.hpp" -#include "kapi/devices.hpp" - -#include "arch/devices/local_apic.hpp" - -#include -#include - -#include -#include - -namespace kapi::platform -{ - namespace - { - constexpr auto candidate_flags = acpi::processor_local_apic::flags::processor_enabled // - | acpi::processor_local_apic::flags::online_capable; - } - - auto discover_cpu_topology(kapi::devices::bus & bus) -> bool - { - auto static const core_major = kapi::devices::allocate_major_number(); - auto static const interrupt_controller_major = kapi::devices::allocate_major_number(); - - auto madt = kapi::acpi::get_table(); - if (!madt) - { - kstd::println("[x86_64:PLT] Failed to find ACPI APIC table"); - return false; - } - - auto bsp_found = false; - auto core_count = 0uz; - auto local_apic_address = madt->local_interrupt_controller_address(); - - auto lapic_entries = *madt | std::views::filter([](auto const & entry) { - return entry.type() == acpi::multiple_apic_description_table_entry::types::processor_local_apic; - }) | std::views::transform([](auto const & entry) { - return static_cast(entry); - }) | std::views::filter([](auto const & entry) { - return static_cast(entry.active_flags() & candidate_flags); - }); - - for (auto const & apic : lapic_entries) - { - auto is_bsp = !bsp_found; - bsp_found = true; - auto instance = kstd::make_unique(interrupt_controller_major, core_count, - apic.apic_id(), local_apic_address, is_bsp); - if (kapi::platform::cpu_detected(bus, core_major, core_count, apic.processor_id(), is_bsp, std::move(instance))) - { - ++core_count; - } - } - - kstd::println("[x86_64:PLT] Found {} CPU cores", core_count); - return core_count > 0; - } - -} // namespace kapi::platform -- cgit v1.2.3 From dd8dfa3e674d05927e9ed4b7efcb634a634bfdcc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 10 Apr 2026 10:30:32 +0200 Subject: kapi: move CPU to kapi --- arch/x86_64/include/arch/cpu/initialization.hpp | 5 ++++- arch/x86_64/kapi/cpu.cpp | 26 ++++++++++++++----------- 2 files changed, 19 insertions(+), 12 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/cpu/initialization.hpp b/arch/x86_64/include/arch/cpu/initialization.hpp index 71186d4..564c544 100644 --- a/arch/x86_64/include/arch/cpu/initialization.hpp +++ b/arch/x86_64/include/arch/cpu/initialization.hpp @@ -1,4 +1,5 @@ -#pragma once +#ifndef TEACHOS_ARCH_X86_64_CPU_INITIALIZATION_HPP +#define TEACHOS_ARCH_X86_64_CPU_INITIALIZATION_HPP namespace arch::cpu { @@ -7,3 +8,5 @@ namespace arch::cpu auto initialize_legacy_interrupts() -> void; } // namespace arch::cpu + +#endif diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index 1382e08..726ec6a 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -2,6 +2,7 @@ #include "kapi/acpi.hpp" #include "kapi/devices.hpp" +#include "kapi/devices/cpu.hpp" #include "kapi/system.hpp" #include "arch/cpu/initialization.hpp" @@ -42,8 +43,9 @@ namespace kapi::cpu __builtin_unreachable(); } - auto discover_topology(kapi::devices::bus & bus) -> bool + auto discover_topology() -> bool { + auto static const cpu_major = kapi::devices::allocate_major_number(); auto static const core_major = kapi::devices::allocate_major_number(); auto static const interrupt_controller_major = kapi::devices::allocate_major_number(); @@ -54,10 +56,6 @@ namespace kapi::cpu return false; } - auto bsp_found = false; - auto core_count = 0uz; - auto local_apic_address = madt->local_interrupt_controller_address(); - auto lapic_entries = *madt | std::views::filter([](auto const & entry) { return entry.type() == acpi::multiple_apic_description_table_entry::types::processor_local_apic; }) | std::views::transform([](auto const & entry) { @@ -66,18 +64,24 @@ namespace kapi::cpu return static_cast(entry.active_flags() & candidate_flags); }); + auto bsp_found = false; + auto core_count = 0uz; + auto local_apic_address = madt->local_interrupt_controller_address(); + auto cpu_bus = kstd::make_unique(cpu_major, 0); + for (auto const & apic : lapic_entries) { auto is_bsp = !bsp_found; bsp_found = true; - auto instance = kstd::make_unique(interrupt_controller_major, core_count, - apic.apic_id(), local_apic_address, is_bsp); - if (core_detected(bus, core_major, core_count, apic.processor_id(), is_bsp, std::move(instance))) - { - ++core_count; - } + auto core = kstd::make_unique(core_major, core_count, apic.processor_id(), is_bsp); + core->add_child(kstd::make_unique(interrupt_controller_major, core_count, + apic.apic_id(), local_apic_address, is_bsp)); + cpu_bus->add_child(std::move(core)); + ++core_count; } + devices::get_root_bus().add_child(std::move(cpu_bus)); + kstd::println("[x86_64:PLT] Found {} CPU cores", core_count); return core_count > 0; } -- cgit v1.2.3 From c3f7b747f02a79b34ed914c54ce74be973b17af1 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 10 Apr 2026 17:39:14 +0200 Subject: kapi: extract ACPI functionality to libs --- arch/x86_64/kapi/acpi.cpp | 10 ++++++---- arch/x86_64/kapi/cpu.cpp | 15 +++++++++------ 2 files changed, 15 insertions(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/acpi.cpp b/arch/x86_64/kapi/acpi.cpp index ec38aee..40b7160 100644 --- a/arch/x86_64/kapi/acpi.cpp +++ b/arch/x86_64/kapi/acpi.cpp @@ -4,24 +4,26 @@ #include +#include + namespace kapi::acpi { - auto get_root_pointer() -> kstd::observer_ptr + auto get_root_pointer() -> kstd::observer_ptr<::acpi::rsdp const> { auto const & mbi = kapi::boot::bootstrap_information.mbi; - auto system_description_pointer = static_cast(nullptr); + 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(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(data); + system_description_pointer = reinterpret_cast<::acpi::rsdp const *>(data); } return kstd::make_observer(system_description_pointer); diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index 726ec6a..a836b20 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -3,6 +3,7 @@ #include "kapi/acpi.hpp" #include "kapi/devices.hpp" #include "kapi/devices/cpu.hpp" +#include "kapi/memory.hpp" #include "kapi/system.hpp" #include "arch/cpu/initialization.hpp" @@ -11,6 +12,8 @@ #include #include +#include + #include #include #include @@ -20,8 +23,8 @@ namespace kapi::cpu namespace { - constexpr auto candidate_flags = acpi::processor_local_apic::flags::processor_enabled // - | acpi::processor_local_apic::flags::online_capable; + constexpr auto candidate_flags = ::acpi::processor_local_apic::flags::processor_enabled // + | ::acpi::processor_local_apic::flags::online_capable; } auto init() -> void @@ -49,7 +52,7 @@ namespace kapi::cpu auto static const core_major = kapi::devices::allocate_major_number(); auto static const interrupt_controller_major = kapi::devices::allocate_major_number(); - auto madt = kapi::acpi::get_table(); + auto madt = kapi::acpi::get_table<::acpi::madt_table_signature>(); if (!madt) { kstd::println("[x86_64:PLT] Failed to find ACPI APIC table"); @@ -57,16 +60,16 @@ namespace kapi::cpu } auto lapic_entries = *madt | std::views::filter([](auto const & entry) { - return entry.type() == acpi::multiple_apic_description_table_entry::types::processor_local_apic; + return entry.type() == ::acpi::madt_entry::types::processor_local_apic; }) | std::views::transform([](auto const & entry) { - return static_cast(entry); + return static_cast<::acpi::processor_local_apic const &>(entry); }) | std::views::filter([](auto const & entry) { return static_cast(entry.active_flags() & candidate_flags); }); auto bsp_found = false; auto core_count = 0uz; - auto local_apic_address = madt->local_interrupt_controller_address(); + auto local_apic_address = memory::physical_address{madt->local_interrupt_controller_address()}; auto cpu_bus = kstd::make_unique(cpu_major, 0); for (auto const & apic : lapic_entries) -- 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/CMakeLists.txt | 1 - arch/x86_64/kapi/acpi.cpp | 32 ------------------------------- arch/x86_64/src/devices/init.cpp | 41 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 35 deletions(-) delete mode 100644 arch/x86_64/kapi/acpi.cpp (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 62a2aad..f182651 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -12,7 +12,6 @@ target_link_libraries("x86_64" PUBLIC target_sources("x86_64" PRIVATE # Platform-dependent KAPI implementation - "kapi/acpi.cpp" "kapi/boot_modules.cpp" "kapi/cio.cpp" "kapi/cpu.cpp" diff --git a/arch/x86_64/kapi/acpi.cpp b/arch/x86_64/kapi/acpi.cpp deleted file mode 100644 index 40b7160..0000000 --- a/arch/x86_64/kapi/acpi.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "kapi/acpi.hpp" - -#include "arch/boot/boot.hpp" - -#include - -#include - -namespace kapi::acpi -{ - - auto get_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 kapi::acpi \ No newline at end of file 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 3ab0e537368e57dc67b2f7f21aea06ee4001f7a3 Mon Sep 17 00:00:00 2001 From: Marcel Braun Date: Mon, 6 Apr 2026 10:44:46 +0200 Subject: Clean up boot modules --- arch/x86_64/support/grub.cfg.in | 2 -- arch/x86_64/support/modules/test.img | Bin 2097152 -> 0 bytes 2 files changed, 2 deletions(-) delete mode 100644 arch/x86_64/support/modules/test.img (limited to 'arch') diff --git a/arch/x86_64/support/grub.cfg.in b/arch/x86_64/support/grub.cfg.in index 834345a..49f19ce 100644 --- a/arch/x86_64/support/grub.cfg.in +++ b/arch/x86_64/support/grub.cfg.in @@ -3,7 +3,5 @@ default=0 menuentry "TeachOS" { multiboot2 /$ - module2 /modules/test.img bbbbbbb - module2 /modules/test.img aaaa boot } \ No newline at end of file diff --git a/arch/x86_64/support/modules/test.img b/arch/x86_64/support/modules/test.img deleted file mode 100644 index 914fa7f..0000000 Binary files a/arch/x86_64/support/modules/test.img and /dev/null differ -- cgit v1.2.3 From eef84863f56a9453aaf086391a85b8d78d722358 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Wed, 8 Apr 2026 15:26:27 +0200 Subject: add test images --- arch/x86_64/support/grub.cfg.in | 2 ++ arch/x86_64/support/modules/ext2_1KB_fs.img | 3 +++ arch/x86_64/support/modules/ext2_4KB_fs.img | 3 +++ 3 files changed, 8 insertions(+) create mode 100644 arch/x86_64/support/modules/ext2_1KB_fs.img create mode 100644 arch/x86_64/support/modules/ext2_4KB_fs.img (limited to 'arch') diff --git a/arch/x86_64/support/grub.cfg.in b/arch/x86_64/support/grub.cfg.in index 49f19ce..35621f9 100644 --- a/arch/x86_64/support/grub.cfg.in +++ b/arch/x86_64/support/grub.cfg.in @@ -3,5 +3,7 @@ default=0 menuentry "TeachOS" { multiboot2 /$ + module2 /modules/ext2_4KB_fs.img + module2 /modules/ext2_1KB_fs.img boot } \ No newline at end of file diff --git a/arch/x86_64/support/modules/ext2_1KB_fs.img b/arch/x86_64/support/modules/ext2_1KB_fs.img new file mode 100644 index 0000000..9f1ee4a --- /dev/null +++ b/arch/x86_64/support/modules/ext2_1KB_fs.img @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:94d3988bc309eb9e81f06042c72bf4c4fb5991cd7fdd597eb00c518a96c792d8 +size 10485760 diff --git a/arch/x86_64/support/modules/ext2_4KB_fs.img b/arch/x86_64/support/modules/ext2_4KB_fs.img new file mode 100644 index 0000000..3aaceb8 --- /dev/null +++ b/arch/x86_64/support/modules/ext2_4KB_fs.img @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4ce6a1aea277906e1af6de223c017ff900b96569f076b4d99fc04eaa1ee986f4 +size 10485760 -- cgit v1.2.3 From 5865dac062f3291b8081eca39c2835015d2c43c6 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Wed, 8 Apr 2026 15:48:32 +0200 Subject: extend tests with another filesystem --- arch/x86_64/support/grub.cfg.in | 1 + arch/x86_64/support/modules/ext2_2KB_fs.img | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 arch/x86_64/support/modules/ext2_2KB_fs.img (limited to 'arch') diff --git a/arch/x86_64/support/grub.cfg.in b/arch/x86_64/support/grub.cfg.in index 35621f9..45c3356 100644 --- a/arch/x86_64/support/grub.cfg.in +++ b/arch/x86_64/support/grub.cfg.in @@ -5,5 +5,6 @@ menuentry "TeachOS" { multiboot2 /$ module2 /modules/ext2_4KB_fs.img module2 /modules/ext2_1KB_fs.img + module2 /modules/ext2_2KB_fs.img boot } \ No newline at end of file diff --git a/arch/x86_64/support/modules/ext2_2KB_fs.img b/arch/x86_64/support/modules/ext2_2KB_fs.img new file mode 100644 index 0000000..1880911 --- /dev/null +++ b/arch/x86_64/support/modules/ext2_2KB_fs.img @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9a13da5abb9c65c737105b1da0d4344c7cd7604c7952c762c4f4e3d3f96fd42d +size 5242880 -- cgit v1.2.3 From 210d55251dc7143da9e099c6fc6b8d0f465d4153 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Wed, 8 Apr 2026 15:54:33 +0200 Subject: add notes about the content of the test images --- arch/x86_64/support/modules/README.md | 82 +++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 arch/x86_64/support/modules/README.md (limited to 'arch') diff --git a/arch/x86_64/support/modules/README.md b/arch/x86_64/support/modules/README.md new file mode 100644 index 0000000..f3955fa --- /dev/null +++ b/arch/x86_64/support/modules/README.md @@ -0,0 +1,82 @@ +# Default images +The default images contain predefined data and structures that are specifically designed for testing purposes. +The ext2_4KB_fs image is intentionally fragmented, as some files were created and deleted before additional files were added, resulting in a non-contiguous layout. + +## ext2_1KB_fs +. +./lost+found +./information +./information/info_1.txt +./information/info_2.txt +./closed.txt + +## ext2_2KB_fs +. +./lost+found +./monkey_house +./monkey_house/infrastructure +./monkey_house/infrastructure/info.txt +./monkey_house/infrastructure/water.txt +./monkey_house/monkey_1.txt +./monkey_house/monkey_2.txt +./monkey_house/monkey_3.txt +./monkey_house/caretaker +./monkey_house/caretaker/isabelle.txt +./monkey_house/caretaker/peter.txt + +## ext2_4KB_fs +. +./lost+found +./entrance +./entrance/tickets.txt +./entrance/map.txt +./enclosures +./enclosures/lion_house +./enclosures/lion_house/cage_a +./enclosures/lion_house/cage_a/history.txt +./enclosures/lion_house/cage_a/animals.txt +./enclosures/lion_house/cage_b +./enclosures/lion_house/cage_b/animals.txt +./enclosures/lion_house/cage_b/history.txt +./enclosures/elephant_house +./enclosures/elephant_house/elephant_1.txt +./enclosures/aquarium +./enclosures/aquarium/tank_1 +./enclosures/aquarium/tank_1/fish_1.txt +./enclosures/aquarium/tank_1/fish_2.txt +./enclosures/aquarium/tank_1/fish_3.txt +./enclosures/aquarium/tank_1/fish_4.txt +./enclosures/aquarium/tank_2 +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_1.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_2.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_3.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_4.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_5.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_6.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_7.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_8.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_9.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_10.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_11.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_12.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_13.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_14.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_15.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_16.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_17.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_18.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_19.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_20.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_21.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_22.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_23.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_24.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_25.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_26.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_27.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_28.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_29.txt +./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_30.txt +./enclosures/aquarium/spawn_fish.sh +./enclosures/info.txt +./info.txt -- cgit v1.2.3 From 5354654a486296be674ecc7ba5e92ca01cc29107 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Tue, 14 Apr 2026 08:44:41 +0200 Subject: add tests to mount filesystems backed by a file --- arch/x86_64/support/modules/README.md | 26 ++++++++++++++++++++++++++ arch/x86_64/support/modules/ext2_1KB_fs.img | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/support/modules/README.md b/arch/x86_64/support/modules/README.md index f3955fa..fb64767 100644 --- a/arch/x86_64/support/modules/README.md +++ b/arch/x86_64/support/modules/README.md @@ -5,11 +5,37 @@ The ext2_4KB_fs image is intentionally fragmented, as some files were created an ## ext2_1KB_fs . ./lost+found +./archiv +./archiv/2024.img +./archiv/2025.img ./information ./information/info_1.txt ./information/info_2.txt ./closed.txt +### 2024.img +(2KB Block size) +. +./lost+found +./sheep_1.txt +./sheep_2.txt +./stable/pig_1.txt +./stable/pig_2.txt +./stable/pig_3.txt + +### 2025.img +(4KB Block size) +. +./lost+found +./snake_1.txt +./snake_2.txt +./petting_zoo/goat_1.txt +./petting_zoo/goat_2.txt +./petting_zoo/chicken_coop +./petting_zoo/chicken_coop/chicken_1.txt +./petting_zoo/chicken_coop/chicken_2.txt +./petting_zoo/chicken_coop/chicken_3.txt + ## ext2_2KB_fs . ./lost+found diff --git a/arch/x86_64/support/modules/ext2_1KB_fs.img b/arch/x86_64/support/modules/ext2_1KB_fs.img index 9f1ee4a..5bbb76d 100644 --- a/arch/x86_64/support/modules/ext2_1KB_fs.img +++ b/arch/x86_64/support/modules/ext2_1KB_fs.img @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94d3988bc309eb9e81f06042c72bf4c4fb5991cd7fdd597eb00c518a96c792d8 +oid sha256:c2ef9536a439825520d9e230eedaa9ae327f9763350eddbc0f24bf5b9b5d2bf2 size 10485760 -- cgit v1.2.3 From 1fa31688a0e237dec1170dcea9e8f0a0571a25e5 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 15 Apr 2026 08:55:03 +0200 Subject: acpi: add basic MADT tests --- arch/x86_64/kapi/cpu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index a836b20..22936c2 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -60,7 +60,7 @@ namespace kapi::cpu } auto lapic_entries = *madt | std::views::filter([](auto const & entry) { - return entry.type() == ::acpi::madt_entry::types::processor_local_apic; + return entry.type() == ::acpi::madt_entry::type::processor_local_apic; }) | std::views::transform([](auto const & entry) { return static_cast<::acpi::processor_local_apic const &>(entry); }) | std::views::filter([](auto const & entry) { -- cgit v1.2.3 From 776ab2749d5af0a34fd2aa6103a377ddc04d4c53 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 16 Apr 2026 10:03:35 +0200 Subject: acpi: introduce XSDT type --- arch/x86_64/kapi/cpu.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index 22936c2..965998c 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -23,8 +23,8 @@ namespace kapi::cpu namespace { - constexpr auto candidate_flags = ::acpi::processor_local_apic::flags::processor_enabled // - | ::acpi::processor_local_apic::flags::online_capable; + constexpr auto candidate_flags = ::acpi::processor_local_apic_entry::flags::processor_enabled // + | ::acpi::processor_local_apic_entry::flags::online_capable; } auto init() -> void @@ -52,7 +52,7 @@ namespace kapi::cpu auto static const core_major = kapi::devices::allocate_major_number(); auto static const interrupt_controller_major = kapi::devices::allocate_major_number(); - auto madt = kapi::acpi::get_table<::acpi::madt_table_signature>(); + auto madt = kapi::acpi::get_table<::acpi::table_signature_v<::acpi::madt>>(); if (!madt) { kstd::println("[x86_64:PLT] Failed to find ACPI APIC table"); @@ -62,10 +62,8 @@ namespace kapi::cpu auto lapic_entries = *madt | std::views::filter([](auto const & entry) { return entry.type() == ::acpi::madt_entry::type::processor_local_apic; }) | std::views::transform([](auto const & entry) { - return static_cast<::acpi::processor_local_apic const &>(entry); - }) | std::views::filter([](auto const & entry) { - return static_cast(entry.active_flags() & candidate_flags); - }); + return static_cast<::acpi::processor_local_apic_entry const &>(entry); + }) | std::views::filter([](auto const & entry) { return static_cast(entry.flags() & candidate_flags); }); auto bsp_found = false; auto core_count = 0uz; @@ -77,8 +75,8 @@ namespace kapi::cpu auto is_bsp = !bsp_found; bsp_found = true; auto core = kstd::make_unique(core_major, core_count, apic.processor_id(), is_bsp); - core->add_child(kstd::make_unique(interrupt_controller_major, core_count, - apic.apic_id(), local_apic_address, is_bsp)); + core->add_child(kstd::make_unique(interrupt_controller_major, core_count, apic.id(), + local_apic_address, is_bsp)); cpu_bus->add_child(std::move(core)); ++core_count; } -- cgit v1.2.3 From 25d50b311544a21a0d126cf236c23a0912a3eedc Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Sun, 19 Apr 2026 09:39:37 +0200 Subject: improve readme of default modules --- arch/x86_64/support/modules/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/support/modules/README.md b/arch/x86_64/support/modules/README.md index fb64767..a04b9af 100644 --- a/arch/x86_64/support/modules/README.md +++ b/arch/x86_64/support/modules/README.md @@ -14,7 +14,7 @@ The ext2_4KB_fs image is intentionally fragmented, as some files were created an ./closed.txt ### 2024.img -(2KB Block size) +(ext2 filesystem with 2KB Block size) . ./lost+found ./sheep_1.txt @@ -24,7 +24,7 @@ The ext2_4KB_fs image is intentionally fragmented, as some files were created an ./stable/pig_3.txt ### 2025.img -(4KB Block size) +(ext2 filesystem 4KB Block size) . ./lost+found ./snake_1.txt -- cgit v1.2.3 From 9b4cbc6ba3f8059278a20a4893780717851ce8e4 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 21 Apr 2026 13:06:35 +0200 Subject: build: clean up configuration --- arch/x86_64/CMakeLists.txt | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index f182651..9e346ef 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -1,14 +1,9 @@ -add_library("x86_64" OBJECT) -add_library("os::arch" ALIAS "x86_64") - -target_include_directories("x86_64" PUBLIC - "include" -) +#[============================================================================[ +# Library +#]============================================================================] -target_link_libraries("x86_64" PUBLIC - "os::kapi" - "libs::multiboot2" -) +add_library("x86_64" OBJECT) +add_library("arch::lib" ALIAS "x86_64") target_sources("x86_64" PRIVATE # Platform-dependent KAPI implementation @@ -54,7 +49,11 @@ target_sources("x86_64" PRIVATE "src/vga/text/device.cpp" ) -file(GLOB_RECURSE ARCH_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "include/**.hpp") +file(GLOB_RECURSE ARCH_HEADERS + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + CONFIGURE_DEPENDS + "include/**.hpp" +) target_sources("x86_64" PUBLIC FILE_SET HEADERS @@ -62,7 +61,23 @@ target_sources("x86_64" PUBLIC FILES ${ARCH_HEADERS} ) +target_include_directories("x86_64" PUBLIC + "include" +) + +target_link_libraries("x86_64" PUBLIC + "acpi::lib" + "elf::lib" + "kapi::lib" + "kstd::lib" + "multiboot2::lib" +) + set(KERNEL_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/kernel.ld" PARENT_SCOPE ) + +set_target_properties("x86_64" PROPERTIES + VERIFY_INTERFACE_HEADER_SETS YES +) -- 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/include/arch/cpu/global_descriptor_table.hpp | 4 ++-- arch/x86_64/include/arch/cpu/interrupts.hpp | 4 ++-- arch/x86_64/include/arch/cpu/registers.hpp | 4 ++-- arch/x86_64/include/arch/debug/qemu_output.hpp | 4 ++-- arch/x86_64/include/arch/memory/higher_half_mapper.hpp | 4 ++-- arch/x86_64/include/arch/memory/kernel_mapper.hpp | 1 + arch/x86_64/include/arch/vga/text/device.hpp | 4 ++-- arch/x86_64/kapi/boot_modules.cpp | 6 +++--- arch/x86_64/kapi/cpu.cpp | 8 ++++---- arch/x86_64/kapi/memory.cpp | 6 +++--- 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 ++-- 17 files changed, 44 insertions(+), 42 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp b/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp index 402c87d..bc7d328 100644 --- a/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp +++ b/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp @@ -1,10 +1,10 @@ #ifndef TEACHOS_X86_64_GLOBAL_DESCRIPTOR_TABLE_HPP #define TEACHOS_X86_64_GLOBAL_DESCRIPTOR_TABLE_HPP -#include "kapi/memory.hpp" - #include "arch/cpu/segment_descriptor.hpp" +#include "kapi/memory.hpp" + #include #include #include diff --git a/arch/x86_64/include/arch/cpu/interrupts.hpp b/arch/x86_64/include/arch/cpu/interrupts.hpp index b9adb6e..24b72e9 100644 --- a/arch/x86_64/include/arch/cpu/interrupts.hpp +++ b/arch/x86_64/include/arch/cpu/interrupts.hpp @@ -1,10 +1,10 @@ #ifndef TEACHOS_X86_64_CPU_INTERRUPTS_HPP #define TEACHOS_X86_64_CPU_INTERRUPTS_HPP -#include "kapi/memory.hpp" - #include "arch/cpu/segment_selector.hpp" +#include "kapi/memory.hpp" + #include #include #include diff --git a/arch/x86_64/include/arch/cpu/registers.hpp b/arch/x86_64/include/arch/cpu/registers.hpp index d7def10..62206bf 100644 --- a/arch/x86_64/include/arch/cpu/registers.hpp +++ b/arch/x86_64/include/arch/cpu/registers.hpp @@ -1,11 +1,11 @@ #ifndef TEACHOS_X86_64_CPU_REGISTERS_HPP #define TEACHOS_X86_64_CPU_REGISTERS_HPP -#include "kapi/memory.hpp" - #include "arch/cpu/control_register.hpp" // IWYU pragma: export #include "arch/cpu/model_specific_register.hpp" // IWYU pragma: export +#include "kapi/memory.hpp" + namespace arch::cpu { diff --git a/arch/x86_64/include/arch/debug/qemu_output.hpp b/arch/x86_64/include/arch/debug/qemu_output.hpp index e72eb39..f43e147 100644 --- a/arch/x86_64/include/arch/debug/qemu_output.hpp +++ b/arch/x86_64/include/arch/debug/qemu_output.hpp @@ -1,10 +1,10 @@ #ifndef TEACHOS_X86_64_DEBUG_QEMU_OUTPUT_HPP #define TEACHOS_X86_64_DEBUG_QEMU_OUTPUT_HPP -#include "kapi/cio.hpp" - #include "arch/device_io/port_io.hpp" +#include "kapi/cio.hpp" + #include namespace arch::debug diff --git a/arch/x86_64/include/arch/memory/higher_half_mapper.hpp b/arch/x86_64/include/arch/memory/higher_half_mapper.hpp index c8df40c..24bea17 100644 --- a/arch/x86_64/include/arch/memory/higher_half_mapper.hpp +++ b/arch/x86_64/include/arch/memory/higher_half_mapper.hpp @@ -1,10 +1,10 @@ #ifndef TEACHOS_X86_64_HIGHER_HALF_MAPPER_HPP #define TEACHOS_X86_64_HIGHER_HALF_MAPPER_HPP -#include "kapi/memory.hpp" - #include "arch/memory/page_table.hpp" +#include "kapi/memory.hpp" + #include namespace arch::memory diff --git a/arch/x86_64/include/arch/memory/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/kernel_mapper.hpp index 4329f1b..ae593a5 100644 --- a/arch/x86_64/include/arch/memory/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/kernel_mapper.hpp @@ -5,6 +5,7 @@ #include #include + #include #include diff --git a/arch/x86_64/include/arch/vga/text/device.hpp b/arch/x86_64/include/arch/vga/text/device.hpp index 11b3281..d0eb45d 100644 --- a/arch/x86_64/include/arch/vga/text/device.hpp +++ b/arch/x86_64/include/arch/vga/text/device.hpp @@ -3,10 +3,10 @@ // IWYU pragma: private, include "arch/vga/text.hpp" -#include "kapi/cio.hpp" - #include "arch/vga/text/buffer.hpp" +#include "kapi/cio.hpp" + #include namespace arch::vga::text diff --git a/arch/x86_64/kapi/boot_modules.cpp b/arch/x86_64/kapi/boot_modules.cpp index ba01285..1a588cf 100644 --- a/arch/x86_64/kapi/boot_modules.cpp +++ b/arch/x86_64/kapi/boot_modules.cpp @@ -1,14 +1,14 @@ #include "kapi/boot_modules.hpp" +#include "arch/boot/boot.hpp" +#include "arch/boot/ld.hpp" + #include "kapi/boot.hpp" #include "kapi/boot_module/boot_module.hpp" #include "kapi/boot_module/boot_module_registry.hpp" #include "kapi/memory.hpp" #include "kapi/system.hpp" -#include "arch/boot/boot.hpp" -#include "arch/boot/ld.hpp" - #include #include diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index 965998c..baeab4b 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -1,19 +1,19 @@ #include "kapi/cpu.hpp" +#include "arch/cpu/initialization.hpp" +#include "arch/devices/local_apic.hpp" + #include "kapi/acpi.hpp" #include "kapi/devices.hpp" #include "kapi/devices/cpu.hpp" #include "kapi/memory.hpp" #include "kapi/system.hpp" -#include "arch/cpu/initialization.hpp" -#include "arch/devices/local_apic.hpp" +#include #include #include -#include - #include #include #include diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index 5f12e5c..423913d 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -1,8 +1,5 @@ #include "kapi/memory.hpp" -#include "kapi/boot.hpp" -#include "kapi/system.hpp" - #include "arch/boot/boot.hpp" #include "arch/boot/ld.hpp" #include "arch/cpu/registers.hpp" @@ -12,6 +9,9 @@ #include "arch/memory/page_utilities.hpp" #include "arch/memory/region_allocator.hpp" +#include "kapi/boot.hpp" +#include "kapi/system.hpp" + #include #include 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/include/arch/boot/boot.hpp | 2 +- arch/x86_64/include/arch/bus/isa.hpp | 2 +- arch/x86_64/include/arch/cpu/control_register.hpp | 4 ++-- .../include/arch/cpu/global_descriptor_table.hpp | 4 ++-- arch/x86_64/include/arch/cpu/interrupts.hpp | 4 ++-- arch/x86_64/include/arch/cpu/legacy_pic.hpp | 2 +- .../include/arch/cpu/model_specific_register.hpp | 2 +- arch/x86_64/include/arch/cpu/registers.hpp | 6 ++--- arch/x86_64/include/arch/debug/qemu_output.hpp | 4 ++-- arch/x86_64/include/arch/devices/legacy_pit.hpp | 4 ++-- arch/x86_64/include/arch/devices/local_apic.hpp | 4 ++-- .../include/arch/memory/higher_half_mapper.hpp | 4 ++-- arch/x86_64/include/arch/memory/kernel_mapper.hpp | 2 +- arch/x86_64/include/arch/memory/mmu.hpp | 2 +- arch/x86_64/include/arch/memory/page_table.hpp | 2 +- arch/x86_64/include/arch/memory/page_utilities.hpp | 2 +- .../include/arch/memory/region_allocator.hpp | 6 ++--- arch/x86_64/include/arch/vga/crtc.hpp | 2 +- arch/x86_64/include/arch/vga/text.hpp | 10 ++++----- arch/x86_64/include/arch/vga/text/attribute.hpp | 6 ++--- arch/x86_64/include/arch/vga/text/buffer.hpp | 4 ++-- arch/x86_64/include/arch/vga/text/color.hpp | 2 +- .../include/arch/vga/text/common_attributes.hpp | 8 +++---- arch/x86_64/include/arch/vga/text/device.hpp | 6 ++--- arch/x86_64/include/arch/vga/text/flags.hpp | 2 +- arch/x86_64/kapi/boot_modules.cpp | 16 ++++++------- arch/x86_64/kapi/cio.cpp | 6 ++--- arch/x86_64/kapi/cpu.cpp | 16 ++++++------- arch/x86_64/kapi/devices.cpp | 4 ++-- arch/x86_64/kapi/interrupts.cpp | 2 +- arch/x86_64/kapi/memory.cpp | 26 +++++++++++----------- arch/x86_64/kapi/system.cpp | 2 +- .../pre/include/arch/context_switching/main.hpp | 4 ++-- arch/x86_64/pre/src/context_switching/main.cpp | 16 ++++++------- .../pre/src/context_switching/syscall/main.cpp | 2 +- .../context_switching/syscall/syscall_enable.cpp | 8 +++---- .../context_switching/syscall/syscall_handler.cpp | 14 ++++++------ arch/x86_64/pre/src/kernel/main.cpp | 24 ++++++++++---------- arch/x86_64/pre/src/user/main.cpp | 6 ++--- 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 ++++----- 54 files changed, 177 insertions(+), 177 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/include/arch/boot/boot.hpp b/arch/x86_64/include/arch/boot/boot.hpp index 3a598f5..7df61c4 100644 --- a/arch/x86_64/include/arch/boot/boot.hpp +++ b/arch/x86_64/include/arch/boot/boot.hpp @@ -31,7 +31,7 @@ // clang-format on #else -#include "kapi/boot.hpp" // IWYU pragma: export +#include // IWYU pragma: export #include diff --git a/arch/x86_64/include/arch/bus/isa.hpp b/arch/x86_64/include/arch/bus/isa.hpp index 5deed25..e56f56a 100644 --- a/arch/x86_64/include/arch/bus/isa.hpp +++ b/arch/x86_64/include/arch/bus/isa.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_BUS_ISA_HPP #define TEACHOS_X86_64_BUS_ISA_HPP -#include "kapi/devices/bus.hpp" +#include #include diff --git a/arch/x86_64/include/arch/cpu/control_register.hpp b/arch/x86_64/include/arch/cpu/control_register.hpp index fafbfc7..9cedc35 100644 --- a/arch/x86_64/include/arch/cpu/control_register.hpp +++ b/arch/x86_64/include/arch/cpu/control_register.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_X86_64_CPU_CONTROL_REGISTERS_HPP #define TEACHOS_X86_64_CPU_CONTROL_REGISTERS_HPP -// IWYU pragma: private, include "arch/cpu/registers.hpp" +// IWYU pragma: private, include -#include "kapi/memory.hpp" +#include #include diff --git a/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp b/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp index bc7d328..b17c509 100644 --- a/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp +++ b/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_X86_64_GLOBAL_DESCRIPTOR_TABLE_HPP #define TEACHOS_X86_64_GLOBAL_DESCRIPTOR_TABLE_HPP -#include "arch/cpu/segment_descriptor.hpp" +#include -#include "kapi/memory.hpp" +#include #include #include diff --git a/arch/x86_64/include/arch/cpu/interrupts.hpp b/arch/x86_64/include/arch/cpu/interrupts.hpp index 24b72e9..6162f56 100644 --- a/arch/x86_64/include/arch/cpu/interrupts.hpp +++ b/arch/x86_64/include/arch/cpu/interrupts.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_X86_64_CPU_INTERRUPTS_HPP #define TEACHOS_X86_64_CPU_INTERRUPTS_HPP -#include "arch/cpu/segment_selector.hpp" +#include -#include "kapi/memory.hpp" +#include #include #include diff --git a/arch/x86_64/include/arch/cpu/legacy_pic.hpp b/arch/x86_64/include/arch/cpu/legacy_pic.hpp index 9f53d86..56ca9c4 100644 --- a/arch/x86_64/include/arch/cpu/legacy_pic.hpp +++ b/arch/x86_64/include/arch/cpu/legacy_pic.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_CPU_LEGACY_PIC_HPP #define TEACHOS_X86_64_CPU_LEGACY_PIC_HPP -#include "arch/device_io/port_io.hpp" +#include #include diff --git a/arch/x86_64/include/arch/cpu/model_specific_register.hpp b/arch/x86_64/include/arch/cpu/model_specific_register.hpp index 8539a24..bd4aff9 100644 --- a/arch/x86_64/include/arch/cpu/model_specific_register.hpp +++ b/arch/x86_64/include/arch/cpu/model_specific_register.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_CPU_MODEL_SPECIFIC_REGISTER_HPP #define TEACHOS_X86_64_CPU_MODEL_SPECIFIC_REGISTER_HPP -// IWYU pragma: private, include "x86_64/cpu/registers.hpp" +// IWYU pragma: private, include #include diff --git a/arch/x86_64/include/arch/cpu/registers.hpp b/arch/x86_64/include/arch/cpu/registers.hpp index 62206bf..58633f6 100644 --- a/arch/x86_64/include/arch/cpu/registers.hpp +++ b/arch/x86_64/include/arch/cpu/registers.hpp @@ -1,10 +1,10 @@ #ifndef TEACHOS_X86_64_CPU_REGISTERS_HPP #define TEACHOS_X86_64_CPU_REGISTERS_HPP -#include "arch/cpu/control_register.hpp" // IWYU pragma: export -#include "arch/cpu/model_specific_register.hpp" // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export -#include "kapi/memory.hpp" +#include namespace arch::cpu { diff --git a/arch/x86_64/include/arch/debug/qemu_output.hpp b/arch/x86_64/include/arch/debug/qemu_output.hpp index f43e147..5ddd4be 100644 --- a/arch/x86_64/include/arch/debug/qemu_output.hpp +++ b/arch/x86_64/include/arch/debug/qemu_output.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_X86_64_DEBUG_QEMU_OUTPUT_HPP #define TEACHOS_X86_64_DEBUG_QEMU_OUTPUT_HPP -#include "arch/device_io/port_io.hpp" +#include -#include "kapi/cio.hpp" +#include #include diff --git a/arch/x86_64/include/arch/devices/legacy_pit.hpp b/arch/x86_64/include/arch/devices/legacy_pit.hpp index de742ae..356895c 100644 --- a/arch/x86_64/include/arch/devices/legacy_pit.hpp +++ b/arch/x86_64/include/arch/devices/legacy_pit.hpp @@ -1,8 +1,8 @@ #ifndef TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP #define TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP -#include "kapi/devices/device.hpp" -#include "kapi/interrupts.hpp" +#include +#include #include #include diff --git a/arch/x86_64/include/arch/devices/local_apic.hpp b/arch/x86_64/include/arch/devices/local_apic.hpp index ee1073f..f8f080d 100644 --- a/arch/x86_64/include/arch/devices/local_apic.hpp +++ b/arch/x86_64/include/arch/devices/local_apic.hpp @@ -1,8 +1,8 @@ #ifndef TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP #define TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP -#include "kapi/devices/device.hpp" -#include "kapi/memory.hpp" +#include +#include #include #include diff --git a/arch/x86_64/include/arch/memory/higher_half_mapper.hpp b/arch/x86_64/include/arch/memory/higher_half_mapper.hpp index 24bea17..9b02ee6 100644 --- a/arch/x86_64/include/arch/memory/higher_half_mapper.hpp +++ b/arch/x86_64/include/arch/memory/higher_half_mapper.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_X86_64_HIGHER_HALF_MAPPER_HPP #define TEACHOS_X86_64_HIGHER_HALF_MAPPER_HPP -#include "arch/memory/page_table.hpp" +#include -#include "kapi/memory.hpp" +#include #include diff --git a/arch/x86_64/include/arch/memory/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/kernel_mapper.hpp index ae593a5..adbf688 100644 --- a/arch/x86_64/include/arch/memory/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/kernel_mapper.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_KERNEL_MAPPER_HPP #define TEACHOS_X86_64_KERNEL_MAPPER_HPP -#include "kapi/memory.hpp" +#include #include #include diff --git a/arch/x86_64/include/arch/memory/mmu.hpp b/arch/x86_64/include/arch/memory/mmu.hpp index 2d64184..64373f4 100644 --- a/arch/x86_64/include/arch/memory/mmu.hpp +++ b/arch/x86_64/include/arch/memory/mmu.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_MEMORY_MMU_HPP #define TEACHOS_X86_64_MEMORY_MMU_HPP -#include "kapi/memory/address.hpp" +#include namespace arch::memory { diff --git a/arch/x86_64/include/arch/memory/page_table.hpp b/arch/x86_64/include/arch/memory/page_table.hpp index c75ccaf..ce3d3a1 100644 --- a/arch/x86_64/include/arch/memory/page_table.hpp +++ b/arch/x86_64/include/arch/memory/page_table.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_PAGE_TABLE_HPP #define TEACHOS_X86_64_PAGE_TABLE_HPP -#include "kapi/memory.hpp" +#include #include #include diff --git a/arch/x86_64/include/arch/memory/page_utilities.hpp b/arch/x86_64/include/arch/memory/page_utilities.hpp index c48e74f..068e824 100644 --- a/arch/x86_64/include/arch/memory/page_utilities.hpp +++ b/arch/x86_64/include/arch/memory/page_utilities.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_PAGE_UTILITIES_HPP #define TEACHOS_X86_64_PAGE_UTILITIES_HPP -#include "kapi/memory.hpp" +#include #include diff --git a/arch/x86_64/include/arch/memory/region_allocator.hpp b/arch/x86_64/include/arch/memory/region_allocator.hpp index c7a836f..5d9da2e 100644 --- a/arch/x86_64/include/arch/memory/region_allocator.hpp +++ b/arch/x86_64/include/arch/memory/region_allocator.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP #define TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP -#include "kapi/memory/address.hpp" -#include "kapi/memory/frame.hpp" -#include "kapi/memory/frame_allocator.hpp" +#include +#include +#include #include diff --git a/arch/x86_64/include/arch/vga/crtc.hpp b/arch/x86_64/include/arch/vga/crtc.hpp index dbdc365..a8bec93 100644 --- a/arch/x86_64/include/arch/vga/crtc.hpp +++ b/arch/x86_64/include/arch/vga/crtc.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_VGA_IO_HPP #define TEACHOS_X86_64_VGA_IO_HPP -#include "arch/device_io/port_io.hpp" +#include #include diff --git a/arch/x86_64/include/arch/vga/text.hpp b/arch/x86_64/include/arch/vga/text.hpp index f81ab60..2e73dd2 100644 --- a/arch/x86_64/include/arch/vga/text.hpp +++ b/arch/x86_64/include/arch/vga/text.hpp @@ -1,10 +1,10 @@ #ifndef TEACHOS_X86_64_VGA_TEXT_HPP #define TEACHOS_X86_64_VGA_TEXT_HPP -#include "text/attribute.hpp" // IWYU pragma: export -#include "text/color.hpp" // IWYU pragma: export -#include "text/common_attributes.hpp" // IWYU pragma: export -#include "text/device.hpp" // IWYU pragma: export -#include "text/flags.hpp" // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export #endif // TEACHOS_ARCH_X86_64_VIDEO_VGA_TEXT_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/vga/text/attribute.hpp b/arch/x86_64/include/arch/vga/text/attribute.hpp index 6a0f995..6395aed 100644 --- a/arch/x86_64/include/arch/vga/text/attribute.hpp +++ b/arch/x86_64/include/arch/vga/text/attribute.hpp @@ -1,10 +1,10 @@ #ifndef TEACHOS_X86_64_VGA_TEXT_ATTRIBUTE_HPP #define TEACHOS_X86_64_VGA_TEXT_ATTRIBUTE_HPP -// IWYU pragma: private, include "arch/vga/text.hpp" +// IWYU pragma: private, include -#include "arch/vga/text/color.hpp" -#include "arch/vga/text/flags.hpp" +#include +#include namespace arch::vga::text { diff --git a/arch/x86_64/include/arch/vga/text/buffer.hpp b/arch/x86_64/include/arch/vga/text/buffer.hpp index 648d37a..8eb6645 100644 --- a/arch/x86_64/include/arch/vga/text/buffer.hpp +++ b/arch/x86_64/include/arch/vga/text/buffer.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_X86_64_VGA_TEXT_BUFFER_HPP #define TEACHOS_X86_64_VGA_TEXT_BUFFER_HPP -// IWYU pragma: private, include "arch/vga/text.hpp" +// IWYU pragma: private, include -#include "arch/vga/text/attribute.hpp" +#include #include #include diff --git a/arch/x86_64/include/arch/vga/text/color.hpp b/arch/x86_64/include/arch/vga/text/color.hpp index a541830..e0ad6df 100644 --- a/arch/x86_64/include/arch/vga/text/color.hpp +++ b/arch/x86_64/include/arch/vga/text/color.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_VGA_TEXT_COLOR_HPP #define TEACHOS_X86_64_VGA_TEXT_COLOR_HPP -// IWYU pragma: private, include "arch/vga/text.hpp" +// IWYU pragma: private, include #include diff --git a/arch/x86_64/include/arch/vga/text/common_attributes.hpp b/arch/x86_64/include/arch/vga/text/common_attributes.hpp index 9bd61a5..3d8929f 100644 --- a/arch/x86_64/include/arch/vga/text/common_attributes.hpp +++ b/arch/x86_64/include/arch/vga/text/common_attributes.hpp @@ -1,11 +1,11 @@ #ifndef TEACHOS_X86_64_VGA_TEXT_COMMON_ATTRIBUTES_HPP #define TEACHOS_X86_64_VGA_TEXT_COMMON_ATTRIBUTES_HPP -// IWYU pragma: private, include "arch/vga/text.hpp" +// IWYU pragma: private, include -#include "arch/vga/text/attribute.hpp" -#include "arch/vga/text/color.hpp" -#include "arch/vga/text/flags.hpp" +#include +#include +#include namespace arch::vga::text { diff --git a/arch/x86_64/include/arch/vga/text/device.hpp b/arch/x86_64/include/arch/vga/text/device.hpp index d0eb45d..0a0e017 100644 --- a/arch/x86_64/include/arch/vga/text/device.hpp +++ b/arch/x86_64/include/arch/vga/text/device.hpp @@ -1,11 +1,11 @@ #ifndef TEACHOS_X86_64_VGA_TEXT_DEVICE_HPP #define TEACHOS_X86_64_VGA_TEXT_DEVICE_HPP -// IWYU pragma: private, include "arch/vga/text.hpp" +// IWYU pragma: private, include -#include "arch/vga/text/buffer.hpp" +#include -#include "kapi/cio.hpp" +#include #include diff --git a/arch/x86_64/include/arch/vga/text/flags.hpp b/arch/x86_64/include/arch/vga/text/flags.hpp index 67c6c11..7a29e33 100644 --- a/arch/x86_64/include/arch/vga/text/flags.hpp +++ b/arch/x86_64/include/arch/vga/text/flags.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_X86_64_VGA_TEXT_FLAGS_HPP #define TEACHOS_X86_64_VGA_TEXT_FLAGS_HPP -// IWYU pragma: private, include "arch/vga/text.hpp" +// IWYU pragma: private, include namespace arch::vga::text { diff --git a/arch/x86_64/kapi/boot_modules.cpp b/arch/x86_64/kapi/boot_modules.cpp index 1a588cf..fb6bf46 100644 --- a/arch/x86_64/kapi/boot_modules.cpp +++ b/arch/x86_64/kapi/boot_modules.cpp @@ -1,13 +1,13 @@ -#include "kapi/boot_modules.hpp" +#include -#include "arch/boot/boot.hpp" -#include "arch/boot/ld.hpp" +#include +#include -#include "kapi/boot.hpp" -#include "kapi/boot_module/boot_module.hpp" -#include "kapi/boot_module/boot_module_registry.hpp" -#include "kapi/memory.hpp" -#include "kapi/system.hpp" +#include +#include +#include +#include +#include #include diff --git a/arch/x86_64/kapi/cio.cpp b/arch/x86_64/kapi/cio.cpp index 015cf5e..b33c6e0 100644 --- a/arch/x86_64/kapi/cio.cpp +++ b/arch/x86_64/kapi/cio.cpp @@ -1,7 +1,7 @@ -#include "kapi/cio.hpp" +#include -#include "arch/debug/qemu_output.hpp" -#include "arch/vga/text.hpp" +#include +#include #include diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index baeab4b..40dc228 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -1,13 +1,13 @@ -#include "kapi/cpu.hpp" +#include -#include "arch/cpu/initialization.hpp" -#include "arch/devices/local_apic.hpp" +#include +#include -#include "kapi/acpi.hpp" -#include "kapi/devices.hpp" -#include "kapi/devices/cpu.hpp" -#include "kapi/memory.hpp" -#include "kapi/system.hpp" +#include +#include +#include +#include +#include #include diff --git a/arch/x86_64/kapi/devices.cpp b/arch/x86_64/kapi/devices.cpp index 47c7f8c..f188c92 100644 --- a/arch/x86_64/kapi/devices.cpp +++ b/arch/x86_64/kapi/devices.cpp @@ -1,6 +1,6 @@ -#include "kapi/devices.hpp" +#include -#include "arch/devices/init.hpp" +#include namespace kapi::devices { diff --git a/arch/x86_64/kapi/interrupts.cpp b/arch/x86_64/kapi/interrupts.cpp index cf1defa..85acc0f 100644 --- a/arch/x86_64/kapi/interrupts.cpp +++ b/arch/x86_64/kapi/interrupts.cpp @@ -1,4 +1,4 @@ -#include "kapi/interrupts.hpp" +#include namespace kapi::interrupts { diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index 423913d..5b870d5 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -1,16 +1,16 @@ -#include "kapi/memory.hpp" - -#include "arch/boot/boot.hpp" -#include "arch/boot/ld.hpp" -#include "arch/cpu/registers.hpp" -#include "arch/memory/higher_half_mapper.hpp" -#include "arch/memory/kernel_mapper.hpp" -#include "arch/memory/page_table.hpp" -#include "arch/memory/page_utilities.hpp" -#include "arch/memory/region_allocator.hpp" - -#include "kapi/boot.hpp" -#include "kapi/system.hpp" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include #include #include diff --git a/arch/x86_64/kapi/system.cpp b/arch/x86_64/kapi/system.cpp index 09c7152..73a77e5 100644 --- a/arch/x86_64/kapi/system.cpp +++ b/arch/x86_64/kapi/system.cpp @@ -1,4 +1,4 @@ -#include "kapi/system.hpp" +#include namespace kapi::system { diff --git a/arch/x86_64/pre/include/arch/context_switching/main.hpp b/arch/x86_64/pre/include/arch/context_switching/main.hpp index f8477ea..07e00e8 100644 --- a/arch/x86_64/pre/include/arch/context_switching/main.hpp +++ b/arch/x86_64/pre/include/arch/context_switching/main.hpp @@ -1,8 +1,8 @@ #ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP #define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP -#include "arch/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.hpp" -#include "arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp" +#include +#include namespace teachos::arch::context_switching { diff --git a/arch/x86_64/pre/src/context_switching/main.cpp b/arch/x86_64/pre/src/context_switching/main.cpp index 3eb6dae..0961499 100644 --- a/arch/x86_64/pre/src/context_switching/main.cpp +++ b/arch/x86_64/pre/src/context_switching/main.cpp @@ -1,12 +1,12 @@ -#include "arch/context_switching/main.hpp" +#include -#include "arch/boot/pointers.hpp" -#include "arch/context_switching/syscall/syscall_enable.hpp" -#include "arch/kernel/cpu/call.hpp" -#include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/segment_register.hpp" -#include "arch/kernel/cpu/tr.hpp" -#include "arch/user/main.hpp" +#include +#include +#include +#include +#include +#include +#include namespace teachos::arch::context_switching { diff --git a/arch/x86_64/pre/src/context_switching/syscall/main.cpp b/arch/x86_64/pre/src/context_switching/syscall/main.cpp index b4ab468..10bd087 100644 --- a/arch/x86_64/pre/src/context_switching/syscall/main.cpp +++ b/arch/x86_64/pre/src/context_switching/syscall/main.cpp @@ -1,4 +1,4 @@ -#include "arch/context_switching/syscall/main.hpp" +#include namespace teachos::arch::context_switching::syscall { diff --git a/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp b/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp index dbb3ed9..f9f070a 100644 --- a/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp +++ b/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp @@ -1,8 +1,8 @@ -#include "arch/context_switching/syscall/syscall_enable.hpp" +#include -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" -#include "arch/context_switching/syscall/syscall_handler.hpp" -#include "arch/kernel/cpu/msr.hpp" +#include +#include +#include namespace teachos::arch::context_switching::syscall { diff --git a/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp index c120f77..430d65c 100644 --- a/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp +++ b/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp @@ -1,11 +1,11 @@ -#include "arch/context_switching/syscall/syscall_handler.hpp" +#include -#include "arch/context_switching/syscall/main.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/exception_handling/panic.hpp" -#include "arch/memory/heap/global_heap_allocator.hpp" -#include "arch/memory/main.hpp" -#include "arch/video/vga/text.hpp" +#include +#include +#include +#include +#include +#include namespace teachos::arch::context_switching::syscall { diff --git a/arch/x86_64/pre/src/kernel/main.cpp b/arch/x86_64/pre/src/kernel/main.cpp index 43b5f90..2658678 100644 --- a/arch/x86_64/pre/src/kernel/main.cpp +++ b/arch/x86_64/pre/src/kernel/main.cpp @@ -1,16 +1,16 @@ -#include "arch/kernel/main.hpp" +#include -#include "arch/boot/pointers.hpp" -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" -#include "arch/context_switching/main.hpp" -#include "arch/kernel/cpu/if.hpp" -#include "arch/kernel/cpu/segment_register.hpp" -#include "arch/memory/heap/bump_allocator.hpp" -#include "arch/memory/heap/global_heap_allocator.hpp" -#include "arch/memory/main.hpp" -#include "arch/memory/multiboot/reader.hpp" -#include "arch/stl/vector.hpp" -#include "arch/video/vga/text.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace teachos::arch::kernel { diff --git a/arch/x86_64/pre/src/user/main.cpp b/arch/x86_64/pre/src/user/main.cpp index 8b07e4a..10a17db 100644 --- a/arch/x86_64/pre/src/user/main.cpp +++ b/arch/x86_64/pre/src/user/main.cpp @@ -1,7 +1,7 @@ -#include "arch/user/main.hpp" +#include -#include "arch/context_switching/syscall/main.hpp" -#include "arch/memory/heap/global_heap_allocator.hpp" +#include +#include #include #include 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/CMakeLists.txt | 50 ++- arch/x86_64/arch/boot/boot.hpp | 56 +++ arch/x86_64/arch/boot/boot32.S | 443 +++++++++++++++++++++ arch/x86_64/arch/boot/entry64.s | 62 +++ arch/x86_64/arch/boot/initialize_runtime.cpp | 22 + arch/x86_64/arch/boot/ld.hpp | 61 +++ arch/x86_64/arch/boot/multiboot.s | 33 ++ arch/x86_64/arch/bus/isa.cpp | 14 + arch/x86_64/arch/bus/isa.hpp | 18 + arch/x86_64/arch/cpu/control_register.hpp | 249 ++++++++++++ arch/x86_64/arch/cpu/global_descriptor_table.hpp | 91 +++++ arch/x86_64/arch/cpu/initialization.cpp | 164 ++++++++ arch/x86_64/arch/cpu/initialization.hpp | 12 + arch/x86_64/arch/cpu/interrupts.S | 112 ++++++ arch/x86_64/arch/cpu/interrupts.cpp | 203 ++++++++++ arch/x86_64/arch/cpu/interrupts.hpp | 116 ++++++ arch/x86_64/arch/cpu/legacy_pic.hpp | 19 + arch/x86_64/arch/cpu/model_specific_register.hpp | 151 +++++++ arch/x86_64/arch/cpu/registers.hpp | 32 ++ arch/x86_64/arch/cpu/segment_descriptor.hpp | 61 +++ arch/x86_64/arch/cpu/segment_selector.hpp | 21 + arch/x86_64/arch/cpu/task_state_segment.hpp | 30 ++ arch/x86_64/arch/debug/qemu_output.cpp | 25 ++ arch/x86_64/arch/debug/qemu_output.hpp | 43 ++ arch/x86_64/arch/device_io/port_io.hpp | 112 ++++++ arch/x86_64/arch/devices/init.cpp | 76 ++++ arch/x86_64/arch/devices/init.hpp | 12 + arch/x86_64/arch/devices/legacy_pit.cpp | 60 +++ arch/x86_64/arch/devices/legacy_pit.hpp | 29 ++ arch/x86_64/arch/devices/local_apic.cpp | 134 +++++++ arch/x86_64/arch/devices/local_apic.hpp | 37 ++ arch/x86_64/arch/memory/higher_half_mapper.cpp | 119 ++++++ arch/x86_64/arch/memory/higher_half_mapper.hpp | 44 ++ arch/x86_64/arch/memory/kernel_mapper.cpp | 117 ++++++ arch/x86_64/arch/memory/kernel_mapper.hpp | 35 ++ arch/x86_64/arch/memory/mmu.cpp | 19 + arch/x86_64/arch/memory/mmu.hpp | 27 ++ arch/x86_64/arch/memory/page_table.cpp | 82 ++++ arch/x86_64/arch/memory/page_table.hpp | 232 +++++++++++ arch/x86_64/arch/memory/page_utilities.hpp | 29 ++ arch/x86_64/arch/memory/region_allocator.cpp | 165 ++++++++ arch/x86_64/arch/memory/region_allocator.hpp | 93 +++++ arch/x86_64/arch/vga/crtc.hpp | 35 ++ arch/x86_64/arch/vga/text.hpp | 10 + arch/x86_64/arch/vga/text/attribute.hpp | 30 ++ arch/x86_64/arch/vga/text/buffer.cpp | 101 +++++ arch/x86_64/arch/vga/text/buffer.hpp | 101 +++++ arch/x86_64/arch/vga/text/color.hpp | 35 ++ arch/x86_64/arch/vga/text/common_attributes.hpp | 37 ++ arch/x86_64/arch/vga/text/device.cpp | 60 +++ arch/x86_64/arch/vga/text/device.hpp | 45 +++ arch/x86_64/arch/vga/text/flags.hpp | 38 ++ arch/x86_64/include/arch/boot/boot.hpp | 56 --- arch/x86_64/include/arch/boot/ld.hpp | 61 --- arch/x86_64/include/arch/bus/isa.hpp | 18 - arch/x86_64/include/arch/cpu/control_register.hpp | 249 ------------ .../include/arch/cpu/global_descriptor_table.hpp | 91 ----- arch/x86_64/include/arch/cpu/initialization.hpp | 12 - arch/x86_64/include/arch/cpu/interrupts.hpp | 116 ------ arch/x86_64/include/arch/cpu/legacy_pic.hpp | 19 - .../include/arch/cpu/model_specific_register.hpp | 151 ------- arch/x86_64/include/arch/cpu/registers.hpp | 32 -- .../x86_64/include/arch/cpu/segment_descriptor.hpp | 61 --- arch/x86_64/include/arch/cpu/segment_selector.hpp | 21 - .../x86_64/include/arch/cpu/task_state_segment.hpp | 30 -- arch/x86_64/include/arch/debug/qemu_output.hpp | 43 -- arch/x86_64/include/arch/device_io/port_io.hpp | 112 ------ arch/x86_64/include/arch/devices/init.hpp | 12 - arch/x86_64/include/arch/devices/legacy_pit.hpp | 29 -- arch/x86_64/include/arch/devices/local_apic.hpp | 37 -- .../include/arch/memory/higher_half_mapper.hpp | 44 -- arch/x86_64/include/arch/memory/kernel_mapper.hpp | 35 -- arch/x86_64/include/arch/memory/mmu.hpp | 27 -- arch/x86_64/include/arch/memory/page_table.hpp | 232 ----------- arch/x86_64/include/arch/memory/page_utilities.hpp | 29 -- .../include/arch/memory/region_allocator.hpp | 93 ----- arch/x86_64/include/arch/vga/crtc.hpp | 35 -- arch/x86_64/include/arch/vga/text.hpp | 10 - arch/x86_64/include/arch/vga/text/attribute.hpp | 30 -- arch/x86_64/include/arch/vga/text/buffer.hpp | 101 ----- arch/x86_64/include/arch/vga/text/color.hpp | 35 -- .../include/arch/vga/text/common_attributes.hpp | 37 -- arch/x86_64/include/arch/vga/text/device.hpp | 45 --- arch/x86_64/include/arch/vga/text/flags.hpp | 38 -- .../pre/include/arch/context_switching/main.hpp | 51 --- .../arch/context_switching/syscall/main.hpp | 91 ----- .../context_switching/syscall/syscall_enable.hpp | 18 - .../context_switching/syscall/syscall_handler.hpp | 18 - arch/x86_64/pre/include/arch/kernel/halt.hpp | 13 - arch/x86_64/pre/include/arch/kernel/main.hpp | 13 - arch/x86_64/pre/include/arch/user/main.hpp | 16 - arch/x86_64/pre/src/context_switching/main.cpp | 66 --- .../pre/src/context_switching/syscall/main.cpp | 35 -- .../context_switching/syscall/syscall_enable.cpp | 32 -- .../context_switching/syscall/syscall_handler.cpp | 121 ------ arch/x86_64/pre/src/kernel/main.cpp | 71 ---- arch/x86_64/pre/src/user/main.cpp | 35 -- 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 --- 116 files changed, 3982 insertions(+), 4552 deletions(-) create mode 100644 arch/x86_64/arch/boot/boot.hpp create mode 100644 arch/x86_64/arch/boot/boot32.S create mode 100644 arch/x86_64/arch/boot/entry64.s create mode 100644 arch/x86_64/arch/boot/initialize_runtime.cpp create mode 100644 arch/x86_64/arch/boot/ld.hpp create mode 100644 arch/x86_64/arch/boot/multiboot.s create mode 100644 arch/x86_64/arch/bus/isa.cpp create mode 100644 arch/x86_64/arch/bus/isa.hpp create mode 100644 arch/x86_64/arch/cpu/control_register.hpp create mode 100644 arch/x86_64/arch/cpu/global_descriptor_table.hpp create mode 100644 arch/x86_64/arch/cpu/initialization.cpp create mode 100644 arch/x86_64/arch/cpu/initialization.hpp create mode 100644 arch/x86_64/arch/cpu/interrupts.S create mode 100644 arch/x86_64/arch/cpu/interrupts.cpp create mode 100644 arch/x86_64/arch/cpu/interrupts.hpp create mode 100644 arch/x86_64/arch/cpu/legacy_pic.hpp create mode 100644 arch/x86_64/arch/cpu/model_specific_register.hpp create mode 100644 arch/x86_64/arch/cpu/registers.hpp create mode 100644 arch/x86_64/arch/cpu/segment_descriptor.hpp create mode 100644 arch/x86_64/arch/cpu/segment_selector.hpp create mode 100644 arch/x86_64/arch/cpu/task_state_segment.hpp create mode 100644 arch/x86_64/arch/debug/qemu_output.cpp create mode 100644 arch/x86_64/arch/debug/qemu_output.hpp create mode 100644 arch/x86_64/arch/device_io/port_io.hpp create mode 100644 arch/x86_64/arch/devices/init.cpp create mode 100644 arch/x86_64/arch/devices/init.hpp create mode 100644 arch/x86_64/arch/devices/legacy_pit.cpp create mode 100644 arch/x86_64/arch/devices/legacy_pit.hpp create mode 100644 arch/x86_64/arch/devices/local_apic.cpp create mode 100644 arch/x86_64/arch/devices/local_apic.hpp create mode 100644 arch/x86_64/arch/memory/higher_half_mapper.cpp create mode 100644 arch/x86_64/arch/memory/higher_half_mapper.hpp create mode 100644 arch/x86_64/arch/memory/kernel_mapper.cpp create mode 100644 arch/x86_64/arch/memory/kernel_mapper.hpp create mode 100644 arch/x86_64/arch/memory/mmu.cpp create mode 100644 arch/x86_64/arch/memory/mmu.hpp create mode 100644 arch/x86_64/arch/memory/page_table.cpp create mode 100644 arch/x86_64/arch/memory/page_table.hpp create mode 100644 arch/x86_64/arch/memory/page_utilities.hpp create mode 100644 arch/x86_64/arch/memory/region_allocator.cpp create mode 100644 arch/x86_64/arch/memory/region_allocator.hpp create mode 100644 arch/x86_64/arch/vga/crtc.hpp create mode 100644 arch/x86_64/arch/vga/text.hpp create mode 100644 arch/x86_64/arch/vga/text/attribute.hpp create mode 100644 arch/x86_64/arch/vga/text/buffer.cpp create mode 100644 arch/x86_64/arch/vga/text/buffer.hpp create mode 100644 arch/x86_64/arch/vga/text/color.hpp create mode 100644 arch/x86_64/arch/vga/text/common_attributes.hpp create mode 100644 arch/x86_64/arch/vga/text/device.cpp create mode 100644 arch/x86_64/arch/vga/text/device.hpp create mode 100644 arch/x86_64/arch/vga/text/flags.hpp delete mode 100644 arch/x86_64/include/arch/boot/boot.hpp delete mode 100644 arch/x86_64/include/arch/boot/ld.hpp delete mode 100644 arch/x86_64/include/arch/bus/isa.hpp delete mode 100644 arch/x86_64/include/arch/cpu/control_register.hpp delete mode 100644 arch/x86_64/include/arch/cpu/global_descriptor_table.hpp delete mode 100644 arch/x86_64/include/arch/cpu/initialization.hpp delete mode 100644 arch/x86_64/include/arch/cpu/interrupts.hpp delete mode 100644 arch/x86_64/include/arch/cpu/legacy_pic.hpp delete mode 100644 arch/x86_64/include/arch/cpu/model_specific_register.hpp delete mode 100644 arch/x86_64/include/arch/cpu/registers.hpp delete mode 100644 arch/x86_64/include/arch/cpu/segment_descriptor.hpp delete mode 100644 arch/x86_64/include/arch/cpu/segment_selector.hpp delete mode 100644 arch/x86_64/include/arch/cpu/task_state_segment.hpp delete mode 100644 arch/x86_64/include/arch/debug/qemu_output.hpp delete mode 100644 arch/x86_64/include/arch/device_io/port_io.hpp delete mode 100644 arch/x86_64/include/arch/devices/init.hpp delete mode 100644 arch/x86_64/include/arch/devices/legacy_pit.hpp delete mode 100644 arch/x86_64/include/arch/devices/local_apic.hpp delete mode 100644 arch/x86_64/include/arch/memory/higher_half_mapper.hpp delete mode 100644 arch/x86_64/include/arch/memory/kernel_mapper.hpp delete mode 100644 arch/x86_64/include/arch/memory/mmu.hpp delete mode 100644 arch/x86_64/include/arch/memory/page_table.hpp delete mode 100644 arch/x86_64/include/arch/memory/page_utilities.hpp delete mode 100644 arch/x86_64/include/arch/memory/region_allocator.hpp delete mode 100644 arch/x86_64/include/arch/vga/crtc.hpp delete mode 100644 arch/x86_64/include/arch/vga/text.hpp delete mode 100644 arch/x86_64/include/arch/vga/text/attribute.hpp delete mode 100644 arch/x86_64/include/arch/vga/text/buffer.hpp delete mode 100644 arch/x86_64/include/arch/vga/text/color.hpp delete mode 100644 arch/x86_64/include/arch/vga/text/common_attributes.hpp delete mode 100644 arch/x86_64/include/arch/vga/text/device.hpp delete mode 100644 arch/x86_64/include/arch/vga/text/flags.hpp delete mode 100644 arch/x86_64/pre/include/arch/context_switching/main.hpp delete mode 100644 arch/x86_64/pre/include/arch/context_switching/syscall/main.hpp delete mode 100644 arch/x86_64/pre/include/arch/context_switching/syscall/syscall_enable.hpp delete mode 100644 arch/x86_64/pre/include/arch/context_switching/syscall/syscall_handler.hpp delete mode 100644 arch/x86_64/pre/include/arch/kernel/halt.hpp delete mode 100644 arch/x86_64/pre/include/arch/kernel/main.hpp delete mode 100644 arch/x86_64/pre/include/arch/user/main.hpp delete mode 100644 arch/x86_64/pre/src/context_switching/main.cpp delete mode 100644 arch/x86_64/pre/src/context_switching/syscall/main.cpp delete mode 100644 arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp delete mode 100644 arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp delete mode 100644 arch/x86_64/pre/src/kernel/main.cpp delete mode 100644 arch/x86_64/pre/src/user/main.cpp 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') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 9e346ef..5657010 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -5,8 +5,16 @@ add_library("x86_64" OBJECT) add_library("arch::lib" ALIAS "x86_64") +target_include_directories("x86_64" PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}" +) + +target_link_libraries("x86_64" PUBLIC + "os::kapi" + "libs::multiboot2" +) + target_sources("x86_64" PRIVATE - # Platform-dependent KAPI implementation "kapi/boot_modules.cpp" "kapi/cio.cpp" "kapi/cpu.cpp" @@ -14,39 +22,41 @@ target_sources("x86_64" PRIVATE "kapi/interrupts.cpp" "kapi/memory.cpp" "kapi/system.cpp" +) +target_sources("x86_64" PRIVATE # CPU Initialization - "src/cpu/initialization.cpp" - "src/cpu/interrupts.cpp" - "src/cpu/interrupt_stubs.S" + "arch/cpu/initialization.cpp" + "arch/cpu/interrupts.cpp" + "arch/cpu/interrupts.S" # Bus Initialization - "src/bus/isa.cpp" + "arch/bus/isa.cpp" # Low-level bootstrap - "src/boot/boot32.S" - "src/boot/entry64.s" - "src/boot/initialize_runtime.cpp" - "src/boot/multiboot.s" + "arch/boot/boot32.S" + "arch/boot/entry64.s" + "arch/boot/initialize_runtime.cpp" + "arch/boot/multiboot.s" # Debug interfaces - "src/debug/qemu_output.cpp" + "arch/debug/qemu_output.cpp" # Devices - "src/devices/init.cpp" - "src/devices/legacy_pit.cpp" - "src/devices/local_apic.cpp" + "arch/devices/init.cpp" + "arch/devices/legacy_pit.cpp" + "arch/devices/local_apic.cpp" # Memory management - "src/memory/kernel_mapper.cpp" - "src/memory/higher_half_mapper.cpp" - "src/memory/mmu.cpp" - "src/memory/page_table.cpp" - "src/memory/region_allocator.cpp" + "arch/memory/kernel_mapper.cpp" + "arch/memory/higher_half_mapper.cpp" + "arch/memory/mmu.cpp" + "arch/memory/page_table.cpp" + "arch/memory/region_allocator.cpp" # VGA text mode - "src/vga/text/buffer.cpp" - "src/vga/text/device.cpp" + "arch/vga/text/buffer.cpp" + "arch/vga/text/device.cpp" ) file(GLOB_RECURSE ARCH_HEADERS diff --git a/arch/x86_64/arch/boot/boot.hpp b/arch/x86_64/arch/boot/boot.hpp new file mode 100644 index 0000000..7df61c4 --- /dev/null +++ b/arch/x86_64/arch/boot/boot.hpp @@ -0,0 +1,56 @@ +#ifndef TEACHOS_X86_64_BOOT_BOOT_HPP +#define TEACHOS_X86_64_BOOT_BOOT_HPP + +#ifdef __ASSEMBLER__ +// clang-format off + +//! The number of huge pages to map during bootstrap. +#define HUGE_PAGES_TO_MAP (16) + +//! The magic value to be set in eax by the multiboot 2 loader. +#define MULTIBOOT2_MAGIC (0x36d76289) + +//! The "A" bit in a GDT entry. +#define GDT_ACCESSED (1 << 40) + +//! The "R/W" bit in a GDT entry +#define GDT_READ_WRITE (1 << 41) + +//! The "E" bit in a GDT entry. +#define GDT_EXECUTABLE (1 << 43) + +//! The "S" bit in a GDT entry. +#define GDT_DESCRIPTOR_TYPE (1 << 44) + +//! The "P" bit in a GDT entry. +#define GDT_PRESENT (1 << 47) + +//! The "L" bit in a GDT entry. +#define GDT_LONG_MODE (1 << 53) + +// clang-format on +#else + +#include // IWYU pragma: export + +#include + +#include + +namespace kapi::boot +{ + + struct information + { + //! A pointer to the loader provided Multiboot2 Information structure. + multiboot2::information_view const * mbi; + + //! The index of the next character to be written in the VGA text buffer after handoff. + std::size_t vga_buffer_index; + }; + +} // namespace kapi::boot + +#endif + +#endif diff --git a/arch/x86_64/arch/boot/boot32.S b/arch/x86_64/arch/boot/boot32.S new file mode 100644 index 0000000..e6fcd85 --- /dev/null +++ b/arch/x86_64/arch/boot/boot32.S @@ -0,0 +1,443 @@ +#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/arch/boot/entry64.s b/arch/x86_64/arch/boot/entry64.s new file mode 100644 index 0000000..29fb778 --- /dev/null +++ b/arch/x86_64/arch/boot/entry64.s @@ -0,0 +1,62 @@ +.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/arch/boot/initialize_runtime.cpp b/arch/x86_64/arch/boot/initialize_runtime.cpp new file mode 100644 index 0000000..b08c13c --- /dev/null +++ b/arch/x86_64/arch/boot/initialize_runtime.cpp @@ -0,0 +1,22 @@ +#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/arch/boot/ld.hpp b/arch/x86_64/arch/boot/ld.hpp new file mode 100644 index 0000000..988723d --- /dev/null +++ b/arch/x86_64/arch/boot/ld.hpp @@ -0,0 +1,61 @@ +//! @file +//! The interface to linker script defined symbols. +//! +//! This header provides declarations for symbols that are defined in the linker script itself. The symbols declared +//! here provide important information, for example the start and end of the kernel image in virtual and physical +//! memory. +//! +//! Any variables defined in this file must not be read themselves, but rather their address shall be taken, yielding a +//! pointer to the memory location the represent. +//! +//! @note The symbols declared in this header are declared using C-language linkage in order to suppress name mangling. +//! +//! @see arch/x86_64/scripts/kernel.ld + +#ifndef TEACHOS_X86_64_BOOT_LD_HPP +#define TEACHOS_X86_64_BOOT_LD_HPP + +#include + +namespace arch::boot +{ + + extern "C" + { + //! The beginning of the kernel image in physical memory + //! + //! This symbol marks the start of the kernel image in physical memory. + //! + //! @see _end_physical + extern std::byte _start_physical; + + //! The first byte after the loaded kernel image. + //! + //! This symbol marks the end of the kernel image in physical memory. + //! + //! @see _start_physical + extern std::byte _end_physical; + + //! The first byte of the loaded kernel image in the virtual address space. + //! + //! This symbol and marks the start of the kernel image in virtual memory. + //! + //! @see _end_virtual + extern std::byte _start_virtual; + + //! The first byte after the loaded kernel image in the virtual address space. + //! + //! This symbol marks the end of the kernel image in virtual memory. + //! + //! @see _start_virtual + extern std::byte _end_virtual; + + //! The first byte of the kernel's virtual address space. + //! + //! This symbol marks beginning of the kernel virtual address space. + extern std::byte TEACHOS_VMA; + } + +} // namespace arch::boot + +#endif diff --git a/arch/x86_64/arch/boot/multiboot.s b/arch/x86_64/arch/boot/multiboot.s new file mode 100644 index 0000000..37d8afe --- /dev/null +++ b/arch/x86_64/arch/boot/multiboot.s @@ -0,0 +1,33 @@ +.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/arch/bus/isa.cpp b/arch/x86_64/arch/bus/isa.cpp new file mode 100644 index 0000000..f6cc72d --- /dev/null +++ b/arch/x86_64/arch/bus/isa.cpp @@ -0,0 +1,14 @@ +#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/arch/bus/isa.hpp b/arch/x86_64/arch/bus/isa.hpp new file mode 100644 index 0000000..e56f56a --- /dev/null +++ b/arch/x86_64/arch/bus/isa.hpp @@ -0,0 +1,18 @@ +#ifndef TEACHOS_X86_64_BUS_ISA_HPP +#define TEACHOS_X86_64_BUS_ISA_HPP + +#include + +#include + +namespace arch::bus +{ + + struct isa final : public kapi::devices::bus + { + isa(std::size_t major); + }; + +} // namespace arch::bus + +#endif // TEACHOS_X86_64_BUS_ISA_HPP diff --git a/arch/x86_64/arch/cpu/control_register.hpp b/arch/x86_64/arch/cpu/control_register.hpp new file mode 100644 index 0000000..9cedc35 --- /dev/null +++ b/arch/x86_64/arch/cpu/control_register.hpp @@ -0,0 +1,249 @@ +#ifndef TEACHOS_X86_64_CPU_CONTROL_REGISTERS_HPP +#define TEACHOS_X86_64_CPU_CONTROL_REGISTERS_HPP + +// IWYU pragma: private, include + +#include + +#include + +#include +#include +#include +#include + +namespace arch::cpu +{ + namespace impl + { + //! The assembler templates used to access (r/w) CR0; + constexpr auto static cr0_asm = std::pair{"mov %%cr0, %0", "mov %0, %%cr0"}; + + //! The assembler templates used to access (r/w) CR2; + constexpr auto static cr2_asm = std::pair{"mov %%cr2, %0", "mov %0, %%cr2"}; + + //! The assembler templates used to access (r/w) CR3; + constexpr auto static cr3_asm = std::pair{"mov %%cr3, %0", "mov %0, %%cr3"}; + } // namespace impl + + //! The flags that can be set on CR0 configuration register. + enum struct cr0_flags : uint64_t + { + //! Enable protected mode. + protection_enable = 1uz << 0, + //! Enable wait-monitoring of the coprocessor after task switching. + monitor_coprocessor = 1uz << 1, + //! Emulate floating point coprocessor. + emulation = 1uz << 2, + //! Marks that a task switch has occurred. + task_switched = 1uz << 3, + //! Marks Intel 387 DX math coprocessor as available + extension_type = 1uz << 4, + //! Numeric error handling mode. + numeric_error = 1uz << 5, + //! Disable writing to read-only marked memory. + write_protect = 1uz << 16, + //! Enable Ring-3 alignment checks + alignment_check = 1uz << 18, + //! Disable write through + not_write_through = 1uz << 29, + //! Disable caching of memory accesses + cache_disable = 1uz << 30, + //! Enable paging + paging = 1uz << 31 + }; + + enum struct cr3_flags : std::uint64_t + { + page_level_write_through = 1uz << 0, + page_level_cache_disable = 1uz << 1, + }; +} // namespace arch::cpu + +namespace kstd::ext +{ + template<> + struct is_bitfield_enum : std::true_type + { + }; + + template<> + struct is_bitfield_enum : std::true_type + { + }; +} // namespace kstd::ext + +namespace arch::cpu +{ + //! A mixin for flag-oriented control registers. + //! + //! This mixin provides additional functionality for flag-oriented, or partially flag-oriented, control registers. A + //! control register is flag-oriented, if it comprises a bitfield and zero or more additional non-bitfield parts. + //! + //! @tparam Derived The class deriving from this mixin. + //! @tparam ValueType The value type of the class deriving from this mixin. + template + struct control_register_with_flags + { + private: + constexpr control_register_with_flags() noexcept = default; + friend Derived; + }; + + //! @copydoc control_register_with_flags + //! + //! @note This specialization provides the implementation for the case in which the value type of the control register + //! is an enum. + template + struct control_register_with_flags>> + { + //! The type of the flags used by this control register + using flags = ValueType; + + //! Set one or more flags in this control register. + //! + //! @warning This function is to be considered **UNSAFE**. Setting flags in a control register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param value One or a combination of flags to be set in the control register. + auto static set(ValueType value) -> void + { + auto current = Derived::read(); + current |= value; + Derived::write(current); + } + + //! Clear one or more flags in this control register. + //! + //! @warning This function is to be considered **UNSAFE**. Clearing flags in a control register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param value One or a combination of flags to be cleared in the control register. + auto static clear(ValueType value) -> void + { + auto current = Derived::read(); + current &= ~value; + Derived::write(current); + } + }; + + //! A CPU control register. + //! + //! CPU control registers are used to configure builtin features of the CPU, for example memory protection and FPU + //! error reporting. Writing to a control register is inherently dangerous, since a misconfiguration can leave the CPU + //! in an invalid/undefined state. + template + struct control_register : control_register_with_flags, ValueType> + { + //! Read the current value of the control register. + //! + //! @return The currently set value of the control register. + [[nodiscard]] auto static read() -> ValueType + { + auto value = ValueType{}; + asm volatile((AssemblerTemplates->first) : "=r"(value)); + return value; + } + + //! Write a new value to the control register. + //! + //! @warning This function should be considered **UNSAFE**. Writing values to a control register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param value The new value to write to the control register. + auto static write(ValueType value) -> void + { + asm volatile((AssemblerTemplates->second) : : "r"(value)); + } + }; + + //! The value type of the CR3 control register. + //! + //! The CR3 control register holds the root configuration of the virtual memory protection mechanism. It contains the + //! page aligned physical address of the root page map, as well as the root paging configuration flags. + struct cr3_value + { + //! Contstruct a 0-value CR3 value. + constexpr cr3_value() = default; + + //! Construct a CR3 value using the given root page map address and flags. + //! + //! @param address The physical address of the root page map + //! @param flags The root configuration flags of the paging system. + constexpr cr3_value(kapi::memory::physical_address address, cr3_flags flags = static_cast(0)) + : m_flags{static_cast(flags)} + , m_address{static_cast(address.raw())} + {} + + //! Extract the physical address of the root page map from this value. + //! + //! @return The physical address of the root page map. + [[nodiscard]] constexpr auto address() const -> kapi::memory::physical_address + { + constexpr auto address_shift = 12uz; + return kapi::memory::physical_address{m_address << address_shift}; + } + + //! Encode the frame aligned physical address of the root page map into this value. + //! + //! @param frame The frame containing a PML4. + constexpr auto frame(kapi::memory::frame frame) -> void + { + m_address = static_cast(frame.number()); + } + + //! Extract the root paging configuration flags from this value. + //! + //! @return The root paging configuration flags. + [[nodiscard]] constexpr auto flags() const -> cr3_flags + { + return static_cast(m_flags); + } + + //! Encode the root paging configuration flags into this value. + //! + //! @param flags The root paging configuration flags. + constexpr auto flags(cr3_flags flags) -> void + { + m_flags = static_cast(flags); + } + + //! Add the given flags to the current set of encoded root configuration flags of this value. + //! + //! @param flags The root configuration flags to add. + //! @return A reference to this value. + constexpr auto operator|=(cr3_flags flags) -> cr3_value & + { + m_flags |= static_cast(flags); + return *this; + } + + //! Mask the root configuration flags of this value. + //! + //! @param mask The mask to apply to the root configuration flags. + //! @return A reference to this value. + constexpr auto operator&=(cr3_flags mask) -> cr3_value & + { + m_flags &= static_cast(mask); + return *this; + } + + private: + //! Reserved bits. + std::uint64_t : 3; + //! The root paging configuration flags. + std::uint64_t m_flags : 2 {}; + //! Reserved bits. + std::uint64_t : 7; + //! The page aligned physical address of the root page map. + std::uint64_t m_address : 52 {}; + }; + + static_assert(sizeof(cr3_value) == sizeof(std::uint64_t)); + +} // namespace arch::cpu + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/cpu/global_descriptor_table.hpp b/arch/x86_64/arch/cpu/global_descriptor_table.hpp new file mode 100644 index 0000000..b17c509 --- /dev/null +++ b/arch/x86_64/arch/cpu/global_descriptor_table.hpp @@ -0,0 +1,91 @@ +#ifndef TEACHOS_X86_64_GLOBAL_DESCRIPTOR_TABLE_HPP +#define TEACHOS_X86_64_GLOBAL_DESCRIPTOR_TABLE_HPP + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace arch::cpu +{ + + template + struct global_descriptor_table; + + struct [[gnu::packed]] global_descriptor_table_pointer + { + template + global_descriptor_table_pointer(global_descriptor_table const & gdt) + : size{GdtSize * sizeof(segment_descriptor) - 1} + , address{kapi::memory::physical_address{std::bit_cast(&gdt)}.raw()} + {} + + auto load() -> void + { + asm volatile("lgdt %0" : : "m"(*this)); + } + + std::uint16_t size{}; + std::uint64_t address{}; + }; + + static_assert(sizeof(global_descriptor_table_pointer) == sizeof(std::uint16_t) + sizeof(std::uint64_t)); + + template + struct global_descriptor_table + { + template... SegmentDescriptors> + constexpr global_descriptor_table(SegmentDescriptors const &... descriptors) + : m_descriptors{} + { + auto descriptor_data = std::array{ + std::pair{std::bit_cast(&descriptors), sizeof(descriptors)} + ... + }; + auto written_size = 0uz; + std::ranges::for_each(descriptor_data, [&written_size, this](auto entry) { + std::ranges::copy(entry.first, entry.first + entry.second, m_descriptors.begin() + written_size); + written_size += entry.second; + }); + } + + auto load(std::size_t code_segment_index, std::size_t data_segment_index) const -> void + { + auto pointer = global_descriptor_table_pointer{*this}; + pointer.load(); + + asm volatile("push %0\n" + "lea 1f(%%rip), %%rax\n" + "push %%rax\n" + "lretq\n" + "1:\n" + "mov %1, %%rax\n" + "mov %%rax, %%ss\n" + "mov %%rax, %%ds\n" + "mov %%rax, %%es\n" + "mov %%rax, %%fs\n" + "mov %%rax, %%gs\n" + : + : "X"(code_segment_index * sizeof(segment_descriptor)), + "X"(data_segment_index * sizeof(segment_descriptor)) + : "rax"); + } + + private: + std::array m_descriptors; + }; + + template... SegmentDescriptors> + global_descriptor_table(SegmentDescriptors const &... descriptors) + -> global_descriptor_table<(sizeof(SegmentDescriptors) + ...)>; + +} // namespace arch::cpu + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/cpu/initialization.cpp b/arch/x86_64/arch/cpu/initialization.cpp new file mode 100644 index 0000000..1be9c82 --- /dev/null +++ b/arch/x86_64/arch/cpu/initialization.cpp @@ -0,0 +1,164 @@ +#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/arch/cpu/initialization.hpp b/arch/x86_64/arch/cpu/initialization.hpp new file mode 100644 index 0000000..564c544 --- /dev/null +++ b/arch/x86_64/arch/cpu/initialization.hpp @@ -0,0 +1,12 @@ +#ifndef TEACHOS_ARCH_X86_64_CPU_INITIALIZATION_HPP +#define TEACHOS_ARCH_X86_64_CPU_INITIALIZATION_HPP + +namespace arch::cpu +{ + auto initialize_descriptors() -> void; + + auto initialize_legacy_interrupts() -> void; + +} // namespace arch::cpu + +#endif diff --git a/arch/x86_64/arch/cpu/interrupts.S b/arch/x86_64/arch/cpu/interrupts.S new file mode 100644 index 0000000..e59bdd2 --- /dev/null +++ b/arch/x86_64/arch/cpu/interrupts.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/arch/cpu/interrupts.cpp b/arch/x86_64/arch/cpu/interrupts.cpp new file mode 100644 index 0000000..f40422f --- /dev/null +++ b/arch/x86_64/arch/cpu/interrupts.cpp @@ -0,0 +1,203 @@ +#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/arch/cpu/interrupts.hpp b/arch/x86_64/arch/cpu/interrupts.hpp new file mode 100644 index 0000000..6162f56 --- /dev/null +++ b/arch/x86_64/arch/cpu/interrupts.hpp @@ -0,0 +1,116 @@ +#ifndef TEACHOS_X86_64_CPU_INTERRUPTS_HPP +#define TEACHOS_X86_64_CPU_INTERRUPTS_HPP + +#include + +#include + +#include +#include +#include + +namespace arch::cpu +{ + + //! The types of supported gates. + enum struct gate_type : std::uint8_t + { + //! A gate entered through the @p INT instruction. + interrupt_gate = 0b1110, + //! A gate entered via an exception. + trap_gate = 0b1111, + }; + + struct alignas(std::uint64_t) gate_descriptor + { + //! The lowest 16 bits of the address of this gate's handler function. + std::uint16_t offset_low : 16; + //! The code segment used when handling the respective interrupt. + segment_selector m_code_segment; + //! The index into the Interrupt Stack Table naming the stack to use. + std::uint8_t interrupt_stack_table_selector : 3; + //! Reserved + std::uint8_t : 5; + //! The type of this gate. + enum gate_type gate_type : 4; + //! Reserved + std::uint8_t : 1; + //! The privilege level required to enter through this gate. + std::uint8_t descriptor_privilege_level : 2; + //! Whether this gate is present or not. + std::uint8_t present : 1; + //! The middle 16 bits of the address of this gate's handler function. + std::uint16_t offset_middle : 16; + //! The highest 32 bits of the address of this gate's handler function. + std::uint32_t offset_high : 32; + //! Reserved + std::uint32_t : 32; + }; + + static_assert(sizeof(gate_descriptor) == 2 * sizeof(std::uint64_t)); + static_assert(std::is_aggregate_v); + + //! The stack frame as established by the low-level assembly interrupt stubs. + //! + //! @note The layout of this struct is reverse than what would reasonably be expected. The reason for this reversal is + //! that fact that it represents a stack frame. Stack frames on x86_64 grow towards lower addresses, meaning the first + //! item on the stack is the last item in C++ memory layout order. + struct interrupt_frame + { + struct + { + std::uint64_t r15{}; + std::uint64_t r14{}; + std::uint64_t r13{}; + std::uint64_t r12{}; + std::uint64_t r11{}; + std::uint64_t r10{}; + std::uint64_t r9{}; + std::uint64_t r8{}; + std::uint64_t rdi{}; + std::uint64_t rsi{}; + std::uint64_t rbp{}; + std::uint64_t rdx{}; + std::uint64_t rcx{}; + std::uint64_t rbx{}; + std::uint64_t rax{}; + } handler_saved; + + struct + { + std::uint64_t number{}; + std::uint64_t error_code{}; + } interrupt; + + struct + { + kapi::memory::linear_address rip{}; + std::uint64_t cs{}; + std::uint64_t rflags{}; + kapi::memory::linear_address rsp{}; + std::uint64_t ss{}; + } cpu_saved; + }; + + struct interrupt_descriptor_table + { + interrupt_descriptor_table() noexcept; + + auto load() const -> void; + + private: + std::array m_descriptors{}; + }; + + struct [[gnu::packed]] interrupt_descriptor_table_register + { + std::uint16_t limit; + gate_descriptor const * base; + + auto load() const -> void; + auto static read() -> interrupt_descriptor_table_register; + }; + +} // namespace arch::cpu + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/cpu/legacy_pic.hpp b/arch/x86_64/arch/cpu/legacy_pic.hpp new file mode 100644 index 0000000..56ca9c4 --- /dev/null +++ b/arch/x86_64/arch/cpu/legacy_pic.hpp @@ -0,0 +1,19 @@ +#ifndef TEACHOS_X86_64_CPU_LEGACY_PIC_HPP +#define TEACHOS_X86_64_CPU_LEGACY_PIC_HPP + +#include + +#include + +namespace arch::cpu +{ + 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_end_of_interrupt = std::uint8_t{0x20}; + +} // namespace arch::cpu + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/cpu/model_specific_register.hpp b/arch/x86_64/arch/cpu/model_specific_register.hpp new file mode 100644 index 0000000..bd4aff9 --- /dev/null +++ b/arch/x86_64/arch/cpu/model_specific_register.hpp @@ -0,0 +1,151 @@ +#ifndef TEACHOS_X86_64_CPU_MODEL_SPECIFIC_REGISTER_HPP +#define TEACHOS_X86_64_CPU_MODEL_SPECIFIC_REGISTER_HPP + +// IWYU pragma: private, include + +#include + +#include +#include +#include + +namespace arch::cpu +{ + + //! The flags of the IA32_EFER (Extended Features Enable Register) MSR. + enum struct ia32_efer_flags : std::uint64_t + { + //! Enable the syscall and sysret instructions. + syscall_enable = 1uz << 0, + //! Enable IA-32e mode operation. + ia32e_mode_enable = 1uz << 8, + //! Indicates IA-32e mode is active (read-only) + ia32e_mode_active = 1uz << 10, + //! Enable the use of the NX page table bit. + execute_disable_bit_enable = 1uz << 11, + }; + +} // namespace arch::cpu + +namespace kstd::ext +{ + + template<> + struct is_bitfield_enum : std::true_type + { + }; + +} // namespace kstd::ext + +namespace arch::cpu +{ + //! The MSR number for the IA32_EFER MSR + constexpr auto ia32_efer_number = 0xC000'0080u; + + //! A mixin for flag-oriented model specific registers. + //! + //! This mixin provides additional functionality for a flag-oriented model specific register. A models specific + //! register is flag-oriented, if it comprises a single field of bitfield. + //! + //! @tparam Derived The class deriving from this mixin. + //! @tparam ValueType The value type of the class deriving from this mixin. + template + struct model_specific_register_with_flags + { + private: + constexpr model_specific_register_with_flags() noexcept = default; + friend Derived; + }; + + //! @copydoc model_specific_register_with_flags + //! + //! @note This specialization provides the implementation for the case in which the value type of the model specific + //! register is a bitfield enum. + template + struct model_specific_register_with_flags>> + { + //! The of the flags used by this model specific register. + using flags = ValueType; + + //! Set one or more flags in this model specific register. + //! + //! @warning This function is to be considered **UNSAFE**. Setting flags in a model specific register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param flag One or a combination of flags to be set in the model specific register. + auto static set(flags flag) -> void + { + auto current = Derived::read(); + current |= flag; + Derived::write(current); + } + + //! Clear one or more flags in this model specific register. + //! + //! @warning This function is to be considered **UNSAFE**. Clearing flags in a model specific register may lead to + //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function + //! will perform no additional checks, and may, by extension, crash the system. + //! + //! @param flag One or a combination of flags to be cleared in the model specific register. + auto static clear(flags flag) -> void + { + auto current = Derived::read(); + current &= ~flag; + Derived::write(current); + } + + //! Test one or more flags in this model specific register + //! + //! @param flag One or a combination of flags to test for. + auto test(flags flag) -> flags + { + return Derived::read() & flag; + } + }; + + //! A model specific register (MSR) + //! + //! Model specific register are used to configure CPU features that a not necessarily present on all CPUs generations. + //! In the past, some MSRs have been defined to be architectural, meaning all CPUs of a given architecture (x86-64 in + //! this case) support them. Writing to a MSR is inherently dangerous, since a misconfiguration cal leave the CPU in + //! an invalid/undefined state. + //! + //! @tparam Number The register number of this MSR + //! @tparam ValueType The value type of this MSR + template + struct model_specific_register + : model_specific_register_with_flags, ValueType> + { + //! A raw MSR value, comprising two halfs. + //! + //! MSRs have been 64-bit in size even in the 32-bit intel architecture, and are thus written in two halfs. + struct raw_value + { + std::uint32_t low_half; //!< The lower half of the register value + std::uint32_t high_half; //!< The upper half of the register value + }; + + //! Read the current value of this MSR. + //! + //! @return The current value of this MSR. + auto static read() -> ValueType + { + auto raw = raw_value{}; + asm volatile("rdmsr" : "=a"(raw.low_half), "=d"(raw.high_half) : "c"(Number)); + return static_cast(std::bit_cast(raw)); + } + + //! Write a new value to this MSR. + //! + //! @param value The new value for this MSR. + auto static write(ValueType value) -> void + { + auto raw = std::bit_cast(static_cast(value)); + asm volatile("wrmsr" : : "a"(raw.low_half), "d"(raw.high_half), "c"(Number)); + } + }; + +} // namespace arch::cpu + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/cpu/registers.hpp b/arch/x86_64/arch/cpu/registers.hpp new file mode 100644 index 0000000..58633f6 --- /dev/null +++ b/arch/x86_64/arch/cpu/registers.hpp @@ -0,0 +1,32 @@ +#ifndef TEACHOS_X86_64_CPU_REGISTERS_HPP +#define TEACHOS_X86_64_CPU_REGISTERS_HPP + +#include // IWYU pragma: export +#include // IWYU pragma: export + +#include + +namespace arch::cpu +{ + + //! Configuration Register 0. + //! + //! This configuration register holds various control flags to configure the configure the basic operation of the CPU. + using cr0 = control_register; + + //! Configuration Register 2. + //! + //! This configuration register holds the memory address the access to which has triggered the most recent page fault. + using cr2 = control_register; + + //! Configuration Register 3. + //! + //! This register holds the configuration of the virtual memory protection configuration. + using cr3 = control_register; + + //! The I32_EFER (Extended Feature Enable Register) MSR + using i32_efer = model_specific_register; + +} // namespace arch::cpu + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/cpu/segment_descriptor.hpp b/arch/x86_64/arch/cpu/segment_descriptor.hpp new file mode 100644 index 0000000..9570670 --- /dev/null +++ b/arch/x86_64/arch/cpu/segment_descriptor.hpp @@ -0,0 +1,61 @@ +#ifndef TEACHOS_X86_64_SEGMENT_DESCRIPTOR_HPP +#define TEACHOS_X86_64_SEGMENT_DESCRIPTOR_HPP + +#include + +namespace arch::cpu +{ + + //! The type of segment described by a segment_descriptor. + enum struct segment_type : std::uint8_t + { + //! A system (TSS or LDT) segment + system = 0, + //! A code or data segment + code_or_data = 1, + }; + + //! The granularity of a segment described by a segment_descriptor + enum struct segment_granularity : std::uint8_t + { + //! The limit of the segment is defined in bytes. + byte = 0, + //! The limit of the segment is defined in pages (4KiB) + page = 1, + }; + + //! An entry in a segment descriptor table + struct segment_descriptor + { + std::uint64_t limit_low : 16; + std::uint64_t base_low : 24; + bool accessed : 1; + bool read_write : 1; + bool direction_or_conforming : 1; + bool executable : 1; + segment_type type : 1; + std::uint64_t privilege_level : 2; + bool present : 1; + std::uint64_t limit_high : 4; + std::uint64_t : 1; + bool long_mode : 1; + bool protected_mode : 1; + segment_granularity granularity : 1; + std::uint64_t base_high : 8; + }; + + static_assert(sizeof(segment_descriptor) == sizeof(std::uint64_t)); + static_assert(alignof(segment_descriptor) == alignof(std::uint64_t)); + + struct system_segment_descriptor : segment_descriptor + { + std::uint64_t base_extended : 32; + std::uint64_t : 32; + }; + + static_assert(sizeof(system_segment_descriptor) == 2 * sizeof(std::uint64_t)); + static_assert(alignof(system_segment_descriptor) == alignof(segment_descriptor)); + +} // namespace arch::cpu + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/cpu/segment_selector.hpp b/arch/x86_64/arch/cpu/segment_selector.hpp new file mode 100644 index 0000000..1a78c47 --- /dev/null +++ b/arch/x86_64/arch/cpu/segment_selector.hpp @@ -0,0 +1,21 @@ +#ifndef TEACHOS_X86_64_SEGMENT_SELECTOR_HPP +#define TEACHOS_X86_64_SEGMENT_SELECTOR_HPP + +#include + +namespace arch::cpu +{ + + struct segment_selector + { + std::uint16_t request_privilege_level : 2; + bool use_local_descriptor_table : 1; + std::uint16_t table_index : 13; + }; + + static_assert(sizeof(segment_selector) == sizeof(std::uint16_t)); + static_assert(alignof(segment_selector) == alignof(std::uint16_t)); + +} // namespace arch::cpu + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/cpu/task_state_segment.hpp b/arch/x86_64/arch/cpu/task_state_segment.hpp new file mode 100644 index 0000000..57729dd --- /dev/null +++ b/arch/x86_64/arch/cpu/task_state_segment.hpp @@ -0,0 +1,30 @@ +#ifndef TEACHOS_X86_64_TASK_STATE_SEGMENT_HPP +#define TEACHOS_X86_64_TASK_STATE_SEGMENT_HPP + +#include + +namespace arch::cpu +{ + + struct [[gnu::packed]] task_state_segment + { + uint32_t : 32; + uint64_t rsp0 = {}; + uint64_t rsp1 = {}; + uint64_t rsp2 = {}; + uint64_t : 64; + uint64_t ist1 = {}; + uint64_t ist2 = {}; + uint64_t ist3 = {}; + uint64_t ist4 = {}; + uint64_t ist5 = {}; + uint64_t ist6 = {}; + uint64_t ist7 = {}; + uint64_t : 64; + uint16_t : 16; + uint16_t io_map_base_address = {}; + }; + +} // namespace arch::cpu + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/debug/qemu_output.cpp b/arch/x86_64/arch/debug/qemu_output.cpp new file mode 100644 index 0000000..71acede --- /dev/null +++ b/arch/x86_64/arch/debug/qemu_output.cpp @@ -0,0 +1,25 @@ +#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/arch/debug/qemu_output.hpp b/arch/x86_64/arch/debug/qemu_output.hpp new file mode 100644 index 0000000..5ddd4be --- /dev/null +++ b/arch/x86_64/arch/debug/qemu_output.hpp @@ -0,0 +1,43 @@ +#ifndef TEACHOS_X86_64_DEBUG_QEMU_OUTPUT_HPP +#define TEACHOS_X86_64_DEBUG_QEMU_OUTPUT_HPP + +#include + +#include + +#include + +namespace arch::debug +{ + + //! A QEMU debug console output device. + //! + //! This device implements output to the port 0xE9 debug console present in QEMU in Bochs. It is designed to wrap a + //! different output device (e.g. a VGA text output device) and forwards the written data accordingly. + //! + //! @note Support for the device has to be enabled when the emulator is started. The device will try to detect if the + //! port is available. If the port is detected, any output to the device will be written to port before being + //! forwarded to the lower device. + struct qemu_output : kapi::cio::output_device + { + //! The port to write to. + using port = io::port<0xE9, unsigned char, io::port_write, io::port_read>; + + //! Construct a new debug device wrapper for the given output device. + //! + //! @param lower The device to forward the output to. + explicit qemu_output(output_device & lower); + + //! @copydoc kapi::cio::output_device + auto write(kapi::cio::output_stream stream, std::string_view text) -> void override; + + private: + //! The device to forward the output to. + output_device & m_lower; + //! Whether the device has been detected. + bool m_present; + }; + +} // namespace arch::debug + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/device_io/port_io.hpp b/arch/x86_64/arch/device_io/port_io.hpp new file mode 100644 index 0000000..4c8d66a --- /dev/null +++ b/arch/x86_64/arch/device_io/port_io.hpp @@ -0,0 +1,112 @@ +#ifndef TEACHOS_X86_64_IO_PORT_IO_HPP +#define TEACHOS_X86_64_IO_PORT_IO_HPP + +#include +#include +#include +#include +#include +#include + +namespace arch::io +{ + + //! The requirements imposed on a type usable for port I/O. + template + concept port_io_type = requires { + requires sizeof(ValueType) == 1 || sizeof(ValueType) == 2 || sizeof(ValueType) == 4; + requires std::default_initializable; + std::bit_cast( + std::conditional_t>{}); + }; + + template + struct port_read + { + //! Read from the I/O port. + //! + //! @return The data read from the I/O port. + auto static read() noexcept + { + auto data = typename Derived::value_type{}; + asm volatile((code[Derived::size / 2]) + : [data] "=m"(data) + : [port] "i"(Derived::address) + : "dx", (Derived::data_register)); + return data; + } + + private: + constexpr port_read() noexcept = default; + friend Derived; + + //! The assembly templates used for reading from an I/O port. + constexpr auto static code = std::array{ + std::string_view{"mov %[port], %%dx\nin %%dx, %%al\nmov %%al, %[data]"}, + std::string_view{"mov %[port], %%dx\nin %%dx, %%ax\nmov %%ax, %[data]"}, + std::string_view{"mov %[port], %%dx\nin %%dx, %%eax\nmov %%eax, %[data]"}, + }; + }; + + template + struct port_write + { + //! Write data to the I/O port. + //! + //! @param data The data to write to the I/O port. + auto static write(std::same_as auto data) noexcept -> void + { + asm volatile((code[Derived::size / 2]) + : + : [port] "i"(Derived::address), [data] "im"(data) + : "dx", (Derived::data_register)); + } + + private: + constexpr port_write() noexcept = default; + friend Derived; + + //! The assembly templates used for writing to an I/O port. + constexpr auto static code = std::array{ + std::string_view{"mov %[port], %%dx\nmov %[data], %%al\nout %%al, %%dx"}, + std::string_view{"mov %[port], %%dx\nmov %[data], %%ax\nout %%ax, %%dx"}, + std::string_view{"mov %[port], %%dx\nmov %[data], %%eax\nout %%eax, %%dx"}, + }; + }; + + //! An I/O port of a given size at a given address. + //! + //! Port I/O leverages a separate address space to communicate with devices via the memory bus, allowing for byte + //! to double-word sized transfers. + //! + //! @tparam Address The address (port number) of the I/O port. + //! @tparam Size The size (in bytes) of the I/O port. + //! @tparam Features The features (readable, writeable) + template typename... Features> + requires(sizeof...(Features) > 0) + struct port : Features>... + { + //! The type of the data of this port. + using value_type = ValueType; + + //! The address of this I/O port. + constexpr auto static address = Address; + + //! The size of this I/O port. + constexpr auto static size = sizeof(value_type); + + //! The register clobbered by the I/O operation. + constexpr auto static data_register = size == 1 ? std::string_view{"al"} + : size == 2 ? std::string_view{"ax"} + : std::string_view{"eax"}; + }; + + auto inline wait() -> void + { + port<0x80, std::uint8_t, port_write>::write(0); + } + +} // namespace arch::io + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/devices/init.cpp b/arch/x86_64/arch/devices/init.cpp new file mode 100644 index 0000000..c30e8cf --- /dev/null +++ b/arch/x86_64/arch/devices/init.cpp @@ -0,0 +1,76 @@ +#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/arch/devices/init.hpp b/arch/x86_64/arch/devices/init.hpp new file mode 100644 index 0000000..c5fbf37 --- /dev/null +++ b/arch/x86_64/arch/devices/init.hpp @@ -0,0 +1,12 @@ +#ifndef TEACHOS_ARCH_X86_64_DEVICES_INIT_HPP +#define TEACHOS_ARCH_X86_64_DEVICES_INIT_HPP + +namespace arch::devices +{ + + auto init_acpi_devices() -> void; + auto init_legacy_devices() -> void; + +} // namespace arch::devices + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/devices/legacy_pit.cpp b/arch/x86_64/arch/devices/legacy_pit.cpp new file mode 100644 index 0000000..d542d47 --- /dev/null +++ b/arch/x86_64/arch/devices/legacy_pit.cpp @@ -0,0 +1,60 @@ +#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/arch/devices/legacy_pit.hpp b/arch/x86_64/arch/devices/legacy_pit.hpp new file mode 100644 index 0000000..356895c --- /dev/null +++ b/arch/x86_64/arch/devices/legacy_pit.hpp @@ -0,0 +1,29 @@ +#ifndef TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP +#define TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP + +#include +#include + +#include +#include + +namespace arch::devices +{ + + struct legacy_pit : kapi::devices::device, kapi::interrupts::handler + { + legacy_pit(std::size_t major, std::uint32_t frequency_in_hz); + + auto init() -> bool override; + + auto handle_interrupt(std::uint32_t irq_number) -> kapi::interrupts::status override; + + private: + std::uint32_t m_irq_number{}; + std::uint32_t m_frequency_in_hz{}; + std::uint64_t m_ticks{}; + }; + +} // namespace arch::devices + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/devices/local_apic.cpp b/arch/x86_64/arch/devices/local_apic.cpp new file mode 100644 index 0000000..660921b --- /dev/null +++ b/arch/x86_64/arch/devices/local_apic.cpp @@ -0,0 +1,134 @@ +#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/arch/devices/local_apic.hpp b/arch/x86_64/arch/devices/local_apic.hpp new file mode 100644 index 0000000..f8f080d --- /dev/null +++ b/arch/x86_64/arch/devices/local_apic.hpp @@ -0,0 +1,37 @@ +#ifndef TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP +#define TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP + +#include +#include + +#include +#include + +namespace arch::devices +{ + + struct local_apic : kapi::devices::device + { + local_apic(std::size_t major, std::size_t minor, std::uint64_t hardware_id, kapi::memory::physical_address base, + bool is_bsp); + + auto init() -> bool override; + + private: + enum struct registers : std::ptrdiff_t; + + [[nodiscard]] auto read_register(registers id) const -> std::uint32_t; + auto write_register(registers id, std::uint32_t value) -> void; + + std::uint64_t m_hardware_id{}; + kapi::memory::physical_address m_base{}; + kapi::memory::mmio_region m_mapped_region{}; + bool m_is_bsp{}; + std::uint8_t m_version{}; + std::uint8_t m_highest_lvt_entry_index{}; + bool m_supports_eoi_broadcast_suppression{}; + }; + +} // namespace arch::devices + +#endif diff --git a/arch/x86_64/arch/memory/higher_half_mapper.cpp b/arch/x86_64/arch/memory/higher_half_mapper.cpp new file mode 100644 index 0000000..75adb3c --- /dev/null +++ b/arch/x86_64/arch/memory/higher_half_mapper.cpp @@ -0,0 +1,119 @@ +#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/arch/memory/higher_half_mapper.hpp b/arch/x86_64/arch/memory/higher_half_mapper.hpp new file mode 100644 index 0000000..9b02ee6 --- /dev/null +++ b/arch/x86_64/arch/memory/higher_half_mapper.hpp @@ -0,0 +1,44 @@ +#ifndef TEACHOS_X86_64_HIGHER_HALF_MAPPER_HPP +#define TEACHOS_X86_64_HIGHER_HALF_MAPPER_HPP + +#include + +#include + +#include + +namespace arch::memory +{ + + //! A simple page mapper making use of a Higher Half Direct Map (HHDM) to access and modify page tables. + struct higher_half_mapper : kapi::memory::page_mapper + { + //! Construct a new mapper for a hierarchy rooted in the given PML. + //! + //! @param root The root of the hierarchy to operate on. + explicit higher_half_mapper(page_table * root); + + //! @copydoc kapi::memory::page_mapper::map + auto map(kapi::memory::page page, kapi::memory::frame frame, flags flags) -> std::byte * override; + + //! @copydoc kapi::memory::page_mapper::unmap + auto unmap(kapi::memory::page page) -> void override; + + //! @copydoc kapi::memory::page_mapper::try_unmap + auto try_unmap(kapi::memory::page page) noexcept -> bool override; + + private: + //! Try to retrieve the the PML1 responsible for mapping this page, creating one if necessary. + //! + //! This function will create a page table hierarchy leading to the target PML1 if it doesn't exist. + //! + //! @param page The page to get the PML1 for. + //! @return The PML1 that manages the given page, nullptr it the system runs out of memory. + auto get_or_create_page_table(kapi::memory::page page) noexcept -> page_table *; + + page_table * m_root; + }; + +} // namespace arch::memory + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/memory/kernel_mapper.cpp b/arch/x86_64/arch/memory/kernel_mapper.cpp new file mode 100644 index 0000000..74272a0 --- /dev/null +++ b/arch/x86_64/arch/memory/kernel_mapper.cpp @@ -0,0 +1,117 @@ +#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/arch/memory/kernel_mapper.hpp b/arch/x86_64/arch/memory/kernel_mapper.hpp new file mode 100644 index 0000000..adbf688 --- /dev/null +++ b/arch/x86_64/arch/memory/kernel_mapper.hpp @@ -0,0 +1,35 @@ +#ifndef TEACHOS_X86_64_KERNEL_MAPPER_HPP +#define TEACHOS_X86_64_KERNEL_MAPPER_HPP + +#include + +#include +#include + +#include + +#include +#include + +namespace arch::memory +{ + + struct kernel_mapper + { + using section_header_type = elf::section_header; + + explicit kernel_mapper(multiboot2::information_view const * mbi); + + auto remap_kernel(kapi::memory::page_mapper & mapper) -> void; + + private: + auto map_section(section_header_type const & section, std::string_view name, kapi::memory::page_mapper & mapper) + -> void; + + multiboot2::information_view const * m_mbi; + std::uintptr_t m_kernel_load_base; + }; + +} // namespace arch::memory + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/memory/mmu.cpp b/arch/x86_64/arch/memory/mmu.cpp new file mode 100644 index 0000000..2b53fa4 --- /dev/null +++ b/arch/x86_64/arch/memory/mmu.cpp @@ -0,0 +1,19 @@ +#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/arch/memory/mmu.hpp b/arch/x86_64/arch/memory/mmu.hpp new file mode 100644 index 0000000..64373f4 --- /dev/null +++ b/arch/x86_64/arch/memory/mmu.hpp @@ -0,0 +1,27 @@ +#ifndef TEACHOS_X86_64_MEMORY_MMU_HPP +#define TEACHOS_X86_64_MEMORY_MMU_HPP + +#include + +namespace arch::memory +{ + /** + * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained + * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. + * + * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for + * that page. + */ + auto tlb_flush(kapi::memory::linear_address address) -> void; + + /** + * @brief Invalidates the translation lookaside buffer (TLB) entry for all page tables. + * + * @note Simply reassigns the CR3 register the value of the CR3 register, causing a flush of the TLB buffer, because + * the system has to assume that the location of the level 4 page table moved. + */ + auto tlb_flush_all() -> void; + +} // namespace arch::memory + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/memory/page_table.cpp b/arch/x86_64/arch/memory/page_table.cpp new file mode 100644 index 0000000..2180420 --- /dev/null +++ b/arch/x86_64/arch/memory/page_table.cpp @@ -0,0 +1,82 @@ +#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/arch/memory/page_table.hpp b/arch/x86_64/arch/memory/page_table.hpp new file mode 100644 index 0000000..ce3d3a1 --- /dev/null +++ b/arch/x86_64/arch/memory/page_table.hpp @@ -0,0 +1,232 @@ +#ifndef TEACHOS_X86_64_PAGE_TABLE_HPP +#define TEACHOS_X86_64_PAGE_TABLE_HPP + +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace arch::memory +{ + + //! A table containing page mapping entries. + //! + //! Page tables exist in a multi-level hierarchy and are used to map pages (virtual memory) onto frames (physical + //! memory). Conceptually, pages represent the data found in a virtual address space, while frames represent their + //! storage. In most cases, only a level 1 page table maps an actual page onto a frame. All other page tables on + //! higher levels do not map payload pages, but rather their subordinate page tables. The only exception to that rule + //! is the use of huge pages. + struct page_table + { + //! An entry in a page table. + //! + //! A page table entry is a combination of a frame number and a set of flags that determine the properties and + //! access rights to a mapped page. Entries at a higher level in the page hierarchy do not map a page directly, + //! unless that page is marked as huge on the relevant level, but rather map the next lower page table. + struct entry + { + //! Flags marking the state and configuration of an entry. + //! + //! An entry in a page table may have any combination of these flags active at the same time. The final flags of a + //! page are determined as the strictest combination (logical AND) of all flags along the hierarchy. + //! + //! @note This is a bitfield enum as defined by kstd::ext::bitfield_enum. + enum struct flags : std::uint64_t + { + empty = 0, + present = 1uz << 0, //!< The page is mapped. + writable = 1uz << 1, //!< The page is writable. + user_accessible = 1uz << 2, //!< The page is accessible in user mode. + write_through = 1uz << 3, //!< Any writes to the page must immediately hit memory. + disable_cache = 1uz << 4, //!< Any writes to the page must never be cached. + accessed = 1uz << 5, //!< The page was accessed. + dirty = 1uz << 6, //!< The page was written to. + huge_page = 1uz << 7, //!< The page is huge. + global = 1uz << 8, //!< The TLB entry for this page must not be flushed on context switches. + no_execute = 1uz << 63, //!< The data in this page must not be executed. + }; + + //! Construct an empty entry. + entry() = default; + + //! Clear this entry, ensuring all information is set to zero. + //! + //! This effectively marks the page represented by this entry as not present. In addition, it also removes any + //! information about the frame referenced by this entry. + auto clear() noexcept -> void; + + //! Check if the page represented by this entry is present. + //! + //! @note This function does not attempt to walk the page table hierarchy, but only performs a local check. This + //! means, that if the page is not mapped at a lower level, this will not be detected. + //! + //! @return @p true iff. the page is present at this level, @p false otherwise. + [[nodiscard]] auto present() const noexcept -> bool; + + //! Check if the page represented by this entry is a huge page. + //! + //! @note The effective size of the page depends on the level of the page table containing this entry. + //! + //! @return @p true iff. the page is marked as being huge, @p false otherwise. + [[nodiscard]] auto huge() const noexcept -> bool; + + //! Get all flags present in this entry. + //! + //! @return The flags that are currently set on this entry. + [[nodiscard]] auto all_flags() const noexcept -> flags; + + //! Set all flags of this entry. + //! + //! @param flags The flags to apply to this entry. + auto all_flags(flags flags) noexcept -> void; + + //! Add the given flags to the flags of this entry. + //! + //! @param rhs The flags to add to this entry's flags. + //! @return A reference to this entry. + auto operator|=(flags rhs) noexcept -> entry &; + + //! Get the frame number associated with this entry, if the referenced page is present. + //! + //! @return an engaged std::optional iff. this entry maps a page, std::nullopt otherwise. + [[nodiscard]] auto frame() const noexcept -> std::optional; + + //! Map this entry. + //! + //! @param frame The frame to map in this entry. + //! @param flags The flags to apply to this entry. + auto frame(kapi::memory::frame frame, flags flags) noexcept -> void; + + private: + //! A mask to retrieve, or exclude, the frame number from the raw entry. + //! + //! Page table entries in x86_64 are a compacted combination of the relevant flags and the frame number. This mask + //! represents the bits that make up the frame number in an entry. + constexpr auto static frame_number_mask{0x000f'ffff'ffff'f000uz}; + + //! The raw entry bytes. + //! + //! @see entry::frame_number_mask + std::uint64_t m_raw{}; + }; + + //! The maximum number of entries in this table. + constexpr auto static entry_count{kapi::memory::page::size / kstd::units::bytes{sizeof(entry)}}; + + //! Get the entry at the given index. + //! + //! @warning This function will panic if the entry index is out of bounds. + //! + //! @param index The index of the desired entry. + //! @return A reference to the entry at the given index. + [[nodiscard]] auto operator[](std::size_t index) -> entry &; + + //! @copydoc page_table::operator[] + [[nodiscard]] auto operator[](std::size_t index) const -> entry const &; + + //! Clear the entire page table. + //! + //! This function effectively marks the page table as not mapping any pages. + auto clear() noexcept -> void; + + //! Check if the page table is empty. + //! + //! @return @p true iff. this page table has no entries marked present, @p false otherwise. + [[nodiscard]] auto empty() const noexcept -> bool; + + private: + std::array m_entries{}; + }; + +} // namespace arch::memory + +namespace kstd::ext +{ + template<> + struct is_bitfield_enum : std::true_type + { + }; +} // namespace kstd::ext + +namespace arch::memory +{ + + constexpr auto to_mapper_flags(page_table::entry::flags flags) -> kapi::memory::page_mapper::flags + { + using table_flags = page_table::entry::flags; + using mapper_flags = kapi::memory::page_mapper::flags; + + auto result = mapper_flags{}; + + if ((flags & table_flags::no_execute) == table_flags::empty) + { + result |= mapper_flags::executable; + } + + if ((flags & table_flags::writable) != table_flags::empty) + { + result |= mapper_flags::writable; + } + + if ((flags & (table_flags::disable_cache | table_flags::write_through)) != table_flags::empty) + { + result |= mapper_flags::uncached; + } + + if ((flags & table_flags::user_accessible) == table_flags::empty) + { + result |= mapper_flags::supervisor_only; + } + + if ((flags & table_flags::global) != table_flags::empty) + { + result |= mapper_flags::global; + } + + return result; + } + + constexpr auto to_table_flags(kapi::memory::page_mapper::flags flags) -> page_table::entry::flags + { + using table_flags = page_table::entry::flags; + using mapper_flags = kapi::memory::page_mapper::flags; + + auto result = table_flags{}; + + if ((flags & mapper_flags::executable) == mapper_flags::empty) + { + result |= table_flags::no_execute; + } + + if ((flags & mapper_flags::writable) != mapper_flags::empty) + { + result |= table_flags::writable; + } + + if ((flags & mapper_flags::uncached) != mapper_flags::empty) + { + result |= (table_flags::disable_cache | table_flags::write_through); + } + + if ((flags & mapper_flags::supervisor_only) == mapper_flags::empty) + { + result |= table_flags::user_accessible; + } + + if ((flags & mapper_flags::global) != mapper_flags::empty) + { + result |= table_flags::global; + } + + return result; + } + +} // namespace arch::memory + +#endif diff --git a/arch/x86_64/arch/memory/page_utilities.hpp b/arch/x86_64/arch/memory/page_utilities.hpp new file mode 100644 index 0000000..068e824 --- /dev/null +++ b/arch/x86_64/arch/memory/page_utilities.hpp @@ -0,0 +1,29 @@ +#ifndef TEACHOS_X86_64_PAGE_UTILITIES_HPP +#define TEACHOS_X86_64_PAGE_UTILITIES_HPP + +#include + +#include + +namespace arch::memory +{ + + constexpr auto inline pml_index(std::size_t index, kapi::memory::page page) noexcept -> std::size_t + { + constexpr auto bits_per_level = 9; + auto shift_width = (index - 1) * bits_per_level; + constexpr auto index_mask = 0x1ffuz; + return page.number() >> shift_width & index_mask; + } + + template + [[nodiscard]] constexpr auto to_higher_half_pointer(kapi::memory::physical_address address) -> ValueType * + { + using namespace kapi::memory; + auto const higher_half_address = higher_half_direct_map_base + address.raw(); + return static_cast(higher_half_address); + } + +} // namespace arch::memory + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/memory/region_allocator.cpp b/arch/x86_64/arch/memory/region_allocator.cpp new file mode 100644 index 0000000..4086a10 --- /dev/null +++ b/arch/x86_64/arch/memory/region_allocator.cpp @@ -0,0 +1,165 @@ +#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/arch/memory/region_allocator.hpp b/arch/x86_64/arch/memory/region_allocator.hpp new file mode 100644 index 0000000..5d9da2e --- /dev/null +++ b/arch/x86_64/arch/memory/region_allocator.hpp @@ -0,0 +1,93 @@ +#ifndef TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP +#define TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP + +#include +#include +#include + +#include + +#include +#include +#include + +namespace arch::memory +{ + //! A simple, memory-region based frame allocator. + //! + //! This frame allocator linearly allocates frames that are in available memory regions. It automatically skips any + //! frames occupied by the kernel image or any bootloader provided data. + //! + //! @note This allocator will never release frames. + struct region_allocator final : kapi::memory::frame_allocator + { + struct memory_information + { + //! The memory range occupied by the loaded kernel image. + //! + //! This includes all sections that are marked as occupying space in the kernel executable. The internal structure + //! of this area is more described in a more fine-grained manner by the ELF symbol information provided in the + //! Multiboot2 information by the loader. + std::pair image_range; + + //! The memory range occupied by the loader supplied Multiboot2 information structure. + //! + //! In general, this information is allocated somewhere in the range of the loaded image, but the loader protocol + //! does not guarantee this. It is thus imperative to be able to handle the cases where the loader chooses to + //! allocate the information structure outside of the image range. + std::pair mbi_range; + + //! The loader supplied map of memory regions. + //! + //! These include available, unavailable, and reclaimable regions. In general, only frames that are located in + //! non-reserved (as in available) regions should be allocated for page storage. + multiboot2::memory_map memory_map; + + //! The loader supplied Multiboot2 information structure. + //! + //! This is used to query boot module ranges so these frames can be excluded from early allocations. + multiboot2::information_view const * mbi; + }; + + using region = multiboot2::memory_map::region; + + //! Construct a new allocator using the provided memory information + //! + //! @param information The description of the detected memory regions as well as regions that are already occupied. + explicit region_allocator(memory_information const & information); + + //! @copydoc kapi::memory::frame_allocator::allocate_many + //! + //! @note As long as free frames are available, successive calls to this implementation are guaranteed to yield + //! frames in ascending order. + auto allocate_many(std::size_t count = 1) noexcept + -> std::optional> override; + + //! @copydoc kapi::memory::frame_allocator::mark_used + auto mark_used(kapi::memory::frame frame) -> void override; + + //! @copydoc kapi::memory::frame_allocator::release_many + //! + //! @note This implementation will never actually release any frames. + auto release_many(std::pair frame_set) -> void override; + + auto next_free_frame() noexcept -> std::optional; + + private: + //! Find the next memory area and write it into current_area. + auto choose_next_region() -> void; + auto find_next_frame() -> std::optional; + + kapi::memory::frame m_next_frame; //!< The next available frame. + std::optional m_current_region; //!< The memory region currently used for allocation + multiboot2::memory_map m_memory_map; //!< The boot loader supplied memory map. + kapi::memory::frame m_kernel_start; //!< The start of the kernel image in physical memory. + kapi::memory::frame m_kernel_end; //!< The end of the kernel image in physical memory. + kapi::memory::frame m_multiboot_start; //!< The start of the Multiboot2 information in physical memory. + kapi::memory::frame m_multiboot_end; //!< The end of the Multiboot2 information in physical memory. + multiboot2::information_view const * m_multiboot_information; //!< Source of Multiboot2 module ranges. + }; + +} // namespace arch::memory + +#endif diff --git a/arch/x86_64/arch/vga/crtc.hpp b/arch/x86_64/arch/vga/crtc.hpp new file mode 100644 index 0000000..a8bec93 --- /dev/null +++ b/arch/x86_64/arch/vga/crtc.hpp @@ -0,0 +1,35 @@ +#ifndef TEACHOS_X86_64_VGA_IO_HPP +#define TEACHOS_X86_64_VGA_IO_HPP + +#include + +#include + +namespace arch::vga::crtc +{ + /** + * @brief The address port of the CRT Controller. + */ + using address = io::port<0x3d4, std::byte, io::port_write>; + + /** + * @brief The data port of the CRT Controller. + */ + using data = io::port<0x3d5, std::byte, io::port_read, io::port_write>; + + namespace registers + { + /** + * @brief The address of the Cursor Start register of the CRTC. + */ + [[maybe_unused]] constexpr auto cursor_start = std::byte{0x0a}; + + /** + * @brief The address of the Cursor End register of the CRTC. + */ + [[maybe_unused]] constexpr auto cursor_end = std::byte{0x0b}; + } // namespace registers + +} // namespace arch::vga::crtc + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/vga/text.hpp b/arch/x86_64/arch/vga/text.hpp new file mode 100644 index 0000000..2e73dd2 --- /dev/null +++ b/arch/x86_64/arch/vga/text.hpp @@ -0,0 +1,10 @@ +#ifndef TEACHOS_X86_64_VGA_TEXT_HPP +#define TEACHOS_X86_64_VGA_TEXT_HPP + +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export + +#endif // TEACHOS_ARCH_X86_64_VIDEO_VGA_TEXT_HPP \ No newline at end of file diff --git a/arch/x86_64/arch/vga/text/attribute.hpp b/arch/x86_64/arch/vga/text/attribute.hpp new file mode 100644 index 0000000..6395aed --- /dev/null +++ b/arch/x86_64/arch/vga/text/attribute.hpp @@ -0,0 +1,30 @@ +#ifndef TEACHOS_X86_64_VGA_TEXT_ATTRIBUTE_HPP +#define TEACHOS_X86_64_VGA_TEXT_ATTRIBUTE_HPP + +// IWYU pragma: private, include + +#include +#include + +namespace arch::vga::text +{ + //! The VGA text mode attribute. + //! + //! @note In the text mode of VGA, every code point being presented is followed by an attribute description. This + //! allows for the modification of how the relevant "cell" is presented. + //! + //! @see text::foreground_flag + //! @see text::background_flag + struct attribute + { + color foreground_color : 3; ///< The foreground color of the cell, e.g. the color of the code point. + enum foreground_flag foreground_flag : 1; ///< The foreground color modification flag of the cell. + color background_color : 3; ///< The background color of the cell. + enum background_flag background_flag : 1; ///< The background color modification flag of the cell. + }; + + static_assert(sizeof(attribute) == 1, "The VGA text mode attribute must fit inside a single byte."); + +} // namespace arch::vga::text + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/vga/text/buffer.cpp b/arch/x86_64/arch/vga/text/buffer.cpp new file mode 100644 index 0000000..498b9a3 --- /dev/null +++ b/arch/x86_64/arch/vga/text/buffer.cpp @@ -0,0 +1,101 @@ +#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/arch/vga/text/buffer.hpp b/arch/x86_64/arch/vga/text/buffer.hpp new file mode 100644 index 0000000..8eb6645 --- /dev/null +++ b/arch/x86_64/arch/vga/text/buffer.hpp @@ -0,0 +1,101 @@ +#ifndef TEACHOS_X86_64_VGA_TEXT_BUFFER_HPP +#define TEACHOS_X86_64_VGA_TEXT_BUFFER_HPP + +// IWYU pragma: private, include + +#include + +#include +#include +#include +#include + +namespace arch::vga::text +{ + //! A VGA text buffer. + //! + //! VGA text mode presents a linear buffer of so-called cells. Each cell consists of a single code point and a + //! rendering attribute. The codepoint determines the character being rendered in a specific cell, while the attribute + //! determines the visual style of that cell. + //! + //! @see text::attribute + struct buffer + { + using cell = std::pair; + + //! Create a new buffer. + //! + //! @param width The width of the buffer + //! @param height The height of the buffer + //! @param start A pointer to the first byte of the buffer. + //! @param position The starting position for the first write to the buffer + buffer(std::size_t width, std::size_t height, cell * start, std::size_t position = 0); + + //! Clear the buffer. + //! + //! Clearing the buffer ensures it is filled with zeroes, effectively erasing all data and resetting the output + //! position to the start of the buffer. + auto clear() -> void; + + //! Write a string of formatted code points to the buffer. + //! + //! @param code_points A string of (8-bit) code points to write to the buffer. + //! @param attribute The formatting to apply to the written sequence of code points. + auto write(std::string_view code_points, attribute attribute) -> void; + + //! Write a single, formatted code point to the buffer. + //! + //! @param code_point A single (8-bit) code point + //! @param attribute The formatting to apply to the code point. + auto write(char code_point, attribute attribute) -> void; + + //! Move the output position to a new line and scroll the buffer if necessary. + auto newline() -> void; + + //! Scroll the buffer contents. + //! + //! @param nof_lines The number of lines to scroll up. + auto scroll(std::size_t nof_lines = 1) -> void; + + private: + //! Get column number of the current cell. + [[nodiscard]] auto column() const noexcept -> std::ptrdiff_t; + + //! Get the line number of the current cell. + [[nodiscard]] auto line() const noexcept -> std::ptrdiff_t; + + //! Process the semantics of special code points, for example newlines and carriage returns. + //! + //! @param code_point The code point to process. + //! @param attribute The attribute to use when writing to the text buffer. + //! @return @p true iff. the code point was handled, @p false otherwise. + auto handle_special_code_point(char code_point, attribute attribute) -> bool; + + //! Perform the actual output to the buffer. + //! + //! @param code_points The code points to output.. + //! @param attribute The attribute to use when writing to the text buffer. + auto do_write(std::string_view code_points, attribute attribute) -> void; + + //! Perform the actual output to the buffer. + //! + //! @param code_point The code point to output. + //! @param attribute The attribute to use when writing to the text buffer. + auto do_write(char code_point, attribute attribute) -> void; + + //! The width, in cells, of the buffer. + std::size_t m_width{}; + + //! The height, in cells, of the buffer. + std::size_t m_height{}; + + //! The text mode data buffer. + std::span m_buffer; + + //! The position of the next cell to be written to. + std::size_t m_position{}; + }; + +} // namespace arch::vga::text + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/vga/text/color.hpp b/arch/x86_64/arch/vga/text/color.hpp new file mode 100644 index 0000000..e0ad6df --- /dev/null +++ b/arch/x86_64/arch/vga/text/color.hpp @@ -0,0 +1,35 @@ +#ifndef TEACHOS_X86_64_VGA_TEXT_COLOR_HPP +#define TEACHOS_X86_64_VGA_TEXT_COLOR_HPP + +// IWYU pragma: private, include + +#include + +namespace arch::vga::text +{ + //! VGA Text Mode standard colors. + //! + //! Every color may be used as a foreground and/or background color, in any combination. + enum struct color : std::uint8_t + { + //! Equivalent to HTML color \#000000. + black, + //! Equivalent to HTML color \#0000AA. + blue, + //! Equivalent to HTML color \#00AA00. + green, + //! Equivalent to HTML color \#00AAAA. + cyan, + //! Equivalent to HTML color \#AA0000. + red, + //! Equivalent to HTML color \#AA00AA. + purple, + //! Equivalent to HTML color \#AA5500. + brown, + //! Equivalent to HTML color \#AAAAAA. + gray, + }; + +} // namespace arch::vga::text + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/vga/text/common_attributes.hpp b/arch/x86_64/arch/vga/text/common_attributes.hpp new file mode 100644 index 0000000..3d8929f --- /dev/null +++ b/arch/x86_64/arch/vga/text/common_attributes.hpp @@ -0,0 +1,37 @@ +#ifndef TEACHOS_X86_64_VGA_TEXT_COMMON_ATTRIBUTES_HPP +#define TEACHOS_X86_64_VGA_TEXT_COMMON_ATTRIBUTES_HPP + +// IWYU pragma: private, include + +#include +#include +#include + +namespace arch::vga::text +{ + //! Make the affected cell display with a gray foreground and black background. + [[maybe_unused]] constexpr auto gray_on_black = attribute{.foreground_color = color::gray, + .foreground_flag = foreground_flag::none, + .background_color = color::black, + .background_flag = background_flag::none}; + + //! Make the affected cell display with a green foreground and black background. + [[maybe_unused]] constexpr auto green_on_black = attribute{.foreground_color = color::green, + .foreground_flag = foreground_flag::none, + .background_color = color::black, + .background_flag = background_flag::none}; + + //! Make the affected cell display with a green foreground and black background. + [[maybe_unused]] constexpr auto red_on_black = attribute{.foreground_color = color::red, + .foreground_flag = foreground_flag::none, + .background_color = color::black, + .background_flag = background_flag::none}; + + //! Make the affected cell display with a white (gray + intense) foreground and red background. + [[maybe_unused]] constexpr auto white_on_red = attribute{.foreground_color = color::gray, + .foreground_flag = foreground_flag::intense, + .background_color = color::red, + .background_flag = background_flag::none}; +} // namespace arch::vga::text + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/vga/text/device.cpp b/arch/x86_64/arch/vga/text/device.cpp new file mode 100644 index 0000000..8468358 --- /dev/null +++ b/arch/x86_64/arch/vga/text/device.cpp @@ -0,0 +1,60 @@ +#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 diff --git a/arch/x86_64/arch/vga/text/device.hpp b/arch/x86_64/arch/vga/text/device.hpp new file mode 100644 index 0000000..0a0e017 --- /dev/null +++ b/arch/x86_64/arch/vga/text/device.hpp @@ -0,0 +1,45 @@ +#ifndef TEACHOS_X86_64_VGA_TEXT_DEVICE_HPP +#define TEACHOS_X86_64_VGA_TEXT_DEVICE_HPP + +// IWYU pragma: private, include + +#include + +#include + +#include + +namespace arch::vga::text +{ + //! A VGA Text Mode device. + //! + //! VGA text mode presents a linear buffer of so-called cells. Each cell consists of a single code point and a + //! rendering attribute. The codepoint determines the character being rendered in a specific cell, while the attribute + //! determines the visual style of that cell. + //! + //! @see text::attribute + struct device final : kapi::cio::output_device + { + device(); + + //! Clear the screen. + //! + //! Clearing the screen ensures the text mode buffer is filled with zeroes, effectively erasing all displayed data + //! and resetting the output position to the start of the buffer. + auto clear() -> void; + + //! Enable or disable the VGA text mode cursor. + //! + //! @param enabled Whether to enable the cursor. + auto cursor(bool enabled) -> void; + + //! @copydoc kapi::cio::output_device + auto write(kapi::cio::output_stream stream, std::string_view text) -> void override; + + private: + buffer m_buffer; + }; + +} // namespace arch::vga::text + +#endif \ No newline at end of file diff --git a/arch/x86_64/arch/vga/text/flags.hpp b/arch/x86_64/arch/vga/text/flags.hpp new file mode 100644 index 0000000..7a29e33 --- /dev/null +++ b/arch/x86_64/arch/vga/text/flags.hpp @@ -0,0 +1,38 @@ +#ifndef TEACHOS_X86_64_VGA_TEXT_FLAGS_HPP +#define TEACHOS_X86_64_VGA_TEXT_FLAGS_HPP + +// IWYU pragma: private, include + +namespace arch::vga::text +{ + + //! VGA Text Mode standard background modification flags. + enum struct background_flag : bool + { + //! Do not modify the foreground rendering. + none, + //! Render the background as blinking or intense. + //! + //! Whether this flag is interpreted as 'blink' or 'bright' depends on the currently active configuration of the VGA + //! device. + //! + //! @note The VGA standard does not specify the exact effect of this 'intense', however, most devices render such + //! colors brighter. + blink_or_bright, + }; + + //! VGA Text Mode standard foreground modification flags. + enum struct foreground_flag : bool + { + //! Do not modify the foreground rendering. + none, + //! Render the foreground as intense. + //! + //! @note The VGA standard does not specify the exact effect of this 'intense', however, most devices render such + //! colors brighter. + intense, + }; + +} // namespace arch::vga::text + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/boot/boot.hpp b/arch/x86_64/include/arch/boot/boot.hpp deleted file mode 100644 index 7df61c4..0000000 --- a/arch/x86_64/include/arch/boot/boot.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef TEACHOS_X86_64_BOOT_BOOT_HPP -#define TEACHOS_X86_64_BOOT_BOOT_HPP - -#ifdef __ASSEMBLER__ -// clang-format off - -//! The number of huge pages to map during bootstrap. -#define HUGE_PAGES_TO_MAP (16) - -//! The magic value to be set in eax by the multiboot 2 loader. -#define MULTIBOOT2_MAGIC (0x36d76289) - -//! The "A" bit in a GDT entry. -#define GDT_ACCESSED (1 << 40) - -//! The "R/W" bit in a GDT entry -#define GDT_READ_WRITE (1 << 41) - -//! The "E" bit in a GDT entry. -#define GDT_EXECUTABLE (1 << 43) - -//! The "S" bit in a GDT entry. -#define GDT_DESCRIPTOR_TYPE (1 << 44) - -//! The "P" bit in a GDT entry. -#define GDT_PRESENT (1 << 47) - -//! The "L" bit in a GDT entry. -#define GDT_LONG_MODE (1 << 53) - -// clang-format on -#else - -#include // IWYU pragma: export - -#include - -#include - -namespace kapi::boot -{ - - struct information - { - //! A pointer to the loader provided Multiboot2 Information structure. - multiboot2::information_view const * mbi; - - //! The index of the next character to be written in the VGA text buffer after handoff. - std::size_t vga_buffer_index; - }; - -} // namespace kapi::boot - -#endif - -#endif diff --git a/arch/x86_64/include/arch/boot/ld.hpp b/arch/x86_64/include/arch/boot/ld.hpp deleted file mode 100644 index 988723d..0000000 --- a/arch/x86_64/include/arch/boot/ld.hpp +++ /dev/null @@ -1,61 +0,0 @@ -//! @file -//! The interface to linker script defined symbols. -//! -//! This header provides declarations for symbols that are defined in the linker script itself. The symbols declared -//! here provide important information, for example the start and end of the kernel image in virtual and physical -//! memory. -//! -//! Any variables defined in this file must not be read themselves, but rather their address shall be taken, yielding a -//! pointer to the memory location the represent. -//! -//! @note The symbols declared in this header are declared using C-language linkage in order to suppress name mangling. -//! -//! @see arch/x86_64/scripts/kernel.ld - -#ifndef TEACHOS_X86_64_BOOT_LD_HPP -#define TEACHOS_X86_64_BOOT_LD_HPP - -#include - -namespace arch::boot -{ - - extern "C" - { - //! The beginning of the kernel image in physical memory - //! - //! This symbol marks the start of the kernel image in physical memory. - //! - //! @see _end_physical - extern std::byte _start_physical; - - //! The first byte after the loaded kernel image. - //! - //! This symbol marks the end of the kernel image in physical memory. - //! - //! @see _start_physical - extern std::byte _end_physical; - - //! The first byte of the loaded kernel image in the virtual address space. - //! - //! This symbol and marks the start of the kernel image in virtual memory. - //! - //! @see _end_virtual - extern std::byte _start_virtual; - - //! The first byte after the loaded kernel image in the virtual address space. - //! - //! This symbol marks the end of the kernel image in virtual memory. - //! - //! @see _start_virtual - extern std::byte _end_virtual; - - //! The first byte of the kernel's virtual address space. - //! - //! This symbol marks beginning of the kernel virtual address space. - extern std::byte TEACHOS_VMA; - } - -} // namespace arch::boot - -#endif diff --git a/arch/x86_64/include/arch/bus/isa.hpp b/arch/x86_64/include/arch/bus/isa.hpp deleted file mode 100644 index e56f56a..0000000 --- a/arch/x86_64/include/arch/bus/isa.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TEACHOS_X86_64_BUS_ISA_HPP -#define TEACHOS_X86_64_BUS_ISA_HPP - -#include - -#include - -namespace arch::bus -{ - - struct isa final : public kapi::devices::bus - { - isa(std::size_t major); - }; - -} // namespace arch::bus - -#endif // TEACHOS_X86_64_BUS_ISA_HPP diff --git a/arch/x86_64/include/arch/cpu/control_register.hpp b/arch/x86_64/include/arch/cpu/control_register.hpp deleted file mode 100644 index 9cedc35..0000000 --- a/arch/x86_64/include/arch/cpu/control_register.hpp +++ /dev/null @@ -1,249 +0,0 @@ -#ifndef TEACHOS_X86_64_CPU_CONTROL_REGISTERS_HPP -#define TEACHOS_X86_64_CPU_CONTROL_REGISTERS_HPP - -// IWYU pragma: private, include - -#include - -#include - -#include -#include -#include -#include - -namespace arch::cpu -{ - namespace impl - { - //! The assembler templates used to access (r/w) CR0; - constexpr auto static cr0_asm = std::pair{"mov %%cr0, %0", "mov %0, %%cr0"}; - - //! The assembler templates used to access (r/w) CR2; - constexpr auto static cr2_asm = std::pair{"mov %%cr2, %0", "mov %0, %%cr2"}; - - //! The assembler templates used to access (r/w) CR3; - constexpr auto static cr3_asm = std::pair{"mov %%cr3, %0", "mov %0, %%cr3"}; - } // namespace impl - - //! The flags that can be set on CR0 configuration register. - enum struct cr0_flags : uint64_t - { - //! Enable protected mode. - protection_enable = 1uz << 0, - //! Enable wait-monitoring of the coprocessor after task switching. - monitor_coprocessor = 1uz << 1, - //! Emulate floating point coprocessor. - emulation = 1uz << 2, - //! Marks that a task switch has occurred. - task_switched = 1uz << 3, - //! Marks Intel 387 DX math coprocessor as available - extension_type = 1uz << 4, - //! Numeric error handling mode. - numeric_error = 1uz << 5, - //! Disable writing to read-only marked memory. - write_protect = 1uz << 16, - //! Enable Ring-3 alignment checks - alignment_check = 1uz << 18, - //! Disable write through - not_write_through = 1uz << 29, - //! Disable caching of memory accesses - cache_disable = 1uz << 30, - //! Enable paging - paging = 1uz << 31 - }; - - enum struct cr3_flags : std::uint64_t - { - page_level_write_through = 1uz << 0, - page_level_cache_disable = 1uz << 1, - }; -} // namespace arch::cpu - -namespace kstd::ext -{ - template<> - struct is_bitfield_enum : std::true_type - { - }; - - template<> - struct is_bitfield_enum : std::true_type - { - }; -} // namespace kstd::ext - -namespace arch::cpu -{ - //! A mixin for flag-oriented control registers. - //! - //! This mixin provides additional functionality for flag-oriented, or partially flag-oriented, control registers. A - //! control register is flag-oriented, if it comprises a bitfield and zero or more additional non-bitfield parts. - //! - //! @tparam Derived The class deriving from this mixin. - //! @tparam ValueType The value type of the class deriving from this mixin. - template - struct control_register_with_flags - { - private: - constexpr control_register_with_flags() noexcept = default; - friend Derived; - }; - - //! @copydoc control_register_with_flags - //! - //! @note This specialization provides the implementation for the case in which the value type of the control register - //! is an enum. - template - struct control_register_with_flags>> - { - //! The type of the flags used by this control register - using flags = ValueType; - - //! Set one or more flags in this control register. - //! - //! @warning This function is to be considered **UNSAFE**. Setting flags in a control register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param value One or a combination of flags to be set in the control register. - auto static set(ValueType value) -> void - { - auto current = Derived::read(); - current |= value; - Derived::write(current); - } - - //! Clear one or more flags in this control register. - //! - //! @warning This function is to be considered **UNSAFE**. Clearing flags in a control register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param value One or a combination of flags to be cleared in the control register. - auto static clear(ValueType value) -> void - { - auto current = Derived::read(); - current &= ~value; - Derived::write(current); - } - }; - - //! A CPU control register. - //! - //! CPU control registers are used to configure builtin features of the CPU, for example memory protection and FPU - //! error reporting. Writing to a control register is inherently dangerous, since a misconfiguration can leave the CPU - //! in an invalid/undefined state. - template - struct control_register : control_register_with_flags, ValueType> - { - //! Read the current value of the control register. - //! - //! @return The currently set value of the control register. - [[nodiscard]] auto static read() -> ValueType - { - auto value = ValueType{}; - asm volatile((AssemblerTemplates->first) : "=r"(value)); - return value; - } - - //! Write a new value to the control register. - //! - //! @warning This function should be considered **UNSAFE**. Writing values to a control register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param value The new value to write to the control register. - auto static write(ValueType value) -> void - { - asm volatile((AssemblerTemplates->second) : : "r"(value)); - } - }; - - //! The value type of the CR3 control register. - //! - //! The CR3 control register holds the root configuration of the virtual memory protection mechanism. It contains the - //! page aligned physical address of the root page map, as well as the root paging configuration flags. - struct cr3_value - { - //! Contstruct a 0-value CR3 value. - constexpr cr3_value() = default; - - //! Construct a CR3 value using the given root page map address and flags. - //! - //! @param address The physical address of the root page map - //! @param flags The root configuration flags of the paging system. - constexpr cr3_value(kapi::memory::physical_address address, cr3_flags flags = static_cast(0)) - : m_flags{static_cast(flags)} - , m_address{static_cast(address.raw())} - {} - - //! Extract the physical address of the root page map from this value. - //! - //! @return The physical address of the root page map. - [[nodiscard]] constexpr auto address() const -> kapi::memory::physical_address - { - constexpr auto address_shift = 12uz; - return kapi::memory::physical_address{m_address << address_shift}; - } - - //! Encode the frame aligned physical address of the root page map into this value. - //! - //! @param frame The frame containing a PML4. - constexpr auto frame(kapi::memory::frame frame) -> void - { - m_address = static_cast(frame.number()); - } - - //! Extract the root paging configuration flags from this value. - //! - //! @return The root paging configuration flags. - [[nodiscard]] constexpr auto flags() const -> cr3_flags - { - return static_cast(m_flags); - } - - //! Encode the root paging configuration flags into this value. - //! - //! @param flags The root paging configuration flags. - constexpr auto flags(cr3_flags flags) -> void - { - m_flags = static_cast(flags); - } - - //! Add the given flags to the current set of encoded root configuration flags of this value. - //! - //! @param flags The root configuration flags to add. - //! @return A reference to this value. - constexpr auto operator|=(cr3_flags flags) -> cr3_value & - { - m_flags |= static_cast(flags); - return *this; - } - - //! Mask the root configuration flags of this value. - //! - //! @param mask The mask to apply to the root configuration flags. - //! @return A reference to this value. - constexpr auto operator&=(cr3_flags mask) -> cr3_value & - { - m_flags &= static_cast(mask); - return *this; - } - - private: - //! Reserved bits. - std::uint64_t : 3; - //! The root paging configuration flags. - std::uint64_t m_flags : 2 {}; - //! Reserved bits. - std::uint64_t : 7; - //! The page aligned physical address of the root page map. - std::uint64_t m_address : 52 {}; - }; - - static_assert(sizeof(cr3_value) == sizeof(std::uint64_t)); - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp b/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp deleted file mode 100644 index b17c509..0000000 --- a/arch/x86_64/include/arch/cpu/global_descriptor_table.hpp +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef TEACHOS_X86_64_GLOBAL_DESCRIPTOR_TABLE_HPP -#define TEACHOS_X86_64_GLOBAL_DESCRIPTOR_TABLE_HPP - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace arch::cpu -{ - - template - struct global_descriptor_table; - - struct [[gnu::packed]] global_descriptor_table_pointer - { - template - global_descriptor_table_pointer(global_descriptor_table const & gdt) - : size{GdtSize * sizeof(segment_descriptor) - 1} - , address{kapi::memory::physical_address{std::bit_cast(&gdt)}.raw()} - {} - - auto load() -> void - { - asm volatile("lgdt %0" : : "m"(*this)); - } - - std::uint16_t size{}; - std::uint64_t address{}; - }; - - static_assert(sizeof(global_descriptor_table_pointer) == sizeof(std::uint16_t) + sizeof(std::uint64_t)); - - template - struct global_descriptor_table - { - template... SegmentDescriptors> - constexpr global_descriptor_table(SegmentDescriptors const &... descriptors) - : m_descriptors{} - { - auto descriptor_data = std::array{ - std::pair{std::bit_cast(&descriptors), sizeof(descriptors)} - ... - }; - auto written_size = 0uz; - std::ranges::for_each(descriptor_data, [&written_size, this](auto entry) { - std::ranges::copy(entry.first, entry.first + entry.second, m_descriptors.begin() + written_size); - written_size += entry.second; - }); - } - - auto load(std::size_t code_segment_index, std::size_t data_segment_index) const -> void - { - auto pointer = global_descriptor_table_pointer{*this}; - pointer.load(); - - asm volatile("push %0\n" - "lea 1f(%%rip), %%rax\n" - "push %%rax\n" - "lretq\n" - "1:\n" - "mov %1, %%rax\n" - "mov %%rax, %%ss\n" - "mov %%rax, %%ds\n" - "mov %%rax, %%es\n" - "mov %%rax, %%fs\n" - "mov %%rax, %%gs\n" - : - : "X"(code_segment_index * sizeof(segment_descriptor)), - "X"(data_segment_index * sizeof(segment_descriptor)) - : "rax"); - } - - private: - std::array m_descriptors; - }; - - template... SegmentDescriptors> - global_descriptor_table(SegmentDescriptors const &... descriptors) - -> global_descriptor_table<(sizeof(SegmentDescriptors) + ...)>; - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/initialization.hpp b/arch/x86_64/include/arch/cpu/initialization.hpp deleted file mode 100644 index 564c544..0000000 --- a/arch/x86_64/include/arch/cpu/initialization.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CPU_INITIALIZATION_HPP -#define TEACHOS_ARCH_X86_64_CPU_INITIALIZATION_HPP - -namespace arch::cpu -{ - auto initialize_descriptors() -> void; - - auto initialize_legacy_interrupts() -> void; - -} // namespace arch::cpu - -#endif diff --git a/arch/x86_64/include/arch/cpu/interrupts.hpp b/arch/x86_64/include/arch/cpu/interrupts.hpp deleted file mode 100644 index 6162f56..0000000 --- a/arch/x86_64/include/arch/cpu/interrupts.hpp +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef TEACHOS_X86_64_CPU_INTERRUPTS_HPP -#define TEACHOS_X86_64_CPU_INTERRUPTS_HPP - -#include - -#include - -#include -#include -#include - -namespace arch::cpu -{ - - //! The types of supported gates. - enum struct gate_type : std::uint8_t - { - //! A gate entered through the @p INT instruction. - interrupt_gate = 0b1110, - //! A gate entered via an exception. - trap_gate = 0b1111, - }; - - struct alignas(std::uint64_t) gate_descriptor - { - //! The lowest 16 bits of the address of this gate's handler function. - std::uint16_t offset_low : 16; - //! The code segment used when handling the respective interrupt. - segment_selector m_code_segment; - //! The index into the Interrupt Stack Table naming the stack to use. - std::uint8_t interrupt_stack_table_selector : 3; - //! Reserved - std::uint8_t : 5; - //! The type of this gate. - enum gate_type gate_type : 4; - //! Reserved - std::uint8_t : 1; - //! The privilege level required to enter through this gate. - std::uint8_t descriptor_privilege_level : 2; - //! Whether this gate is present or not. - std::uint8_t present : 1; - //! The middle 16 bits of the address of this gate's handler function. - std::uint16_t offset_middle : 16; - //! The highest 32 bits of the address of this gate's handler function. - std::uint32_t offset_high : 32; - //! Reserved - std::uint32_t : 32; - }; - - static_assert(sizeof(gate_descriptor) == 2 * sizeof(std::uint64_t)); - static_assert(std::is_aggregate_v); - - //! The stack frame as established by the low-level assembly interrupt stubs. - //! - //! @note The layout of this struct is reverse than what would reasonably be expected. The reason for this reversal is - //! that fact that it represents a stack frame. Stack frames on x86_64 grow towards lower addresses, meaning the first - //! item on the stack is the last item in C++ memory layout order. - struct interrupt_frame - { - struct - { - std::uint64_t r15{}; - std::uint64_t r14{}; - std::uint64_t r13{}; - std::uint64_t r12{}; - std::uint64_t r11{}; - std::uint64_t r10{}; - std::uint64_t r9{}; - std::uint64_t r8{}; - std::uint64_t rdi{}; - std::uint64_t rsi{}; - std::uint64_t rbp{}; - std::uint64_t rdx{}; - std::uint64_t rcx{}; - std::uint64_t rbx{}; - std::uint64_t rax{}; - } handler_saved; - - struct - { - std::uint64_t number{}; - std::uint64_t error_code{}; - } interrupt; - - struct - { - kapi::memory::linear_address rip{}; - std::uint64_t cs{}; - std::uint64_t rflags{}; - kapi::memory::linear_address rsp{}; - std::uint64_t ss{}; - } cpu_saved; - }; - - struct interrupt_descriptor_table - { - interrupt_descriptor_table() noexcept; - - auto load() const -> void; - - private: - std::array m_descriptors{}; - }; - - struct [[gnu::packed]] interrupt_descriptor_table_register - { - std::uint16_t limit; - gate_descriptor const * base; - - auto load() const -> void; - auto static read() -> interrupt_descriptor_table_register; - }; - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/legacy_pic.hpp b/arch/x86_64/include/arch/cpu/legacy_pic.hpp deleted file mode 100644 index 56ca9c4..0000000 --- a/arch/x86_64/include/arch/cpu/legacy_pic.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef TEACHOS_X86_64_CPU_LEGACY_PIC_HPP -#define TEACHOS_X86_64_CPU_LEGACY_PIC_HPP - -#include - -#include - -namespace arch::cpu -{ - 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_end_of_interrupt = std::uint8_t{0x20}; - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/model_specific_register.hpp b/arch/x86_64/include/arch/cpu/model_specific_register.hpp deleted file mode 100644 index bd4aff9..0000000 --- a/arch/x86_64/include/arch/cpu/model_specific_register.hpp +++ /dev/null @@ -1,151 +0,0 @@ -#ifndef TEACHOS_X86_64_CPU_MODEL_SPECIFIC_REGISTER_HPP -#define TEACHOS_X86_64_CPU_MODEL_SPECIFIC_REGISTER_HPP - -// IWYU pragma: private, include - -#include - -#include -#include -#include - -namespace arch::cpu -{ - - //! The flags of the IA32_EFER (Extended Features Enable Register) MSR. - enum struct ia32_efer_flags : std::uint64_t - { - //! Enable the syscall and sysret instructions. - syscall_enable = 1uz << 0, - //! Enable IA-32e mode operation. - ia32e_mode_enable = 1uz << 8, - //! Indicates IA-32e mode is active (read-only) - ia32e_mode_active = 1uz << 10, - //! Enable the use of the NX page table bit. - execute_disable_bit_enable = 1uz << 11, - }; - -} // namespace arch::cpu - -namespace kstd::ext -{ - - template<> - struct is_bitfield_enum : std::true_type - { - }; - -} // namespace kstd::ext - -namespace arch::cpu -{ - //! The MSR number for the IA32_EFER MSR - constexpr auto ia32_efer_number = 0xC000'0080u; - - //! A mixin for flag-oriented model specific registers. - //! - //! This mixin provides additional functionality for a flag-oriented model specific register. A models specific - //! register is flag-oriented, if it comprises a single field of bitfield. - //! - //! @tparam Derived The class deriving from this mixin. - //! @tparam ValueType The value type of the class deriving from this mixin. - template - struct model_specific_register_with_flags - { - private: - constexpr model_specific_register_with_flags() noexcept = default; - friend Derived; - }; - - //! @copydoc model_specific_register_with_flags - //! - //! @note This specialization provides the implementation for the case in which the value type of the model specific - //! register is a bitfield enum. - template - struct model_specific_register_with_flags>> - { - //! The of the flags used by this model specific register. - using flags = ValueType; - - //! Set one or more flags in this model specific register. - //! - //! @warning This function is to be considered **UNSAFE**. Setting flags in a model specific register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param flag One or a combination of flags to be set in the model specific register. - auto static set(flags flag) -> void - { - auto current = Derived::read(); - current |= flag; - Derived::write(current); - } - - //! Clear one or more flags in this model specific register. - //! - //! @warning This function is to be considered **UNSAFE**. Clearing flags in a model specific register may lead to - //! unexpected CPU behavior if the prerequisites imposed by the CPU specification are not fulfilled. This function - //! will perform no additional checks, and may, by extension, crash the system. - //! - //! @param flag One or a combination of flags to be cleared in the model specific register. - auto static clear(flags flag) -> void - { - auto current = Derived::read(); - current &= ~flag; - Derived::write(current); - } - - //! Test one or more flags in this model specific register - //! - //! @param flag One or a combination of flags to test for. - auto test(flags flag) -> flags - { - return Derived::read() & flag; - } - }; - - //! A model specific register (MSR) - //! - //! Model specific register are used to configure CPU features that a not necessarily present on all CPUs generations. - //! In the past, some MSRs have been defined to be architectural, meaning all CPUs of a given architecture (x86-64 in - //! this case) support them. Writing to a MSR is inherently dangerous, since a misconfiguration cal leave the CPU in - //! an invalid/undefined state. - //! - //! @tparam Number The register number of this MSR - //! @tparam ValueType The value type of this MSR - template - struct model_specific_register - : model_specific_register_with_flags, ValueType> - { - //! A raw MSR value, comprising two halfs. - //! - //! MSRs have been 64-bit in size even in the 32-bit intel architecture, and are thus written in two halfs. - struct raw_value - { - std::uint32_t low_half; //!< The lower half of the register value - std::uint32_t high_half; //!< The upper half of the register value - }; - - //! Read the current value of this MSR. - //! - //! @return The current value of this MSR. - auto static read() -> ValueType - { - auto raw = raw_value{}; - asm volatile("rdmsr" : "=a"(raw.low_half), "=d"(raw.high_half) : "c"(Number)); - return static_cast(std::bit_cast(raw)); - } - - //! Write a new value to this MSR. - //! - //! @param value The new value for this MSR. - auto static write(ValueType value) -> void - { - auto raw = std::bit_cast(static_cast(value)); - asm volatile("wrmsr" : : "a"(raw.low_half), "d"(raw.high_half), "c"(Number)); - } - }; - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/registers.hpp b/arch/x86_64/include/arch/cpu/registers.hpp deleted file mode 100644 index 58633f6..0000000 --- a/arch/x86_64/include/arch/cpu/registers.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef TEACHOS_X86_64_CPU_REGISTERS_HPP -#define TEACHOS_X86_64_CPU_REGISTERS_HPP - -#include // IWYU pragma: export -#include // IWYU pragma: export - -#include - -namespace arch::cpu -{ - - //! Configuration Register 0. - //! - //! This configuration register holds various control flags to configure the configure the basic operation of the CPU. - using cr0 = control_register; - - //! Configuration Register 2. - //! - //! This configuration register holds the memory address the access to which has triggered the most recent page fault. - using cr2 = control_register; - - //! Configuration Register 3. - //! - //! This register holds the configuration of the virtual memory protection configuration. - using cr3 = control_register; - - //! The I32_EFER (Extended Feature Enable Register) MSR - using i32_efer = model_specific_register; - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/segment_descriptor.hpp b/arch/x86_64/include/arch/cpu/segment_descriptor.hpp deleted file mode 100644 index 9570670..0000000 --- a/arch/x86_64/include/arch/cpu/segment_descriptor.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef TEACHOS_X86_64_SEGMENT_DESCRIPTOR_HPP -#define TEACHOS_X86_64_SEGMENT_DESCRIPTOR_HPP - -#include - -namespace arch::cpu -{ - - //! The type of segment described by a segment_descriptor. - enum struct segment_type : std::uint8_t - { - //! A system (TSS or LDT) segment - system = 0, - //! A code or data segment - code_or_data = 1, - }; - - //! The granularity of a segment described by a segment_descriptor - enum struct segment_granularity : std::uint8_t - { - //! The limit of the segment is defined in bytes. - byte = 0, - //! The limit of the segment is defined in pages (4KiB) - page = 1, - }; - - //! An entry in a segment descriptor table - struct segment_descriptor - { - std::uint64_t limit_low : 16; - std::uint64_t base_low : 24; - bool accessed : 1; - bool read_write : 1; - bool direction_or_conforming : 1; - bool executable : 1; - segment_type type : 1; - std::uint64_t privilege_level : 2; - bool present : 1; - std::uint64_t limit_high : 4; - std::uint64_t : 1; - bool long_mode : 1; - bool protected_mode : 1; - segment_granularity granularity : 1; - std::uint64_t base_high : 8; - }; - - static_assert(sizeof(segment_descriptor) == sizeof(std::uint64_t)); - static_assert(alignof(segment_descriptor) == alignof(std::uint64_t)); - - struct system_segment_descriptor : segment_descriptor - { - std::uint64_t base_extended : 32; - std::uint64_t : 32; - }; - - static_assert(sizeof(system_segment_descriptor) == 2 * sizeof(std::uint64_t)); - static_assert(alignof(system_segment_descriptor) == alignof(segment_descriptor)); - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/segment_selector.hpp b/arch/x86_64/include/arch/cpu/segment_selector.hpp deleted file mode 100644 index 1a78c47..0000000 --- a/arch/x86_64/include/arch/cpu/segment_selector.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef TEACHOS_X86_64_SEGMENT_SELECTOR_HPP -#define TEACHOS_X86_64_SEGMENT_SELECTOR_HPP - -#include - -namespace arch::cpu -{ - - struct segment_selector - { - std::uint16_t request_privilege_level : 2; - bool use_local_descriptor_table : 1; - std::uint16_t table_index : 13; - }; - - static_assert(sizeof(segment_selector) == sizeof(std::uint16_t)); - static_assert(alignof(segment_selector) == alignof(std::uint16_t)); - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/cpu/task_state_segment.hpp b/arch/x86_64/include/arch/cpu/task_state_segment.hpp deleted file mode 100644 index 57729dd..0000000 --- a/arch/x86_64/include/arch/cpu/task_state_segment.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef TEACHOS_X86_64_TASK_STATE_SEGMENT_HPP -#define TEACHOS_X86_64_TASK_STATE_SEGMENT_HPP - -#include - -namespace arch::cpu -{ - - struct [[gnu::packed]] task_state_segment - { - uint32_t : 32; - uint64_t rsp0 = {}; - uint64_t rsp1 = {}; - uint64_t rsp2 = {}; - uint64_t : 64; - uint64_t ist1 = {}; - uint64_t ist2 = {}; - uint64_t ist3 = {}; - uint64_t ist4 = {}; - uint64_t ist5 = {}; - uint64_t ist6 = {}; - uint64_t ist7 = {}; - uint64_t : 64; - uint16_t : 16; - uint16_t io_map_base_address = {}; - }; - -} // namespace arch::cpu - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/debug/qemu_output.hpp b/arch/x86_64/include/arch/debug/qemu_output.hpp deleted file mode 100644 index 5ddd4be..0000000 --- a/arch/x86_64/include/arch/debug/qemu_output.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef TEACHOS_X86_64_DEBUG_QEMU_OUTPUT_HPP -#define TEACHOS_X86_64_DEBUG_QEMU_OUTPUT_HPP - -#include - -#include - -#include - -namespace arch::debug -{ - - //! A QEMU debug console output device. - //! - //! This device implements output to the port 0xE9 debug console present in QEMU in Bochs. It is designed to wrap a - //! different output device (e.g. a VGA text output device) and forwards the written data accordingly. - //! - //! @note Support for the device has to be enabled when the emulator is started. The device will try to detect if the - //! port is available. If the port is detected, any output to the device will be written to port before being - //! forwarded to the lower device. - struct qemu_output : kapi::cio::output_device - { - //! The port to write to. - using port = io::port<0xE9, unsigned char, io::port_write, io::port_read>; - - //! Construct a new debug device wrapper for the given output device. - //! - //! @param lower The device to forward the output to. - explicit qemu_output(output_device & lower); - - //! @copydoc kapi::cio::output_device - auto write(kapi::cio::output_stream stream, std::string_view text) -> void override; - - private: - //! The device to forward the output to. - output_device & m_lower; - //! Whether the device has been detected. - bool m_present; - }; - -} // namespace arch::debug - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/device_io/port_io.hpp b/arch/x86_64/include/arch/device_io/port_io.hpp deleted file mode 100644 index 4c8d66a..0000000 --- a/arch/x86_64/include/arch/device_io/port_io.hpp +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef TEACHOS_X86_64_IO_PORT_IO_HPP -#define TEACHOS_X86_64_IO_PORT_IO_HPP - -#include -#include -#include -#include -#include -#include - -namespace arch::io -{ - - //! The requirements imposed on a type usable for port I/O. - template - concept port_io_type = requires { - requires sizeof(ValueType) == 1 || sizeof(ValueType) == 2 || sizeof(ValueType) == 4; - requires std::default_initializable; - std::bit_cast( - std::conditional_t>{}); - }; - - template - struct port_read - { - //! Read from the I/O port. - //! - //! @return The data read from the I/O port. - auto static read() noexcept - { - auto data = typename Derived::value_type{}; - asm volatile((code[Derived::size / 2]) - : [data] "=m"(data) - : [port] "i"(Derived::address) - : "dx", (Derived::data_register)); - return data; - } - - private: - constexpr port_read() noexcept = default; - friend Derived; - - //! The assembly templates used for reading from an I/O port. - constexpr auto static code = std::array{ - std::string_view{"mov %[port], %%dx\nin %%dx, %%al\nmov %%al, %[data]"}, - std::string_view{"mov %[port], %%dx\nin %%dx, %%ax\nmov %%ax, %[data]"}, - std::string_view{"mov %[port], %%dx\nin %%dx, %%eax\nmov %%eax, %[data]"}, - }; - }; - - template - struct port_write - { - //! Write data to the I/O port. - //! - //! @param data The data to write to the I/O port. - auto static write(std::same_as auto data) noexcept -> void - { - asm volatile((code[Derived::size / 2]) - : - : [port] "i"(Derived::address), [data] "im"(data) - : "dx", (Derived::data_register)); - } - - private: - constexpr port_write() noexcept = default; - friend Derived; - - //! The assembly templates used for writing to an I/O port. - constexpr auto static code = std::array{ - std::string_view{"mov %[port], %%dx\nmov %[data], %%al\nout %%al, %%dx"}, - std::string_view{"mov %[port], %%dx\nmov %[data], %%ax\nout %%ax, %%dx"}, - std::string_view{"mov %[port], %%dx\nmov %[data], %%eax\nout %%eax, %%dx"}, - }; - }; - - //! An I/O port of a given size at a given address. - //! - //! Port I/O leverages a separate address space to communicate with devices via the memory bus, allowing for byte - //! to double-word sized transfers. - //! - //! @tparam Address The address (port number) of the I/O port. - //! @tparam Size The size (in bytes) of the I/O port. - //! @tparam Features The features (readable, writeable) - template typename... Features> - requires(sizeof...(Features) > 0) - struct port : Features>... - { - //! The type of the data of this port. - using value_type = ValueType; - - //! The address of this I/O port. - constexpr auto static address = Address; - - //! The size of this I/O port. - constexpr auto static size = sizeof(value_type); - - //! The register clobbered by the I/O operation. - constexpr auto static data_register = size == 1 ? std::string_view{"al"} - : size == 2 ? std::string_view{"ax"} - : std::string_view{"eax"}; - }; - - auto inline wait() -> void - { - port<0x80, std::uint8_t, port_write>::write(0); - } - -} // namespace arch::io - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/devices/init.hpp b/arch/x86_64/include/arch/devices/init.hpp deleted file mode 100644 index c5fbf37..0000000 --- a/arch/x86_64/include/arch/devices/init.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_DEVICES_INIT_HPP -#define TEACHOS_ARCH_X86_64_DEVICES_INIT_HPP - -namespace arch::devices -{ - - auto init_acpi_devices() -> void; - auto init_legacy_devices() -> void; - -} // namespace arch::devices - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/devices/legacy_pit.hpp b/arch/x86_64/include/arch/devices/legacy_pit.hpp deleted file mode 100644 index 356895c..0000000 --- a/arch/x86_64/include/arch/devices/legacy_pit.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP -#define TEACHOS_ARCH_X86_64_DEVICES_LEGACY_PIT_HPP - -#include -#include - -#include -#include - -namespace arch::devices -{ - - struct legacy_pit : kapi::devices::device, kapi::interrupts::handler - { - legacy_pit(std::size_t major, std::uint32_t frequency_in_hz); - - auto init() -> bool override; - - auto handle_interrupt(std::uint32_t irq_number) -> kapi::interrupts::status override; - - private: - std::uint32_t m_irq_number{}; - std::uint32_t m_frequency_in_hz{}; - std::uint64_t m_ticks{}; - }; - -} // namespace arch::devices - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/devices/local_apic.hpp b/arch/x86_64/include/arch/devices/local_apic.hpp deleted file mode 100644 index f8f080d..0000000 --- a/arch/x86_64/include/arch/devices/local_apic.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP -#define TEACHOS_ARCH_X86_64_DEVICES_LOCAL_APIC_HPP - -#include -#include - -#include -#include - -namespace arch::devices -{ - - struct local_apic : kapi::devices::device - { - local_apic(std::size_t major, std::size_t minor, std::uint64_t hardware_id, kapi::memory::physical_address base, - bool is_bsp); - - auto init() -> bool override; - - private: - enum struct registers : std::ptrdiff_t; - - [[nodiscard]] auto read_register(registers id) const -> std::uint32_t; - auto write_register(registers id, std::uint32_t value) -> void; - - std::uint64_t m_hardware_id{}; - kapi::memory::physical_address m_base{}; - kapi::memory::mmio_region m_mapped_region{}; - bool m_is_bsp{}; - std::uint8_t m_version{}; - std::uint8_t m_highest_lvt_entry_index{}; - bool m_supports_eoi_broadcast_suppression{}; - }; - -} // namespace arch::devices - -#endif diff --git a/arch/x86_64/include/arch/memory/higher_half_mapper.hpp b/arch/x86_64/include/arch/memory/higher_half_mapper.hpp deleted file mode 100644 index 9b02ee6..0000000 --- a/arch/x86_64/include/arch/memory/higher_half_mapper.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef TEACHOS_X86_64_HIGHER_HALF_MAPPER_HPP -#define TEACHOS_X86_64_HIGHER_HALF_MAPPER_HPP - -#include - -#include - -#include - -namespace arch::memory -{ - - //! A simple page mapper making use of a Higher Half Direct Map (HHDM) to access and modify page tables. - struct higher_half_mapper : kapi::memory::page_mapper - { - //! Construct a new mapper for a hierarchy rooted in the given PML. - //! - //! @param root The root of the hierarchy to operate on. - explicit higher_half_mapper(page_table * root); - - //! @copydoc kapi::memory::page_mapper::map - auto map(kapi::memory::page page, kapi::memory::frame frame, flags flags) -> std::byte * override; - - //! @copydoc kapi::memory::page_mapper::unmap - auto unmap(kapi::memory::page page) -> void override; - - //! @copydoc kapi::memory::page_mapper::try_unmap - auto try_unmap(kapi::memory::page page) noexcept -> bool override; - - private: - //! Try to retrieve the the PML1 responsible for mapping this page, creating one if necessary. - //! - //! This function will create a page table hierarchy leading to the target PML1 if it doesn't exist. - //! - //! @param page The page to get the PML1 for. - //! @return The PML1 that manages the given page, nullptr it the system runs out of memory. - auto get_or_create_page_table(kapi::memory::page page) noexcept -> page_table *; - - page_table * m_root; - }; - -} // namespace arch::memory - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/kernel_mapper.hpp deleted file mode 100644 index adbf688..0000000 --- a/arch/x86_64/include/arch/memory/kernel_mapper.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef TEACHOS_X86_64_KERNEL_MAPPER_HPP -#define TEACHOS_X86_64_KERNEL_MAPPER_HPP - -#include - -#include -#include - -#include - -#include -#include - -namespace arch::memory -{ - - struct kernel_mapper - { - using section_header_type = elf::section_header; - - explicit kernel_mapper(multiboot2::information_view const * mbi); - - auto remap_kernel(kapi::memory::page_mapper & mapper) -> void; - - private: - auto map_section(section_header_type const & section, std::string_view name, kapi::memory::page_mapper & mapper) - -> void; - - multiboot2::information_view const * m_mbi; - std::uintptr_t m_kernel_load_base; - }; - -} // namespace arch::memory - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/mmu.hpp b/arch/x86_64/include/arch/memory/mmu.hpp deleted file mode 100644 index 64373f4..0000000 --- a/arch/x86_64/include/arch/memory/mmu.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TEACHOS_X86_64_MEMORY_MMU_HPP -#define TEACHOS_X86_64_MEMORY_MMU_HPP - -#include - -namespace arch::memory -{ - /** - * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained - * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. - * - * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for - * that page. - */ - auto tlb_flush(kapi::memory::linear_address address) -> void; - - /** - * @brief Invalidates the translation lookaside buffer (TLB) entry for all page tables. - * - * @note Simply reassigns the CR3 register the value of the CR3 register, causing a flush of the TLB buffer, because - * the system has to assume that the location of the level 4 page table moved. - */ - auto tlb_flush_all() -> void; - -} // namespace arch::memory - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/page_table.hpp b/arch/x86_64/include/arch/memory/page_table.hpp deleted file mode 100644 index ce3d3a1..0000000 --- a/arch/x86_64/include/arch/memory/page_table.hpp +++ /dev/null @@ -1,232 +0,0 @@ -#ifndef TEACHOS_X86_64_PAGE_TABLE_HPP -#define TEACHOS_X86_64_PAGE_TABLE_HPP - -#include - -#include -#include - -#include -#include -#include -#include -#include - -namespace arch::memory -{ - - //! A table containing page mapping entries. - //! - //! Page tables exist in a multi-level hierarchy and are used to map pages (virtual memory) onto frames (physical - //! memory). Conceptually, pages represent the data found in a virtual address space, while frames represent their - //! storage. In most cases, only a level 1 page table maps an actual page onto a frame. All other page tables on - //! higher levels do not map payload pages, but rather their subordinate page tables. The only exception to that rule - //! is the use of huge pages. - struct page_table - { - //! An entry in a page table. - //! - //! A page table entry is a combination of a frame number and a set of flags that determine the properties and - //! access rights to a mapped page. Entries at a higher level in the page hierarchy do not map a page directly, - //! unless that page is marked as huge on the relevant level, but rather map the next lower page table. - struct entry - { - //! Flags marking the state and configuration of an entry. - //! - //! An entry in a page table may have any combination of these flags active at the same time. The final flags of a - //! page are determined as the strictest combination (logical AND) of all flags along the hierarchy. - //! - //! @note This is a bitfield enum as defined by kstd::ext::bitfield_enum. - enum struct flags : std::uint64_t - { - empty = 0, - present = 1uz << 0, //!< The page is mapped. - writable = 1uz << 1, //!< The page is writable. - user_accessible = 1uz << 2, //!< The page is accessible in user mode. - write_through = 1uz << 3, //!< Any writes to the page must immediately hit memory. - disable_cache = 1uz << 4, //!< Any writes to the page must never be cached. - accessed = 1uz << 5, //!< The page was accessed. - dirty = 1uz << 6, //!< The page was written to. - huge_page = 1uz << 7, //!< The page is huge. - global = 1uz << 8, //!< The TLB entry for this page must not be flushed on context switches. - no_execute = 1uz << 63, //!< The data in this page must not be executed. - }; - - //! Construct an empty entry. - entry() = default; - - //! Clear this entry, ensuring all information is set to zero. - //! - //! This effectively marks the page represented by this entry as not present. In addition, it also removes any - //! information about the frame referenced by this entry. - auto clear() noexcept -> void; - - //! Check if the page represented by this entry is present. - //! - //! @note This function does not attempt to walk the page table hierarchy, but only performs a local check. This - //! means, that if the page is not mapped at a lower level, this will not be detected. - //! - //! @return @p true iff. the page is present at this level, @p false otherwise. - [[nodiscard]] auto present() const noexcept -> bool; - - //! Check if the page represented by this entry is a huge page. - //! - //! @note The effective size of the page depends on the level of the page table containing this entry. - //! - //! @return @p true iff. the page is marked as being huge, @p false otherwise. - [[nodiscard]] auto huge() const noexcept -> bool; - - //! Get all flags present in this entry. - //! - //! @return The flags that are currently set on this entry. - [[nodiscard]] auto all_flags() const noexcept -> flags; - - //! Set all flags of this entry. - //! - //! @param flags The flags to apply to this entry. - auto all_flags(flags flags) noexcept -> void; - - //! Add the given flags to the flags of this entry. - //! - //! @param rhs The flags to add to this entry's flags. - //! @return A reference to this entry. - auto operator|=(flags rhs) noexcept -> entry &; - - //! Get the frame number associated with this entry, if the referenced page is present. - //! - //! @return an engaged std::optional iff. this entry maps a page, std::nullopt otherwise. - [[nodiscard]] auto frame() const noexcept -> std::optional; - - //! Map this entry. - //! - //! @param frame The frame to map in this entry. - //! @param flags The flags to apply to this entry. - auto frame(kapi::memory::frame frame, flags flags) noexcept -> void; - - private: - //! A mask to retrieve, or exclude, the frame number from the raw entry. - //! - //! Page table entries in x86_64 are a compacted combination of the relevant flags and the frame number. This mask - //! represents the bits that make up the frame number in an entry. - constexpr auto static frame_number_mask{0x000f'ffff'ffff'f000uz}; - - //! The raw entry bytes. - //! - //! @see entry::frame_number_mask - std::uint64_t m_raw{}; - }; - - //! The maximum number of entries in this table. - constexpr auto static entry_count{kapi::memory::page::size / kstd::units::bytes{sizeof(entry)}}; - - //! Get the entry at the given index. - //! - //! @warning This function will panic if the entry index is out of bounds. - //! - //! @param index The index of the desired entry. - //! @return A reference to the entry at the given index. - [[nodiscard]] auto operator[](std::size_t index) -> entry &; - - //! @copydoc page_table::operator[] - [[nodiscard]] auto operator[](std::size_t index) const -> entry const &; - - //! Clear the entire page table. - //! - //! This function effectively marks the page table as not mapping any pages. - auto clear() noexcept -> void; - - //! Check if the page table is empty. - //! - //! @return @p true iff. this page table has no entries marked present, @p false otherwise. - [[nodiscard]] auto empty() const noexcept -> bool; - - private: - std::array m_entries{}; - }; - -} // namespace arch::memory - -namespace kstd::ext -{ - template<> - struct is_bitfield_enum : std::true_type - { - }; -} // namespace kstd::ext - -namespace arch::memory -{ - - constexpr auto to_mapper_flags(page_table::entry::flags flags) -> kapi::memory::page_mapper::flags - { - using table_flags = page_table::entry::flags; - using mapper_flags = kapi::memory::page_mapper::flags; - - auto result = mapper_flags{}; - - if ((flags & table_flags::no_execute) == table_flags::empty) - { - result |= mapper_flags::executable; - } - - if ((flags & table_flags::writable) != table_flags::empty) - { - result |= mapper_flags::writable; - } - - if ((flags & (table_flags::disable_cache | table_flags::write_through)) != table_flags::empty) - { - result |= mapper_flags::uncached; - } - - if ((flags & table_flags::user_accessible) == table_flags::empty) - { - result |= mapper_flags::supervisor_only; - } - - if ((flags & table_flags::global) != table_flags::empty) - { - result |= mapper_flags::global; - } - - return result; - } - - constexpr auto to_table_flags(kapi::memory::page_mapper::flags flags) -> page_table::entry::flags - { - using table_flags = page_table::entry::flags; - using mapper_flags = kapi::memory::page_mapper::flags; - - auto result = table_flags{}; - - if ((flags & mapper_flags::executable) == mapper_flags::empty) - { - result |= table_flags::no_execute; - } - - if ((flags & mapper_flags::writable) != mapper_flags::empty) - { - result |= table_flags::writable; - } - - if ((flags & mapper_flags::uncached) != mapper_flags::empty) - { - result |= (table_flags::disable_cache | table_flags::write_through); - } - - if ((flags & mapper_flags::supervisor_only) == mapper_flags::empty) - { - result |= table_flags::user_accessible; - } - - if ((flags & mapper_flags::global) != mapper_flags::empty) - { - result |= table_flags::global; - } - - return result; - } - -} // namespace arch::memory - -#endif diff --git a/arch/x86_64/include/arch/memory/page_utilities.hpp b/arch/x86_64/include/arch/memory/page_utilities.hpp deleted file mode 100644 index 068e824..0000000 --- a/arch/x86_64/include/arch/memory/page_utilities.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef TEACHOS_X86_64_PAGE_UTILITIES_HPP -#define TEACHOS_X86_64_PAGE_UTILITIES_HPP - -#include - -#include - -namespace arch::memory -{ - - constexpr auto inline pml_index(std::size_t index, kapi::memory::page page) noexcept -> std::size_t - { - constexpr auto bits_per_level = 9; - auto shift_width = (index - 1) * bits_per_level; - constexpr auto index_mask = 0x1ffuz; - return page.number() >> shift_width & index_mask; - } - - template - [[nodiscard]] constexpr auto to_higher_half_pointer(kapi::memory::physical_address address) -> ValueType * - { - using namespace kapi::memory; - auto const higher_half_address = higher_half_direct_map_base + address.raw(); - return static_cast(higher_half_address); - } - -} // namespace arch::memory - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/region_allocator.hpp b/arch/x86_64/include/arch/memory/region_allocator.hpp deleted file mode 100644 index 5d9da2e..0000000 --- a/arch/x86_64/include/arch/memory/region_allocator.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP -#define TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP - -#include -#include -#include - -#include - -#include -#include -#include - -namespace arch::memory -{ - //! A simple, memory-region based frame allocator. - //! - //! This frame allocator linearly allocates frames that are in available memory regions. It automatically skips any - //! frames occupied by the kernel image or any bootloader provided data. - //! - //! @note This allocator will never release frames. - struct region_allocator final : kapi::memory::frame_allocator - { - struct memory_information - { - //! The memory range occupied by the loaded kernel image. - //! - //! This includes all sections that are marked as occupying space in the kernel executable. The internal structure - //! of this area is more described in a more fine-grained manner by the ELF symbol information provided in the - //! Multiboot2 information by the loader. - std::pair image_range; - - //! The memory range occupied by the loader supplied Multiboot2 information structure. - //! - //! In general, this information is allocated somewhere in the range of the loaded image, but the loader protocol - //! does not guarantee this. It is thus imperative to be able to handle the cases where the loader chooses to - //! allocate the information structure outside of the image range. - std::pair mbi_range; - - //! The loader supplied map of memory regions. - //! - //! These include available, unavailable, and reclaimable regions. In general, only frames that are located in - //! non-reserved (as in available) regions should be allocated for page storage. - multiboot2::memory_map memory_map; - - //! The loader supplied Multiboot2 information structure. - //! - //! This is used to query boot module ranges so these frames can be excluded from early allocations. - multiboot2::information_view const * mbi; - }; - - using region = multiboot2::memory_map::region; - - //! Construct a new allocator using the provided memory information - //! - //! @param information The description of the detected memory regions as well as regions that are already occupied. - explicit region_allocator(memory_information const & information); - - //! @copydoc kapi::memory::frame_allocator::allocate_many - //! - //! @note As long as free frames are available, successive calls to this implementation are guaranteed to yield - //! frames in ascending order. - auto allocate_many(std::size_t count = 1) noexcept - -> std::optional> override; - - //! @copydoc kapi::memory::frame_allocator::mark_used - auto mark_used(kapi::memory::frame frame) -> void override; - - //! @copydoc kapi::memory::frame_allocator::release_many - //! - //! @note This implementation will never actually release any frames. - auto release_many(std::pair frame_set) -> void override; - - auto next_free_frame() noexcept -> std::optional; - - private: - //! Find the next memory area and write it into current_area. - auto choose_next_region() -> void; - auto find_next_frame() -> std::optional; - - kapi::memory::frame m_next_frame; //!< The next available frame. - std::optional m_current_region; //!< The memory region currently used for allocation - multiboot2::memory_map m_memory_map; //!< The boot loader supplied memory map. - kapi::memory::frame m_kernel_start; //!< The start of the kernel image in physical memory. - kapi::memory::frame m_kernel_end; //!< The end of the kernel image in physical memory. - kapi::memory::frame m_multiboot_start; //!< The start of the Multiboot2 information in physical memory. - kapi::memory::frame m_multiboot_end; //!< The end of the Multiboot2 information in physical memory. - multiboot2::information_view const * m_multiboot_information; //!< Source of Multiboot2 module ranges. - }; - -} // namespace arch::memory - -#endif diff --git a/arch/x86_64/include/arch/vga/crtc.hpp b/arch/x86_64/include/arch/vga/crtc.hpp deleted file mode 100644 index a8bec93..0000000 --- a/arch/x86_64/include/arch/vga/crtc.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef TEACHOS_X86_64_VGA_IO_HPP -#define TEACHOS_X86_64_VGA_IO_HPP - -#include - -#include - -namespace arch::vga::crtc -{ - /** - * @brief The address port of the CRT Controller. - */ - using address = io::port<0x3d4, std::byte, io::port_write>; - - /** - * @brief The data port of the CRT Controller. - */ - using data = io::port<0x3d5, std::byte, io::port_read, io::port_write>; - - namespace registers - { - /** - * @brief The address of the Cursor Start register of the CRTC. - */ - [[maybe_unused]] constexpr auto cursor_start = std::byte{0x0a}; - - /** - * @brief The address of the Cursor End register of the CRTC. - */ - [[maybe_unused]] constexpr auto cursor_end = std::byte{0x0b}; - } // namespace registers - -} // namespace arch::vga::crtc - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/vga/text.hpp b/arch/x86_64/include/arch/vga/text.hpp deleted file mode 100644 index 2e73dd2..0000000 --- a/arch/x86_64/include/arch/vga/text.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef TEACHOS_X86_64_VGA_TEXT_HPP -#define TEACHOS_X86_64_VGA_TEXT_HPP - -#include // IWYU pragma: export -#include // IWYU pragma: export -#include // IWYU pragma: export -#include // IWYU pragma: export -#include // IWYU pragma: export - -#endif // TEACHOS_ARCH_X86_64_VIDEO_VGA_TEXT_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/vga/text/attribute.hpp b/arch/x86_64/include/arch/vga/text/attribute.hpp deleted file mode 100644 index 6395aed..0000000 --- a/arch/x86_64/include/arch/vga/text/attribute.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef TEACHOS_X86_64_VGA_TEXT_ATTRIBUTE_HPP -#define TEACHOS_X86_64_VGA_TEXT_ATTRIBUTE_HPP - -// IWYU pragma: private, include - -#include -#include - -namespace arch::vga::text -{ - //! The VGA text mode attribute. - //! - //! @note In the text mode of VGA, every code point being presented is followed by an attribute description. This - //! allows for the modification of how the relevant "cell" is presented. - //! - //! @see text::foreground_flag - //! @see text::background_flag - struct attribute - { - color foreground_color : 3; ///< The foreground color of the cell, e.g. the color of the code point. - enum foreground_flag foreground_flag : 1; ///< The foreground color modification flag of the cell. - color background_color : 3; ///< The background color of the cell. - enum background_flag background_flag : 1; ///< The background color modification flag of the cell. - }; - - static_assert(sizeof(attribute) == 1, "The VGA text mode attribute must fit inside a single byte."); - -} // namespace arch::vga::text - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/vga/text/buffer.hpp b/arch/x86_64/include/arch/vga/text/buffer.hpp deleted file mode 100644 index 8eb6645..0000000 --- a/arch/x86_64/include/arch/vga/text/buffer.hpp +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef TEACHOS_X86_64_VGA_TEXT_BUFFER_HPP -#define TEACHOS_X86_64_VGA_TEXT_BUFFER_HPP - -// IWYU pragma: private, include - -#include - -#include -#include -#include -#include - -namespace arch::vga::text -{ - //! A VGA text buffer. - //! - //! VGA text mode presents a linear buffer of so-called cells. Each cell consists of a single code point and a - //! rendering attribute. The codepoint determines the character being rendered in a specific cell, while the attribute - //! determines the visual style of that cell. - //! - //! @see text::attribute - struct buffer - { - using cell = std::pair; - - //! Create a new buffer. - //! - //! @param width The width of the buffer - //! @param height The height of the buffer - //! @param start A pointer to the first byte of the buffer. - //! @param position The starting position for the first write to the buffer - buffer(std::size_t width, std::size_t height, cell * start, std::size_t position = 0); - - //! Clear the buffer. - //! - //! Clearing the buffer ensures it is filled with zeroes, effectively erasing all data and resetting the output - //! position to the start of the buffer. - auto clear() -> void; - - //! Write a string of formatted code points to the buffer. - //! - //! @param code_points A string of (8-bit) code points to write to the buffer. - //! @param attribute The formatting to apply to the written sequence of code points. - auto write(std::string_view code_points, attribute attribute) -> void; - - //! Write a single, formatted code point to the buffer. - //! - //! @param code_point A single (8-bit) code point - //! @param attribute The formatting to apply to the code point. - auto write(char code_point, attribute attribute) -> void; - - //! Move the output position to a new line and scroll the buffer if necessary. - auto newline() -> void; - - //! Scroll the buffer contents. - //! - //! @param nof_lines The number of lines to scroll up. - auto scroll(std::size_t nof_lines = 1) -> void; - - private: - //! Get column number of the current cell. - [[nodiscard]] auto column() const noexcept -> std::ptrdiff_t; - - //! Get the line number of the current cell. - [[nodiscard]] auto line() const noexcept -> std::ptrdiff_t; - - //! Process the semantics of special code points, for example newlines and carriage returns. - //! - //! @param code_point The code point to process. - //! @param attribute The attribute to use when writing to the text buffer. - //! @return @p true iff. the code point was handled, @p false otherwise. - auto handle_special_code_point(char code_point, attribute attribute) -> bool; - - //! Perform the actual output to the buffer. - //! - //! @param code_points The code points to output.. - //! @param attribute The attribute to use when writing to the text buffer. - auto do_write(std::string_view code_points, attribute attribute) -> void; - - //! Perform the actual output to the buffer. - //! - //! @param code_point The code point to output. - //! @param attribute The attribute to use when writing to the text buffer. - auto do_write(char code_point, attribute attribute) -> void; - - //! The width, in cells, of the buffer. - std::size_t m_width{}; - - //! The height, in cells, of the buffer. - std::size_t m_height{}; - - //! The text mode data buffer. - std::span m_buffer; - - //! The position of the next cell to be written to. - std::size_t m_position{}; - }; - -} // namespace arch::vga::text - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/vga/text/color.hpp b/arch/x86_64/include/arch/vga/text/color.hpp deleted file mode 100644 index e0ad6df..0000000 --- a/arch/x86_64/include/arch/vga/text/color.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef TEACHOS_X86_64_VGA_TEXT_COLOR_HPP -#define TEACHOS_X86_64_VGA_TEXT_COLOR_HPP - -// IWYU pragma: private, include - -#include - -namespace arch::vga::text -{ - //! VGA Text Mode standard colors. - //! - //! Every color may be used as a foreground and/or background color, in any combination. - enum struct color : std::uint8_t - { - //! Equivalent to HTML color \#000000. - black, - //! Equivalent to HTML color \#0000AA. - blue, - //! Equivalent to HTML color \#00AA00. - green, - //! Equivalent to HTML color \#00AAAA. - cyan, - //! Equivalent to HTML color \#AA0000. - red, - //! Equivalent to HTML color \#AA00AA. - purple, - //! Equivalent to HTML color \#AA5500. - brown, - //! Equivalent to HTML color \#AAAAAA. - gray, - }; - -} // namespace arch::vga::text - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/vga/text/common_attributes.hpp b/arch/x86_64/include/arch/vga/text/common_attributes.hpp deleted file mode 100644 index 3d8929f..0000000 --- a/arch/x86_64/include/arch/vga/text/common_attributes.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef TEACHOS_X86_64_VGA_TEXT_COMMON_ATTRIBUTES_HPP -#define TEACHOS_X86_64_VGA_TEXT_COMMON_ATTRIBUTES_HPP - -// IWYU pragma: private, include - -#include -#include -#include - -namespace arch::vga::text -{ - //! Make the affected cell display with a gray foreground and black background. - [[maybe_unused]] constexpr auto gray_on_black = attribute{.foreground_color = color::gray, - .foreground_flag = foreground_flag::none, - .background_color = color::black, - .background_flag = background_flag::none}; - - //! Make the affected cell display with a green foreground and black background. - [[maybe_unused]] constexpr auto green_on_black = attribute{.foreground_color = color::green, - .foreground_flag = foreground_flag::none, - .background_color = color::black, - .background_flag = background_flag::none}; - - //! Make the affected cell display with a green foreground and black background. - [[maybe_unused]] constexpr auto red_on_black = attribute{.foreground_color = color::red, - .foreground_flag = foreground_flag::none, - .background_color = color::black, - .background_flag = background_flag::none}; - - //! Make the affected cell display with a white (gray + intense) foreground and red background. - [[maybe_unused]] constexpr auto white_on_red = attribute{.foreground_color = color::gray, - .foreground_flag = foreground_flag::intense, - .background_color = color::red, - .background_flag = background_flag::none}; -} // namespace arch::vga::text - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/vga/text/device.hpp b/arch/x86_64/include/arch/vga/text/device.hpp deleted file mode 100644 index 0a0e017..0000000 --- a/arch/x86_64/include/arch/vga/text/device.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef TEACHOS_X86_64_VGA_TEXT_DEVICE_HPP -#define TEACHOS_X86_64_VGA_TEXT_DEVICE_HPP - -// IWYU pragma: private, include - -#include - -#include - -#include - -namespace arch::vga::text -{ - //! A VGA Text Mode device. - //! - //! VGA text mode presents a linear buffer of so-called cells. Each cell consists of a single code point and a - //! rendering attribute. The codepoint determines the character being rendered in a specific cell, while the attribute - //! determines the visual style of that cell. - //! - //! @see text::attribute - struct device final : kapi::cio::output_device - { - device(); - - //! Clear the screen. - //! - //! Clearing the screen ensures the text mode buffer is filled with zeroes, effectively erasing all displayed data - //! and resetting the output position to the start of the buffer. - auto clear() -> void; - - //! Enable or disable the VGA text mode cursor. - //! - //! @param enabled Whether to enable the cursor. - auto cursor(bool enabled) -> void; - - //! @copydoc kapi::cio::output_device - auto write(kapi::cio::output_stream stream, std::string_view text) -> void override; - - private: - buffer m_buffer; - }; - -} // namespace arch::vga::text - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/vga/text/flags.hpp b/arch/x86_64/include/arch/vga/text/flags.hpp deleted file mode 100644 index 7a29e33..0000000 --- a/arch/x86_64/include/arch/vga/text/flags.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef TEACHOS_X86_64_VGA_TEXT_FLAGS_HPP -#define TEACHOS_X86_64_VGA_TEXT_FLAGS_HPP - -// IWYU pragma: private, include - -namespace arch::vga::text -{ - - //! VGA Text Mode standard background modification flags. - enum struct background_flag : bool - { - //! Do not modify the foreground rendering. - none, - //! Render the background as blinking or intense. - //! - //! Whether this flag is interpreted as 'blink' or 'bright' depends on the currently active configuration of the VGA - //! device. - //! - //! @note The VGA standard does not specify the exact effect of this 'intense', however, most devices render such - //! colors brighter. - blink_or_bright, - }; - - //! VGA Text Mode standard foreground modification flags. - enum struct foreground_flag : bool - { - //! Do not modify the foreground rendering. - none, - //! Render the foreground as intense. - //! - //! @note The VGA standard does not specify the exact effect of this 'intense', however, most devices render such - //! colors brighter. - intense, - }; - -} // namespace arch::vga::text - -#endif \ No newline at end of file diff --git a/arch/x86_64/pre/include/arch/context_switching/main.hpp b/arch/x86_64/pre/include/arch/context_switching/main.hpp deleted file mode 100644 index 07e00e8..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/main.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP - -#include -#include - -namespace teachos::arch::context_switching -{ - /** - * @brief Contains the references to the tables required for context switching - */ - struct descriptor_tables - { - segment_descriptor_table::global_descriptor_table & gdt; ///< Reference to the global descriptor table. - interrupt_descriptor_table::interrupt_descriptor_table & idt; ///< Reference to the interrupt descriptor table. - }; - - /** - * @brief Creates the Interrupt Descriptor Table and Global Descriptor Table as a static variable the first time this - * method is called and update IDTR and GDTR registers values. - * - * @note Subsequent calls after the first one, will simply return the previously created tables, but not update the - * registers again. - * - * @return References to the statically created Interrupt Descriptor and Global Descriptor Table. - */ - auto initialize_descriptor_tables() -> descriptor_tables; - - /** - * @brief Switches from the current Kernel Mode (Level 0) to User Mode (Level 3). Will simply use predefined Segment - * Selectors for the User Data and User Code Segment, which are Index 3 and 4 in the GDT respectively. - */ - auto switch_to_user_mode() -> void; - - /** - * @brief Switches from the current Code and Data Segment to the given Code and Data Segment. - * - * @note This method will additionally call initialize_descriptor_tables, to ensure the GDTR and IDTR have been setup - * correctly before attempting to switch the context. This switch is achieved using a far return, which will once - * executed call the given void function. - * - * @param data_segment Data Segment that the SS, DS; ES, FS and GS register will be set too. - * @param code_segment Code Segment that the CS register will be set too. - * @param return_function Function that will be called once the switch has been achieved. - */ - auto switch_context(interrupt_descriptor_table::segment_selector data_segment, - interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void; - -} // namespace teachos::arch::context_switching - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_MAIN_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/syscall/main.hpp b/arch/x86_64/pre/include/arch/context_switching/syscall/main.hpp deleted file mode 100644 index f507c61..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/syscall/main.hpp +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP - -#include - -namespace teachos::arch::context_switching::syscall -{ - /** - * @brief Possible syscall implementation that should actually be called. - * - * @note Attempts to reflect the Linux interface partially. See https://filippo.io/linux-syscall-table/ for more - * information. - */ - enum class type : uint64_t - { - WRITE = 1U, ///< Loads the arg_0 parameter as an address pointing to a const char array, which will then be printed - ///< onto the VGA buffer screen. - EXPAND_HEAP = 2U, /// Expands the User Heap by additonally mapping 100 KiB of virtual page memory. Ignores the - /// parameters and uses them as out parameters instead, where arg_0 is the start of the newly - /// mapped heap area and arg_1 is the size of the entire area. Can be less than 100 KiB if less - /// space remains. - ASSERT = 3U, /// Loads the arg_0 parameter as a boolean which needs to be true or it will print the message in - /// arg_1 parameter onto the VGA buffer screen, keep it as a nullptr if it shouldn't print anything - /// and then it halts the further execution of the application. - }; - - /** - * @brief Possible error codes that can be returned by the different syscall methods called depending on the type - * enum. - */ - enum class error : uint8_t - { - OK = 0U, ///< No error occured in syscall. - OUT_OF_MEMORY = 1U, ///< Expanding heap failed because we have run out of mappable virtual address space. - }; - - /** - * @brief Allows to convert the error enum type into a boolean directly. Where any code besides 0 being no error, will - * return true. The remaining errors return true. - * - * @param e Error code that was returned by the syscall. - * @return Return true if there was no error and false otherwise. - */ - constexpr bool operator!(error e) - { - return e == error::OK; - } - - /** - * @brief Maximum amount of arguments that can be passed to a syscall. Default value is 0 and arguments are only ever - * used depending on the actual enum type and if the method requires thoose parameters. - */ - struct arguments - { - uint64_t arg_0{}; ///< First optional paramter to the syscall representing the RDI register. - uint64_t arg_1{}; ///< Second optional paramter to the syscall representing the RSI register. - uint64_t arg_2{}; ///< Third optional paramter to the syscall representing the RDX register. - uint64_t arg_3{}; ///< Fourth optional paramter to the syscall representing the R10 register. - uint64_t arg_4{}; ///< Fifth optional paramter to the syscall representing the R8 register. - uint64_t arg_5{}; ///< Sixth optional paramter to the syscall representing the R9 register. - }; - - /** - * @brief Response of a systemcall always containin an error code, signaling if the syscall even succeeded or not. - * Additionally it may contain up to 6 return values in the values struct. - */ - struct response - { - error error_code; ///< Error code returned by the syscall. If it failed all the values will be 0. - arguments values = {}; ///< Optional return values of the syscall implementation. - }; - - /** - * @brief Calls the method associated with the given syscall number and passes the given optional arguments to it, - * over the RDI, RSI, RDX, R10, R8 and R9 register. - * - * @param syscall_number Syscall method that should be called. See enum values in type for possible implemented - * methods. - * @param args Optional arguments passable to the different syscall methods, called depending on the syscall_number. - * Not passing the required parameters to the method, will result in passing 0 instead, which might make the fail or - * not function correctly. - * @return The syscall implementation always returns a bool-convertable error code converting to true if the syscall - * failed or false if it didn't. Additionally it might pase additional values besides the error code, they will be set - * in the arguments struct. So the value can be read and used for further processing. - */ - [[gnu::section(".user_text")]] - auto syscall(type syscall_number, arguments args = {}) -> response; - -} // namespace teachos::arch::context_switching::syscall - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_MAIN_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_enable.hpp b/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_enable.hpp deleted file mode 100644 index 8cb468a..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_enable.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_ENABLE_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_ENABLE_HPP - -namespace teachos::arch::context_switching::syscall -{ - /** - * @brief Enables and sets up internal CPU registers to allow for syscall to function correctly and switch context - * temporarily back to the kernel level. - * - * @note Configures the Model Specific Register required by syscall (LSTAR, FMASK, STAR) with the correct values so - * that the syscall_handler is called and sets the System Call Extension bit on the EFER flags to allow for syscall - * to be used. - */ - auto enable_syscall() -> void; - -} // namespace teachos::arch::context_switching::syscall - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_ENABLE_HPP diff --git a/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_handler.hpp b/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_handler.hpp deleted file mode 100644 index 2e7bcd1..0000000 --- a/arch/x86_64/pre/include/arch/context_switching/syscall/syscall_handler.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_HANDLER_HPP -#define TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_HANDLER_HPP - -#include - -namespace teachos::arch::context_switching::syscall -{ - /** - * @brief Handler for SYSCALL instruction. Calls a specific implementation based - * on the register RAX. - * - * @return Returns with LEAVE, SYSRETQ - */ - auto syscall_handler() -> void; - -} // namespace teachos::arch::context_switching::syscall - -#endif // TEACHOS_ARCH_X86_64_CONTEXT_SWITCHING_SYSCALL_SYSCALL_HANDLER_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/halt.hpp b/arch/x86_64/pre/include/arch/kernel/halt.hpp deleted file mode 100644 index 377acc0..0000000 --- a/arch/x86_64/pre/include/arch/kernel/halt.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP - -namespace teachos::arch::kernel -{ - /** - * @brief Halts the kernel execution, meaning any code after a call to this will not run anymore. - */ - extern "C" [[noreturn]] auto halt() -> void; - -} // namespace teachos::arch::kernel - -#endif // TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP diff --git a/arch/x86_64/pre/include/arch/kernel/main.hpp b/arch/x86_64/pre/include/arch/kernel/main.hpp deleted file mode 100644 index a13e5f4..0000000 --- a/arch/x86_64/pre/include/arch/kernel/main.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP -#define TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP - -namespace teachos::arch::kernel -{ - /** - * @brief Initalizes the kernel system. - */ - auto main() -> void; - -} // namespace teachos::arch::kernel - -#endif // TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP diff --git a/arch/x86_64/pre/include/arch/user/main.hpp b/arch/x86_64/pre/include/arch/user/main.hpp deleted file mode 100644 index c168a1f..0000000 --- a/arch/x86_64/pre/include/arch/user/main.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_USER_MAIN_HPP -#define TEACHOS_ARCH_X86_64_USER_MAIN_HPP - -namespace teachos::arch::user -{ - /** - * @brief User Main method. If this method finishes there is no code left to run and the whole OS will shut down. - * Additionally this main method is executed at Ring 3 and accessing CPU Registers or Kernel level functionality can - * only be done over syscalls and not directly anymore. - */ - [[gnu::section(".user_text")]] - auto main() -> void; - -} // namespace teachos::arch::user - -#endif // TEACHOS_ARCH_X86_64_USER_MAIN_HPP diff --git a/arch/x86_64/pre/src/context_switching/main.cpp b/arch/x86_64/pre/src/context_switching/main.cpp deleted file mode 100644 index 0961499..0000000 --- a/arch/x86_64/pre/src/context_switching/main.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace teachos::arch::context_switching -{ - namespace - { - constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ - 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - constexpr kernel::cpu::far_pointer KERNEL_CODE_POINTER{&kernel::cpu::reload_data_segment_registers, - KERNEL_CODE_SEGMENT_SELECTOR}; - constexpr context_switching::interrupt_descriptor_table::segment_selector USER_CODE_SEGMENT_SELECTOR{ - 3U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - constexpr context_switching::interrupt_descriptor_table::segment_selector USER_DATA_SEGMENT_SELECTOR{ - 4U, context_switching::interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_USER}; - - auto reload_gdtr() -> void - { - kernel::cpu::call(KERNEL_CODE_POINTER); - } - } // namespace - - auto initialize_descriptor_tables() -> descriptor_tables - { - bool static initalized = false; - - if (!initalized) - { - kernel::cpu::clear_interrupt_flag(); - - segment_descriptor_table::update_gdtr(); - interrupt_descriptor_table::update_interrupt_descriptor_table_register(); - - reload_gdtr(); - segment_descriptor_table::update_tss_register(); - - kernel::cpu::set_interrupt_flag(); - initalized = true; - } - - descriptor_tables tables = {segment_descriptor_table::get_or_create_gdt(), - interrupt_descriptor_table::get_or_create_interrupt_descriptor_table()}; - return tables; - } - - auto switch_to_user_mode() -> void - { - syscall::enable_syscall(); - switch_context(USER_DATA_SEGMENT_SELECTOR, USER_CODE_SEGMENT_SELECTOR, user::main); - } - - auto switch_context(interrupt_descriptor_table::segment_selector data_segment, - interrupt_descriptor_table::segment_selector code_segment, void (*return_function)()) -> void - { - (void)initialize_descriptor_tables(); - kernel::cpu::set_data_segment_registers(data_segment); - kernel::cpu::set_code_segment_register(data_segment, code_segment, reinterpret_cast(return_function)); - } -} // namespace teachos::arch::context_switching diff --git a/arch/x86_64/pre/src/context_switching/syscall/main.cpp b/arch/x86_64/pre/src/context_switching/syscall/main.cpp deleted file mode 100644 index 10bd087..0000000 --- a/arch/x86_64/pre/src/context_switching/syscall/main.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include - -namespace teachos::arch::context_switching::syscall -{ - auto syscall(type syscall_number, arguments args) -> response - { - asm volatile("mov %[input], %%rax" - : /* no output from call */ - : [input] "m"(syscall_number) - : "memory"); - - asm volatile("mov %[input], %%rdi " : /* no output from call */ : [input] "m"(args.arg_0) : "memory"); - asm volatile("mov %[input], %%rsi" : /* no output from call */ : [input] "m"(args.arg_1) : "memory"); - asm volatile("mov %[input], %%rdx" : /* no output from call */ : [input] "m"(args.arg_2) : "memory"); - asm volatile("mov %[input], %%r10" : /* no output from call */ : [input] "m"(args.arg_3) : "memory"); - asm volatile("mov %[input], %%r8" : /* no output from call */ : [input] "m"(args.arg_4) : "memory"); - asm volatile("mov %[input], %%r9" : /* no output from call */ : [input] "m"(args.arg_5) : "memory"); - - asm volatile("syscall"); - - arguments values{}; - asm volatile("mov %%rdi, %[output]" : [output] "=m"(values.arg_0)); - asm volatile("mov %%rsi, %[output]" : [output] "=m"(values.arg_1)); - asm volatile("mov %%rdx, %[output]" : [output] "=m"(values.arg_2)); - asm volatile("mov %%r10, %[output]" : [output] "=m"(values.arg_3)); - asm volatile("mov %%r8, %[output]" : [output] "=m"(values.arg_4)); - asm volatile("mov %%r9, %[output]" : [output] "=m"(values.arg_5)); - - error error_code{}; - asm volatile("mov %%al, %[output]" : [output] "=m"(error_code)); - - return {error_code, values}; - } - -} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp b/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp deleted file mode 100644 index f9f070a..0000000 --- a/arch/x86_64/pre/src/context_switching/syscall/syscall_enable.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include - -#include -#include -#include - -namespace teachos::arch::context_switching::syscall -{ - namespace - { - constexpr interrupt_descriptor_table::segment_selector KERNEL_CODE_SEGMENT_SELECTOR{ - 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - - constexpr auto IA32_STAR_ADDRESS = 0xC000'0081; - constexpr auto IA32_LSTAR_ADDRESS = 0xC000'0082; - constexpr auto IA32_FMASK_ADDRESS = 0xC000'0084; - - } // namespace - - auto enable_syscall() -> void - { - uint64_t const syscall_function = reinterpret_cast(syscall_handler); - kernel::cpu::write_msr(IA32_LSTAR_ADDRESS, syscall_function); - kernel::cpu::write_msr(IA32_FMASK_ADDRESS, 0U); - - uint64_t const kernel_cs = KERNEL_CODE_SEGMENT_SELECTOR; - uint64_t const star_value = (kernel_cs << 32) | (kernel_cs << 48); - kernel::cpu::write_msr(IA32_STAR_ADDRESS, star_value); - - kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::SCE); - } -} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp deleted file mode 100644 index 430d65c..0000000 --- a/arch/x86_64/pre/src/context_switching/syscall/syscall_handler.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include - -namespace teachos::arch::context_switching::syscall -{ - - namespace - { - auto write_to_vga_buffer(uint64_t buffer) -> response - { - video::vga::text::write(reinterpret_cast(buffer), - video::vga::text::common_attributes::green_on_black); - video::vga::text::newline(); - return {error::OK}; - } - - auto expand_user_heap() -> response - { - auto static current_heap_end = memory::heap::USER_HEAP_START; - uint64_t const heap_start = current_heap_end; - memory::remap_heap(heap_start, memory::heap::USER_HEAP_SIZE, memory::paging::entry::USER_ACCESSIBLE); - current_heap_end += memory::heap::USER_HEAP_SIZE; - return { - error::OK, - {heap_start, memory::heap::USER_HEAP_SIZE} - }; - } - } // namespace - - auto syscall_handler() -> void - { - // Saving state of rcx and r11 because it is required by sysretq to function. - // Calls to other functions potentially overwrite these registers, because of - // callee saved calling convention. - uint64_t return_instruction_pointer, rflags = {}; - asm volatile("mov %%rcx, %[output]" : [output] "=m"(return_instruction_pointer)); - asm volatile("mov %%r11, %[output]" : [output] "=m"(rflags)); - - uint64_t syscall_number, arg_0, arg_1, arg_2, arg_3, arg_4, arg_5 = {}; - asm volatile("mov %%rdi, %[output]" : [output] "=m"(arg_0)); - asm volatile("mov %%rsi, %[output]" : [output] "=m"(arg_1)); - asm volatile("mov %%rdx, %[output]" : [output] "=m"(arg_2)); - asm volatile("mov %%r10, %[output]" : [output] "=m"(arg_3)); - asm volatile("mov %%r8, %[output]" : [output] "=m"(arg_4)); - asm volatile("mov %%r9, %[output]" : [output] "=m"(arg_5)); - - // RAX is read last, because paired with our type enum, we can use it to check - // if the register has been written by the compiled code between executing the syscall - // and now. - asm volatile("mov %%rax, %[output]" : [output] "=m"(syscall_number)); - - response result; - switch (static_cast(syscall_number)) - { - case type::WRITE: - result = write_to_vga_buffer(arg_0); - break; - case type::EXPAND_HEAP: - result = expand_user_heap(); - break; - case type::ASSERT: - teachos::arch::exception_handling::assert(arg_0, reinterpret_cast(arg_1)); - break; - default: - teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number"); - break; - } - - asm volatile("mov %[input], %%rax" - : /* no output from call */ - : [input] "m"(result.error_code) - : "memory"); - - asm volatile("mov %[input], %%rdi" - : /* no output from call */ - : [input] "m"(result.values.arg_0) - : "memory"); - asm volatile("mov %[input], %%rsi" - : /* no output from call */ - : [input] "m"(result.values.arg_1) - : "memory"); - asm volatile("mov %[input], %%rdx" - : /* no output from call */ - : [input] "m"(result.values.arg_2) - : "memory"); - asm volatile("mov %[input], %%r10" - : /* no output from call */ - : [input] "m"(result.values.arg_3) - : "memory"); - asm volatile("mov %[input], %%r8" - : /* no output from call */ - : [input] "m"(result.values.arg_4) - : "memory"); - asm volatile("mov %[input], %%r9" - : /* no output from call */ - : [input] "m"(result.values.arg_5) - : "memory"); - - asm volatile("mov %[input], %%rcx" - : /* no output from call */ - : [input] "m"(return_instruction_pointer) - : "memory"); - asm volatile("mov %[input], %%r11" - : /* no output from call */ - : [input] "m"(rflags) - : "memory"); - - // Additionally call leave, because x86 allocates stack space for the internal variables. If we do not clean up this - // newly created stack frame the syscall instruction that landed in this syscall_handler, will never return to the - // method that originally called it, because the RIP has not been restored from the previous stack frame. - asm volatile("leave\n" - "sysretq"); - } - -} // namespace teachos::arch::context_switching::syscall diff --git a/arch/x86_64/pre/src/kernel/main.cpp b/arch/x86_64/pre/src/kernel/main.cpp deleted file mode 100644 index 2658678..0000000 --- a/arch/x86_64/pre/src/kernel/main.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace teachos::arch::kernel -{ - auto stack_overflow_test(int count) -> int - { - int test[5000] = {}; - if (test[0] == 0xFFFF) - { - return count; - } - count = stack_overflow_test(count); - return count++; - } - - auto heap_test() -> void - { - auto test2 = new memory::multiboot::memory_information{}; - auto test3 = new memory::multiboot::memory_information{}; - auto test4 = *test2; - auto test5 = *test3; - test4.kernel_end = 5000; - test5.kernel_end = 3000; - auto test6 = test4.kernel_end; - auto test7 = test5.kernel_end; - auto test8 = memory::multiboot::read_multiboot2(); - if (test6 && test7 && test8.kernel_end) - { - video::vga::text::write("Heap test successful", video::vga::text::common_attributes::green_on_black); - } - test2->kernel_end = 2000; - test2->kernel_start = 1000; - test2->multiboot_start = 2000; - delete test2; - delete test3; - - auto test9 = new int(50); - delete test9; - } - - auto main() -> void - { - video::vga::text::clear(); - video::vga::text::cursor(false); - video::vga::text::write("TeachOS is starting up...", video::vga::text::common_attributes::green_on_black); - video::vga::text::newline(); - - memory::initialize_memory_management(); - // stack_overflow_test(0); - - memory::heap::global_heap_allocator::register_heap_allocator(memory::heap::heap_allocator_type::LINKED_LIST); - // heap_test(); - - auto address = memory::heap::global_heap_allocator::kmalloc(8U); - (void)address; - - context_switching::switch_to_user_mode(); - } -} // namespace teachos::arch::kernel diff --git a/arch/x86_64/pre/src/user/main.cpp b/arch/x86_64/pre/src/user/main.cpp deleted file mode 100644 index 10a17db..0000000 --- a/arch/x86_64/pre/src/user/main.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include - -#include -#include - -#include -#include -#include -#include - -namespace teachos::arch::user -{ - auto main() -> void - { - constexpr char syscall_message[] = "Successfully entered user mode and wrote to VGA buffer via syscall!"; - context_switching::syscall::syscall(context_switching::syscall::type::WRITE, - {reinterpret_cast(&syscall_message)}); - - // Test C++ standard library - std::array, 4> array_test = {std::atomic{5}, std::atomic{10}, - std::atomic{15}, std::atomic{20}}; - std::ranges::for_each(array_test, [](auto & item) { - auto value = item.load(); - uint8_t max_value = std::max(value, uint8_t{10}); - item.exchange(max_value + 2); - }); - - auto address = new uint64_t{10U}; - (void)address; - - for (;;) - { - } - } -} // namespace teachos::arch::user 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 From c3d5a155025b445ab9213f131681afe9410b4e66 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Apr 2026 09:29:20 +0200 Subject: x86_64: fix library references --- arch/x86_64/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 5657010..20a48f9 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -10,8 +10,8 @@ target_include_directories("x86_64" PUBLIC ) target_link_libraries("x86_64" PUBLIC - "os::kapi" - "libs::multiboot2" + "kapi::lib" + "multiboot2::lib" ) target_sources("x86_64" PRIVATE -- cgit v1.2.3 From 9aaabb2cf73f20cc4d4c68588e7bf4592837626f Mon Sep 17 00:00:00 2001 From: Marcel Braun Date: Mon, 4 May 2026 23:25:16 +0200 Subject: Add simple symlink tests --- arch/x86_64/support/modules/README.md | 5 ++++- arch/x86_64/support/modules/ext2_1KB_fs.img | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/support/modules/README.md b/arch/x86_64/support/modules/README.md index a04b9af..fac5daf 100644 --- a/arch/x86_64/support/modules/README.md +++ b/arch/x86_64/support/modules/README.md @@ -8,10 +8,13 @@ The ext2_4KB_fs image is intentionally fragmented, as some files were created an ./archiv ./archiv/2024.img ./archiv/2025.img +./closed.txt ./information ./information/info_1.txt ./information/info_2.txt -./closed.txt +./symlinks +./symlinks/info_1_absolute -> /information/info_1.txt +./symlinks/info_1_relative -> ../information/info_1.txt ### 2024.img (ext2 filesystem with 2KB Block size) diff --git a/arch/x86_64/support/modules/ext2_1KB_fs.img b/arch/x86_64/support/modules/ext2_1KB_fs.img index 5bbb76d..0312727 100644 --- a/arch/x86_64/support/modules/ext2_1KB_fs.img +++ b/arch/x86_64/support/modules/ext2_1KB_fs.img @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c2ef9536a439825520d9e230eedaa9ae327f9763350eddbc0f24bf5b9b5d2bf2 +oid sha256:7cf40c3cf3d8e3be614cadf2da1c76138c492734c3730eadbca645f50ed99a50 size 10485760 -- cgit v1.2.3 From 2c24321681974e1aa8b1240155420f49a16f3c2e Mon Sep 17 00:00:00 2001 From: Marcel Braun Date: Tue, 5 May 2026 17:15:09 +0200 Subject: Add testing symlinks to filesystem images --- arch/x86_64/support/modules/ext2_1KB_fs.img | 2 +- arch/x86_64/support/modules/ext2_2KB_fs.img | 2 +- arch/x86_64/support/modules/ext2_4KB_fs.img | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/support/modules/ext2_1KB_fs.img b/arch/x86_64/support/modules/ext2_1KB_fs.img index 0312727..a5202ca 100644 --- a/arch/x86_64/support/modules/ext2_1KB_fs.img +++ b/arch/x86_64/support/modules/ext2_1KB_fs.img @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7cf40c3cf3d8e3be614cadf2da1c76138c492734c3730eadbca645f50ed99a50 +oid sha256:98ac3c1be872806e25fb14eea168ca79a91959f4e6a5ac3d00c5d8224c1f73a3 size 10485760 diff --git a/arch/x86_64/support/modules/ext2_2KB_fs.img b/arch/x86_64/support/modules/ext2_2KB_fs.img index 1880911..8327022 100644 --- a/arch/x86_64/support/modules/ext2_2KB_fs.img +++ b/arch/x86_64/support/modules/ext2_2KB_fs.img @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9a13da5abb9c65c737105b1da0d4344c7cd7604c7952c762c4f4e3d3f96fd42d +oid sha256:a1d102f2e40083613060d43b2b32d31031137bbef99761a2d1bf4d38e155adb7 size 5242880 diff --git a/arch/x86_64/support/modules/ext2_4KB_fs.img b/arch/x86_64/support/modules/ext2_4KB_fs.img index 3aaceb8..2cd452f 100644 --- a/arch/x86_64/support/modules/ext2_4KB_fs.img +++ b/arch/x86_64/support/modules/ext2_4KB_fs.img @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4ce6a1aea277906e1af6de223c017ff900b96569f076b4d99fc04eaa1ee986f4 +oid sha256:62e1fa40f95e0cb037c43e3f55d0094ab6cb4d68e00914f555a90faf7cc00c31 size 10485760 -- cgit v1.2.3 From 491d7cb23f48b995e954b7cbb836ab3efb47ea88 Mon Sep 17 00:00:00 2001 From: Marcel Braun Date: Tue, 5 May 2026 17:22:27 +0200 Subject: Update readme for images, add symlink to readme into test_assets folder --- arch/x86_64/support/modules/README.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/support/modules/README.md b/arch/x86_64/support/modules/README.md index fac5daf..67b1217 100644 --- a/arch/x86_64/support/modules/README.md +++ b/arch/x86_64/support/modules/README.md @@ -8,13 +8,21 @@ The ext2_4KB_fs image is intentionally fragmented, as some files were created an ./archiv ./archiv/2024.img ./archiv/2025.img +./archiv/mnt ./closed.txt ./information ./information/info_1.txt ./information/info_2.txt -./symlinks -./symlinks/info_1_absolute -> /information/info_1.txt -./symlinks/info_1_relative -> ../information/info_1.txt +./symlinks +./symlinks/info_1_absolute -> /information/info_1.txt +./symlinks/info_1_relative -> ../information/info_1.txt +./symlinks/information_directory_absolute -> /information +./symlinks/information_directory_relative -> ../information +./symlinks/invalid_absolute -> ../invalid/non_existant.txt +./symlinks/invalid_relative -> ../invalid/non_existant.txt +./symlinks/symloop_a -> ./symloop_b +./symlinks/symloop_b -> /symlinks/symloop_a +./symlinks/traverse_back_5_times -> ../../../../../ ### 2024.img (ext2 filesystem with 2KB Block size) @@ -25,6 +33,8 @@ The ext2_4KB_fs image is intentionally fragmented, as some files were created an ./stable/pig_1.txt ./stable/pig_2.txt ./stable/pig_3.txt +./symlinks +./symlinks/traverse_back_twice -> ../../ ### 2025.img (ext2 filesystem 4KB Block size) @@ -52,6 +62,7 @@ The ext2_4KB_fs image is intentionally fragmented, as some files were created an ./monkey_house/caretaker ./monkey_house/caretaker/isabelle.txt ./monkey_house/caretaker/peter.txt +./symlinks/leave_and_reenter_mount -> ../../archiv/../information/monkey_house ## ext2_4KB_fs . @@ -109,3 +120,4 @@ The ext2_4KB_fs image is intentionally fragmented, as some files were created an ./enclosures/aquarium/spawn_fish.sh ./enclosures/info.txt ./info.txt +./symlinks/very_long_symlink -> ../enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_30.txt -- cgit v1.2.3 From c7e3528e9d40f62e6acf72b206a31105f252b529 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Tue, 5 May 2026 19:40:55 +0200 Subject: fix readme --- arch/x86_64/support/modules/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/support/modules/README.md b/arch/x86_64/support/modules/README.md index 67b1217..6893176 100644 --- a/arch/x86_64/support/modules/README.md +++ b/arch/x86_64/support/modules/README.md @@ -18,7 +18,7 @@ The ext2_4KB_fs image is intentionally fragmented, as some files were created an ./symlinks/info_1_relative -> ../information/info_1.txt ./symlinks/information_directory_absolute -> /information ./symlinks/information_directory_relative -> ../information -./symlinks/invalid_absolute -> ../invalid/non_existant.txt +./symlinks/invalid_absolute -> /invalid/non_existant.txt ./symlinks/invalid_relative -> ../invalid/non_existant.txt ./symlinks/symloop_a -> ./symloop_b ./symlinks/symloop_b -> /symlinks/symloop_a -- cgit v1.2.3 From 8739d65ea50f13dbbb5bd1a27f461c367deb5b99 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Tue, 5 May 2026 20:59:52 +0200 Subject: add symlink chain to image --- arch/x86_64/support/modules/README.md | 6 +++++- arch/x86_64/support/modules/ext2_4KB_fs.img | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/support/modules/README.md b/arch/x86_64/support/modules/README.md index 6893176..1a29ce5 100644 --- a/arch/x86_64/support/modules/README.md +++ b/arch/x86_64/support/modules/README.md @@ -78,9 +78,12 @@ The ext2_4KB_fs image is intentionally fragmented, as some files were created an ./enclosures/lion_house/cage_b ./enclosures/lion_house/cage_b/animals.txt ./enclosures/lion_house/cage_b/history.txt +./enclosures/lion_house/symlink_chain_2 -> /entrance/../enclosures/aquarium/symlink_chain_3 ./enclosures/elephant_house ./enclosures/elephant_house/elephant_1.txt ./enclosures/aquarium +./enclosures/aquarium/spawn_fish.sh +./enclosures/aquarium/symlink_chain_3 -> ../../entrance ./enclosures/aquarium/tank_1 ./enclosures/aquarium/tank_1/fish_1.txt ./enclosures/aquarium/tank_1/fish_2.txt @@ -117,7 +120,8 @@ The ext2_4KB_fs image is intentionally fragmented, as some files were created an ./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_28.txt ./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_29.txt ./enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_30.txt -./enclosures/aquarium/spawn_fish.sh ./enclosures/info.txt ./info.txt +./symlinks +./symlinks/symlink_chain_1 -> ../enclosures/lion_house/symlink_chain_2 ./symlinks/very_long_symlink -> ../enclosures/aquarium/tank_2/this_is_a_very_very_long_fish_filename_that_keeps_going_and_going_until_it_almost_breaks_linux_filesystem_limits_for_testing_purposes_and_we_add_more_characters_to_make_it_even_longer_30.txt diff --git a/arch/x86_64/support/modules/ext2_4KB_fs.img b/arch/x86_64/support/modules/ext2_4KB_fs.img index 2cd452f..c3f6daf 100644 --- a/arch/x86_64/support/modules/ext2_4KB_fs.img +++ b/arch/x86_64/support/modules/ext2_4KB_fs.img @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:62e1fa40f95e0cb037c43e3f55d0094ab6cb4d68e00914f555a90faf7cc00c31 +oid sha256:026ca30269dbd80beb2dd74677c94676d1d4a7f6b5fe406c4ddb82836ba2dc00 size 10485760 -- cgit v1.2.3 From 91821da0110e05724640903434c3d85fc3d02466 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Tue, 12 May 2026 12:00:40 +0200 Subject: if the boot_root_fs contains a /dev directory, vfs mounts the devfs onto the existing directory --- arch/x86_64/support/modules/README.md | 3 +++ arch/x86_64/support/modules/ext2_2KB_fs.img | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/x86_64/support/modules/README.md b/arch/x86_64/support/modules/README.md index 1a29ce5..6d235a7 100644 --- a/arch/x86_64/support/modules/README.md +++ b/arch/x86_64/support/modules/README.md @@ -40,6 +40,9 @@ The ext2_4KB_fs image is intentionally fragmented, as some files were created an (ext2 filesystem 4KB Block size) . ./lost+found +./dev +./dev/image_1.txt +./dev/image_2.txt ./snake_1.txt ./snake_2.txt ./petting_zoo/goat_1.txt diff --git a/arch/x86_64/support/modules/ext2_2KB_fs.img b/arch/x86_64/support/modules/ext2_2KB_fs.img index 8327022..7f297f0 100644 --- a/arch/x86_64/support/modules/ext2_2KB_fs.img +++ b/arch/x86_64/support/modules/ext2_2KB_fs.img @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a1d102f2e40083613060d43b2b32d31031137bbef99761a2d1bf4d38e155adb7 +oid sha256:6d9e872916e7d9107b321cc007e151899d5f19400a694666c0b24d482aef61ca size 5242880 -- cgit v1.2.3 From dc9bd3b44cbbd0235a176f05c27eb15ff31f5e09 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 22 May 2026 20:18:05 +0200 Subject: kernel/vfs: prepare fs type registration support --- arch/x86_64/scripts/kernel.ld | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch') diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index a429570..388c46e 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -72,6 +72,11 @@ SECTIONS .kernel_rodata ALIGN(4K) : AT (ADDR (.kernel_rodata) - TEACHOS_VMA) { *(.rodata*) + + . = ALIGN(8); + PROVIDE(__vfs_type_descriptors_begin = .); + KEEP(*(.vfs_type_descriptors*)); + PROVIDE(__vfs_type_descriptors_end = .); } :kernel_rodata .kernel_data ALIGN(4K) : AT (ADDR (.kernel_data) - TEACHOS_VMA) -- cgit v1.2.3 From 86170be29f6cb72b29865db0975de09bec89f854 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 1 Jun 2026 10:40:39 +0200 Subject: kernel/vfs: rename type descriptor section --- arch/x86_64/scripts/kernel.ld | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 388c46e..a1d8a65 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -74,9 +74,9 @@ SECTIONS *(.rodata*) . = ALIGN(8); - PROVIDE(__vfs_type_descriptors_begin = .); - KEEP(*(.vfs_type_descriptors*)); - PROVIDE(__vfs_type_descriptors_end = .); + PROVIDE(__start_vfs_type_descriptors = .); + KEEP(*(vfs_type_descriptors)); + PROVIDE(__stop_vfs_type_descriptors = .); } :kernel_rodata .kernel_data ALIGN(4K) : AT (ADDR (.kernel_data) - TEACHOS_VMA) -- cgit v1.2.3 From d2d4fa3330a09f421b8658c077166cc493532b9e Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Jun 2026 10:54:17 +0200 Subject: kernel/vfs: extract fs type registry --- arch/x86_64/scripts/kernel.ld | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index a1d8a65..dbb0f8f 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -74,9 +74,10 @@ SECTIONS *(.rodata*) . = ALIGN(8); - PROVIDE(__start_vfs_type_descriptors = .); - KEEP(*(vfs_type_descriptors)); - PROVIDE(__stop_vfs_type_descriptors = .); + + PROVIDE(__start_fs_types = .); + KEEP(*(fs_types)); + PROVIDE(__stop_fs_types = .); } :kernel_rodata .kernel_data ALIGN(4K) : AT (ADDR (.kernel_data) - TEACHOS_VMA) -- cgit v1.2.3