From 3a2efa4ebc6b07a2304416262d5032a32dcddd8b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 13:06:17 +0000 Subject: x86_64: fix syscall error code reading --- arch/x86_64/src/context_switching/syscall/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp index e291c10..b4ab468 100644 --- a/arch/x86_64/src/context_switching/syscall/main.cpp +++ b/arch/x86_64/src/context_switching/syscall/main.cpp @@ -27,7 +27,7 @@ namespace teachos::arch::context_switching::syscall asm volatile("mov %%r9, %[output]" : [output] "=m"(values.arg_5)); error error_code{}; - asm volatile("mov %%rax, %[output]" : [output] "=m"(error_code)); + asm volatile("mov %%al, %[output]" : [output] "=m"(error_code)); return {error_code, values}; } -- cgit v1.2.3 From e7eedd234954509f4f5ec52b2d62cbc4a1723936 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 15:39:09 +0000 Subject: libs: begin extraction of kernel std --- .../src/memory/heap/linked_list_allocator.cpp | 2 +- arch/x86_64/src/memory/multiboot/reader.cpp | 250 +++++++++++---------- arch/x86_64/src/stl/mutex.cpp | 16 -- 3 files changed, 128 insertions(+), 140 deletions(-) delete mode 100644 arch/x86_64/src/stl/mutex.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp index 63a6111..00ca366 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -9,7 +9,7 @@ namespace teachos::arch::memory::heap { linked_list_allocator::linked_list_allocator(std::size_t heap_start, std::size_t heap_end) : first(nullptr) - , mutex{stl::mutex{}} + , mutex{kstd::mutex{}} { auto const heap_size = heap_end - heap_start; exception_handling::assert( diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp index 2bf5b25..b05e6b3 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -2,130 +2,134 @@ #include "arch/boot/pointers.hpp" #include "arch/exception_handling/assert.hpp" -#include "arch/memory/multiboot/elf_symbols_section.hpp" -#include "arch/memory/multiboot/info.hpp" +#include "multiboot2/information.hpp" +// #include "arch/memory/multiboot/elf_symbols_section.hpp" +// #include "arch/memory/multiboot/info.hpp" #include #include -namespace teachos::arch::memory::multiboot -{ - namespace - { - template - requires std::is_pointer::value - auto align_to_8_byte_boundary(T ptr, uint32_t size) -> T - { - return reinterpret_cast(reinterpret_cast(ptr) + ((size + 7) & ~7)); - } - - auto process_memory_map(memory_map_header * mminfo) -> memory_area_container - { - auto const expected_entry_size = mminfo->entry_size; - auto constexpr actual_entry_size = sizeof(memory_area); - exception_handling::assert(expected_entry_size == actual_entry_size, - "[Multiboot Reader] Unexpected memory area entry size"); - - auto const total_size = mminfo->info.size; - auto const total_entries_size = total_size - sizeof(memory_map_header) + actual_entry_size; - auto const number_of_entries = total_entries_size / actual_entry_size; - - auto const begin = memory_area_container::iterator{&mminfo->entries}; - auto const end = begin + number_of_entries; - return memory_area_container{begin, end}; - } - - auto process_elf_sections(elf_symbols_section_header * symbol, std::size_t & kernel_start, - std::size_t & kernel_end) -> elf_section_header_container - { - auto const expected_entry_size = symbol->entry_size; - auto constexpr actual_entry_size = sizeof(elf_section_header); - exception_handling::assert(expected_entry_size == actual_entry_size, - "[Multiboot Reader] Unexpected elf section header entry size"); - - auto const expected_total_size = symbol->info.size; - auto const actual_total_entry_size = actual_entry_size * symbol->number_of_sections; - auto constexpr actual_total_section_size = sizeof(elf_symbols_section_header) - sizeof(uint32_t); - auto const actual_total_size = actual_total_entry_size + actual_total_section_size; - exception_handling::assert(expected_total_size == actual_total_size, - "[Multiboot Reader] Unexpected elf symbols section header total size"); - - auto const begin = elf_section_header_container::iterator{reinterpret_cast(&symbol->end)}; - auto const end = begin + symbol->number_of_sections; - exception_handling::assert(begin->is_null(), - "[Multiboot Reader] Elf symbols section not starting with SHT_NULL section"); - - elf_section_header_container sections{begin, end}; - - auto allocated_sections = sections | std::views::filter([](auto const & section) { - return section.flags.contains_flags(elf_section_flags::OCCUPIES_MEMORY); - }); - - auto const elf_section_with_lowest_physical_address = std::ranges::min_element( - allocated_sections, [](auto const & a, auto const & b) { return a.physical_address < b.physical_address; }); - - auto const elf_section_with_highest_physical_address = - std::ranges::max_element(allocated_sections, [](auto const & a, auto const & b) { - auto a_physical_address_end = a.physical_address + a.section_size; - auto b_physical_address_end = b.physical_address + b.section_size; - return a_physical_address_end < b_physical_address_end; - }); - - auto const symbol_table_section_count = std::ranges::count_if(sections, [](auto const & section) { - return section.type == elf_section_type::DYNAMIC_SYMBOL_TABLE || section.type == elf_section_type::SYMBOL_TABLE; - }); - auto const dynamic_section_count = std::ranges::count_if( - sections, [](auto const & section) { return section.type == elf_section_type::DYNAMIC; }); - - exception_handling::assert( - symbol_table_section_count == 1U, - "[Multiboot Reader] ELF Specifications allows only (1) symbol table section, but got more"); - exception_handling::assert( - dynamic_section_count <= 1U, - "[Multiboot Reader] ELF Specifications allows only (1) or less dynamic sections, but got more"); - - auto const lowest_elf_section = *elf_section_with_lowest_physical_address; - kernel_start = lowest_elf_section.physical_address; - - auto const highest_elf_section = *elf_section_with_highest_physical_address; - kernel_end = highest_elf_section.physical_address + highest_elf_section.section_size; - - return sections; - } - } // namespace - - auto read_multiboot2() -> memory_information - { - memory_information mem_info{UINT64_MAX, - 0U, - elf_section_header_container{}, - boot::multiboot_information_pointer, - 0U, - memory_area_container{}}; - - auto const multiboot_information_pointer = reinterpret_cast(boot::multiboot_information_pointer); - auto const multiboot_tag = &multiboot_information_pointer->tags; - mem_info.multiboot_end = mem_info.multiboot_start + multiboot_information_pointer->total_size; - - for (auto tag = multiboot_tag; tag->type != tag_type::END; tag = align_to_8_byte_boundary(tag, tag->size)) - { - switch (tag->type) - { - case tag_type::ELF_SECTIONS: { - auto const symbol = reinterpret_cast(tag); - mem_info.sections = process_elf_sections(symbol, mem_info.kernel_start, mem_info.kernel_end); - break; - } - case tag_type::MEMORY_MAP: { - auto const mminfo = reinterpret_cast(tag); - mem_info.areas = process_memory_map(mminfo); - break; - } - default: - // All other cases are not important and can be ignored. - break; - } - } - return mem_info; - } -} // namespace teachos::arch::memory::multiboot +// namespace teachos::arch::memory::multiboot +// { +// namespace +// { +// template +// requires std::is_pointer::value +// auto align_to_8_byte_boundary(T ptr, uint32_t size) -> T +// { +// return reinterpret_cast(reinterpret_cast(ptr) + ((size + 7) & ~7)); +// } + +// auto process_memory_map(memory_map_header * mminfo) -> memory_area_container +// { +// auto const expected_entry_size = mminfo->entry_size; +// auto constexpr actual_entry_size = sizeof(memory_area); +// exception_handling::assert(expected_entry_size == actual_entry_size, +// "[Multiboot Reader] Unexpected memory area entry size"); + +// auto const total_size = mminfo->info.size; +// auto const total_entries_size = total_size - sizeof(memory_map_header) + actual_entry_size; +// auto const number_of_entries = total_entries_size / actual_entry_size; + +// auto const begin = memory_area_container::iterator{&mminfo->entries}; +// auto const end = begin + number_of_entries; +// return memory_area_container{begin, end}; +// } + +// auto process_elf_sections(elf_symbols_section_header * symbol, std::size_t & kernel_start, std::size_t & +// kernel_end) +// -> elf_section_header_container +// { +// auto const expected_entry_size = symbol->entry_size; +// auto constexpr actual_entry_size = sizeof(elf_section_header); +// exception_handling::assert(expected_entry_size == actual_entry_size, +// "[Multiboot Reader] Unexpected elf section header entry size"); + +// auto const expected_total_size = symbol->info.size; +// auto const actual_total_entry_size = actual_entry_size * symbol->number_of_sections; +// auto constexpr actual_total_section_size = sizeof(elf_symbols_section_header) - sizeof(uint32_t); +// auto const actual_total_size = actual_total_entry_size + actual_total_section_size; +// exception_handling::assert(expected_total_size == actual_total_size, +// "[Multiboot Reader] Unexpected elf symbols section header total size"); + +// auto const begin = elf_section_header_container::iterator{reinterpret_cast(&symbol->end)}; auto const end = begin + symbol->number_of_sections; +// exception_handling::assert(begin->is_null(), +// "[Multiboot Reader] Elf symbols section not starting with SHT_NULL section"); + +// elf_section_header_container sections{begin, end}; + +// auto allocated_sections = sections | std::views::filter([](auto const & section) { +// return section.flags.contains_flags(elf_section_flags::OCCUPIES_MEMORY); +// }); + +// auto const elf_section_with_lowest_physical_address = std::ranges::min_element( +// allocated_sections, [](auto const & a, auto const & b) { return a.physical_address < b.physical_address; +// }); + +// auto const elf_section_with_highest_physical_address = +// std::ranges::max_element(allocated_sections, [](auto const & a, auto const & b) { +// auto a_physical_address_end = a.physical_address + a.section_size; +// auto b_physical_address_end = b.physical_address + b.section_size; +// return a_physical_address_end < b_physical_address_end; +// }); + +// auto const symbol_table_section_count = std::ranges::count_if(sections, [](auto const & section) { +// return section.type == elf_section_type::DYNAMIC_SYMBOL_TABLE || section.type == +// elf_section_type::SYMBOL_TABLE; +// }); +// auto const dynamic_section_count = std::ranges::count_if( +// sections, [](auto const & section) { return section.type == elf_section_type::DYNAMIC; }); + +// exception_handling::assert( +// symbol_table_section_count == 1U, +// "[Multiboot Reader] ELF Specifications allows only (1) symbol table section, but got more"); +// exception_handling::assert( +// dynamic_section_count <= 1U, +// "[Multiboot Reader] ELF Specifications allows only (1) or less dynamic sections, but got more"); + +// auto const lowest_elf_section = *elf_section_with_lowest_physical_address; +// kernel_start = lowest_elf_section.physical_address; + +// auto const highest_elf_section = *elf_section_with_highest_physical_address; +// kernel_end = highest_elf_section.physical_address + highest_elf_section.section_size; + +// return sections; +// } +// } // namespace + +// auto read_multiboot2() -> memory_information +// { +// memory_information mem_info{UINT64_MAX, +// 0U, +// elf_section_header_container{}, +// boot::multiboot_information_pointer, +// 0U, +// memory_area_container{}}; + +// auto const multiboot_information_pointer = reinterpret_cast(boot::multiboot_information_pointer); +// auto const multiboot_tag = &multiboot_information_pointer->tags; +// mem_info.multiboot_end = mem_info.multiboot_start + multiboot_information_pointer->total_size; + +// for (auto tag = multiboot_tag; tag->type != tag_type::END; tag = align_to_8_byte_boundary(tag, tag->size)) +// { +// switch (tag->type) +// { +// case tag_type::ELF_SECTIONS: { +// auto const symbol = reinterpret_cast(tag); +// mem_info.sections = process_elf_sections(symbol, mem_info.kernel_start, mem_info.kernel_end); +// break; +// } +// case tag_type::MEMORY_MAP: { +// auto const mminfo = reinterpret_cast(tag); +// mem_info.areas = process_memory_map(mminfo); +// break; +// } +// default: +// // All other cases are not important and can be ignored. +// break; +// } +// } +// return mem_info; +// } +// } // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/src/stl/mutex.cpp b/arch/x86_64/src/stl/mutex.cpp deleted file mode 100644 index 232a11c..0000000 --- a/arch/x86_64/src/stl/mutex.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "arch/stl/mutex.hpp" - -namespace teachos::arch::stl -{ - auto mutex::lock() -> void - { - while (!try_lock()) - { - // Nothing to do - } - } - - auto mutex::try_lock() -> bool { return !locked.exchange(true, std::memory_order_acquire); } - - auto mutex::unlock() -> void { locked.store(false, std::memory_order_release); } -} // namespace teachos::arch::stl -- cgit v1.2.3 From ec572bff8150e2f8cd2dc99e053c5e8c8a0b99e3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 16:25:00 +0000 Subject: arch: prepare interfaces --- arch/x86_64/src/boot/boot.s | 2 +- arch/x86_64/src/io.cpp | 22 ++++++++++++++++ arch/x86_64/src/memory.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++++ arch/x86_64/src/system.cpp | 12 +++++++++ 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 arch/x86_64/src/io.cpp create mode 100644 arch/x86_64/src/memory.cpp create mode 100644 arch/x86_64/src/system.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 7932045..5488073 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -364,5 +364,5 @@ _transition_to_long_mode: call _init - call kernel_main + call main call halt diff --git a/arch/x86_64/src/io.cpp b/arch/x86_64/src/io.cpp new file mode 100644 index 0000000..8808dbb --- /dev/null +++ b/arch/x86_64/src/io.cpp @@ -0,0 +1,22 @@ +namespace teachos::arch::io +{ + + // using x86_64::vga::text_mode::attributes; + // using x86_64::vga::text_mode::color; + + // namespace + // { + // auto constexpr error_attributes = + // attributes{.foreground = color::light_gray, .bright = true, .background = color::red, .blink = true}; + // } // namespace + + auto init() -> void + { + // kernel::set_print_handler([](auto text) { return x86_64::vga::text_mode::print(text); }); + // kernel::set_println_handler([](auto text) { return x86_64::vga::text_mode::println(text); }); + // kernel::set_print_error_handler([](auto text) { return x86_64::vga::text_mode::print(text, error_attributes); }); + // kernel::set_println_error_handler( + // [](auto text) { return x86_64::vga::text_mode::println(text, error_attributes); }); + } + +} // namespace teachos::arch::io diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp new file mode 100644 index 0000000..245d7bd --- /dev/null +++ b/arch/x86_64/src/memory.cpp @@ -0,0 +1,62 @@ +#include "arch/memory.hpp" + +// #include "noarch/error.hpp" +// #include "noarch/print.hpp" +// #include "x86_64/bootstrap/mutiboot.hpp" +// #include "x86_64/memory/frame_allocator.hpp" +// #include "x86_64/memory/mbi_frame_allocator.hpp" + +// #include +// #include +// #include +// #include + +namespace teachos::arch::memory +{ + + // namespace + // { + // /** + // * @brief Remap the kernel according to the ELF information. + // * + // * After initial bootup, a basic identity mapping of the lower 1GiB is set up. This mapping allows execution + // from, + // * as well as read and write access to, the mapped memory. In order to protect the kernel, remap it according to + // the + // * information supplied by the ELF file. This means remapping code sections as read-only and data sections as + // * no-execute (and read only for .rodata). + // * + // * @param sections Information about the sections in the loaded kernel binary. + // * @param allocator The frame allocator used to create new page mappings. + // */ + // auto remap_kernel(elf::section_header_table const & sections, x86_64::memory::frame_allocator & allocator) -> + // void + // { + // static_cast(sections); + // static_cast(allocator); + // } + // } // namespace + + auto init() -> void + { + // kernel::println("Initializing memory"); + + // if (!x86_64::bootstrap::multiboot_information_pointer->has()) + // { + // kernel::panic("Received no memory map from the boot loader!"); + // } + + // if (!x86_64::bootstrap::multiboot_information_pointer->has()) + // { + // kernel::panic("Received no ELF symbol information from the boot loader!"); + // } + + // auto memory_map = x86_64::bootstrap::multiboot_information_pointer->memory_map(); + // auto elf_symbols = x86_64::bootstrap::multiboot_information_pointer->elf_symbols(); + // auto section_header_table = elf::section_header_table{elf_symbols.data(), elf::file_class::bits_64}; + // auto allocator = x86_64::memory::mbi_frame_allocator{memory_map, section_header_table}; + + // remap_kernel(section_header_table, allocator); + } + +} // namespace teachos::arch::memory diff --git a/arch/x86_64/src/system.cpp b/arch/x86_64/src/system.cpp new file mode 100644 index 0000000..60ebf0e --- /dev/null +++ b/arch/x86_64/src/system.cpp @@ -0,0 +1,12 @@ +#include "arch/system.hpp" + +namespace teachos::arch::system +{ + + auto halt() -> void + { + asm volatile("1: hlt\njmp 1b"); + __builtin_unreachable(); + } + +} // namespace teachos::arch::system -- cgit v1.2.3 From 3a47a8bd0edcfa3aa03562d0a5c390ef85ad0c6b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 21:08:02 +0000 Subject: x86_64: move basic text output implementation --- arch/x86_64/src/io.cpp | 28 ++++++++-------- arch/x86_64/src/vga/text.cpp | 66 ++++++++++++++++++++++++++++++++++++++ arch/x86_64/src/video/vga/text.cpp | 66 -------------------------------------- 3 files changed, 80 insertions(+), 80 deletions(-) create mode 100644 arch/x86_64/src/vga/text.cpp delete mode 100644 arch/x86_64/src/video/vga/text.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/io.cpp b/arch/x86_64/src/io.cpp index 8808dbb..5fb1c85 100644 --- a/arch/x86_64/src/io.cpp +++ b/arch/x86_64/src/io.cpp @@ -1,22 +1,22 @@ +#include "kern/print.hpp" +#include "x86_64/vga/text.hpp" + namespace teachos::arch::io { - // using x86_64::vga::text_mode::attributes; - // using x86_64::vga::text_mode::color; - - // namespace - // { - // auto constexpr error_attributes = - // attributes{.foreground = color::light_gray, .bright = true, .background = color::red, .blink = true}; - // } // namespace - auto init() -> void { - // kernel::set_print_handler([](auto text) { return x86_64::vga::text_mode::print(text); }); - // kernel::set_println_handler([](auto text) { return x86_64::vga::text_mode::println(text); }); - // kernel::set_print_error_handler([](auto text) { return x86_64::vga::text_mode::print(text, error_attributes); }); - // kernel::set_println_error_handler( - // [](auto text) { return x86_64::vga::text_mode::println(text, error_attributes); }); + teachos::set_print_handler( + [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); }); + teachos::set_println_handler( + [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); }); + + teachos::set_print_error_handler( + [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); }); + teachos::set_println_error_handler( + [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); }); + + teachos::println("[x86-64] Basic VGA text output initialized."); } } // namespace teachos::arch::io diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp new file mode 100644 index 0000000..9b7946d --- /dev/null +++ b/arch/x86_64/src/vga/text.cpp @@ -0,0 +1,66 @@ +#include "x86_64/vga/text.hpp" + +#include "arch/asm_pointer.hpp" +#include "x86_64/vga/io.hpp" + +#include +#include +#include +#include + +extern "C" teachos::arch::asm_pointer> vga_buffer_pointer; + +namespace teachos::x86_64::vga::text +{ + namespace + { + // auto constexpr DEFAULT_VGA_TEXT_BUFFER_ADDRESS = 0xB8000; + + auto buffer_offset = std::ptrdiff_t{}; + + auto constexpr DEFAULT_TEXT_BUFFER_WIDTH = 80U; + auto constexpr DEFAULT_TEXT_BUFFER_HEIGHT = 25U; + } // namespace + + auto clear(attribute attribute) -> void + { + buffer_offset = 0; + std::ranges::fill_n(vga_buffer_pointer.get(), 2000, std::pair{' ', attribute}); + } + + auto cursor(bool enabled) -> void + { + auto cursor_disable_byte = std::byte{!enabled} << 5; + + io::crtc::address_port::write(io::crtc::registers::cursor_start); + io::crtc::data_port::write(io::crtc::data_port::read() | cursor_disable_byte); + } + + auto newline() -> void + { + auto current_line = buffer_offset / DEFAULT_TEXT_BUFFER_WIDTH; + auto next_line = current_line + 1; + + if (next_line >= DEFAULT_TEXT_BUFFER_HEIGHT) + { + auto begin = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH; + auto end = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT; + std::ranges::move(begin, end, vga_buffer_pointer.get()); + buffer_offset = current_line * DEFAULT_TEXT_BUFFER_WIDTH; + } + else + { + buffer_offset = next_line * DEFAULT_TEXT_BUFFER_WIDTH; + } + } + + auto write_char(char code_point, attribute attribute) -> void + { + vga_buffer_pointer[buffer_offset++] = std::pair{code_point, attribute}; + }; + + auto write(std::string_view code_points, attribute attribute) -> void + { + std::ranges::for_each(code_points, [&](auto code_point) { write_char(code_point, attribute); }); + } +} // namespace teachos::x86_64::vga::text diff --git a/arch/x86_64/src/video/vga/text.cpp b/arch/x86_64/src/video/vga/text.cpp deleted file mode 100644 index b070a0a..0000000 --- a/arch/x86_64/src/video/vga/text.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "arch/video/vga/text.hpp" - -#include "arch/video/vga/io.hpp" -#include "memory/asm_pointer.hpp" - -#include -#include -#include - -extern "C" std::pair * vga_buffer_pointer; - -namespace teachos::arch::video::vga::text -{ - namespace - { - auto constexpr DEFAULT_TEXT_BUFFER_WIDTH = 80U; - auto constexpr DEFAULT_TEXT_BUFFER_HEIGHT = 25U; - - auto constinit text_buffer = teachos::memory::asm_pointer{vga_buffer_pointer}; - } // namespace - - auto clear(attribute attribute) -> void - { - *text_buffer = reinterpret_cast(DEFAULT_VGA_TEXT_BUFFER_ADDRESS); - std::ranges::fill_n(*text_buffer, 2000, std::pair{' ', attribute}); - } - - auto cursor(bool enabled) -> void - { - auto cursor_disable_byte = std::byte{!enabled} << 5; - - crtc::address_port::write(crtc::registers::cursor_start); - crtc::data_port::write(vga::crtc::data_port::read() | cursor_disable_byte); - } - - auto newline() -> void - { - auto base = reinterpret_cast(DEFAULT_VGA_TEXT_BUFFER_ADDRESS); - auto & raw_buffer = *text_buffer; - auto current_line = (raw_buffer - base) / DEFAULT_TEXT_BUFFER_WIDTH; - auto next_line = current_line + 1; - - if (next_line >= DEFAULT_TEXT_BUFFER_HEIGHT) - { - auto begin = base + DEFAULT_TEXT_BUFFER_WIDTH; - auto end = base + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT; - std::ranges::move(begin, end, base); - raw_buffer = base + current_line * DEFAULT_TEXT_BUFFER_WIDTH; - } - else - { - raw_buffer = base + next_line * DEFAULT_TEXT_BUFFER_WIDTH; - } - } - - auto write_char(char code_point, attribute attribute) -> void - { - auto & p = *text_buffer; - (*p++) = std::pair{code_point, attribute}; - }; - - auto write(std::string_view code_points, attribute attribute) -> void - { - std::ranges::for_each(code_points, [&](auto code_point) { write_char(code_point, attribute); }); - } -} // namespace teachos::arch::video::vga::text -- cgit v1.2.3 From 05ac8c2bdd000d27b38411db2223eabb649c318f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 21:29:10 +0000 Subject: build: reintroduce bootable ISO --- arch/x86_64/src/boot/boot.s | 2 +- arch/x86_64/src/io.cpp | 14 ++++++++++---- arch/x86_64/src/vga/text.cpp | 2 -- 3 files changed, 11 insertions(+), 7 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 5488073..728380d 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -105,7 +105,7 @@ mesage_long_mode_not_supported: * We need a pointer to our current position in the VGA text buffer. */ .global vga_buffer_pointer -vga_buffer_pointer: .long 0xb8000 +vga_buffer_pointer: .quad 0xb8000 /** * Code for the bootstrapping process. diff --git a/arch/x86_64/src/io.cpp b/arch/x86_64/src/io.cpp index 5fb1c85..8e9e411 100644 --- a/arch/x86_64/src/io.cpp +++ b/arch/x86_64/src/io.cpp @@ -6,15 +6,21 @@ namespace teachos::arch::io auto init() -> void { + x86_64::vga::text::cursor(false); + teachos::set_print_handler( [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); }); - teachos::set_println_handler( - [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); }); + teachos::set_println_handler([](auto text) { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); + x86_64::vga::text::newline(); + }); teachos::set_print_error_handler( [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); }); - teachos::set_println_error_handler( - [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); }); + teachos::set_println_error_handler([](auto text) { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); + x86_64::vga::text::newline(); + }); teachos::println("[x86-64] Basic VGA text output initialized."); } diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 9b7946d..16abf08 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -14,8 +14,6 @@ namespace teachos::x86_64::vga::text { namespace { - // auto constexpr DEFAULT_VGA_TEXT_BUFFER_ADDRESS = 0xB8000; - auto buffer_offset = std::ptrdiff_t{}; auto constexpr DEFAULT_TEXT_BUFFER_WIDTH = 80U; -- cgit v1.2.3 From a832505d9696ae66248b53602d41637bef4868aa Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 18 Jul 2025 10:49:03 +0000 Subject: kernel: turn into a PIE --- arch/x86_64/src/boot/boot.s | 112 ++++++++++++++++++++++++++++++++------------ 1 file changed, 82 insertions(+), 30 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 728380d..ada6426 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -71,16 +71,7 @@ stack_top: global_descriptor_table: .quad 0 global_descriptor_table_code = . - global_descriptor_table .quad (1<<43) | (1<<44) | (1<<47) | (1<<53) - -/** - * We also need a pointer that we can load into the GDTR. - * - * The pointer consists of a word describing the size of the table minus 1 and - * the pointer to the actual table. - */ -global_descriptor_table_pointer: -.word . - global_descriptor_table - 1 -.quad global_descriptor_table +global_descriptor_table_end: /** * We are going to print some messages in case we panic during boot, so we are @@ -130,7 +121,12 @@ _panic: push %ebp mov %esp, %ebp - push message_prefix_panic + call .Lpanic_get_ip +.Lpanic_get_ip: + pop %eax + lea (message_prefix_panic - .Lpanic_get_ip)(%eax), %eax + + push %eax push $0x4f call _print add $8, %esp @@ -155,10 +151,17 @@ _print: push %ebx push %esi + push %edi + + call .Lprint_get_ip +.Lprint_get_ip: + pop %edi + lea (vga_buffer_pointer - .Lprint_get_ip)(%edi), %edi + mov 8(%ebp), %eax mov 12(%ebp), %ebx mov $0, %ecx - mov (vga_buffer_pointer), %esi + mov (%edi), %esi .Lprint_loop: mov (%ebx, %ecx), %dl @@ -171,9 +174,11 @@ _print: .Lupdate_vga_buffer_address: shl $1, %ecx - add %ecx, (vga_buffer_pointer) + add %ecx, %esi + mov %esi, (%edi) .Lprint_end: + pop %edi pop %esi pop %ebx mov %ebp, %esp @@ -187,7 +192,12 @@ _print: */ .global _start _start: - mov $stack_top, %esp + call .Lstart_get_ip +.Lstart_get_ip: + pop %esi + lea (stack_top - .Lstart_get_ip)(%esi), %ebx + + mov %ebx, %esp mov %esp, %ebp call assert_loaded_by_multiboot2_loader @@ -197,8 +207,19 @@ _start: call enable_paging call enable_sse - lgdt (global_descriptor_table_pointer) - jmp $global_descriptor_table_code, $_transition_to_long_mode + sub $10, %esp + lea (global_descriptor_table - .Lstart_get_ip)(%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 + + lea (_transition_to_long_mode - .Lstart_get_ip)(%esi), %eax + pushl $global_descriptor_table_code + pushl %eax + lret call halt @@ -217,7 +238,11 @@ assert_cpu_supports_long_mode: jz .Llong_mode_assertion_failed ret .Llong_mode_assertion_failed: - push $mesage_long_mode_not_supported + call .Lassert_cpu_supports_long_mode_fail_get_ip +.Lassert_cpu_supports_long_mode_fail_get_ip: + pop %eax + lea (mesage_long_mode_not_supported - .Lassert_cpu_supports_long_mode_fail_get_ip)(%eax), %eax + push %eax call _panic /** @@ -245,7 +270,11 @@ assert_cpuid_instruction_is_supported: je .Lcpuid_assertion_fail ret .Lcpuid_assertion_fail: - push $message_cpuid_instruction_no_supported + call .Lassert_cpuid_instruction_is_supported_fail_get_ip +.Lassert_cpuid_instruction_is_supported_fail_get_ip: + pop %eax + lea (message_cpuid_instruction_no_supported - .Lassert_cpuid_instruction_is_supported_fail_get_ip)(%eax), %eax + push %eax call _panic /** @@ -259,10 +288,18 @@ assert_loaded_by_multiboot2_loader: cmp $0x36d76289, %eax /* Check if we received the expected magic */ jne .Lmultiboot2_assertion_fail /* Panic otherwise */ - mov %ebx, multiboot_information_pointer /* Store the MBI pointer */ + call .Lassert_loaded_by_multiboot2_loader_get_ip +.Lassert_loaded_by_multiboot2_loader_get_ip: + pop %eax + lea (multiboot_information_pointer - .Lassert_loaded_by_multiboot2_loader_get_ip)(%eax), %eax + mov %ebx, (%eax) /* Store the MBI pointer */ ret .Lmultiboot2_assertion_fail: - push $message_not_loaded_by_multiboot2 + call .Lassert_loaded_by_multiboot2_loader_fail_get_ip +.Lassert_loaded_by_multiboot2_loader_fail_get_ip: + pop %eax + lea (message_not_loaded_by_multiboot2 - .Lassert_loaded_by_multiboot2_loader_fail_get_ip)(%eax), %eax + push %eax call _panic /** @@ -272,7 +309,10 @@ assert_loaded_by_multiboot2_loader: * set up for use. */ enable_paging: - mov $page_map_level_4, %eax + call .Lenable_paging_get_ip +.Lenable_paging_get_ip: + pop %eax +lea (page_map_level_4 - .Lenable_paging_get_ip)(%eax), %eax mov %eax, %cr3 /* Enable Physical Address Extension */ @@ -316,37 +356,46 @@ enable_sse: * page map entries. */ prepare_page_maps: + call .Lprepare_page_maps_get_ip +.Lprepare_page_maps_get_ip: + pop %edi /* Map the P4 table recursively */ - mov $page_map_level_4, %eax + lea (page_map_level_4 - .Lprepare_page_maps_get_ip)(%edi), %eax + mov %eax, %ebx or $0b11, %eax /* Write present + writable flags into eax register */ - mov %eax, (page_map_level_4 + 511 * 8) + mov %eax, (511 * 8)(%ebx) /* Add an entry to the PML4, pointing to the PML3 */ - mov $page_map_level_3, %eax + lea (page_map_level_3 - .Lprepare_page_maps_get_ip)(%edi), %eax + lea (page_map_level_4 - .Lprepare_page_maps_get_ip)(%edi), %ebx or $0x3, %eax - mov %eax, (page_map_level_4 + ((0x0000000000100000 >> 39) & 0x1ff) * 8) + mov %eax, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%ebx) /* Add an entry to the PML3, pointing to the PML2 */ - mov $page_map_level_2, %eax + lea (page_map_level_2 - .Lprepare_page_maps_get_ip)(%edi), %eax + lea (page_map_level_3 - .Lprepare_page_maps_get_ip)(%edi), %ebx or $0x3, %eax - mov %eax, (page_map_level_3 + ((0x0000000000100000 >> 30) & 0x1ff) * 8) + mov %eax, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%ebx) xor %ecx, %ecx - mov $_end_linear, %esi + push %esi + lea (_end_linear - .Lprepare_page_maps_get_ip)(%edi), %esi shr $21, %esi add $2, %esi .Lmap_pages: + lea (page_map_level_2 - .Lprepare_page_maps_get_ip)(%edi), %ebx mov $(1 << 21), %eax mul %ecx or $((1 << 0) | (1 << 1) | (1 << 7)), %eax - mov %eax, page_map_level_2(,%ecx,8) + mov %eax, (%ebx,%ecx,8) inc %ecx cmp %esi, %ecx jne .Lmap_pages + pop %esi ret .section .boot_text, "ax", @progbits @@ -360,7 +409,10 @@ _transition_to_long_mode: mov %rax, %fs mov %rax, %gs - movl $0xb8000, (vga_buffer_pointer) + leaq vga_buffer_pointer(%rip), %rax + movl $0xb8000, (%rax) + + xor %rax, %rax call _init -- cgit v1.2.3 From 14ed096fc5de6844cb116f3319c0d03043d26ea2 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 17 Jul 2025 21:09:02 +0000 Subject: x86-64: prepare new architecture --- arch/x86_64/src/boot/boot.s | 2 +- arch/x86_64/src/memory.cpp | 90 ++++++++++---------- .../x86_64/src/memory/allocator/physical_frame.cpp | 24 ------ arch/x86_64/src/memory/region_allocator.cpp | 95 ++++++++++++++++++++++ 4 files changed, 137 insertions(+), 74 deletions(-) delete mode 100644 arch/x86_64/src/memory/allocator/physical_frame.cpp create mode 100644 arch/x86_64/src/memory/region_allocator.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index ada6426..e0cff7c 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -12,7 +12,7 @@ * Reserve some space for the Multiboot 2 information pointer. */ .global multiboot_information_pointer -multiboot_information_pointer: .skip 4 +multiboot_information_pointer: .skip 8 /** * Align page maps to 4 KiB or the assembler code, will cause crashes when attempting to enable paging. diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp index 245d7bd..2b16beb 100644 --- a/arch/x86_64/src/memory.cpp +++ b/arch/x86_64/src/memory.cpp @@ -1,62 +1,54 @@ #include "arch/memory.hpp" -// #include "noarch/error.hpp" -// #include "noarch/print.hpp" -// #include "x86_64/bootstrap/mutiboot.hpp" -// #include "x86_64/memory/frame_allocator.hpp" -// #include "x86_64/memory/mbi_frame_allocator.hpp" +#include "kern/error.hpp" -// #include -// #include -// #include -// #include +#include "arch/asm_pointer.hpp" +#include "x86_64/memory/region_allocator.hpp" -namespace teachos::arch::memory -{ +#include - // namespace - // { - // /** - // * @brief Remap the kernel according to the ELF information. - // * - // * After initial bootup, a basic identity mapping of the lower 1GiB is set up. This mapping allows execution - // from, - // * as well as read and write access to, the mapped memory. In order to protect the kernel, remap it according to - // the - // * information supplied by the ELF file. This means remapping code sections as read-only and data sections as - // * no-execute (and read only for .rodata). - // * - // * @param sections Information about the sections in the loaded kernel binary. - // * @param allocator The frame allocator used to create new page mappings. - // */ - // auto remap_kernel(elf::section_header_table const & sections, x86_64::memory::frame_allocator & allocator) -> - // void - // { - // static_cast(sections); - // static_cast(allocator); - // } - // } // namespace +#include - auto init() -> void - { - // kernel::println("Initializing memory"); +extern "C" teachos::arch::asm_pointer multiboot_information_pointer; - // if (!x86_64::bootstrap::multiboot_information_pointer->has()) - // { - // kernel::panic("Received no memory map from the boot loader!"); - // } +namespace teachos::arch::memory +{ + namespace + { + auto constinit is_initialized = std::atomic_flag{}; - // if (!x86_64::bootstrap::multiboot_information_pointer->has()) - // { - // kernel::panic("Received no ELF symbol information from the boot loader!"); - // } + // auto create_memory_information() -> x86_64::memory::region_allocator::memory_information { - // auto memory_map = x86_64::bootstrap::multiboot_information_pointer->memory_map(); - // auto elf_symbols = x86_64::bootstrap::multiboot_information_pointer->elf_symbols(); - // auto section_header_table = elf::section_header_table{elf_symbols.data(), elf::file_class::bits_64}; - // auto allocator = x86_64::memory::mbi_frame_allocator{memory_map, section_header_table}; + // }; + } // namespace - // remap_kernel(section_header_table, allocator); + auto init() -> void + { + if (is_initialized.test_and_set()) + { + teachos::panic("[x86_64] Memory management has already been initialized."); + } + + auto memory_map = multiboot_information_pointer->maybe_memory_map(); + if (!memory_map) + { + teachos::panic("[x86_64] No memory map available."); + } + + // auto mem_info = x86_64::memory::region_allocator::memory_information{}; + // auto allocator = x86_64::memory::region_allocator{mem_info}; + + // kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); + // kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); + + // paging::kernel_mapper kernel(allocator, memory_information); + // kernel.remap_kernel(); + // video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); + // video::vga::text::newline(); + + // remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); + // video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); + // video::vga::text::newline(); } } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/memory/allocator/physical_frame.cpp b/arch/x86_64/src/memory/allocator/physical_frame.cpp deleted file mode 100644 index ec387a1..0000000 --- a/arch/x86_64/src/memory/allocator/physical_frame.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "arch/memory/allocator/physical_frame.hpp" - -namespace teachos::arch::memory::allocator -{ - auto physical_frame::containing_address(physical_address address) -> physical_frame - { - return physical_frame{address / PAGE_FRAME_SIZE}; - } - - auto physical_frame::start_address() const -> physical_address { return frame_number * PAGE_FRAME_SIZE; } - - auto physical_frame::operator++(int) -> physical_frame - { - physical_frame const old_value = *this; - ++frame_number; - return old_value; - } - - auto physical_frame::operator++() -> physical_frame & - { - ++frame_number; - return *this; - } -} // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp new file mode 100644 index 0000000..c9a98b4 --- /dev/null +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -0,0 +1,95 @@ +// #include "arch/memory/allocator/region_allocator.hpp" + +// #include "arch/exception_handling/assert.hpp" + +// #include +// #include +// #include + +#include "x86_64/memory/region_allocator.hpp" + +#include "x86_64/memory/address.hpp" +#include "x86_64/memory/frame.hpp" + +#include + +#include +#include + +namespace teachos::x86_64::memory +{ + namespace + { + auto constexpr last_frame(multiboot2::memory_map::region const & region) + { + return frame::containing(physical_address{region.base + region.size_in_B - 1}); + } + } // namespace + + region_allocator::region_allocator(memory_information const & mem_info) + : m_next_frame{} + , m_current_region{} + , m_memory_map{} + , m_kernel_start(frame::containing(mem_info.image_range.first)) + , m_kernel_end(frame::containing(mem_info.image_range.second)) + , m_multiboot_start(frame::containing(mem_info.mbi_range.first)) + , m_multiboot_end(frame::containing(mem_info.mbi_range.second)) + { + choose_next_area(); + } + + auto region_allocator::choose_next_area() -> void + { + m_current_region.reset(); + auto next_area_with_free_frames = + m_memory_map | std::views::filter(&multiboot2::memory_map::region::available) | + std::views::filter([next = m_next_frame](auto const & region) { return last_frame(region) >= next; }); + + auto lowest_region_with_free_frames = + std::ranges::min_element(next_area_with_free_frames, [](auto lhs, auto rhs) { return lhs.base < rhs.base; }); + + if (lowest_region_with_free_frames != next_area_with_free_frames.end()) + { + m_current_region = *lowest_region_with_free_frames; + auto start_frame = frame::containing(physical_address{m_current_region->base}); + if (m_next_frame < start_frame) + { + m_next_frame = start_frame; + } + } + } + + auto region_allocator::allocate_frame() -> std::optional + { + if (!m_current_region) + { + return {}; + } + + auto const end_address = physical_address{m_current_region->base + m_current_region->size_in_B - 1}; + auto end_frame = frame::containing(end_address); + + if (m_next_frame > end_frame) + { + choose_next_area(); + } + else if (m_next_frame >= m_kernel_start && m_next_frame <= m_kernel_end) + { + m_next_frame = m_kernel_end + 1; + } + else if (m_next_frame >= m_multiboot_start && m_next_frame <= m_multiboot_end) + { + m_next_frame = m_multiboot_end + 1; + } + else + { + auto allocated = m_next_frame; + ++m_next_frame; + return allocated; + } + + return allocate_frame(); + } + + auto region_allocator::deallocate_frame(frame const &) -> void {} +} // namespace teachos::x86_64::memory -- cgit v1.2.3 From 4ae38294b0db1870f82cc402dc4a8bb38cea4a67 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 18 Jul 2025 11:16:43 +0000 Subject: x86_64: don't lose multi boot information pointer Since the transition to a PIE, more registers are required to perform the relative lookups of data references. As part of that change, a subtle mistake was introduced in _start, overwriting the multiboot information pointer that gets handed to kernel by the boot loader in %ebx. --- arch/x86_64/src/boot/boot.s | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index e0cff7c..ba5c6f0 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -195,9 +195,9 @@ _start: call .Lstart_get_ip .Lstart_get_ip: pop %esi - lea (stack_top - .Lstart_get_ip)(%esi), %ebx + lea (stack_top - .Lstart_get_ip)(%esi), %ecx - mov %ebx, %esp + mov %ecx, %esp mov %esp, %ebp call assert_loaded_by_multiboot2_loader -- cgit v1.2.3 From fd6282947bb13af4cfff8cf2209c442b568275f3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 18 Jul 2025 11:35:58 +0000 Subject: x86_64: add data segment to boot GDT --- arch/x86_64/src/boot/boot.s | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index ba5c6f0..2decf26 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -58,19 +58,22 @@ stack_top: .section .boot_rodata, "a", @progbits /** - * A valid Global Descriptor Table is still required in long mode. However, we - * only need a single entry for the "code segment", so we will setup a single - * segment table below. + * A valid Global Descriptor Table is still required in long mode. * + * Bit 41: "RW" in the access byte => mark the segment as readable (code) or writable (data). * Bit 43: "E" in the access byte => mark the segment as executable. * Bit 44: "S" in the access byte => mark the segment as code or data. * Bit 47: "P" in the access byte => mark the segment as being present. * Bit 53: "L" in the flags byte => mark the segment as being for long mode */ -global_descriptor_table: .quad 0 +global_descriptor_table: +global_descriptor_table_null = . - global_descriptor_table +.quad 0 global_descriptor_table_code = . - global_descriptor_table -.quad (1<<43) | (1<<44) | (1<<47) | (1<<53) +.quad (1<<41) | (1<<43) | (1<<44) | (1<<47) | (1<<53) +global_descriptor_table_data = . - global_descriptor_table +.quad (1<<41) | (1<<44) | (1<<47) global_descriptor_table_end: /** @@ -402,7 +405,7 @@ prepare_page_maps: .code64 _transition_to_long_mode: - xor %rax, %rax + mov $global_descriptor_table_data, %rax mov %rax, %ss mov %rax, %ds mov %rax, %es -- cgit v1.2.3 From 3a67a3e1088508148002e7c20befa571fb0b72c0 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 18 Jul 2025 11:44:15 +0000 Subject: x86_64: set GDT entries as accessed. --- arch/x86_64/src/boot/boot.s | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 2decf26..f3d9585 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -60,6 +60,7 @@ stack_top: /** * A valid Global Descriptor Table is still required in long mode. * + * Bit 41: "A" in the access byte => mark the segment as accessed. * Bit 41: "RW" in the access byte => mark the segment as readable (code) or writable (data). * Bit 43: "E" in the access byte => mark the segment as executable. * Bit 44: "S" in the access byte => mark the segment as code or data. @@ -71,9 +72,9 @@ global_descriptor_table: global_descriptor_table_null = . - global_descriptor_table .quad 0 global_descriptor_table_code = . - global_descriptor_table -.quad (1<<41) | (1<<43) | (1<<44) | (1<<47) | (1<<53) +.quad (1<<40) | (1<<41) | (1<<43) | (1<<44) | (1<<47) | (1<<53) global_descriptor_table_data = . - global_descriptor_table -.quad (1<<41) | (1<<44) | (1<<47) +.quad (1<<40) | (1<<41) | (1<<44) | (1<<47) global_descriptor_table_end: /** -- cgit v1.2.3 From eb22cdcad4c27527a63a6e457e80c752f76821c6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 21 Jul 2025 12:13:10 +0000 Subject: x86_64: clean up bootstrap code --- arch/x86_64/src/boot/boot.s | 512 +++++++++++++++++++++++--------------------- 1 file changed, 265 insertions(+), 247 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index f3d9585..7a46795 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -1,50 +1,22 @@ -.extern _end_physical -.extern _init -.extern kernel_main - - /** - * Uninitialized data for the bootstrapping process. + * @brief Uninitialized data for the bootstrapping process. */ .section .boot_bss, "aw", @nobits /** - * Reserve some space for the Multiboot 2 information pointer. + * @brief Storage for the multiboot2 information pointer. */ .global multiboot_information_pointer multiboot_information_pointer: .skip 8 -/** - * Align page maps to 4 KiB or the assembler code, will cause crashes when attempting to enable paging. - */ .align 4096 -/** - * Reserve space for the page maps we are going to use during startup. - * - * Note: We are going to use large pages to make the initial mapping code - * simpler. - * - * We need: - * - A single PML 4 (since we will only use 4-level paging) - * - 1 PML 3 - * - 1 PML 2 - */ - -.global page_map_level_4 page_map_level_4: .skip 512 * 8 - -.global page_map_level_3 page_map_level_3: .skip 512 * 8 - -.global page_map_level_2 page_map_level_2: .skip 512 * 8 /** - * Stack space for the bootstrapping process. - * - * Note: We are going to reserve 1 MiB for now. If/when the kernel requires - * more space to run, it will have to relocate the stack. + * @brief Storage for the bootstrap stack. */ .section .boot_stack, "aw", @nobits .align 16 @@ -53,210 +25,240 @@ stack_bottom: .skip 1 << 20 stack_top: /** - * Constants for the bootstrapping process. + * @brief Constants for the bootstrapping process. */ .section .boot_rodata, "a", @progbits /** - * A valid Global Descriptor Table is still required in long mode. - * - * Bit 41: "A" in the access byte => mark the segment as accessed. - * Bit 41: "RW" in the access byte => mark the segment as readable (code) or writable (data). - * Bit 43: "E" in the access byte => mark the segment as executable. - * Bit 44: "S" in the access byte => mark the segment as code or data. - * Bit 47: "P" in the access byte => mark the segment as being present. - * Bit 53: "L" in the flags byte => mark the segment as being for long mode + * @brief A basic GDT for long mode. */ - global_descriptor_table: +.set GDT_ACCESSED, 40 +.set GDT_READ_WRITE, 41 +.set GDT_EXECUTABLE, 43 +.set GDT_DESCRIPTOR_TYPE, 44 +.set GDT_PRESENT, 47 +.set GDT_LONG_MODE, 53 global_descriptor_table_null = . - global_descriptor_table .quad 0 global_descriptor_table_code = . - global_descriptor_table -.quad (1<<40) | (1<<41) | (1<<43) | (1<<44) | (1<<47) | (1<<53) +.quad (1 << GDT_ACCESSED) | (1 << GDT_READ_WRITE) | (1 << GDT_EXECUTABLE) | (1 << GDT_DESCRIPTOR_TYPE) | (1 << GDT_PRESENT) | (1 << GDT_LONG_MODE) global_descriptor_table_data = . - global_descriptor_table -.quad (1<<40) | (1<<41) | (1<<44) | (1<<47) +.quad (1 << GDT_ACCESSED) | (1 << GDT_READ_WRITE) | (1 << GDT_DESCRIPTOR_TYPE) | (1 << GDT_PRESENT) global_descriptor_table_end: -/** - * We are going to print some messages in case we panic during boot, so we are - * going to store them here as well - */ -.global message_prefix_panic -message_prefix_panic: -.string "TeachOS 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." -mesage_long_mode_not_supported: -.string "Long mode is not supported by this platform." +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." /** - * Mutable data for the bootstrapping process. + * @brief Initialized data for the bootstrapping process. */ .section .boot_data, "aw", @progbits /** - * We need a pointer to our current position in the VGA text buffer. + * @brief A pointer to the current position within the VGA text buffer. */ .global vga_buffer_pointer vga_buffer_pointer: .quad 0xb8000 /** - * Code for the bootstrapping process. + * @brief Code for the bootstrapping process. */ .section .boot_text, "ax", @progbits .align 16 .code32 -.global halt -halt: -1: - hlt - jmp 1b +.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 /** - * Print a given panic message and then halt the machine. + * @brief Prepare the environment and start the kernel. * - * Parameters: - * - [stack - 0] message: the message to print + * 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. */ -_panic: - push %ebp +.global _start +_start: + call 0f +0: + pop %esi + + lea (stack_top - 0b)(%esi), %ecx + + mov %ecx, %esp mov %esp, %ebp - call .Lpanic_get_ip -.Lpanic_get_ip: - pop %eax - lea (message_prefix_panic - .Lpanic_get_ip)(%eax), %eax + call _assert_loaded_by_multiboot2_loader + call _save_multiboot_information_pointer - push %eax - push $0x4f - call _print - add $8, %esp + call _assert_cpuid_instruction_is_supported + call _assert_cpu_supports_long_mode - push 8(%ebp) - push 0x4f - call _print - add $8, %esp + call _prepare_page_maps + call _enable_paging + call _enable_sse + call _reload_gdt + + lea (_transition_to_long_mode - 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. + */ +.global halt +_halt: + function_start - call halt +1: + hlt + jmp 1b + + function_end /** - * Print a message via the VGA buffer. + * @brief Print a message via the VGA text buffer. * - * Parameters: - * - [stack - 4] message: the message to print - * - [stack - 0] color: the color of the message + * @param ebp+12 The message to print. + * @param ebp+8 The color to print the message in. */ _print: - push %ebp - mov %esp, %ebp + pie_function_start - push %ebx - push %esi push %edi + push %ebx - call .Lprint_get_ip -.Lprint_get_ip: - pop %edi - lea (vga_buffer_pointer - .Lprint_get_ip)(%edi), %edi - - mov 8(%ebp), %eax - mov 12(%ebp), %ebx + mov 8(%ebp), %al + mov 12(%ebp), %edx mov $0, %ecx - mov (%edi), %esi - -.Lprint_loop: - mov (%ebx, %ecx), %dl - test %dl, %dl - je .Lupdate_vga_buffer_address - mov %dl, (%esi, %ecx, 2) - mov %al, 1(%esi, %ecx, 2) + 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 .Lprint_loop + jmp 1b -.Lupdate_vga_buffer_address: +2: shl $1, %ecx - add %ecx, %esi - mov %esi, (%edi) + add %ecx, %edi + lea (vga_buffer_pointer - 0b)(%esi), %ecx + mov %edi, (%ecx) -.Lprint_end: - pop %edi - pop %esi pop %ebx - mov %ebp, %esp - pop %ebp - ret + pop %edi + + pie_function_end /** - * This is our entry point after being loaded by the bootloader. + * @brief Print a given panic message and then halt the machine as if by calling ::halt() * - * Having this in assembly makes it easier for us to keep things together. + * @param ebp+4 A message to print. + * @return This function does not return. */ -.global _start -_start: - call .Lstart_get_ip -.Lstart_get_ip: - pop %esi - lea (stack_top - .Lstart_get_ip)(%esi), %ecx - - mov %ecx, %esp - mov %esp, %ebp +_panic: + pie_function_start - call assert_loaded_by_multiboot2_loader - call assert_cpuid_instruction_is_supported - call assert_cpu_supports_long_mode - call prepare_page_maps - call enable_paging - call enable_sse + lea (message_prefix_panic - 0b)(%esi), %eax - sub $10, %esp - lea (global_descriptor_table - .Lstart_get_ip)(%esi), %eax - movw $(global_descriptor_table_end - global_descriptor_table -1), (%esp) - mov %eax, 2(%esp) - movl $0, 6(%esp) + push %eax + push $0x4f + call _print - lgdt (%esp) - add $10, %esp + mov 16(%ebp), %eax + mov %eax, 8(%ebp) + call _print + add $8, %esp - lea (_transition_to_long_mode - .Lstart_get_ip)(%esi), %eax - pushl $global_descriptor_table_code - pushl %eax - lret + call _halt - call halt + pie_function_end /** - * Assert that the CPU supports going into long mode. + * 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_cpu_supports_long_mode: - mov $0x80000000, %eax - cpuid - cmp $0x80000001, %eax - jb .Llong_mode_assertion_failed +_assert_loaded_by_multiboot2_loader: + pie_function_start - mov $0x80000001, %eax - cpuid - test $(1 << 29), %edx - jz .Llong_mode_assertion_failed - ret -.Llong_mode_assertion_failed: - call .Lassert_cpu_supports_long_mode_fail_get_ip -.Lassert_cpu_supports_long_mode_fail_get_ip: - pop %eax - lea (mesage_long_mode_not_supported - .Lassert_cpu_supports_long_mode_fail_get_ip)(%eax), %eax + .set MULTIBOOT2_MAGIC, 0x36d76289 + cmp $MULTIBOOT2_MAGIC, %eax + je 1f + lea (message_not_loaded_by_multiboot2 - 0b)(%esi), %eax push %eax call _panic +1: + pie_function_end /** - * Assert that the CPU supports the CPUID instruction. + * @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: +_assert_cpuid_instruction_is_supported: + pie_function_start + pushfl pop %eax mov %eax, %ecx @@ -271,52 +273,100 @@ assert_cpuid_instruction_is_supported: popfl cmp %ecx, %eax - je .Lcpuid_assertion_fail - ret -.Lcpuid_assertion_fail: - call .Lassert_cpuid_instruction_is_supported_fail_get_ip -.Lassert_cpuid_instruction_is_supported_fail_get_ip: - pop %eax - lea (message_cpuid_instruction_no_supported - .Lassert_cpuid_instruction_is_supported_fail_get_ip)(%eax), %eax + jne 1f + lea (message_cpuid_instruction_no_supported - 0b)(%esi), %eax push %eax call _panic +1: + 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`. + * @brief Assert that the CPU supports going into long mode. */ -assert_loaded_by_multiboot2_loader: - cmp $0x36d76289, %eax /* Check if we received the - expected magic */ - jne .Lmultiboot2_assertion_fail /* Panic otherwise */ - call .Lassert_loaded_by_multiboot2_loader_get_ip -.Lassert_loaded_by_multiboot2_loader_get_ip: - pop %eax - lea (multiboot_information_pointer - .Lassert_loaded_by_multiboot2_loader_get_ip)(%eax), %eax - mov %ebx, (%eax) /* Store the MBI pointer */ - ret -.Lmultiboot2_assertion_fail: - call .Lassert_loaded_by_multiboot2_loader_fail_get_ip -.Lassert_loaded_by_multiboot2_loader_fail_get_ip: - pop %eax - lea (message_not_loaded_by_multiboot2 - .Lassert_loaded_by_multiboot2_loader_fail_get_ip)(%eax), %eax +_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 /** - * Enable paging. + * @brief Prepare a recursive page map hierarchy + * + * We map all physical memory we were loaded in plus one additional page. The + * mapping is done in terms of huge pages (2 MiB per page) to save on required + * page map entries. + * + * @return void + */ +_prepare_page_maps: + pie_function_start + push %ebx + + .set HUGE_PAGES_TO_MAP, 16 + + /* Map the P4 table recursively */ + lea (page_map_level_4 - 0b)(%esi), %eax + mov %eax, %ebx + or $0b11, %ebx + mov %ebx, (511 * 8)(%eax) + + /* Add an entry to the PML4, pointing to the PML3 */ + lea (page_map_level_3 - 0b)(%esi), %ebx + or $0b11, %ebx + mov %ebx, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%eax) + + /* Add an entry to the PML3, pointing to the PML2 */ + lea (page_map_level_3 - 0b)(%esi), %eax + lea (page_map_level_2 - 0b)(%esi), %ebx + or $0b11, %ebx + mov %ebx, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%eax) + + /* Add entries for huge pages to the PML2 */ + push %edi + lea (page_map_level_2 - 0b)(%esi), %ebx + mov $HUGE_PAGES_TO_MAP, %edi + xor %ecx, %ecx + +1: + mov $(1 << 21), %eax + mul %ecx + or $0b10000011, %eax + mov %eax, (%ebx, %ecx, 8) + + inc %ecx + cmp %edi, %ecx + jne 1b + + pop %edi + pop %ebx + 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. - */ -enable_paging: - call .Lenable_paging_get_ip -.Lenable_paging_get_ip: - pop %eax -lea (page_map_level_4 - .Lenable_paging_get_ip)(%eax), %eax + * + * @return void + */For +_enable_paging: + pie_function_start + + lea (page_map_level_4 - 0b)(%esi), %eax mov %eax, %cr3 /* Enable Physical Address Extension */ @@ -335,12 +385,14 @@ lea (page_map_level_4 - .Lenable_paging_get_ip)(%eax), %eax or $(1 << 31), %eax mov %eax, %cr0 - ret + pie_function_end /** - * Enable use of SSE instructions. + * @brief Enable use of SSE instructions. */ -enable_sse: +_enable_sse: + function_start + mov %cr0, %eax and $0xfffffffb, %eax or $0x00000002, %eax @@ -350,57 +402,26 @@ enable_sse: or $(3 << 9), %eax mov %eax, %cr4 - ret + function_end /** - * Prepare the page maps. + * @brief Prepare a new GTD and load make it active. * - * We map all physical memory we were loaded in plus one additional page. The - * mapping is done in terms of huge pages (2 MiB per page) to save on required - * page map entries. + * @return void */ -prepare_page_maps: - call .Lprepare_page_maps_get_ip -.Lprepare_page_maps_get_ip: - pop %edi - /* Map the P4 table recursively */ - lea (page_map_level_4 - .Lprepare_page_maps_get_ip)(%edi), %eax - mov %eax, %ebx - or $0b11, %eax /* Write present + writable flags into eax register */ - mov %eax, (511 * 8)(%ebx) - - /* Add an entry to the PML4, pointing to the PML3 */ - lea (page_map_level_3 - .Lprepare_page_maps_get_ip)(%edi), %eax - lea (page_map_level_4 - .Lprepare_page_maps_get_ip)(%edi), %ebx - or $0x3, %eax - mov %eax, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%ebx) - - /* Add an entry to the PML3, pointing to the PML2 */ - lea (page_map_level_2 - .Lprepare_page_maps_get_ip)(%edi), %eax - lea (page_map_level_3 - .Lprepare_page_maps_get_ip)(%edi), %ebx - or $0x3, %eax - mov %eax, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%ebx) - - xor %ecx, %ecx - - push %esi - lea (_end_linear - .Lprepare_page_maps_get_ip)(%edi), %esi - shr $21, %esi - add $2, %esi +_reload_gdt: + pie_function_start -.Lmap_pages: - lea (page_map_level_2 - .Lprepare_page_maps_get_ip)(%edi), %ebx - mov $(1 << 21), %eax - mul %ecx - or $((1 << 0) | (1 << 1) | (1 << 7)), %eax - mov %eax, (%ebx,%ecx,8) + 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) - inc %ecx - cmp %esi, %ecx - jne .Lmap_pages + lgdt (%esp) + add $10, %esp - pop %esi - ret + pie_function_end .section .boot_text, "ax", @progbits .code64 @@ -413,12 +434,9 @@ _transition_to_long_mode: mov %rax, %fs mov %rax, %gs - leaq vga_buffer_pointer(%rip), %rax - movl $0xb8000, (%rax) - xor %rax, %rax call _init call main - call halt + call _halt -- cgit v1.2.3 From ce8683e63fc9ef59e1800927afb1753507a42ef6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 22 Jul 2025 20:48:11 +0000 Subject: x86_64: extract constants from bootstrap code --- arch/x86_64/src/boot/boot.S | 433 +++++++++++++++++++++++++++++++++++++++++++ arch/x86_64/src/boot/boot.s | 442 -------------------------------------------- arch/x86_64/src/memory.cpp | 5 +- 3 files changed, 435 insertions(+), 445 deletions(-) create mode 100644 arch/x86_64/src/boot/boot.S delete mode 100644 arch/x86_64/src/boot/boot.s (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.S b/arch/x86_64/src/boot/boot.S new file mode 100644 index 0000000..d65c865 --- /dev/null +++ b/arch/x86_64/src/boot/boot.S @@ -0,0 +1,433 @@ +#include "x86_64/boot/boot.hpp" + +/** + * @brief Uninitialized data for the bootstrapping process. + */ +.section .boot_bss, "aw", @nobits + +/** + * @brief Storage for the multiboot2 information pointer. + */ +.global multiboot_information_pointer +multiboot_information_pointer: .skip 8 + +.align 4096 + +page_map_level_4: .skip 512 * 8 +page_map_level_3: .skip 512 * 8 +page_map_level_2: .skip 512 * 8 + +/** + * @brief Storage for the bootstrap stack. + */ +.section .boot_stack, "aw", @nobits +.align 16 + +stack_bottom: .skip 1 << 20 +stack_top: + +/** + * @brief Constants for the bootstrapping process. + */ +.section .boot_rodata, "a", @progbits + +/** + * @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_ACCESSED | GDT_READ_WRITE | GDT_EXECUTABLE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | GDT_LONG_MODE +global_descriptor_table_data = . - global_descriptor_table +.quad GDT_ACCESSED | GDT_READ_WRITE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT +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. + */ +_start: + call 0f +0: + pop %esi + + lea (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 + + call _prepare_page_maps + call _enable_paging + call _enable_sse + call _reload_gdt + + lea (_transition_to_long_mode - 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 16(%ebp), %eax + mov %eax, 8(%ebp) + 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 recursive page map hierarchy + * + * We map all physical memory we were loaded in plus one additional page. The + * mapping is done in terms of huge pages (2 MiB per page) to save on required + * page map entries. + * + * @return void + */ +_prepare_page_maps: + pie_function_start + push %ebx + + /* Map the P4 table recursively */ + lea (page_map_level_4 - 0b)(%esi), %eax + mov %eax, %ebx + or $0b11, %ebx + mov %ebx, (511 * 8)(%eax) + + /* Add an entry to the PML4, pointing to the PML3 */ + lea (page_map_level_3 - 0b)(%esi), %ebx + or $0b11, %ebx + mov %ebx, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%eax) + + /* Add an entry to the PML3, pointing to the PML2 */ + lea (page_map_level_3 - 0b)(%esi), %eax + lea (page_map_level_2 - 0b)(%esi), %ebx + or $0b11, %ebx + mov %ebx, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%eax) + + /* Add entries for huge pages to the PML2 */ + push %edi + lea (page_map_level_2 - 0b)(%esi), %ebx + mov $HUGE_PAGES_TO_MAP, %edi + xor %ecx, %ecx + +1: + mov $(1 << 21), %eax + mul %ecx + or $0b10000011, %eax + mov %eax, (%ebx, %ecx, 8) + + inc %ecx + cmp %edi, %ecx + jne 1b + + pop %edi + pop %ebx + 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 + +.section .boot_text, "ax", @progbits +.code64 + +_transition_to_long_mode: + mov $global_descriptor_table_data, %rax + mov %rax, %ss + mov %rax, %ds + mov %rax, %es + mov %rax, %fs + mov %rax, %gs + + xor %rax, %rax + + call _init + + call main + call _halt diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s deleted file mode 100644 index 7a46795..0000000 --- a/arch/x86_64/src/boot/boot.s +++ /dev/null @@ -1,442 +0,0 @@ -/** - * @brief Uninitialized data for the bootstrapping process. - */ -.section .boot_bss, "aw", @nobits - -/** - * @brief Storage for the multiboot2 information pointer. - */ -.global multiboot_information_pointer -multiboot_information_pointer: .skip 8 - -.align 4096 - -page_map_level_4: .skip 512 * 8 -page_map_level_3: .skip 512 * 8 -page_map_level_2: .skip 512 * 8 - -/** - * @brief Storage for the bootstrap stack. - */ -.section .boot_stack, "aw", @nobits -.align 16 - -stack_bottom: .skip 1 << 20 -stack_top: - -/** - * @brief Constants for the bootstrapping process. - */ -.section .boot_rodata, "a", @progbits - -/** - * @brief A basic GDT for long mode. - */ -global_descriptor_table: -.set GDT_ACCESSED, 40 -.set GDT_READ_WRITE, 41 -.set GDT_EXECUTABLE, 43 -.set GDT_DESCRIPTOR_TYPE, 44 -.set GDT_PRESENT, 47 -.set GDT_LONG_MODE, 53 -global_descriptor_table_null = . - global_descriptor_table -.quad 0 -global_descriptor_table_code = . - global_descriptor_table -.quad (1 << GDT_ACCESSED) | (1 << GDT_READ_WRITE) | (1 << GDT_EXECUTABLE) | (1 << GDT_DESCRIPTOR_TYPE) | (1 << GDT_PRESENT) | (1 << GDT_LONG_MODE) -global_descriptor_table_data = . - global_descriptor_table -.quad (1 << GDT_ACCESSED) | (1 << GDT_READ_WRITE) | (1 << GDT_DESCRIPTOR_TYPE) | (1 << GDT_PRESENT) -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 (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 - - call _prepare_page_maps - call _enable_paging - call _enable_sse - call _reload_gdt - - lea (_transition_to_long_mode - 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. - */ -.global halt -_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 16(%ebp), %eax - mov %eax, 8(%ebp) - 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 - - .set MULTIBOOT2_MAGIC, 0x36d76289 - 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 recursive page map hierarchy - * - * We map all physical memory we were loaded in plus one additional page. The - * mapping is done in terms of huge pages (2 MiB per page) to save on required - * page map entries. - * - * @return void - */ -_prepare_page_maps: - pie_function_start - push %ebx - - .set HUGE_PAGES_TO_MAP, 16 - - /* Map the P4 table recursively */ - lea (page_map_level_4 - 0b)(%esi), %eax - mov %eax, %ebx - or $0b11, %ebx - mov %ebx, (511 * 8)(%eax) - - /* Add an entry to the PML4, pointing to the PML3 */ - lea (page_map_level_3 - 0b)(%esi), %ebx - or $0b11, %ebx - mov %ebx, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%eax) - - /* Add an entry to the PML3, pointing to the PML2 */ - lea (page_map_level_3 - 0b)(%esi), %eax - lea (page_map_level_2 - 0b)(%esi), %ebx - or $0b11, %ebx - mov %ebx, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%eax) - - /* Add entries for huge pages to the PML2 */ - push %edi - lea (page_map_level_2 - 0b)(%esi), %ebx - mov $HUGE_PAGES_TO_MAP, %edi - xor %ecx, %ecx - -1: - mov $(1 << 21), %eax - mul %ecx - or $0b10000011, %eax - mov %eax, (%ebx, %ecx, 8) - - inc %ecx - cmp %edi, %ecx - jne 1b - - pop %edi - pop %ebx - 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 - */For -_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 - -.section .boot_text, "ax", @progbits -.code64 - -_transition_to_long_mode: - mov $global_descriptor_table_data, %rax - mov %rax, %ss - mov %rax, %ds - mov %rax, %es - mov %rax, %fs - mov %rax, %gs - - xor %rax, %rax - - call _init - - call main - call _halt diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp index 2b16beb..a31627b 100644 --- a/arch/x86_64/src/memory.cpp +++ b/arch/x86_64/src/memory.cpp @@ -2,14 +2,13 @@ #include "kern/error.hpp" -#include "arch/asm_pointer.hpp" -#include "x86_64/memory/region_allocator.hpp" +#include "x86_64/boot/boot.hpp" #include #include -extern "C" teachos::arch::asm_pointer multiboot_information_pointer; +// extern "C" teachos::arch::asm_pointer multiboot_information_pointer; namespace teachos::arch::memory { -- cgit v1.2.3 From c8cb4346064c69ab8431aa0d3c287e2fad60ce80 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 22 Jul 2025 21:23:23 +0000 Subject: x86_64: split bootstrap code along mode lines --- arch/x86_64/src/boot/boot.S | 433 ----------------------------------------- arch/x86_64/src/boot/boot32.S | 418 +++++++++++++++++++++++++++++++++++++++ arch/x86_64/src/boot/entry64.s | 21 ++ 3 files changed, 439 insertions(+), 433 deletions(-) delete mode 100644 arch/x86_64/src/boot/boot.S create mode 100644 arch/x86_64/src/boot/boot32.S create mode 100644 arch/x86_64/src/boot/entry64.s (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot.S b/arch/x86_64/src/boot/boot.S deleted file mode 100644 index d65c865..0000000 --- a/arch/x86_64/src/boot/boot.S +++ /dev/null @@ -1,433 +0,0 @@ -#include "x86_64/boot/boot.hpp" - -/** - * @brief Uninitialized data for the bootstrapping process. - */ -.section .boot_bss, "aw", @nobits - -/** - * @brief Storage for the multiboot2 information pointer. - */ -.global multiboot_information_pointer -multiboot_information_pointer: .skip 8 - -.align 4096 - -page_map_level_4: .skip 512 * 8 -page_map_level_3: .skip 512 * 8 -page_map_level_2: .skip 512 * 8 - -/** - * @brief Storage for the bootstrap stack. - */ -.section .boot_stack, "aw", @nobits -.align 16 - -stack_bottom: .skip 1 << 20 -stack_top: - -/** - * @brief Constants for the bootstrapping process. - */ -.section .boot_rodata, "a", @progbits - -/** - * @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_ACCESSED | GDT_READ_WRITE | GDT_EXECUTABLE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | GDT_LONG_MODE -global_descriptor_table_data = . - global_descriptor_table -.quad GDT_ACCESSED | GDT_READ_WRITE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT -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. - */ -_start: - call 0f -0: - pop %esi - - lea (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 - - call _prepare_page_maps - call _enable_paging - call _enable_sse - call _reload_gdt - - lea (_transition_to_long_mode - 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 16(%ebp), %eax - mov %eax, 8(%ebp) - 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 recursive page map hierarchy - * - * We map all physical memory we were loaded in plus one additional page. The - * mapping is done in terms of huge pages (2 MiB per page) to save on required - * page map entries. - * - * @return void - */ -_prepare_page_maps: - pie_function_start - push %ebx - - /* Map the P4 table recursively */ - lea (page_map_level_4 - 0b)(%esi), %eax - mov %eax, %ebx - or $0b11, %ebx - mov %ebx, (511 * 8)(%eax) - - /* Add an entry to the PML4, pointing to the PML3 */ - lea (page_map_level_3 - 0b)(%esi), %ebx - or $0b11, %ebx - mov %ebx, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%eax) - - /* Add an entry to the PML3, pointing to the PML2 */ - lea (page_map_level_3 - 0b)(%esi), %eax - lea (page_map_level_2 - 0b)(%esi), %ebx - or $0b11, %ebx - mov %ebx, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%eax) - - /* Add entries for huge pages to the PML2 */ - push %edi - lea (page_map_level_2 - 0b)(%esi), %ebx - mov $HUGE_PAGES_TO_MAP, %edi - xor %ecx, %ecx - -1: - mov $(1 << 21), %eax - mul %ecx - or $0b10000011, %eax - mov %eax, (%ebx, %ecx, 8) - - inc %ecx - cmp %edi, %ecx - jne 1b - - pop %edi - pop %ebx - 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 - -.section .boot_text, "ax", @progbits -.code64 - -_transition_to_long_mode: - mov $global_descriptor_table_data, %rax - mov %rax, %ss - mov %rax, %ds - mov %rax, %es - mov %rax, %fs - mov %rax, %gs - - xor %rax, %rax - - call _init - - call main - call _halt diff --git a/arch/x86_64/src/boot/boot32.S b/arch/x86_64/src/boot/boot32.S new file mode 100644 index 0000000..7e6c2ae --- /dev/null +++ b/arch/x86_64/src/boot/boot32.S @@ -0,0 +1,418 @@ +#include "x86_64/boot/boot.hpp" + +/** + * @brief Uninitialized data for the bootstrapping process. + */ +.section .boot_bss, "aw", @nobits + +/** + * @brief Storage for the multiboot2 information pointer. + */ +.global multiboot_information_pointer +multiboot_information_pointer: .skip 8 + +.align 4096 + +page_map_level_4: .skip 512 * 8 +page_map_level_3: .skip 512 * 8 +page_map_level_2: .skip 512 * 8 + +/** + * @brief Storage for the bootstrap stack. + */ +.section .boot_stack, "aw", @nobits +.align 16 + +stack_bottom: .skip 1 << 20 +stack_top: + +/** + * @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_ACCESSED | GDT_READ_WRITE | GDT_EXECUTABLE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | GDT_LONG_MODE +global_descriptor_table_data = . - global_descriptor_table +.quad GDT_ACCESSED | GDT_READ_WRITE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT +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 (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 + + call _prepare_page_maps + 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 16(%ebp), %eax + mov %eax, 8(%ebp) + 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 recursive page map hierarchy + * + * We map all physical memory we were loaded in plus one additional page. The + * mapping is done in terms of huge pages (2 MiB per page) to save on required + * page map entries. + * + * @return void + */ +_prepare_page_maps: + pie_function_start + push %ebx + + /* Map the P4 table recursively */ + lea (page_map_level_4 - 0b)(%esi), %eax + mov %eax, %ebx + or $0b11, %ebx + mov %ebx, (511 * 8)(%eax) + + /* Add an entry to the PML4, pointing to the PML3 */ + lea (page_map_level_3 - 0b)(%esi), %ebx + or $0b11, %ebx + mov %ebx, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%eax) + + /* Add an entry to the PML3, pointing to the PML2 */ + lea (page_map_level_3 - 0b)(%esi), %eax + lea (page_map_level_2 - 0b)(%esi), %ebx + or $0b11, %ebx + mov %ebx, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%eax) + + /* Add entries for huge pages to the PML2 */ + push %edi + lea (page_map_level_2 - 0b)(%esi), %ebx + mov $HUGE_PAGES_TO_MAP, %edi + xor %ecx, %ecx + +1: + mov $(1 << 21), %eax + mul %ecx + or $0b10000011, %eax + mov %eax, (%ebx, %ecx, 8) + + inc %ecx + cmp %edi, %ecx + jne 1b + + pop %edi + pop %ebx + 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 new file mode 100644 index 0000000..f575c50 --- /dev/null +++ b/arch/x86_64/src/boot/entry64.s @@ -0,0 +1,21 @@ +.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 + + xor %rax, %rax + + call _init + + call main + +1: + hlt + jmp 1b -- cgit v1.2.3 From e97e86d169849527190cef1913efdd247e6f68df Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 23 Jul 2025 13:21:32 +0000 Subject: libs: move asm_ptr to kstd --- arch/x86_64/src/vga/text.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 16abf08..dcfdb6b 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -1,15 +1,14 @@ #include "x86_64/vga/text.hpp" -#include "arch/asm_pointer.hpp" +#include "x86_64/boot/boot.hpp" #include "x86_64/vga/io.hpp" #include +#include #include #include #include -extern "C" teachos::arch::asm_pointer> vga_buffer_pointer; - namespace teachos::x86_64::vga::text { namespace @@ -23,7 +22,7 @@ namespace teachos::x86_64::vga::text auto clear(attribute attribute) -> void { buffer_offset = 0; - std::ranges::fill_n(vga_buffer_pointer.get(), 2000, std::pair{' ', attribute}); + std::ranges::fill_n(vga_buffer_pointer.get(), 2000, std::pair{' ', std::bit_cast(attribute)}); } auto cursor(bool enabled) -> void @@ -54,7 +53,7 @@ namespace teachos::x86_64::vga::text auto write_char(char code_point, attribute attribute) -> void { - vga_buffer_pointer[buffer_offset++] = std::pair{code_point, attribute}; + vga_buffer_pointer[buffer_offset++] = std::pair{code_point, std::bit_cast(attribute)}; }; auto write(std::string_view code_points, attribute attribute) -> void -- cgit v1.2.3 From be5c7e992ef3f7827e7229d77af3f812484de260 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 23 Jul 2025 13:52:28 +0000 Subject: x86_64: extract linker script interface header --- arch/x86_64/src/memory.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp index a31627b..105d69b 100644 --- a/arch/x86_64/src/memory.cpp +++ b/arch/x86_64/src/memory.cpp @@ -3,22 +3,33 @@ #include "kern/error.hpp" #include "x86_64/boot/boot.hpp" +#include "x86_64/boot/ld.hpp" +#include "x86_64/memory/address.hpp" +#include "x86_64/memory/region_allocator.hpp" #include #include -// extern "C" teachos::arch::asm_pointer multiboot_information_pointer; - namespace teachos::arch::memory { + using namespace x86_64::memory; + using namespace x86_64::boot; + namespace { auto constinit is_initialized = std::atomic_flag{}; - // auto create_memory_information() -> x86_64::memory::region_allocator::memory_information { + auto create_memory_information() -> region_allocator::memory_information + { + auto const & mbi = multiboot_information_pointer.get(); + auto map = mbi->memory_map(); - // }; + return {std::make_pair(physical_address{&_start_linear}, physical_address{&_end_linear}), + std::make_pair(physical_address{std::bit_cast(&mbi)}, + physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), + map}; + }; } // namespace auto init() -> void @@ -34,8 +45,10 @@ namespace teachos::arch::memory teachos::panic("[x86_64] No memory map available."); } - // auto mem_info = x86_64::memory::region_allocator::memory_information{}; - // auto allocator = x86_64::memory::region_allocator{mem_info}; + auto mem_info = create_memory_information(); + auto allocator = region_allocator{mem_info}; + + static_cast(allocator); // kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); // kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); -- cgit v1.2.3 From bb685cca3a537f0df4205050a9c52b411dee95c6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 23 Jul 2025 14:15:09 +0000 Subject: x86_64: rename _*_linear to _*_physical --- arch/x86_64/src/memory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp index 105d69b..b6901a5 100644 --- a/arch/x86_64/src/memory.cpp +++ b/arch/x86_64/src/memory.cpp @@ -25,7 +25,7 @@ namespace teachos::arch::memory auto const & mbi = multiboot_information_pointer.get(); auto map = mbi->memory_map(); - return {std::make_pair(physical_address{&_start_linear}, physical_address{&_end_linear}), + return {std::make_pair(physical_address{&_start_physical}, physical_address{&_end_physical}), std::make_pair(physical_address{std::bit_cast(&mbi)}, physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), map}; -- cgit v1.2.3 From 2ebf8d525e6a030efc8ca23bcbdf92c2d0cb8985 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 10:17:53 +0000 Subject: x86_64: implement high/low split --- arch/x86_64/src/boot/boot32.S | 102 +++++++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 36 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot32.S b/arch/x86_64/src/boot/boot32.S index 7e6c2ae..3039f38 100644 --- a/arch/x86_64/src/boot/boot32.S +++ b/arch/x86_64/src/boot/boot32.S @@ -13,9 +13,13 @@ multiboot_information_pointer: .skip 8 .align 4096 -page_map_level_4: .skip 512 * 8 -page_map_level_3: .skip 512 * 8 -page_map_level_2: .skip 512 * 8 +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 bootstrap stack. @@ -40,9 +44,9 @@ global_descriptor_table: global_descriptor_table_null = . - global_descriptor_table .quad 0 global_descriptor_table_code = . - global_descriptor_table -.quad GDT_ACCESSED | GDT_READ_WRITE | GDT_EXECUTABLE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | GDT_LONG_MODE +.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_ACCESSED | GDT_READ_WRITE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT +.quad GDT_READ_WRITE | GDT_DESCRIPTOR_TYPE | GDT_PRESENT | (1 << 54) | (1 << 55) global_descriptor_table_end: message_prefix_panic: .string "Panic: " @@ -125,7 +129,10 @@ _start: 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 @@ -302,51 +309,74 @@ _assert_cpu_supports_long_mode: /** * @brief Prepare a recursive page map hierarchy * - * We map all physical memory we were loaded in plus one additional page. The - * mapping is done in terms of huge pages (2 MiB per page) to save on required - * page map entries. - * + * @param ebp+8 The number of huge pages to map * @return void */ _prepare_page_maps: pie_function_start - push %ebx - /* Map the P4 table recursively */ - lea (page_map_level_4 - 0b)(%esi), %eax - mov %eax, %ebx - or $0b11, %ebx - mov %ebx, (511 * 8)(%eax) - - /* Add an entry to the PML4, pointing to the PML3 */ - lea (page_map_level_3 - 0b)(%esi), %ebx - or $0b11, %ebx - mov %ebx, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%eax) - - /* Add an entry to the PML3, pointing to the PML2 */ - lea (page_map_level_3 - 0b)(%esi), %eax - lea (page_map_level_2 - 0b)(%esi), %ebx - or $0b11, %ebx - mov %ebx, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%eax) - - /* Add entries for huge pages to the PML2 */ push %edi - lea (page_map_level_2 - 0b)(%esi), %ebx - mov $HUGE_PAGES_TO_MAP, %edi - xor %ecx, %ecx + + call _clear_page_map_memory + + lea (page_map_level_4 - 0b)(%esi), %edi + mov %edi, %eax + or $0b11, %eax + mov %eax, (510 * 8)(%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, (%ebx, %ecx, 8) + mov %eax, (%edi, %ecx, 8) - inc %ecx - cmp %edi, %ecx - jne 1b + test %ecx, %ecx + jnz 1b pop %edi - pop %ebx + + 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 /** -- cgit v1.2.3 From f62b05c93c6c539d899d2656c0638d404a036f1a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 12:28:23 +0000 Subject: x86_64: implement robust C++ global initialization Implement a comprehensive mechanism to ensure correct C++ runtime initialization before the kernel main function is called. This replaces the previous, incomplete reliance on an `_init` function. The new design robustly handles both legacy `.ctors` and modern `.init_array` initialization schemes used by the GNU toolchain. A single C++ function, `invoke_global_constructors`, now iterates through both arrays of function pointers to ensure all types of global initializers are executed. --- arch/x86_64/src/boot/crti.s | 13 ------------- arch/x86_64/src/boot/crtn.s | 9 --------- arch/x86_64/src/boot/entry64.s | 4 ++-- arch/x86_64/src/boot/initialize_runtime.cpp | 24 ++++++++++++++++++++++++ 4 files changed, 26 insertions(+), 24 deletions(-) delete mode 100644 arch/x86_64/src/boot/crti.s delete mode 100644 arch/x86_64/src/boot/crtn.s create mode 100644 arch/x86_64/src/boot/initialize_runtime.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/crti.s b/arch/x86_64/src/boot/crti.s deleted file mode 100644 index 26878fe..0000000 --- a/arch/x86_64/src/boot/crti.s +++ /dev/null @@ -1,13 +0,0 @@ -.code64 - -.section .init -.global _init -_init: - push %rbp - movq %rsp, %rbp - -.section .fini -.global _fini -_fini: - push %rbp - movq %rsp, %rbp diff --git a/arch/x86_64/src/boot/crtn.s b/arch/x86_64/src/boot/crtn.s deleted file mode 100644 index 06fb7ce..0000000 --- a/arch/x86_64/src/boot/crtn.s +++ /dev/null @@ -1,9 +0,0 @@ -.code64 - -.section .init - popq %rbp - ret - -.section .fini - popq %rbp - ret diff --git a/arch/x86_64/src/boot/entry64.s b/arch/x86_64/src/boot/entry64.s index f575c50..110ced8 100644 --- a/arch/x86_64/src/boot/entry64.s +++ b/arch/x86_64/src/boot/entry64.s @@ -12,8 +12,8 @@ _entry64: xor %rax, %rax - call _init - + call invoke_global_constructors + call main 1: diff --git a/arch/x86_64/src/boot/initialize_runtime.cpp b/arch/x86_64/src/boot/initialize_runtime.cpp new file mode 100644 index 0000000..9a3df0e --- /dev/null +++ b/arch/x86_64/src/boot/initialize_runtime.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +extern "C" +{ + using global_initializer = auto (*)() -> void; + + extern global_initializer __ctors_start; + extern global_initializer __ctors_end; + extern global_initializer __init_array_start; + extern global_initializer __init_array_end; + + auto invoke_global_constructors() -> void + { + auto constructors = std::span{&__ctors_start, &__ctors_end}; + auto initializers = std::span{&__init_array_start, &__init_array_end}; + + auto apply_invoke = [](auto invokable) { return std::invoke(invokable); }; + + std::ranges::for_each(constructors, apply_invoke); + std::ranges::for_each(initializers, apply_invoke); + } +} -- cgit v1.2.3 From ef907825e861b63726952bb34b425a98f34ed412 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 13:52:42 +0000 Subject: x86_64: provide a clean slate on entry to long mode --- arch/x86_64/src/boot/boot32.S | 4 ++++ arch/x86_64/src/boot/entry64.s | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot32.S b/arch/x86_64/src/boot/boot32.S index 3039f38..27eed4d 100644 --- a/arch/x86_64/src/boot/boot32.S +++ b/arch/x86_64/src/boot/boot32.S @@ -27,8 +27,12 @@ page_maps_size = page_maps_end - page_maps_start .section .boot_stack, "aw", @nobits .align 16 +.global stack_size +.global stack_bottom + stack_bottom: .skip 1 << 20 stack_top: +stack_size = stack_top - stack_bottom /** * @brief Constants for the bootstrapping process. diff --git a/arch/x86_64/src/boot/entry64.s b/arch/x86_64/src/boot/entry64.s index 110ced8..c5df5db 100644 --- a/arch/x86_64/src/boot/entry64.s +++ b/arch/x86_64/src/boot/entry64.s @@ -10,10 +10,20 @@ _entry64: mov %rax, %fs mov %rax, %gs - xor %rax, %rax - 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: -- cgit v1.2.3 From 4edbe94ce1266c9acc6a695fedf1d2edd4ce11cd Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 15:31:31 +0000 Subject: build: factor out kernel API --- arch/x86_64/src/io.cpp | 44 ++++++++++++++++++++++++++------------------ arch/x86_64/src/memory.cpp | 12 ++++++------ arch/x86_64/src/system.cpp | 6 +++--- 3 files changed, 35 insertions(+), 27 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/io.cpp b/arch/x86_64/src/io.cpp index 8e9e411..eab6473 100644 --- a/arch/x86_64/src/io.cpp +++ b/arch/x86_64/src/io.cpp @@ -1,28 +1,36 @@ -#include "kern/print.hpp" +#include "kapi/io.hpp" + #include "x86_64/vga/text.hpp" -namespace teachos::arch::io +namespace teachos::io { auto init() -> void { + x86_64::vga::text::clear(); x86_64::vga::text::cursor(false); + } + + auto print(std::string_view text) -> void + { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); + } + + auto println(std::string_view text) -> void + { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); + x86_64::vga::text::newline(); + } + + auto print_error(std::string_view text) -> void + { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); + } - teachos::set_print_handler( - [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); }); - teachos::set_println_handler([](auto text) { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); - x86_64::vga::text::newline(); - }); - - teachos::set_print_error_handler( - [](auto text) { return x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); }); - teachos::set_println_error_handler([](auto text) { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); - x86_64::vga::text::newline(); - }); - - teachos::println("[x86-64] Basic VGA text output initialized."); + auto println_error(std::string_view text) -> void + { + x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); + x86_64::vga::text::newline(); } -} // namespace teachos::arch::io +} // namespace teachos::io diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp index b6901a5..d1c1f03 100644 --- a/arch/x86_64/src/memory.cpp +++ b/arch/x86_64/src/memory.cpp @@ -1,6 +1,6 @@ -#include "arch/memory.hpp" +#include "kapi/memory.hpp" -#include "kern/error.hpp" +#include "kapi/system.hpp" #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" @@ -11,7 +11,7 @@ #include -namespace teachos::arch::memory +namespace teachos::memory { using namespace x86_64::memory; using namespace x86_64::boot; @@ -36,13 +36,13 @@ namespace teachos::arch::memory { if (is_initialized.test_and_set()) { - teachos::panic("[x86_64] Memory management has already been initialized."); + system::panic("[x86_64] Memory management has already been initialized."); } auto memory_map = multiboot_information_pointer->maybe_memory_map(); if (!memory_map) { - teachos::panic("[x86_64] No memory map available."); + system::panic("[x86_64] No memory map available."); } auto mem_info = create_memory_information(); @@ -63,4 +63,4 @@ namespace teachos::arch::memory // video::vga::text::newline(); } -} // namespace teachos::arch::memory +} // namespace teachos::memory diff --git a/arch/x86_64/src/system.cpp b/arch/x86_64/src/system.cpp index 60ebf0e..2d4c3fe 100644 --- a/arch/x86_64/src/system.cpp +++ b/arch/x86_64/src/system.cpp @@ -1,6 +1,6 @@ -#include "arch/system.hpp" +#include "kapi/system.hpp" -namespace teachos::arch::system +namespace teachos::system { auto halt() -> void @@ -9,4 +9,4 @@ namespace teachos::arch::system __builtin_unreachable(); } -} // namespace teachos::arch::system +} // namespace teachos::system -- cgit v1.2.3 From c6629ba11c17601695b0542d7d1d1bf5dc036d84 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 15:37:36 +0000 Subject: build: clean up configuration --- arch/x86_64/src/io.cpp | 36 ------------------------- arch/x86_64/src/memory.cpp | 66 ---------------------------------------------- arch/x86_64/src/system.cpp | 12 --------- 3 files changed, 114 deletions(-) delete mode 100644 arch/x86_64/src/io.cpp delete mode 100644 arch/x86_64/src/memory.cpp delete mode 100644 arch/x86_64/src/system.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/io.cpp b/arch/x86_64/src/io.cpp deleted file mode 100644 index eab6473..0000000 --- a/arch/x86_64/src/io.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "kapi/io.hpp" - -#include "x86_64/vga/text.hpp" - -namespace teachos::io -{ - - auto init() -> void - { - x86_64::vga::text::clear(); - x86_64::vga::text::cursor(false); - } - - auto print(std::string_view text) -> void - { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); - } - - auto println(std::string_view text) -> void - { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::green_on_black); - x86_64::vga::text::newline(); - } - - auto print_error(std::string_view text) -> void - { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); - } - - auto println_error(std::string_view text) -> void - { - x86_64::vga::text::write(text, x86_64::vga::text::common_attributes::red_on_black); - x86_64::vga::text::newline(); - } - -} // namespace teachos::io diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp deleted file mode 100644 index d1c1f03..0000000 --- a/arch/x86_64/src/memory.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "kapi/memory.hpp" - -#include "kapi/system.hpp" - -#include "x86_64/boot/boot.hpp" -#include "x86_64/boot/ld.hpp" -#include "x86_64/memory/address.hpp" -#include "x86_64/memory/region_allocator.hpp" - -#include - -#include - -namespace teachos::memory -{ - using namespace x86_64::memory; - using namespace x86_64::boot; - - namespace - { - auto constinit is_initialized = std::atomic_flag{}; - - auto create_memory_information() -> region_allocator::memory_information - { - auto const & mbi = multiboot_information_pointer.get(); - auto map = mbi->memory_map(); - - return {std::make_pair(physical_address{&_start_physical}, physical_address{&_end_physical}), - std::make_pair(physical_address{std::bit_cast(&mbi)}, - physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), - map}; - }; - } // namespace - - auto init() -> void - { - if (is_initialized.test_and_set()) - { - system::panic("[x86_64] Memory management has already been initialized."); - } - - auto memory_map = multiboot_information_pointer->maybe_memory_map(); - if (!memory_map) - { - system::panic("[x86_64] No memory map available."); - } - - auto mem_info = create_memory_information(); - auto allocator = region_allocator{mem_info}; - - static_cast(allocator); - - // kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); - // kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); - - // paging::kernel_mapper kernel(allocator, memory_information); - // kernel.remap_kernel(); - // video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); - // video::vga::text::newline(); - - // remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); - // video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); - // video::vga::text::newline(); - } - -} // namespace teachos::memory diff --git a/arch/x86_64/src/system.cpp b/arch/x86_64/src/system.cpp deleted file mode 100644 index 2d4c3fe..0000000 --- a/arch/x86_64/src/system.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "kapi/system.hpp" - -namespace teachos::system -{ - - auto halt() -> void - { - asm volatile("1: hlt\njmp 1b"); - __builtin_unreachable(); - } - -} // namespace teachos::system -- cgit v1.2.3 From 3b9bbbb4be529f2365b8bc2e43c1c8e9a65b1a07 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 16:15:31 +0000 Subject: x86_64: clean up vga hierarchy --- arch/x86_64/src/vga/text.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index dcfdb6b..5c94b84 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -1,7 +1,7 @@ #include "x86_64/vga/text.hpp" #include "x86_64/boot/boot.hpp" -#include "x86_64/vga/io.hpp" +#include "x86_64/vga/crtc.hpp" #include #include @@ -29,8 +29,8 @@ namespace teachos::x86_64::vga::text { auto cursor_disable_byte = std::byte{!enabled} << 5; - io::crtc::address_port::write(io::crtc::registers::cursor_start); - io::crtc::data_port::write(io::crtc::data_port::read() | cursor_disable_byte); + crtc::address::write(crtc::registers::cursor_start); + crtc::data::write(crtc::data::read() | cursor_disable_byte); } auto newline() -> void -- cgit v1.2.3 From 1b65136a11453fe7e89320dfe6170a0cd75e60dd Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 16:33:10 +0000 Subject: x86_64: clean up hw details --- arch/x86_64/src/cpu/registers.cpp | 64 ++++++++++++++++++++++++ arch/x86_64/src/kernel/cpu/control_register.cpp | 66 ------------------------- arch/x86_64/src/kernel/cpu/tlb.cpp | 16 ------ arch/x86_64/src/memory/mmu.cpp | 17 +++++++ 4 files changed, 81 insertions(+), 82 deletions(-) create mode 100644 arch/x86_64/src/cpu/registers.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/control_register.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/tlb.cpp create mode 100644 arch/x86_64/src/memory/mmu.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/registers.cpp b/arch/x86_64/src/cpu/registers.cpp new file mode 100644 index 0000000..7ade98d --- /dev/null +++ b/arch/x86_64/src/cpu/registers.cpp @@ -0,0 +1,64 @@ +#include "x86_64/cpu/registers.hpp" + +#include + +namespace teachos::x86_64::cpu +{ + auto read_control_register(control_register cr) -> uint64_t + { + uint64_t current_value; + switch (cr) + { + case control_register::cr0: + asm volatile("mov %%cr0, %[output]" : [output] "=r"(current_value)); + break; + case control_register::cr2: + asm volatile("mov %%cr2, %[output]" : [output] "=r"(current_value)); + break; + case control_register::cr3: + asm volatile("mov %%cr3, %[output]" : [output] "=r"(current_value)); + break; + case control_register::cr4: + asm volatile("mov %%cr4, %[output]" : [output] "=r"(current_value)); + break; + } + return current_value; + } + + auto write_control_register(control_register cr, uint64_t new_value) -> void + { + switch (cr) + { + case control_register::cr0: + asm volatile("mov %[input], %%cr0" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + case control_register::cr2: + asm volatile("mov %[input], %%cr2" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + case control_register::cr3: + asm volatile("mov %[input], %%cr3" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + case control_register::cr4: + asm volatile("mov %[input], %%cr4" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + } + } + + auto set_cr0_bit(cr0_flags flag) -> void + { + auto const cr0 = read_control_register(control_register::cr0); + write_control_register(control_register::cr0, static_cast::type>(flag) | cr0); + } +} // namespace teachos::x86_64::cpu diff --git a/arch/x86_64/src/kernel/cpu/control_register.cpp b/arch/x86_64/src/kernel/cpu/control_register.cpp deleted file mode 100644 index 41b8cd7..0000000 --- a/arch/x86_64/src/kernel/cpu/control_register.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "arch/kernel/cpu/control_register.hpp" - -#include "arch/exception_handling/panic.hpp" - -#include - -namespace teachos::arch::kernel::cpu -{ - auto read_control_register(control_register cr) -> uint64_t - { - uint64_t current_value; - switch (cr) - { - case control_register::CR0: - asm volatile("mov %%cr0, %[output]" : [output] "=r"(current_value)); - break; - case control_register::CR2: - asm volatile("mov %%cr2, %[output]" : [output] "=r"(current_value)); - break; - case control_register::CR3: - asm volatile("mov %%cr3, %[output]" : [output] "=r"(current_value)); - break; - case control_register::CR4: - asm volatile("mov %%cr4, %[output]" : [output] "=r"(current_value)); - break; - } - return current_value; - } - - auto write_control_register(control_register cr, uint64_t new_value) -> void - { - switch (cr) - { - case control_register::CR0: - asm volatile("mov %[input], %%cr0" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::CR2: - asm volatile("mov %[input], %%cr2" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::CR3: - asm volatile("mov %[input], %%cr3" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::CR4: - asm volatile("mov %[input], %%cr4" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - } - } - - auto set_cr0_bit(cr0_flags flag) -> void - { - auto const cr0 = read_control_register(control_register::CR0); - write_control_register(control_register::CR0, static_cast::type>(flag) | cr0); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/tlb.cpp b/arch/x86_64/src/kernel/cpu/tlb.cpp deleted file mode 100644 index a09001c..0000000 --- a/arch/x86_64/src/kernel/cpu/tlb.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "arch/kernel/cpu/tlb.hpp" - -#include "arch/kernel/cpu/control_register.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto tlb_flush(memory::paging::virtual_address address) -> void - { - asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); - } - - auto tlb_flush_all() -> void - { - write_control_register(cpu::control_register::CR3, read_control_register(cpu::control_register::CR3)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp new file mode 100644 index 0000000..31783fe --- /dev/null +++ b/arch/x86_64/src/memory/mmu.cpp @@ -0,0 +1,17 @@ +#include "x86_64/memory/mmu.hpp" + +#include "x86_64/cpu/registers.hpp" + +namespace teachos::x86_64::memory +{ + auto tlb_flush(linear_address address) -> void + { + asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); + } + + auto tlb_flush_all() -> void + { + auto current_value = cpu::read_control_register(cpu::control_register::cr3); + cpu::write_control_register(cpu::control_register::cr3, current_value); + } +} // namespace teachos::x86_64::memory -- cgit v1.2.3 From 2d3399ab6072acd85811a54fce8eff50628888b6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 16:35:34 +0000 Subject: x86_64: move files out of the way --- .../interrupt_descriptor_table/gate_descriptor.cpp | 24 --- .../interrupt_descriptor_table/idt_flags.cpp | 17 -- .../interrupt_descriptor_table.cpp | 53 ------ .../interrupt_descriptor_table_pointer.cpp | 13 -- .../interrupt_descriptor_table/ist_offset.cpp | 10 -- .../segment_selector.cpp | 15 -- arch/x86_64/src/context_switching/main.cpp | 63 ------- .../segment_descriptor_table/access_byte.cpp | 17 -- .../segment_descriptor_table/gdt_flags.cpp | 20 --- .../global_descriptor_table.cpp | 109 ----------- .../global_descriptor_table_pointer.cpp | 11 -- .../segment_descriptor_base.cpp | 38 ---- .../segment_descriptor_extension.cpp | 24 --- arch/x86_64/src/context_switching/syscall/main.cpp | 35 ---- .../context_switching/syscall/syscall_enable.cpp | 32 ---- .../context_switching/syscall/syscall_handler.cpp | 118 ------------ arch/x86_64/src/exception_handling/abort.cpp | 15 -- arch/x86_64/src/exception_handling/assert.cpp | 15 -- arch/x86_64/src/exception_handling/panic.cpp | 22 --- .../x86_64/src/exception_handling/pure_virtual.cpp | 6 - .../generic_interrupt_handler.cpp | 13 -- arch/x86_64/src/kernel/cpu/call.cpp | 9 - arch/x86_64/src/kernel/cpu/gdtr.cpp | 19 -- arch/x86_64/src/kernel/cpu/idtr.cpp | 18 -- arch/x86_64/src/kernel/cpu/if.cpp | 7 - arch/x86_64/src/kernel/cpu/msr.cpp | 31 ---- arch/x86_64/src/kernel/cpu/segment_register.cpp | 98 ---------- arch/x86_64/src/kernel/cpu/tr.cpp | 16 -- arch/x86_64/src/kernel/main.cpp | 71 -------- .../src/memory/allocator/area_frame_allocator.cpp | 85 --------- .../src/memory/allocator/tiny_frame_allocator.cpp | 34 ---- arch/x86_64/src/memory/heap/bump_allocator.cpp | 54 ------ .../src/memory/heap/global_heap_allocator.cpp | 135 -------------- .../src/memory/heap/linked_list_allocator.cpp | 177 ------------------ arch/x86_64/src/memory/heap/memory_block.cpp | 15 -- .../x86_64/src/memory/heap/user_heap_allocator.cpp | 200 --------------------- arch/x86_64/src/memory/main.cpp | 77 -------- .../src/memory/multiboot/elf_symbols_section.cpp | 13 -- arch/x86_64/src/memory/multiboot/reader.cpp | 135 -------------- .../x86_64/src/memory/paging/active_page_table.cpp | 98 ---------- .../src/memory/paging/inactive_page_table.cpp | 20 --- arch/x86_64/src/memory/paging/page_entry.cpp | 63 ------- arch/x86_64/src/memory/paging/page_table.cpp | 128 ------------- arch/x86_64/src/memory/paging/temporary_page.cpp | 29 --- arch/x86_64/src/memory/paging/virtual_page.cpp | 33 ---- arch/x86_64/src/user/main.cpp | 35 ---- 46 files changed, 2270 deletions(-) delete mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp delete mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp delete mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp delete mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp delete mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp delete mode 100644 arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp delete mode 100644 arch/x86_64/src/context_switching/main.cpp delete mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp delete mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp delete mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp delete mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp delete mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp delete mode 100644 arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp delete mode 100644 arch/x86_64/src/context_switching/syscall/main.cpp delete mode 100644 arch/x86_64/src/context_switching/syscall/syscall_enable.cpp delete mode 100644 arch/x86_64/src/context_switching/syscall/syscall_handler.cpp delete mode 100644 arch/x86_64/src/exception_handling/abort.cpp delete mode 100644 arch/x86_64/src/exception_handling/assert.cpp delete mode 100644 arch/x86_64/src/exception_handling/panic.cpp delete mode 100644 arch/x86_64/src/exception_handling/pure_virtual.cpp delete mode 100644 arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/call.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/gdtr.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/idtr.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/if.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/msr.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/segment_register.cpp delete mode 100644 arch/x86_64/src/kernel/cpu/tr.cpp delete mode 100644 arch/x86_64/src/kernel/main.cpp delete mode 100644 arch/x86_64/src/memory/allocator/area_frame_allocator.cpp delete mode 100644 arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp delete mode 100644 arch/x86_64/src/memory/heap/bump_allocator.cpp delete mode 100644 arch/x86_64/src/memory/heap/global_heap_allocator.cpp delete mode 100644 arch/x86_64/src/memory/heap/linked_list_allocator.cpp delete mode 100644 arch/x86_64/src/memory/heap/memory_block.cpp delete mode 100644 arch/x86_64/src/memory/heap/user_heap_allocator.cpp delete mode 100644 arch/x86_64/src/memory/main.cpp delete mode 100644 arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp delete mode 100644 arch/x86_64/src/memory/multiboot/reader.cpp delete mode 100644 arch/x86_64/src/memory/paging/active_page_table.cpp delete mode 100644 arch/x86_64/src/memory/paging/inactive_page_table.cpp delete mode 100644 arch/x86_64/src/memory/paging/page_entry.cpp delete mode 100644 arch/x86_64/src/memory/paging/page_table.cpp delete mode 100644 arch/x86_64/src/memory/paging/temporary_page.cpp delete mode 100644 arch/x86_64/src/memory/paging/virtual_page.cpp delete mode 100644 arch/x86_64/src/user/main.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/gate_descriptor.cpp deleted file mode 100644 index 28f289c..0000000 --- a/arch/x86_64/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/src/context_switching/interrupt_descriptor_table/idt_flags.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp deleted file mode 100644 index d36a4c1..0000000 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/idt_flags.cpp +++ /dev/null @@ -1,17 +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/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table.cpp deleted file mode 100644 index 7aa0859..0000000 --- a/arch/x86_64/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 - static interrupt_descriptor_table 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/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/interrupt_descriptor_table_pointer.cpp deleted file mode 100644 index 7bcbae6..0000000 --- a/arch/x86_64/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/src/context_switching/interrupt_descriptor_table/ist_offset.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/ist_offset.cpp deleted file mode 100644 index a70e75d..0000000 --- a/arch/x86_64/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/src/context_switching/interrupt_descriptor_table/segment_selector.cpp b/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp deleted file mode 100644 index 27f0a3b..0000000 --- a/arch/x86_64/src/context_switching/interrupt_descriptor_table/segment_selector.cpp +++ /dev/null @@ -1,15 +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/src/context_switching/main.cpp b/arch/x86_64/src/context_switching/main.cpp deleted file mode 100644 index 9539428..0000000 --- a/arch/x86_64/src/context_switching/main.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "arch/context_switching/main.hpp" - -#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" - -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 - { - static bool 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/src/context_switching/segment_descriptor_table/access_byte.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp deleted file mode 100644 index e31e021..0000000 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/access_byte.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "arch/context_switching/segment_descriptor_table/access_byte.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - access_byte::access_byte(uint8_t flags) - : _flags(flags) - { - // Nothing to do. - } - - auto access_byte::contains_flags(std::bitset<8U> other) const -> bool - { - return (std::bitset<8U>{_flags} & other) == other; - } - - auto access_byte::operator|=(std::bitset<8U> other) -> void { _flags |= other.to_ulong(); } -} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp deleted file mode 100644 index e444a24..0000000 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/gdt_flags.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "arch/context_switching/segment_descriptor_table/gdt_flags.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - gdt_flags::gdt_flags(uint8_t flags, std::bitset<20U> limit) - : _limit_2(limit.to_ulong() >> 16U) - , _flags(flags) - { - // Nothing to do. - } - - auto gdt_flags::contains_flags(std::bitset<4U> other) const -> bool - { - return (std::bitset<4U>{_flags} & other) == other; - } - - auto gdt_flags::get_limit() const -> std::bitset<4U> { return std::bitset<4U>{_limit_2}; } - - auto gdt_flags::operator|=(std::bitset<4U> other) -> void { _flags |= other.to_ulong(); } -} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp deleted file mode 100644 index bbcee31..0000000 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "arch/context_switching/segment_descriptor_table/global_descriptor_table.hpp" - -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/kernel/cpu/gdtr.hpp" -#include "arch/kernel/cpu/tr.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - namespace - { - auto create_segment_descriptor(segment_descriptor_type segment_descriptor_type, access_byte access_level) - -> segment_descriptor_base - { - uint64_t constexpr BASE = 0x0; - std::bitset<20U> constexpr LIMIT{0xFFFFF}; - gdt_flags flags{gdt_flags::GRANULARITY, LIMIT}; - - access_level |= access_byte::PRESENT | access_byte::CODE_OR_DATA_SEGMENT; - if (segment_descriptor_type == segment_descriptor_type::CODE_SEGMENT) - { - flags |= gdt_flags::LONG_MODE; - access_level |= access_byte::CODE_SEGMENT | access_byte::READABLE; - } - else if (segment_descriptor_type == segment_descriptor_type::DATA_SEGMENT) - { - access_level |= access_byte::WRITABLE; - } - - segment_descriptor_base const segment_descriptor_base{access_level, flags, BASE, LIMIT}; - return segment_descriptor_base; - } - - auto create_tss_descriptor(task_state_segment * tss) -> segment_descriptor_extension - { - uint64_t constexpr TSS_LIMIT = sizeof(task_state_segment) - 1; - access_byte const tss_access_byte{access_byte::PRESENT | access_byte::DESCRIPTOR_LEVEL_KERNEL | - access_byte::TASK_STATE_SEGMENT_AVAILABLE}; - gdt_flags const tss_gdt_flags{0U, TSS_LIMIT}; - segment_descriptor_extension const tss_descriptor{tss_access_byte, tss_gdt_flags, reinterpret_cast(tss), - TSS_LIMIT}; - return tss_descriptor; - } - - auto create_gdt() -> global_descriptor_table - { - segment_descriptor_base const null_segment{0}; - segment_descriptor_base const kernel_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor_base const kernel_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_KERNEL); - segment_descriptor_base const user_code_segment = - create_segment_descriptor(segment_descriptor_type::CODE_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); - segment_descriptor_base const user_data_segment = - create_segment_descriptor(segment_descriptor_type::DATA_SEGMENT, access_byte::DESCRIPTOR_LEVEL_USER); - - // Task State Segment needs to be kept alive - static auto tss = new task_state_segment(); - segment_descriptor_extension const tss_descriptor = create_tss_descriptor(tss); - - global_descriptor_table global_descriptor_table{null_segment, - kernel_code_segment, - kernel_data_segment, - user_code_segment, - user_data_segment, - tss_descriptor.get_first_gdt_entry(), - tss_descriptor.get_second_gdt_entry()}; - return global_descriptor_table; - } - } // namespace - - auto get_or_create_gdt() -> global_descriptor_table & - { - // Global Descriptor Table needs to be kept alive - static global_descriptor_table gdt = create_gdt(); - return gdt; - } - - auto update_gdtr() -> void - { - decltype(auto) gdt = get_or_create_gdt(); - - // Calculate the size of the gdt in bytes - 1. This subtraction occurs because the maximum value of Size is 65535, - // while the GDT can be up to 65536 bytes in length (8192 entries). Further, no GDT can have a size of 0 bytes. - uint16_t gdt_size = static_cast((gdt.size() * sizeof(segment_descriptor_base)) - 1); - global_descriptor_table_pointer gdt_pointer{gdt_size, gdt.data()}; - kernel::cpu::load_global_descriptor_table(gdt_pointer); - - auto const stored_gdt_pointer = kernel::cpu::store_global_descriptor_table(); - arch::exception_handling::assert( - gdt_pointer == stored_gdt_pointer, - "[Global Descriptor Table] Loaded GDTR value is not the same as the stored value."); - } - - auto update_tss_register() -> void - { - decltype(auto) gdt = get_or_create_gdt(); - - // Load task state segment descriptor from the last element in the global descriptor table, done by calculating - // offset in bytes to the start of the segment descriptor (5 * 8) = 40 - uint16_t tss_selector = (gdt.size() * sizeof(segment_descriptor_base)) - sizeof(segment_descriptor_extension); - kernel::cpu::load_task_register(tss_selector); - - auto const stored_task_register = kernel::cpu::store_task_register(); - arch::exception_handling::assert(tss_selector == stored_task_register, - "[Global Descriptor Table] Loaded TR value is not the same as the stored value."); - } - -} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp deleted file mode 100644 index 79088b8..0000000 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/global_descriptor_table_pointer.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - global_descriptor_table_pointer::global_descriptor_table_pointer(uint16_t table_length, uint64_t * address) - : table_length(table_length) - , address(address) - { - // Nothing to do. - } -} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp deleted file mode 100644 index 04804d9..0000000 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_base.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_base.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - segment_descriptor_base::segment_descriptor_base(uint64_t flags) - : _limit_1(flags) - , _base_1(flags >> 16U) - , _access(flags >> 40U) - , _flag(flags >> 52U, flags >> 48U) - , _base_2(flags >> 56U) - { - // Nothing to do. - } - - segment_descriptor_base::segment_descriptor_base(access_byte access_byte, gdt_flags flags, uint32_t base, - std::bitset<20U> limit) - : _limit_1(limit.to_ulong()) - , _base_1(base) - , _access(access_byte) - , _flag(flags) - , _base_2(base >> 24U) - { - // Nothing to do - } - - auto segment_descriptor_base::get_segment_type() const -> segment_descriptor_type - { - if (!_access.contains_flags(access_byte::CODE_OR_DATA_SEGMENT)) - { - return segment_descriptor_type::SYSTEM_SEGMENT; - } - return _access.contains_flags(access_byte::CODE_SEGMENT) ? segment_descriptor_type::CODE_SEGMENT - : segment_descriptor_type::DATA_SEGMENT; - } - - segment_descriptor_base::operator uint64_t() const { return *reinterpret_cast(this); } - -} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp b/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp deleted file mode 100644 index a28ec9b..0000000 --- a/arch/x86_64/src/context_switching/segment_descriptor_table/segment_descriptor_extension.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "arch/context_switching/segment_descriptor_table/segment_descriptor_extension.hpp" - -namespace teachos::arch::context_switching::segment_descriptor_table -{ - segment_descriptor_extension::segment_descriptor_extension(uint128_t flags) - : _base(flags) - , _base_3(flags >> 64U) - { - // Nothing to do. - } - - segment_descriptor_extension::segment_descriptor_extension(access_byte access_byte, gdt_flags flags, uint64_t base, - std::bitset<20U> limit) - : _base(access_byte, flags, base, limit) - , _base_3(base >> 32U) - { - // Nothing to do - } - - auto segment_descriptor_extension::get_first_gdt_entry() const -> segment_descriptor_base { return _base; } - - auto segment_descriptor_extension::get_second_gdt_entry() const -> uint64_t { return _base_3; } - -} // namespace teachos::arch::context_switching::segment_descriptor_table diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp deleted file mode 100644 index b4ab468..0000000 --- a/arch/x86_64/src/context_switching/syscall/main.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "arch/context_switching/syscall/main.hpp" - -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/src/context_switching/syscall/syscall_enable.cpp b/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp deleted file mode 100644 index 3c43336..0000000 --- a/arch/x86_64/src/context_switching/syscall/syscall_enable.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "arch/context_switching/syscall/syscall_enable.hpp" - -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" -#include "arch/context_switching/syscall/syscall_handler.hpp" -#include "arch/kernel/cpu/msr.hpp" - -namespace teachos::arch::context_switching::syscall -{ - namespace - { - interrupt_descriptor_table::segment_selector constexpr KERNEL_CODE_SEGMENT_SELECTOR{ - 1U, interrupt_descriptor_table::segment_selector::REQUEST_LEVEL_KERNEL}; - - auto constexpr IA32_STAR_ADDRESS = 0xC0000081; - auto constexpr IA32_LSTAR_ADDRESS = 0xC0000082; - auto constexpr IA32_FMASK_ADDRESS = 0xC0000084; - - } // 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/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp deleted file mode 100644 index 84dbe5f..0000000 --- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "arch/context_switching/syscall/syscall_handler.hpp" - -#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" - -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 - { - static auto 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/src/exception_handling/abort.cpp b/arch/x86_64/src/exception_handling/abort.cpp deleted file mode 100644 index e12e4cb..0000000 --- a/arch/x86_64/src/exception_handling/abort.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "arch/exception_handling/panic.hpp" - -#include - -namespace teachos::arch::exception_handling -{ - /** - * @brief Override for the newlib abort function. - * - * @note newlib defines @p ::abort as a weak symbol, thus allowing implementations to override it by simply providing - * a matching implementation. Since the default implemenatation calls a number of functions the kernel does not - * currently implement, @p ::abort gets overridden to simply panic. - */ - extern "C" auto abort() -> void { panic("Terminate was called, possibly due to an unhandled exception"); } -} // namespace teachos::arch::exception_handling diff --git a/arch/x86_64/src/exception_handling/assert.cpp b/arch/x86_64/src/exception_handling/assert.cpp deleted file mode 100644 index b2963de..0000000 --- a/arch/x86_64/src/exception_handling/assert.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "arch/exception_handling/assert.hpp" - -#include "arch/exception_handling/panic.hpp" - -namespace teachos::arch::exception_handling -{ - auto assert(bool condition, char const * message) -> void - { - if (condition) - { - return; - } - panic("Assertion Violation: ", message); - } -} // namespace teachos::arch::exception_handling diff --git a/arch/x86_64/src/exception_handling/panic.cpp b/arch/x86_64/src/exception_handling/panic.cpp deleted file mode 100644 index 8e3802a..0000000 --- a/arch/x86_64/src/exception_handling/panic.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "arch/exception_handling/panic.hpp" - -#include "arch/kernel/halt.hpp" -#include "arch/video/vga/text.hpp" - -namespace teachos::arch::exception_handling -{ - extern "C" char const message_prefix_panic[]; - - auto panic(char const * reason) -> void { panic(message_prefix_panic, reason); } - - auto panic(char const * prefix, char const * reason) -> void - { - using video::vga::text::common_attributes::white_on_red; - - video::vga::text::newline(); - video::vga::text::write(prefix, white_on_red); - video::vga::text::write(reason, white_on_red); - - kernel::halt(); - }; -} // namespace teachos::arch::exception_handling diff --git a/arch/x86_64/src/exception_handling/pure_virtual.cpp b/arch/x86_64/src/exception_handling/pure_virtual.cpp deleted file mode 100644 index 67772f7..0000000 --- a/arch/x86_64/src/exception_handling/pure_virtual.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "arch/exception_handling/panic.hpp" - -extern "C" auto __cxa_pure_virtual() -> void -{ - teachos::arch::exception_handling::panic("Runtime", "Tried to call a pure virtual function!"); -} diff --git a/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp b/arch/x86_64/src/interrupt_handling/generic_interrupt_handler.cpp deleted file mode 100644 index 9d061a8..0000000 --- a/arch/x86_64/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/src/kernel/cpu/call.cpp b/arch/x86_64/src/kernel/cpu/call.cpp deleted file mode 100644 index 98fa248..0000000 --- a/arch/x86_64/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/src/kernel/cpu/gdtr.cpp b/arch/x86_64/src/kernel/cpu/gdtr.cpp deleted file mode 100644 index 74a4e1c..0000000 --- a/arch/x86_64/src/kernel/cpu/gdtr.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "arch/kernel/cpu/gdtr.hpp" - -#include "arch/context_switching/segment_descriptor_table/global_descriptor_table_pointer.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto store_global_descriptor_table() -> context_switching::segment_descriptor_table::global_descriptor_table_pointer - { - context_switching::segment_descriptor_table::global_descriptor_table_pointer current_value{}; - asm("sgdt %[output]" : [output] "=m"(current_value)); - return current_value; - } - - auto load_global_descriptor_table( - context_switching::segment_descriptor_table::global_descriptor_table_pointer const & gdt_pointer) -> void - { - asm volatile("lgdt %[input]" : /* no output from call */ : [input] "m"(gdt_pointer)); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/idtr.cpp b/arch/x86_64/src/kernel/cpu/idtr.cpp deleted file mode 100644 index 7aa20c1..0000000 --- a/arch/x86_64/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/src/kernel/cpu/if.cpp b/arch/x86_64/src/kernel/cpu/if.cpp deleted file mode 100644 index 60a90a3..0000000 --- a/arch/x86_64/src/kernel/cpu/if.cpp +++ /dev/null @@ -1,7 +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/src/kernel/cpu/msr.cpp b/arch/x86_64/src/kernel/cpu/msr.cpp deleted file mode 100644 index 9c474a1..0000000 --- a/arch/x86_64/src/kernel/cpu/msr.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "arch/kernel/cpu/msr.hpp" - -namespace teachos::arch::kernel::cpu -{ - namespace - { - auto constexpr IA32_EFER_ADDRESS = 0xC0000080; - } - - auto read_msr(uint32_t msr) -> uint64_t - { - uint32_t low, high; - asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr)); - return (static_cast(high) << 32) | low; - } - - auto write_msr(uint32_t msr, uint64_t value) -> void - { - uint32_t low = value; - uint32_t high = value >> 32; - asm volatile("wrmsr" - : /* no output from call */ - : "c"(msr), "a"(low), "d"(high)); - } - - auto set_efer_bit(efer_flags flag) -> void - { - auto const efer = read_msr(IA32_EFER_ADDRESS); - write_msr(IA32_EFER_ADDRESS, static_cast::type>(flag) | efer); - } -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/segment_register.cpp b/arch/x86_64/src/kernel/cpu/segment_register.cpp deleted file mode 100644 index b08c9c4..0000000 --- a/arch/x86_64/src/kernel/cpu/segment_register.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "arch/kernel/cpu/segment_register.hpp" - -#include "arch/context_switching/interrupt_descriptor_table/segment_selector.hpp" -#include "arch/exception_handling/assert.hpp" - -namespace teachos::arch::kernel::cpu -{ - auto reload_data_segment_registers() -> void - { - asm volatile("xor %%rax, %%rax\n" - "mov %%rax, %%ss\n" - "mov %%rax, %%ds\n" - "mov %%rax, %%es\n" - "mov %%rax, %%fs\n" - "mov %%rax, %%gs\n" - : /* no output from call */ - : /* no input to call */ - : "rax"); - } - - auto set_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) -> void - { - asm volatile("xor %%rax, %%rax\n" - "mov %[input], %%ax\n" - "mov %%rax, %%ds\n" - "mov %%rax, %%es\n" - "mov %%rax, %%fs\n" - "mov %%rax, %%gs\n" - : /* no output from call */ - : [input] "m"(data_segment) - : "rax"); - } - - auto read_code_segment_register() -> context_switching::interrupt_descriptor_table::segment_selector - { - context_switching::interrupt_descriptor_table::segment_selector current_value{}; - asm volatile("mov %%cs, %[output]" : [output] "=r"(current_value)); - return current_value; - } - - auto validate_data_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment) - -> void - { - context_switching::interrupt_descriptor_table::segment_selector ss{}; - context_switching::interrupt_descriptor_table::segment_selector ds{}; - context_switching::interrupt_descriptor_table::segment_selector es{}; - context_switching::interrupt_descriptor_table::segment_selector fs{}; - context_switching::interrupt_descriptor_table::segment_selector gs{}; - - asm volatile( - "mov %%ss, %[ss_output]\n" - "mov %%ds, %[ds_output]\n" - "mov %%es, %[es_output]\n" - "mov %%fs, %[fs_output]\n" - "mov %%gs, %[gs_output]\n" - : [ss_output] "=r"(ss), [ds_output] "=r"(ds), [es_output] "=r"(es), [fs_output] "=r"(fs), [gs_output] "=r"(gs)); - - auto result = (ss == ds && ss == es && ss == fs && ss == gs); - exception_handling::assert(result, "[Segment Register] Values in data register are not the same."); - result = (ss == data_segment); - exception_handling::assert( - result, "[Segment Register] Expected Data Segment is not the same as the value in the Stack Segment register."); - } - - auto validate_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector code_segment) - -> void - { - auto const cs = read_code_segment_register(); - exception_handling::assert( - cs == code_segment, - "[Segment Register] Expected Code Segment is not the same as the value in the Code Segment register."); - } - - auto validate_segment_registers(context_switching::interrupt_descriptor_table::segment_selector data_segment, - context_switching::interrupt_descriptor_table::segment_selector code_segment) -> void - { - validate_data_segment_registers(data_segment); - validate_code_segment_register(code_segment); - } - - auto set_code_segment_register(context_switching::interrupt_descriptor_table::segment_selector data_segment, - context_switching::interrupt_descriptor_table::segment_selector code_segment, - uint64_t address) -> void - { - asm volatile("mov %%rsp, %%rax\n" - "push %[data_segment]\n" - "push %%rax\n" - "pushfq\n" - "push %[code_segment]\n" - "mov %[return_function], %%rax\n" - "push %%rax\n" - "iretq\n" - : /* no output from call */ - : [data_segment] "m"(data_segment), [code_segment] "m"(code_segment), [return_function] "r"(address) - : "rax"); - } - -} // namespace teachos::arch::kernel::cpu diff --git a/arch/x86_64/src/kernel/cpu/tr.cpp b/arch/x86_64/src/kernel/cpu/tr.cpp deleted file mode 100644 index a435540..0000000 --- a/arch/x86_64/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 diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp deleted file mode 100644 index 43b5f90..0000000 --- a/arch/x86_64/src/kernel/main.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "arch/kernel/main.hpp" - -#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" - -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/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp deleted file mode 100644 index a5a1b49..0000000 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "arch/memory/allocator/area_frame_allocator.hpp" - -#include "arch/exception_handling/assert.hpp" - -#include -#include -#include - -namespace teachos::arch::memory::allocator -{ - area_frame_allocator::area_frame_allocator(multiboot::memory_information const & mem_info) - : next_free_frame() - , current_area(std::nullopt) - , memory_areas(mem_info.areas) - , kernel_start(physical_frame::containing_address(mem_info.kernel_start)) - , kernel_end(physical_frame::containing_address(mem_info.kernel_end)) - , multiboot_start(physical_frame::containing_address(mem_info.multiboot_start)) - , multiboot_end(physical_frame::containing_address(mem_info.multiboot_end)) - { - choose_next_area(); - } - - auto area_frame_allocator::choose_next_area() -> void - { - current_area = std::nullopt; - auto next_area_with_free_frames = memory_areas | std::views::filter([this](auto const & area) { - auto address = area.base_address + area.area_length - 1; - return physical_frame::containing_address(address) >= next_free_frame; - }); - - auto const lowest_area_with_free_frames = std::ranges::min_element( - next_area_with_free_frames, [](auto const & a, auto const & b) { return a.base_address < b.base_address; }); - - if (lowest_area_with_free_frames != next_area_with_free_frames.end()) - { - current_area = *lowest_area_with_free_frames; - // Update the `next_free_frame` according to the new memory area - auto const start_frame = physical_frame::containing_address(current_area.value().base_address); - if (next_free_frame < start_frame) - { - next_free_frame = start_frame; - } - } - } - - auto area_frame_allocator::allocate_frame() -> std::optional - { - // Only try to allocate memory if current_area is not null, because - // the current_area is null if there is no more available memory. - if (!current_area.has_value()) - { - return std::nullopt; - } - - auto const address = current_area.value().base_address + current_area.value().area_length - 1; - physical_frame current_area_last_frame = physical_frame::containing_address(address); - - if (next_free_frame > current_area_last_frame) - { - // All frames of current area are used, switch to next area. - choose_next_area(); - } - else if (next_free_frame >= kernel_start && next_free_frame <= kernel_end) - { - // `physical_frame` is used by the kernel or multiboot information structure. - next_free_frame = allocator::physical_frame{kernel_end.frame_number + 1}; - } - else if (next_free_frame >= multiboot_start && next_free_frame <= multiboot_end) - { - // `physical_frame` is used by the kernel or multiboot information structure. - next_free_frame = allocator::physical_frame{multiboot_end.frame_number + 1}; - } - else - { - // Frame is unused, increment `next_free_frame` and return it. - next_free_frame.frame_number += 1; - return next_free_frame; - } - - // `physical_frame` was not valid, try it again with the updated `next_free_frame`. - return allocate_frame(); - } - - auto area_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void { (void)physical_frame; } -} // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp deleted file mode 100644 index 3cdf9c7..0000000 --- a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "arch/memory/allocator/tiny_frame_allocator.hpp" - -#include "arch/exception_handling/panic.hpp" - -namespace teachos::arch::memory::allocator -{ - auto tiny_frame_allocator::allocate_frame() -> std::optional - { - for (auto & frame_option : frames) - { - if (frame_option.has_value()) - { - auto value = frame_option; - frame_option.reset(); - return value; - } - } - return std::nullopt; - } - - auto tiny_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void - { - for (auto & frame_option : frames) - { - if (!frame_option.has_value()) - { - frame_option.emplace(physical_frame); - return; - } - } - exception_handling::panic( - "[Tiny Frame Allocator] Attempted to deallocate more than the 3 frames, that can be held"); - } -} // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/heap/bump_allocator.cpp b/arch/x86_64/src/memory/heap/bump_allocator.cpp deleted file mode 100644 index 525f45c..0000000 --- a/arch/x86_64/src/memory/heap/bump_allocator.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "arch/memory/heap/bump_allocator.hpp" - -#include "arch/exception_handling/assert.hpp" - -#include -#include - -namespace teachos::arch::memory::heap -{ - namespace - { - template - auto saturating_add(T x, T y) -> T - requires std::is_unsigned_v - { - if (x > std::numeric_limits::max() - y) - { - return std::numeric_limits::max(); - } - T result = x + y; - return result; - } - } // namespace - - auto bump_allocator::allocate(std::size_t size) -> void * - { - // Reading the value only has to be done once, because compare_exchange_weak updates the value as well if the - // exchange failed, becuase the value was not the expected one. - auto alloc_start = next.load(std::memory_order::relaxed); - // Repeat allocation until it succeeds, has to be done, because another allocator could overtake it at any time - // causing the value to differ and the calculation to have to be redone. - for (;;) - { - auto const alloc_end = saturating_add(alloc_start, size); - arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory"); - // Check if the atomic value is still the one initally loaded, if it isn't we have been overtaken by another - // thread and need to redo the calculation. Spurious failure by weak can be ignored, because the whole allocation - // is wrapped in an infinite for loop so a failure that wasn't actually one will simply be retried until it works. - auto const updated = next.compare_exchange_weak(alloc_start, alloc_end, std::memory_order::relaxed); - if (updated) - { - return reinterpret_cast(alloc_start); - } - } - } - - auto bump_allocator::deallocate(void * pointer) noexcept -> void - { - if (pointer) - { - } - } - -} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp b/arch/x86_64/src/memory/heap/global_heap_allocator.cpp deleted file mode 100644 index 35cd623..0000000 --- a/arch/x86_64/src/memory/heap/global_heap_allocator.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "arch/memory/heap/global_heap_allocator.hpp" - -#include "arch/context_switching/syscall/main.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/kernel/cpu/segment_register.hpp" -#include "arch/memory/heap/bump_allocator.hpp" -#include "arch/memory/heap/linked_list_allocator.hpp" -#include "arch/memory/heap/user_heap_allocator.hpp" - -namespace teachos::arch::memory::heap -{ - namespace - { - constexpr char NOT_REGISTRED_ERROR_MESSAGE[] = - "Attempted to allocate or deallocate using the global_heap_allocator before " - "register_heap_allocation_type was called."; - constexpr uint16_t KERNEL_CODE_INDEX = 1U; - - [[gnu::section(".user_text")]] - auto os_in_kernel_mode() -> bool - { - auto const cs = teachos::arch::kernel::cpu::read_code_segment_register(); - return cs.get_index() == KERNEL_CODE_INDEX; - } - } // namespace - - heap_allocator * global_heap_allocator::kernel_allocator_instance = nullptr; - user_heap_allocator * global_heap_allocator::user_allocator_instance = nullptr; - - auto global_heap_allocator::kmalloc(std::size_t size) -> void * { return kernel().allocate(size); } - - auto global_heap_allocator::kfree(void * pointer) noexcept -> void { kernel().deallocate(pointer); } - - auto global_heap_allocator::malloc(std::size_t size) -> void * { return user().allocate(size); } - - auto global_heap_allocator::free(void * pointer) noexcept -> void { user().deallocate(pointer); } - - auto global_heap_allocator::register_heap_allocator(heap_allocator_type new_type) -> void - { - exception_handling::assert(kernel_allocator_instance == nullptr, - "Calling register_heap_allocator_type can only be done once."); - - switch (new_type) - { - case heap_allocator_type::NONE: - // Nothing to do - break; - case heap_allocator_type::BUMP: { - static bump_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; - kernel_allocator_instance = &kernel_allocator; - break; - } - case heap_allocator_type::LINKED_LIST: { - static linked_list_allocator kernel_allocator{KERNEL_HEAP_START, KERNEL_HEAP_START + KERNEL_HEAP_SIZE}; - kernel_allocator_instance = &kernel_allocator; - break; - } - } - - [[gnu::section(".user_data")]] - static user_heap_allocator user_allocator{}; - user_allocator_instance = &user_allocator; - } - - auto global_heap_allocator::kernel() -> heap_allocator & - { - exception_handling::assert(kernel_allocator_instance != nullptr, NOT_REGISTRED_ERROR_MESSAGE); - - return *kernel_allocator_instance; - } - - auto global_heap_allocator::user() -> user_heap_allocator & - { - context_switching::syscall::syscall( - context_switching::syscall::type::ASSERT, - {user_allocator_instance != nullptr, reinterpret_cast(&NOT_REGISTRED_ERROR_MESSAGE)}); - return *user_allocator_instance; - } -} // namespace teachos::arch::memory::heap - -auto operator new(std::size_t size) -> void * -{ - if (teachos::arch::memory::heap::os_in_kernel_mode()) - { - return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); - } - return teachos::arch::memory::heap::global_heap_allocator::malloc(size); -} - -auto operator delete(void * pointer) noexcept -> void -{ - if (teachos::arch::memory::heap::os_in_kernel_mode()) - { - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); - } - teachos::arch::memory::heap::global_heap_allocator::free(pointer); -} - -auto operator delete(void * pointer, std::size_t size) noexcept -> void -{ - (void)size; - if (teachos::arch::memory::heap::os_in_kernel_mode()) - { - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); - } - teachos::arch::memory::heap::global_heap_allocator::free(pointer); -} - -auto operator new[](std::size_t size) -> void * -{ - if (teachos::arch::memory::heap::os_in_kernel_mode()) - { - return teachos::arch::memory::heap::global_heap_allocator::kmalloc(size); - } - return teachos::arch::memory::heap::global_heap_allocator::malloc(size); -} - -auto operator delete[](void * pointer) noexcept -> void -{ - if (teachos::arch::memory::heap::os_in_kernel_mode()) - { - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); - } - teachos::arch::memory::heap::global_heap_allocator::free(pointer); -} - -auto operator delete[](void * pointer, std::size_t size) noexcept -> void -{ - (void)size; - if (teachos::arch::memory::heap::os_in_kernel_mode()) - { - teachos::arch::memory::heap::global_heap_allocator::kfree(pointer); - } - teachos::arch::memory::heap::global_heap_allocator::free(pointer); -} diff --git a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp deleted file mode 100644 index 00ca366..0000000 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include "arch/memory/heap/linked_list_allocator.hpp" - -#include "arch/exception_handling/assert.hpp" -#include "arch/exception_handling/panic.hpp" - -#include - -namespace teachos::arch::memory::heap -{ - linked_list_allocator::linked_list_allocator(std::size_t heap_start, std::size_t heap_end) - : first(nullptr) - , mutex{kstd::mutex{}} - { - auto const heap_size = heap_end - heap_start; - exception_handling::assert( - heap_size > min_allocatable_size(), - "[Linked List Allocator] Total heap size can not be smaller than minimum of 16 bytes to hold " - "atleast one memory hole entry"); - first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); - } - - auto linked_list_allocator::allocate(std::size_t size) -> void * - { - // Add size of size_t to the total allocated size, because we add a header that includes the size of the allocated - // block, to allow for deallocation without the need to call with the corresponding size - auto const total_size = size + sizeof(std::size_t); - mutex.lock(); - - memory_block * previous = nullptr; - auto current = first; - - while (current != nullptr) - { - if (current->size == total_size) - { - auto const memory_address = remove_free_memory_block(previous, current); - new (memory_address) std::size_t(total_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); - } - else if (current->size >= total_size + min_allocatable_size()) - { - // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards - // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if - // the total size was less and simply deallocate it as well - auto const max_size = std::max(total_size, min_allocatable_size()); - auto const memory_address = split_free_memory_block(previous, current, max_size); - new (memory_address) std::size_t(max_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); - } - - previous = current; - current = current->next; - } - - exception_handling::panic("[Linked List Allocator] Out of memory"); - } - - auto linked_list_allocator::deallocate(void * pointer) noexcept -> void - { - mutex.lock(); - - // Read configured header size of the complete allocated block - auto const header_pointer = reinterpret_cast(reinterpret_cast(pointer) - sizeof(std::size_t)); - auto const total_size = *reinterpret_cast(header_pointer); - - auto const start_address = reinterpret_cast(header_pointer); - auto const end_address = start_address + total_size; - - memory_block * previous = nullptr; - auto current = first; - - while (current != nullptr) - { - // Current address of the free memory block now points to an address that is after our block to deallocate in heap - // memory space. - if (reinterpret_cast(current) >= end_address) - { - break; - } - - previous = current; - current = current->next; - } - - coalesce_free_memory_block(previous, current, header_pointer, total_size); - mutex.unlock(); - } - - auto linked_list_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) - -> void * - { - return replace_free_memory_block(previous_block, current_block, current_block->next); - } - - auto linked_list_allocator::split_free_memory_block(memory_block * previous_block, memory_block * current_block, - std::size_t size) -> void * - { - auto const end_address = reinterpret_cast(current_block) + size; - auto const new_block = - new (reinterpret_cast(end_address)) memory_block(current_block->size - size, current_block->next); - return replace_free_memory_block(previous_block, current_block, new_block); - } - - auto linked_list_allocator::replace_free_memory_block(memory_block * previous_block, memory_block * current_block, - memory_block * new_block) -> void * - { - auto const start_address = reinterpret_cast(current_block); - // If we want to allocate into the first block that is before any other free block, then there exists no previous - // free block (nullptr). Therefore we have to overwrite the first block instead of overwriting its next value. - if (previous_block == nullptr) - { - first = new_block; - } - else - { - previous_block->next = new_block; - } - current_block->~memory_block(); - return reinterpret_cast(start_address); - } - - auto linked_list_allocator::coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, - void * pointer, std::size_t size) -> void - { - auto const start_address = reinterpret_cast(pointer); - auto const end_address = start_address + size; - - // Inital values if there are no adjacent blocks either before or after, meaning we have to simply create a free - // memory block that is placed in between the previous and next block. - auto block_size = size; - auto next_block = current_block; - - // If the block we want to deallocate is before another free block and we can therefore combine both into one. - // This is done by deleting the current free block and creating a new block at the start address of the block to - // deallocate with both the size of the block to deallcoate and the free block next to it. - if (end_address == reinterpret_cast(current_block)) - { - block_size += current_block->size; - next_block = current_block->next; - current_block->~memory_block(); - } - - // If the block we want to deallocate is behind another free block and we can therefore combine both into one. - // This is done by simply changin the size of the previous block to include the size of the block to deallocate. - // This is done, because the previous block might still be referencered by the next field of other memory blocks. - if (previous_block != nullptr && - start_address == (reinterpret_cast(previous_block) + previous_block->size)) - { - block_size += previous_block->size; - - previous_block->size = block_size; - previous_block->next = next_block; - return; - } - - // Check if the block we want to deallocate is contained in the previous block, because if it is it can only mean - // that the block has already been deallocated and we therefore attempted a double free. - exception_handling::assert(previous_block == nullptr || - start_address >= - (reinterpret_cast(previous_block) + previous_block->size), - "[Linked List Allocator] Attempted double free detected"); - - auto const new_block = new (pointer) memory_block(block_size, next_block); - // If we want to deallocate the first block that is before any other free block, then there exists no previous free - // block (nullptr). Therefore we have to overwrite the first block instead of overwriting its - // next value. - if (previous_block == nullptr) - { - first = new_block; - return; - } - previous_block->next = new_block; - } - -} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/heap/memory_block.cpp b/arch/x86_64/src/memory/heap/memory_block.cpp deleted file mode 100644 index bc97bd6..0000000 --- a/arch/x86_64/src/memory/heap/memory_block.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "arch/memory/heap/memory_block.hpp" - -#include - -namespace teachos::arch::memory::heap -{ - memory_block::memory_block(std::size_t size, memory_block * next) - { - memset(static_cast(this), 0U, size); - this->size = size; - this->next = next; - } - - memory_block::~memory_block() { memset(static_cast(this), 0U, sizeof(memory_block)); } -} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp deleted file mode 100644 index 427a68a..0000000 --- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include "arch/memory/heap/user_heap_allocator.hpp" - -#include "arch/context_switching/syscall/main.hpp" - -#include - -namespace teachos::arch::memory::heap -{ - auto user_heap_allocator::allocate(std::size_t size) -> void * - { - // Add size of size_t to the total allocated size, because we add a header that includes the size of the allocated - // block, to allow for deallocation without the need to call with the corresponding size - auto const total_size = size + sizeof(std::size_t); - mutex.lock(); - - memory_block * previous = nullptr; - auto current = first; - - while (current != nullptr) - { - auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size); - if (memory.has_value()) - { - return memory.value(); - } - - previous = current; - current = current->next; - } - - current = expand_heap_if_full(); - - if (current != nullptr) - { - auto memory = allocate_into_memory_block_if_big_enough(current, previous, total_size); - if (memory.has_value()) - { - return memory.value(); - } - } - - char constexpr OUT_OF_MEMORY_ERROR_MESSAGE[] = "[Linked List Allocator] Out of memory"; - context_switching::syscall::syscall(context_switching::syscall::type::ASSERT, - {false, reinterpret_cast(&OUT_OF_MEMORY_ERROR_MESSAGE)}); - return nullptr; - } - - auto user_heap_allocator::deallocate(void * pointer) noexcept -> void - { - mutex.lock(); - - // Read configured header size of the complete allocated block - auto const header_pointer = reinterpret_cast(reinterpret_cast(pointer) - sizeof(std::size_t)); - auto const total_size = *reinterpret_cast(header_pointer); - - auto const start_address = reinterpret_cast(header_pointer); - auto const end_address = start_address + total_size; - - memory_block * previous = nullptr; - auto current = first; - - while (current != nullptr) - { - // Current address of the free memory block now points to an address that is after our block to deallocate in heap - // memory space. - if (reinterpret_cast(current) >= end_address) - { - break; - } - - previous = current; - current = current->next; - } - - coalesce_free_memory_block(previous, current, header_pointer, total_size); - mutex.unlock(); - } - - auto user_heap_allocator::allocate_into_memory_block_if_big_enough(memory_block * current, memory_block * previous, - std::size_t total_size) -> std::optional - { - if (current->size == total_size) - { - auto const memory_address = remove_free_memory_block(previous, current); - new (memory_address) std::size_t(total_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); - } - else if (current->size >= total_size + min_allocatable_size()) - { - // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards - // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if - // the total size was less and simply deallocate it as well - auto const max_size = std::max(total_size, min_allocatable_size()); - auto const memory_address = split_free_memory_block(previous, current, max_size); - new (memory_address) std::size_t(max_size); - mutex.unlock(); - return reinterpret_cast(reinterpret_cast(memory_address) + sizeof(std::size_t)); - } - return std::nullopt; - } - - auto user_heap_allocator::expand_heap_if_full() -> memory_block * - { - auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP); - - uint64_t const heap_start = result.values.arg_0; - uint64_t const heap_size = result.values.arg_1; - return !result.error_code ? new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr) : nullptr; - } - - auto user_heap_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block) - -> void * - { - return replace_free_memory_block(previous_block, current_block, current_block->next); - } - - auto user_heap_allocator::split_free_memory_block(memory_block * previous_block, memory_block * current_block, - std::size_t size) -> void * - { - auto const end_address = reinterpret_cast(current_block) + size; - auto const new_block = - new (reinterpret_cast(end_address)) memory_block(current_block->size - size, current_block->next); - return replace_free_memory_block(previous_block, current_block, new_block); - } - - auto user_heap_allocator::replace_free_memory_block(memory_block * previous_block, memory_block * current_block, - memory_block * new_block) -> void * - { - auto const start_address = reinterpret_cast(current_block); - // If we want to allocate into the first block that is before any other free block, then there exists no previous - // free block (nullptr). Therefore we have to overwrite the first block instead of overwriting its next value. - if (previous_block == nullptr) - { - first = new_block; - } - else - { - previous_block->next = new_block; - } - current_block->~memory_block(); - return reinterpret_cast(start_address); - } - - auto user_heap_allocator::coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, - void * pointer, std::size_t size) -> void - { - auto const start_address = reinterpret_cast(pointer); - auto const end_address = start_address + size; - - // Inital values if there are no adjacent blocks either before or after, meaning we have to simply create a free - // memory block that is placed in between the previous and next block. - auto block_size = size; - auto next_block = current_block; - - // If the block we want to deallocate is before another free block and we can therefore combine both into one. - // This is done by deleting the current free block and creating a new block at the start address of the block to - // deallocate with both the size of the block to deallcoate and the free block next to it. - if (end_address == reinterpret_cast(current_block)) - { - block_size += current_block->size; - next_block = current_block->next; - current_block->~memory_block(); - } - - // If the block we want to deallocate is behind another free block and we can therefore combine both into one. - // This is done by simply changin the size of the previous block to include the size of the block to deallocate. - // This is done, because the previous block might still be referencered by the next field of other memory blocks. - if (previous_block != nullptr && - start_address == (reinterpret_cast(previous_block) + previous_block->size)) - { - block_size += previous_block->size; - - previous_block->size = block_size; - previous_block->next = next_block; - return; - } - - // Check if the block we want to deallocate is contained in the previous block, because if it is it can only mean - // that the block has already been deallocated and we therefore attempted a double free. - char constexpr DOUBLE_FREE_ERROR_MESSAGE[] = "[Linked List Allocator] Attempted double free detected"; - context_switching::syscall::syscall( - context_switching::syscall::type::ASSERT, - {previous_block == nullptr || - start_address >= (reinterpret_cast(previous_block) + previous_block->size), - reinterpret_cast(&DOUBLE_FREE_ERROR_MESSAGE)}); - - auto const new_block = new (pointer) memory_block(block_size, next_block); - // If we want to deallocate the first block that is before any other free block, then there exists no previous free - // block (nullptr). Therefore we have to overwrite the first block instead of overwriting its - // next value. - if (previous_block == nullptr) - { - first = new_block; - return; - } - previous_block->next = new_block; - } - -} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp deleted file mode 100644 index 2746a71..0000000 --- a/arch/x86_64/src/memory/main.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "arch/memory/main.hpp" - -#include "arch/exception_handling/assert.hpp" -#include "arch/kernel/cpu/control_register.hpp" -#include "arch/kernel/cpu/msr.hpp" -#include "arch/memory/allocator/area_frame_allocator.hpp" -#include "arch/memory/allocator/concept.hpp" -#include "arch/memory/heap/global_heap_allocator.hpp" -#include "arch/memory/paging/active_page_table.hpp" -#include "arch/memory/paging/kernel_mapper.hpp" - -#include - -namespace teachos::arch::memory -{ - namespace - { - static std::optional frame_allocator; - - auto create_frame_allocator(multiboot::memory_information const & memory_information) - -> allocator::area_frame_allocator & - { - frame_allocator.emplace(memory_information); - return frame_allocator.value(); - } - - auto get_frame_allocator() -> allocator::area_frame_allocator & - { - exception_handling::assert(frame_allocator.has_value(), - "[Initialization] Frame allocator has not been created yet"); - return frame_allocator.value(); - } - } // namespace - - auto remap_heap(std::size_t heap_start, std::size_t heap_size, paging::entry::bitset additional_flags = {}) -> void - { - decltype(auto) allocator = get_frame_allocator(); - decltype(auto) active_table = paging::active_page_table::create_or_get(); - auto const start_page = paging::virtual_page::containing_address(heap_start); - auto const end_page = ++(paging::virtual_page::containing_address(heap_start + heap_size - 1)); - - paging::page_container::iterator const begin{start_page}; - paging::page_container::iterator const end{end_page}; - paging::page_container const pages{begin, end}; - - constexpr auto base_flags = paging::entry::WRITABLE; - auto const flags = base_flags | additional_flags; - - for (auto const & page : pages) - { - active_table.map_page_to_next_free_frame(allocator, page, flags); - } - } - - auto initialize_memory_management() -> void - { - static bool has_been_called = false; - arch::exception_handling::assert(!has_been_called, - "[Initialization] Memory management has already been initialized"); - has_been_called = true; - - auto const memory_information = multiboot::read_multiboot2(); - decltype(auto) allocator = create_frame_allocator(memory_information); - - kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); - kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); - - paging::kernel_mapper kernel(allocator, memory_information); - kernel.remap_kernel(); - video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); - video::vga::text::newline(); - - remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); - video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); - video::vga::text::newline(); - } -} // namespace teachos::arch::memory diff --git a/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp b/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp deleted file mode 100644 index f5d126b..0000000 --- a/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "arch/memory/multiboot/elf_symbols_section.hpp" - -namespace teachos::arch::memory::multiboot -{ - auto elf_section_flags::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } - - auto elf_section_header::is_null() const -> bool - { - return name_table_index == 0U && type == elf_section_type::INACTIVE && flags == elf_section_flags(0U) && - physical_address == 0U && file_offset == 0U && additional_information == 0U && address_alignment == 0U && - fixed_table_entry_size == 0U; - } -} // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp deleted file mode 100644 index b05e6b3..0000000 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "arch/memory/multiboot/reader.hpp" - -#include "arch/boot/pointers.hpp" -#include "arch/exception_handling/assert.hpp" -#include "multiboot2/information.hpp" -// #include "arch/memory/multiboot/elf_symbols_section.hpp" -// #include "arch/memory/multiboot/info.hpp" - -#include -#include - -// namespace teachos::arch::memory::multiboot -// { -// namespace -// { -// template -// requires std::is_pointer::value -// auto align_to_8_byte_boundary(T ptr, uint32_t size) -> T -// { -// return reinterpret_cast(reinterpret_cast(ptr) + ((size + 7) & ~7)); -// } - -// auto process_memory_map(memory_map_header * mminfo) -> memory_area_container -// { -// auto const expected_entry_size = mminfo->entry_size; -// auto constexpr actual_entry_size = sizeof(memory_area); -// exception_handling::assert(expected_entry_size == actual_entry_size, -// "[Multiboot Reader] Unexpected memory area entry size"); - -// auto const total_size = mminfo->info.size; -// auto const total_entries_size = total_size - sizeof(memory_map_header) + actual_entry_size; -// auto const number_of_entries = total_entries_size / actual_entry_size; - -// auto const begin = memory_area_container::iterator{&mminfo->entries}; -// auto const end = begin + number_of_entries; -// return memory_area_container{begin, end}; -// } - -// auto process_elf_sections(elf_symbols_section_header * symbol, std::size_t & kernel_start, std::size_t & -// kernel_end) -// -> elf_section_header_container -// { -// auto const expected_entry_size = symbol->entry_size; -// auto constexpr actual_entry_size = sizeof(elf_section_header); -// exception_handling::assert(expected_entry_size == actual_entry_size, -// "[Multiboot Reader] Unexpected elf section header entry size"); - -// auto const expected_total_size = symbol->info.size; -// auto const actual_total_entry_size = actual_entry_size * symbol->number_of_sections; -// auto constexpr actual_total_section_size = sizeof(elf_symbols_section_header) - sizeof(uint32_t); -// auto const actual_total_size = actual_total_entry_size + actual_total_section_size; -// exception_handling::assert(expected_total_size == actual_total_size, -// "[Multiboot Reader] Unexpected elf symbols section header total size"); - -// auto const begin = elf_section_header_container::iterator{reinterpret_cast(&symbol->end)}; auto const end = begin + symbol->number_of_sections; -// exception_handling::assert(begin->is_null(), -// "[Multiboot Reader] Elf symbols section not starting with SHT_NULL section"); - -// elf_section_header_container sections{begin, end}; - -// auto allocated_sections = sections | std::views::filter([](auto const & section) { -// return section.flags.contains_flags(elf_section_flags::OCCUPIES_MEMORY); -// }); - -// auto const elf_section_with_lowest_physical_address = std::ranges::min_element( -// allocated_sections, [](auto const & a, auto const & b) { return a.physical_address < b.physical_address; -// }); - -// auto const elf_section_with_highest_physical_address = -// std::ranges::max_element(allocated_sections, [](auto const & a, auto const & b) { -// auto a_physical_address_end = a.physical_address + a.section_size; -// auto b_physical_address_end = b.physical_address + b.section_size; -// return a_physical_address_end < b_physical_address_end; -// }); - -// auto const symbol_table_section_count = std::ranges::count_if(sections, [](auto const & section) { -// return section.type == elf_section_type::DYNAMIC_SYMBOL_TABLE || section.type == -// elf_section_type::SYMBOL_TABLE; -// }); -// auto const dynamic_section_count = std::ranges::count_if( -// sections, [](auto const & section) { return section.type == elf_section_type::DYNAMIC; }); - -// exception_handling::assert( -// symbol_table_section_count == 1U, -// "[Multiboot Reader] ELF Specifications allows only (1) symbol table section, but got more"); -// exception_handling::assert( -// dynamic_section_count <= 1U, -// "[Multiboot Reader] ELF Specifications allows only (1) or less dynamic sections, but got more"); - -// auto const lowest_elf_section = *elf_section_with_lowest_physical_address; -// kernel_start = lowest_elf_section.physical_address; - -// auto const highest_elf_section = *elf_section_with_highest_physical_address; -// kernel_end = highest_elf_section.physical_address + highest_elf_section.section_size; - -// return sections; -// } -// } // namespace - -// auto read_multiboot2() -> memory_information -// { -// memory_information mem_info{UINT64_MAX, -// 0U, -// elf_section_header_container{}, -// boot::multiboot_information_pointer, -// 0U, -// memory_area_container{}}; - -// auto const multiboot_information_pointer = reinterpret_cast(boot::multiboot_information_pointer); -// auto const multiboot_tag = &multiboot_information_pointer->tags; -// mem_info.multiboot_end = mem_info.multiboot_start + multiboot_information_pointer->total_size; - -// for (auto tag = multiboot_tag; tag->type != tag_type::END; tag = align_to_8_byte_boundary(tag, tag->size)) -// { -// switch (tag->type) -// { -// case tag_type::ELF_SECTIONS: { -// auto const symbol = reinterpret_cast(tag); -// mem_info.sections = process_elf_sections(symbol, mem_info.kernel_start, mem_info.kernel_end); -// break; -// } -// case tag_type::MEMORY_MAP: { -// auto const mminfo = reinterpret_cast(tag); -// mem_info.areas = process_memory_map(mminfo); -// break; -// } -// default: -// // All other cases are not important and can be ignored. -// break; -// } -// } -// return mem_info; -// } -// } // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp deleted file mode 100644 index 0113869..0000000 --- a/arch/x86_64/src/memory/paging/active_page_table.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "arch/memory/paging/active_page_table.hpp" - -namespace teachos::arch::memory::paging -{ - namespace - { - paging::virtual_address constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; - } - - auto active_page_table::create_or_get() -> active_page_table & - { - static page_table_handle active_handle{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS), - page_table_handle::LEVEL4}; - static active_page_table active_page{active_handle}; - return active_page; - } - - auto active_page_table::operator[](std::size_t index) -> entry & { return active_handle[index]; } - - auto active_page_table::translate_address(virtual_address address) -> std::optional - { - auto const offset = address % allocator::PAGE_FRAME_SIZE; - auto const page = virtual_page::containing_address(address); - auto const frame = translate_page(page); - - if (frame.has_value()) - { - return frame.value().frame_number * allocator::PAGE_FRAME_SIZE + offset; - } - - return std::nullopt; - } - - auto active_page_table::translate_page(virtual_page page) -> std::optional - { - auto current_handle = active_handle; - - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) - { - auto const next_handle = current_handle.next_table(page.get_level_index(level)); - // If the next table method failed then it is highly likely that it was a huge page and we therefore have to - // parse the table differently. Therefore, we attempt to parse it using the method required by huge pages. - if (!next_handle.has_value()) - { - return translate_huge_page(page); - } - current_handle = next_handle.value(); - } - - auto const level1_index = page.get_level_index(page_table_handle::LEVEL1); - auto const level1_entry = current_handle[level1_index]; - return level1_entry.calculate_pointed_to_frame(); - } - - auto active_page_table::translate_huge_page(virtual_page page) -> std::optional - { - auto current_handle = active_handle; - auto level3_handle = current_handle.next_table(page.get_level_index(page_table_handle::LEVEL4)); - - if (!level3_handle.has_value()) - { - return std::nullopt; - } - - auto const level3_entry = level3_handle.value()[page.get_level_index(page_table_handle::LEVEL3)]; - auto const level3_frame = level3_entry.calculate_pointed_to_frame(); - if (level3_frame.has_value() && level3_entry.contains_flags(entry::HUGE_PAGE)) - { - exception_handling::assert( - level3_frame.value().frame_number % (PAGE_TABLE_ENTRY_COUNT * PAGE_TABLE_ENTRY_COUNT) == 0U, - "[Page Mapper] Physical address must be 1 GiB aligned"); - return allocator::physical_frame{level3_frame.value().frame_number + - page.get_level_index(page_table_handle::LEVEL2) * PAGE_TABLE_ENTRY_COUNT + - page.get_level_index(page_table_handle::LEVEL1)}; - } - - auto level2_handle = level3_handle.value().next_table(page.get_level_index(page_table_handle::LEVEL3)); - if (level2_handle.has_value()) - { - auto const level2_entry = level2_handle.value()[page.get_level_index(page_table_handle::LEVEL2)]; - auto const level2_frame = level2_entry.calculate_pointed_to_frame(); - if (level2_frame.has_value() && level2_entry.contains_flags(entry::HUGE_PAGE)) - { - exception_handling::assert(level2_frame.value().frame_number % PAGE_TABLE_ENTRY_COUNT == 0U, - "[Page Mapper] Physical address must be 2 MiB aligned"); - return allocator::physical_frame{level2_frame.value().frame_number + - page.get_level_index(page_table_handle::LEVEL1)}; - } - } - return std::nullopt; - } - - active_page_table::active_page_table(page_table_handle active_handle) - : active_handle(active_handle) - { - // Nothing to do - } -} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp deleted file mode 100644 index 4e0610e..0000000 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "arch/memory/paging/inactive_page_table.hpp" - -namespace teachos::arch::memory::paging -{ - inactive_page_table::inactive_page_table(allocator::physical_frame frame) - : page_table_level_4_frame{frame} - { - // Nothing to do - } - - inactive_page_table::inactive_page_table(allocator::physical_frame frame, active_page_table & active_page_table, - temporary_page & temporary_page) - : page_table_level_4_frame{frame} - { - auto table = temporary_page.map_table_frame(page_table_level_4_frame, active_page_table); - table.zero_entries(); - table[511].set_entry(page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); - temporary_page.unmap_page(active_page_table); - } -} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp deleted file mode 100644 index 57045ca..0000000 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "arch/memory/paging/page_entry.hpp" - -#include "arch/exception_handling/assert.hpp" - -namespace teachos::arch::memory::paging -{ - namespace - { - std::size_t constexpr PHYSICAL_ADDRESS_MASK = 0x000fffff'fffff000; - } // namespace - - entry::entry(uint64_t flags) - : flags(flags) - { - // Nothing to do. - } - - entry::entry(multiboot::elf_section_flags elf_flags) - { - if (elf_flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) - { - flags |= entry::PRESENT; - } - - if (elf_flags.contains_flags(multiboot::elf_section_flags::WRITABLE)) - { - flags |= entry::WRITABLE; - } - - if (!elf_flags.contains_flags(multiboot::elf_section_flags::EXECUTABLE_CODE)) - { - flags |= entry::EXECUTING_CODE_FORBIDDEN; - } - } - - auto entry::is_unused() const -> bool { return flags == 0U; } - - auto entry::set_unused() -> void { flags = 0U; } - - auto entry::set_user_accessible() -> void { flags |= entry::USER_ACCESSIBLE; } - - auto entry::calculate_pointed_to_frame() const -> std::optional - { - if (contains_flags(PRESENT)) - { - auto const address = flags.to_ulong() & PHYSICAL_ADDRESS_MASK; - return allocator::physical_frame::containing_address(address); - } - return std::nullopt; - } - - auto entry::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } - - auto entry::set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void - { - exception_handling::assert((frame.start_address() & ~PHYSICAL_ADDRESS_MASK) == 0, - "[Paging Entry] Start address is not aligned with page"); - - flags = frame.start_address() | additional_flags.to_ulong(); - } - - auto entry::get_flags() const -> std::bitset<64U> { return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; } -} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp deleted file mode 100644 index eb11810..0000000 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "arch/memory/paging/page_table.hpp" - -#include -#include -#include - -/* - * This is a linker variable reference. This referenc cannot reside inside a namespace, because in - * that case the compiler would try to find arch::memory::paging::_end_of_image inside the ELF file. - */ -extern char _end_of_image; - -namespace teachos::arch::memory::paging -{ - /** - * @brief A Page table containing 512 entries. - */ - struct page_table - { - auto zero_entries() -> void; - - auto is_empty() const -> bool; - - auto next_table(std::size_t table_index) const -> std::optional; - - auto operator[](std::size_t index) -> entry &; - - auto operator[](std::size_t index) const -> entry const &; - - private: - /** - * @brief Calculates the address of the next page table level for the given table index. - * - * @note The next page table address is only valid if the corresponding entry is present and not a huge page. - * Meaning we use an index into a Level 4 page table to get the according Level 3 page table address. - * - * @param table_index Index of this page table in the page table one level higher. - * @return An optional of the address of the next page table or null. - */ - auto next_table_address(std::size_t table_index) const -> std::optional; - - std::array entries = - {}; ///< Entries containing addresses to page tables of a level below or - ///< actual virtual addresses for the level 1 page table. - }; - - auto page_table::zero_entries() -> void - { - std::ranges::for_each(entries, [](auto & entry) { entry.set_unused(); }); - } - - auto page_table::is_empty() const -> bool - { - return std::all_of(entries.begin(), entries.end(), [](entry const & entry) { return entry.is_unused(); }); - } - - auto page_table::next_table(std::size_t table_index) const -> std::optional - { - auto const address = next_table_address(table_index); - if (address.has_value()) - { - return reinterpret_cast(address.value()); - } - return std::nullopt; - } - - auto page_table::operator[](std::size_t index) -> entry & - { - exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] Index out of bounds"); - return entries[index]; - } - - auto page_table::operator[](std::size_t index) const -> entry const & - { - exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] Index out of bounds"); - return entries[index]; - } - - auto page_table::next_table_address(std::size_t table_index) const -> std::optional - { - auto const entry = this->operator[](table_index); - - if (entry.contains_flags(entry::PRESENT) && !entry.contains_flags(entry::HUGE_PAGE)) - { - auto const table_address = reinterpret_cast(this); - return ((table_address << 9) | (table_index << 12)); - } - return std::nullopt; - } - - page_table_handle::page_table_handle(page_table * table, page_table_handle::level table_level) - : table(table) - , table_level(table_level) - { - exception_handling::assert(table != nullptr, - "[Page Table] Attempted to pass nullptr as table to page table table method"); - } - - auto page_table_handle::zero_entries() -> void { table->zero_entries(); } - - auto page_table_handle::is_empty() const -> bool { return table->is_empty(); } - - auto page_table_handle::next_table(std::size_t table_index) const -> std::optional - { - exception_handling::assert(table_level != page_table_handle::LEVEL1, - "[Page Table] Attempted to call next_table on level 1 page table"); - auto const next_table = table->next_table(table_index); - if (next_table.has_value()) - { - auto const new_level = static_cast(table_level - 1); - return page_table_handle{next_table.value(), new_level}; - } - return std::nullopt; - } - - auto page_table_handle::get_level() const -> page_table_handle::level { return table_level; } - - auto page_table_handle::operator[](std::size_t index) -> entry & { return table->operator[](index); } - - auto operator--(page_table_handle::level & value) -> page_table_handle::level & - { - exception_handling::assert(value != page_table_handle::LEVEL1, - "[Page table] Attempted to decrement enum to value outside of range"); - auto new_value = static_cast::type>(value); - value = static_cast(--new_value); - return value; - } -} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp deleted file mode 100644 index 8e73523..0000000 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "arch/memory/paging/temporary_page.hpp" - -#include "arch/memory/paging/page_entry.hpp" - -namespace teachos::arch::memory::paging -{ - auto temporary_page::map_table_frame(allocator::physical_frame frame, active_page_table & active_table) - -> page_table_handle - { - page_table_handle handle{reinterpret_cast(map_to_frame(frame, active_table)), - page_table_handle::LEVEL1}; - return handle; - } - - auto temporary_page::map_to_frame(allocator::physical_frame frame, active_page_table & active_table) - -> virtual_address - { - exception_handling::assert(!active_table.translate_page(page).has_value(), - "[Temporary page] Page is already mapped"); - - active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE); - return page.start_address(); - } - - auto temporary_page::unmap_page(active_page_table & active_table) -> void - { - active_table.unmap_page(allocator, page); - } -} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/virtual_page.cpp b/arch/x86_64/src/memory/paging/virtual_page.cpp deleted file mode 100644 index d374156..0000000 --- a/arch/x86_64/src/memory/paging/virtual_page.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "arch/memory/paging/virtual_page.hpp" - -#include "arch/exception_handling/assert.hpp" - -namespace teachos::arch::memory::paging -{ - auto virtual_page::containing_address(virtual_address address) -> virtual_page - { - exception_handling::assert(address < 0x00008000'00000000 || address >= 0xffff8000'00000000, - "[Virtual Page] Attempted to create virtual page from invalid address"); - return virtual_page{address / allocator::PAGE_FRAME_SIZE}; - } - - auto virtual_page::start_address() const -> virtual_address { return page_number * allocator::PAGE_FRAME_SIZE; } - - auto virtual_page::get_level_index(page_table_handle::level level) const -> size_t - { - return (page_number >> (level * 9U)) & 0x1FF; - } - - auto virtual_page::operator++(int) -> virtual_page - { - virtual_page const old_value = *this; - ++page_number; - return old_value; - } - - auto virtual_page::operator++() -> virtual_page & - { - ++page_number; - return *this; - } -} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/user/main.cpp b/arch/x86_64/src/user/main.cpp deleted file mode 100644 index 8b07e4a..0000000 --- a/arch/x86_64/src/user/main.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "arch/user/main.hpp" - -#include "arch/context_switching/syscall/main.hpp" -#include "arch/memory/heap/global_heap_allocator.hpp" - -#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 -- cgit v1.2.3 From dd04850c27e8bc273506f4a64bb28b7ddf111dc5 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 24 Jul 2025 20:51:55 +0000 Subject: kapi: rework text device interface --- arch/x86_64/src/vga/text.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 5c94b84..af089fd 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -13,19 +13,24 @@ namespace teachos::x86_64::vga::text { namespace { - auto buffer_offset = std::ptrdiff_t{}; + auto constinit buffer_offset = std::ptrdiff_t{}; auto constexpr DEFAULT_TEXT_BUFFER_WIDTH = 80U; auto constexpr DEFAULT_TEXT_BUFFER_HEIGHT = 25U; + + auto write_char(char code_point, attribute attribute) -> void + { + vga_buffer_pointer[buffer_offset++] = std::pair{code_point, std::bit_cast(attribute)}; + }; } // namespace - auto clear(attribute attribute) -> void + auto device::clear(attribute attribute) -> void { buffer_offset = 0; std::ranges::fill_n(vga_buffer_pointer.get(), 2000, std::pair{' ', std::bit_cast(attribute)}); } - auto cursor(bool enabled) -> void + auto device::cursor(bool enabled) -> void { auto cursor_disable_byte = std::byte{!enabled} << 5; @@ -33,7 +38,7 @@ namespace teachos::x86_64::vga::text crtc::data::write(crtc::data::read() | cursor_disable_byte); } - auto newline() -> void + auto device::newline() -> void { auto current_line = buffer_offset / DEFAULT_TEXT_BUFFER_WIDTH; auto next_line = current_line + 1; @@ -51,13 +56,15 @@ namespace teachos::x86_64::vga::text } } - auto write_char(char code_point, attribute attribute) -> void + auto device::write(std::string_view code_points, attribute attribute) -> void { - vga_buffer_pointer[buffer_offset++] = std::pair{code_point, std::bit_cast(attribute)}; - }; + std::ranges::for_each(code_points, [&](auto code_point) { write_char(code_point, attribute); }); + } - auto write(std::string_view code_points, attribute attribute) -> void + auto device::writeln(std::string_view code_points, attribute attribute) -> void { std::ranges::for_each(code_points, [&](auto code_point) { write_char(code_point, attribute); }); + newline(); } + } // namespace teachos::x86_64::vga::text -- cgit v1.2.3 From 7671b1f0e4790b43bb8f8747b63cd44b7a65e10f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 27 Oct 2025 13:58:55 +0000 Subject: x86_64: move kapi implementation to src --- arch/x86_64/src/kapi/cio.cpp | 16 ++++++++++ arch/x86_64/src/kapi/memory.cpp | 66 +++++++++++++++++++++++++++++++++++++++++ arch/x86_64/src/kapi/system.cpp | 12 ++++++++ 3 files changed, 94 insertions(+) create mode 100644 arch/x86_64/src/kapi/cio.cpp create mode 100644 arch/x86_64/src/kapi/memory.cpp create mode 100644 arch/x86_64/src/kapi/system.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/cio.cpp b/arch/x86_64/src/kapi/cio.cpp new file mode 100644 index 0000000..ac3ae39 --- /dev/null +++ b/arch/x86_64/src/kapi/cio.cpp @@ -0,0 +1,16 @@ +#include "kapi/cio.hpp" + +#include "x86_64/vga/text.hpp" + +namespace teachos::cio +{ + + auto static constinit vga_device = std::optional{}; + + auto init() -> void + { + vga_device.emplace(); + set_output_device(*vga_device); + } + +} // namespace teachos::cio diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp new file mode 100644 index 0000000..d1c1f03 --- /dev/null +++ b/arch/x86_64/src/kapi/memory.cpp @@ -0,0 +1,66 @@ +#include "kapi/memory.hpp" + +#include "kapi/system.hpp" + +#include "x86_64/boot/boot.hpp" +#include "x86_64/boot/ld.hpp" +#include "x86_64/memory/address.hpp" +#include "x86_64/memory/region_allocator.hpp" + +#include + +#include + +namespace teachos::memory +{ + using namespace x86_64::memory; + using namespace x86_64::boot; + + namespace + { + auto constinit is_initialized = std::atomic_flag{}; + + auto create_memory_information() -> region_allocator::memory_information + { + auto const & mbi = multiboot_information_pointer.get(); + auto map = mbi->memory_map(); + + return {std::make_pair(physical_address{&_start_physical}, physical_address{&_end_physical}), + std::make_pair(physical_address{std::bit_cast(&mbi)}, + physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), + map}; + }; + } // namespace + + auto init() -> void + { + if (is_initialized.test_and_set()) + { + system::panic("[x86_64] Memory management has already been initialized."); + } + + auto memory_map = multiboot_information_pointer->maybe_memory_map(); + if (!memory_map) + { + system::panic("[x86_64] No memory map available."); + } + + auto mem_info = create_memory_information(); + auto allocator = region_allocator{mem_info}; + + static_cast(allocator); + + // kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); + // kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); + + // paging::kernel_mapper kernel(allocator, memory_information); + // kernel.remap_kernel(); + // video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); + // video::vga::text::newline(); + + // remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); + // video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); + // video::vga::text::newline(); + } + +} // namespace teachos::memory diff --git a/arch/x86_64/src/kapi/system.cpp b/arch/x86_64/src/kapi/system.cpp new file mode 100644 index 0000000..2d4c3fe --- /dev/null +++ b/arch/x86_64/src/kapi/system.cpp @@ -0,0 +1,12 @@ +#include "kapi/system.hpp" + +namespace teachos::system +{ + + auto halt() -> void + { + asm volatile("1: hlt\njmp 1b"); + __builtin_unreachable(); + } + +} // namespace teachos::system -- cgit v1.2.3 From 6434de8ff75a9143847ef529bc209790ac4909b3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 11:09:42 +0100 Subject: kapi: move frame and address to KAPI --- arch/x86_64/src/cpu/registers.cpp | 4 ++-- arch/x86_64/src/kapi/cio.cpp | 2 +- arch/x86_64/src/kapi/memory.cpp | 8 +++++--- arch/x86_64/src/memory/mmu.cpp | 6 ++++-- arch/x86_64/src/memory/region_allocator.cpp | 16 ++++------------ arch/x86_64/src/vga/text.cpp | 6 ++++-- 6 files changed, 20 insertions(+), 22 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/registers.cpp b/arch/x86_64/src/cpu/registers.cpp index 7ade98d..8646829 100644 --- a/arch/x86_64/src/cpu/registers.cpp +++ b/arch/x86_64/src/cpu/registers.cpp @@ -2,7 +2,7 @@ #include -namespace teachos::x86_64::cpu +namespace teachos::cpu::x86_64 { auto read_control_register(control_register cr) -> uint64_t { @@ -61,4 +61,4 @@ namespace teachos::x86_64::cpu auto const cr0 = read_control_register(control_register::cr0); write_control_register(control_register::cr0, static_cast::type>(flag) | cr0); } -} // namespace teachos::x86_64::cpu +} // namespace teachos::cpu::x86_64 diff --git a/arch/x86_64/src/kapi/cio.cpp b/arch/x86_64/src/kapi/cio.cpp index ac3ae39..eb0142a 100644 --- a/arch/x86_64/src/kapi/cio.cpp +++ b/arch/x86_64/src/kapi/cio.cpp @@ -5,7 +5,7 @@ namespace teachos::cio { - auto static constinit vga_device = std::optional{}; + auto static constinit vga_device = std::optional{}; auto init() -> void { diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index d1c1f03..55e6ba9 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -1,10 +1,10 @@ #include "kapi/memory.hpp" +#include "kapi/memory/frame.hpp" #include "kapi/system.hpp" #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" -#include "x86_64/memory/address.hpp" #include "x86_64/memory/region_allocator.hpp" #include @@ -13,8 +13,10 @@ namespace teachos::memory { - using namespace x86_64::memory; - using namespace x86_64::boot; + using namespace boot::x86_64; + using namespace memory::x86_64; + + std::size_t const PLATFORM_FRAME_SIZE{4096}; namespace { diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp index 31783fe..e573b4e 100644 --- a/arch/x86_64/src/memory/mmu.cpp +++ b/arch/x86_64/src/memory/mmu.cpp @@ -2,8 +2,10 @@ #include "x86_64/cpu/registers.hpp" -namespace teachos::x86_64::memory +namespace teachos::memory::x86_64 { + namespace cpu = cpu::x86_64; + auto tlb_flush(linear_address address) -> void { asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); @@ -14,4 +16,4 @@ namespace teachos::x86_64::memory auto current_value = cpu::read_control_register(cpu::control_register::cr3); cpu::write_control_register(cpu::control_register::cr3, current_value); } -} // namespace teachos::x86_64::memory +} // namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index c9a98b4..91a5d49 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -1,22 +1,14 @@ -// #include "arch/memory/allocator/region_allocator.hpp" - -// #include "arch/exception_handling/assert.hpp" - -// #include -// #include -// #include - #include "x86_64/memory/region_allocator.hpp" -#include "x86_64/memory/address.hpp" -#include "x86_64/memory/frame.hpp" +#include "kapi/memory/address.hpp" +#include "kapi/memory/frame.hpp" #include #include #include -namespace teachos::x86_64::memory +namespace teachos::memory::x86_64 { namespace { @@ -92,4 +84,4 @@ namespace teachos::x86_64::memory } auto region_allocator::deallocate_frame(frame const &) -> void {} -} // namespace teachos::x86_64::memory +} // namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index af089fd..8f78ea9 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -9,8 +9,10 @@ #include #include -namespace teachos::x86_64::vga::text +namespace teachos::vga::x86_64::text { + using boot::x86_64::vga_buffer_pointer; + namespace { auto constinit buffer_offset = std::ptrdiff_t{}; @@ -67,4 +69,4 @@ namespace teachos::x86_64::vga::text newline(); } -} // namespace teachos::x86_64::vga::text +} // namespace teachos::vga::x86_64::text -- cgit v1.2.3 From e7b04ef7f5da8e014e8b85fcf65448b317cca8ff Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 11:15:50 +0100 Subject: kapi: move halt to cpu namespace --- arch/x86_64/src/kapi/cpu.cpp | 12 ++++++++++++ arch/x86_64/src/kapi/system.cpp | 12 ------------ 2 files changed, 12 insertions(+), 12 deletions(-) create mode 100644 arch/x86_64/src/kapi/cpu.cpp delete mode 100644 arch/x86_64/src/kapi/system.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/cpu.cpp b/arch/x86_64/src/kapi/cpu.cpp new file mode 100644 index 0000000..22543ee --- /dev/null +++ b/arch/x86_64/src/kapi/cpu.cpp @@ -0,0 +1,12 @@ +#include "kapi/cpu.hpp" + +namespace teachos::cpu +{ + + auto halt() -> void + { + asm volatile("1: hlt\njmp 1b"); + __builtin_unreachable(); + } + +} // namespace teachos::cpu diff --git a/arch/x86_64/src/kapi/system.cpp b/arch/x86_64/src/kapi/system.cpp deleted file mode 100644 index 2d4c3fe..0000000 --- a/arch/x86_64/src/kapi/system.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "kapi/system.hpp" - -namespace teachos::system -{ - - auto halt() -> void - { - asm volatile("1: hlt\njmp 1b"); - __builtin_unreachable(); - } - -} // namespace teachos::system -- cgit v1.2.3 From 845a96f5e6bfbbbeba19bf3df07f0e9de53d9a88 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 11:40:49 +0100 Subject: kapi: export frame_allocator interface --- arch/x86_64/src/kapi/memory.cpp | 12 ++++++++++++ arch/x86_64/src/memory/region_allocator.cpp | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 55e6ba9..be47941 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -1,6 +1,7 @@ #include "kapi/memory.hpp" #include "kapi/memory/frame.hpp" +#include "kapi/memory/frame_allocator.hpp" #include "kapi/system.hpp" #include "x86_64/boot/boot.hpp" @@ -21,6 +22,7 @@ namespace teachos::memory namespace { auto constinit is_initialized = std::atomic_flag{}; + auto constinit allocator = static_cast(nullptr); auto create_memory_information() -> region_allocator::memory_information { @@ -34,6 +36,16 @@ namespace teachos::memory }; } // namespace + auto active_allocator() -> frame_allocator & + { + if (!allocator) + { + system::panic("[x86_64] The frame allocator has not been set yet."); + } + + return *allocator; + } + auto init() -> void { if (is_initialized.test_and_set()) diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index 91a5d49..11ffce2 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -51,7 +51,7 @@ namespace teachos::memory::x86_64 } } - auto region_allocator::allocate_frame() -> std::optional + auto region_allocator::allocate() -> std::optional { if (!m_current_region) { @@ -80,8 +80,8 @@ namespace teachos::memory::x86_64 return allocated; } - return allocate_frame(); + return allocate(); } - auto region_allocator::deallocate_frame(frame const &) -> void {} + auto region_allocator::release(frame) -> void {} } // namespace teachos::memory::x86_64 -- cgit v1.2.3 From c71d18f32e06fb456bc2829d9dfc5b42b78160b0 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 11:53:34 +0100 Subject: x86_64: reduce using namespace use --- arch/x86_64/src/kapi/memory.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index be47941..46686b6 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -6,6 +6,7 @@ #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" +#include "x86_64/cpu/registers.hpp" #include "x86_64/memory/region_allocator.hpp" #include @@ -14,9 +15,6 @@ namespace teachos::memory { - using namespace boot::x86_64; - using namespace memory::x86_64; - std::size_t const PLATFORM_FRAME_SIZE{4096}; namespace @@ -24,12 +22,13 @@ namespace teachos::memory auto constinit is_initialized = std::atomic_flag{}; auto constinit allocator = static_cast(nullptr); - auto create_memory_information() -> region_allocator::memory_information + auto create_memory_information() -> x86_64::region_allocator::memory_information { - auto const & mbi = multiboot_information_pointer.get(); + auto const & mbi = boot::x86_64::multiboot_information_pointer.get(); auto map = mbi->memory_map(); - return {std::make_pair(physical_address{&_start_physical}, physical_address{&_end_physical}), + return {std::make_pair(physical_address{&boot::x86_64::_start_physical}, + physical_address{&boot::x86_64::_end_physical}), std::make_pair(physical_address{std::bit_cast(&mbi)}, physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), map}; @@ -53,19 +52,20 @@ namespace teachos::memory system::panic("[x86_64] Memory management has already been initialized."); } - auto memory_map = multiboot_information_pointer->maybe_memory_map(); + auto memory_map = boot::x86_64::multiboot_information_pointer->maybe_memory_map(); if (!memory_map) { system::panic("[x86_64] No memory map available."); } auto mem_info = create_memory_information(); - auto allocator = region_allocator{mem_info}; + auto allocator = x86_64::region_allocator{mem_info}; static_cast(allocator); - // kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); - // kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); + cpu::x86_64::set_cr0_bit(cpu::x86_64::cr0_flags::WRITE_PROTECT); + + // set_efer_bit(efer_flags::NXE); // paging::kernel_mapper kernel(allocator, memory_information); // kernel.remap_kernel(); -- cgit v1.2.3 From f5aee1e1ab521d6aeb4c79f6ef276625159e202f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 11:58:12 +0100 Subject: x86_64: extract early boot steps --- arch/x86_64/src/kapi/memory.cpp | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 46686b6..a29a0cd 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -33,6 +33,23 @@ namespace teachos::memory physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), map}; }; + + auto create_early_frame_allocator() + { + auto memory_map = boot::x86_64::multiboot_information_pointer->maybe_memory_map(); + if (!memory_map) + { + system::panic("[x86_64] Failed to create early allocator, no memory map available."); + } + + return x86_64::region_allocator{create_memory_information()}; + } + + auto enable_cpu_protections() -> void + { + cpu::x86_64::set_cr0_bit(cpu::x86_64::cr0_flags::WRITE_PROTECT); + // set_efer_bit(efer_flags::NXE); + } } // namespace auto active_allocator() -> frame_allocator & @@ -52,20 +69,8 @@ namespace teachos::memory system::panic("[x86_64] Memory management has already been initialized."); } - auto memory_map = boot::x86_64::multiboot_information_pointer->maybe_memory_map(); - if (!memory_map) - { - system::panic("[x86_64] No memory map available."); - } - - auto mem_info = create_memory_information(); - auto allocator = x86_64::region_allocator{mem_info}; - - static_cast(allocator); - - cpu::x86_64::set_cr0_bit(cpu::x86_64::cr0_flags::WRITE_PROTECT); - - // set_efer_bit(efer_flags::NXE); + [[maybe_unused]] auto allocator = create_early_frame_allocator(); + enable_cpu_protections(); // paging::kernel_mapper kernel(allocator, memory_information); // kernel.remap_kernel(); -- cgit v1.2.3 From f06fc25b9a54a800c5301eec7320903380da947c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 12:11:09 +0100 Subject: x86_64/memory: simplify region allocator --- arch/x86_64/src/memory/region_allocator.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index 11ffce2..d94e810 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -16,6 +16,11 @@ namespace teachos::memory::x86_64 { return frame::containing(physical_address{region.base + region.size_in_B - 1}); } + + auto constexpr falls_within(frame const & candidate, frame const & start, frame const & end) + { + return candidate >= start && candidate <= end; + } } // namespace region_allocator::region_allocator(memory_information const & mem_info) @@ -65,19 +70,17 @@ namespace teachos::memory::x86_64 { choose_next_area(); } - else if (m_next_frame >= m_kernel_start && m_next_frame <= m_kernel_end) + else if (falls_within(m_next_frame, m_kernel_start, m_kernel_end)) { m_next_frame = m_kernel_end + 1; } - else if (m_next_frame >= m_multiboot_start && m_next_frame <= m_multiboot_end) + else if (falls_within(m_next_frame, m_multiboot_start, m_multiboot_end)) { m_next_frame = m_multiboot_end + 1; } else { - auto allocated = m_next_frame; - ++m_next_frame; - return allocated; + return m_next_frame++; } return allocate(); -- cgit v1.2.3 From 40e67a6dba7837c562613016bdc8bad17d069e57 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 12:24:41 +0100 Subject: x86_64/memory: fix region allocator initialization During construction, the memory map was not extracted from the supplied memory information. This lead to a situation in which the allocator would never allocate any frames since it believed that there was no memory in the system. --- arch/x86_64/src/memory/region_allocator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index d94e810..13103c7 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -26,7 +26,7 @@ namespace teachos::memory::x86_64 region_allocator::region_allocator(memory_information const & mem_info) : m_next_frame{} , m_current_region{} - , m_memory_map{} + , m_memory_map{mem_info.memory_map} , m_kernel_start(frame::containing(mem_info.image_range.first)) , m_kernel_end(frame::containing(mem_info.image_range.second)) , m_multiboot_start(frame::containing(mem_info.mbi_range.first)) -- cgit v1.2.3 From 465817e3e124bafb95de0d8a030b66bc067046b6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 13:35:58 +0100 Subject: x86_64/memory: fix region_allocator initialization --- arch/x86_64/src/kapi/memory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index a29a0cd..61d462f 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -29,8 +29,8 @@ namespace teachos::memory return {std::make_pair(physical_address{&boot::x86_64::_start_physical}, physical_address{&boot::x86_64::_end_physical}), - std::make_pair(physical_address{std::bit_cast(&mbi)}, - physical_address{std::bit_cast(&mbi) + mbi->size_bytes()}), + std::make_pair(physical_address{std::bit_cast(mbi)}, + physical_address{std::bit_cast(mbi) + mbi->size_bytes()}), map}; }; -- cgit v1.2.3 From b157e2c472d8bd67ac1656404a6a6ee821260f4b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 15:01:43 +0100 Subject: chore: reformat source code --- arch/x86_64/src/boot/initialize_runtime.cpp | 4 +++- arch/x86_64/src/memory/region_allocator.cpp | 4 ++-- arch/x86_64/src/vga/text.cpp | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/initialize_runtime.cpp b/arch/x86_64/src/boot/initialize_runtime.cpp index 9a3df0e..70172c9 100644 --- a/arch/x86_64/src/boot/initialize_runtime.cpp +++ b/arch/x86_64/src/boot/initialize_runtime.cpp @@ -16,7 +16,9 @@ extern "C" auto constructors = std::span{&__ctors_start, &__ctors_end}; auto initializers = std::span{&__init_array_start, &__init_array_end}; - auto apply_invoke = [](auto invokable) { return std::invoke(invokable); }; + auto apply_invoke = [](auto invokable) { + return std::invoke(invokable); + }; std::ranges::for_each(constructors, apply_invoke); std::ranges::for_each(initializers, apply_invoke); diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index 13103c7..a0579a3 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -12,12 +12,12 @@ namespace teachos::memory::x86_64 { namespace { - auto constexpr last_frame(multiboot2::memory_map::region const & region) + constexpr auto last_frame(multiboot2::memory_map::region const & region) { return frame::containing(physical_address{region.base + region.size_in_B - 1}); } - auto constexpr falls_within(frame const & candidate, frame const & start, frame const & end) + constexpr auto falls_within(frame const & candidate, frame const & start, frame const & end) { return candidate >= start && candidate <= end; } diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 8f78ea9..8aa809f 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -17,8 +17,8 @@ namespace teachos::vga::x86_64::text { auto constinit buffer_offset = std::ptrdiff_t{}; - auto constexpr DEFAULT_TEXT_BUFFER_WIDTH = 80U; - auto constexpr DEFAULT_TEXT_BUFFER_HEIGHT = 25U; + constexpr auto DEFAULT_TEXT_BUFFER_WIDTH = 80U; + constexpr auto DEFAULT_TEXT_BUFFER_HEIGHT = 25U; auto write_char(char code_point, attribute attribute) -> void { -- cgit v1.2.3 From 7b9df8bec5038e0316540d2397df632fb14c9169 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 29 Oct 2025 17:01:22 +0100 Subject: chore: configure clang-tidy --- arch/x86_64/src/cpu/registers.cpp | 4 ++-- arch/x86_64/src/kapi/cio.cpp | 1 + arch/x86_64/src/kapi/memory.cpp | 14 +++++++++----- arch/x86_64/src/vga/text.cpp | 7 +++++-- 4 files changed, 17 insertions(+), 9 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/registers.cpp b/arch/x86_64/src/cpu/registers.cpp index 8646829..d59776b 100644 --- a/arch/x86_64/src/cpu/registers.cpp +++ b/arch/x86_64/src/cpu/registers.cpp @@ -6,7 +6,7 @@ namespace teachos::cpu::x86_64 { auto read_control_register(control_register cr) -> uint64_t { - uint64_t current_value; + uint64_t current_value{}; switch (cr) { case control_register::cr0: @@ -59,6 +59,6 @@ namespace teachos::cpu::x86_64 auto set_cr0_bit(cr0_flags flag) -> void { auto const cr0 = read_control_register(control_register::cr0); - write_control_register(control_register::cr0, static_cast::type>(flag) | cr0); + write_control_register(control_register::cr0, static_cast>(flag) | cr0); } } // namespace teachos::cpu::x86_64 diff --git a/arch/x86_64/src/kapi/cio.cpp b/arch/x86_64/src/kapi/cio.cpp index eb0142a..456477a 100644 --- a/arch/x86_64/src/kapi/cio.cpp +++ b/arch/x86_64/src/kapi/cio.cpp @@ -5,6 +5,7 @@ namespace teachos::cio { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto static constinit vga_device = std::optional{}; auto init() -> void diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 61d462f..e05fde9 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -19,19 +19,23 @@ namespace teachos::memory namespace { + // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) auto constinit is_initialized = std::atomic_flag{}; auto constinit allocator = static_cast(nullptr); + // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) auto create_memory_information() -> x86_64::region_allocator::memory_information { auto const & mbi = boot::x86_64::multiboot_information_pointer.get(); auto map = mbi->memory_map(); - return {std::make_pair(physical_address{&boot::x86_64::_start_physical}, - physical_address{&boot::x86_64::_end_physical}), - std::make_pair(physical_address{std::bit_cast(mbi)}, - physical_address{std::bit_cast(mbi) + mbi->size_bytes()}), - map}; + // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) + return {.image_range = std::make_pair(physical_address{&boot::x86_64::_start_physical}, + physical_address{&boot::x86_64::_end_physical}), + .mbi_range = std::make_pair(physical_address{std::bit_cast(mbi)}, + physical_address{std::bit_cast(mbi) + mbi->size_bytes()}), + .memory_map = map}; + // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) }; auto create_early_frame_allocator() diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 8aa809f..0e0d353 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -15,10 +15,12 @@ namespace teachos::vga::x86_64::text namespace { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit buffer_offset = std::ptrdiff_t{}; constexpr auto DEFAULT_TEXT_BUFFER_WIDTH = 80U; constexpr auto DEFAULT_TEXT_BUFFER_HEIGHT = 25U; + constexpr auto CURSOR_ENABLED_BIT = 5U; auto write_char(char code_point, attribute attribute) -> void { @@ -29,12 +31,13 @@ namespace teachos::vga::x86_64::text auto device::clear(attribute attribute) -> void { buffer_offset = 0; - std::ranges::fill_n(vga_buffer_pointer.get(), 2000, std::pair{' ', std::bit_cast(attribute)}); + std::ranges::fill_n(vga_buffer_pointer.get(), DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT, + std::pair{' ', std::bit_cast(attribute)}); } auto device::cursor(bool enabled) -> void { - auto cursor_disable_byte = std::byte{!enabled} << 5; + auto cursor_disable_byte = std::byte{!enabled} << CURSOR_ENABLED_BIT; crtc::address::write(crtc::registers::cursor_start); crtc::data::write(crtc::data::read() | cursor_disable_byte); -- cgit v1.2.3 From b1143bde71bb029ac2bf7d08ba422fcdaedd56a6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 31 Oct 2025 07:19:16 +0100 Subject: build: enable linting --- arch/x86_64/src/boot/initialize_runtime.cpp | 4 ++-- arch/x86_64/src/memory/region_allocator.cpp | 6 +++--- arch/x86_64/src/vga/text.cpp | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/initialize_runtime.cpp b/arch/x86_64/src/boot/initialize_runtime.cpp index 70172c9..46dd5e4 100644 --- a/arch/x86_64/src/boot/initialize_runtime.cpp +++ b/arch/x86_64/src/boot/initialize_runtime.cpp @@ -16,8 +16,8 @@ extern "C" auto constructors = std::span{&__ctors_start, &__ctors_end}; auto initializers = std::span{&__init_array_start, &__init_array_end}; - auto apply_invoke = [](auto invokable) { - return std::invoke(invokable); + auto apply_invoke = [](auto invokable) -> void { + std::invoke(invokable); }; std::ranges::for_each(constructors, apply_invoke); diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index a0579a3..8ea76c6 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -40,10 +40,10 @@ namespace teachos::memory::x86_64 m_current_region.reset(); auto next_area_with_free_frames = m_memory_map | std::views::filter(&multiboot2::memory_map::region::available) | - std::views::filter([next = m_next_frame](auto const & region) { return last_frame(region) >= next; }); + std::views::filter([next = m_next_frame](auto const & region) -> bool { return last_frame(region) >= next; }); - auto lowest_region_with_free_frames = - std::ranges::min_element(next_area_with_free_frames, [](auto lhs, auto rhs) { return lhs.base < rhs.base; }); + auto lowest_region_with_free_frames = std::ranges::min_element( + next_area_with_free_frames, [](auto lhs, auto rhs) -> bool { return lhs.base < rhs.base; }); if (lowest_region_with_free_frames != next_area_with_free_frames.end()) { diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 0e0d353..6ecffa3 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -48,7 +48,7 @@ namespace teachos::vga::x86_64::text auto current_line = buffer_offset / DEFAULT_TEXT_BUFFER_WIDTH; auto next_line = current_line + 1; - if (next_line >= DEFAULT_TEXT_BUFFER_HEIGHT) + if (std::cmp_greater_equal(next_line, DEFAULT_TEXT_BUFFER_HEIGHT)) { auto begin = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH; auto end = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT; @@ -63,12 +63,12 @@ namespace teachos::vga::x86_64::text auto device::write(std::string_view code_points, attribute attribute) -> void { - std::ranges::for_each(code_points, [&](auto code_point) { write_char(code_point, attribute); }); + std::ranges::for_each(code_points, [&](auto code_point) -> void { write_char(code_point, attribute); }); } auto device::writeln(std::string_view code_points, attribute attribute) -> void { - std::ranges::for_each(code_points, [&](auto code_point) { write_char(code_point, attribute); }); + std::ranges::for_each(code_points, [&](auto code_point) -> void { write_char(code_point, attribute); }); newline(); } -- cgit v1.2.3 From 49dcbdaaca348784d7fa05e12a06123f4dc252ec Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 18 Nov 2025 18:14:30 +0100 Subject: x86_64/memory: perform slight cleanup --- arch/x86_64/src/kapi/memory.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index e05fde9..aa3eb58 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -27,15 +27,12 @@ namespace teachos::memory auto create_memory_information() -> x86_64::region_allocator::memory_information { auto const & mbi = boot::x86_64::multiboot_information_pointer.get(); - auto map = mbi->memory_map(); - // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) return {.image_range = std::make_pair(physical_address{&boot::x86_64::_start_physical}, physical_address{&boot::x86_64::_end_physical}), .mbi_range = std::make_pair(physical_address{std::bit_cast(mbi)}, physical_address{std::bit_cast(mbi) + mbi->size_bytes()}), - .memory_map = map}; - // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) + .memory_map = mbi->memory_map()}; }; auto create_early_frame_allocator() -- cgit v1.2.3 From a5ca21e45e9c8ead0b5895771c0b2f3fe3baf96b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 21 Nov 2025 14:53:37 +0100 Subject: x86_64: rework control register access --- arch/x86_64/src/cpu/registers.cpp | 64 --------------------------------------- arch/x86_64/src/kapi/memory.cpp | 3 +- arch/x86_64/src/memory/mmu.cpp | 4 +-- 3 files changed, 4 insertions(+), 67 deletions(-) delete mode 100644 arch/x86_64/src/cpu/registers.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/cpu/registers.cpp b/arch/x86_64/src/cpu/registers.cpp deleted file mode 100644 index d59776b..0000000 --- a/arch/x86_64/src/cpu/registers.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "x86_64/cpu/registers.hpp" - -#include - -namespace teachos::cpu::x86_64 -{ - auto read_control_register(control_register cr) -> uint64_t - { - uint64_t current_value{}; - switch (cr) - { - case control_register::cr0: - asm volatile("mov %%cr0, %[output]" : [output] "=r"(current_value)); - break; - case control_register::cr2: - asm volatile("mov %%cr2, %[output]" : [output] "=r"(current_value)); - break; - case control_register::cr3: - asm volatile("mov %%cr3, %[output]" : [output] "=r"(current_value)); - break; - case control_register::cr4: - asm volatile("mov %%cr4, %[output]" : [output] "=r"(current_value)); - break; - } - return current_value; - } - - auto write_control_register(control_register cr, uint64_t new_value) -> void - { - switch (cr) - { - case control_register::cr0: - asm volatile("mov %[input], %%cr0" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::cr2: - asm volatile("mov %[input], %%cr2" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::cr3: - asm volatile("mov %[input], %%cr3" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - case control_register::cr4: - asm volatile("mov %[input], %%cr4" - : /* no output from call */ - : [input] "r"(new_value) - : "memory"); - break; - } - } - - auto set_cr0_bit(cr0_flags flag) -> void - { - auto const cr0 = read_control_register(control_register::cr0); - write_control_register(control_register::cr0, static_cast>(flag) | cr0); - } -} // namespace teachos::cpu::x86_64 diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index aa3eb58..4766bb3 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -6,6 +6,7 @@ #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" +#include "x86_64/cpu/impl/control_registers.hpp" #include "x86_64/cpu/registers.hpp" #include "x86_64/memory/region_allocator.hpp" @@ -48,7 +49,7 @@ namespace teachos::memory auto enable_cpu_protections() -> void { - cpu::x86_64::set_cr0_bit(cpu::x86_64::cr0_flags::WRITE_PROTECT); + cpu::x86_64::cr0::clear(cpu::x86_64::cr0::flags::write_protect); // set_efer_bit(efer_flags::NXE); } } // namespace diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp index e573b4e..8ec8a2e 100644 --- a/arch/x86_64/src/memory/mmu.cpp +++ b/arch/x86_64/src/memory/mmu.cpp @@ -13,7 +13,7 @@ namespace teachos::memory::x86_64 auto tlb_flush_all() -> void { - auto current_value = cpu::read_control_register(cpu::control_register::cr3); - cpu::write_control_register(cpu::control_register::cr3, current_value); + auto paging_root = cpu::cr3::read(); + cpu::cr3::write(paging_root); } } // namespace teachos::memory::x86_64 -- cgit v1.2.3 From 7f935cdc3e57d80c4ef83760e1a616c33684271d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 21 Nov 2025 14:55:10 +0100 Subject: x86_64: fix enabling of write protection --- arch/x86_64/src/kapi/memory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 4766bb3..6102bee 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -49,7 +49,7 @@ namespace teachos::memory auto enable_cpu_protections() -> void { - cpu::x86_64::cr0::clear(cpu::x86_64::cr0::flags::write_protect); + cpu::x86_64::cr0::set(cpu::x86_64::cr0::flags::write_protect); // set_efer_bit(efer_flags::NXE); } } // namespace -- cgit v1.2.3 From 9ee028e52bd60affded3b90ea8dcd20c93bb5025 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Nov 2025 13:16:35 +0100 Subject: x86-64/kapi: reimplement ia32_efer support --- arch/x86_64/src/kapi/memory.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 6102bee..d0d966b 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -6,7 +6,6 @@ #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" -#include "x86_64/cpu/impl/control_registers.hpp" #include "x86_64/cpu/registers.hpp" #include "x86_64/memory/region_allocator.hpp" @@ -50,7 +49,7 @@ namespace teachos::memory auto enable_cpu_protections() -> void { cpu::x86_64::cr0::set(cpu::x86_64::cr0::flags::write_protect); - // set_efer_bit(efer_flags::NXE); + cpu::x86_64::i32_efer::set(cpu::x86_64::i32_efer::flags::execute_disable_bit_enable); } } // namespace -- cgit v1.2.3 From 2b3dca0d0329b61881ffbecca0f120cfda3314fa Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Nov 2025 13:25:12 +0100 Subject: x86_64/kapi: clean up one linter warning --- arch/x86_64/src/kapi/memory.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index d0d966b..5142a2a 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -19,10 +19,8 @@ namespace teachos::memory namespace { - // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) - auto constinit is_initialized = std::atomic_flag{}; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit allocator = static_cast(nullptr); - // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) auto create_memory_information() -> x86_64::region_allocator::memory_information { @@ -65,6 +63,7 @@ namespace teachos::memory auto init() -> void { + auto static constinit is_initialized = std::atomic_flag{}; if (is_initialized.test_and_set()) { system::panic("[x86_64] Memory management has already been initialized."); -- cgit v1.2.3 From 1a3c20cc9ea191a862eb7e8ac55b3a69ac74ad5e Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Nov 2025 16:59:24 +0100 Subject: x86_64/vga: rely less on magic state --- arch/x86_64/src/boot/entry64.s | 19 ++++++++++++++++ arch/x86_64/src/kapi/memory.cpp | 4 ++-- arch/x86_64/src/vga/text.cpp | 50 ++++++++++++++++++++++++----------------- 3 files changed, 50 insertions(+), 23 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/entry64.s b/arch/x86_64/src/boot/entry64.s index c5df5db..636e4cd 100644 --- a/arch/x86_64/src/boot/entry64.s +++ b/arch/x86_64/src/boot/entry64.s @@ -1,3 +1,16 @@ +.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 @@ -10,6 +23,12 @@ _entry64: mov %rax, %fs mov %rax, %gs + mov multiboot_information_pointer, %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 diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 5142a2a..3848fb8 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -24,7 +24,7 @@ namespace teachos::memory auto create_memory_information() -> x86_64::region_allocator::memory_information { - auto const & mbi = boot::x86_64::multiboot_information_pointer.get(); + auto const & mbi = boot::bootstrap_information.mbi; return {.image_range = std::make_pair(physical_address{&boot::x86_64::_start_physical}, physical_address{&boot::x86_64::_end_physical}), @@ -35,7 +35,7 @@ namespace teachos::memory auto create_early_frame_allocator() { - auto memory_map = boot::x86_64::multiboot_information_pointer->maybe_memory_map(); + auto memory_map = boot::bootstrap_information.mbi->maybe_memory_map(); if (!memory_map) { system::panic("[x86_64] Failed to create early allocator, no memory map available."); diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 6ecffa3..8b7f01b 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -1,38 +1,41 @@ #include "x86_64/vga/text.hpp" +#include "kapi/boot.hpp" + #include "x86_64/boot/boot.hpp" +#include "x86_64/boot/ld.hpp" #include "x86_64/vga/crtc.hpp" #include #include #include +#include #include #include namespace teachos::vga::x86_64::text { - using boot::x86_64::vga_buffer_pointer; - namespace { - // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) - auto constinit buffer_offset = std::ptrdiff_t{}; - + constexpr auto BUFFER_BASE_ADDRESS = std::uintptr_t{0xb8000}; constexpr auto DEFAULT_TEXT_BUFFER_WIDTH = 80U; constexpr auto DEFAULT_TEXT_BUFFER_HEIGHT = 25U; constexpr auto CURSOR_ENABLED_BIT = 5U; - - auto write_char(char code_point, attribute attribute) -> void - { - vga_buffer_pointer[buffer_offset++] = std::pair{code_point, std::bit_cast(attribute)}; - }; } // namespace + std::span const device::buffer = + std::span{std::bit_cast(BUFFER_BASE_ADDRESS + + std::bit_cast(&teachos::boot::x86_64::TEACHOS_VMA)), + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT}; + + device::device() + : m_position{boot::bootstrap_information.vga_buffer_index} + {} + auto device::clear(attribute attribute) -> void { - buffer_offset = 0; - std::ranges::fill_n(vga_buffer_pointer.get(), DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT, - std::pair{' ', std::bit_cast(attribute)}); + m_position = 0; + std::ranges::fill(buffer, std::pair{' ', std::bit_cast(attribute)}); } auto device::cursor(bool enabled) -> void @@ -45,30 +48,35 @@ namespace teachos::vga::x86_64::text auto device::newline() -> void { - auto current_line = buffer_offset / DEFAULT_TEXT_BUFFER_WIDTH; + auto current_line = m_position / DEFAULT_TEXT_BUFFER_WIDTH; auto next_line = current_line + 1; if (std::cmp_greater_equal(next_line, DEFAULT_TEXT_BUFFER_HEIGHT)) { - auto begin = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH; - auto end = vga_buffer_pointer + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT; - std::ranges::move(begin, end, vga_buffer_pointer.get()); - buffer_offset = current_line * DEFAULT_TEXT_BUFFER_WIDTH; + auto begin = buffer.begin() + DEFAULT_TEXT_BUFFER_WIDTH; + auto end = buffer.begin() + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT; + std::ranges::move(begin, end, buffer.begin()); + m_position = current_line * DEFAULT_TEXT_BUFFER_WIDTH; } else { - buffer_offset = next_line * DEFAULT_TEXT_BUFFER_WIDTH; + m_position = next_line * DEFAULT_TEXT_BUFFER_WIDTH; } } auto device::write(std::string_view code_points, attribute attribute) -> void { - std::ranges::for_each(code_points, [&](auto code_point) -> void { write_char(code_point, attribute); }); + std::ranges::for_each(code_points, [&](auto code_point) -> void { write(code_point, attribute); }); } + auto device::write(char code_point, attribute attribute) -> void + { + buffer[m_position++] = std::pair{code_point, std::bit_cast(attribute)}; + }; + auto device::writeln(std::string_view code_points, attribute attribute) -> void { - std::ranges::for_each(code_points, [&](auto code_point) -> void { write_char(code_point, attribute); }); + std::ranges::for_each(code_points, [&](auto code_point) -> void { write(code_point, attribute); }); newline(); } -- cgit v1.2.3 From 1db039ca1c67e8daba8b5ec6d5158cb2110e1410 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 28 Nov 2025 16:06:15 +0100 Subject: x86_64: port basic page and page table abstractions --- arch/x86_64/src/kapi/memory.cpp | 10 +++--- arch/x86_64/src/memory/page_table.cpp | 57 ++++++++++++++++++++++++++++++++++ arch/x86_64/src/memory/paging_root.cpp | 19 ++++++++++++ 3 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 arch/x86_64/src/memory/page_table.cpp create mode 100644 arch/x86_64/src/memory/paging_root.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 3848fb8..99dcb5c 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -12,6 +12,7 @@ #include #include +#include namespace teachos::memory { @@ -25,11 +26,12 @@ namespace teachos::memory auto create_memory_information() -> x86_64::region_allocator::memory_information { auto const & mbi = boot::bootstrap_information.mbi; + auto mbi_span = std::span{std::bit_cast(mbi), mbi->size_bytes()}; + auto image_span = std::span{&boot::x86_64::_start_physical, &boot::x86_64::_end_physical}; - return {.image_range = std::make_pair(physical_address{&boot::x86_64::_start_physical}, - physical_address{&boot::x86_64::_end_physical}), - .mbi_range = std::make_pair(physical_address{std::bit_cast(mbi)}, - physical_address{std::bit_cast(mbi) + mbi->size_bytes()}), + return {.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 = mbi->memory_map()}; }; diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp new file mode 100644 index 0000000..c716c5c --- /dev/null +++ b/arch/x86_64/src/memory/page_table.cpp @@ -0,0 +1,57 @@ +#include "x86_64/memory/page_table.hpp" + +#include + +namespace teachos::memory::x86_64 +{ + + auto page_table::entry::clear() -> void + { + m_raw = 0; + } + + auto page_table::entry::present() const -> bool + { + return (flags() & flags::present) != flags::empty; + } + + auto page_table::entry::huge() const -> bool + { + return (flags() & flags::huge_page) != flags::empty; + } + + auto page_table::entry::all_flags() const -> flags + { + return std::bit_cast(m_raw & ~frame_number_mask); + } + + auto page_table::entry::frame() const -> std::optional + { + if (present()) + { + return frame::containing(physical_address{m_raw & frame_number_mask}); + } + return std::nullopt; + } + + auto page_table::entry::frame(struct frame frame, flags flags) -> 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() -> void + { + std::ranges::for_each(m_entries, &page_table::entry::clear); + } + +} // namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp new file mode 100644 index 0000000..1234308 --- /dev/null +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -0,0 +1,19 @@ +#include "x86_64/memory/paging_root.hpp" + +#include + +namespace teachos::memory::x86_64 +{ + + namespace + { + constexpr auto PML_RECURSIVE_BASE = std::uintptr_t{0177777'776'776'776'776'0000uz}; + } + + auto paging_root::get() -> paging_root & + { + auto pml4_address = std::bit_cast(PML_RECURSIVE_BASE); + return *pml4_address; + } + +} // namespace teachos::memory::x86_64 \ No newline at end of file -- cgit v1.2.3 From 57d140f41b462483b8f32a883cbb0b599b9feaed Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 30 Nov 2025 16:59:17 +0100 Subject: x86_64/memory: fix entry checks --- arch/x86_64/src/memory/page_table.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index c716c5c..1273676 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -12,12 +12,12 @@ namespace teachos::memory::x86_64 auto page_table::entry::present() const -> bool { - return (flags() & flags::present) != flags::empty; + return (all_flags() & flags::present) != flags::empty; } auto page_table::entry::huge() const -> bool { - return (flags() & flags::huge_page) != flags::empty; + return (all_flags() & flags::huge_page) != flags::empty; } auto page_table::entry::all_flags() const -> flags -- cgit v1.2.3 From 27eddc3fa8d4c6001f223670d6001554fc47b657 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 1 Dec 2025 15:56:58 +0100 Subject: x86_64/memory: implement PML4 injection --- arch/x86_64/src/kapi/memory.cpp | 74 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 99dcb5c..f34729a 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -1,28 +1,34 @@ #include "kapi/memory.hpp" -#include "kapi/memory/frame.hpp" -#include "kapi/memory/frame_allocator.hpp" +#include "kapi/cio.hpp" #include "kapi/system.hpp" #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" #include "x86_64/cpu/registers.hpp" +#include "x86_64/memory/mmu.hpp" +#include "x86_64/memory/page_table.hpp" +#include "x86_64/memory/paging_root.hpp" #include "x86_64/memory/region_allocator.hpp" #include #include +#include #include namespace teachos::memory { std::size_t const PLATFORM_FRAME_SIZE{4096}; + std::size_t const PLATFORM_PAGE_SIZE{PLATFORM_FRAME_SIZE}; namespace { // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit allocator = static_cast(nullptr); + constexpr auto static unused_page_address = 0x0000'7fff'cafe'faceuz; + auto create_memory_information() -> x86_64::region_allocator::memory_information { auto const & mbi = boot::bootstrap_information.mbi; @@ -51,6 +57,67 @@ namespace teachos::memory cpu::x86_64::cr0::set(cpu::x86_64::cr0::flags::write_protect); cpu::x86_64::i32_efer::set(cpu::x86_64::i32_efer::flags::execute_disable_bit_enable); } + + auto inject_faux_pml4(frame_allocator & allocator) -> void + { + using entry_flags = x86_64::page_table::entry::flags; + using page_table = x86_64::page_table; + + auto temporary_page = page::containing(linear_address{unused_page_address}); + auto temporary_page_address = temporary_page.start_address(); + + auto & pml4 = x86_64::paging_root::get(); + + // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers) + auto faux_pml4_frame = + allocator.allocate() + .and_then([&](auto frame) -> auto { + auto index = temporary_page_address >> 39 & 0x1ffu; + pml4[index].frame(frame, entry_flags::present | entry_flags::writable); + return pml4.next(index); + }) + .and_then([&](auto pml) -> auto { + std::construct_at(pml); + auto index = temporary_page_address >> 30 & 0x1ffu; + (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); + return pml->next(index); + }) + .and_then([&](auto pml) -> auto { + std::construct_at(pml); + auto index = temporary_page_address >> 21 & 0x1ffu; + (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); + return pml->next(index); + }) + .transform([&](auto pml) -> auto { + std::construct_at(pml); + auto index = temporary_page_address >> 12 & 0x1ffu; + (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); + return pml; + }) + .and_then([&](auto pml) -> auto { + auto faux_pml4_pointer = std::bit_cast(temporary_page_address.raw()); + auto faux_pml4 = std::construct_at(faux_pml4_pointer); + + auto index = temporary_page_address >> 12 & 0x1ffu; + auto frame = (*pml)[index].frame(); + + (*faux_pml4)[510].frame(*frame, entry_flags::present | entry_flags::writable); + return frame; + }); + // NOLINTEND(cppcoreguidelines-avoid-magic-numbers) + + if (!faux_pml4_frame) + { + system::panic("[MEM] Failed to map and construct faux PML4"); + } + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) + pml4[510].frame(*faux_pml4_frame, entry_flags::present | entry_flags::writable); + x86_64::tlb_flush_all(); + + cio::println("[MEM] Injected faux PML4 as recursive map."); + } + } // namespace auto active_allocator() -> frame_allocator & @@ -71,8 +138,9 @@ namespace teachos::memory system::panic("[x86_64] Memory management has already been initialized."); } - [[maybe_unused]] auto allocator = create_early_frame_allocator(); + auto allocator = create_early_frame_allocator(); enable_cpu_protections(); + inject_faux_pml4(allocator); // paging::kernel_mapper kernel(allocator, memory_information); // kernel.remap_kernel(); -- cgit v1.2.3 From 203355e51690073e571d4906d53f2494c3dad41b Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 1 Dec 2025 19:32:19 +0100 Subject: x86_64/memory: prepare scoped_mapping extraction --- arch/x86_64/src/kapi/memory.cpp | 12 +++++ arch/x86_64/src/memory/scoped_mapping.cpp | 73 +++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 arch/x86_64/src/memory/scoped_mapping.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index f34729a..920c82b 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -10,6 +10,7 @@ #include "x86_64/memory/page_table.hpp" #include "x86_64/memory/paging_root.hpp" #include "x86_64/memory/region_allocator.hpp" +#include "x86_64/memory/scoped_mapping.hpp" #include @@ -140,8 +141,19 @@ namespace teachos::memory auto allocator = create_early_frame_allocator(); enable_cpu_protections(); + + // TODO: remove inject_faux_pml4(allocator); + // TODO: implement + auto temporary_mapper = x86_64::scoped_mapping{linear_address{unused_page_address}, allocator}; + auto new_pml4_frame = allocator.allocate(); + + auto new_plm4 = temporary_mapper.map_as( + *new_pml4_frame, x86_64::page_table::entry::flags::present | x86_64::page_table::entry::flags::writable); + (*new_plm4)[510].frame(new_pml4_frame.value(), + x86_64::page_table::entry::flags::present | x86_64::page_table::entry::flags::writable); + // paging::kernel_mapper kernel(allocator, memory_information); // kernel.remap_kernel(); // video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp new file mode 100644 index 0000000..c436ee5 --- /dev/null +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -0,0 +1,73 @@ +#include "x86_64/memory/scoped_mapping.hpp" + +#include "kapi/memory.hpp" +#include "kapi/system.hpp" + +#include "x86_64/memory/mmu.hpp" + +#include + +namespace teachos::memory::x86_64 +{ + + scoped_mapping::scoped_mapping(scoped_mapping && other) + : m_address{std::exchange(other.m_address, linear_address{})} + , m_allocator{std::exchange(other.m_allocator, nullptr)} + , m_mapped{std::exchange(other.m_mapped, false)} + {} + + scoped_mapping::scoped_mapping(linear_address address, frame_allocator & allocator) + : m_address{address} + , m_allocator{&allocator} + , m_mapped{false} + {} + + scoped_mapping::~scoped_mapping() + { + if (m_mapped) + { + unmap(); + x86_64::tlb_flush(m_address); + } + } + + auto scoped_mapping::operator=(scoped_mapping && other) -> scoped_mapping & + { + if (&other == this) + { + return *this; + } + + using std::swap; + + swap(m_address, other.m_address); + swap(m_allocator, other.m_allocator); + swap(m_mapped, other.m_mapped); + + return *this; + } + + auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * + { + static_cast(frame); + static_cast(flags); + + m_mapped = true; + + return nullptr; + } + + auto scoped_mapping::unmap() -> void + { + if (!m_mapped) + { + system::panic("[MEM] Tried to release an unmapped temporary mapping!"); + } + + // TODO: scan pages + // TODO: remove mapping + // TODO: release temporary table frames + m_mapped = false; + } + +} // namespace teachos::memory::x86_64 \ No newline at end of file -- cgit v1.2.3 From be86be1facfce8fe3f376153b9c582f2c5c026aa Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 12:31:53 +0100 Subject: x86_64/memory: extend scoped_mapping --- arch/x86_64/src/memory/paging_root.cpp | 41 +++++++++++++++++++++++++++++++ arch/x86_64/src/memory/scoped_mapping.cpp | 8 +++++- 2 files changed, 48 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 1234308..6b65f60 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -1,6 +1,11 @@ #include "x86_64/memory/paging_root.hpp" +#include "kapi/memory.hpp" + +#include "x86_64/memory/page_utilities.hpp" + #include +#include namespace teachos::memory::x86_64 { @@ -16,4 +21,40 @@ namespace teachos::memory::x86_64 return *pml4_address; } + auto paging_root::translate(linear_address address) const -> std::optional + { + auto offset = address.raw() % PLATFORM_PAGE_SIZE; + return translate(page::containing(address)).transform([offset](auto frame) -> auto { + return physical_address{frame.start_address().raw() + offset}; + }); + } + + auto paging_root::translate(page page) const -> std::optional + { + auto pml3 = next(pml_index<4>(page)); + + if (!pml3) + { + return std::nullopt; + } + + auto handle_huge_page = [&] -> std::optional { + auto pml3_entry = pml3.transform([&](auto pml3) -> auto { return (*pml3)[pml_index<3>(page)]; }); + if (pml3_entry && pml3_entry->huge()) + { + auto pml3_entry_frame = *pml3_entry->frame(); + return frame{pml3_entry_frame.number() + pml_index<2>(page) * entry_count + pml_index<1>(page)}; + } + + // auto pml3_entry = (**pml3)[page.start_address().raw() >> 39 & 0x1ff]; + + return std::nullopt; + }; + + return pml3.and_then([&](auto pml3) -> auto { return pml3->next(pml_index<3>(page)); }) + .and_then([&](auto pml2) -> auto { return pml2->next(pml_index<2>(page)); }) + .and_then([&](auto pml1) -> auto { return (*pml1)[pml_index<1>(page)].frame(); }) + .or_else(handle_huge_page); + } + } // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index c436ee5..27c4785 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -4,6 +4,7 @@ #include "kapi/system.hpp" #include "x86_64/memory/mmu.hpp" +#include "x86_64/memory/paging_root.hpp" #include @@ -20,7 +21,12 @@ namespace teachos::memory::x86_64 : m_address{address} , m_allocator{&allocator} , m_mapped{false} - {} + { + if (paging_root::get().translate(address)) + { + system::panic("[MEM] Tried to map a page that is already mapped!"); + } + } scoped_mapping::~scoped_mapping() { -- cgit v1.2.3 From a96b1b4b43a1ed962b412c3d28db0fe00661d96f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 18:40:10 +0100 Subject: x86_64/memory: extract PML4 injection --- arch/x86_64/src/kapi/memory.cpp | 79 +++++-------------------------- arch/x86_64/src/memory/page_table.cpp | 6 +++ arch/x86_64/src/memory/paging_root.cpp | 18 ++++++- arch/x86_64/src/memory/scoped_mapping.cpp | 77 +++++++++++++++++++++++++----- 4 files changed, 98 insertions(+), 82 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 920c82b..36b1706 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -1,6 +1,5 @@ #include "kapi/memory.hpp" -#include "kapi/cio.hpp" #include "kapi/system.hpp" #include "x86_64/boot/boot.hpp" @@ -28,7 +27,8 @@ namespace teachos::memory // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit allocator = static_cast(nullptr); - constexpr auto static unused_page_address = 0x0000'7fff'cafe'faceuz; + constexpr auto static unused_page_address = linear_address{0x0000'7fff'cafe'faceuz}; + constexpr auto static recursive_page_map_index = 510; auto create_memory_information() -> x86_64::region_allocator::memory_information { @@ -61,62 +61,18 @@ namespace teachos::memory auto inject_faux_pml4(frame_allocator & allocator) -> void { - using entry_flags = x86_64::page_table::entry::flags; - using page_table = x86_64::page_table; - - auto temporary_page = page::containing(linear_address{unused_page_address}); - auto temporary_page_address = temporary_page.start_address(); - - auto & pml4 = x86_64::paging_root::get(); - - // NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers) - auto faux_pml4_frame = - allocator.allocate() - .and_then([&](auto frame) -> auto { - auto index = temporary_page_address >> 39 & 0x1ffu; - pml4[index].frame(frame, entry_flags::present | entry_flags::writable); - return pml4.next(index); - }) - .and_then([&](auto pml) -> auto { - std::construct_at(pml); - auto index = temporary_page_address >> 30 & 0x1ffu; - (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); - return pml->next(index); - }) - .and_then([&](auto pml) -> auto { - std::construct_at(pml); - auto index = temporary_page_address >> 21 & 0x1ffu; - (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); - return pml->next(index); - }) - .transform([&](auto pml) -> auto { - std::construct_at(pml); - auto index = temporary_page_address >> 12 & 0x1ffu; - (*pml)[index].frame(*allocator.allocate(), entry_flags::present | entry_flags::writable); - return pml; - }) - .and_then([&](auto pml) -> auto { - auto faux_pml4_pointer = std::bit_cast(temporary_page_address.raw()); - auto faux_pml4 = std::construct_at(faux_pml4_pointer); - - auto index = temporary_page_address >> 12 & 0x1ffu; - auto frame = (*pml)[index].frame(); - - (*faux_pml4)[510].frame(*frame, entry_flags::present | entry_flags::writable); - return frame; - }); - // NOLINTEND(cppcoreguidelines-avoid-magic-numbers) - - if (!faux_pml4_frame) - { - system::panic("[MEM] Failed to map and construct faux PML4"); - } + using namespace x86_64; + using entry_flags = page_table::entry::flags; + + auto temporary_mapper = scoped_mapping{page::containing(unused_page_address), allocator}; + auto new_pml4_frame = allocator.allocate(); - // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) - pml4[510].frame(*faux_pml4_frame, entry_flags::present | entry_flags::writable); - x86_64::tlb_flush_all(); + auto pml4 = std::construct_at(temporary_mapper.map_as(*new_pml4_frame, entry_flags::writable)); + (*pml4)[recursive_page_map_index].frame(new_pml4_frame.value(), entry_flags::present | entry_flags::writable); + paging_root::get()[recursive_page_map_index].frame(new_pml4_frame.value(), + entry_flags::present | entry_flags::writable); - cio::println("[MEM] Injected faux PML4 as recursive map."); + tlb_flush_all(); } } // namespace @@ -141,19 +97,8 @@ namespace teachos::memory auto allocator = create_early_frame_allocator(); enable_cpu_protections(); - - // TODO: remove inject_faux_pml4(allocator); - // TODO: implement - auto temporary_mapper = x86_64::scoped_mapping{linear_address{unused_page_address}, allocator}; - auto new_pml4_frame = allocator.allocate(); - - auto new_plm4 = temporary_mapper.map_as( - *new_pml4_frame, x86_64::page_table::entry::flags::present | x86_64::page_table::entry::flags::writable); - (*new_plm4)[510].frame(new_pml4_frame.value(), - x86_64::page_table::entry::flags::present | x86_64::page_table::entry::flags::writable); - // paging::kernel_mapper kernel(allocator, memory_information); // kernel.remap_kernel(); // video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index 1273676..60bf94d 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -54,4 +54,10 @@ namespace teachos::memory::x86_64 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 teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 6b65f60..a29304e 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -40,13 +40,27 @@ namespace teachos::memory::x86_64 auto handle_huge_page = [&] -> std::optional { auto pml3_entry = pml3.transform([&](auto pml3) -> auto { return (*pml3)[pml_index<3>(page)]; }); - if (pml3_entry && pml3_entry->huge()) + if (!pml3_entry) + { + return std::nullopt; + } + else if (pml3_entry->huge()) { auto pml3_entry_frame = *pml3_entry->frame(); return frame{pml3_entry_frame.number() + pml_index<2>(page) * entry_count + pml_index<1>(page)}; } - // auto pml3_entry = (**pml3)[page.start_address().raw() >> 39 & 0x1ff]; + auto pml2 = (*pml3)->next(pml_index<3>(page)); + auto pml2_entry = pml2.transform([&](auto pml2) -> auto { return (*pml2)[pml_index<2>(page)]; }); + if (!pml2_entry) + { + return std::nullopt; + } + else if (pml2_entry->huge()) + { + auto pml2_entry_frame = *pml2_entry->frame(); + return frame{pml2_entry_frame.number() + pml_index<1>(page)}; + } return std::nullopt; }; diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 27c4785..602198e 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -4,25 +4,28 @@ #include "kapi/system.hpp" #include "x86_64/memory/mmu.hpp" +#include "x86_64/memory/page_table.hpp" +#include "x86_64/memory/page_utilities.hpp" #include "x86_64/memory/paging_root.hpp" +#include #include namespace teachos::memory::x86_64 { scoped_mapping::scoped_mapping(scoped_mapping && other) - : m_address{std::exchange(other.m_address, linear_address{})} + : m_page{std::exchange(other.m_page, page{})} , m_allocator{std::exchange(other.m_allocator, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} {} - scoped_mapping::scoped_mapping(linear_address address, frame_allocator & allocator) - : m_address{address} + scoped_mapping::scoped_mapping(page page, frame_allocator & allocator) + : m_page{page} , m_allocator{&allocator} , m_mapped{false} { - if (paging_root::get().translate(address)) + if (paging_root::get().translate(page)) { system::panic("[MEM] Tried to map a page that is already mapped!"); } @@ -33,7 +36,7 @@ namespace teachos::memory::x86_64 if (m_mapped) { unmap(); - x86_64::tlb_flush(m_address); + x86_64::tlb_flush(m_page.start_address()); } } @@ -46,7 +49,7 @@ namespace teachos::memory::x86_64 using std::swap; - swap(m_address, other.m_address); + swap(m_page, other.m_page); swap(m_allocator, other.m_allocator); swap(m_mapped, other.m_mapped); @@ -55,12 +58,38 @@ namespace teachos::memory::x86_64 auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * { - static_cast(frame); - static_cast(flags); + auto & pml4 = paging_root::get(); + auto pml4_index = pml_index<4>(m_page); + if (!pml4[pml4_index].present()) + { + auto new_frame = m_allocator->allocate(); + pml4[pml4_index].frame(*new_frame, page_table::entry::flags::present | flags); + std::construct_at(pml4.next(pml4_index).value()); + } - m_mapped = true; + auto pml3 = pml4.next(pml4_index).value(); + auto pml3_index = pml_index<3>(m_page); + if (!(*pml3)[pml3_index].present()) + { + auto new_frame = m_allocator->allocate(); + (*pml3)[pml3_index].frame(*new_frame, page_table::entry::flags::present | flags); + std::construct_at((*pml3).next(pml3_index).value()); + } - return nullptr; + auto pml2 = (*pml3).next(pml3_index).value(); + auto pml2_index = pml_index<2>(m_page); + if (!(*pml2)[pml2_index].present()) + { + auto new_frame = m_allocator->allocate(); + (*pml2)[pml2_index].frame(*new_frame, page_table::entry::flags::present | flags); + std::construct_at((*pml2).next(pml2_index).value()); + } + + auto pml1 = (*pml2).next(pml2_index).value(); + auto pml1_index = pml_index<1>(m_page); + (*pml1)[pml1_index].frame(frame, page_table::entry::flags::present | flags); + + return static_cast(frame.start_address()); } auto scoped_mapping::unmap() -> void @@ -70,9 +99,31 @@ namespace teachos::memory::x86_64 system::panic("[MEM] Tried to release an unmapped temporary mapping!"); } - // TODO: scan pages - // TODO: remove mapping - // TODO: release temporary table frames + auto pml3 = paging_root::get().next(pml_index<4>(m_page)).value(); + auto pml2 = pml3->next(pml_index<3>(m_page)).value(); + auto pml1 = pml2->next(pml_index<2>(m_page)).value(); + + auto pml1_entry = (*pml1)[pml_index<1>(m_page)]; + (*pml1)[pml_index<1>(m_page)].clear(); + if (pml1->empty()) + { + m_allocator->release(pml1_entry.frame().value()); + } + + auto pml2_entry = (*pml2)[pml_index<2>(m_page)]; + (*pml2)[pml_index<2>(m_page)].clear(); + if (pml2->empty()) + { + m_allocator->release(pml2_entry.frame().value()); + } + + auto pml3_entry = (*pml3)[pml_index<3>(m_page)]; + (*pml3)[pml_index<3>(m_page)].clear(); + if (pml3->empty()) + { + m_allocator->release(pml3_entry.frame().value()); + } + m_mapped = false; } -- cgit v1.2.3 From 331c070547634a2096c5e2165559fb0f11ee6330 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 18:49:36 +0100 Subject: kapi: make PLATFORM_*_SIZE constexpr --- arch/x86_64/src/kapi/memory.cpp | 2 -- arch/x86_64/src/memory/paging_root.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 36b1706..1a8b36f 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -19,8 +19,6 @@ namespace teachos::memory { - std::size_t const PLATFORM_FRAME_SIZE{4096}; - std::size_t const PLATFORM_PAGE_SIZE{PLATFORM_FRAME_SIZE}; namespace { diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index a29304e..6b8e1ab 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -23,7 +23,7 @@ namespace teachos::memory::x86_64 auto paging_root::translate(linear_address address) const -> std::optional { - auto offset = address.raw() % PLATFORM_PAGE_SIZE; + auto offset = address.raw() % page::size; return translate(page::containing(address)).transform([offset](auto frame) -> auto { return physical_address{frame.start_address().raw() + offset}; }); -- cgit v1.2.3 From 588fe1a3600475bdc312a4fe758d2f1125eb149c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 18:56:12 +0100 Subject: x86_64: basic code cleanup --- arch/x86_64/src/kapi/memory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 1a8b36f..e138641 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -26,7 +26,7 @@ namespace teachos::memory auto constinit allocator = static_cast(nullptr); constexpr auto static unused_page_address = linear_address{0x0000'7fff'cafe'faceuz}; - constexpr auto static recursive_page_map_index = 510; + constexpr auto static recursive_page_map_index = x86_64::page_table::entry_count - 2; auto create_memory_information() -> x86_64::region_allocator::memory_information { -- cgit v1.2.3 From 148c54a3d470c6019ebebe1387a7d889a2b8808e Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 19:17:42 +0100 Subject: x86_64/memory: introduce frame allocation buffer --- arch/x86_64/src/kapi/memory.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index e138641..703b3e1 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -5,6 +5,7 @@ #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" #include "x86_64/cpu/registers.hpp" +#include "x86_64/memory/buffered_allocator.hpp" #include "x86_64/memory/mmu.hpp" #include "x86_64/memory/page_table.hpp" #include "x86_64/memory/paging_root.hpp" @@ -95,7 +96,9 @@ namespace teachos::memory auto allocator = create_early_frame_allocator(); enable_cpu_protections(); - inject_faux_pml4(allocator); + + auto allocation_buffer = x86_64::buffered_allocator<4>{&allocator}; + inject_faux_pml4(allocation_buffer); // paging::kernel_mapper kernel(allocator, memory_information); // kernel.remap_kernel(); -- cgit v1.2.3 From 9331afdcbbe95bc1bd79d657f0d7c5b91a19a375 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 2 Dec 2025 19:39:03 +0100 Subject: x86_64/memory: fix temporary page unmapping --- arch/x86_64/src/kapi/memory.cpp | 34 ++++++++++++++++++++++++++++++- arch/x86_64/src/memory/scoped_mapping.cpp | 2 ++ 2 files changed, 35 insertions(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 703b3e1..0e4b78e 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -8,6 +8,7 @@ #include "x86_64/memory/buffered_allocator.hpp" #include "x86_64/memory/mmu.hpp" #include "x86_64/memory/page_table.hpp" +#include "x86_64/memory/page_utilities.hpp" #include "x86_64/memory/paging_root.hpp" #include "x86_64/memory/region_allocator.hpp" #include "x86_64/memory/scoped_mapping.hpp" @@ -63,15 +64,46 @@ namespace teachos::memory using namespace x86_64; using entry_flags = page_table::entry::flags; - auto temporary_mapper = scoped_mapping{page::containing(unused_page_address), allocator}; + auto page = page::containing(unused_page_address); + + auto temporary_mapper = scoped_mapping{page, allocator}; auto new_pml4_frame = allocator.allocate(); auto pml4 = std::construct_at(temporary_mapper.map_as(*new_pml4_frame, entry_flags::writable)); (*pml4)[recursive_page_map_index].frame(new_pml4_frame.value(), entry_flags::present | entry_flags::writable); + + auto pml4_index = pml_index<4>(page); + auto & old_pml4 = paging_root::get(); + auto pml4_entry = old_pml4[pml4_index]; + + auto pml3_index = pml_index<3>(page); + auto old_pml3 = old_pml4.next(pml4_index); + auto pml3_entry = (**old_pml3)[pml3_index]; + + auto pml2_index = pml_index<2>(page); + auto old_pml2 = (**old_pml3).next(pml3_index); + auto pml2_entry = (**old_pml2)[pml2_index]; + + auto pml1_index = pml_index<1>(page); + auto old_pml1 = (**old_pml2).next(pml2_index); + auto pml1_entry = (**old_pml1)[pml1_index]; + paging_root::get()[recursive_page_map_index].frame(new_pml4_frame.value(), entry_flags::present | entry_flags::writable); tlb_flush_all(); + + auto & new_pml4 = paging_root::get(); + new_pml4[pml4_index] = pml4_entry; + + auto new_pml3 = new_pml4.next(pml4_index); + (**new_pml3)[pml3_index] = pml3_entry; + + auto new_pml2 = (**new_pml3).next(pml3_index); + (**new_pml2)[pml2_index] = pml2_entry; + + auto new_pml1 = (**new_pml2).next(pml2_index); + (**new_pml1)[pml1_index] = pml1_entry; } } // namespace diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 602198e..191a7ad 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -89,6 +89,8 @@ namespace teachos::memory::x86_64 auto pml1_index = pml_index<1>(m_page); (*pml1)[pml1_index].frame(frame, page_table::entry::flags::present | flags); + m_mapped = true; + return static_cast(frame.start_address()); } -- cgit v1.2.3 From a08847ded5fba25859e7a3ad06ae3fed342d4d6a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 14:02:07 +0100 Subject: x86_64/boot: move stack to higher half --- arch/x86_64/src/boot/boot32.S | 11 ++++------- arch/x86_64/src/boot/entry64.s | 9 +++++++++ 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/boot32.S b/arch/x86_64/src/boot/boot32.S index 27eed4d..79b3ec7 100644 --- a/arch/x86_64/src/boot/boot32.S +++ b/arch/x86_64/src/boot/boot32.S @@ -27,12 +27,9 @@ page_maps_size = page_maps_end - page_maps_start .section .boot_stack, "aw", @nobits .align 16 -.global stack_size -.global stack_bottom - -stack_bottom: .skip 1 << 20 -stack_top: -stack_size = stack_top - stack_bottom +early_stack_bottom: .skip 1 << 8 +early_stack_top: +early_stack_size = early_stack_top - early_stack_bottom /** * @brief Constants for the bootstrapping process. @@ -122,7 +119,7 @@ _start: 0: pop %esi - lea (stack_top - 0b)(%esi), %ecx + lea (early_stack_top - 0b)(%esi), %ecx mov %ecx, %esp mov %esp, %ebp diff --git a/arch/x86_64/src/boot/entry64.s b/arch/x86_64/src/boot/entry64.s index 636e4cd..2932354 100644 --- a/arch/x86_64/src/boot/entry64.s +++ b/arch/x86_64/src/boot/entry64.s @@ -11,6 +11,12 @@ .global bootstrap_information bootstrap_information: .skip 16 +.align 16 +.global stack_top +stack_bottom: .skip 1 << 20 +stack_top: +stack_size = stack_top - stack_bottom + .section .boot_text, "ax", @progbits .code64 @@ -23,6 +29,9 @@ _entry64: mov %rax, %fs mov %rax, %gs + mov $stack_top, %rsp + mov %rsp, %rbp + mov multiboot_information_pointer, %rax mov vga_buffer_pointer, %rdx sub $0xb8000, %rdx -- cgit v1.2.3 From 9907cb6c0108b89b846fee52de56a9c335caaedc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 17:08:44 +0100 Subject: x86_64/memory: fix return in scoped_mapping::map Previously, scoped_mapping::map returned the start address of the frame. Unfortunately, the initial mapping performed in the bootstrap code maps physical memory starting at 0x0000'0000'0000'0000, which means no fault was triggered. The map function now correctly return the start address of the scoped_mapping's page, which must alway work by definition. --- arch/x86_64/src/memory/scoped_mapping.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 191a7ad..5446b2a 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -91,7 +91,7 @@ namespace teachos::memory::x86_64 m_mapped = true; - return static_cast(frame.start_address()); + return static_cast(m_page.start_address()); } auto scoped_mapping::unmap() -> void -- cgit v1.2.3 From 448632c3c9c919e8eda44e8a83082f60983057b7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 20:16:36 +0100 Subject: x86_64/memory: add missing noexcept specifiers --- arch/x86_64/src/memory/scoped_mapping.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 5446b2a..6e2328d 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -14,7 +14,7 @@ namespace teachos::memory::x86_64 { - scoped_mapping::scoped_mapping(scoped_mapping && other) + scoped_mapping::scoped_mapping(scoped_mapping && other) noexcept : m_page{std::exchange(other.m_page, page{})} , m_allocator{std::exchange(other.m_allocator, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} @@ -40,7 +40,7 @@ namespace teachos::memory::x86_64 } } - auto scoped_mapping::operator=(scoped_mapping && other) -> scoped_mapping & + auto scoped_mapping::operator=(scoped_mapping && other) noexcept -> scoped_mapping & { if (&other == this) { -- cgit v1.2.3 From f3dd2b2f5bd1b5dd4d4309a30db3c7733b8f63bb Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 20:40:54 +0100 Subject: x86_64/memory: only deallocate allocated frames --- arch/x86_64/src/memory/scoped_mapping.cpp | 39 +++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 6e2328d..be15330 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -18,12 +18,14 @@ namespace teachos::memory::x86_64 : m_page{std::exchange(other.m_page, page{})} , m_allocator{std::exchange(other.m_allocator, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} + , m_allocated{std::exchange(other.m_allocated, 0)} {} scoped_mapping::scoped_mapping(page page, frame_allocator & allocator) : m_page{page} , m_allocator{&allocator} , m_mapped{false} + , m_allocated{} { if (paging_root::get().translate(page)) { @@ -52,6 +54,7 @@ namespace teachos::memory::x86_64 swap(m_page, other.m_page); swap(m_allocator, other.m_allocator); swap(m_mapped, other.m_mapped); + swap(m_allocated, other.m_allocated); return *this; } @@ -65,6 +68,7 @@ namespace teachos::memory::x86_64 auto new_frame = m_allocator->allocate(); pml4[pml4_index].frame(*new_frame, page_table::entry::flags::present | flags); std::construct_at(pml4.next(pml4_index).value()); + m_allocated |= 1uz << 2; } auto pml3 = pml4.next(pml4_index).value(); @@ -74,6 +78,7 @@ namespace teachos::memory::x86_64 auto new_frame = m_allocator->allocate(); (*pml3)[pml3_index].frame(*new_frame, page_table::entry::flags::present | flags); std::construct_at((*pml3).next(pml3_index).value()); + m_allocated |= 1uz << 1; } auto pml2 = (*pml3).next(pml3_index).value(); @@ -83,6 +88,7 @@ namespace teachos::memory::x86_64 auto new_frame = m_allocator->allocate(); (*pml2)[pml2_index].frame(*new_frame, page_table::entry::flags::present | flags); std::construct_at((*pml2).next(pml2_index).value()); + m_allocated |= 1uz << 0; } auto pml1 = (*pml2).next(pml2_index).value(); @@ -105,25 +111,34 @@ namespace teachos::memory::x86_64 auto pml2 = pml3->next(pml_index<3>(m_page)).value(); auto pml1 = pml2->next(pml_index<2>(m_page)).value(); - auto pml1_entry = (*pml1)[pml_index<1>(m_page)]; - (*pml1)[pml_index<1>(m_page)].clear(); - if (pml1->empty()) + if (m_allocated & 1uz << 0) { - m_allocator->release(pml1_entry.frame().value()); + auto pml1_entry = (*pml1)[pml_index<1>(m_page)]; + (*pml1)[pml_index<1>(m_page)].clear(); + if (pml1->empty()) + { + m_allocator->release(pml1_entry.frame().value()); + } } - auto pml2_entry = (*pml2)[pml_index<2>(m_page)]; - (*pml2)[pml_index<2>(m_page)].clear(); - if (pml2->empty()) + if (m_allocated & 1uz << 1) { - m_allocator->release(pml2_entry.frame().value()); + auto pml2_entry = (*pml2)[pml_index<2>(m_page)]; + (*pml2)[pml_index<2>(m_page)].clear(); + if (pml2->empty()) + { + m_allocator->release(pml2_entry.frame().value()); + } } - auto pml3_entry = (*pml3)[pml_index<3>(m_page)]; - (*pml3)[pml_index<3>(m_page)].clear(); - if (pml3->empty()) + if (m_allocated & 1uz << 2) { - m_allocator->release(pml3_entry.frame().value()); + auto pml3_entry = (*pml3)[pml_index<3>(m_page)]; + (*pml3)[pml_index<3>(m_page)].clear(); + if (pml3->empty()) + { + m_allocator->release(pml3_entry.frame().value()); + } } m_mapped = false; -- cgit v1.2.3 From fc26187d9ace9798d9494341f3513eb0840b006d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 3 Dec 2025 20:45:30 +0100 Subject: x86_64/memory: make scoped_mapping swappable --- arch/x86_64/src/memory/scoped_mapping.cpp | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index be15330..c9c6459 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -44,18 +44,7 @@ namespace teachos::memory::x86_64 auto scoped_mapping::operator=(scoped_mapping && other) noexcept -> scoped_mapping & { - if (&other == this) - { - return *this; - } - - using std::swap; - - swap(m_page, other.m_page); - swap(m_allocator, other.m_allocator); - swap(m_mapped, other.m_mapped); - swap(m_allocated, other.m_allocated); - + this->swap(other); return *this; } @@ -144,4 +133,22 @@ namespace teachos::memory::x86_64 m_mapped = false; } + auto scoped_mapping::swap(scoped_mapping & other) -> void + { + using std::swap; + + if (&other == this) + return; + + swap(m_page, other.m_page); + swap(m_allocator, other.m_allocator); + swap(m_mapped, other.m_mapped); + swap(m_allocated, other.m_allocated); + } + + auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void + { + lhs.swap(rhs); + } + } // namespace teachos::memory::x86_64 \ No newline at end of file -- cgit v1.2.3 From 36cd516c84cf2edd16defcd39e99e2bee0bca892 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 4 Dec 2025 22:52:35 +0100 Subject: x86_64/memory: simplify initialization implementation --- arch/x86_64/src/kapi/memory.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 0e4b78e..d09a4c1 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -30,18 +30,7 @@ namespace teachos::memory constexpr auto static unused_page_address = linear_address{0x0000'7fff'cafe'faceuz}; constexpr auto static recursive_page_map_index = x86_64::page_table::entry_count - 2; - auto create_memory_information() -> x86_64::region_allocator::memory_information - { - auto const & mbi = boot::bootstrap_information.mbi; - auto mbi_span = std::span{std::bit_cast(mbi), mbi->size_bytes()}; - auto image_span = std::span{&boot::x86_64::_start_physical, &boot::x86_64::_end_physical}; - - return {.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 = mbi->memory_map()}; - }; - + //! Instantiate a basic, memory region based, early frame allocator for remapping. auto create_early_frame_allocator() { auto memory_map = boot::bootstrap_information.mbi->maybe_memory_map(); @@ -50,15 +39,27 @@ namespace teachos::memory system::panic("[x86_64] Failed to create early allocator, no memory map available."); } - return x86_64::region_allocator{create_memory_information()}; + auto const & mbi = boot::bootstrap_information.mbi; + auto mbi_span = std::span{std::bit_cast(mbi), mbi->size_bytes()}; + auto image_span = std::span{&boot::x86_64::_start_physical, &boot::x86_64::_end_physical}; + + return x86_64::region_allocator{ + { + .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, + } + }; } + //! Enable additional CPU protection features, required during later stages of the kernel. auto enable_cpu_protections() -> void { cpu::x86_64::cr0::set(cpu::x86_64::cr0::flags::write_protect); cpu::x86_64::i32_efer::set(cpu::x86_64::i32_efer::flags::execute_disable_bit_enable); } + //! Inject, or graft, a faux recursive PML4 into the active page mapping structure. auto inject_faux_pml4(frame_allocator & allocator) -> void { using namespace x86_64; -- cgit v1.2.3 From 448a79328544e3ecb72d0b3b95c0b9b0d49faafc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 10 Dec 2025 12:27:37 +0100 Subject: x86_64/memory: fix scoped_mapping unmap logic --- arch/x86_64/src/memory/scoped_mapping.cpp | 32 +++++++++++++------------------ 1 file changed, 13 insertions(+), 19 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index c9c6459..44dbf45 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -96,38 +96,32 @@ namespace teachos::memory::x86_64 system::panic("[MEM] Tried to release an unmapped temporary mapping!"); } - auto pml3 = paging_root::get().next(pml_index<4>(m_page)).value(); + auto pml4 = &paging_root::get(); + auto pml3 = pml4->next(pml_index<4>(m_page)).value(); auto pml2 = pml3->next(pml_index<3>(m_page)).value(); auto pml1 = pml2->next(pml_index<2>(m_page)).value(); + (*pml1)[pml_index<1>(m_page)].clear(); + if (m_allocated & 1uz << 0) { - auto pml1_entry = (*pml1)[pml_index<1>(m_page)]; - (*pml1)[pml_index<1>(m_page)].clear(); - if (pml1->empty()) - { - m_allocator->release(pml1_entry.frame().value()); - } + auto pml1_frame = (*pml2)[pml_index<2>(m_page)].frame().value(); + m_allocator->release(pml1_frame); + (*pml2)[pml_index<2>(m_page)].clear(); } if (m_allocated & 1uz << 1) { - auto pml2_entry = (*pml2)[pml_index<2>(m_page)]; - (*pml2)[pml_index<2>(m_page)].clear(); - if (pml2->empty()) - { - m_allocator->release(pml2_entry.frame().value()); - } + auto pml2_frame = (*pml3)[pml_index<3>(m_page)].frame().value(); + m_allocator->release(pml2_frame); + (*pml3)[pml_index<3>(m_page)].clear(); } if (m_allocated & 1uz << 2) { - auto pml3_entry = (*pml3)[pml_index<3>(m_page)]; - (*pml3)[pml_index<3>(m_page)].clear(); - if (pml3->empty()) - { - m_allocator->release(pml3_entry.frame().value()); - } + auto pml3_frame = (*pml4)[pml_index<4>(m_page)].frame().value(); + m_allocator->release(pml3_frame); + (*pml4)[pml_index<4>(m_page)].clear(); } m_mapped = false; -- cgit v1.2.3 From b9d445bf92725d79269becf978059e040519c00a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 10 Dec 2025 16:51:44 +0100 Subject: x86_64/memory: implement simple kernel remapper --- arch/x86_64/src/kapi/memory.cpp | 20 ++++-- arch/x86_64/src/memory/kernel_mapper.cpp | 107 +++++++++++++++++++++++++++++++ arch/x86_64/src/memory/page_table.cpp | 13 ++++ arch/x86_64/src/memory/paging_root.cpp | 55 +++++++++++++++- 4 files changed, 188 insertions(+), 7 deletions(-) create mode 100644 arch/x86_64/src/memory/kernel_mapper.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index d09a4c1..ed3edef 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -1,11 +1,14 @@ #include "kapi/memory.hpp" +#include "kapi/cio.hpp" #include "kapi/system.hpp" #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" +#include "x86_64/cpu/impl/control_registers.hpp" #include "x86_64/cpu/registers.hpp" #include "x86_64/memory/buffered_allocator.hpp" +#include "x86_64/memory/kernel_mapper.hpp" #include "x86_64/memory/mmu.hpp" #include "x86_64/memory/page_table.hpp" #include "x86_64/memory/page_utilities.hpp" @@ -60,7 +63,7 @@ namespace teachos::memory } //! Inject, or graft, a faux recursive PML4 into the active page mapping structure. - auto inject_faux_pml4(frame_allocator & allocator) -> void + auto inject_faux_pml4(frame_allocator & allocator) { using namespace x86_64; using entry_flags = page_table::entry::flags; @@ -105,6 +108,8 @@ namespace teachos::memory auto new_pml1 = (**new_pml2).next(pml2_index); (**new_pml1)[pml1_index] = pml1_entry; + + return *new_pml4_frame; } } // namespace @@ -131,12 +136,15 @@ namespace teachos::memory enable_cpu_protections(); auto allocation_buffer = x86_64::buffered_allocator<4>{&allocator}; - inject_faux_pml4(allocation_buffer); + auto new_pml4_frame = inject_faux_pml4(allocation_buffer); - // paging::kernel_mapper kernel(allocator, memory_information); - // kernel.remap_kernel(); - // video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); - // video::vga::text::newline(); + auto mapper = x86_64::kernel_mapper{allocation_buffer, boot::bootstrap_information.mbi}; + mapper.remap_kernel(); + cio::println("[x86_64:MEM] prepared new kernel image page maps."); + + auto cr3 = cpu::x86_64::cr3::read(); + cr3.address(new_pml4_frame.start_address()); + cpu::x86_64::cr3::write(cr3); // remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); // video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp new file mode 100644 index 0000000..b1d12a4 --- /dev/null +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -0,0 +1,107 @@ +#include "x86_64/memory/kernel_mapper.hpp" + +#include "kapi/cio.hpp" +#include "kapi/memory.hpp" +#include "kapi/system.hpp" + +#include "x86_64/boot/ld.hpp" +#include "x86_64/memory/page_table.hpp" +#include "x86_64/memory/paging_root.hpp" + +#include +#include + +#include +#include + +namespace teachos::memory::x86_64 +{ + + inline namespace + { + using namespace std::string_view_literals; + + 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(frame_allocator & allocator, multiboot2::information_view const * mbi) + : m_allocator{&allocator} + , m_mbi(std::move(mbi)) + , m_kernel_load_base{std::bit_cast(&boot::x86_64::TEACHOS_VMA)} + {} + + auto kernel_mapper::remap_kernel() -> void + { + auto elf_information = m_mbi->maybe_elf_symbols(); + if (!elf_information) + { + 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()) + { + 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)); }); + } + + auto kernel_mapper::map_section(section_header_type const & section, std::string_view name) -> void + { + cio::print("[x86_64:MEM] mapping "); + cio::println(name); + + auto number_of_pages = (section.size + (PLATFORM_PAGE_SIZE - 1)) / PLATFORM_PAGE_SIZE; + + auto linear_start_address = linear_address{section.virtual_load_address}; + auto physical_start_address = physical_address{section.virtual_load_address & ~m_kernel_load_base}; + + auto first_page = page::containing(linear_start_address); + auto first_frame = frame::containing(physical_start_address); + + auto page_flags = page_table::entry::flags::empty; + + if (section.writable()) + { + page_flags |= page_table::entry::flags::writable; + } + + if (!section.executable()) + { + page_flags |= page_table::entry::flags::no_execute; + } + + 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 |= page_table::entry::flags::user_accessible; + } + + for (auto i = 0uz; i < number_of_pages; ++i) + { + paging_root::get().map(page{first_page.number() + i}, frame{first_frame.number() + i}, page_flags, *m_allocator); + } + } + +} // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index 60bf94d..e797b22 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -1,6 +1,7 @@ #include "x86_64/memory/page_table.hpp" #include +#include namespace teachos::memory::x86_64 { @@ -25,6 +26,18 @@ namespace teachos::memory::x86_64 return std::bit_cast(m_raw & ~frame_number_mask); } + auto page_table::entry::all_flags(flags flags) -> void + { + m_raw = (m_raw & ~frame_number_mask) | std::to_underlying(flags); + } + + auto page_table::entry::operator|=(flags rhs) -> 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 -> std::optional { if (present()) diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 6b8e1ab..5ca2bf0 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -1,10 +1,15 @@ #include "x86_64/memory/paging_root.hpp" #include "kapi/memory.hpp" +#include "kapi/system.hpp" +#include "x86_64/memory/page_table.hpp" #include "x86_64/memory/page_utilities.hpp" +#include "x86_64/memory/scoped_mapping.hpp" +#include #include +#include #include namespace teachos::memory::x86_64 @@ -13,7 +18,45 @@ namespace teachos::memory::x86_64 namespace { constexpr auto PML_RECURSIVE_BASE = std::uintptr_t{0177777'776'776'776'776'0000uz}; - } + + //! Perform the actual mapping of the page, via the recursive page map. + //! + //! On any level above PML1, the entries need to not be no_execute, because the image is densely packed. The entries + //! also need to be writable, since the mapping is being performed through the recursive page map hierarchy. When + //! setting the final entry in the PML1, the actually desired flags are set as is, with the present bit added, thus + //! still enforcing non-writability and non-execution of the affected page. + template + requires(Level > 1uz && Level < 5uz) + auto do_map(recursive_page_table * pml, page page, page_table::entry::flags flags, + frame_allocator & allocator) + { + auto index = pml_index(page); + flags = flags & ~page_table::entry::flags::no_execute; + flags = flags | page_table::entry::flags::writable; + if (!(*pml)[index].present()) + { + auto new_table_frame = allocator.allocate(); + auto mapping = scoped_mapping{page, allocator}; + (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | flags); + auto new_table = std::optional{std::construct_at(*pml->next(index))}; + return new_table; + } + (*pml)[index] |= flags; + return pml->next(index); + } + + //! Perform the actual PML1 update. + auto do_map(page_table * pml, page page, frame frame, page_table::entry::flags flags) -> std::optional + { + auto index = pml_index<1>(page); + if ((*pml)[index].present()) + { + system::panic("[x86_64:MEM] Tried to map a page that is already mapped"); + } + (*pml)[index].frame(frame, page_table::entry::flags::present | flags); + return std::optional{static_cast(page.start_address())}; + } + } // namespace auto paging_root::get() -> paging_root & { @@ -71,4 +114,14 @@ namespace teachos::memory::x86_64 .or_else(handle_huge_page); } + auto paging_root::map(page page, frame frame, page_table::entry::flags flags, frame_allocator & allocator) + -> std::optional + { + return std::optional{this} + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, frame, flags); }); + } + } // namespace teachos::memory::x86_64 \ No newline at end of file -- cgit v1.2.3 From eafbf588760c289b7f54a4771b39af0ccfe8cf59 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 10 Dec 2025 21:55:42 +0100 Subject: kapi: extract page_mapper interface --- arch/x86_64/src/kapi/memory.cpp | 29 +++++-- arch/x86_64/src/memory/kernel_mapper.cpp | 7 +- arch/x86_64/src/memory/paging_root.cpp | 52 ++++++++++--- arch/x86_64/src/memory/recursive_page_mapper.cpp | 38 +++++++++ arch/x86_64/src/memory/scoped_mapping.cpp | 99 ++---------------------- 5 files changed, 116 insertions(+), 109 deletions(-) create mode 100644 arch/x86_64/src/memory/recursive_page_mapper.cpp (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index ed3edef..00b9de3 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -13,6 +13,7 @@ #include "x86_64/memory/page_table.hpp" #include "x86_64/memory/page_utilities.hpp" #include "x86_64/memory/paging_root.hpp" +#include "x86_64/memory/recursive_page_mapper.hpp" #include "x86_64/memory/region_allocator.hpp" #include "x86_64/memory/scoped_mapping.hpp" @@ -29,6 +30,8 @@ namespace teachos::memory { // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) auto constinit allocator = static_cast(nullptr); + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) + auto constinit mapper = static_cast(nullptr); constexpr auto static unused_page_address = linear_address{0x0000'7fff'cafe'faceuz}; constexpr auto static recursive_page_map_index = x86_64::page_table::entry_count - 2; @@ -70,7 +73,7 @@ namespace teachos::memory auto page = page::containing(unused_page_address); - auto temporary_mapper = scoped_mapping{page, allocator}; + auto temporary_mapper = scoped_mapping{page}; auto new_pml4_frame = allocator.allocate(); auto pml4 = std::construct_at(temporary_mapper.map_as(*new_pml4_frame, entry_flags::writable)); @@ -124,6 +127,15 @@ namespace teachos::memory return *allocator; } + auto active_mapper() -> page_mapper & + { + if (!mapper) + { + system::panic("[x86_64] The page mapper has not been set you."); + } + return *mapper; + } + auto init() -> void { auto static constinit is_initialized = std::atomic_flag{}; @@ -132,14 +144,19 @@ namespace teachos::memory system::panic("[x86_64] Memory management has already been initialized."); } - auto allocator = create_early_frame_allocator(); enable_cpu_protections(); - auto allocation_buffer = x86_64::buffered_allocator<4>{&allocator}; + auto early_allocator = create_early_frame_allocator(); + auto allocation_buffer = x86_64::buffered_allocator<4>{&early_allocator}; + allocator = &allocation_buffer; + + auto recursive_mapper = x86_64::recursive_page_mapper{allocation_buffer}; + mapper = &recursive_mapper; + auto new_pml4_frame = inject_faux_pml4(allocation_buffer); - auto mapper = x86_64::kernel_mapper{allocation_buffer, boot::bootstrap_information.mbi}; - mapper.remap_kernel(); + auto kernel_mapper = x86_64::kernel_mapper{boot::bootstrap_information.mbi}; + kernel_mapper.remap_kernel(); cio::println("[x86_64:MEM] prepared new kernel image page maps."); auto cr3 = cpu::x86_64::cr3::read(); @@ -149,6 +166,8 @@ namespace teachos::memory // remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); // video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); // video::vga::text::newline(); + mapper = nullptr; + allocator = nullptr; } } // namespace teachos::memory diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp index b1d12a4..f46b5b5 100644 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -32,9 +32,8 @@ namespace teachos::memory::x86_64 } // namespace - kernel_mapper::kernel_mapper(frame_allocator & allocator, multiboot2::information_view const * mbi) - : m_allocator{&allocator} - , m_mbi(std::move(mbi)) + kernel_mapper::kernel_mapper(multiboot2::information_view const * mbi) + : m_mbi{std::move(mbi)} , m_kernel_load_base{std::bit_cast(&boot::x86_64::TEACHOS_VMA)} {} @@ -100,7 +99,7 @@ namespace teachos::memory::x86_64 for (auto i = 0uz; i < number_of_pages; ++i) { - paging_root::get().map(page{first_page.number() + i}, frame{first_frame.number() + i}, page_flags, *m_allocator); + paging_root::get().map(page{first_page.number() + i}, frame{first_frame.number() + i}, page_flags); } } diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 5ca2bf0..c458093 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -27,16 +27,15 @@ namespace teachos::memory::x86_64 //! still enforcing non-writability and non-execution of the affected page. template requires(Level > 1uz && Level < 5uz) - auto do_map(recursive_page_table * pml, page page, page_table::entry::flags flags, - frame_allocator & allocator) + auto do_map(recursive_page_table * pml, page page, page_table::entry::flags flags) { auto index = pml_index(page); flags = flags & ~page_table::entry::flags::no_execute; flags = flags | page_table::entry::flags::writable; if (!(*pml)[index].present()) { - auto new_table_frame = allocator.allocate(); - auto mapping = scoped_mapping{page, allocator}; + auto new_table_frame = active_allocator().allocate(); + auto mapping = scoped_mapping{page}; (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | flags); auto new_table = std::optional{std::construct_at(*pml->next(index))}; return new_table; @@ -114,14 +113,49 @@ namespace teachos::memory::x86_64 .or_else(handle_huge_page); } - auto paging_root::map(page page, frame frame, page_table::entry::flags flags, frame_allocator & allocator) - -> std::optional + auto paging_root::map(page page, frame frame, page_table::entry::flags flags) -> std::optional { return std::optional{this} - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags, allocator); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) .and_then([&](auto pml) -> auto { return do_map(pml, page, frame, flags); }); } + auto paging_root::unmap(page page) -> void + { + if (!this->translate(page)) + { + system::panic("[x86_64:MEM] Tried to unmap a page that was not mapped."); + } + + auto pml4 = this; + auto pml3 = pml4->next(pml_index<4>(page)).value(); + auto pml2 = pml3->next(pml_index<3>(page)).value(); + auto pml1 = pml2->next(pml_index<2>(page)).value(); + + (*pml1)[pml_index<1>(page)].clear(); + + if (pml1->empty()) + { + auto pml1_frame = (*pml2)[pml_index<2>(page)].frame().value(); + active_allocator().release(pml1_frame); + (*pml2)[pml_index<2>(page)].clear(); + } + + if (pml2->empty()) + { + auto pml2_frame = (*pml3)[pml_index<3>(page)].frame().value(); + active_allocator().release(pml2_frame); + (*pml3)[pml_index<3>(page)].clear(); + } + + if (pml3->empty()) + { + auto pml3_frame = (*pml4)[pml_index<4>(page)].frame().value(); + active_allocator().release(pml3_frame); + (*pml4)[pml_index<4>(page)].clear(); + } + } + } // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp new file mode 100644 index 0000000..ea89f38 --- /dev/null +++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp @@ -0,0 +1,38 @@ +#include "x86_64/memory/recursive_page_mapper.hpp" + +#include "kapi/system.hpp" + +#include "x86_64/memory/page_table.hpp" +#include "x86_64/memory/paging_root.hpp" + +namespace teachos::memory::x86_64 +{ + recursive_page_mapper::recursive_page_mapper(frame_allocator & allocator) + : m_allocator{&allocator} + {} + + auto recursive_page_mapper::map(page page, frame frame, flags flags) -> std::byte * + { + return paging_root::get().map(page, frame, to_table_flags(flags)).value_or(nullptr); + } + + auto recursive_page_mapper::unmap(page page) -> void + { + if (!try_unmap(page)) + { + system::panic("[x86_64:MEM] Tried to unmap a page that was not mapped."); + } + } + + auto recursive_page_mapper::try_unmap(page page) -> bool + { + auto & root = paging_root::get(); + if (!root.translate(page)) + { + return false; + } + root.unmap(page); + return true; + } + +} // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 44dbf45..6f3461c 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -5,10 +5,8 @@ #include "x86_64/memory/mmu.hpp" #include "x86_64/memory/page_table.hpp" -#include "x86_64/memory/page_utilities.hpp" #include "x86_64/memory/paging_root.hpp" -#include #include namespace teachos::memory::x86_64 @@ -16,16 +14,12 @@ namespace teachos::memory::x86_64 scoped_mapping::scoped_mapping(scoped_mapping && other) noexcept : m_page{std::exchange(other.m_page, page{})} - , m_allocator{std::exchange(other.m_allocator, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} - , m_allocated{std::exchange(other.m_allocated, 0)} {} - scoped_mapping::scoped_mapping(page page, frame_allocator & allocator) + scoped_mapping::scoped_mapping(page page) : m_page{page} - , m_allocator{&allocator} , m_mapped{false} - , m_allocated{} { if (paging_root::get().translate(page)) { @@ -44,105 +38,28 @@ namespace teachos::memory::x86_64 auto scoped_mapping::operator=(scoped_mapping && other) noexcept -> scoped_mapping & { - this->swap(other); + swap(*this, other); return *this; } auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * { - auto & pml4 = paging_root::get(); - auto pml4_index = pml_index<4>(m_page); - if (!pml4[pml4_index].present()) - { - auto new_frame = m_allocator->allocate(); - pml4[pml4_index].frame(*new_frame, page_table::entry::flags::present | flags); - std::construct_at(pml4.next(pml4_index).value()); - m_allocated |= 1uz << 2; - } - - auto pml3 = pml4.next(pml4_index).value(); - auto pml3_index = pml_index<3>(m_page); - if (!(*pml3)[pml3_index].present()) - { - auto new_frame = m_allocator->allocate(); - (*pml3)[pml3_index].frame(*new_frame, page_table::entry::flags::present | flags); - std::construct_at((*pml3).next(pml3_index).value()); - m_allocated |= 1uz << 1; - } - - auto pml2 = (*pml3).next(pml3_index).value(); - auto pml2_index = pml_index<2>(m_page); - if (!(*pml2)[pml2_index].present()) - { - auto new_frame = m_allocator->allocate(); - (*pml2)[pml2_index].frame(*new_frame, page_table::entry::flags::present | flags); - std::construct_at((*pml2).next(pml2_index).value()); - m_allocated |= 1uz << 0; - } - - auto pml1 = (*pml2).next(pml2_index).value(); - auto pml1_index = pml_index<1>(m_page); - (*pml1)[pml1_index].frame(frame, page_table::entry::flags::present | flags); - + auto result = active_mapper().map(m_page, frame, to_mapper_flags(flags)); m_mapped = true; - - return static_cast(m_page.start_address()); + return result; } auto scoped_mapping::unmap() -> void { - if (!m_mapped) - { - system::panic("[MEM] Tried to release an unmapped temporary mapping!"); - } - - auto pml4 = &paging_root::get(); - auto pml3 = pml4->next(pml_index<4>(m_page)).value(); - auto pml2 = pml3->next(pml_index<3>(m_page)).value(); - auto pml1 = pml2->next(pml_index<2>(m_page)).value(); - - (*pml1)[pml_index<1>(m_page)].clear(); - - if (m_allocated & 1uz << 0) - { - auto pml1_frame = (*pml2)[pml_index<2>(m_page)].frame().value(); - m_allocator->release(pml1_frame); - (*pml2)[pml_index<2>(m_page)].clear(); - } - - if (m_allocated & 1uz << 1) - { - auto pml2_frame = (*pml3)[pml_index<3>(m_page)].frame().value(); - m_allocator->release(pml2_frame); - (*pml3)[pml_index<3>(m_page)].clear(); - } - - if (m_allocated & 1uz << 2) - { - auto pml3_frame = (*pml4)[pml_index<4>(m_page)].frame().value(); - m_allocator->release(pml3_frame); - (*pml4)[pml_index<4>(m_page)].clear(); - } - + active_mapper().unmap(m_page); m_mapped = false; } - auto scoped_mapping::swap(scoped_mapping & other) -> void - { - using std::swap; - - if (&other == this) - return; - - swap(m_page, other.m_page); - swap(m_allocator, other.m_allocator); - swap(m_mapped, other.m_mapped); - swap(m_allocated, other.m_allocated); - } - auto swap(scoped_mapping & lhs, scoped_mapping & rhs) -> void { - lhs.swap(rhs); + using std::swap; + swap(lhs.m_page, rhs.m_page); + swap(lhs.m_mapped, rhs.m_mapped); } } // namespace teachos::memory::x86_64 \ No newline at end of file -- cgit v1.2.3 From 998a001fc621ca0e7560ca09a8acd29469ae3373 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 11 Dec 2025 17:46:02 +0100 Subject: docs: improve documentation --- arch/x86_64/src/memory/page_table.cpp | 18 +++++++++--------- arch/x86_64/src/memory/region_allocator.cpp | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index e797b22..0e404e5 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -6,39 +6,39 @@ namespace teachos::memory::x86_64 { - auto page_table::entry::clear() -> void + auto page_table::entry::clear() noexcept -> void { m_raw = 0; } - auto page_table::entry::present() const -> bool + auto page_table::entry::present() const noexcept -> bool { return (all_flags() & flags::present) != flags::empty; } - auto page_table::entry::huge() const -> bool + auto page_table::entry::huge() const noexcept -> bool { return (all_flags() & flags::huge_page) != flags::empty; } - auto page_table::entry::all_flags() const -> flags + 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) -> void + 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) -> page_table::entry & + 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 -> std::optional + auto page_table::entry::frame() const noexcept -> std::optional { if (present()) { @@ -47,7 +47,7 @@ namespace teachos::memory::x86_64 return std::nullopt; } - auto page_table::entry::frame(struct frame frame, flags flags) -> void + auto page_table::entry::frame(struct frame frame, flags flags) noexcept -> void { m_raw = (frame.start_address().raw() | static_cast(flags)); }; @@ -62,7 +62,7 @@ namespace teachos::memory::x86_64 return m_entries.at(index); } - auto page_table::clear() -> void + auto page_table::clear() noexcept -> void { std::ranges::for_each(m_entries, &page_table::entry::clear); } diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index 8ea76c6..e477ec0 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -56,7 +56,7 @@ namespace teachos::memory::x86_64 } } - auto region_allocator::allocate() -> std::optional + auto region_allocator::allocate() noexcept -> std::optional { if (!m_current_region) { -- cgit v1.2.3 From cf8d0d899ee17db734ce8ab7ee618333eb1767f2 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 11 Dec 2025 18:36:23 +0100 Subject: kapi: finish documentation --- arch/x86_64/src/kapi/memory.cpp | 4 ++-- arch/x86_64/src/memory/paging_root.cpp | 8 ++++---- arch/x86_64/src/memory/recursive_page_mapper.cpp | 2 +- arch/x86_64/src/memory/scoped_mapping.cpp | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 00b9de3..cd0bd77 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -117,7 +117,7 @@ namespace teachos::memory } // namespace - auto active_allocator() -> frame_allocator & + auto active_frame_allocator() -> frame_allocator & { if (!allocator) { @@ -127,7 +127,7 @@ namespace teachos::memory return *allocator; } - auto active_mapper() -> page_mapper & + auto active_page_mapper() -> page_mapper & { if (!mapper) { diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index c458093..078686b 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -34,7 +34,7 @@ namespace teachos::memory::x86_64 flags = flags | page_table::entry::flags::writable; if (!(*pml)[index].present()) { - auto new_table_frame = active_allocator().allocate(); + auto new_table_frame = active_frame_allocator().allocate(); auto mapping = scoped_mapping{page}; (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | flags); auto new_table = std::optional{std::construct_at(*pml->next(index))}; @@ -139,21 +139,21 @@ namespace teachos::memory::x86_64 if (pml1->empty()) { auto pml1_frame = (*pml2)[pml_index<2>(page)].frame().value(); - active_allocator().release(pml1_frame); + active_frame_allocator().release(pml1_frame); (*pml2)[pml_index<2>(page)].clear(); } if (pml2->empty()) { auto pml2_frame = (*pml3)[pml_index<3>(page)].frame().value(); - active_allocator().release(pml2_frame); + active_frame_allocator().release(pml2_frame); (*pml3)[pml_index<3>(page)].clear(); } if (pml3->empty()) { auto pml3_frame = (*pml4)[pml_index<4>(page)].frame().value(); - active_allocator().release(pml3_frame); + active_frame_allocator().release(pml3_frame); (*pml4)[pml_index<4>(page)].clear(); } } diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp index ea89f38..47148f0 100644 --- a/arch/x86_64/src/memory/recursive_page_mapper.cpp +++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp @@ -24,7 +24,7 @@ namespace teachos::memory::x86_64 } } - auto recursive_page_mapper::try_unmap(page page) -> bool + auto recursive_page_mapper::try_unmap(page page) noexcept -> bool { auto & root = paging_root::get(); if (!root.translate(page)) diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index 6f3461c..e243dc9 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -44,14 +44,14 @@ namespace teachos::memory::x86_64 auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * { - auto result = active_mapper().map(m_page, frame, to_mapper_flags(flags)); + auto result = active_page_mapper().map(m_page, frame, to_mapper_flags(flags)); m_mapped = true; return result; } auto scoped_mapping::unmap() -> void { - active_mapper().unmap(m_page); + active_page_mapper().unmap(m_page); m_mapped = false; } -- cgit v1.2.3 From 4bb59ebf68351754ab97e722914e0434c4d347fd Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 10:51:55 +0100 Subject: x86_64/cio: disable cursor by default --- arch/x86_64/src/kapi/cio.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/cio.cpp b/arch/x86_64/src/kapi/cio.cpp index 456477a..3f169a1 100644 --- a/arch/x86_64/src/kapi/cio.cpp +++ b/arch/x86_64/src/kapi/cio.cpp @@ -11,6 +11,7 @@ namespace teachos::cio auto init() -> void { vga_device.emplace(); + vga_device->cursor(false); set_output_device(*vga_device); } -- cgit v1.2.3 From 6fdfe22f75c7202eee84b9b89f6abd5dbc60fedc Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 10:54:22 +0100 Subject: x86_64/cpu: flatten file hierarchy --- arch/x86_64/src/kapi/memory.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index cd0bd77..a20483c 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -5,7 +5,6 @@ #include "x86_64/boot/boot.hpp" #include "x86_64/boot/ld.hpp" -#include "x86_64/cpu/impl/control_registers.hpp" #include "x86_64/cpu/registers.hpp" #include "x86_64/memory/buffered_allocator.hpp" #include "x86_64/memory/kernel_mapper.hpp" -- cgit v1.2.3 From 8fc5f9e3cc28b07b1f120eb1ffedc042fa6662b8 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 13:00:26 +0100 Subject: x86_64/kapi: implement remaining mapping steps --- arch/x86_64/src/kapi/memory.cpp | 54 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index a20483c..abc0526 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -1,5 +1,6 @@ #include "kapi/memory.hpp" +#include "kapi/boot.hpp" #include "kapi/cio.hpp" #include "kapi/system.hpp" @@ -19,6 +20,7 @@ #include #include +#include #include #include @@ -114,6 +116,42 @@ namespace teachos::memory return *new_pml4_frame; } + auto remap_kernel() -> void + { + auto kernel_mapper = x86_64::kernel_mapper{boot::bootstrap_information.mbi}; + kernel_mapper.remap_kernel(); + } + + auto remap_vga_text_mode_buffer(page_mapper & mapper) -> void + { + constexpr auto vga_base = std::uintptr_t{0xb8000}; + auto vga_physical_start = physical_address{vga_base}; + auto vga_virtual_start = linear_address{vga_base + std::bit_cast(&boot::x86_64::TEACHOS_VMA)}; + + auto page = page::containing(vga_virtual_start); + auto frame = frame::containing(vga_physical_start); + + mapper.map(page, frame, page_mapper::flags::writable); + } + + 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_physical_start = physical_address{mbi_base}; + auto mbi_virtual_start = linear_address{mbi_base + std::bit_cast(&boot::x86_64::TEACHOS_VMA)}; + auto mbi_block_count = (mbi_size + PLATFORM_FRAME_SIZE - 1) / PLATFORM_FRAME_SIZE; + + for (auto i = 0uz; i < mbi_block_count; ++i) + { + auto page = page::containing(mbi_virtual_start) + 1; + auto frame = frame::containing(mbi_physical_start) + 1; + mapper.map(page, frame, page_mapper::flags::empty); + } + + boot::bootstrap_information.mbi = std::bit_cast(mbi_virtual_start.raw()); + } + } // namespace auto active_frame_allocator() -> frame_allocator & @@ -138,11 +176,14 @@ namespace teachos::memory auto init() -> void { auto static constinit is_initialized = std::atomic_flag{}; + if (is_initialized.test_and_set()) { system::panic("[x86_64] Memory management has already been initialized."); } + cio::println("[x86_64:MEM] Enabling additional CPU protection features."); + enable_cpu_protections(); auto early_allocator = create_early_frame_allocator(); @@ -154,17 +195,18 @@ namespace teachos::memory auto new_pml4_frame = inject_faux_pml4(allocation_buffer); - auto kernel_mapper = x86_64::kernel_mapper{boot::bootstrap_information.mbi}; - kernel_mapper.remap_kernel(); - cio::println("[x86_64:MEM] prepared new kernel image page maps."); + cio::println("[x86_64:MEM] Preparing new paging hierarchy."); + + remap_kernel(); + remap_vga_text_mode_buffer(recursive_mapper); + remap_multiboot_information(recursive_mapper); + + cio::println("[x86_64:MEM] Switching to new paging hierarchy."); auto cr3 = cpu::x86_64::cr3::read(); cr3.address(new_pml4_frame.start_address()); cpu::x86_64::cr3::write(cr3); - // remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); - // video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); - // video::vga::text::newline(); mapper = nullptr; allocator = nullptr; } -- cgit v1.2.3 From 50c9c9a1d963e66f7658ab31e9ecd65bf227cfff Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 14:07:28 +0100 Subject: x86_64/memory: clean up dependencies --- arch/x86_64/src/kapi/memory.cpp | 36 +++--- arch/x86_64/src/memory/kernel_mapper.cpp | 25 ++-- arch/x86_64/src/memory/paging_root.cpp | 149 +---------------------- arch/x86_64/src/memory/recursive_page_mapper.cpp | 85 ++++++++++++- arch/x86_64/src/memory/scoped_mapping.cpp | 11 +- 5 files changed, 118 insertions(+), 188 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index abc0526..ae0401e 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -67,25 +67,25 @@ namespace teachos::memory } //! Inject, or graft, a faux recursive PML4 into the active page mapping structure. - auto inject_faux_pml4(frame_allocator & allocator) + auto inject_faux_pml4(frame_allocator & allocator, page_mapper & mapper) { using namespace x86_64; using entry_flags = page_table::entry::flags; auto page = page::containing(unused_page_address); - auto temporary_mapper = scoped_mapping{page}; + auto temporary_mapper = scoped_mapping{page, mapper}; auto new_pml4_frame = allocator.allocate(); auto pml4 = std::construct_at(temporary_mapper.map_as(*new_pml4_frame, entry_flags::writable)); (*pml4)[recursive_page_map_index].frame(new_pml4_frame.value(), entry_flags::present | entry_flags::writable); auto pml4_index = pml_index<4>(page); - auto & old_pml4 = paging_root::get(); - auto pml4_entry = old_pml4[pml4_index]; + auto old_pml4 = paging_root::get(); + auto pml4_entry = (*old_pml4)[pml4_index]; auto pml3_index = pml_index<3>(page); - auto old_pml3 = old_pml4.next(pml4_index); + auto old_pml3 = old_pml4->next(pml4_index); auto pml3_entry = (**old_pml3)[pml3_index]; auto pml2_index = pml_index<2>(page); @@ -96,15 +96,15 @@ namespace teachos::memory auto old_pml1 = (**old_pml2).next(pml2_index); auto pml1_entry = (**old_pml1)[pml1_index]; - paging_root::get()[recursive_page_map_index].frame(new_pml4_frame.value(), - entry_flags::present | entry_flags::writable); + (*paging_root::get())[recursive_page_map_index].frame(new_pml4_frame.value(), + entry_flags::present | entry_flags::writable); tlb_flush_all(); - auto & new_pml4 = paging_root::get(); - new_pml4[pml4_index] = pml4_entry; + auto new_pml4 = paging_root::get(); + (*new_pml4)[pml4_index] = pml4_entry; - auto new_pml3 = new_pml4.next(pml4_index); + auto new_pml3 = new_pml4->next(pml4_index); (**new_pml3)[pml3_index] = pml3_entry; auto new_pml2 = (**new_pml3).next(pml3_index); @@ -116,10 +116,10 @@ namespace teachos::memory return *new_pml4_frame; } - auto remap_kernel() -> void + auto remap_kernel(page_mapper & mapper) -> void { auto kernel_mapper = x86_64::kernel_mapper{boot::bootstrap_information.mbi}; - kernel_mapper.remap_kernel(); + kernel_mapper.remap_kernel(mapper); } auto remap_vga_text_mode_buffer(page_mapper & mapper) -> void @@ -188,16 +188,13 @@ namespace teachos::memory auto early_allocator = create_early_frame_allocator(); auto allocation_buffer = x86_64::buffered_allocator<4>{&early_allocator}; - allocator = &allocation_buffer; - auto recursive_mapper = x86_64::recursive_page_mapper{allocation_buffer}; - mapper = &recursive_mapper; - - auto new_pml4_frame = inject_faux_pml4(allocation_buffer); cio::println("[x86_64:MEM] Preparing new paging hierarchy."); - remap_kernel(); + auto new_pml4_frame = inject_faux_pml4(allocation_buffer, recursive_mapper); + + remap_kernel(recursive_mapper); remap_vga_text_mode_buffer(recursive_mapper); remap_multiboot_information(recursive_mapper); @@ -206,9 +203,6 @@ namespace teachos::memory auto cr3 = cpu::x86_64::cr3::read(); cr3.address(new_pml4_frame.start_address()); cpu::x86_64::cr3::write(cr3); - - mapper = nullptr; - allocator = nullptr; } } // namespace teachos::memory diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp index f46b5b5..a28cf00 100644 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -5,8 +5,6 @@ #include "kapi/system.hpp" #include "x86_64/boot/ld.hpp" -#include "x86_64/memory/page_table.hpp" -#include "x86_64/memory/paging_root.hpp" #include #include @@ -17,7 +15,7 @@ namespace teachos::memory::x86_64 { - inline namespace + namespace { using namespace std::string_view_literals; @@ -37,7 +35,7 @@ namespace teachos::memory::x86_64 , m_kernel_load_base{std::bit_cast(&boot::x86_64::TEACHOS_VMA)} {} - auto kernel_mapper::remap_kernel() -> void + auto kernel_mapper::remap_kernel(page_mapper & mapper) -> void { auto elf_information = m_mbi->maybe_elf_symbols(); if (!elf_information) @@ -60,10 +58,11 @@ namespace teachos::memory::x86_64 } std::ranges::for_each(allocated_sections, - [&](auto const & section) -> auto { map_section(section, sections.name(section)); }); + [&](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) -> void + auto kernel_mapper::map_section(section_header_type const & section, std::string_view name, page_mapper & mapper) + -> void { cio::print("[x86_64:MEM] mapping "); cio::println(name); @@ -76,30 +75,30 @@ namespace teachos::memory::x86_64 auto first_page = page::containing(linear_start_address); auto first_frame = frame::containing(physical_start_address); - auto page_flags = page_table::entry::flags::empty; + auto page_flags = page_mapper::flags::empty; if (section.writable()) { - page_flags |= page_table::entry::flags::writable; + page_flags |= page_mapper::flags::writable; } - if (!section.executable()) + if (section.executable()) { - page_flags |= page_table::entry::flags::no_execute; + page_flags |= 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)) + if (!std::ranges::any_of(user_accessible_prefixes, is_prefix_of_name)) { - page_flags |= page_table::entry::flags::user_accessible; + page_flags |= page_mapper::flags::supervisor_only; } for (auto i = 0uz; i < number_of_pages; ++i) { - paging_root::get().map(page{first_page.number() + i}, frame{first_frame.number() + i}, page_flags); + mapper.map(first_page + i, first_frame + i, page_flags); } } diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 078686b..4f88657 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -1,161 +1,18 @@ #include "x86_64/memory/paging_root.hpp" -#include "kapi/memory.hpp" -#include "kapi/system.hpp" - -#include "x86_64/memory/page_table.hpp" -#include "x86_64/memory/page_utilities.hpp" -#include "x86_64/memory/scoped_mapping.hpp" - -#include #include -#include -#include namespace teachos::memory::x86_64 { namespace { - constexpr auto PML_RECURSIVE_BASE = std::uintptr_t{0177777'776'776'776'776'0000uz}; - - //! Perform the actual mapping of the page, via the recursive page map. - //! - //! On any level above PML1, the entries need to not be no_execute, because the image is densely packed. The entries - //! also need to be writable, since the mapping is being performed through the recursive page map hierarchy. When - //! setting the final entry in the PML1, the actually desired flags are set as is, with the present bit added, thus - //! still enforcing non-writability and non-execution of the affected page. - template - requires(Level > 1uz && Level < 5uz) - auto do_map(recursive_page_table * pml, page page, page_table::entry::flags flags) - { - auto index = pml_index(page); - flags = flags & ~page_table::entry::flags::no_execute; - flags = flags | page_table::entry::flags::writable; - if (!(*pml)[index].present()) - { - auto new_table_frame = active_frame_allocator().allocate(); - auto mapping = scoped_mapping{page}; - (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | flags); - auto new_table = std::optional{std::construct_at(*pml->next(index))}; - return new_table; - } - (*pml)[index] |= flags; - return pml->next(index); - } - - //! Perform the actual PML1 update. - auto do_map(page_table * pml, page page, frame frame, page_table::entry::flags flags) -> std::optional - { - auto index = pml_index<1>(page); - if ((*pml)[index].present()) - { - system::panic("[x86_64:MEM] Tried to map a page that is already mapped"); - } - (*pml)[index].frame(frame, page_table::entry::flags::present | flags); - return std::optional{static_cast(page.start_address())}; - } + constexpr auto recursive_base = std::uintptr_t{0177777'776'776'776'776'0000uz}; } // namespace - auto paging_root::get() -> paging_root & - { - auto pml4_address = std::bit_cast(PML_RECURSIVE_BASE); - return *pml4_address; - } - - auto paging_root::translate(linear_address address) const -> std::optional - { - auto offset = address.raw() % page::size; - return translate(page::containing(address)).transform([offset](auto frame) -> auto { - return physical_address{frame.start_address().raw() + offset}; - }); - } - - auto paging_root::translate(page page) const -> std::optional - { - auto pml3 = next(pml_index<4>(page)); - - if (!pml3) - { - return std::nullopt; - } - - auto handle_huge_page = [&] -> std::optional { - auto pml3_entry = pml3.transform([&](auto pml3) -> auto { return (*pml3)[pml_index<3>(page)]; }); - if (!pml3_entry) - { - return std::nullopt; - } - else if (pml3_entry->huge()) - { - auto pml3_entry_frame = *pml3_entry->frame(); - return frame{pml3_entry_frame.number() + pml_index<2>(page) * entry_count + pml_index<1>(page)}; - } - - auto pml2 = (*pml3)->next(pml_index<3>(page)); - auto pml2_entry = pml2.transform([&](auto pml2) -> auto { return (*pml2)[pml_index<2>(page)]; }); - if (!pml2_entry) - { - return std::nullopt; - } - else if (pml2_entry->huge()) - { - auto pml2_entry_frame = *pml2_entry->frame(); - return frame{pml2_entry_frame.number() + pml_index<1>(page)}; - } - - return std::nullopt; - }; - - return pml3.and_then([&](auto pml3) -> auto { return pml3->next(pml_index<3>(page)); }) - .and_then([&](auto pml2) -> auto { return pml2->next(pml_index<2>(page)); }) - .and_then([&](auto pml1) -> auto { return (*pml1)[pml_index<1>(page)].frame(); }) - .or_else(handle_huge_page); - } - - auto paging_root::map(page page, frame frame, page_table::entry::flags flags) -> std::optional + auto paging_root::get() -> paging_root * { - return std::optional{this} - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, flags); }) - .and_then([&](auto pml) -> auto { return do_map(pml, page, frame, flags); }); - } - - auto paging_root::unmap(page page) -> void - { - if (!this->translate(page)) - { - system::panic("[x86_64:MEM] Tried to unmap a page that was not mapped."); - } - - auto pml4 = this; - auto pml3 = pml4->next(pml_index<4>(page)).value(); - auto pml2 = pml3->next(pml_index<3>(page)).value(); - auto pml1 = pml2->next(pml_index<2>(page)).value(); - - (*pml1)[pml_index<1>(page)].clear(); - - if (pml1->empty()) - { - auto pml1_frame = (*pml2)[pml_index<2>(page)].frame().value(); - active_frame_allocator().release(pml1_frame); - (*pml2)[pml_index<2>(page)].clear(); - } - - if (pml2->empty()) - { - auto pml2_frame = (*pml3)[pml_index<3>(page)].frame().value(); - active_frame_allocator().release(pml2_frame); - (*pml3)[pml_index<3>(page)].clear(); - } - - if (pml3->empty()) - { - auto pml3_frame = (*pml4)[pml_index<4>(page)].frame().value(); - active_frame_allocator().release(pml3_frame); - (*pml4)[pml_index<4>(page)].clear(); - } + return std::bit_cast(recursive_base); } } // namespace teachos::memory::x86_64 \ No newline at end of file diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp index 47148f0..fe4fd50 100644 --- a/arch/x86_64/src/memory/recursive_page_mapper.cpp +++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp @@ -7,13 +7,63 @@ namespace teachos::memory::x86_64 { + namespace + { + //! Perform the actual mapping of the page, via the recursive page map. + //! + //! On any level above PML1, the entries need to not be no_execute, because the image is densely packed. The entries + //! also need to be writable, since the mapping is being performed through the recursive page map hierarchy. When + //! setting the final entry in the PML1, the actually desired flags are set as is, with the present bit + //! added, thus + //! still enforcing non-writability and non-execution of the affected page. + template + requires(Level > 1uz && Level < 5uz) + auto do_map(recursive_page_table * pml, page page, frame_allocator & allocator, page_mapper::flags flags) + { + auto index = pml_index(page); + auto entry_flags = to_table_flags(flags); + + entry_flags = entry_flags & ~page_table::entry::flags::no_execute; + entry_flags = entry_flags | page_table::entry::flags::writable; + if (!(*pml)[index].present()) + { + auto new_table_frame = allocator.allocate(); + (*pml)[index].frame(new_table_frame.value(), page_table::entry::flags::present | entry_flags); + auto new_table = std::optional{std::construct_at(*pml->next(index))}; + return new_table; + } + (*pml)[index] |= entry_flags; + return pml->next(index); + } + + //! Perform the actual PML1 update. + auto do_map(page_table * pml, page page, frame frame, page_mapper::flags flags) -> std::optional + { + auto index = pml_index<1>(page); + if ((*pml)[index].present()) + { + system::panic("[x86_64:MEM] Tried to map a page that is already mapped"); + } + (*pml)[index].frame(frame, page_table::entry::flags::present | to_table_flags(flags)); + return std::optional{static_cast(page.start_address())}; + } + + } // namespace + recursive_page_mapper::recursive_page_mapper(frame_allocator & allocator) : m_allocator{&allocator} {} auto recursive_page_mapper::map(page page, frame frame, flags flags) -> std::byte * { - return paging_root::get().map(page, frame, to_table_flags(flags)).value_or(nullptr); + auto pml4 = static_cast *>((paging_root::get())); + + return std::optional{pml4} + .and_then([&](auto pml) -> auto { return do_map(pml, page, *m_allocator, flags); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, *m_allocator, flags); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, *m_allocator, flags); }) + .and_then([&](auto pml) -> auto { return do_map(pml, page, frame, flags); }) + .value_or(nullptr); } auto recursive_page_mapper::unmap(page page) -> void @@ -26,12 +76,39 @@ namespace teachos::memory::x86_64 auto recursive_page_mapper::try_unmap(page page) noexcept -> bool { - auto & root = paging_root::get(); - if (!root.translate(page)) + if (!paging_root::get()->translate(page)) { return false; } - root.unmap(page); + + auto pml4 = paging_root::get(); + auto pml3 = pml4->next(pml_index<4>(page)).value(); + auto pml2 = pml3->next(pml_index<3>(page)).value(); + auto pml1 = pml2->next(pml_index<2>(page)).value(); + + (*pml1)[pml_index<1>(page)].clear(); + + if (pml1->empty()) + { + auto pml1_frame = (*pml2)[pml_index<2>(page)].frame().value(); + m_allocator->release(pml1_frame); + (*pml2)[pml_index<2>(page)].clear(); + } + + if (pml2->empty()) + { + auto pml2_frame = (*pml3)[pml_index<3>(page)].frame().value(); + m_allocator->release(pml2_frame); + (*pml3)[pml_index<3>(page)].clear(); + } + + if (pml3->empty()) + { + auto pml3_frame = (*pml4)[pml_index<4>(page)].frame().value(); + m_allocator->release(pml3_frame); + (*pml4)[pml_index<4>(page)].clear(); + } + return true; } diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index e243dc9..fa68387 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -14,14 +14,16 @@ namespace teachos::memory::x86_64 scoped_mapping::scoped_mapping(scoped_mapping && other) noexcept : m_page{std::exchange(other.m_page, page{})} + , m_mapper{std::exchange(other.m_mapper, nullptr)} , m_mapped{std::exchange(other.m_mapped, false)} {} - scoped_mapping::scoped_mapping(page page) + scoped_mapping::scoped_mapping(page page, page_mapper & mapper) : m_page{page} + , m_mapper{&mapper} , m_mapped{false} { - if (paging_root::get().translate(page)) + if (paging_root::get()->translate(page)) { system::panic("[MEM] Tried to map a page that is already mapped!"); } @@ -44,14 +46,14 @@ namespace teachos::memory::x86_64 auto scoped_mapping::map(frame frame, page_table::entry::flags flags) -> std::byte * { - auto result = active_page_mapper().map(m_page, frame, to_mapper_flags(flags)); + auto result = m_mapper->map(m_page, frame, to_mapper_flags(flags)); m_mapped = true; return result; } auto scoped_mapping::unmap() -> void { - active_page_mapper().unmap(m_page); + m_mapper->unmap(m_page); m_mapped = false; } @@ -59,6 +61,7 @@ namespace teachos::memory::x86_64 { using std::swap; swap(lhs.m_page, rhs.m_page); + swap(lhs.m_mapper, rhs.m_mapper); swap(lhs.m_mapped, rhs.m_mapped); } -- cgit v1.2.3 From 5f695cd3519d8a09a53485c08971f49ed92969ff Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 12 Dec 2025 14:11:25 +0100 Subject: x86_64/memory: silence linter warning --- arch/x86_64/src/memory/recursive_page_mapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp index fe4fd50..798233a 100644 --- a/arch/x86_64/src/memory/recursive_page_mapper.cpp +++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp @@ -17,7 +17,7 @@ namespace teachos::memory::x86_64 //! added, thus //! still enforcing non-writability and non-execution of the affected page. template - requires(Level > 1uz && Level < 5uz) + requires(Level > 1uz && Level <= PLATFORM_PAGING_LEVELS) auto do_map(recursive_page_table * pml, page page, frame_allocator & allocator, page_mapper::flags flags) { auto index = pml_index(page); -- cgit v1.2.3 From 40804526a58ddf2cc0df0750550c8dcfa7b7c57c Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 15 Dec 2025 11:34:30 +0100 Subject: x86_64/boot: use high-mem address of MBI --- arch/x86_64/src/boot/entry64.s | 1 + arch/x86_64/src/kapi/memory.cpp | 6 ++---- arch/x86_64/src/memory/recursive_page_mapper.cpp | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/boot/entry64.s b/arch/x86_64/src/boot/entry64.s index 2932354..657b0a8 100644 --- a/arch/x86_64/src/boot/entry64.s +++ b/arch/x86_64/src/boot/entry64.s @@ -33,6 +33,7 @@ _entry64: mov %rsp, %rbp mov multiboot_information_pointer, %rax + or $TEACHOS_VMA, %rax mov vga_buffer_pointer, %rdx sub $0xb8000, %rdx mov %rax, (bootstrap_information) diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index ae0401e..748893a 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -138,8 +138,8 @@ namespace teachos::memory { auto mbi_base = std::bit_cast(boot::bootstrap_information.mbi); auto mbi_size = boot::bootstrap_information.mbi->size_bytes(); - auto mbi_physical_start = physical_address{mbi_base}; - auto mbi_virtual_start = linear_address{mbi_base + std::bit_cast(&boot::x86_64::TEACHOS_VMA)}; + auto mbi_physical_start = physical_address{mbi_base & ~std::bit_cast(&boot::x86_64::TEACHOS_VMA)}; + auto mbi_virtual_start = linear_address{mbi_base}; auto mbi_block_count = (mbi_size + PLATFORM_FRAME_SIZE - 1) / PLATFORM_FRAME_SIZE; for (auto i = 0uz; i < mbi_block_count; ++i) @@ -148,8 +148,6 @@ namespace teachos::memory auto frame = frame::containing(mbi_physical_start) + 1; mapper.map(page, frame, page_mapper::flags::empty); } - - boot::bootstrap_information.mbi = std::bit_cast(mbi_virtual_start.raw()); } } // namespace diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp index 798233a..ef234ad 100644 --- a/arch/x86_64/src/memory/recursive_page_mapper.cpp +++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp @@ -14,8 +14,7 @@ namespace teachos::memory::x86_64 //! On any level above PML1, the entries need to not be no_execute, because the image is densely packed. The entries //! also need to be writable, since the mapping is being performed through the recursive page map hierarchy. When //! setting the final entry in the PML1, the actually desired flags are set as is, with the present bit - //! added, thus - //! still enforcing non-writability and non-execution of the affected page. + //! added, thus still enforcing non-writability and non-execution of the affected page. template requires(Level > 1uz && Level <= PLATFORM_PAGING_LEVELS) auto do_map(recursive_page_table * pml, page page, frame_allocator & allocator, page_mapper::flags flags) -- cgit v1.2.3 From 43ddde5e30a0d71aa11025a5ae232cea83e7fbde Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 15 Dec 2025 16:28:16 +0100 Subject: kapi: remodel memory API to follow cio API --- arch/x86_64/src/kapi/memory.cpp | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index 748893a..abfb32e 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -21,19 +21,17 @@ #include #include +#include +#include #include #include +#include namespace teachos::memory { namespace { - // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) - auto constinit allocator = static_cast(nullptr); - // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) - auto constinit mapper = static_cast(nullptr); - constexpr auto static unused_page_address = linear_address{0x0000'7fff'cafe'faceuz}; constexpr auto static recursive_page_map_index = x86_64::page_table::entry_count - 2; @@ -152,25 +150,6 @@ namespace teachos::memory } // namespace - auto active_frame_allocator() -> frame_allocator & - { - if (!allocator) - { - system::panic("[x86_64] The frame allocator has not been set yet."); - } - - return *allocator; - } - - auto active_page_mapper() -> page_mapper & - { - if (!mapper) - { - system::panic("[x86_64] The page mapper has not been set you."); - } - return *mapper; - } - auto init() -> void { auto static constinit is_initialized = std::atomic_flag{}; -- cgit v1.2.3 From 1945dd16716392e70e74efacd19e779f121bd1da Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 15 Dec 2025 16:46:51 +0100 Subject: chore: fix missing includes --- arch/x86_64/src/kapi/cio.cpp | 2 ++ arch/x86_64/src/memory/kernel_mapper.cpp | 6 ++++++ arch/x86_64/src/memory/mmu.cpp | 2 ++ arch/x86_64/src/memory/page_table.cpp | 6 ++++++ arch/x86_64/src/memory/paging_root.cpp | 1 + arch/x86_64/src/memory/recursive_page_mapper.cpp | 5 +++++ arch/x86_64/src/memory/region_allocator.cpp | 1 + arch/x86_64/src/memory/scoped_mapping.cpp | 1 + arch/x86_64/src/vga/text.cpp | 1 + 9 files changed, 25 insertions(+) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/cio.cpp b/arch/x86_64/src/kapi/cio.cpp index 3f169a1..ade02aa 100644 --- a/arch/x86_64/src/kapi/cio.cpp +++ b/arch/x86_64/src/kapi/cio.cpp @@ -2,6 +2,8 @@ #include "x86_64/vga/text.hpp" +#include + namespace teachos::cio { diff --git a/arch/x86_64/src/memory/kernel_mapper.cpp b/arch/x86_64/src/memory/kernel_mapper.cpp index a28cf00..4781d64 100644 --- a/arch/x86_64/src/memory/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/kernel_mapper.cpp @@ -8,9 +8,15 @@ #include #include +#include #include +#include +#include +#include #include +#include +#include namespace teachos::memory::x86_64 { diff --git a/arch/x86_64/src/memory/mmu.cpp b/arch/x86_64/src/memory/mmu.cpp index 8ec8a2e..e15d94e 100644 --- a/arch/x86_64/src/memory/mmu.cpp +++ b/arch/x86_64/src/memory/mmu.cpp @@ -1,5 +1,7 @@ #include "x86_64/memory/mmu.hpp" +#include "kapi/memory.hpp" + #include "x86_64/cpu/registers.hpp" namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/page_table.cpp b/arch/x86_64/src/memory/page_table.cpp index 0e404e5..2de099d 100644 --- a/arch/x86_64/src/memory/page_table.cpp +++ b/arch/x86_64/src/memory/page_table.cpp @@ -1,6 +1,12 @@ #include "x86_64/memory/page_table.hpp" +#include "kapi/memory.hpp" + #include +#include +#include +#include +#include #include namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/paging_root.cpp b/arch/x86_64/src/memory/paging_root.cpp index 4f88657..d849a82 100644 --- a/arch/x86_64/src/memory/paging_root.cpp +++ b/arch/x86_64/src/memory/paging_root.cpp @@ -1,5 +1,6 @@ #include "x86_64/memory/paging_root.hpp" +#include #include namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/recursive_page_mapper.cpp b/arch/x86_64/src/memory/recursive_page_mapper.cpp index ef234ad..c5aabcb 100644 --- a/arch/x86_64/src/memory/recursive_page_mapper.cpp +++ b/arch/x86_64/src/memory/recursive_page_mapper.cpp @@ -1,10 +1,15 @@ #include "x86_64/memory/recursive_page_mapper.hpp" +#include "kapi/memory.hpp" #include "kapi/system.hpp" #include "x86_64/memory/page_table.hpp" +#include "x86_64/memory/page_utilities.hpp" #include "x86_64/memory/paging_root.hpp" +#include +#include + namespace teachos::memory::x86_64 { namespace diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index e477ec0..dbe14cd 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -6,6 +6,7 @@ #include #include +#include #include namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/memory/scoped_mapping.cpp b/arch/x86_64/src/memory/scoped_mapping.cpp index fa68387..a86aaed 100644 --- a/arch/x86_64/src/memory/scoped_mapping.cpp +++ b/arch/x86_64/src/memory/scoped_mapping.cpp @@ -7,6 +7,7 @@ #include "x86_64/memory/page_table.hpp" #include "x86_64/memory/paging_root.hpp" +#include #include namespace teachos::memory::x86_64 diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index 8b7f01b..c9eee71 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From a9eeec745e29d89afd48ee43d09432eb6fc35be7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 15 Dec 2025 17:04:15 +0100 Subject: kapi/memory: initialize memory subsystem --- arch/x86_64/src/kapi/memory.cpp | 36 ++++++++++++++++++----------- arch/x86_64/src/memory/region_allocator.cpp | 1 + 2 files changed, 23 insertions(+), 14 deletions(-) (limited to 'arch/x86_64/src') diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp index abfb32e..8c53c4c 100644 --- a/arch/x86_64/src/kapi/memory.cpp +++ b/arch/x86_64/src/kapi/memory.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -36,7 +37,7 @@ namespace teachos::memory constexpr auto static recursive_page_map_index = x86_64::page_table::entry_count - 2; //! Instantiate a basic, memory region based, early frame allocator for remapping. - auto create_early_frame_allocator() + auto collect_memory_information() { auto memory_map = boot::bootstrap_information.mbi->maybe_memory_map(); if (!memory_map) @@ -48,12 +49,10 @@ namespace teachos::memory auto mbi_span = std::span{std::bit_cast(mbi), mbi->size_bytes()}; auto image_span = std::span{&boot::x86_64::_start_physical, &boot::x86_64::_end_physical}; - return x86_64::region_allocator{ - { - .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, - } + return x86_64::region_allocator::memory_information{ + .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, }; } @@ -150,6 +149,12 @@ namespace teachos::memory } // namespace + // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) + auto constinit region_based_allocator = std::optional{}; + auto constinit buffered_allocator = std::optional>{}; + auto constinit recursive_page_mapper = std::optional{}; + // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) + auto init() -> void { auto static constinit is_initialized = std::atomic_flag{}; @@ -163,23 +168,26 @@ namespace teachos::memory enable_cpu_protections(); - auto early_allocator = create_early_frame_allocator(); - auto allocation_buffer = x86_64::buffered_allocator<4>{&early_allocator}; - auto recursive_mapper = x86_64::recursive_page_mapper{allocation_buffer}; + region_based_allocator.emplace(collect_memory_information()); + buffered_allocator.emplace(&*region_based_allocator); + recursive_page_mapper.emplace(*buffered_allocator); cio::println("[x86_64:MEM] Preparing new paging hierarchy."); - auto new_pml4_frame = inject_faux_pml4(allocation_buffer, recursive_mapper); + auto new_pml4_frame = inject_faux_pml4(*buffered_allocator, *recursive_page_mapper); - remap_kernel(recursive_mapper); - remap_vga_text_mode_buffer(recursive_mapper); - remap_multiboot_information(recursive_mapper); + remap_kernel(*recursive_page_mapper); + remap_vga_text_mode_buffer(*recursive_page_mapper); + remap_multiboot_information(*recursive_page_mapper); cio::println("[x86_64:MEM] Switching to new paging hierarchy."); auto cr3 = cpu::x86_64::cr3::read(); cr3.address(new_pml4_frame.start_address()); cpu::x86_64::cr3::write(cr3); + + set_frame_allocator(*buffered_allocator); + set_page_mapper(*recursive_page_mapper); } } // namespace teachos::memory diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp index dbe14cd..0f65b3a 100644 --- a/arch/x86_64/src/memory/region_allocator.cpp +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace teachos::memory::x86_64 { -- cgit v1.2.3