From 6288868ebd728720236d6a857df2658bff2d6547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 29 Sep 2024 07:02:25 +0000 Subject: Pass multiboot info to main function --- arch/x86_64/include/arch/kernel/main.hpp | 2 +- arch/x86_64/src/kernel/main.cpp | 7 ++++++- src/kernel/main.cpp | 5 ++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/include/arch/kernel/main.hpp b/arch/x86_64/include/arch/kernel/main.hpp index 6961594..57b9b58 100644 --- a/arch/x86_64/include/arch/kernel/main.hpp +++ b/arch/x86_64/include/arch/kernel/main.hpp @@ -5,7 +5,7 @@ namespace teachos::arch::kernel { - auto main() -> void; + auto main(size_t multiboot_information_address) -> void; } #endif \ No newline at end of file diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 0e90264..01c14a5 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -2,14 +2,19 @@ #include "arch/video/vga/text.hpp" +#include "stdio.h" + namespace teachos::arch::kernel { - auto main() -> void + auto main(size_t multiboot_information_address) -> void { using namespace video::vga; text::clear(); text::cursor(false); text::write("TeachOS is starting up...", text::common_attributes::green_on_black); + char address[32U] = {}; + snprintf(address, sizeof(address), "Multiboot address: (%lu)", multiboot_information_address); + text::write(address, text::common_attributes::green_on_black); } } // namespace teachos::arch::kernel diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 07a9955..a1ef159 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -1,3 +1,6 @@ #include "arch/kernel/main.hpp" -extern "C" auto kernel_main() -> void { teachos::arch::kernel::main(); } \ No newline at end of file +extern "C" auto kernel_main(size_t multiboot_information_address) -> void +{ + teachos::arch::kernel::main(multiboot_information_address); +} -- cgit v1.2.3 From 4e991f05b8beb7538cee6939777f36610f8b7bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 29 Sep 2024 07:56:50 +0000 Subject: Pass multiboot to main from edi register --- arch/x86_64/src/boot/boot.s | 2 ++ arch/x86_64/src/kernel/main.cpp | 9 ++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 7b4e193..d41981a 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -366,5 +366,7 @@ _transition_to_long_mode: call _init + mov multiboot_information_pointer, %ebx + mov %ebx, %edi call kernel_main hlt diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 01c14a5..cb5092c 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -2,8 +2,6 @@ #include "arch/video/vga/text.hpp" -#include "stdio.h" - namespace teachos::arch::kernel { auto main(size_t multiboot_information_address) -> void @@ -13,8 +11,9 @@ namespace teachos::arch::kernel text::clear(); text::cursor(false); text::write("TeachOS is starting up...", text::common_attributes::green_on_black); - char address[32U] = {}; - snprintf(address, sizeof(address), "Multiboot address: (%lu)", multiboot_information_address); - text::write(address, text::common_attributes::green_on_black); + if (multiboot_information_address > 5) + { + return; + } } } // namespace teachos::arch::kernel -- cgit v1.2.3 From eeee7967c17704fee443a3b5b02d53a580f18b73 Mon Sep 17 00:00:00 2001 From: TheSoeren Date: Sun, 29 Sep 2024 08:52:28 +0000 Subject: use multiboot_information_pointer public variable --- arch/x86_64/include/arch/boot/multiboot.hpp | 14 ++++++++++++++ arch/x86_64/include/arch/boot/pointers.hpp | 2 +- arch/x86_64/include/arch/kernel/main.hpp | 2 +- arch/x86_64/src/boot/boot.s | 2 -- arch/x86_64/src/kernel/main.cpp | 16 +++++++++++----- src/kernel/main.cpp | 5 +---- 6 files changed, 28 insertions(+), 13 deletions(-) create mode 100644 arch/x86_64/include/arch/boot/multiboot.hpp diff --git a/arch/x86_64/include/arch/boot/multiboot.hpp b/arch/x86_64/include/arch/boot/multiboot.hpp new file mode 100644 index 0000000..c6fed55 --- /dev/null +++ b/arch/x86_64/include/arch/boot/multiboot.hpp @@ -0,0 +1,14 @@ +#include + +struct multiboot_tag +{ + uint32_t type; + uint32_t size; +}; + +struct multiboot_info +{ + uint32_t total_size; + uint32_t reserved; + struct multiboot_tag tags[1]; // TODO: Size 0 +}; \ No newline at end of file diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index dcd14fe..c7424e2 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -5,7 +5,7 @@ namespace teachos::arch::boot { - extern "C" std::byte const multiboot_information_pointer; + extern "C" size_t const multiboot_information_pointer; } // namespace teachos::arch::boot #endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/kernel/main.hpp b/arch/x86_64/include/arch/kernel/main.hpp index 57b9b58..6961594 100644 --- a/arch/x86_64/include/arch/kernel/main.hpp +++ b/arch/x86_64/include/arch/kernel/main.hpp @@ -5,7 +5,7 @@ namespace teachos::arch::kernel { - auto main(size_t multiboot_information_address) -> void; + auto main() -> void; } #endif \ No newline at end of file diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index d41981a..7b4e193 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -366,7 +366,5 @@ _transition_to_long_mode: call _init - mov multiboot_information_pointer, %ebx - mov %ebx, %edi call kernel_main hlt diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index cb5092c..e77818e 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,19 +1,25 @@ #include "arch/kernel/main.hpp" +#include "arch/boot/multiboot.hpp" +#include "arch/boot/pointers.hpp" #include "arch/video/vga/text.hpp" namespace teachos::arch::kernel { - auto main(size_t multiboot_information_address) -> void + auto main() -> void { using namespace video::vga; + auto t = arch::boot::multiboot_information_pointer; + // auto multiboot_tag = (struct multiboot_tag *) ((uint8_t) t + 8); + // for (auto tag = multiboot_tag; tag->type != ) + + if (t == 300) + { + } + text::clear(); text::cursor(false); text::write("TeachOS is starting up...", text::common_attributes::green_on_black); - if (multiboot_information_address > 5) - { - return; - } } } // namespace teachos::arch::kernel diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index a1ef159..4799b29 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -1,6 +1,3 @@ #include "arch/kernel/main.hpp" -extern "C" auto kernel_main(size_t multiboot_information_address) -> void -{ - teachos::arch::kernel::main(multiboot_information_address); -} +extern "C" auto kernel_main() -> void { teachos::arch::kernel::main(); } -- cgit v1.2.3 From 8f91d0ef50e01440f7e6e9f4afa5887f6afefea1 Mon Sep 17 00:00:00 2001 From: TheSoeren Date: Sun, 29 Sep 2024 09:26:17 +0000 Subject: read basic mem info --- arch/x86_64/include/arch/boot/multiboot.hpp | 38 +++++++++++++++++++++++++++-- arch/x86_64/src/kernel/main.cpp | 34 ++++++++++++++++++++------ 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/arch/x86_64/include/arch/boot/multiboot.hpp b/arch/x86_64/include/arch/boot/multiboot.hpp index c6fed55..9a0757e 100644 --- a/arch/x86_64/include/arch/boot/multiboot.hpp +++ b/arch/x86_64/include/arch/boot/multiboot.hpp @@ -10,5 +10,39 @@ struct multiboot_info { uint32_t total_size; uint32_t reserved; - struct multiboot_tag tags[1]; // TODO: Size 0 -}; \ No newline at end of file + /* + * field "tags" is an array of multiboot_tags, however the array is never + * being accessed by index and using an array definition with size 0 produces a compiler + * error. + */ + struct multiboot_tag tags; +}; + +/* + * Define all multiboot tag types to ther respective values + * The gnu boot information format is defined here: + * https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Boot-information-format + */ +#define MULTIBOOT_TAG_ALIGN 8 +#define MULTIBOOT_TAG_TYPE_END 0 +#define MULTIBOOT_TAG_TYPE_CMDLINE 1 +#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 +#define MULTIBOOT_TAG_TYPE_MODULE 3 +#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 +#define MULTIBOOT_TAG_TYPE_BOOTDEV 5 +#define MULTIBOOT_TAG_TYPE_MMAP 6 +#define MULTIBOOT_TAG_TYPE_VBE 7 +#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 +#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9 +#define MULTIBOOT_TAG_TYPE_APM 10 +#define MULTIBOOT_TAG_TYPE_EFI32 11 +#define MULTIBOOT_TAG_TYPE_EFI64 12 +#define MULTIBOOT_TAG_TYPE_SMBIOS 13 +#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14 +#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15 +#define MULTIBOOT_TAG_TYPE_NETWORK 16 +#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17 +#define MULTIBOOT_TAG_TYPE_EFI_BS 18 +#define MULTIBOOT_TAG_TYPE_EFI32_IH 19 +#define MULTIBOOT_TAG_TYPE_EFI64_IH 20 +#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21 diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index e77818e..8ca577a 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -10,16 +10,34 @@ namespace teachos::arch::kernel { using namespace video::vga; - auto t = arch::boot::multiboot_information_pointer; - // auto multiboot_tag = (struct multiboot_tag *) ((uint8_t) t + 8); - // for (auto tag = multiboot_tag; tag->type != ) - - if (t == 300) - { - } - text::clear(); text::cursor(false); text::write("TeachOS is starting up...", text::common_attributes::green_on_black); + + auto mip = arch::boot::multiboot_information_pointer; + + // Address of the first multiboot tag + auto multiboot_tag = (struct multiboot_tag *)((uint8_t *)mip + 8); + + /* + * Loop over the multiboot2 tags to access the information needed. + * Tags are defined in the header. + */ + for (auto tag = multiboot_tag; tag->type != MULTIBOOT_TAG_TYPE_END; + tag = (struct multiboot_tag *)((uint8_t *)tag + ((tag->size + 7) & ~7))) + { + switch (tag->type) + { + case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: + uint32_t size = tag->size; + uint32_t mem_lower = *(uint32_t *)(&size + 32); + uint32_t mem_upper = *(uint32_t *)(&size + 64); + if (mem_lower > mem_upper) + { + } + text::write("BUFFER IS HERE", text::common_attributes::green_on_black); + break; + } + } } } // namespace teachos::arch::kernel -- cgit v1.2.3 From d2e1c8ba686d7d4ab32eda91c2f532676e9b8acf Mon Sep 17 00:00:00 2001 From: TheSoeren Date: Sun, 29 Sep 2024 14:03:39 +0000 Subject: create write_number function --- arch/x86_64/include/arch/video/vga/text.hpp | 50 +++++++++++++++++++++++++++++ arch/x86_64/src/kernel/main.cpp | 10 +++--- arch/x86_64/src/video/vga/text.cpp | 15 ++++----- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/arch/x86_64/include/arch/video/vga/text.hpp b/arch/x86_64/include/arch/video/vga/text.hpp index 1e584d6..97344da 100644 --- a/arch/x86_64/include/arch/video/vga/text.hpp +++ b/arch/x86_64/include/arch/video/vga/text.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace teachos::arch::video::vga::text { @@ -108,6 +109,55 @@ namespace teachos::arch::video::vga::text * @see vga::text::attribute */ auto write(std::string_view code_points, attribute attribute) -> void; + + /** + * @brief Write a single character to the VGA text buffer. + * + * @note This function also updates the text mode buffer pointer. + * + * @param code_point A code point to write to the VGA text mode buffer. + * @param attribute The attribute to apply to the written sequence of code points. + * @see vga::text::attribute + */ + auto write_char(char code_point, attribute attribute) -> void; + + // TODO: Move concepts to their own file/folder + template + concept Integral = std::is_integral_v; + + /** + * @brief Write a integral value to the VGA text buffer. + * + * @note This function also updates the text mode buffer pointer. + * + * @param code_points A integral value to write to the VGA text mode buffer. + * @param attribute The attribute to apply to the written sequence of code points. + * @see vga::text::attribute + */ + template + auto write_number(T value, attribute attribute) -> void + { + T current_value = value; + + T divisor = 1; + while (current_value > 9) + { + divisor *= 10; + current_value = current_value / 10; + } + + current_value = value; + while (divisor > 0) + { + uint8_t quotient = current_value / divisor; + char ascii_digit = quotient + '0'; + + write_char(ascii_digit, attribute); + current_value %= divisor; + + divisor /= 10; + } + } } // namespace teachos::arch::video::vga::text #endif \ No newline at end of file diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 8ca577a..a5ffbb4 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -32,10 +32,12 @@ namespace teachos::arch::kernel uint32_t size = tag->size; uint32_t mem_lower = *(uint32_t *)(&size + 32); uint32_t mem_upper = *(uint32_t *)(&size + 64); - if (mem_lower > mem_upper) - { - } - text::write("BUFFER IS HERE", text::common_attributes::green_on_black); + + text::write_number(mem_lower, text::common_attributes::green_on_black); + text::write("Lower memory bound", text::common_attributes::green_on_black); + text::write_number(mem_lower, text::common_attributes::green_on_black); + text::write("Upper memory bound", text::common_attributes::green_on_black); + text::write_number(mem_upper, text::common_attributes::green_on_black); break; } } diff --git a/arch/x86_64/src/video/vga/text.cpp b/arch/x86_64/src/video/vga/text.cpp index f1e7412..bf60410 100644 --- a/arch/x86_64/src/video/vga/text.cpp +++ b/arch/x86_64/src/video/vga/text.cpp @@ -17,12 +17,6 @@ namespace teachos::arch::video::vga::text extern "C" std::pair * vga_buffer_pointer; auto constinit text_buffer = teachos::memory::asm_pointer{vga_buffer_pointer}; - - auto write(char code_point, attribute attribute) -> void - { - auto & p = *text_buffer; - (*p++) = std::pair{code_point, attribute}; - }; } // namespace auto clear(attribute attribute) -> void @@ -39,9 +33,14 @@ namespace teachos::arch::video::vga::text crtc::data_port::write(vga::crtc::data_port::read() | cursor_disable_byte); } + 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(code_point, attribute); }); + 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 20a5e5377c0f8e0769d67a7928891597bc463e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 30 Sep 2024 11:32:56 +0000 Subject: Attempt to print memory map --- arch/x86_64/include/arch/boot/multiboot.hpp | 11 +++++- arch/x86_64/include/arch/boot/pointers.hpp | 2 +- arch/x86_64/include/arch/io/port_io.hpp | 2 +- arch/x86_64/include/arch/kernel/main.hpp | 2 +- arch/x86_64/include/arch/video/vga/io.hpp | 4 +-- arch/x86_64/include/arch/video/vga/text.hpp | 3 +- arch/x86_64/src/kernel/main.cpp | 53 ++++++++++++++++++++++++----- arch/x86_64/src/video/vga/text.cpp | 1 - 8 files changed, 59 insertions(+), 19 deletions(-) diff --git a/arch/x86_64/include/arch/boot/multiboot.hpp b/arch/x86_64/include/arch/boot/multiboot.hpp index 9a0757e..4182a18 100644 --- a/arch/x86_64/include/arch/boot/multiboot.hpp +++ b/arch/x86_64/include/arch/boot/multiboot.hpp @@ -2,7 +2,8 @@ struct multiboot_tag { - uint32_t type; + uint16_t type; + uint16_t flags; uint32_t size; }; @@ -18,6 +19,14 @@ struct multiboot_info struct multiboot_tag tags; }; +struct memory_map_entry +{ + uint64_t base_addr; + uint64_t length; + uint32_t type; + uint32_t reserved; +}; + /* * Define all multiboot tag types to ther respective values * The gnu boot information format is defined here: diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index c7424e2..25800f4 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -8,4 +8,4 @@ namespace teachos::arch::boot extern "C" size_t const multiboot_information_pointer; } // namespace teachos::arch::boot -#endif \ No newline at end of file +#endif diff --git a/arch/x86_64/include/arch/io/port_io.hpp b/arch/x86_64/include/arch/io/port_io.hpp index 5b61f90..c0f1ef3 100644 --- a/arch/x86_64/include/arch/io/port_io.hpp +++ b/arch/x86_64/include/arch/io/port_io.hpp @@ -131,4 +131,4 @@ namespace teachos::arch::io } // namespace teachos::arch::io -#endif \ No newline at end of file +#endif diff --git a/arch/x86_64/include/arch/kernel/main.hpp b/arch/x86_64/include/arch/kernel/main.hpp index 6961594..6759eb2 100644 --- a/arch/x86_64/include/arch/kernel/main.hpp +++ b/arch/x86_64/include/arch/kernel/main.hpp @@ -8,4 +8,4 @@ namespace teachos::arch::kernel auto main() -> void; } -#endif \ No newline at end of file +#endif diff --git a/arch/x86_64/include/arch/video/vga/io.hpp b/arch/x86_64/include/arch/video/vga/io.hpp index 9226c5c..da9375d 100644 --- a/arch/x86_64/include/arch/video/vga/io.hpp +++ b/arch/x86_64/include/arch/video/vga/io.hpp @@ -7,10 +7,8 @@ namespace teachos::arch::video::vga { - namespace crtc { - /** * @brief The address port of the CRT Controller */ @@ -38,4 +36,4 @@ namespace teachos::arch::video::vga } // namespace teachos::arch::video::vga -#endif \ No newline at end of file +#endif diff --git a/arch/x86_64/include/arch/video/vga/text.hpp b/arch/x86_64/include/arch/video/vga/text.hpp index 97344da..3b484e5 100644 --- a/arch/x86_64/include/arch/video/vga/text.hpp +++ b/arch/x86_64/include/arch/video/vga/text.hpp @@ -138,8 +138,8 @@ namespace teachos::arch::video::vga::text auto write_number(T value, attribute attribute) -> void { T current_value = value; - T divisor = 1; + while (current_value > 9) { divisor *= 10; @@ -154,7 +154,6 @@ namespace teachos::arch::video::vga::text write_char(ascii_digit, attribute); current_value %= divisor; - divisor /= 10; } } diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index a5ffbb4..6eb8521 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -6,6 +6,46 @@ namespace teachos::arch::kernel { + + auto print_meminfo(multiboot_tag * tag) -> void + { + using namespace video::vga; + + uint32_t * pointer = &tag->size; + uint32_t mem_lower = *(++pointer); + uint32_t mem_upper = *(++pointer); + + text::write("Lower memory bound: ", text::common_attributes::green_on_black); + text::write_number(mem_lower, text::common_attributes::green_on_black); + text::write("Upper memory bound: ", text::common_attributes::green_on_black); + text::write_number(mem_upper, text::common_attributes::green_on_black); + } + + auto print_memory_map(multiboot_tag * tag) -> void + { + using namespace video::vga; + + uint32_t * pointer = &tag->size; + uint32_t entry_size = *(++pointer); + uint32_t entry_version = *(++pointer); + text::write("Version: ", text::common_attributes::green_on_black); + text::write_number(entry_version, text::common_attributes::green_on_black); + + auto begin = (struct memory_map_entry *)++pointer; + auto end = begin + entry_size; + for (auto itr = begin; itr < end; ++itr) + { + text::write("Base Address: ", text::common_attributes::green_on_black); + text::write_number(itr->base_addr, text::common_attributes::green_on_black); + text::write("Length: ", text::common_attributes::green_on_black); + text::write_number(itr->length, text::common_attributes::green_on_black); + text::write("Type: ", text::common_attributes::green_on_black); + text::write_number(itr->type, text::common_attributes::green_on_black); + text::write("Reserved: ", text::common_attributes::green_on_black); + text::write_number(itr->reserved, text::common_attributes::green_on_black); + } + } + auto main() -> void { using namespace video::vga; @@ -29,15 +69,10 @@ namespace teachos::arch::kernel switch (tag->type) { case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: - uint32_t size = tag->size; - uint32_t mem_lower = *(uint32_t *)(&size + 32); - uint32_t mem_upper = *(uint32_t *)(&size + 64); - - text::write_number(mem_lower, text::common_attributes::green_on_black); - text::write("Lower memory bound", text::common_attributes::green_on_black); - text::write_number(mem_lower, text::common_attributes::green_on_black); - text::write("Upper memory bound", text::common_attributes::green_on_black); - text::write_number(mem_upper, text::common_attributes::green_on_black); + print_meminfo(tag); + break; + case MULTIBOOT_TAG_TYPE_MMAP: + print_memory_map(tag); break; } } diff --git a/arch/x86_64/src/video/vga/text.cpp b/arch/x86_64/src/video/vga/text.cpp index bf60410..a613c3b 100644 --- a/arch/x86_64/src/video/vga/text.cpp +++ b/arch/x86_64/src/video/vga/text.cpp @@ -10,7 +10,6 @@ namespace teachos::arch::video::vga::text { - namespace { auto constexpr default_text_buffer_address = 0xb8000; -- cgit v1.2.3 From b8e58d2f64fbb171b8687b9dd104ddd22fe4fc8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 1 Oct 2024 07:42:09 +0000 Subject: Adjust printing of memory map --- arch/x86_64/include/arch/boot/multiboot.hpp | 11 +++++-- arch/x86_64/src/kernel/main.cpp | 46 ++++++++++------------------- 2 files changed, 25 insertions(+), 32 deletions(-) diff --git a/arch/x86_64/include/arch/boot/multiboot.hpp b/arch/x86_64/include/arch/boot/multiboot.hpp index 4182a18..c39081a 100644 --- a/arch/x86_64/include/arch/boot/multiboot.hpp +++ b/arch/x86_64/include/arch/boot/multiboot.hpp @@ -2,8 +2,7 @@ struct multiboot_tag { - uint16_t type; - uint16_t flags; + uint32_t type; uint32_t size; }; @@ -27,6 +26,14 @@ struct memory_map_entry uint32_t reserved; }; +struct memory_map_info +{ + multiboot_tag tag; + uint32_t entry_size; + uint32_t entry_version; + struct memory_map_entry entries; +}; + /* * Define all multiboot tag types to ther respective values * The gnu boot information format is defined here: diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 6eb8521..7107a36 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -6,43 +6,32 @@ namespace teachos::arch::kernel { - - auto print_meminfo(multiboot_tag * tag) -> void + auto print_memory_map(memory_map_info * mminfo) -> void { using namespace video::vga; - uint32_t * pointer = &tag->size; - uint32_t mem_lower = *(++pointer); - uint32_t mem_upper = *(++pointer); - - text::write("Lower memory bound: ", text::common_attributes::green_on_black); - text::write_number(mem_lower, text::common_attributes::green_on_black); - text::write("Upper memory bound: ", text::common_attributes::green_on_black); - text::write_number(mem_upper, text::common_attributes::green_on_black); - } - - auto print_memory_map(multiboot_tag * tag) -> void - { - using namespace video::vga; - - uint32_t * pointer = &tag->size; - uint32_t entry_size = *(++pointer); - uint32_t entry_version = *(++pointer); + uint32_t const entry_size = mminfo->entry_size; + uint32_t const entry_version = mminfo->entry_version; + text::write("Entry Size: ", text::common_attributes::green_on_black); + text::write_number(entry_size, text::common_attributes::green_on_black); text::write("Version: ", text::common_attributes::green_on_black); text::write_number(entry_version, text::common_attributes::green_on_black); - auto begin = (struct memory_map_entry *)++pointer; - auto end = begin + entry_size; - for (auto itr = begin; itr < end; ++itr) + uint32_t const remaining_size = mminfo->tag.size - (4 * sizeof(uint32_t)); + uint32_t const entry_amount = remaining_size / entry_size; + + auto begin = &mminfo->entries; + auto end = begin + entry_amount; + for (auto entry = begin; entry != end; ++entry) { text::write("Base Address: ", text::common_attributes::green_on_black); - text::write_number(itr->base_addr, text::common_attributes::green_on_black); + text::write_number(entry->base_addr, text::common_attributes::green_on_black); text::write("Length: ", text::common_attributes::green_on_black); - text::write_number(itr->length, text::common_attributes::green_on_black); + text::write_number(entry->length, text::common_attributes::green_on_black); text::write("Type: ", text::common_attributes::green_on_black); - text::write_number(itr->type, text::common_attributes::green_on_black); + text::write_number(entry->type, text::common_attributes::green_on_black); text::write("Reserved: ", text::common_attributes::green_on_black); - text::write_number(itr->reserved, text::common_attributes::green_on_black); + text::write_number(entry->reserved, text::common_attributes::green_on_black); } } @@ -68,11 +57,8 @@ namespace teachos::arch::kernel { switch (tag->type) { - case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: - print_meminfo(tag); - break; case MULTIBOOT_TAG_TYPE_MMAP: - print_memory_map(tag); + print_memory_map((struct memory_map_info *)tag); break; } } -- cgit v1.2.3 From e90fcb84fa43773d1e48bd82ce08381c6549a9cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 1 Oct 2024 08:22:40 +0000 Subject: Added efl section print method --- arch/x86_64/include/arch/boot/multiboot.hpp | 40 +++++++++++++++++++-- arch/x86_64/src/kernel/main.cpp | 54 +++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/include/arch/boot/multiboot.hpp b/arch/x86_64/include/arch/boot/multiboot.hpp index c39081a..dfb289d 100644 --- a/arch/x86_64/include/arch/boot/multiboot.hpp +++ b/arch/x86_64/include/arch/boot/multiboot.hpp @@ -11,9 +11,9 @@ struct multiboot_info uint32_t total_size; uint32_t reserved; /* - * field "tags" is an array of multiboot_tags, however the array is never - * being accessed by index and using an array definition with size 0 produces a compiler - * error. + * field "tags" is an array of multiboot_tag, however the array is never + * being accessed by index we don't know the real size at compile-time, + * and using an array definition with size 0 produces a compiler error. */ struct multiboot_tag tags; }; @@ -22,6 +22,11 @@ struct memory_map_entry { uint64_t base_addr; uint64_t length; +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 uint32_t type; uint32_t reserved; }; @@ -31,9 +36,38 @@ struct memory_map_info multiboot_tag tag; uint32_t entry_size; uint32_t entry_version; + /* + * field "entries" is an array of memory_map_entry, however the array is never + * being accessed by index, we don't know the real size at compile-time, + * and using an array definition with size 0 produces a compiler error. + */ struct memory_map_entry entries; }; +struct elf64_section_header +{ + uint32_t sh_name; + uint32_t sh_type; + uint64_t sh_flags; + uint64_t sh_addr; + uint64_t sh_offset; + uint64_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint64_t sh_addralign; + uint64_t sh_entsize; +}; + +struct elf_symbols_section +{ + multiboot_tag tag; + uint16_t num; + uint16_t entsize; + uint16_t shndx; + uint16_t reserved; + struct elf64_section_header sections; +}; + /* * Define all multiboot tag types to ther respective values * The gnu boot information format is defined here: diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 7107a36..2040fe3 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -35,6 +35,57 @@ namespace teachos::arch::kernel } } + auto print_elf_sections(elf_symbols_section * symbol) -> void + { + using namespace video::vga; + + uint16_t const num = symbol->num; + text::write("Number of entries: ", text::common_attributes::green_on_black); + text::write_number(num, text::common_attributes::green_on_black); + uint16_t const entsize = symbol->entsize; + text::write("Entry Size: ", text::common_attributes::green_on_black); + text::write_number(entsize, text::common_attributes::green_on_black); + uint16_t const shndx = symbol->shndx; + text::write("Section index: ", text::common_attributes::green_on_black); + text::write_number(shndx, text::common_attributes::green_on_black); + + auto begin = &symbol->sections; + auto end = begin + num; + for (auto section = begin; section != end; ++section) + { + uint32_t const sh_name = section->sh_name; + text::write("Section name: ", text::common_attributes::green_on_black); + text::write_number(sh_name, text::common_attributes::green_on_black); + uint32_t const sh_type = section->sh_type; + text::write("Section type: ", text::common_attributes::green_on_black); + text::write_number(sh_type, text::common_attributes::green_on_black); + uint64_t const sh_flags = section->sh_flags; + text::write("Section flags: ", text::common_attributes::green_on_black); + text::write_number(sh_flags, text::common_attributes::green_on_black); + uint64_t const sh_addr = section->sh_addr; + text::write("Section name: ", text::common_attributes::green_on_black); + text::write_number(sh_addr, text::common_attributes::green_on_black); + uint64_t const sh_offset = section->sh_offset; + text::write("Section name: ", text::common_attributes::green_on_black); + text::write_number(sh_offset, text::common_attributes::green_on_black); + uint64_t const sh_size = section->sh_size; + text::write("Section name: ", text::common_attributes::green_on_black); + text::write_number(sh_size, text::common_attributes::green_on_black); + uint32_t const sh_link = section->sh_link; + text::write("Section name: ", text::common_attributes::green_on_black); + text::write_number(sh_link, text::common_attributes::green_on_black); + uint32_t const sh_info = section->sh_info; + text::write("Section name: ", text::common_attributes::green_on_black); + text::write_number(sh_info, text::common_attributes::green_on_black); + uint64_t const sh_addralign = section->sh_addralign; + text::write("Section name: ", text::common_attributes::green_on_black); + text::write_number(sh_addralign, text::common_attributes::green_on_black); + uint64_t const sh_entsize = section->sh_entsize; + text::write("Section name: ", text::common_attributes::green_on_black); + text::write_number(sh_entsize, text::common_attributes::green_on_black); + } + } + auto main() -> void { using namespace video::vga; @@ -57,6 +108,9 @@ namespace teachos::arch::kernel { switch (tag->type) { + case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: + print_elf_sections((struct elf_symbols_section *)tag); + break; case MULTIBOOT_TAG_TYPE_MMAP: print_memory_map((struct memory_map_info *)tag); break; -- cgit v1.2.3 From 4c60bad3150b07e973eb385613a90ebb8c94ecac Mon Sep 17 00:00:00 2001 From: TheSoeren Date: Tue, 1 Oct 2024 11:59:40 +0000 Subject: add structs, clean mip code --- arch/x86_64/include/arch/boot/multiboot.hpp | 86 +++++++++++++++++++++++++---- arch/x86_64/src/kernel/main.cpp | 60 +++++++++++++++----- 2 files changed, 120 insertions(+), 26 deletions(-) diff --git a/arch/x86_64/include/arch/boot/multiboot.hpp b/arch/x86_64/include/arch/boot/multiboot.hpp index dfb289d..d3787f2 100644 --- a/arch/x86_64/include/arch/boot/multiboot.hpp +++ b/arch/x86_64/include/arch/boot/multiboot.hpp @@ -6,6 +6,14 @@ struct multiboot_tag uint32_t size; }; +struct basic_memory_info +{ + uint32_t type; + uint32_t size; + uint32_t mem_lower; + uint32_t mem_upper; +}; + struct multiboot_info { uint32_t total_size; @@ -44,18 +52,72 @@ struct memory_map_info struct memory_map_entry entries; }; -struct elf64_section_header +#define EI_NIDENT 16 + +/* ELF standard typedefs (yet more proof that was way overdue) */ +typedef uint16_t Elf64_Half; +typedef int16_t Elf64_SHalf; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +typedef uint64_t Elf64_Off; +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Section; + +struct executable_header +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +}; + +struct program_header +{ + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +}; + +struct elf_section_header +{ + Elf64_Word sh_name; /* Section name (string tbl index) */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section flags */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Section size in bytes */ + Elf64_Word sh_link; /* Link to another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +}; + +struct elf_symbol { - uint32_t sh_name; - uint32_t sh_type; - uint64_t sh_flags; - uint64_t sh_addr; - uint64_t sh_offset; - uint64_t sh_size; - uint32_t sh_link; - uint32_t sh_info; - uint64_t sh_addralign; - uint64_t sh_entsize; + Elf64_Word st_name; /* Symbol name (string tbl index) */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf64_Section st_shndx; /* Section index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Symbol size */ }; struct elf_symbols_section @@ -65,7 +127,7 @@ struct elf_symbols_section uint16_t entsize; uint16_t shndx; uint16_t reserved; - struct elf64_section_header sections; + struct elf_section_header sections; }; /* diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 2040fe3..4deac6d 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -6,14 +6,28 @@ namespace teachos::arch::kernel { + auto print_mem_info(basic_memory_info * mem_info) -> void + { + using namespace video::vga; + + auto mem_lower = mem_info->mem_lower; + text::write("Lower memory (kB): ", text::common_attributes::green_on_black); + text::write_number(mem_lower, text::common_attributes::green_on_black); + + auto mem_upper = mem_info->mem_upper; + text::write("Upper memory (kB): ", text::common_attributes::green_on_black); + text::write_number(mem_upper, text::common_attributes::green_on_black); + } + auto print_memory_map(memory_map_info * mminfo) -> void { using namespace video::vga; uint32_t const entry_size = mminfo->entry_size; - uint32_t const entry_version = mminfo->entry_version; text::write("Entry Size: ", text::common_attributes::green_on_black); text::write_number(entry_size, text::common_attributes::green_on_black); + + uint32_t const entry_version = mminfo->entry_version; text::write("Version: ", text::common_attributes::green_on_black); text::write_number(entry_version, text::common_attributes::green_on_black); @@ -26,10 +40,13 @@ namespace teachos::arch::kernel { text::write("Base Address: ", text::common_attributes::green_on_black); text::write_number(entry->base_addr, text::common_attributes::green_on_black); + text::write("Length: ", text::common_attributes::green_on_black); text::write_number(entry->length, text::common_attributes::green_on_black); + text::write("Type: ", text::common_attributes::green_on_black); text::write_number(entry->type, text::common_attributes::green_on_black); + text::write("Reserved: ", text::common_attributes::green_on_black); text::write_number(entry->reserved, text::common_attributes::green_on_black); } @@ -42,9 +59,11 @@ namespace teachos::arch::kernel uint16_t const num = symbol->num; text::write("Number of entries: ", text::common_attributes::green_on_black); text::write_number(num, text::common_attributes::green_on_black); + uint16_t const entsize = symbol->entsize; text::write("Entry Size: ", text::common_attributes::green_on_black); text::write_number(entsize, text::common_attributes::green_on_black); + uint16_t const shndx = symbol->shndx; text::write("Section index: ", text::common_attributes::green_on_black); text::write_number(shndx, text::common_attributes::green_on_black); @@ -56,32 +75,41 @@ namespace teachos::arch::kernel uint32_t const sh_name = section->sh_name; text::write("Section name: ", text::common_attributes::green_on_black); text::write_number(sh_name, text::common_attributes::green_on_black); + uint32_t const sh_type = section->sh_type; text::write("Section type: ", text::common_attributes::green_on_black); text::write_number(sh_type, text::common_attributes::green_on_black); + uint64_t const sh_flags = section->sh_flags; text::write("Section flags: ", text::common_attributes::green_on_black); text::write_number(sh_flags, text::common_attributes::green_on_black); + uint64_t const sh_addr = section->sh_addr; - text::write("Section name: ", text::common_attributes::green_on_black); + text::write("Section address: ", text::common_attributes::green_on_black); text::write_number(sh_addr, text::common_attributes::green_on_black); + uint64_t const sh_offset = section->sh_offset; - text::write("Section name: ", text::common_attributes::green_on_black); + text::write("Section offset: ", text::common_attributes::green_on_black); text::write_number(sh_offset, text::common_attributes::green_on_black); + uint64_t const sh_size = section->sh_size; - text::write("Section name: ", text::common_attributes::green_on_black); + text::write("Section size: ", text::common_attributes::green_on_black); text::write_number(sh_size, text::common_attributes::green_on_black); + uint32_t const sh_link = section->sh_link; - text::write("Section name: ", text::common_attributes::green_on_black); + text::write("Section link: ", text::common_attributes::green_on_black); text::write_number(sh_link, text::common_attributes::green_on_black); + uint32_t const sh_info = section->sh_info; - text::write("Section name: ", text::common_attributes::green_on_black); + text::write("Section info: ", text::common_attributes::green_on_black); text::write_number(sh_info, text::common_attributes::green_on_black); + uint64_t const sh_addralign = section->sh_addralign; - text::write("Section name: ", text::common_attributes::green_on_black); + text::write("Section address align: ", text::common_attributes::green_on_black); text::write_number(sh_addralign, text::common_attributes::green_on_black); + uint64_t const sh_entsize = section->sh_entsize; - text::write("Section name: ", text::common_attributes::green_on_black); + text::write("Section entry size: ", text::common_attributes::green_on_black); text::write_number(sh_entsize, text::common_attributes::green_on_black); } } @@ -94,20 +122,24 @@ namespace teachos::arch::kernel text::cursor(false); text::write("TeachOS is starting up...", text::common_attributes::green_on_black); - auto mip = arch::boot::multiboot_information_pointer; - - // Address of the first multiboot tag - auto multiboot_tag = (struct multiboot_tag *)((uint8_t *)mip + 8); + multiboot_info * multiboot_information_pointer = (multiboot_info *)arch::boot::multiboot_information_pointer; + auto multiboot_tag = &(multiboot_information_pointer->tags); /* * Loop over the multiboot2 tags to access the information needed. - * Tags are defined in the header. + * Tags are defined in the header file and are padded so that each + * Tag starts at an 8-bytes aligned adress. + * + * The increment part aligns the size to an 8-byte address. */ for (auto tag = multiboot_tag; tag->type != MULTIBOOT_TAG_TYPE_END; - tag = (struct multiboot_tag *)((uint8_t *)tag + ((tag->size + 7) & ~7))) + tag = (struct multiboot_tag *)(((uint8_t *)tag) + ((tag->size + 7) & ~7))) { switch (tag->type) { + case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: + print_mem_info((struct basic_memory_info *)tag); + break; case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: print_elf_sections((struct elf_symbols_section *)tag); break; -- cgit v1.2.3 From 32add45849744dc976c7af6ec24f985bbace47d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 2 Oct 2024 13:02:35 +0000 Subject: Creating base frame allocation code --- arch/x86_64/include/arch/kernel/main.hpp | 2 - .../x86_64/include/arch/memory/frame_allocator.hpp | 48 ++++++++++++++++++++++ arch/x86_64/src/kernel/main.cpp | 6 +++ arch/x86_64/src/memory/frame_allocator.cpp | 9 ++++ 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/frame_allocator.hpp create mode 100644 arch/x86_64/src/memory/frame_allocator.cpp diff --git a/arch/x86_64/include/arch/kernel/main.hpp b/arch/x86_64/include/arch/kernel/main.hpp index 6759eb2..8813b46 100644 --- a/arch/x86_64/include/arch/kernel/main.hpp +++ b/arch/x86_64/include/arch/kernel/main.hpp @@ -1,8 +1,6 @@ #ifndef TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP #define TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP -#include - namespace teachos::arch::kernel { auto main() -> void; diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp new file mode 100644 index 0000000..bcb0882 --- /dev/null +++ b/arch/x86_64/include/arch/memory/frame_allocator.hpp @@ -0,0 +1,48 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP + +#include +#include + +namespace teachos::arch::memory +{ + namespace + { + const size_t PAGE_FRAME_SIZE = 4096U; + } + + struct Frame + { + size_t frame_number; + + Frame(size_t frame_number) + : frame_number(frame_number) + { + // Nothing to do + } + + auto containing_address(size_t address) -> Frame { return Frame{address / PAGE_FRAME_SIZE}; } + }; + + struct IFrameAllocator + { + virtual auto allocate_frame() -> std::optional = 0; + virtual auto deallocate_frame(Frame frame) -> void = 0; + }; + + struct AreaFrameAllocator : public IFrameAllocator + { + Frame next_free_frame; + // std::optional current_area; + // MemoryArea * areas; + Frame kernel_start; + Frame kernel_end; + Frame multiboot_start; + Frame multiboot_end; + + auto allocate_frame() -> std::optional override; + auto deallocate_frame(Frame frame) -> void override; + }; +} // namespace teachos::arch::memory + +#endif // TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 4deac6d..da496a6 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -125,6 +125,12 @@ namespace teachos::arch::kernel multiboot_info * multiboot_information_pointer = (multiboot_info *)arch::boot::multiboot_information_pointer; auto multiboot_tag = &(multiboot_information_pointer->tags); + text::write("Multiboot Start: ", text::common_attributes::green_on_black); + text::write_number(arch::boot::multiboot_information_pointer, text::common_attributes::green_on_black); + text::write("Multiboot End: ", text::common_attributes::green_on_black); + text::write_number(arch::boot::multiboot_information_pointer + multiboot_information_pointer->total_size, + text::common_attributes::green_on_black); + /* * Loop over the multiboot2 tags to access the information needed. * Tags are defined in the header file and are padded so that each diff --git a/arch/x86_64/src/memory/frame_allocator.cpp b/arch/x86_64/src/memory/frame_allocator.cpp new file mode 100644 index 0000000..425528a --- /dev/null +++ b/arch/x86_64/src/memory/frame_allocator.cpp @@ -0,0 +1,9 @@ +#include "arch/memory/frame_allocator.hpp" + +namespace teachos::arch::memory +{ + auto AreaFrameAllocator::allocate_frame() -> std::optional {} + + auto AreaFrameAllocator::deallocate_frame(Frame frame) -> void {} + +} // namespace teachos::arch::memory -- cgit v1.2.3 From c2c7ad21fdd42111180d317ef50b15b7404769d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 2 Oct 2024 13:32:28 +0000 Subject: Improve naming, add enums and move into namespace --- arch/x86_64/include/arch/boot/multiboot.hpp | 160 ----------------------- arch/x86_64/include/arch/memory/multiboot.hpp | 174 ++++++++++++++++++++++++++ arch/x86_64/src/kernel/main.cpp | 33 ++--- 3 files changed, 193 insertions(+), 174 deletions(-) delete mode 100644 arch/x86_64/include/arch/boot/multiboot.hpp create mode 100644 arch/x86_64/include/arch/memory/multiboot.hpp diff --git a/arch/x86_64/include/arch/boot/multiboot.hpp b/arch/x86_64/include/arch/boot/multiboot.hpp deleted file mode 100644 index d3787f2..0000000 --- a/arch/x86_64/include/arch/boot/multiboot.hpp +++ /dev/null @@ -1,160 +0,0 @@ -#include - -struct multiboot_tag -{ - uint32_t type; - uint32_t size; -}; - -struct basic_memory_info -{ - uint32_t type; - uint32_t size; - uint32_t mem_lower; - uint32_t mem_upper; -}; - -struct multiboot_info -{ - uint32_t total_size; - uint32_t reserved; - /* - * field "tags" is an array of multiboot_tag, however the array is never - * being accessed by index we don't know the real size at compile-time, - * and using an array definition with size 0 produces a compiler error. - */ - struct multiboot_tag tags; -}; - -struct memory_map_entry -{ - uint64_t base_addr; - uint64_t length; -#define MULTIBOOT_MEMORY_AVAILABLE 1 -#define MULTIBOOT_MEMORY_RESERVED 2 -#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 -#define MULTIBOOT_MEMORY_NVS 4 -#define MULTIBOOT_MEMORY_BADRAM 5 - uint32_t type; - uint32_t reserved; -}; - -struct memory_map_info -{ - multiboot_tag tag; - uint32_t entry_size; - uint32_t entry_version; - /* - * field "entries" is an array of memory_map_entry, however the array is never - * being accessed by index, we don't know the real size at compile-time, - * and using an array definition with size 0 produces a compiler error. - */ - struct memory_map_entry entries; -}; - -#define EI_NIDENT 16 - -/* ELF standard typedefs (yet more proof that was way overdue) */ -typedef uint16_t Elf64_Half; -typedef int16_t Elf64_SHalf; -typedef uint32_t Elf64_Word; -typedef int32_t Elf64_Sword; -typedef uint64_t Elf64_Xword; -typedef int64_t Elf64_Sxword; - -typedef uint64_t Elf64_Off; -typedef uint64_t Elf64_Addr; -typedef uint16_t Elf64_Section; - -struct executable_header -{ - unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ - Elf64_Half e_type; /* Object file type */ - Elf64_Half e_machine; /* Architecture */ - Elf64_Word e_version; /* Object file version */ - Elf64_Addr e_entry; /* Entry point virtual address */ - Elf64_Off e_phoff; /* Program header table file offset */ - Elf64_Off e_shoff; /* Section header table file offset */ - Elf64_Word e_flags; /* Processor-specific flags */ - Elf64_Half e_ehsize; /* ELF header size in bytes */ - Elf64_Half e_phentsize; /* Program header table entry size */ - Elf64_Half e_phnum; /* Program header table entry count */ - Elf64_Half e_shentsize; /* Section header table entry size */ - Elf64_Half e_shnum; /* Section header table entry count */ - Elf64_Half e_shstrndx; /* Section header string table index */ -}; - -struct program_header -{ - Elf64_Word p_type; /* Segment type */ - Elf64_Word p_flags; /* Segment flags */ - Elf64_Off p_offset; /* Segment file offset */ - Elf64_Addr p_vaddr; /* Segment virtual address */ - Elf64_Addr p_paddr; /* Segment physical address */ - Elf64_Xword p_filesz; /* Segment size in file */ - Elf64_Xword p_memsz; /* Segment size in memory */ - Elf64_Xword p_align; /* Segment alignment */ -}; - -struct elf_section_header -{ - Elf64_Word sh_name; /* Section name (string tbl index) */ - Elf64_Word sh_type; /* Section type */ - Elf64_Xword sh_flags; /* Section flags */ - Elf64_Addr sh_addr; /* Section virtual addr at execution */ - Elf64_Off sh_offset; /* Section file offset */ - Elf64_Xword sh_size; /* Section size in bytes */ - Elf64_Word sh_link; /* Link to another section */ - Elf64_Word sh_info; /* Additional section information */ - Elf64_Xword sh_addralign; /* Section alignment */ - Elf64_Xword sh_entsize; /* Entry size if section holds table */ -}; - -struct elf_symbol -{ - Elf64_Word st_name; /* Symbol name (string tbl index) */ - unsigned char st_info; /* Symbol type and binding */ - unsigned char st_other; /* Symbol visibility */ - Elf64_Section st_shndx; /* Section index */ - Elf64_Addr st_value; /* Symbol value */ - Elf64_Xword st_size; /* Symbol size */ -}; - -struct elf_symbols_section -{ - multiboot_tag tag; - uint16_t num; - uint16_t entsize; - uint16_t shndx; - uint16_t reserved; - struct elf_section_header sections; -}; - -/* - * Define all multiboot tag types to ther respective values - * The gnu boot information format is defined here: - * https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Boot-information-format - */ -#define MULTIBOOT_TAG_ALIGN 8 -#define MULTIBOOT_TAG_TYPE_END 0 -#define MULTIBOOT_TAG_TYPE_CMDLINE 1 -#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 -#define MULTIBOOT_TAG_TYPE_MODULE 3 -#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 -#define MULTIBOOT_TAG_TYPE_BOOTDEV 5 -#define MULTIBOOT_TAG_TYPE_MMAP 6 -#define MULTIBOOT_TAG_TYPE_VBE 7 -#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 -#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9 -#define MULTIBOOT_TAG_TYPE_APM 10 -#define MULTIBOOT_TAG_TYPE_EFI32 11 -#define MULTIBOOT_TAG_TYPE_EFI64 12 -#define MULTIBOOT_TAG_TYPE_SMBIOS 13 -#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14 -#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15 -#define MULTIBOOT_TAG_TYPE_NETWORK 16 -#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17 -#define MULTIBOOT_TAG_TYPE_EFI_BS 18 -#define MULTIBOOT_TAG_TYPE_EFI32_IH 19 -#define MULTIBOOT_TAG_TYPE_EFI64_IH 20 -#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21 diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp new file mode 100644 index 0000000..95e6404 --- /dev/null +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -0,0 +1,174 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_HPP + +#include + +namespace teachos::arch::memory +{ + /* + * Define all multiboot tag types to ther respective values + * The gnu boot information format is defined here: + * https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Boot-information-format + */ + enum class MultibootTagType : uint32_t + { + END, + CMDLINE, + BOOT_LOADER_NAME, + MODULE, + BASIC_MEMORY_INFO, + BOOTDEV, + MEMORY_MAP, + VBE, + FRAMEBUFFER, + ELF_SECTIONS, + APM, + EFI32, + EFI64, + SMBIOS, + ACPI_OLD, + ACPI_NEW, + NETWORK, + EFI_MEMORY_MAP, + EFI_BS, + EFI32_IH, + EFI64_IH, + LOAD_BASE_ADDRESS + }; + + struct MultibootTag + { + MultibootTagType type; + uint32_t size; + }; + + struct MemoryInfo + { + uint32_t type; + uint32_t size; + uint32_t mem_lower; + uint32_t mem_upper; + }; + + struct MultibootInfo + { + uint32_t total_size; + uint32_t reserved; + /* + * field "tags" is an array of MultibootTag, however the array is never + * being accessed by index we don't know the real size at compile-time, + * and using an array definition with size 0 produces a compiler error. + */ + struct MultibootTag tags; + }; + + enum class MemoryAreaType : uint32_t + { + AVAILABLE = 1, + RESERVED, + ACPI_AVAILABLE, + RESERVED_HIBERNATION, + DEFECTIVE + }; + + struct MemoryArea + { + uint64_t base_addr; + uint64_t length; + MemoryAreaType type; + uint32_t reserved; + }; + + struct MemoryMap + { + MultibootTag tag; + uint32_t entry_size; + uint32_t entry_version; + /* + * field "entries" is an array of MemoryArea, however the array is never + * being accessed by index, we don't know the real size at compile-time, + * and using an array definition with size 0 produces a compiler error. + */ + struct MemoryArea entries; + }; + +#define EI_NIDENT 16 + + /* ELF standard typedefs (yet more proof that was way overdue) */ + typedef uint16_t Elf64_Half; + typedef int16_t Elf64_SHalf; + typedef uint32_t Elf64_Word; + typedef int32_t Elf64_Sword; + typedef uint64_t Elf64_Xword; + typedef int64_t Elf64_Sxword; + + typedef uint64_t Elf64_Off; + typedef uint64_t Elf64_Addr; + typedef uint16_t Elf64_Section; + + struct executable_header + { + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ + }; + + struct program_header + { + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ + }; + + struct elf_section_header + { + Elf64_Word sh_name; /* Section name (string tbl index) */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section flags */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Section size in bytes */ + Elf64_Word sh_link; /* Link to another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ + }; + + struct elf_symbol + { + Elf64_Word st_name; /* Symbol name (string tbl index) */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf64_Section st_shndx; /* Section index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Symbol size */ + }; + + struct elf_symbols_section + { + MultibootTag tag; + uint16_t num; + uint16_t entsize; + uint16_t shndx; + uint16_t reserved; + struct elf_section_header sections; + }; +} // namespace teachos::arch::memory + +#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_HPP diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index da496a6..cffbfb8 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,12 +1,12 @@ #include "arch/kernel/main.hpp" -#include "arch/boot/multiboot.hpp" #include "arch/boot/pointers.hpp" +#include "arch/memory/multiboot.hpp" #include "arch/video/vga/text.hpp" namespace teachos::arch::kernel { - auto print_mem_info(basic_memory_info * mem_info) -> void + auto print_mem_info(arch::memory::MemoryInfo * mem_info) -> void { using namespace video::vga; @@ -19,7 +19,7 @@ namespace teachos::arch::kernel text::write_number(mem_upper, text::common_attributes::green_on_black); } - auto print_memory_map(memory_map_info * mminfo) -> void + auto print_memory_map(arch::memory::MemoryMap * mminfo) -> void { using namespace video::vga; @@ -45,14 +45,15 @@ namespace teachos::arch::kernel text::write_number(entry->length, text::common_attributes::green_on_black); text::write("Type: ", text::common_attributes::green_on_black); - text::write_number(entry->type, text::common_attributes::green_on_black); + text::write_number(static_cast::type>(entry->type), + text::common_attributes::green_on_black); text::write("Reserved: ", text::common_attributes::green_on_black); text::write_number(entry->reserved, text::common_attributes::green_on_black); } } - auto print_elf_sections(elf_symbols_section * symbol) -> void + auto print_elf_sections(arch::memory::elf_symbols_section * symbol) -> void { using namespace video::vga; @@ -122,7 +123,8 @@ namespace teachos::arch::kernel text::cursor(false); text::write("TeachOS is starting up...", text::common_attributes::green_on_black); - multiboot_info * multiboot_information_pointer = (multiboot_info *)arch::boot::multiboot_information_pointer; + arch::memory::MultibootInfo * multiboot_information_pointer = + (arch::memory::MultibootInfo *)arch::boot::multiboot_information_pointer; auto multiboot_tag = &(multiboot_information_pointer->tags); text::write("Multiboot Start: ", text::common_attributes::green_on_black); @@ -138,19 +140,22 @@ namespace teachos::arch::kernel * * The increment part aligns the size to an 8-byte address. */ - for (auto tag = multiboot_tag; tag->type != MULTIBOOT_TAG_TYPE_END; - tag = (struct multiboot_tag *)(((uint8_t *)tag) + ((tag->size + 7) & ~7))) + for (auto tag = multiboot_tag; tag->type != arch::memory::MultibootTagType::END; + tag = (arch::memory::MultibootTag *)(((uint8_t *)tag) + ((tag->size + 7) & ~7))) { switch (tag->type) { - case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: - print_mem_info((struct basic_memory_info *)tag); + case arch::memory::MultibootTagType::BASIC_MEMORY_INFO: + print_mem_info((arch::memory::MemoryInfo *)tag); break; - case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: - print_elf_sections((struct elf_symbols_section *)tag); + case arch::memory::MultibootTagType::ELF_SECTIONS: + print_elf_sections((arch::memory::elf_symbols_section *)tag); break; - case MULTIBOOT_TAG_TYPE_MMAP: - print_memory_map((struct memory_map_info *)tag); + case arch::memory::MultibootTagType::MEMORY_MAP: + print_memory_map((arch::memory::MemoryMap *)tag); + break; + default: + // All other cases are not important and can be ignored break; } } -- cgit v1.2.3 From 1ab9c3c09d32283b39ca1026a9e29ada5ff7fda5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 6 Oct 2024 07:34:30 +0000 Subject: Renaming scheme --- .../x86_64/include/arch/memory/frame_allocator.hpp | 34 +++++++++++----------- arch/x86_64/include/arch/memory/multiboot.hpp | 30 +++++++++---------- arch/x86_64/include/arch/video/vga/text.hpp | 2 +- arch/x86_64/src/kernel/main.cpp | 24 +++++++-------- arch/x86_64/src/memory/frame_allocator.cpp | 4 +-- 5 files changed, 47 insertions(+), 47 deletions(-) diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp index bcb0882..8dee848 100644 --- a/arch/x86_64/include/arch/memory/frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/frame_allocator.hpp @@ -11,37 +11,37 @@ namespace teachos::arch::memory const size_t PAGE_FRAME_SIZE = 4096U; } - struct Frame + struct frame { size_t frame_number; - Frame(size_t frame_number) + frame(size_t frame_number) : frame_number(frame_number) { // Nothing to do } - auto containing_address(size_t address) -> Frame { return Frame{address / PAGE_FRAME_SIZE}; } + auto containing_address(size_t address) -> frame { return frame{address / PAGE_FRAME_SIZE}; } }; - struct IFrameAllocator + struct frame_allocator { - virtual auto allocate_frame() -> std::optional = 0; - virtual auto deallocate_frame(Frame frame) -> void = 0; + virtual auto allocate_frame() -> std::optional = 0; + virtual auto deallocate_frame(frame frame) -> void = 0; }; - struct AreaFrameAllocator : public IFrameAllocator + struct area_frame_allocator : public frame_allocator { - Frame next_free_frame; - // std::optional current_area; - // MemoryArea * areas; - Frame kernel_start; - Frame kernel_end; - Frame multiboot_start; - Frame multiboot_end; - - auto allocate_frame() -> std::optional override; - auto deallocate_frame(Frame frame) -> void override; + frame next_free_frame; + // std::optional current_area; + // memory_area * areas; + frame kernel_start; + frame kernel_end; + frame multiboot_start; + frame multiboot_end; + + auto allocate_frame() -> std::optional override; + auto deallocate_frame(frame frame) -> void override; }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index 95e6404..baad25b 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -10,7 +10,7 @@ namespace teachos::arch::memory * The gnu boot information format is defined here: * https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Boot-information-format */ - enum class MultibootTagType : uint32_t + enum class multi_boot_tag_type : uint32_t { END, CMDLINE, @@ -36,13 +36,13 @@ namespace teachos::arch::memory LOAD_BASE_ADDRESS }; - struct MultibootTag + struct multi_boot_tag { - MultibootTagType type; + multi_boot_tag_type type; uint32_t size; }; - struct MemoryInfo + struct memory_info { uint32_t type; uint32_t size; @@ -50,19 +50,19 @@ namespace teachos::arch::memory uint32_t mem_upper; }; - struct MultibootInfo + struct multi_boot_info { uint32_t total_size; uint32_t reserved; /* - * field "tags" is an array of MultibootTag, however the array is never + * field "tags" is an array of multi_boot_tag, however the array is never * being accessed by index we don't know the real size at compile-time, * and using an array definition with size 0 produces a compiler error. */ - struct MultibootTag tags; + struct multi_boot_tag tags; }; - enum class MemoryAreaType : uint32_t + enum class memory_area_type : uint32_t { AVAILABLE = 1, RESERVED, @@ -71,25 +71,25 @@ namespace teachos::arch::memory DEFECTIVE }; - struct MemoryArea + struct memory_area { uint64_t base_addr; uint64_t length; - MemoryAreaType type; + memory_area_type type; uint32_t reserved; }; - struct MemoryMap + struct memory_map { - MultibootTag tag; + multi_boot_tag tag; uint32_t entry_size; uint32_t entry_version; /* - * field "entries" is an array of MemoryArea, however the array is never + * field "entries" is an array of memory_area, however the array is never * being accessed by index, we don't know the real size at compile-time, * and using an array definition with size 0 produces a compiler error. */ - struct MemoryArea entries; + struct memory_area entries; }; #define EI_NIDENT 16 @@ -162,7 +162,7 @@ namespace teachos::arch::memory struct elf_symbols_section { - MultibootTag tag; + multi_boot_tag tag; uint16_t num; uint16_t entsize; uint16_t shndx; diff --git a/arch/x86_64/include/arch/video/vga/text.hpp b/arch/x86_64/include/arch/video/vga/text.hpp index 3b484e5..9c4c701 100644 --- a/arch/x86_64/include/arch/video/vga/text.hpp +++ b/arch/x86_64/include/arch/video/vga/text.hpp @@ -130,7 +130,7 @@ namespace teachos::arch::video::vga::text * * @note This function also updates the text mode buffer pointer. * - * @param code_points A integral value to write to the VGA text mode buffer. + * @param value A integral value to write to the VGA text mode buffer. * @param attribute The attribute to apply to the written sequence of code points. * @see vga::text::attribute */ diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index cffbfb8..4d6296a 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -6,7 +6,7 @@ namespace teachos::arch::kernel { - auto print_mem_info(arch::memory::MemoryInfo * mem_info) -> void + auto print_mem_info(arch::memory::memory_info * mem_info) -> void { using namespace video::vga; @@ -19,7 +19,7 @@ namespace teachos::arch::kernel text::write_number(mem_upper, text::common_attributes::green_on_black); } - auto print_memory_map(arch::memory::MemoryMap * mminfo) -> void + auto print_memory_map(arch::memory::memory_map * mminfo) -> void { using namespace video::vga; @@ -45,7 +45,7 @@ namespace teachos::arch::kernel text::write_number(entry->length, text::common_attributes::green_on_black); text::write("Type: ", text::common_attributes::green_on_black); - text::write_number(static_cast::type>(entry->type), + text::write_number(static_cast::type>(entry->type), text::common_attributes::green_on_black); text::write("Reserved: ", text::common_attributes::green_on_black); @@ -123,8 +123,8 @@ namespace teachos::arch::kernel text::cursor(false); text::write("TeachOS is starting up...", text::common_attributes::green_on_black); - arch::memory::MultibootInfo * multiboot_information_pointer = - (arch::memory::MultibootInfo *)arch::boot::multiboot_information_pointer; + arch::memory::multi_boot_info * multiboot_information_pointer = + (arch::memory::multi_boot_info *)arch::boot::multiboot_information_pointer; auto multiboot_tag = &(multiboot_information_pointer->tags); text::write("Multiboot Start: ", text::common_attributes::green_on_black); @@ -140,19 +140,19 @@ namespace teachos::arch::kernel * * The increment part aligns the size to an 8-byte address. */ - for (auto tag = multiboot_tag; tag->type != arch::memory::MultibootTagType::END; - tag = (arch::memory::MultibootTag *)(((uint8_t *)tag) + ((tag->size + 7) & ~7))) + for (auto tag = multiboot_tag; tag->type != arch::memory::multi_boot_tag_type::END; + tag = (arch::memory::multi_boot_tag *)(((uint8_t *)tag) + ((tag->size + 7) & ~7))) { switch (tag->type) { - case arch::memory::MultibootTagType::BASIC_MEMORY_INFO: - print_mem_info((arch::memory::MemoryInfo *)tag); + case arch::memory::multi_boot_tag_type::BASIC_MEMORY_INFO: + print_mem_info((arch::memory::memory_info *)tag); break; - case arch::memory::MultibootTagType::ELF_SECTIONS: + case arch::memory::multi_boot_tag_type::ELF_SECTIONS: print_elf_sections((arch::memory::elf_symbols_section *)tag); break; - case arch::memory::MultibootTagType::MEMORY_MAP: - print_memory_map((arch::memory::MemoryMap *)tag); + case arch::memory::multi_boot_tag_type::MEMORY_MAP: + print_memory_map((arch::memory::memory_map *)tag); break; default: // All other cases are not important and can be ignored diff --git a/arch/x86_64/src/memory/frame_allocator.cpp b/arch/x86_64/src/memory/frame_allocator.cpp index 425528a..b9d26a5 100644 --- a/arch/x86_64/src/memory/frame_allocator.cpp +++ b/arch/x86_64/src/memory/frame_allocator.cpp @@ -2,8 +2,8 @@ namespace teachos::arch::memory { - auto AreaFrameAllocator::allocate_frame() -> std::optional {} + auto area_frame_allocator::allocate_frame() -> std::optional {} - auto AreaFrameAllocator::deallocate_frame(Frame frame) -> void {} + auto area_frame_allocator::deallocate_frame(frame frame) -> void {} } // namespace teachos::arch::memory -- cgit v1.2.3 From f7df7167f0c54bd8da79dbf2d48bda5d7491fd32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 6 Oct 2024 08:45:04 +0000 Subject: Remove high memory kernel and needless prints --- arch/x86_64/scripts/kernel.ld | 22 ++++---- arch/x86_64/src/boot/boot.s | 24 +------- arch/x86_64/src/kernel/main.cpp | 120 ++++++++++++---------------------------- 3 files changed, 48 insertions(+), 118 deletions(-) diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 943266c..31d8be3 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -3,7 +3,6 @@ ENTRY(_start) /***************************************************************************** * Virtual and linear start addresses of the TeachOS kernel *****************************************************************************/ -TEACHOS_HIGH = -2048M; TEACHOS_LOW = 1M; PHDRS { @@ -31,7 +30,7 @@ SECTIONS * symbols at the beginning. ***************************************************************************/ _start_linear = .; - _start_virtual = . + TEACHOS_HIGH; + _start_virtual = .; /*************************************************************************** * The bootstrapping infratructure goes first. We first place the read-only @@ -66,9 +65,8 @@ SECTIONS * also make sure to align the loaded data onto a page boundary. ***************************************************************************/ . = ALIGN(4K); - . += TEACHOS_HIGH; - .init ALIGN(4K) : AT(ADDR (.init) - TEACHOS_HIGH) + .init ALIGN(4K) : AT(ADDR (.init)) { /* * Make sure that the crt code is wrapped around the compiler generated @@ -79,7 +77,7 @@ SECTIONS KEEP(*crtn.s.o*(.init)) } :text - .fini ALIGN(4K) : AT(ADDR (.fini) - TEACHOS_HIGH) + .fini ALIGN(4K) : AT(ADDR (.fini)) { /* * Make sure that the crt code is wrapped around the compiler generated @@ -90,18 +88,18 @@ SECTIONS KEEP(*crtn.s.o*(.fini)) } - .text ALIGN(4K) : AT(ADDR (.text) - TEACHOS_HIGH) + .text ALIGN(4K) : AT(ADDR (.text)) { *(.text*) } - .rodata ALIGN(4K) : AT (ADDR (.rodata) - TEACHOS_HIGH) + .rodata ALIGN(4K) : AT (ADDR (.rodata)) { *(.rodata) *(.rodata.*) } :rodata - .ctors ALIGN(4K) : AT (ADDR (.ctors) - TEACHOS_HIGH) + .ctors ALIGN(4K) : AT (ADDR (.ctors)) { KEEP(*crtbegin.o(.ctors)) KEEP(*(EXCLUDE_FILE (*crtend.o) .ctors)) @@ -109,7 +107,7 @@ SECTIONS KEEP(*crtend.o(.ctors)) } :data - .dtors ALIGN(4K) : AT (ADDR (.dtors) - TEACHOS_HIGH) + .dtors ALIGN(4K) : AT (ADDR (.dtors)) { KEEP(*crtbegin.o(.dtors)) KEEP(*(EXCLUDE_FILE (*crtend.o) .dtors)) @@ -117,12 +115,12 @@ SECTIONS KEEP(*crtend.o(.dtors)) } - .data ALIGN(4K) : AT (ADDR (.data) - TEACHOS_HIGH) + .data ALIGN(4K) : AT (ADDR (.data)) { *(.data*) } - .bss ALIGN(4K) : AT (ADDR (.bss) - TEACHOS_HIGH) + .bss ALIGN(4K) : AT (ADDR (.bss)) { *(COMMON) *(.bss*) @@ -133,7 +131,7 @@ SECTIONS * symbols to mark the end of our loaded image. ***************************************************************************/ _end_virtual = ADDR(.bss) + SIZEOF(.bss); - _end_linear = _end_virtual - TEACHOS_HIGH; + _end_linear = _end_virtual; /DISCARD/ : { *(.comment) } } diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 7b4e193..0c21c66 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -17,8 +17,8 @@ * * We need: * - A single PML 4 (since we will only use 4-level paging) - * - 2 PML 3s (since we need to map high (-2GiB) and low (1+MiB) memory) - * - 2 PML 2s (since we need to map high (-2GiB) and low (1+MiB) memory) + * - 2 PML 3s (since we need to map low (1+MiB) memory) + * - 2 PML 2s (since we need to map low (1+MiB) memory) */ .global page_map_level_4 @@ -26,13 +26,9 @@ page_map_level_4: .skip 512 * 8 .global page_map_level_3_low page_map_level_3_low: .skip 512 * 8 -.global page_map_level_3_high -page_map_level_3_high: .skip 512 * 8 .global page_map_level_2_low page_map_level_2_low: .skip 512 * 8 -.global page_map_level_2_high -page_map_level_2_high: .skip 512 * 8 /** * Reserve some space for the Multiboot 2 information pointer. @@ -306,10 +302,7 @@ enable_sse: * * 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. Note that we also map memory both in the low and high - * virtual address ranges, giving us two ways of accessing it. We need to do - * this, because the bootstrapping code lives in low memory, while the rest of - * the kernel will reside on the high end. + * page map entries. */ prepare_page_maps: /* Add an entry to the PML4, pointing to the low PML3 */ @@ -317,21 +310,11 @@ prepare_page_maps: or $0x3, %eax mov %eax, (page_map_level_4 + ((0x0000000000100000 >> 39) & 0x1ff) * 8) - /* Add an entry to the PML4, pointing to the high PML3 */ - mov $page_map_level_3_high, %eax - or $0x3, %eax - mov %eax, (page_map_level_4 + ((0xffffffff80100000 >> 39) & 0x1ff) * 8) - /* Add an entry to the low PML3, pointing to the low PML2 */ mov $page_map_level_2_low, %eax or $0x3, %eax mov %eax, (page_map_level_3_low + ((0x0000000000100000 >> 30) & 0x1ff) * 8) - /* Add an entry to the high PML3, pointing to the high PML2 */ - mov $page_map_level_2_high, %eax - or $0x3, %eax - mov %eax, (page_map_level_3_high + ((0xffffffff80100000 >> 30) & 0x1ff) * 8) - xor %ecx, %ecx mov $_end_linear, %esi @@ -343,7 +326,6 @@ prepare_page_maps: mul %ecx or $((1 << 0) | (1 << 1) | (1 << 7)), %eax mov %eax, page_map_level_2_low(,%ecx,8) - mov %eax, page_map_level_2_high(,%ecx,8) inc %ecx cmp %esi, %ecx diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 4d6296a..e867bad 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -9,47 +9,28 @@ namespace teachos::arch::kernel auto print_mem_info(arch::memory::memory_info * mem_info) -> void { using namespace video::vga; - auto mem_lower = mem_info->mem_lower; - text::write("Lower memory (kB): ", text::common_attributes::green_on_black); - text::write_number(mem_lower, text::common_attributes::green_on_black); - auto mem_upper = mem_info->mem_upper; - text::write("Upper memory (kB): ", text::common_attributes::green_on_black); - text::write_number(mem_upper, text::common_attributes::green_on_black); } auto print_memory_map(arch::memory::memory_map * mminfo) -> void { using namespace video::vga; - uint32_t const entry_size = mminfo->entry_size; - text::write("Entry Size: ", text::common_attributes::green_on_black); - text::write_number(entry_size, text::common_attributes::green_on_black); - - uint32_t const entry_version = mminfo->entry_version; - text::write("Version: ", text::common_attributes::green_on_black); - text::write_number(entry_version, text::common_attributes::green_on_black); - - uint32_t const remaining_size = mminfo->tag.size - (4 * sizeof(uint32_t)); - uint32_t const entry_amount = remaining_size / entry_size; + auto entry_size = mminfo->entry_size; + auto entry_version = mminfo->entry_version; + auto remaining_size = mminfo->tag.size - (4 * sizeof(uint32_t)); + auto entry_amount = remaining_size / entry_size; auto begin = &mminfo->entries; auto end = begin + entry_amount; - for (auto entry = begin; entry != end; ++entry) + for (auto entry = begin; entry != end; + entry = (teachos::arch::memory::memory_area *)(((uint8_t *)entry) + ((entry_size + 7) & ~7))) { - text::write("Base Address: ", text::common_attributes::green_on_black); - text::write_number(entry->base_addr, text::common_attributes::green_on_black); - - text::write("Length: ", text::common_attributes::green_on_black); - text::write_number(entry->length, text::common_attributes::green_on_black); - - text::write("Type: ", text::common_attributes::green_on_black); - text::write_number(static_cast::type>(entry->type), - text::common_attributes::green_on_black); - - text::write("Reserved: ", text::common_attributes::green_on_black); - text::write_number(entry->reserved, text::common_attributes::green_on_black); + auto base_addr = entry->base_addr; + auto length = entry->length; + auto type = entry->type; + auto reserved = entry->reserved; } } @@ -57,61 +38,33 @@ namespace teachos::arch::kernel { using namespace video::vga; - uint16_t const num = symbol->num; - text::write("Number of entries: ", text::common_attributes::green_on_black); - text::write_number(num, text::common_attributes::green_on_black); - - uint16_t const entsize = symbol->entsize; - text::write("Entry Size: ", text::common_attributes::green_on_black); - text::write_number(entsize, text::common_attributes::green_on_black); - - uint16_t const shndx = symbol->shndx; - text::write("Section index: ", text::common_attributes::green_on_black); - text::write_number(shndx, text::common_attributes::green_on_black); + auto num = symbol->num; + auto entsize = symbol->entsize; + auto shndx = symbol->shndx; auto begin = &symbol->sections; auto end = begin + num; - for (auto section = begin; section != end; ++section) - { - uint32_t const sh_name = section->sh_name; - text::write("Section name: ", text::common_attributes::green_on_black); - text::write_number(sh_name, text::common_attributes::green_on_black); - - uint32_t const sh_type = section->sh_type; - text::write("Section type: ", text::common_attributes::green_on_black); - text::write_number(sh_type, text::common_attributes::green_on_black); - - uint64_t const sh_flags = section->sh_flags; - text::write("Section flags: ", text::common_attributes::green_on_black); - text::write_number(sh_flags, text::common_attributes::green_on_black); - uint64_t const sh_addr = section->sh_addr; - text::write("Section address: ", text::common_attributes::green_on_black); - text::write_number(sh_addr, text::common_attributes::green_on_black); - - uint64_t const sh_offset = section->sh_offset; - text::write("Section offset: ", text::common_attributes::green_on_black); - text::write_number(sh_offset, text::common_attributes::green_on_black); - - uint64_t const sh_size = section->sh_size; - text::write("Section size: ", text::common_attributes::green_on_black); - text::write_number(sh_size, text::common_attributes::green_on_black); - - uint32_t const sh_link = section->sh_link; - text::write("Section link: ", text::common_attributes::green_on_black); - text::write_number(sh_link, text::common_attributes::green_on_black); - - uint32_t const sh_info = section->sh_info; - text::write("Section info: ", text::common_attributes::green_on_black); - text::write_number(sh_info, text::common_attributes::green_on_black); - - uint64_t const sh_addralign = section->sh_addralign; - text::write("Section address align: ", text::common_attributes::green_on_black); - text::write_number(sh_addralign, text::common_attributes::green_on_black); - - uint64_t const sh_entsize = section->sh_entsize; - text::write("Section entry size: ", text::common_attributes::green_on_black); - text::write_number(sh_entsize, text::common_attributes::green_on_black); + /* + * Loop over the elf section to access the information needed. + * Sections are defined in the header file and are padded so that each + * Section starts at an 8-bytes aligned adress. + * + * The increment part aligns the size to an 8-byte address. + */ + for (auto section = begin; section != end; + section = (teachos::arch::memory::elf_section_header *)(((uint8_t *)section) + ((entsize + 7) & ~7))) + { + auto sh_name = section->sh_name; + auto sh_type = section->sh_type; + auto sh_flags = section->sh_flags; + auto sh_addr = section->sh_addr; + auto sh_offset = section->sh_offset; + auto sh_size = section->sh_size; + auto sh_link = section->sh_link; + auto sh_info = section->sh_info; + auto sh_addralign = section->sh_addralign; + auto sh_entsize = section->sh_entsize; } } @@ -127,11 +80,8 @@ namespace teachos::arch::kernel (arch::memory::multi_boot_info *)arch::boot::multiboot_information_pointer; auto multiboot_tag = &(multiboot_information_pointer->tags); - text::write("Multiboot Start: ", text::common_attributes::green_on_black); - text::write_number(arch::boot::multiboot_information_pointer, text::common_attributes::green_on_black); - text::write("Multiboot End: ", text::common_attributes::green_on_black); - text::write_number(arch::boot::multiboot_information_pointer + multiboot_information_pointer->total_size, - text::common_attributes::green_on_black); + auto multiboot_start = arch::boot::multiboot_information_pointer; + auto multiboot_end = arch::boot::multiboot_information_pointer + multiboot_information_pointer->total_size; /* * Loop over the multiboot2 tags to access the information needed. -- cgit v1.2.3 From f044a1740f49d632d1436df949fa2285918e5937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 6 Oct 2024 08:53:21 +0000 Subject: Remove unused variable declarations --- arch/x86_64/src/kernel/main.cpp | 42 ++++++++--------------------------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index e867bad..3436127 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -8,42 +8,28 @@ namespace teachos::arch::kernel { auto print_mem_info(arch::memory::memory_info * mem_info) -> void { - using namespace video::vga; - auto mem_lower = mem_info->mem_lower; - auto mem_upper = mem_info->mem_upper; + video::vga::text::write("Memory info low: ", video::vga::text::common_attributes::green_on_black); + video::vga::text::write_number(mem_info->mem_lower, video::vga::text::common_attributes::green_on_black); } auto print_memory_map(arch::memory::memory_map * mminfo) -> void { - using namespace video::vga; - - auto entry_size = mminfo->entry_size; - auto entry_version = mminfo->entry_version; auto remaining_size = mminfo->tag.size - (4 * sizeof(uint32_t)); - auto entry_amount = remaining_size / entry_size; + auto entry_amount = remaining_size / mminfo->entry_size; auto begin = &mminfo->entries; auto end = begin + entry_amount; for (auto entry = begin; entry != end; - entry = (teachos::arch::memory::memory_area *)(((uint8_t *)entry) + ((entry_size + 7) & ~7))) + entry = (teachos::arch::memory::memory_area *)(((uint8_t *)entry) + ((mminfo->entry_size + 7) & ~7))) { - auto base_addr = entry->base_addr; - auto length = entry->length; - auto type = entry->type; - auto reserved = entry->reserved; + video::vga::text::write("Looping Memory area", video::vga::text::common_attributes::green_on_black); } } auto print_elf_sections(arch::memory::elf_symbols_section * symbol) -> void { - using namespace video::vga; - - auto num = symbol->num; - auto entsize = symbol->entsize; - auto shndx = symbol->shndx; - auto begin = &symbol->sections; - auto end = begin + num; + auto end = begin + symbol->num; /* * Loop over the elf section to access the information needed. @@ -53,18 +39,9 @@ namespace teachos::arch::kernel * The increment part aligns the size to an 8-byte address. */ for (auto section = begin; section != end; - section = (teachos::arch::memory::elf_section_header *)(((uint8_t *)section) + ((entsize + 7) & ~7))) + section = (teachos::arch::memory::elf_section_header *)(((uint8_t *)section) + ((symbol->entsize + 7) & ~7))) { - auto sh_name = section->sh_name; - auto sh_type = section->sh_type; - auto sh_flags = section->sh_flags; - auto sh_addr = section->sh_addr; - auto sh_offset = section->sh_offset; - auto sh_size = section->sh_size; - auto sh_link = section->sh_link; - auto sh_info = section->sh_info; - auto sh_addralign = section->sh_addralign; - auto sh_entsize = section->sh_entsize; + video::vga::text::write("Looping Code section", video::vga::text::common_attributes::green_on_black); } } @@ -80,9 +57,6 @@ namespace teachos::arch::kernel (arch::memory::multi_boot_info *)arch::boot::multiboot_information_pointer; auto multiboot_tag = &(multiboot_information_pointer->tags); - auto multiboot_start = arch::boot::multiboot_information_pointer; - auto multiboot_end = arch::boot::multiboot_information_pointer + multiboot_information_pointer->total_size; - /* * Loop over the multiboot2 tags to access the information needed. * Tags are defined in the header file and are padded so that each -- cgit v1.2.3 From 8e3c15daad14dfba76444d83bc4133acd00eaf8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 6 Oct 2024 09:12:40 +0000 Subject: Revert 8 byte aligning --- arch/x86_64/src/kernel/main.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 3436127..d94cbba 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -19,8 +19,7 @@ namespace teachos::arch::kernel auto begin = &mminfo->entries; auto end = begin + entry_amount; - for (auto entry = begin; entry != end; - entry = (teachos::arch::memory::memory_area *)(((uint8_t *)entry) + ((mminfo->entry_size + 7) & ~7))) + for (auto entry = begin; entry != end; ++entry) { video::vga::text::write("Looping Memory area", video::vga::text::common_attributes::green_on_black); } @@ -30,16 +29,7 @@ namespace teachos::arch::kernel { auto begin = &symbol->sections; auto end = begin + symbol->num; - - /* - * Loop over the elf section to access the information needed. - * Sections are defined in the header file and are padded so that each - * Section starts at an 8-bytes aligned adress. - * - * The increment part aligns the size to an 8-byte address. - */ - for (auto section = begin; section != end; - section = (teachos::arch::memory::elf_section_header *)(((uint8_t *)section) + ((symbol->entsize + 7) & ~7))) + for (auto section = begin; section != end; ++section) { video::vga::text::write("Looping Code section", video::vga::text::common_attributes::green_on_black); } -- cgit v1.2.3 From 1b33fc5746be4d23b1c4adacc02263fbcf994524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 6 Oct 2024 09:58:17 +0000 Subject: Add assert method --- arch/x86_64/src/kernel/main.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index d94cbba..fa1e464 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -6,6 +6,15 @@ namespace teachos::arch::kernel { + auto assert(bool condition) -> void + { + video::vga::text::write("Assert failed", video::vga::text::common_attributes::green_on_black); + while (!condition) + { + ; + } + } + auto print_mem_info(arch::memory::memory_info * mem_info) -> void { video::vga::text::write("Memory info low: ", video::vga::text::common_attributes::green_on_black); @@ -14,6 +23,10 @@ namespace teachos::arch::kernel auto print_memory_map(arch::memory::memory_map * mminfo) -> void { + auto expected_entry_size = mminfo->entry_size; + constexpr auto actual_size = sizeof(arch::memory::memory_area); + assert(expected_entry_size == actual_size); + auto remaining_size = mminfo->tag.size - (4 * sizeof(uint32_t)); auto entry_amount = remaining_size / mminfo->entry_size; -- cgit v1.2.3 From 241c17a52e3954a6c1cf8d38f402d240070a5818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 6 Oct 2024 11:55:31 +0000 Subject: Use alignas instead of seperate variable in struct for padding --- arch/x86_64/include/arch/memory/multiboot.hpp | 41 ++------------------------- 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index baad25b..a2d6e9d 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -53,13 +53,12 @@ namespace teachos::arch::memory struct multi_boot_info { uint32_t total_size; - uint32_t reserved; /* * field "tags" is an array of multi_boot_tag, however the array is never * being accessed by index we don't know the real size at compile-time, * and using an array definition with size 0 produces a compiler error. */ - struct multi_boot_tag tags; + alignas(8) struct multi_boot_tag tags; }; enum class memory_area_type : uint32_t @@ -75,8 +74,7 @@ namespace teachos::arch::memory { uint64_t base_addr; uint64_t length; - memory_area_type type; - uint32_t reserved; + alignas(8) memory_area_type type; }; struct memory_map @@ -92,8 +90,6 @@ namespace teachos::arch::memory struct memory_area entries; }; -#define EI_NIDENT 16 - /* ELF standard typedefs (yet more proof that was way overdue) */ typedef uint16_t Elf64_Half; typedef int16_t Elf64_SHalf; @@ -106,36 +102,6 @@ namespace teachos::arch::memory typedef uint64_t Elf64_Addr; typedef uint16_t Elf64_Section; - struct executable_header - { - unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ - Elf64_Half e_type; /* Object file type */ - Elf64_Half e_machine; /* Architecture */ - Elf64_Word e_version; /* Object file version */ - Elf64_Addr e_entry; /* Entry point virtual address */ - Elf64_Off e_phoff; /* Program header table file offset */ - Elf64_Off e_shoff; /* Section header table file offset */ - Elf64_Word e_flags; /* Processor-specific flags */ - Elf64_Half e_ehsize; /* ELF header size in bytes */ - Elf64_Half e_phentsize; /* Program header table entry size */ - Elf64_Half e_phnum; /* Program header table entry count */ - Elf64_Half e_shentsize; /* Section header table entry size */ - Elf64_Half e_shnum; /* Section header table entry count */ - Elf64_Half e_shstrndx; /* Section header string table index */ - }; - - struct program_header - { - Elf64_Word p_type; /* Segment type */ - Elf64_Word p_flags; /* Segment flags */ - Elf64_Off p_offset; /* Segment file offset */ - Elf64_Addr p_vaddr; /* Segment virtual address */ - Elf64_Addr p_paddr; /* Segment physical address */ - Elf64_Xword p_filesz; /* Segment size in file */ - Elf64_Xword p_memsz; /* Segment size in memory */ - Elf64_Xword p_align; /* Segment alignment */ - }; - struct elf_section_header { Elf64_Word sh_name; /* Section name (string tbl index) */ @@ -166,8 +132,7 @@ namespace teachos::arch::memory uint16_t num; uint16_t entsize; uint16_t shndx; - uint16_t reserved; - struct elf_section_header sections; + alignas(8) struct elf_section_header sections; }; } // namespace teachos::arch::memory -- cgit v1.2.3 From b9c5aea495653bb9fc347fa6ba5976b42510af53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 6 Oct 2024 12:40:33 +0000 Subject: Added elf section type enum --- arch/x86_64/include/arch/memory/multiboot.hpp | 70 ++++++++++++++------------- arch/x86_64/src/kernel/main.cpp | 8 ++- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index a2d6e9d..c808213 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_HPP #define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_HPP +#include #include namespace teachos::arch::memory @@ -90,48 +91,51 @@ namespace teachos::arch::memory struct memory_area entries; }; - /* ELF standard typedefs (yet more proof that was way overdue) */ - typedef uint16_t Elf64_Half; - typedef int16_t Elf64_SHalf; - typedef uint32_t Elf64_Word; - typedef int32_t Elf64_Sword; - typedef uint64_t Elf64_Xword; - typedef int64_t Elf64_Sxword; - - typedef uint64_t Elf64_Off; - typedef uint64_t Elf64_Addr; - typedef uint16_t Elf64_Section; - - struct elf_section_header + /** + * https://refspecs.linuxfoundation.org/LSB_2.1.0/LSB-Core-generic/LSB-Core-generic/elftypes.html + */ + enum class elf_section_type : uint32_t { - Elf64_Word sh_name; /* Section name (string tbl index) */ - Elf64_Word sh_type; /* Section type */ - Elf64_Xword sh_flags; /* Section flags */ - Elf64_Addr sh_addr; /* Section virtual addr at execution */ - Elf64_Off sh_offset; /* Section file offset */ - Elf64_Xword sh_size; /* Section size in bytes */ - Elf64_Word sh_link; /* Link to another section */ - Elf64_Word sh_info; /* Additional section information */ - Elf64_Xword sh_addralign; /* Section alignment */ - Elf64_Xword sh_entsize; /* Entry size if section holds table */ + INACTIVE, + PROGRAMM, + SYMBOL_TABLE, + STRING_TABLE, + RELOCATION_ENTRY_WITH_EXPLICIT_ADDENDS, + SYMBOL_HASH_TABLE, + DYNAMIC, + NOTE, + EMPTY, + RELOCATION_ENTRY_WITHOUT_EXPLICIT_ADDENDS, + UNSPECIFIED, + DYNAMIC_SYMBOL, + INITALIZATION_FUNCTION_ARRAY = 14, + TERMINATION_FUNCTION_ARRAY, + PRE_INITALIZATION_FUNCTION_ARRAY }; - struct elf_symbol + struct elf_section_header { - Elf64_Word st_name; /* Symbol name (string tbl index) */ - unsigned char st_info; /* Symbol type and binding */ - unsigned char st_other; /* Symbol visibility */ - Elf64_Section st_shndx; /* Section index */ - Elf64_Addr st_value; /* Symbol value */ - Elf64_Xword st_size; /* Symbol size */ + uint32_t sh_name; /* Section name (string tbl index) */ + elf_section_type sh_type; /* Section type */ + std::bitset<64U> sh_flags; /* Section flags */ + uint64_t sh_addr; /* Section virtual addr at execution */ + uint64_t sh_offset; /* Section file offset */ + uint64_t sh_size; /* Section size in bytes */ + uint32_t sh_link; /* Link to another section */ + uint32_t sh_info; /* Additional section information */ + uint64_t sh_addralign; /* Section alignment */ + uint64_t sh_entsize; /* Entry size if section holds table */ }; + /** + * https://gist.github.com/x0nu11byt3/bcb35c3de461e5fb66173071a2379779 + */ struct elf_symbols_section { multi_boot_tag tag; - uint16_t num; - uint16_t entsize; - uint16_t shndx; + uint32_t num; + uint32_t entsize; + uint32_t shndx; alignas(8) struct elf_section_header sections; }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index fa1e464..481264c 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -24,8 +24,8 @@ namespace teachos::arch::kernel auto print_memory_map(arch::memory::memory_map * mminfo) -> void { auto expected_entry_size = mminfo->entry_size; - constexpr auto actual_size = sizeof(arch::memory::memory_area); - assert(expected_entry_size == actual_size); + constexpr auto actual_entry_size = sizeof(arch::memory::memory_area); + assert(expected_entry_size == actual_entry_size); auto remaining_size = mminfo->tag.size - (4 * sizeof(uint32_t)); auto entry_amount = remaining_size / mminfo->entry_size; @@ -40,6 +40,10 @@ namespace teachos::arch::kernel auto print_elf_sections(arch::memory::elf_symbols_section * symbol) -> void { + auto expected_entry_size = symbol->entsize; + constexpr auto actual_entry_size = sizeof(arch::memory::elf_section_header); + assert(expected_entry_size == actual_entry_size); + auto begin = &symbol->sections; auto end = begin + symbol->num; for (auto section = begin; section != end; ++section) -- cgit v1.2.3 From 951b314b655781dc59aee24cf952d03bf3b3ee83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 6 Oct 2024 13:32:14 +0000 Subject: Interpret files as bitset wrapper --- arch/x86_64/include/arch/memory/multiboot.hpp | 64 ++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index c808213..f1f0613 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -113,18 +113,62 @@ namespace teachos::arch::memory PRE_INITALIZATION_FUNCTION_ARRAY }; + /** + * https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html + */ + class elf_section_flags + { + public: + elf_section_flags(uint64_t flags) + : flags(flags) + { + // Nothing to do + } + + auto writeable() -> bool { return is_bit_set(0); } + + auto occupies_memory() -> bool { return is_bit_set(1); } + + auto is_executable() -> bool { return is_bit_set(2); } + + auto contains_duplicate_data() -> bool { return is_bit_set(4); } + + auto contains_strings() -> bool { return is_bit_set(5); } + + auto section_header_info_is_section_header_table_index() -> bool { return is_bit_set(6); } + + auto preserve_ordering_after_combination() -> bool { return is_bit_set(7); } + + auto requires_special_os_processing() -> bool { return is_bit_set(8); } + + auto is_section_group_member() -> bool { return is_bit_set(9); } + + auto holds_thread_local_data() -> bool { return is_bit_set(10); } + + auto is_compressed() -> bool { return is_bit_set(11); } + + auto has_special_ordering_requirements() -> bool { return is_bit_set(30); } + + auto is_excluded_unless_referenced_or_allocated() -> bool { return is_bit_set(31); } + + private: + auto is_bit_set(uint8_t index) -> bool { return flags[index] == 1; } + + std::bitset<64U> flags; + }; + struct elf_section_header { - uint32_t sh_name; /* Section name (string tbl index) */ - elf_section_type sh_type; /* Section type */ - std::bitset<64U> sh_flags; /* Section flags */ - uint64_t sh_addr; /* Section virtual addr at execution */ - uint64_t sh_offset; /* Section file offset */ - uint64_t sh_size; /* Section size in bytes */ - uint32_t sh_link; /* Link to another section */ - uint32_t sh_info; /* Additional section information */ - uint64_t sh_addralign; /* Section alignment */ - uint64_t sh_entsize; /* Entry size if section holds table */ + uint32_t sh_name; /* Section name (string tbl index) */ + elf_section_type sh_type; /* Section type */ + elf_section_flags sh_flags; /* Section flags */ + uint64_t sh_addr; /* Section virtual addr at execution */ + uint64_t sh_offset; /* Section file offset */ + uint64_t sh_size; /* Section size in bytes */ + uint32_t sh_link; /* Link to another section */ + uint32_t sh_info; /* Additional section information */ + uint64_t sh_addralign; /* Section alignment */ + uint64_t sh_entsize; /* Entry size if section holds table */ }; /** -- cgit v1.2.3 From 78153377d8a964d6b7290d966e5c1d30369abc2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 6 Oct 2024 13:40:24 +0000 Subject: Improve naming --- arch/x86_64/include/arch/memory/multiboot.hpp | 48 ++++++++++++++------------- arch/x86_64/src/kernel/main.cpp | 4 +-- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index f1f0613..37b10f0 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -43,14 +43,6 @@ namespace teachos::arch::memory uint32_t size; }; - struct memory_info - { - uint32_t type; - uint32_t size; - uint32_t mem_lower; - uint32_t mem_upper; - }; - struct multi_boot_info { uint32_t total_size; @@ -62,6 +54,13 @@ namespace teachos::arch::memory alignas(8) struct multi_boot_tag tags; }; + struct memory_info + { + multi_boot_tag tag; + uint32_t mem_lower; + uint32_t mem_upper; + }; + enum class memory_area_type : uint32_t { AVAILABLE = 1, @@ -73,8 +72,8 @@ namespace teachos::arch::memory struct memory_area { - uint64_t base_addr; - uint64_t length; + uint64_t base_address; + uint64_t area_length; alignas(8) memory_area_type type; }; @@ -157,18 +156,21 @@ namespace teachos::arch::memory std::bitset<64U> flags; }; + /** + * https://docs.oracle.com/cd/E19455-01/806-3773/elf-2/index.html + */ struct elf_section_header { - uint32_t sh_name; /* Section name (string tbl index) */ - elf_section_type sh_type; /* Section type */ - elf_section_flags sh_flags; /* Section flags */ - uint64_t sh_addr; /* Section virtual addr at execution */ - uint64_t sh_offset; /* Section file offset */ - uint64_t sh_size; /* Section size in bytes */ - uint32_t sh_link; /* Link to another section */ - uint32_t sh_info; /* Additional section information */ - uint64_t sh_addralign; /* Section alignment */ - uint64_t sh_entsize; /* Entry size if section holds table */ + uint32_t name_table_index; + elf_section_type type; + elf_section_flags flags; + uint64_t virtual_address; + uint64_t file_offset; + uint64_t section_size; + uint32_t other_section; + uint32_t additional_information; + uint64_t address_alignment; + uint64_t fixed_table_entry_size; }; /** @@ -177,9 +179,9 @@ namespace teachos::arch::memory struct elf_symbols_section { multi_boot_tag tag; - uint32_t num; - uint32_t entsize; - uint32_t shndx; + uint32_t number_of_sections; + uint32_t entry_size; + uint32_t section_index; alignas(8) struct elf_section_header sections; }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 481264c..636ddf2 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -40,12 +40,12 @@ namespace teachos::arch::kernel auto print_elf_sections(arch::memory::elf_symbols_section * symbol) -> void { - auto expected_entry_size = symbol->entsize; + auto expected_entry_size = symbol->entry_size; constexpr auto actual_entry_size = sizeof(arch::memory::elf_section_header); assert(expected_entry_size == actual_entry_size); auto begin = &symbol->sections; - auto end = begin + symbol->num; + auto end = begin + symbol->number_of_sections; for (auto section = begin; section != end; ++section) { video::vga::text::write("Looping Code section", video::vga::text::common_attributes::green_on_black); -- cgit v1.2.3 From a6018f84cc8971859d90109740fbada8d77ff5a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 8 Oct 2024 07:58:53 +0000 Subject: Add more asserts for elf sections --- arch/x86_64/include/arch/memory/multiboot.hpp | 46 ++++++++++++++++++--------- arch/x86_64/src/kernel/main.cpp | 19 ++++++++++- 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index 37b10f0..f6ff480 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -124,40 +124,43 @@ namespace teachos::arch::memory // Nothing to do } - auto writeable() -> bool { return is_bit_set(0); } + auto writeable() const -> bool { return is_bit_set(0); } - auto occupies_memory() -> bool { return is_bit_set(1); } + auto occupies_memory() const -> bool { return is_bit_set(1); } - auto is_executable() -> bool { return is_bit_set(2); } + auto is_executable() const -> bool { return is_bit_set(2); } - auto contains_duplicate_data() -> bool { return is_bit_set(4); } + auto contains_duplicate_data() const -> bool { return is_bit_set(4); } - auto contains_strings() -> bool { return is_bit_set(5); } + auto contains_strings() const -> bool { return is_bit_set(5); } - auto section_header_info_is_section_header_table_index() -> bool { return is_bit_set(6); } + auto section_header_info_is_section_header_table_index() const -> bool { return is_bit_set(6); } - auto preserve_ordering_after_combination() -> bool { return is_bit_set(7); } + auto preserve_ordering_after_combination() const -> bool { return is_bit_set(7); } - auto requires_special_os_processing() -> bool { return is_bit_set(8); } + auto requires_special_os_processing() const -> bool { return is_bit_set(8); } - auto is_section_group_member() -> bool { return is_bit_set(9); } + auto is_section_group_member() const -> bool { return is_bit_set(9); } - auto holds_thread_local_data() -> bool { return is_bit_set(10); } + auto holds_thread_local_data() const -> bool { return is_bit_set(10); } - auto is_compressed() -> bool { return is_bit_set(11); } + auto is_compressed() const -> bool { return is_bit_set(11); } - auto has_special_ordering_requirements() -> bool { return is_bit_set(30); } + auto has_special_ordering_requirements() const -> bool { return is_bit_set(30); } - auto is_excluded_unless_referenced_or_allocated() -> bool { return is_bit_set(31); } + auto is_excluded_unless_referenced_or_allocated() const -> bool { return is_bit_set(31); } + + auto operator==(elf_section_flags const & other) const -> bool { return flags == other.flags; } private: - auto is_bit_set(uint8_t index) -> bool { return flags[index] == 1; } + auto is_bit_set(uint8_t index) const -> bool { return flags[index] == 1; } std::bitset<64U> flags; }; /** - * https://docs.oracle.com/cd/E19455-01/806-3773/elf-2/index.html + * @brief Defines the data included in a section header, where each section has exactly one section header. + * See https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html for more information */ struct elf_section_header { @@ -171,6 +174,19 @@ namespace teachos::arch::memory uint32_t additional_information; uint64_t address_alignment; uint64_t fixed_table_entry_size; + + /** + * @brief Detect whether e section header is inactive or not, should always be the case for the first entry in the + * sections table + * @return Whether the current section header is actually null or not, requires all fields besides section_size and + * other_section to actually contain 0 + */ + auto is_null() const -> bool + { + return name_table_index == 0U && type == elf_section_type::UNSPECIFIED && flags == 0U && virtual_address == 0U && + file_offset == 0U && additional_information == 0U && address_alignment == 0U && + fixed_table_entry_size == 0U; + } }; /** diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 636ddf2..2ba4fe2 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -11,7 +11,12 @@ namespace teachos::arch::kernel video::vga::text::write("Assert failed", video::vga::text::common_attributes::green_on_black); while (!condition) { - ; + // Trick the compiler into thinking the variable is changes at run time, + // to prevent the while loop being optimized away + // See + // https://stackoverflow.com/questions/9495856/how-to-prevent-g-from-optimizing-out-a-loop-controlled-by-a-variable-that-can + // for mroe information. + asm volatile("" : "+g"(condition)); } } @@ -44,8 +49,20 @@ namespace teachos::arch::kernel constexpr auto actual_entry_size = sizeof(arch::memory::elf_section_header); assert(expected_entry_size == actual_entry_size); + auto expected_total_size = symbol->tag.size; + auto actual_total_entry_size = actual_entry_size * symbol->number_of_sections; + constexpr auto actual_total_section_size = + sizeof(arch::memory::elf_symbols_section) - actual_entry_size - sizeof(uint32_t); + auto actual_total_size = actual_total_entry_size + actual_total_section_size; + assert(expected_total_size == actual_total_size); + auto begin = &symbol->sections; auto end = begin + symbol->number_of_sections; + // TODO: Last value is completly wrong, should show 0 but shows huge value for size of entries in the table of the + // SHT_NULL elf section entry. Memory around value also make no sense and look even worse? But according to api + // value should be zero :( + // assert(begin->is_null()); + for (auto section = begin; section != end; ++section) { video::vga::text::write("Looping Code section", video::vga::text::common_attributes::green_on_black); -- cgit v1.2.3 From 8773024d1b4e756fe5d3494479247c64c7ad8491 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 8 Oct 2024 09:51:26 +0000 Subject: begin implementing frame allocator --- .../x86_64/include/arch/memory/frame_allocator.hpp | 72 +++++++++++++++++----- arch/x86_64/src/memory/frame_allocator.cpp | 70 ++++++++++++++++++++- 2 files changed, 126 insertions(+), 16 deletions(-) diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp index 8dee848..35d7360 100644 --- a/arch/x86_64/include/arch/memory/frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/frame_allocator.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP #define TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP +#include "multiboot.hpp" #include #include @@ -8,20 +9,26 @@ namespace teachos::arch::memory { namespace { - const size_t PAGE_FRAME_SIZE = 4096U; + const std::size_t PAGE_FRAME_SIZE = 4096U; } struct frame { - size_t frame_number; + std::size_t frame_number; - frame(size_t frame_number) + frame(std::size_t frame_number) : frame_number(frame_number) { // Nothing to do } - auto containing_address(size_t address) -> frame { return frame{address / PAGE_FRAME_SIZE}; } + static auto containing_address(std::size_t address) -> frame { return frame{address / PAGE_FRAME_SIZE}; } + + constexpr bool operator==(const frame & other) const noexcept { return frame_number == other.frame_number; } + constexpr bool operator>(const frame & other) const noexcept { return frame_number > other.frame_number; } + constexpr bool operator<(const frame & other) const noexcept { return frame_number < other.frame_number; } + constexpr bool operator>=(const frame & other) const noexcept { return frame_number >= other.frame_number; } + constexpr bool operator<=(const frame & other) const noexcept { return frame_number <= other.frame_number; } }; struct frame_allocator @@ -30,18 +37,53 @@ namespace teachos::arch::memory virtual auto deallocate_frame(frame frame) -> void = 0; }; - struct area_frame_allocator : public frame_allocator + // TODO: FIX CONCEPT USAGE + // template + // concept FrameAllocator = requires(T t) { + // { t.allocate_frame() } -> std::optional; + // { t.deallocate_frame() } -> void; + // }; + + // template + struct area_frame_allocator : frame_allocator { - frame next_free_frame; - // std::optional current_area; - // memory_area * areas; - frame kernel_start; - frame kernel_end; - frame multiboot_start; - frame multiboot_end; - - auto allocate_frame() -> std::optional override; - auto deallocate_frame(frame frame) -> void override; + frame next_free_frame{0}; //!< The frame after the last allocated one + std::optional current_area{std::nullopt}; //!< The current memory area + arch::memory::memory_area * areas; //!< A list of all memory areas + frame kernel_start; //!< The start address of the kernel code in memory + frame kernel_end; //!< The end address of the kernel code in memory + frame multiboot_start; //!< The start address of the multiboot code in memory + frame multiboot_end; //!< The end address of the multiboot code in memory + + area_frame_allocator(std::size_t kernel_start, std::size_t kernel_end, std::size_t multiboot_start, + std::size_t multiboot_end, arch::memory::memory_area * memory_areas) + : kernel_start(frame{kernel_start}) + , kernel_end(frame{kernel_end}) + , multiboot_start(frame{multiboot_start}) + , multiboot_end(frame{multiboot_end}) + , areas(memory_areas) + { + choose_next_area(); + } + + /** + * @brief Allocate memory be finding and returning a free frame + * + * The frame allocation executes multiple checks before returning + * the frame that is available to allocate. It must at least + * do the following: + * - check if the next_free_frame is within the current_area + * - check if the next_free_frame is actually free + * - update the next_free_frame after finding a free frame + */ + auto allocate_frame() -> std::optional; + auto deallocate_frame(frame frame) -> void; + + private: + /** + * @brief Find the next memory area and write it into current_area + */ + auto choose_next_area() -> void; }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/memory/frame_allocator.cpp b/arch/x86_64/src/memory/frame_allocator.cpp index b9d26a5..b8f53be 100644 --- a/arch/x86_64/src/memory/frame_allocator.cpp +++ b/arch/x86_64/src/memory/frame_allocator.cpp @@ -2,8 +2,76 @@ namespace teachos::arch::memory { - auto area_frame_allocator::allocate_frame() -> std::optional {} + 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) + { + frame frame{next_free_frame.frame_number}; + + struct frame current_area_last_frame = { + frame::containing_address(current_area->base_address + current_area->area_length - 1)}; + + if (next_free_frame > current_area_last_frame) + { + // All frames of current area are used, switch to next area + choose_next_area(); + } + else if (frame >= multiboot_start && frame <= kernel_end) + { + // `frame` is used by the kernel or multiboot information structure + next_free_frame = arch::memory::frame{kernel_end.frame_number + 1}; + } + else + { + // Frame is unused, increment `next_free_frame` and return it + next_free_frame.frame_number += 1; + return frame; + } + + // `frame` was not valid, try it again with the updated `next_free_frame` + return allocate_frame(); + } + + // no free frames left + return std::nullopt; + } auto area_frame_allocator::deallocate_frame(frame frame) -> void {} + namespace + { + auto area_frame_allocator::choose_next_area() -> void + { + current_area = std::nullopt; + + // TODO: Fix this loop as soon as you've created an area iterator + for (const auto & area : areas) + { + std::size_t address = area.base_addr + area.length - 1; + if (frame::containing_address(address) >= next_free_frame) + { + // The `next_free_frame` address is smaller than the last address of the current area + if (!current_area || area.base_addr < current_area->base_address) + { + current_area = area; + } + } + } + + if (current_area) + { + // Update the `next_free_frame` according to the new memory area + frame start_frame = frame::containing_address(current_area->base_address); + if (next_free_frame < start_frame) + { + next_free_frame = start_frame; + } + } + } + + } // namespace } // namespace teachos::arch::memory -- cgit v1.2.3 From 7edd03e9a14a3025b4d2b2ff51d838d20b79b2c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 8 Oct 2024 11:30:01 +0000 Subject: Added doxygen comments to all fields and structs --- arch/x86_64/include/arch/io/port_io.hpp | 1 - .../x86_64/include/arch/memory/frame_allocator.hpp | 86 +++-- arch/x86_64/include/arch/memory/multiboot.hpp | 345 ++++++++++++++------- arch/x86_64/src/kernel/main.cpp | 3 + arch/x86_64/src/memory/multiboot.cpp | 41 +++ 5 files changed, 331 insertions(+), 145 deletions(-) create mode 100644 arch/x86_64/src/memory/multiboot.cpp diff --git a/arch/x86_64/include/arch/io/port_io.hpp b/arch/x86_64/include/arch/io/port_io.hpp index c0f1ef3..1945261 100644 --- a/arch/x86_64/include/arch/io/port_io.hpp +++ b/arch/x86_64/include/arch/io/port_io.hpp @@ -8,7 +8,6 @@ namespace teachos::arch::io { - /** * @brief An I/O port of a given size at a given address. * diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp index 35d7360..3989cdf 100644 --- a/arch/x86_64/include/arch/memory/frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/frame_allocator.hpp @@ -4,6 +4,7 @@ #include "multiboot.hpp" #include #include +#include namespace teachos::arch::memory { @@ -12,51 +13,74 @@ namespace teachos::arch::memory const std::size_t PAGE_FRAME_SIZE = 4096U; } + /** + * @brief Specific frame containing helper functions to determine if a specific address is in that frame or not + */ struct frame { - std::size_t frame_number; + std::size_t frame_number; ///< Index number of the current frame, used to distinguish it from other frames + /** + * @brief Constructor + * + * @param frame_number Index number that should be assigned to this frame + */ frame(std::size_t frame_number) : frame_number(frame_number) { // Nothing to do } + /** + * @brief Returns the frame the given address is contained in + * + * @param address Address we want to get the corresponding frame for + * @return Frame the given address is contained in + */ static auto containing_address(std::size_t address) -> frame { return frame{address / PAGE_FRAME_SIZE}; } - constexpr bool operator==(const frame & other) const noexcept { return frame_number == other.frame_number; } - constexpr bool operator>(const frame & other) const noexcept { return frame_number > other.frame_number; } - constexpr bool operator<(const frame & other) const noexcept { return frame_number < other.frame_number; } - constexpr bool operator>=(const frame & other) const noexcept { return frame_number >= other.frame_number; } - constexpr bool operator<=(const frame & other) const noexcept { return frame_number <= other.frame_number; } - }; + /** + * @brief Defaulted equals operator + */ + constexpr auto operator==(const frame & other) const -> bool = default; - struct frame_allocator - { - virtual auto allocate_frame() -> std::optional = 0; - virtual auto deallocate_frame(frame frame) -> void = 0; + /** + * @brief Defaulted three-way comparsion operator + */ + constexpr auto operator<=>(const frame & other) const -> std::partial_ordering = default; }; - // TODO: FIX CONCEPT USAGE - // template - // concept FrameAllocator = requires(T t) { - // { t.allocate_frame() } -> std::optional; - // { t.deallocate_frame() } -> void; - // }; + template + concept FrameAllocator = requires(T t) { + { t.allocate_frame() } -> std::optional; + { t.deallocate_frame() } -> void; + }; - // template - struct area_frame_allocator : frame_allocator + /** + * @brief Allocates memory using memory areas read from the multiboot2 information pointer + * + */ + struct area_frame_allocator { - frame next_free_frame{0}; //!< The frame after the last allocated one - std::optional current_area{std::nullopt}; //!< The current memory area - arch::memory::memory_area * areas; //!< A list of all memory areas - frame kernel_start; //!< The start address of the kernel code in memory - frame kernel_end; //!< The end address of the kernel code in memory - frame multiboot_start; //!< The start address of the multiboot code in memory - frame multiboot_end; //!< The end address of the multiboot code in memory + frame next_free_frame{0}; //!< The frame after the last allocated one + std::optional current_area{std::nullopt}; //!< The current memory area + memory_area * areas; //!< Pointer to the first element of all memory areas + frame kernel_start; //!< The start address of the kernel code in memory + frame kernel_end; //!< The end address of the kernel code in memory + frame multiboot_start; //!< The start address of the multiboot code in memory + frame multiboot_end; //!< The end address of the multiboot code in memory + /** + * @brief Constructor + * + * @param kernel_start Start address of the kernel code in memory + * @param kernel_end End address of the kernel code in memory + * @param multiboot_start Start address of the multiboot code in memory + * @param multiboot_end End address of the multiboot code in memory + * @param memory_areas Pointer to the first element of all memory areas + */ area_frame_allocator(std::size_t kernel_start, std::size_t kernel_end, std::size_t multiboot_start, - std::size_t multiboot_end, arch::memory::memory_area * memory_areas) + std::size_t multiboot_end, memory_area * memory_areas) : kernel_start(frame{kernel_start}) , kernel_end(frame{kernel_end}) , multiboot_start(frame{multiboot_start}) @@ -67,7 +91,7 @@ namespace teachos::arch::memory } /** - * @brief Allocate memory be finding and returning a free frame + * @brief Allocate memory by finding and returning a free frame * * The frame allocation executes multiple checks before returning * the frame that is available to allocate. It must at least @@ -77,6 +101,12 @@ namespace teachos::arch::memory * - update the next_free_frame after finding a free frame */ auto allocate_frame() -> std::optional; + + /** + * @brief Deallocates a previously allocated frame + * + * @param frame Previously allocated frame that should be allocated + */ auto deallocate_frame(frame frame) -> void; private: diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index f6ff480..5990260 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -6,154 +6,264 @@ namespace teachos::arch::memory { - /* - * Define all multiboot tag types to ther respective values - * The gnu boot information format is defined here: - * https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Boot-information-format + /** + * @brief Defines all possible types a multiboot2 tag structure can have. + * See + * https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Boot-information-format for more information. */ enum class multi_boot_tag_type : uint32_t { - END, - CMDLINE, - BOOT_LOADER_NAME, - MODULE, - BASIC_MEMORY_INFO, - BOOTDEV, - MEMORY_MAP, - VBE, - FRAMEBUFFER, - ELF_SECTIONS, - APM, - EFI32, - EFI64, - SMBIOS, - ACPI_OLD, - ACPI_NEW, - NETWORK, - EFI_MEMORY_MAP, - EFI_BS, - EFI32_IH, - EFI64_IH, - LOAD_BASE_ADDRESS + END, ///< Signals final tag for the multiboot2 information structure + CMDLINE, ///< Contains the command line string + BOOT_LOADER_NAME, ///< Contains the name of the boot loader booting the kernel + MODULE, ///< Indicates the boot module which was loaded along the kernel image + BASIC_MEMORY_INFO, ///< Contains the amount of lower (0MB start address) and upper memory (1MB start address) + BOOTDEV, ///< Indicates which BIOS disk device the hoot loader has loaded the OS image from + MEMORY_MAP, ///< Describes the memory layout of the system with individual areas and their flags + VBE_INFO, ///< Includes information to access and utilize the device GPU + FRAMEBUFFER, ///< VBE framebuffer information + ELF_SECTIONS, ///< Includes list of all section headers from the loaded ELF kernel + APM_INFO, ///< Advanced Power Management information + EFI32, ///< EFI 32 bit system table pointer + EFI64, ///< EFI 64 bit system table pointer + SMBIOS, ///< Contains copy of all Sytem Management BIOS tables + ACPI_OLD, ///< Contains copy of RSDP as defined per ACPI1.0 specification + ACPI_NEW, ///< Contains copy of RSDP as defined per ACPI2.0 or later specification + NETWORK, ///< Contains network information specified specified as DHCP + EFI_MEMORY_MAP, ///< Contains EFI memory map + EFI_BS_NOT_TERMINATED, ///< Indicated ExitBootServies wasn't called + EFI32_IMAGE_HANDLE, ///< EFI 32 bit image handle pointer + EFI64_IMAGE_HANDLE, ///< EFI 64 bit imae handle pointer + LOAD_BASE_ADDRESS ///< Contains image load base physical address }; + /** + * @brief Basic structure that every entry in the multi_boot_tag array of the multi_boot_info struct has to begin + * with. + */ struct multi_boot_tag { - multi_boot_tag_type type; - uint32_t size; + multi_boot_tag_type type; ///< Specific type of this multi_boot_tag entry, used to differentiate handling + uint32_t size; ///< Total size of this multi_boot_tag entry with all fields of the actual type }; + /** + * @brief Basic structure the multiboot_information_pointer points too and which contains all information of + * multiboot2 in the tags array of different types. + */ struct multi_boot_info { - uint32_t total_size; - /* - * field "tags" is an array of multi_boot_tag, however the array is never - * being accessed by index we don't know the real size at compile-time, - * and using an array definition with size 0 produces a compiler error. - */ - alignas(8) struct multi_boot_tag tags; + uint32_t total_size; ///< Total size of all multi_boot_tags and their data + alignas(8) struct multi_boot_tag tags; ///< Specific tags }; + /** + * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type + * multi_boot_tag_type::BASIC_MEMORY_INFO. + */ struct memory_info { - multi_boot_tag tag; - uint32_t mem_lower; - uint32_t mem_upper; + multi_boot_tag tag; ///< Basic multi_boot_tag information + uint32_t mem_lower; ///< Amount of lower memory (0MB start address) + uint32_t mem_upper; ///< Amount of upper memory (1MB start address) }; + /** + * @brief Defines all memory area types possible that the memory region can be in. + */ enum class memory_area_type : uint32_t { - AVAILABLE = 1, - RESERVED, - ACPI_AVAILABLE, - RESERVED_HIBERNATION, - DEFECTIVE + AVAILABLE = 1, ///< Region is available for use by the OS + RESERVED, ///< Region is reserved by firmware or bootloader and should not be used by OS + ACPI_AVAILABLE, ///< Region is reclaimable by OS after ACPI event + RESERVED_HIBERNATION, ///< Region is used for Non-volatile Storage (NVS) + DEFECTIVE ///< Region is defective or unusable }; + /** + * @brief Defines an entry in the entries array of the memory_map struct. + */ struct memory_area { - uint64_t base_address; - uint64_t area_length; - alignas(8) memory_area_type type; + uint64_t base_address; ///< Base address the memory region starts at + uint64_t area_length; ///< Size of the memory region, added to base_address results in the final address + alignas(8) memory_area_type type; ///< Specific type of memory the region can contain }; + /** + * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type + * multi_boot_tag_type::MEMORY_MAP. + */ struct memory_map { - multi_boot_tag tag; - uint32_t entry_size; - uint32_t entry_version; - /* - * field "entries" is an array of memory_area, however the array is never - * being accessed by index, we don't know the real size at compile-time, - * and using an array definition with size 0 produces a compiler error. - */ - struct memory_area entries; + multi_boot_tag tag; ///< Basic multi_boot_tag information + uint32_t entry_size; ///< Size of each entry in the memory_area array. Guaranteed multiple of 8 + uint32_t entry_version; ///< Version of the entries, currently 0 + struct memory_area entries; ///< Specific memory regions }; /** - * https://refspecs.linuxfoundation.org/LSB_2.1.0/LSB-Core-generic/LSB-Core-generic/elftypes.html + * @brief Defines all elf section types an elf section header can have. + * The first section will always be INACTIVE, there can only ever be one DYNAMIC section and only either one + * DYNAMIC_SYMBOL_TABLE or SYMBOL_TABLE. See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html + * for more information. */ enum class elf_section_type : uint32_t { - INACTIVE, - PROGRAMM, - SYMBOL_TABLE, - STRING_TABLE, - RELOCATION_ENTRY_WITH_EXPLICIT_ADDENDS, - SYMBOL_HASH_TABLE, - DYNAMIC, - NOTE, - EMPTY, - RELOCATION_ENTRY_WITHOUT_EXPLICIT_ADDENDS, - UNSPECIFIED, - DYNAMIC_SYMBOL, - INITALIZATION_FUNCTION_ARRAY = 14, - TERMINATION_FUNCTION_ARRAY, - PRE_INITALIZATION_FUNCTION_ARRAY + INACTIVE, ///< (SHT_NULL) Unused, meaning all values are zeroed out + PROGRAMM, ///< (SHT_PROGBITS) Program data + SYMBOL_TABLE, ///< (SHT_SYMBTAB) Contains actual entries pointed to in symbol hash table + STRING_TABLE, ///< (SHT_STRTAB) Contains symbols, section and deubbging null-terminated strings + RELOCATION_ENTRY_WITH_ADDENDS, ///< (SHT_RELA) Only used on 64 bit systems + SYMBOL_HASH_TABLE, ///< (SHT_HASH) Hash table used by dynamic linker to locate symbols + DYNAMIC, ///< (SHT_DYNAMIC) Contains dynamic linking information + NOTE, ///< (SHT_NOTE) Stores information that marks files in some way + EMPTY, ///< (SHT_NOBITS) Program data section, that occupies no space in the file (.bss) + RELOCATION_ENTRY_WITHOUT_ADDENDS, ///< (SHT_REL) Only used on 32 bit systems + UNSPECIFIED, ///< (SHT_SHLIB) Reserved but has unspecified semantics + DYNAMIC_SYMBOL_TABLE, ///< (SHT_DYNSYM) Holds minimal set of symbols adequate for dynamic linking + INITALIZATION_FUNCTION_ARRAY = 14, ///< (SHT_INIT_ARRAY) Array of pointers to intialization functions () -> void + TERMINATION_FUNCTION_ARRAY, ///< (SHT_FINI_ARRAY) Array of pointers to termination functions () -> void + PRE_INITALIZATION_FUNCTION_ARRAY ///< (SHT_PRE_INIT_ARRAY) Array of pointers to functions invoked before other + ///< initalization functions () -> void }; /** - * https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html + * @brief Defines helper function for all states that the elf section flags of an elf section header can + * have. See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html + * See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. */ - class elf_section_flags + struct elf_section_flags { - public: - elf_section_flags(uint64_t flags) + /** + * @brief Constructor. + * + * @param flags Actual value read from the elf section header, which should be converted into a std::bitset, to + * allow reading the state of single bits more easily. + */ + explicit elf_section_flags(uint64_t flags) : flags(flags) { // Nothing to do } - auto writeable() const -> bool { return is_bit_set(0); } + /** + * @brief (SHF_WRITE) Wether the current section is writable or not. Read from bit index 0. + * + * @return Current section is writable. + */ + auto writeable() const -> bool; - auto occupies_memory() const -> bool { return is_bit_set(1); } + /** + * @brief (SHF_ALLOC) Whether the current section occupies memory during execution or not. Read from bit index 1. + * + * @return Current section occupies memory during execution. + */ + auto occupies_memory() const -> bool; - auto is_executable() const -> bool { return is_bit_set(2); } + /** + * @brief (SHF_EXECINSTR) Whether the current section is executable or not. Read from bit index 2. + * + * @return Current section is executable. + */ + auto is_executable() const -> bool; - auto contains_duplicate_data() const -> bool { return is_bit_set(4); } + /** + * @brief (SHF_MERGE) Whether the current section might be merged with another section or not. Read from bit + * index 4. + * + * @return Current section might be merged with another section + */ + auto contains_duplicate_data() const -> bool; - auto contains_strings() const -> bool { return is_bit_set(5); } + /** + * @brief (SHF_STRINGS) Whether the current section contains null-terminated strings or not. Read from bit + * index 5. + * + * @return Current section contains null-terminated strings + */ + auto contains_strings() const -> bool; - auto section_header_info_is_section_header_table_index() const -> bool { return is_bit_set(6); } + /** + * @brief (SHF_INFO_LINK) Whether the current section contains the section header table index in the (sh_info) + * additional_information variable or not. Read from bit index 6. + * + * @return Current section contains the section header table index in the (sh_info) + * additional_information variable + */ + auto section_header_info_is_section_header_table_index() const -> bool; - auto preserve_ordering_after_combination() const -> bool { return is_bit_set(7); } + /** + * @brief (SHF_LINK_ORDER) Whether the current section preserves order after combining with another section or not. + * Read from bit index 7. + * + * @return Current section preserves order after combining with another section + */ + auto preserve_ordering_after_combination() const -> bool; - auto requires_special_os_processing() const -> bool { return is_bit_set(8); } + /** + * @brief (SHF_OS_NONCONFORMING) Whether the current section requires non-standard OS specific handling of its code + * or data, which does not confirm to standard ELF specifications. Read from bit index 8. + * + * @return Current section requires non-standard OS specific handling + */ + auto requires_special_os_processing() const -> bool; - auto is_section_group_member() const -> bool { return is_bit_set(9); } + /** + * @brief (SHF_GROUP) Whether the current section is a member of a section group or not. Read from bit index 9. + * + * @return Current section is a member of a section group + */ + auto is_section_group_member() const -> bool; - auto holds_thread_local_data() const -> bool { return is_bit_set(10); } + /** + * @brief (SHF_TLS) Whether the current section holds thread-local data or not. Read from bit + * index 10. + * + * @return Current section holds thread-local data + */ + auto holds_thread_local_data() const -> bool; - auto is_compressed() const -> bool { return is_bit_set(11); } + /** + * @brief (SHF_COMPRESSED) Whether the current section contains compressed data or not. Read from bit + * index 11. + * + * @return Current section contains compressed data + */ + auto is_compressed() const -> bool; - auto has_special_ordering_requirements() const -> bool { return is_bit_set(30); } + /** + * @brief (SHF_ORDERED) Whether the current section has special ordering requirements, meaning it should be ordered + * in relation to other sections of the same type. Read from bit index 30. + * + * @return current section has special ordering requirements + */ + auto has_special_ordering_requirements() const -> bool; - auto is_excluded_unless_referenced_or_allocated() const -> bool { return is_bit_set(31); } + /** + * @brief (SHF_EXCLUDE) Whether the current section is excluded unless refereenced or allocated, used for LTO + * (Link-Time Optimizations). Read from bit index 31. + * + * @return Current section is excluded unless refereenced or allocated + */ + auto is_excluded_unless_referenced_or_allocated() const -> bool; - auto operator==(elf_section_flags const & other) const -> bool { return flags == other.flags; } + /** + * @brief Allows to compare the underlying std::bitset of two instances + * + * @param other Other instance that we want to compare with + * @return Whether the underlying std::bitset of both types is the same + */ + auto operator==(elf_section_flags const & other) const -> bool; private: - auto is_bit_set(uint8_t index) const -> bool { return flags[index] == 1; } + /** + * @brief Checks the underlying std::bitset if the bit at the specific index is set, meaning a value of 1 + * + * @param index Specific index we want to check at + * @return Bit value 1 is set and will return true + */ + auto is_bit_set(uint8_t index) const -> bool; std::bitset<64U> flags; }; @@ -164,41 +274,44 @@ namespace teachos::arch::memory */ struct elf_section_header { - uint32_t name_table_index; - elf_section_type type; - elf_section_flags flags; - uint64_t virtual_address; - uint64_t file_offset; - uint64_t section_size; - uint32_t other_section; - uint32_t additional_information; - uint64_t address_alignment; - uint64_t fixed_table_entry_size; - - /** - * @brief Detect whether e section header is inactive or not, should always be the case for the first entry in the + uint32_t name_table_index; ///< Index into the section header string table, specifies the name of the section + elf_section_type type; ///< Categorizes the sections content and semantics + elf_section_flags flags; ///< 1-bit flgas that describe section attributes + uint64_t virtual_address; ///< If section appears in memory image of a process, gives address at which the sections + ///< first byte should reside, otherwise 0 + uint64_t file_offset; ///< Offset from the beginning of the file to the first byte in the section. SHT_NOBITS + ///< contains the conceptual placement instead (because it occupies no space in the file) + uint64_t section_size; ///< Complete section size in bytes, SHT_NOBITS may have non-zero value but will always + ///< occupy no space in the file + uint32_t other_section; ///< Section header table index link, behaviour varies on type + ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link + uint32_t additional_information; ///< Extra information, behaviour varies on type + ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link + uint64_t address_alignment; ///< Possible address alignment constraints. Value of virutal_address must be 0 % value + ///< of address_alignment. Value 0 or 1 mean no alignment constraints + uint64_t fixed_table_entry_size; ///< If sections holds table with fixed-sized entries, this gives the size in + ///< bytes of each entry + + /** + * @brief Detect whether a section header is inactive or not, should always be the case for the first entry in the * sections table * @return Whether the current section header is actually null or not, requires all fields besides section_size and - * other_section to actually contain 0 + * other_section to contain 0 */ - auto is_null() const -> bool - { - return name_table_index == 0U && type == elf_section_type::UNSPECIFIED && flags == 0U && virtual_address == 0U && - file_offset == 0U && additional_information == 0U && address_alignment == 0U && - fixed_table_entry_size == 0U; - } + auto is_null() const -> bool; }; /** - * https://gist.github.com/x0nu11byt3/bcb35c3de461e5fb66173071a2379779 + * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type + * multi_boot_tag_type::ELF_SECTIONS. */ struct elf_symbols_section { - multi_boot_tag tag; - uint32_t number_of_sections; - uint32_t entry_size; - uint32_t section_index; - alignas(8) struct elf_section_header sections; + multi_boot_tag tag; ///< Basic multi_boot_tag information + uint32_t number_of_sections; ///< Number of sections in the sections array + uint32_t entry_size; ///< Size of each entry in the sections array + uint32_t section_index; ///< Index to the string table used for symbol names + alignas(8) struct elf_section_header sections; ///< Specific sectons }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 2ba4fe2..6486b7c 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -63,6 +63,9 @@ namespace teachos::arch::kernel // value should be zero :( // assert(begin->is_null()); + // TODO: Check if only contains one DYNSYM or SYMTAB but not both! + // TODO: Check if only contains one dynamic section + for (auto section = begin; section != end; ++section) { video::vga::text::write("Looping Code section", video::vga::text::common_attributes::green_on_black); diff --git a/arch/x86_64/src/memory/multiboot.cpp b/arch/x86_64/src/memory/multiboot.cpp new file mode 100644 index 0000000..91e7550 --- /dev/null +++ b/arch/x86_64/src/memory/multiboot.cpp @@ -0,0 +1,41 @@ +#include "multiboot.hpp" + +namespace teachos::arch::memory +{ + auto elf_section_flags::writeable() const -> bool { return is_bit_set(0); } + + auto elf_section_flags::occupies_memory() const -> bool { return is_bit_set(1); } + + auto elf_section_flags::is_executable() const -> bool { return is_bit_set(2); } + + auto elf_section_flags::contains_duplicate_data() const -> bool { return is_bit_set(4); } + + auto elf_section_flags::contains_strings() const -> bool { return is_bit_set(5); } + + auto elf_section_flags::section_header_info_is_section_header_table_index() const -> bool { return is_bit_set(6); } + + auto elf_section_flags::preserve_ordering_after_combination() const -> bool { return is_bit_set(7); } + + auto elf_section_flags::requires_special_os_processing() const -> bool { return is_bit_set(8); } + + auto elf_section_flags::is_section_group_member() const -> bool { return is_bit_set(9); } + + auto elf_section_flags::holds_thread_local_data() const -> bool { return is_bit_set(10); } + + auto elf_section_flags::is_compressed() const -> bool { return is_bit_set(11); } + + auto elf_section_flags::has_special_ordering_requirements() const -> bool { return is_bit_set(30); } + + auto elf_section_flags::is_excluded_unless_referenced_or_allocated() const -> bool { return is_bit_set(31); } + + auto elf_section_flags::operator==(elf_section_flags const & other) const -> bool { return flags == other.flags; } + + auto elf_section_flags::is_bit_set(uint8_t index) const -> bool { return flags[index] == 1; } + + auto elf_section_header::is_null() const -> bool + { + return name_table_index == 0U && type == elf_section_type::UNSPECIFIED && + flags == teachos::arch::memory::elf_section_flags{0U} && virtual_address == 0U && file_offset == 0U && + additional_information == 0U && address_alignment == 0U && fixed_table_entry_size == 0U; + } +} // namespace teachos::arch::memory -- cgit v1.2.3 From 88818847446c010ccbfce0690a20a4e6531ca6fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 8 Oct 2024 11:39:32 +0000 Subject: Add additional sanity checks to elf parsing --- arch/x86_64/include/arch/memory/multiboot.hpp | 8 ++++---- arch/x86_64/src/kernel/main.cpp | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index 5990260..c049a29 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -103,10 +103,8 @@ namespace teachos::arch::memory }; /** - * @brief Defines all elf section types an elf section header can have. - * The first section will always be INACTIVE, there can only ever be one DYNAMIC section and only either one - * DYNAMIC_SYMBOL_TABLE or SYMBOL_TABLE. See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html - * for more information. + * @brief Defines all elf section types an elf section header can have. See + * https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. */ enum class elf_section_type : uint32_t { @@ -304,6 +302,8 @@ namespace teachos::arch::memory /** * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type * multi_boot_tag_type::ELF_SECTIONS. + * The first section in the sections array will always be INACTIVE, there can only ever be one DYNAMIC section and + * only either one DYNAMIC_SYMBOL_TABLE or SYMBOL_TABLE. */ struct elf_symbols_section { diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 6486b7c..40b2fe5 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -63,13 +63,26 @@ namespace teachos::arch::kernel // value should be zero :( // assert(begin->is_null()); - // TODO: Check if only contains one DYNSYM or SYMTAB but not both! - // TODO: Check if only contains one dynamic section + std::size_t symbol_table_section_count = 0U; + std::size_t dynamic_section_count = 0U; for (auto section = begin; section != end; ++section) { + if (section->type == arch::memory::elf_section_type::DYNAMIC_SYMBOL_TABLE || + section->type == arch::memory::elf_section_type::SYMBOL_TABLE) + { + symbol_table_section_count++; + } + else if (section->type == arch::memory::elf_section_type::DYNAMIC) + { + dynamic_section_count++; + } video::vga::text::write("Looping Code section", video::vga::text::common_attributes::green_on_black); } + + // TODO: Contains two symbol tables and 4 dynamic sections, that is definetly wrong, perhaps same reason as above? + assert(symbol_table_section_count == 1U); + assert(dynamic_section_count == 1U); } auto main() -> void -- cgit v1.2.3 From b28082b1642f049fcf171a85c7d6841093b0682a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 11 Oct 2024 16:42:18 +0000 Subject: Ensure vscode compiles with c++20 --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 21d4f5f..f0f6745 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,7 @@ "cmake.useCMakePresets": "always", "cmake.options.statusBarVisibility": "visible", + "C_Cpp.default.cppStandard": "c++20", "C_Cpp.autoAddFileAssociations": false, "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", "C_Cpp.formatting": "clangFormat", -- cgit v1.2.3 From 553f3a824511bb8107982b2b2737f5b1dff59855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 13 Oct 2024 08:28:30 +0000 Subject: Add missing cpp files to cmake and fix elf alignment issues --- CMakeLists.txt | 8 +++ arch/x86_64/CMakeLists.txt | 9 +++ .../x86_64/include/arch/memory/frame_allocator.hpp | 8 +-- arch/x86_64/include/arch/memory/multiboot.hpp | 11 ++-- arch/x86_64/include/arch/video/vga/text.hpp | 1 - arch/x86_64/src/kernel/main.cpp | 15 ++--- arch/x86_64/src/memory/frame_allocator.cpp | 66 ++++++++++++---------- arch/x86_64/src/memory/multiboot.cpp | 4 +- 8 files changed, 70 insertions(+), 52 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f780d3..f5cc7ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,6 +100,13 @@ add_library("teachos::boot" ALIAS "_boot") add_library("_video" OBJECT) add_library("teachos::video" ALIAS "_video") +#[============================================================================[ +# The memory Library +#]============================================================================] + +add_library("_memory" OBJECT) +add_library("teachos::memory" ALIAS "_memory") + #[============================================================================[ # The Kernel #]============================================================================] @@ -112,6 +119,7 @@ add_executable("teachos::kernel" ALIAS "_kernel") target_link_libraries("_kernel" PRIVATE "teachos::boot" "teachos::video" + "teachos::memory" ) #[============================================================================[ diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 6ff1332..882ea9a 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -36,6 +36,15 @@ target_sources("_video" PRIVATE "src/video/vga/text.cpp" ) +#[============================================================================[ +# The Memory Library +#]============================================================================] + +target_sources("_memory" PRIVATE + "src/memory/multiboot.cpp" + "src/memory/frame_allocator.cpp" +) + #[============================================================================[ # The Bootable ISO Image #]============================================================================] diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp index 3989cdf..a52cc46 100644 --- a/arch/x86_64/include/arch/memory/frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/frame_allocator.hpp @@ -52,8 +52,8 @@ namespace teachos::arch::memory template concept FrameAllocator = requires(T t) { - { t.allocate_frame() } -> std::optional; - { t.deallocate_frame() } -> void; + { t.allocate_frame() } -> std::same_as>; + { t.deallocate_frame() } -> std::same_as; }; /** @@ -81,11 +81,11 @@ namespace teachos::arch::memory */ area_frame_allocator(std::size_t kernel_start, std::size_t kernel_end, std::size_t multiboot_start, std::size_t multiboot_end, memory_area * memory_areas) - : kernel_start(frame{kernel_start}) + : areas(memory_areas) + , kernel_start(frame{kernel_start}) , kernel_end(frame{kernel_end}) , multiboot_start(frame{multiboot_start}) , multiboot_end(frame{multiboot_end}) - , areas(memory_areas) { choose_next_area(); } diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index c049a29..d66ca35 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -307,11 +307,12 @@ namespace teachos::arch::memory */ struct elf_symbols_section { - multi_boot_tag tag; ///< Basic multi_boot_tag information - uint32_t number_of_sections; ///< Number of sections in the sections array - uint32_t entry_size; ///< Size of each entry in the sections array - uint32_t section_index; ///< Index to the string table used for symbol names - alignas(8) struct elf_section_header sections; ///< Specific sectons + multi_boot_tag tag; ///< Basic multi_boot_tag information + uint32_t number_of_sections; ///< Number of sections in the sections array + uint32_t entry_size; ///< Size of each entry in the sections array + uint32_t section_index; ///< Index to the string table used for symbol names + std::byte end; ///< Marks the end of the tag, used to mark the beginning of any additional data + ///< contained in the section, to ensure byte alignment is actually 4 byte }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/include/arch/video/vga/text.hpp b/arch/x86_64/include/arch/video/vga/text.hpp index 9c4c701..79ec7be 100644 --- a/arch/x86_64/include/arch/video/vga/text.hpp +++ b/arch/x86_64/include/arch/video/vga/text.hpp @@ -121,7 +121,6 @@ namespace teachos::arch::video::vga::text */ auto write_char(char code_point, attribute attribute) -> void; - // TODO: Move concepts to their own file/folder template concept Integral = std::is_integral_v; diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 40b2fe5..01c955b 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -28,6 +28,7 @@ namespace teachos::arch::kernel auto print_memory_map(arch::memory::memory_map * mminfo) -> void { + // TODO: Probably same issue as elf sections because the values are kind of weird as well auto expected_entry_size = mminfo->entry_size; constexpr auto actual_entry_size = sizeof(arch::memory::memory_area); assert(expected_entry_size == actual_entry_size); @@ -45,23 +46,20 @@ namespace teachos::arch::kernel auto print_elf_sections(arch::memory::elf_symbols_section * symbol) -> void { + // TODO: Check if sectiosn now actually match the elf file auto expected_entry_size = symbol->entry_size; constexpr auto actual_entry_size = sizeof(arch::memory::elf_section_header); assert(expected_entry_size == actual_entry_size); auto expected_total_size = symbol->tag.size; auto actual_total_entry_size = actual_entry_size * symbol->number_of_sections; - constexpr auto actual_total_section_size = - sizeof(arch::memory::elf_symbols_section) - actual_entry_size - sizeof(uint32_t); + constexpr auto actual_total_section_size = sizeof(arch::memory::elf_symbols_section) - sizeof(uint32_t); auto actual_total_size = actual_total_entry_size + actual_total_section_size; assert(expected_total_size == actual_total_size); - auto begin = &symbol->sections; + auto begin = reinterpret_cast(&symbol->end); auto end = begin + symbol->number_of_sections; - // TODO: Last value is completly wrong, should show 0 but shows huge value for size of entries in the table of the - // SHT_NULL elf section entry. Memory around value also make no sense and look even worse? But according to api - // value should be zero :( - // assert(begin->is_null()); + assert(begin->is_null()); std::size_t symbol_table_section_count = 0U; std::size_t dynamic_section_count = 0U; @@ -80,9 +78,8 @@ namespace teachos::arch::kernel video::vga::text::write("Looping Code section", video::vga::text::common_attributes::green_on_black); } - // TODO: Contains two symbol tables and 4 dynamic sections, that is definetly wrong, perhaps same reason as above? assert(symbol_table_section_count == 1U); - assert(dynamic_section_count == 1U); + assert(dynamic_section_count <= 1U); } auto main() -> void diff --git a/arch/x86_64/src/memory/frame_allocator.cpp b/arch/x86_64/src/memory/frame_allocator.cpp index b8f53be..3793ac6 100644 --- a/arch/x86_64/src/memory/frame_allocator.cpp +++ b/arch/x86_64/src/memory/frame_allocator.cpp @@ -2,6 +2,37 @@ namespace teachos::arch::memory { + auto area_frame_allocator::choose_next_area() -> void + { + current_area = std::nullopt; + auto begin = areas; + auto end = areas + 5; + + // TODO: Fix this loop as soon as you've created an area iterator + for (auto area = begin; area != end; ++area) + { + std::size_t address = area->base_address + area->area_length - 1; + if (frame::containing_address(address) >= next_free_frame) + { + // The `next_free_frame` address is smaller than the last address of the current area + if (!current_area || area->base_address < current_area->base_address) + { + current_area = *area; + } + } + } + + if (current_area) + { + // Update the `next_free_frame` according to the new memory area + frame start_frame = frame::containing_address(current_area->base_address); + if (next_free_frame < start_frame) + { + next_free_frame = start_frame; + } + } + } + auto area_frame_allocator::allocate_frame() -> std::optional { /* @@ -40,38 +71,11 @@ namespace teachos::arch::memory return std::nullopt; } - auto area_frame_allocator::deallocate_frame(frame frame) -> void {} - - namespace + auto area_frame_allocator::deallocate_frame(frame frame) -> void { - auto area_frame_allocator::choose_next_area() -> void + // TODO: Fix, simply done because compiler will complain if frame is unused and not compile + if (frame.frame_number == 3) { - current_area = std::nullopt; - - // TODO: Fix this loop as soon as you've created an area iterator - for (const auto & area : areas) - { - std::size_t address = area.base_addr + area.length - 1; - if (frame::containing_address(address) >= next_free_frame) - { - // The `next_free_frame` address is smaller than the last address of the current area - if (!current_area || area.base_addr < current_area->base_address) - { - current_area = area; - } - } - } - - if (current_area) - { - // Update the `next_free_frame` according to the new memory area - frame start_frame = frame::containing_address(current_area->base_address); - if (next_free_frame < start_frame) - { - next_free_frame = start_frame; - } - } } - - } // namespace + } } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/memory/multiboot.cpp b/arch/x86_64/src/memory/multiboot.cpp index 91e7550..3f6248d 100644 --- a/arch/x86_64/src/memory/multiboot.cpp +++ b/arch/x86_64/src/memory/multiboot.cpp @@ -1,4 +1,4 @@ -#include "multiboot.hpp" +#include "arch/memory/multiboot.hpp" namespace teachos::arch::memory { @@ -34,7 +34,7 @@ namespace teachos::arch::memory auto elf_section_header::is_null() const -> bool { - return name_table_index == 0U && type == elf_section_type::UNSPECIFIED && + return name_table_index == 0U && type == elf_section_type::INACTIVE && flags == teachos::arch::memory::elf_section_flags{0U} && virtual_address == 0U && file_offset == 0U && additional_information == 0U && address_alignment == 0U && fixed_table_entry_size == 0U; } -- cgit v1.2.3 From b3c8a1819226b7dbaad82623c8294b99c91297ef Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 13 Oct 2024 10:58:34 +0000 Subject: continue implementing frame allocator --- .../x86_64/include/arch/memory/frame_allocator.hpp | 45 +++++++++- arch/x86_64/src/kernel/main.cpp | 99 +++++++++++++++------- arch/x86_64/src/memory/frame_allocator.cpp | 13 ++- 3 files changed, 116 insertions(+), 41 deletions(-) diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp index a52cc46..fa22ce5 100644 --- a/arch/x86_64/include/arch/memory/frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/frame_allocator.hpp @@ -56,9 +56,41 @@ namespace teachos::arch::memory { t.deallocate_frame() } -> std::same_as; }; + /** + * @brief Iterator for memory areas + */ + class memory_area_iterator + { + memory_area * ptr; + + public: + std::size_t begin; + std::size_t end; + + explicit memory_area_iterator(memory_area * p) + : ptr(p) + { + } + + memory_area & operator*() const { return *ptr; } + memory_area_iterator & operator++() + { + ++ptr; + return *this; + } + + memory_area_iterator operator++(int) + { + memory_area_iterator temp = *this; + ++(*this); + return temp; + } + + bool operator==(const memory_area_iterator & other) const { return ptr == other.ptr; } + }; + /** * @brief Allocates memory using memory areas read from the multiboot2 information pointer - * */ struct area_frame_allocator { @@ -70,6 +102,10 @@ namespace teachos::arch::memory frame multiboot_start; //!< The start address of the multiboot code in memory frame multiboot_end; //!< The end address of the multiboot code in memory + private: + uint8_t N; + + public: /** * @brief Constructor * @@ -80,12 +116,13 @@ namespace teachos::arch::memory * @param memory_areas Pointer to the first element of all memory areas */ area_frame_allocator(std::size_t kernel_start, std::size_t kernel_end, std::size_t multiboot_start, - std::size_t multiboot_end, memory_area * memory_areas) + std::size_t multiboot_end, memory_area * memory_areas, uint8_t area_count) : areas(memory_areas) , kernel_start(frame{kernel_start}) , kernel_end(frame{kernel_end}) , multiboot_start(frame{multiboot_start}) , multiboot_end(frame{multiboot_end}) + , N(area_count) { choose_next_area(); } @@ -109,6 +146,10 @@ namespace teachos::arch::memory */ auto deallocate_frame(frame frame) -> void; + memory_area_iterator begin() { return memory_area_iterator(areas); } + + memory_area_iterator end() { return memory_area_iterator(areas + N); } + private: /** * @brief Find the next memory area and write it into current_area diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 01c955b..3fa44d3 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,6 +1,7 @@ #include "arch/kernel/main.hpp" #include "arch/boot/pointers.hpp" +#include "arch/memory/frame_allocator.hpp" #include "arch/memory/multiboot.hpp" #include "arch/video/vga/text.hpp" @@ -20,33 +21,21 @@ namespace teachos::arch::kernel } } - auto print_mem_info(arch::memory::memory_info * mem_info) -> void + auto process_memory_map(arch::memory::memory_map * mminfo, arch::memory::memory_area ** memory_areas, + uint8_t * area_count) -> void { - video::vga::text::write("Memory info low: ", video::vga::text::common_attributes::green_on_black); - video::vga::text::write_number(mem_info->mem_lower, video::vga::text::common_attributes::green_on_black); - } - - auto print_memory_map(arch::memory::memory_map * mminfo) -> void - { - // TODO: Probably same issue as elf sections because the values are kind of weird as well auto expected_entry_size = mminfo->entry_size; constexpr auto actual_entry_size = sizeof(arch::memory::memory_area); assert(expected_entry_size == actual_entry_size); - auto remaining_size = mminfo->tag.size - (4 * sizeof(uint32_t)); - auto entry_amount = remaining_size / mminfo->entry_size; - - auto begin = &mminfo->entries; - auto end = begin + entry_amount; - for (auto entry = begin; entry != end; ++entry) - { - video::vga::text::write("Looping Memory area", video::vga::text::common_attributes::green_on_black); - } + *memory_areas = &mminfo->entries; + *area_count = sizeof(mminfo->entries) / mminfo->entry_size; } - auto print_elf_sections(arch::memory::elf_symbols_section * symbol) -> void + auto process_elf_sections(arch::memory::elf_symbols_section * symbol, uint64_t * kernel_start, + uint64_t * kernel_end) -> void { - // TODO: Check if sectiosn now actually match the elf file + // Validate ELF sections auto expected_entry_size = symbol->entry_size; constexpr auto actual_entry_size = sizeof(arch::memory::elf_section_header); assert(expected_entry_size == actual_entry_size); @@ -66,16 +55,31 @@ namespace teachos::arch::kernel for (auto section = begin; section != end; ++section) { - if (section->type == arch::memory::elf_section_type::DYNAMIC_SYMBOL_TABLE || - section->type == arch::memory::elf_section_type::SYMBOL_TABLE) + switch (section->type) { - symbol_table_section_count++; - } - else if (section->type == arch::memory::elf_section_type::DYNAMIC) - { - dynamic_section_count++; + case arch::memory::elf_section_type::PROGRAMM: + if (section->virtual_address < *kernel_start) + { + *kernel_start = section->virtual_address; + } + + if (section->virtual_address + section->section_size > *kernel_end) + { + *kernel_end = section->virtual_address + section->section_size; + } + break; + case arch::memory::elf_section_type::DYNAMIC_SYMBOL_TABLE: + case arch::memory::elf_section_type::SYMBOL_TABLE: + symbol_table_section_count++; + break; + case arch::memory::elf_section_type::DYNAMIC: + symbol_table_section_count++; + dynamic_section_count++; + break; + default: + // All other cases are not important and can be ignored + break; } - video::vga::text::write("Looping Code section", video::vga::text::common_attributes::green_on_black); } assert(symbol_table_section_count == 1U); @@ -94,6 +98,13 @@ namespace teachos::arch::kernel (arch::memory::multi_boot_info *)arch::boot::multiboot_information_pointer; auto multiboot_tag = &(multiboot_information_pointer->tags); + uint64_t kernel_start = UINT64_MAX; + uint64_t kernel_end = 0; + uint64_t multiboot_start = arch::boot::multiboot_information_pointer; + uint64_t multiboot_end = multiboot_start + multiboot_information_pointer->total_size; + arch::memory::memory_area * memory_areas = nullptr; + uint8_t area_count = 0; + /* * Loop over the multiboot2 tags to access the information needed. * Tags are defined in the header file and are padded so that each @@ -106,19 +117,43 @@ namespace teachos::arch::kernel { switch (tag->type) { - case arch::memory::multi_boot_tag_type::BASIC_MEMORY_INFO: - print_mem_info((arch::memory::memory_info *)tag); - break; case arch::memory::multi_boot_tag_type::ELF_SECTIONS: - print_elf_sections((arch::memory::elf_symbols_section *)tag); + process_elf_sections((arch::memory::elf_symbols_section *)tag, &kernel_start, &kernel_end); break; case arch::memory::multi_boot_tag_type::MEMORY_MAP: - print_memory_map((arch::memory::memory_map *)tag); + process_memory_map((arch::memory::memory_map *)tag, &memory_areas, &area_count); break; default: // All other cases are not important and can be ignored break; } } + + // Kernel start 0x100000 + // Kernel end 0x23E943 + // Kernel Size 0x13E943 -> 1'304'899 + // Multiboot start 0x241AA0 + // Multiboot end 0x242280 + // Multiboot Size 0x7E0 -> 2'016 + // Memory area start 0x241b10 + // + // Address of Frame: 0x203F00 + auto allocator = arch::memory::area_frame_allocator(kernel_start, kernel_end, multiboot_start, multiboot_end, + memory_areas, area_count); + std::optional allocated = allocator.allocate_frame(); + + // WATCH OUT: using optional::value() crashes the build... I think its because of missing exception handling + if (allocated.has_value()) + { + video::vga::text::write("Allocated Frame address: ", video::vga::text::common_attributes::green_on_black); + video::vga::text::write_number(reinterpret_cast(&allocated->frame_number), + video::vga::text::common_attributes::green_on_black); + video::vga::text::write("Allocated Frame number: ", video::vga::text::common_attributes::green_on_black); + video::vga::text::write_number(allocated->frame_number, video::vga::text::common_attributes::green_on_black); + } + else + { + video::vga::text::write("NO VALUE", video::vga::text::common_attributes::green_on_black); + } } } // namespace teachos::arch::kernel diff --git a/arch/x86_64/src/memory/frame_allocator.cpp b/arch/x86_64/src/memory/frame_allocator.cpp index 3793ac6..829cd6d 100644 --- a/arch/x86_64/src/memory/frame_allocator.cpp +++ b/arch/x86_64/src/memory/frame_allocator.cpp @@ -5,19 +5,18 @@ namespace teachos::arch::memory auto area_frame_allocator::choose_next_area() -> void { current_area = std::nullopt; - auto begin = areas; - auto end = areas + 5; - // TODO: Fix this loop as soon as you've created an area iterator - for (auto area = begin; area != end; ++area) + for (memory_area_iterator it = begin(); it != end(); ++it) { - std::size_t address = area->base_address + area->area_length - 1; + memory_area & area = *it; + + std::size_t address = area.base_address + area.area_length - 1; if (frame::containing_address(address) >= next_free_frame) { // The `next_free_frame` address is smaller than the last address of the current area - if (!current_area || area->base_address < current_area->base_address) + if (!current_area || area.base_address < current_area->base_address) { - current_area = *area; + current_area = area; } } } -- cgit v1.2.3 From 8beb8b758c33cf1ac5357b31296927e7df8cf971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 14 Oct 2024 08:15:16 +0000 Subject: Fix typos, implementation in header and missing doxygen --- .../x86_64/include/arch/memory/frame_allocator.hpp | 122 ++++++++++++--------- arch/x86_64/src/kernel/main.cpp | 41 ++++--- arch/x86_64/src/memory/frame_allocator.cpp | 32 ++++++ 3 files changed, 125 insertions(+), 70 deletions(-) diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp index fa22ce5..1fd1f08 100644 --- a/arch/x86_64/include/arch/memory/frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/frame_allocator.hpp @@ -10,7 +10,7 @@ namespace teachos::arch::memory { namespace { - const std::size_t PAGE_FRAME_SIZE = 4096U; + constexpr std::size_t PAGE_FRAME_SIZE = 4096U; ///< Default page size of x86_84 is always 4KiB } /** @@ -18,18 +18,12 @@ namespace teachos::arch::memory */ struct frame { - std::size_t frame_number; ///< Index number of the current frame, used to distinguish it from other frames - /** * @brief Constructor * * @param frame_number Index number that should be assigned to this frame */ - frame(std::size_t frame_number) - : frame_number(frame_number) - { - // Nothing to do - } + frame(std::size_t frame_number); /** * @brief Returns the frame the given address is contained in @@ -37,7 +31,7 @@ namespace teachos::arch::memory * @param address Address we want to get the corresponding frame for * @return Frame the given address is contained in */ - static auto containing_address(std::size_t address) -> frame { return frame{address / PAGE_FRAME_SIZE}; } + static auto containing_address(std::size_t address) -> frame; /** * @brief Defaulted equals operator @@ -48,6 +42,8 @@ namespace teachos::arch::memory * @brief Defaulted three-way comparsion operator */ constexpr auto operator<=>(const frame & other) const -> std::partial_ordering = default; + + std::size_t frame_number; ///< Index number of the current frame, used to distinguish it from other frames }; template @@ -57,36 +53,48 @@ namespace teachos::arch::memory }; /** - * @brief Iterator for memory areas + * @brief Iterator for memory areas. */ - class memory_area_iterator + struct memory_area_iterator { - memory_area * ptr; + /** + * @brief Constructor + * + * @param p Underlying address the iterator should point too, ensure to not pass an invalid pointer + */ + explicit memory_area_iterator(memory_area * p); - public: - std::size_t begin; - std::size_t end; + /** + * @brief Dereferences the initally given pointer to its value. + * + * @return Reference to the value + */ + memory_area & operator*() const; - explicit memory_area_iterator(memory_area * p) - : ptr(p) - { - } + /** + * @brief Post increment operator. Returns a copy of the value + * + * @return Copy of the incremented underlying address + */ + memory_area_iterator operator++(int); - memory_area & operator*() const { return *ptr; } - memory_area_iterator & operator++() - { - ++ptr; - return *this; - } + /** + * @brief Pre increment operator. Returns a reference to the changed value + * + * @return Reference to the incremented underlying address + */ + memory_area_iterator & operator++(); - memory_area_iterator operator++(int) - { - memory_area_iterator temp = *this; - ++(*this); - return temp; - } + /** + * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. + * + * @param other Other iterator to compare to + * @return Whether poith iterators point to the same underlying address in memory + */ + bool operator==(memory_area_iterator const & other) const = default; - bool operator==(const memory_area_iterator & other) const { return ptr == other.ptr; } + private: + memory_area * ptr; ///< Underlying address the iterator is currently pointing too }; /** @@ -94,18 +102,6 @@ namespace teachos::arch::memory */ struct area_frame_allocator { - frame next_free_frame{0}; //!< The frame after the last allocated one - std::optional current_area{std::nullopt}; //!< The current memory area - memory_area * areas; //!< Pointer to the first element of all memory areas - frame kernel_start; //!< The start address of the kernel code in memory - frame kernel_end; //!< The end address of the kernel code in memory - frame multiboot_start; //!< The start address of the multiboot code in memory - frame multiboot_end; //!< The end address of the multiboot code in memory - - private: - uint8_t N; - - public: /** * @brief Constructor * @@ -114,15 +110,16 @@ namespace teachos::arch::memory * @param multiboot_start Start address of the multiboot code in memory * @param multiboot_end End address of the multiboot code in memory * @param memory_areas Pointer to the first element of all memory areas + * @param area_count Amount of total entries in the memory_areas array */ area_frame_allocator(std::size_t kernel_start, std::size_t kernel_end, std::size_t multiboot_start, std::size_t multiboot_end, memory_area * memory_areas, uint8_t area_count) - : areas(memory_areas) - , kernel_start(frame{kernel_start}) - , kernel_end(frame{kernel_end}) - , multiboot_start(frame{multiboot_start}) - , multiboot_end(frame{multiboot_end}) - , N(area_count) + : area_begin(memory_areas) + , area_end(memory_areas + area_count) + , kernel_start(frame::containing_address(kernel_start)) + , kernel_end(frame::containing_address(kernel_end)) + , multiboot_start(frame::containing_address(multiboot_start)) + , multiboot_end(frame::containing_address(multiboot_end)) { choose_next_area(); } @@ -146,15 +143,36 @@ namespace teachos::arch::memory */ auto deallocate_frame(frame frame) -> void; - memory_area_iterator begin() { return memory_area_iterator(areas); } + /** + * @brief Returns the iterator pointing to the first element of the memory area. + * Allows using this class in the for each loop, because it follows the InputIterator template scheme + * + * @return Iterator pointing to first element of the memory area + */ + auto begin() -> memory_area_iterator; - memory_area_iterator end() { return memory_area_iterator(areas + N); } + /** + * @brief Returns the iterator pointing to one past the last element of the memory area. + * Allows using this class in the for each loop, because it follows the InputIterator template scheme + * + * @return Iterator pointing to one past the last element of the memory area + */ + auto end() -> memory_area_iterator; private: /** * @brief Find the next memory area and write it into current_area */ auto choose_next_area() -> void; + + frame next_free_frame{0}; ///< The frame after the last allocated one + std::optional current_area{std::nullopt}; ///< The current memory area + memory_area_iterator area_begin; ///< Pointer to the first element of all memory areas + memory_area_iterator area_end; ///< Pointer to one pas the last element of all memory areas + frame const kernel_start; ///< The start address of the kernel code in memory + frame const kernel_end; ///< The end address of the kernel code in memory + frame const multiboot_start; ///< The start address of the multiboot code in memory + frame const multiboot_end; ///< The end address of the multiboot code in memory }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 3fa44d3..1289eb6 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -16,24 +16,28 @@ namespace teachos::arch::kernel // to prevent the while loop being optimized away // See // https://stackoverflow.com/questions/9495856/how-to-prevent-g-from-optimizing-out-a-loop-controlled-by-a-variable-that-can - // for mroe information. + // for more information. asm volatile("" : "+g"(condition)); } } - auto process_memory_map(arch::memory::memory_map * mminfo, arch::memory::memory_area ** memory_areas, - uint8_t * area_count) -> void + auto process_memory_map(arch::memory::memory_map * mminfo, arch::memory::memory_area *& memory_areas, + uint8_t & area_count) -> void { auto expected_entry_size = mminfo->entry_size; constexpr auto actual_entry_size = sizeof(arch::memory::memory_area); assert(expected_entry_size == actual_entry_size); - *memory_areas = &mminfo->entries; - *area_count = sizeof(mminfo->entries) / mminfo->entry_size; + auto total_size = mminfo->tag.size; + auto total_entries_size = total_size - sizeof(arch::memory::memory_map) + actual_entry_size; + auto number_of_entries = total_entries_size / actual_entry_size; + + memory_areas = &mminfo->entries; + area_count = number_of_entries; } - auto process_elf_sections(arch::memory::elf_symbols_section * symbol, uint64_t * kernel_start, - uint64_t * kernel_end) -> void + auto process_elf_sections(arch::memory::elf_symbols_section * symbol, uint64_t & kernel_start, + uint64_t & kernel_end) -> void { // Validate ELF sections auto expected_entry_size = symbol->entry_size; @@ -58,14 +62,14 @@ namespace teachos::arch::kernel switch (section->type) { case arch::memory::elf_section_type::PROGRAMM: - if (section->virtual_address < *kernel_start) + if (section->virtual_address < kernel_start) { - *kernel_start = section->virtual_address; + kernel_start = section->virtual_address; } - if (section->virtual_address + section->section_size > *kernel_end) + if (section->virtual_address + section->section_size > kernel_end) { - *kernel_end = section->virtual_address + section->section_size; + kernel_end = section->virtual_address + section->section_size; } break; case arch::memory::elf_section_type::DYNAMIC_SYMBOL_TABLE: @@ -73,7 +77,6 @@ namespace teachos::arch::kernel symbol_table_section_count++; break; case arch::memory::elf_section_type::DYNAMIC: - symbol_table_section_count++; dynamic_section_count++; break; default: @@ -94,8 +97,8 @@ namespace teachos::arch::kernel text::cursor(false); text::write("TeachOS is starting up...", text::common_attributes::green_on_black); - arch::memory::multi_boot_info * multiboot_information_pointer = - (arch::memory::multi_boot_info *)arch::boot::multiboot_information_pointer; + auto * multiboot_information_pointer = + reinterpret_cast(arch::boot::multiboot_information_pointer); auto multiboot_tag = &(multiboot_information_pointer->tags); uint64_t kernel_start = UINT64_MAX; @@ -113,15 +116,17 @@ namespace teachos::arch::kernel * The increment part aligns the size to an 8-byte address. */ for (auto tag = multiboot_tag; tag->type != arch::memory::multi_boot_tag_type::END; - tag = (arch::memory::multi_boot_tag *)(((uint8_t *)tag) + ((tag->size + 7) & ~7))) + tag = reinterpret_cast((reinterpret_cast(tag)) + + ((tag->size + 7) & ~7))) { switch (tag->type) { case arch::memory::multi_boot_tag_type::ELF_SECTIONS: - process_elf_sections((arch::memory::elf_symbols_section *)tag, &kernel_start, &kernel_end); + process_elf_sections(reinterpret_cast(tag), kernel_start, + kernel_end); break; case arch::memory::multi_boot_tag_type::MEMORY_MAP: - process_memory_map((arch::memory::memory_map *)tag, &memory_areas, &area_count); + process_memory_map(reinterpret_cast(tag), memory_areas, area_count); break; default: // All other cases are not important and can be ignored @@ -140,7 +145,7 @@ namespace teachos::arch::kernel // Address of Frame: 0x203F00 auto allocator = arch::memory::area_frame_allocator(kernel_start, kernel_end, multiboot_start, multiboot_end, memory_areas, area_count); - std::optional allocated = allocator.allocate_frame(); + auto allocated = allocator.allocate_frame(); // WATCH OUT: using optional::value() crashes the build... I think its because of missing exception handling if (allocated.has_value()) diff --git a/arch/x86_64/src/memory/frame_allocator.cpp b/arch/x86_64/src/memory/frame_allocator.cpp index 829cd6d..3ad2d96 100644 --- a/arch/x86_64/src/memory/frame_allocator.cpp +++ b/arch/x86_64/src/memory/frame_allocator.cpp @@ -2,6 +2,34 @@ namespace teachos::arch::memory { + frame::frame(std::size_t frame_number) + : frame_number(frame_number) + { + // Nothing to do + } + + auto frame::containing_address(std::size_t address) -> frame { return frame{address / PAGE_FRAME_SIZE}; } + + memory_area_iterator::memory_area_iterator(memory_area * p) + : ptr(p) + { + // Nothing to do + } + + memory_area & memory_area_iterator::operator*() const { return *ptr; } + + auto memory_area_iterator::operator++(int) -> memory_area_iterator + { + ++(*this); + return *this; + } + + auto memory_area_iterator::operator++() -> memory_area_iterator & + { + ++ptr; + return *this; + } + auto area_frame_allocator::choose_next_area() -> void { current_area = std::nullopt; @@ -77,4 +105,8 @@ namespace teachos::arch::memory { } } + + auto area_frame_allocator::begin() -> memory_area_iterator { return area_begin; } + + auto area_frame_allocator::end() -> memory_area_iterator { return area_end; } } // namespace teachos::arch::memory -- cgit v1.2.3 From 7fc99d55ffff20b49dc4088efc95b68b3d33a45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 14 Oct 2024 09:47:49 +0000 Subject: Use scoped switch statements to extract calculations to variables --- arch/x86_64/include/arch/memory/multiboot.hpp | 8 ++++--- arch/x86_64/src/kernel/main.cpp | 30 +++++++++++++++++---------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index d66ca35..3aee7fc 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -49,7 +49,7 @@ namespace teachos::arch::memory /** * @brief Basic structure the multiboot_information_pointer points too and which contains all information of - * multiboot2 in the tags array of different types. + * multiboot2 in the tags array of different types. The start as well as the content has to be 8 byte aligned. */ struct multi_boot_info { @@ -109,7 +109,7 @@ namespace teachos::arch::memory enum class elf_section_type : uint32_t { INACTIVE, ///< (SHT_NULL) Unused, meaning all values are zeroed out - PROGRAMM, ///< (SHT_PROGBITS) Program data + PROGRAMM, ///< (SHT_PROGBITS) Program data (DATA, CODE) SYMBOL_TABLE, ///< (SHT_SYMBTAB) Contains actual entries pointed to in symbol hash table STRING_TABLE, ///< (SHT_STRTAB) Contains symbols, section and deubbging null-terminated strings RELOCATION_ENTRY_WITH_ADDENDS, ///< (SHT_RELA) Only used on 64 bit systems @@ -146,7 +146,9 @@ namespace teachos::arch::memory } /** - * @brief (SHF_WRITE) Wether the current section is writable or not. Read from bit index 0. + * @brief (SHF_WRITE) Wether the current section is writable at runtime or not. If it isn't then the section is + * assumed to be READONLY and only that behaviour is shown in the objdump -h of the kernel file. Read from bit index + * 0. * * @return Current section is writable. */ diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 1289eb6..1c6aa55 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -9,8 +9,13 @@ namespace teachos::arch::kernel { auto assert(bool condition) -> void { + if (condition) + { + return; + } + video::vga::text::write("Assert failed", video::vga::text::common_attributes::green_on_black); - while (!condition) + for (;;) { // Trick the compiler into thinking the variable is changes at run time, // to prevent the while loop being optimized away @@ -39,7 +44,6 @@ namespace teachos::arch::kernel auto process_elf_sections(arch::memory::elf_symbols_section * symbol, uint64_t & kernel_start, uint64_t & kernel_end) -> void { - // Validate ELF sections auto expected_entry_size = symbol->entry_size; constexpr auto actual_entry_size = sizeof(arch::memory::elf_section_header); assert(expected_entry_size == actual_entry_size); @@ -61,17 +65,18 @@ namespace teachos::arch::kernel { switch (section->type) { - case arch::memory::elf_section_type::PROGRAMM: + case arch::memory::elf_section_type::PROGRAMM: { if (section->virtual_address < kernel_start) { kernel_start = section->virtual_address; } - - if (section->virtual_address + section->section_size > kernel_end) + auto virtual_address_end = section->virtual_address + section->section_size; + if (virtual_address_end > kernel_end) { - kernel_end = section->virtual_address + section->section_size; + kernel_end = virtual_address_end; } break; + } case arch::memory::elf_section_type::DYNAMIC_SYMBOL_TABLE: case arch::memory::elf_section_type::SYMBOL_TABLE: symbol_table_section_count++; @@ -121,13 +126,16 @@ namespace teachos::arch::kernel { switch (tag->type) { - case arch::memory::multi_boot_tag_type::ELF_SECTIONS: - process_elf_sections(reinterpret_cast(tag), kernel_start, - kernel_end); + case arch::memory::multi_boot_tag_type::ELF_SECTIONS: { + auto symbol = reinterpret_cast(tag); + process_elf_sections(symbol, kernel_start, kernel_end); break; - case arch::memory::multi_boot_tag_type::MEMORY_MAP: - process_memory_map(reinterpret_cast(tag), memory_areas, area_count); + } + case arch::memory::multi_boot_tag_type::MEMORY_MAP: { + auto mminfo = reinterpret_cast(tag); + process_memory_map(mminfo, memory_areas, area_count); break; + } default: // All other cases are not important and can be ignored break; -- cgit v1.2.3 From e9dd8ea4343b943032f2af87fbae9f46fe1f9328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 14 Oct 2024 09:55:11 +0000 Subject: Move 8 byte alignment into seperate method --- arch/x86_64/src/kernel/main.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 1c6aa55..106ca2a 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -94,6 +94,13 @@ namespace teachos::arch::kernel assert(dynamic_section_count <= 1U); } + 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 main() -> void { using namespace video::vga; @@ -121,8 +128,7 @@ namespace teachos::arch::kernel * The increment part aligns the size to an 8-byte address. */ for (auto tag = multiboot_tag; tag->type != arch::memory::multi_boot_tag_type::END; - tag = reinterpret_cast((reinterpret_cast(tag)) + - ((tag->size + 7) & ~7))) + tag = align_to_8_byte_boundary(tag, tag->size)) { switch (tag->type) { -- cgit v1.2.3 From 563a3dcbc1f2d26adcd6761358c45d635738f3c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 14 Oct 2024 12:42:54 +0000 Subject: Add more info on which elf flag means which objdump flag --- arch/x86_64/include/arch/memory/multiboot.hpp | 8 +++++--- arch/x86_64/src/kernel/main.cpp | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index 3aee7fc..35b483e 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -147,7 +147,7 @@ namespace teachos::arch::memory /** * @brief (SHF_WRITE) Wether the current section is writable at runtime or not. If it isn't then the section is - * assumed to be READONLY and only that behaviour is shown in the objdump -h of the kernel file. Read from bit index + * assumed to be READONLY and only that flag is shown in the objdump -h of the kernel file. Read from bit index * 0. * * @return Current section is writable. @@ -155,14 +155,16 @@ namespace teachos::arch::memory auto writeable() const -> bool; /** - * @brief (SHF_ALLOC) Whether the current section occupies memory during execution or not. Read from bit index 1. + * @brief (SHF_ALLOC) Whether the current section occupies memory during execution or not. ALLOC flag is shown in + * the objdump -h of the kernel file. Read from bit index 1. * * @return Current section occupies memory during execution. */ auto occupies_memory() const -> bool; /** - * @brief (SHF_EXECINSTR) Whether the current section is executable or not. Read from bit index 2. + * @brief (SHF_EXECINSTR) Whether the current section is executable or not. CODE flag is shown in the object dump. + * Read from bit index 2. * * @return Current section is executable. */ diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 106ca2a..bdf530c 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -63,6 +63,29 @@ namespace teachos::arch::kernel for (auto section = begin; section != end; ++section) { + bool const writeable = section->flags.writeable(); + bool const occupies_memory = section->flags.occupies_memory(); + bool const is_executable = section->flags.is_executable(); + bool const contains_duplicate_data = section->flags.contains_duplicate_data(); + bool const contains_strings = section->flags.contains_strings(); + bool const section_header_info_is_section_header_table_index = + section->flags.section_header_info_is_section_header_table_index(); + bool const preserve_ordering_after_combination = section->flags.preserve_ordering_after_combination(); + bool const requires_special_os_processing = section->flags.requires_special_os_processing(); + bool const is_section_group_member = section->flags.is_section_group_member(); + bool const holds_thread_local_data = section->flags.holds_thread_local_data(); + bool const is_compressed = section->flags.is_compressed(); + bool const has_special_ordering_requirements = section->flags.has_special_ordering_requirements(); + bool const is_excluded_unless_referenced_or_allocated = + section->flags.is_excluded_unless_referenced_or_allocated(); + + if (writeable && occupies_memory && is_executable && contains_duplicate_data && contains_strings && + section_header_info_is_section_header_table_index && preserve_ordering_after_combination && + requires_special_os_processing && is_section_group_member && holds_thread_local_data && is_compressed && + has_special_ordering_requirements && is_excluded_unless_referenced_or_allocated) + { + } + switch (section->type) { case arch::memory::elf_section_type::PROGRAMM: { -- cgit v1.2.3 From 38e0b13ab9a4997fdf9f311fd125825919d2e6c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 14 Oct 2024 14:03:27 +0000 Subject: Start developing paging --- arch/x86_64/CMakeLists.txt | 1 + .../x86_64/include/arch/memory/frame_allocator.hpp | 117 ++++++++-------- arch/x86_64/include/arch/memory/multiboot.hpp | 2 +- arch/x86_64/include/arch/memory/paging.hpp | 150 +++++++++++++++++++++ arch/x86_64/include/arch/video/vga/io.hpp | 8 +- arch/x86_64/include/arch/video/vga/text.hpp | 32 ++--- arch/x86_64/src/kernel/main.cpp | 26 ++-- arch/x86_64/src/memory/frame_allocator.cpp | 35 ++--- arch/x86_64/src/memory/multiboot.cpp | 28 ++-- arch/x86_64/src/memory/paging.cpp | 53 ++++++++ 10 files changed, 328 insertions(+), 124 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/paging.hpp create mode 100644 arch/x86_64/src/memory/paging.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 882ea9a..25f8634 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -43,6 +43,7 @@ target_sources("_video" PRIVATE target_sources("_memory" PRIVATE "src/memory/multiboot.cpp" "src/memory/frame_allocator.cpp" + "src/memory/paging.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp index 1fd1f08..ab93231 100644 --- a/arch/x86_64/include/arch/memory/frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/frame_allocator.hpp @@ -8,47 +8,46 @@ namespace teachos::arch::memory { - namespace - { - constexpr std::size_t PAGE_FRAME_SIZE = 4096U; ///< Default page size of x86_84 is always 4KiB - } + constexpr std::size_t PAGE_FRAME_SIZE = 4096U; ///< Default page size of x86_84 is always 4KiB. /** - * @brief Specific frame containing helper functions to determine if a specific address is in that frame or not + * @brief Specific physical_frame containing helper functions to determine if a specific address is in that + * physical_frame or not. */ - struct frame + struct physical_frame { /** * @brief Constructor * - * @param frame_number Index number that should be assigned to this frame + * @param frame_number Index number that should be assigned to this physical_frame. */ - frame(std::size_t frame_number); + explicit physical_frame(std::size_t frame_number); /** - * @brief Returns the frame the given address is contained in + * @brief Returns the physical_frame the given address is contained in. * - * @param address Address we want to get the corresponding frame for - * @return Frame the given address is contained in + * @param address Address we want to get the corresponding physical_frame for. + * @return Frame the given address is contained in. */ - static auto containing_address(std::size_t address) -> frame; + static auto containing_address(std::size_t address) -> physical_frame; /** - * @brief Defaulted equals operator + * @brief Defaulted equals operator. */ - constexpr auto operator==(const frame & other) const -> bool = default; + constexpr auto operator==(const physical_frame & other) const -> bool = default; /** - * @brief Defaulted three-way comparsion operator + * @brief Defaulted three-way comparsion operator. */ - constexpr auto operator<=>(const frame & other) const -> std::partial_ordering = default; + constexpr auto operator<=>(const physical_frame & other) const -> std::partial_ordering = default; - std::size_t frame_number; ///< Index number of the current frame, used to distinguish it from other frames + std::size_t + frame_number; ///< Index number of the current physical frame, used to distinguish it from other frames. }; template concept FrameAllocator = requires(T t) { - { t.allocate_frame() } -> std::same_as>; + { t.allocate_frame() } -> std::same_as>; { t.deallocate_frame() } -> std::same_as; }; @@ -58,121 +57,121 @@ namespace teachos::arch::memory struct memory_area_iterator { /** - * @brief Constructor + * @brief Constructor. * - * @param p Underlying address the iterator should point too, ensure to not pass an invalid pointer + * @param p Underlying address the iterator should point too, ensure to not pass an invalid pointer. */ explicit memory_area_iterator(memory_area * p); /** * @brief Dereferences the initally given pointer to its value. * - * @return Reference to the value + * @return Reference to the value. */ memory_area & operator*() const; /** * @brief Post increment operator. Returns a copy of the value * - * @return Copy of the incremented underlying address + * @return Copy of the incremented underlying address. */ memory_area_iterator operator++(int); /** - * @brief Pre increment operator. Returns a reference to the changed value + * @brief Pre increment operator. Returns a reference to the changed value. * - * @return Reference to the incremented underlying address + * @return Reference to the incremented underlying address. */ memory_area_iterator & operator++(); /** * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. * - * @param other Other iterator to compare to - * @return Whether poith iterators point to the same underlying address in memory + * @param other Other iterator to compare to. + * @return Whether poith iterators point to the same underlying address in memory. */ bool operator==(memory_area_iterator const & other) const = default; private: - memory_area * ptr; ///< Underlying address the iterator is currently pointing too + memory_area * ptr; ///< Underlying address the iterator is currently pointing too. }; /** - * @brief Allocates memory using memory areas read from the multiboot2 information pointer + * @brief Allocates memory using memory areas read from the multiboot2 information pointer. */ struct area_frame_allocator { /** * @brief Constructor * - * @param kernel_start Start address of the kernel code in memory - * @param kernel_end End address of the kernel code in memory - * @param multiboot_start Start address of the multiboot code in memory - * @param multiboot_end End address of the multiboot code in memory - * @param memory_areas Pointer to the first element of all memory areas - * @param area_count Amount of total entries in the memory_areas array + * @param kernel_start Start address of the kernel code in memory. + * @param kernel_end End address of the kernel code in memory. + * @param multiboot_start Start address of the multiboot code in memory. + * @param multiboot_end End address of the multiboot code in memory. + * @param memory_areas Pointer to the first element of all memory areas. + * @param area_count Amount of total entries in the memory_areas array. */ area_frame_allocator(std::size_t kernel_start, std::size_t kernel_end, std::size_t multiboot_start, std::size_t multiboot_end, memory_area * memory_areas, uint8_t area_count) : area_begin(memory_areas) , area_end(memory_areas + area_count) - , kernel_start(frame::containing_address(kernel_start)) - , kernel_end(frame::containing_address(kernel_end)) - , multiboot_start(frame::containing_address(multiboot_start)) - , multiboot_end(frame::containing_address(multiboot_end)) + , kernel_start(physical_frame::containing_address(kernel_start)) + , kernel_end(physical_frame::containing_address(kernel_end)) + , multiboot_start(physical_frame::containing_address(multiboot_start)) + , multiboot_end(physical_frame::containing_address(multiboot_end)) { choose_next_area(); } /** - * @brief Allocate memory by finding and returning a free frame + * @brief Allocate memory by finding and returning a free physical_frame. * - * The frame allocation executes multiple checks before returning - * the frame that is available to allocate. It must at least + * The physical_frame allocation executes multiple checks before returning + * the physical_frame that is available to allocate. It must at least * do the following: * - check if the next_free_frame is within the current_area * - check if the next_free_frame is actually free - * - update the next_free_frame after finding a free frame + * - update the next_free_frame after finding a free physical_frame */ - auto allocate_frame() -> std::optional; + auto allocate_frame() -> std::optional; /** - * @brief Deallocates a previously allocated frame + * @brief Deallocates a previously allocated physical_frame. * - * @param frame Previously allocated frame that should be allocated + * @param physical_frame Previously allocated physical_frame that should be allocated. */ - auto deallocate_frame(frame frame) -> void; + auto deallocate_frame(physical_frame physical_frame) -> void; /** * @brief Returns the iterator pointing to the first element of the memory area. - * Allows using this class in the for each loop, because it follows the InputIterator template scheme + * Allows using this class in the for each loop, because it follows the InputIterator template scheme. * - * @return Iterator pointing to first element of the memory area + * @return Iterator pointing to first element of the memory area. */ auto begin() -> memory_area_iterator; /** * @brief Returns the iterator pointing to one past the last element of the memory area. - * Allows using this class in the for each loop, because it follows the InputIterator template scheme + * Allows using this class in the for each loop, because it follows the InputIterator template scheme. * - * @return Iterator pointing to one past the last element of the memory area + * @return Iterator pointing to one past the last element of the memory area. */ auto end() -> memory_area_iterator; private: /** - * @brief Find the next memory area and write it into current_area + * @brief Find the next memory area and write it into current_area. */ auto choose_next_area() -> void; - frame next_free_frame{0}; ///< The frame after the last allocated one - std::optional current_area{std::nullopt}; ///< The current memory area - memory_area_iterator area_begin; ///< Pointer to the first element of all memory areas - memory_area_iterator area_end; ///< Pointer to one pas the last element of all memory areas - frame const kernel_start; ///< The start address of the kernel code in memory - frame const kernel_end; ///< The end address of the kernel code in memory - frame const multiboot_start; ///< The start address of the multiboot code in memory - frame const multiboot_end; ///< The end address of the multiboot code in memory + physical_frame next_free_frame{0}; ///< The physical_frame after the last allocated one. + std::optional current_area{std::nullopt}; ///< The current memory area. + memory_area_iterator area_begin; ///< Pointer to the first element of all memory areas. + memory_area_iterator area_end; ///< Pointer to one pas the last element of all memory areas. + physical_frame const kernel_start; ///< The start address of the kernel code in memory. + physical_frame const kernel_end; ///< The end address of the kernel code in memory. + physical_frame const multiboot_start; ///< The start address of the multiboot code in memory. + physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index 35b483e..93d214c 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -152,7 +152,7 @@ namespace teachos::arch::memory * * @return Current section is writable. */ - auto writeable() const -> bool; + auto writable() const -> bool; /** * @brief (SHF_ALLOC) Whether the current section occupies memory during execution or not. ALLOC flag is shown in diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp new file mode 100644 index 0000000..a5408e1 --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -0,0 +1,150 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_HPP + +#include "frame_allocator.hpp" + +namespace teachos::arch::memory +{ + constexpr std::size_t PAGE_TABLE_ENTRY_COUNT = 512U; ///< Default entry count of a page table in x86_84 is 512. + + /** + * @brief Virtual page entry contained in P1 page tables + */ + struct virtual_page + { + std::size_t number; ///< Index number of the current virtual page, used to distinguish it from other pages. + + /** + * @brief Defaulted equals operator. + */ + constexpr auto operator==(const virtual_page & other) const -> bool = default; + + /** + * @brief Defaulted three-way comparsion operator. + */ + constexpr auto operator<=>(const virtual_page & other) const -> std::partial_ordering = default; + }; + + /** + * @brief Marks a specific entry in an actual page table. + */ + struct entry + { + /** + * @brief Whether the current page is unused, meaning the underlying std::bitset is 0. + * + * @return Current page is in memory. + */ + auto is_unused() const -> bool; + + /** + * @brief Marks the page as unused, meaning the underlying std::bitset is set to 0. + */ + auto set_unused() -> void; + + /** + * @brief Whether the current page is in memory and therefore present or not. Read from bit index 0. + * + * @return Current page is in memory. + */ + auto present() const -> bool; + + /** + * @brief Whether it is possible to write to the current page or not. Read from bit index 1. + * + * @return Current page can be written too. + */ + auto writable() const -> bool; + + /** + * @brief Whether the current page can be accessed in user mode, or only in kernel mode code. Read from bit index 2. + * + * @return Current page can be accessed in user mode. + */ + auto user_accessible() const -> bool; + + /** + * @brief Whether any write to the current page go directly to memory instead of the cache or not. Read from bit + * index 3. + * + * @return Writes to the current page go directly to memory. + */ + auto write_through_caching() const -> bool; + + /** + * @brief Whether the current page uses caching or not. Read from bit index 4. + * + * @return Current page does not use caching. + */ + auto disabled_caching() const -> bool; + + /** + * @brief Whether the current page is currently being used or not. Read from bit index 5. + * + * @return Current page is currently being used. + */ + auto is_accessing() const -> bool; + + /** + * @brief Whether the current page has been writen too or not. Read from bit index 6. + * + * @return Current page has been writen too. + */ + auto is_diry() const -> bool; + + /** + * @brief Whether the current page is huge or not (2 MiB page size in P2 page table and 1 GiB in P3 page table, + * instead of 4 KiB). Has to be false for P1 and P4 page tables. Read from bit index 7. + * + * @return Current page is huge + */ + auto is_huge_page() const -> bool; + + /** + * @brief Whether the current page is not flushed from caches on address space switches or not (PGE bit of CR4 + * register has to be set). Read from bit index 8. + * + * @return Current page is not flushed from caches on address space switches. + */ + auto is_global() const -> bool; + + /** + * @brief Whether the current page is forbidden from executing code or not (NXE bit in the EFER register has to be + * set). Read from bit index 63. + * + * @return Current page is forbidden from executing code. + */ + auto executing_code_forbidden() const -> bool; + + /** + * @brief Calculates the physical frame this entry is pointing too, can be null if the page is not present in + * memory. + * + * @return Calculated physical frame entry is pointing too. + */ + auto calculate_pointed_to_frame() const -> std::optional; + + private: + /** + * @brief Extracts the physical address from the underlying bitset read from bit index 12 - 51. Is a 52 bit page + * aligned physical address of the frame of the next page table or the pyhscial address of the frame for P1 page + * tables. + * + * @return Extracted physical address of the next page or of the frame for P1 page tables. + */ + auto calculate_physical_address() const -> std::size_t; + + /** + * @brief Checks the underlying std::bitset if the bit at the specific index is set, meaning a value of 1 + * + * @param index Specific index we want to check at + * @return Bit value 1 is set and will return true + */ + auto is_bit_set(uint8_t index) const -> bool; + + std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be freely + ///< used for additional flagsby the operating system. + }; +} // namespace teachos::arch::memory + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_HPP diff --git a/arch/x86_64/include/arch/video/vga/io.hpp b/arch/x86_64/include/arch/video/vga/io.hpp index da9375d..3d2e90c 100644 --- a/arch/x86_64/include/arch/video/vga/io.hpp +++ b/arch/x86_64/include/arch/video/vga/io.hpp @@ -10,24 +10,24 @@ namespace teachos::arch::video::vga namespace crtc { /** - * @brief The address port of the CRT Controller + * @brief The address port of the CRT Controller. */ using address_port = arch::io::port<0x3d4, 1>; /** - * @brief The data port of the CRT Controller + * @brief The data port of the CRT Controller. */ using data_port = arch::io::port<0x3d5, 1>; namespace registers { /** - * @brief The address of the Cursor Start register of the CRTC + * @brief The address of the Cursor Start register of the CRTC. */ [[maybe_unused]] auto constexpr cursor_start = std::byte{0x0a}; /** - * @brief The address of the Cursor End register of the CRTC + * @brief The address of the Cursor End register of the CRTC. */ [[maybe_unused]] auto constexpr curser_end = std::byte{0x0b}; } // namespace registers diff --git a/arch/x86_64/include/arch/video/vga/text.hpp b/arch/x86_64/include/arch/video/vga/text.hpp index 79ec7be..cfafce0 100644 --- a/arch/x86_64/include/arch/video/vga/text.hpp +++ b/arch/x86_64/include/arch/video/vga/text.hpp @@ -12,14 +12,14 @@ namespace teachos::arch::video::vga::text */ enum struct color : std::uint8_t { - black, /**< Equivalent to HTML color \#000000 */ - blue, /**< Equivalent to HTML color \#0000AA */ - green, /**< Equivalent to HTML color \#00AA00 */ - cyan, /**< Equivalent to HTML color \#00AAAA */ - red, /**< Equivalent to HTML color \#AA0000 */ - purple, /**< Equivalent to HTML color \#AA00AA */ - brown, /**< Equivalent to HTML color \#AA5500 */ - gray, /**< Equivalent to HTML color \#AAAAAA */ + black, ///< Equivalent to HTML color \#000000 + blue, ///< Equivalent to HTML color \#0000AA + green, ///< Equivalent to HTML color \#00AA00 + cyan, ///< Equivalent to HTML color \#00AAAA + red, ///< Equivalent to HTML color \#AA0000 + purple, ///< Equivalent to HTML color \#AA00AA + brown, ///< Equivalent to HTML color \#AA5500 + gray, ///< Equivalent to HTML color \#AAAAAA }; /** @@ -27,8 +27,8 @@ namespace teachos::arch::video::vga::text */ enum struct foreground_flag : bool { - none, /**< Apply no flag e.g., keep color as is. */ - intense, /**< Make the color more intense (usually brighter). */ + none, ///< Apply no flag e.g., keep color as is. + intense, ///< Make the color more intense (usually brighter). }; /** @@ -36,8 +36,8 @@ namespace teachos::arch::video::vga::text */ enum struct background_flag : bool { - none, /**< Apply no flag e.g., keep color as is. */ - blink_or_bright, /**< Make the cell blink or more intense, dependent on the VGA configuration */ + none, ///< Apply no flag e.g., keep color as is. + blink_or_bright, ///< Make the cell blink or more intense, dependent on the VGA configuration }; /** @@ -51,10 +51,10 @@ namespace teachos::arch::video::vga::text */ struct attribute { - color foreground_color : 3; /**< The foreground color of the cell, e.g. the color of the code point.*/ - enum foreground_flag foreground_flag : 1; /**< The foreground color modification flag of the cell.*/ - color bacground_color : 3; /**< The background color of the cell.*/ - enum background_flag background_flag : 1; /**< The background color modification flag of the cell.*/ + color foreground_color : 3; ///< The foreground color of the cell, e.g. the color of the code point + enum foreground_flag foreground_flag : 1; ///< The foreground color modification flag of the cell. + color bacground_color : 3; ///< The background color of the cell. + enum background_flag background_flag : 1; ///< The background color modification flag of the cell. }; static_assert(sizeof(attribute) == 1, "The VGA text mode attribute must fit inside a single byte."); diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index bdf530c..7e4a336 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -5,6 +5,8 @@ #include "arch/memory/multiboot.hpp" #include "arch/video/vga/text.hpp" +#include + namespace teachos::arch::kernel { auto assert(bool condition) -> void @@ -63,7 +65,7 @@ namespace teachos::arch::kernel for (auto section = begin; section != end; ++section) { - bool const writeable = section->flags.writeable(); + bool const writable = section->flags.writable(); bool const occupies_memory = section->flags.occupies_memory(); bool const is_executable = section->flags.is_executable(); bool const contains_duplicate_data = section->flags.contains_duplicate_data(); @@ -79,7 +81,7 @@ namespace teachos::arch::kernel bool const is_excluded_unless_referenced_or_allocated = section->flags.is_excluded_unless_referenced_or_allocated(); - if (writeable && occupies_memory && is_executable && contains_duplicate_data && contains_strings && + if (writable && occupies_memory && is_executable && contains_duplicate_data && contains_strings && section_header_info_is_section_header_table_index && preserve_ordering_after_combination && requires_special_os_processing && is_section_group_member && holds_thread_local_data && is_compressed && has_special_ordering_requirements && is_excluded_unless_referenced_or_allocated) @@ -182,20 +184,16 @@ namespace teachos::arch::kernel // Address of Frame: 0x203F00 auto allocator = arch::memory::area_frame_allocator(kernel_start, kernel_end, multiboot_start, multiboot_end, memory_areas, area_count); - auto allocated = allocator.allocate_frame(); // WATCH OUT: using optional::value() crashes the build... I think its because of missing exception handling - if (allocated.has_value()) - { - video::vga::text::write("Allocated Frame address: ", video::vga::text::common_attributes::green_on_black); - video::vga::text::write_number(reinterpret_cast(&allocated->frame_number), - video::vga::text::common_attributes::green_on_black); - video::vga::text::write("Allocated Frame number: ", video::vga::text::common_attributes::green_on_black); - video::vga::text::write_number(allocated->frame_number, video::vga::text::common_attributes::green_on_black); - } - else + auto last_allocated = allocator.allocate_frame(); + auto allocated = last_allocated; + do { - video::vga::text::write("NO VALUE", video::vga::text::common_attributes::green_on_black); - } + last_allocated = allocated; + allocated = allocator.allocate_frame(); + } while (allocated.has_value()); + video::vga::text::write("Allocated Frames", video::vga::text::common_attributes::green_on_black); + video::vga::text::write_number(allocated->frame_number, video::vga::text::common_attributes::green_on_black); } } // namespace teachos::arch::kernel diff --git a/arch/x86_64/src/memory/frame_allocator.cpp b/arch/x86_64/src/memory/frame_allocator.cpp index 3ad2d96..3733cc3 100644 --- a/arch/x86_64/src/memory/frame_allocator.cpp +++ b/arch/x86_64/src/memory/frame_allocator.cpp @@ -2,13 +2,16 @@ namespace teachos::arch::memory { - frame::frame(std::size_t frame_number) + physical_frame::physical_frame(std::size_t frame_number) : frame_number(frame_number) { // Nothing to do } - auto frame::containing_address(std::size_t address) -> frame { return frame{address / PAGE_FRAME_SIZE}; } + auto physical_frame::containing_address(std::size_t address) -> physical_frame + { + return physical_frame{address / PAGE_FRAME_SIZE}; + } memory_area_iterator::memory_area_iterator(memory_area * p) : ptr(p) @@ -39,7 +42,7 @@ namespace teachos::arch::memory memory_area & area = *it; std::size_t address = area.base_address + area.area_length - 1; - if (frame::containing_address(address) >= next_free_frame) + if (physical_frame::containing_address(address) >= next_free_frame) { // The `next_free_frame` address is smaller than the last address of the current area if (!current_area || area.base_address < current_area->base_address) @@ -52,7 +55,7 @@ namespace teachos::arch::memory if (current_area) { // Update the `next_free_frame` according to the new memory area - frame start_frame = frame::containing_address(current_area->base_address); + physical_frame start_frame = physical_frame::containing_address(current_area->base_address); if (next_free_frame < start_frame) { next_free_frame = start_frame; @@ -60,7 +63,7 @@ namespace teachos::arch::memory } } - auto area_frame_allocator::allocate_frame() -> std::optional + auto area_frame_allocator::allocate_frame() -> std::optional { /* * Only try to allocate memory if current_area is not null, because @@ -68,29 +71,29 @@ namespace teachos::arch::memory */ if (current_area) { - frame frame{next_free_frame.frame_number}; + physical_frame physical_frame{next_free_frame.frame_number}; - struct frame current_area_last_frame = { - frame::containing_address(current_area->base_address + current_area->area_length - 1)}; + struct physical_frame current_area_last_frame = { + physical_frame::containing_address(current_area->base_address + current_area->area_length - 1)}; if (next_free_frame > current_area_last_frame) { // All frames of current area are used, switch to next area choose_next_area(); } - else if (frame >= multiboot_start && frame <= kernel_end) + else if (physical_frame >= multiboot_start && physical_frame <= kernel_end) { - // `frame` is used by the kernel or multiboot information structure - next_free_frame = arch::memory::frame{kernel_end.frame_number + 1}; + // `physical_frame` is used by the kernel or multiboot information structure + next_free_frame = arch::memory::physical_frame{kernel_end.frame_number + 1}; } else { // Frame is unused, increment `next_free_frame` and return it next_free_frame.frame_number += 1; - return frame; + return physical_frame; } - // `frame` was not valid, try it again with the updated `next_free_frame` + // `physical_frame` was not valid, try it again with the updated `next_free_frame` return allocate_frame(); } @@ -98,10 +101,10 @@ namespace teachos::arch::memory return std::nullopt; } - auto area_frame_allocator::deallocate_frame(frame frame) -> void + auto area_frame_allocator::deallocate_frame(physical_frame physical_frame) -> void { - // TODO: Fix, simply done because compiler will complain if frame is unused and not compile - if (frame.frame_number == 3) + // TODO: Fix, simply done because compiler will complain if physical_frame is unused and not compile + if (physical_frame.frame_number == 3) { } } diff --git a/arch/x86_64/src/memory/multiboot.cpp b/arch/x86_64/src/memory/multiboot.cpp index 3f6248d..bd3b00b 100644 --- a/arch/x86_64/src/memory/multiboot.cpp +++ b/arch/x86_64/src/memory/multiboot.cpp @@ -2,35 +2,35 @@ namespace teachos::arch::memory { - auto elf_section_flags::writeable() const -> bool { return is_bit_set(0); } + auto elf_section_flags::writable() const -> bool { return is_bit_set(0U); } - auto elf_section_flags::occupies_memory() const -> bool { return is_bit_set(1); } + auto elf_section_flags::occupies_memory() const -> bool { return is_bit_set(1U); } - auto elf_section_flags::is_executable() const -> bool { return is_bit_set(2); } + auto elf_section_flags::is_executable() const -> bool { return is_bit_set(2U); } - auto elf_section_flags::contains_duplicate_data() const -> bool { return is_bit_set(4); } + auto elf_section_flags::contains_duplicate_data() const -> bool { return is_bit_set(4U); } - auto elf_section_flags::contains_strings() const -> bool { return is_bit_set(5); } + auto elf_section_flags::contains_strings() const -> bool { return is_bit_set(5U); } - auto elf_section_flags::section_header_info_is_section_header_table_index() const -> bool { return is_bit_set(6); } + auto elf_section_flags::section_header_info_is_section_header_table_index() const -> bool { return is_bit_set(6U); } - auto elf_section_flags::preserve_ordering_after_combination() const -> bool { return is_bit_set(7); } + auto elf_section_flags::preserve_ordering_after_combination() const -> bool { return is_bit_set(7U); } - auto elf_section_flags::requires_special_os_processing() const -> bool { return is_bit_set(8); } + auto elf_section_flags::requires_special_os_processing() const -> bool { return is_bit_set(8U); } - auto elf_section_flags::is_section_group_member() const -> bool { return is_bit_set(9); } + auto elf_section_flags::is_section_group_member() const -> bool { return is_bit_set(9U); } - auto elf_section_flags::holds_thread_local_data() const -> bool { return is_bit_set(10); } + auto elf_section_flags::holds_thread_local_data() const -> bool { return is_bit_set(10U); } - auto elf_section_flags::is_compressed() const -> bool { return is_bit_set(11); } + auto elf_section_flags::is_compressed() const -> bool { return is_bit_set(11U); } - auto elf_section_flags::has_special_ordering_requirements() const -> bool { return is_bit_set(30); } + auto elf_section_flags::has_special_ordering_requirements() const -> bool { return is_bit_set(30U); } - auto elf_section_flags::is_excluded_unless_referenced_or_allocated() const -> bool { return is_bit_set(31); } + auto elf_section_flags::is_excluded_unless_referenced_or_allocated() const -> bool { return is_bit_set(31U); } auto elf_section_flags::operator==(elf_section_flags const & other) const -> bool { return flags == other.flags; } - auto elf_section_flags::is_bit_set(uint8_t index) const -> bool { return flags[index] == 1; } + auto elf_section_flags::is_bit_set(uint8_t index) const -> bool { return flags[index] == 1U; } auto elf_section_header::is_null() const -> bool { diff --git a/arch/x86_64/src/memory/paging.cpp b/arch/x86_64/src/memory/paging.cpp new file mode 100644 index 0000000..555357c --- /dev/null +++ b/arch/x86_64/src/memory/paging.cpp @@ -0,0 +1,53 @@ +#include "arch/memory/paging.hpp" + +namespace teachos::arch::memory +{ + auto entry::is_unused() const -> bool { return flags == 0U; } + + auto entry::set_unused() -> void { flags = 0U; } + + auto entry::present() const -> bool { return is_bit_set(0U); } + + auto entry::writable() const -> bool { return is_bit_set(1U); } + + auto entry::user_accessible() const -> bool { return is_bit_set(2U); } + + auto entry::write_through_caching() const -> bool { return is_bit_set(3U); } + + auto entry::disabled_caching() const -> bool { return is_bit_set(4U); } + + auto entry::is_accessing() const -> bool { return is_bit_set(5U); } + + auto entry::is_diry() const -> bool { return is_bit_set(6U); } + + auto entry::is_huge_page() const -> bool { return is_bit_set(7U); } + + auto entry::is_global() const -> bool { return is_bit_set(8U); } + + auto entry::executing_code_forbidden() const -> bool { return is_bit_set(63U); } + + auto entry::calculate_pointed_to_frame() const -> std::optional + { + if (present()) + { + auto physical_address = calculate_physical_address(); + return physical_frame::containing_address(physical_address); + } + return std::nullopt; + } + + auto entry::calculate_physical_address() const -> std::size_t + { + constexpr std::size_t start_bit = 12U; + constexpr std::size_t end_bit = 51U; + size_t value = 0U; + + for (auto i = start_bit; i < end_bit; i++) + { + value |= (flags[i] ? (1 << (i - start_bit)) : 0); + } + return value; + } + + auto entry::is_bit_set(uint8_t index) const -> bool { return flags[index] == 1U; } +} // namespace teachos::arch::memory -- cgit v1.2.3 From 205934ca45d591924b4be6e7ae5a8849958e0cf6 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 15 Oct 2024 08:23:39 +0000 Subject: continue implementing paging --- CMakeLists.txt | 10 ++- arch/x86_64/CMakeLists.txt | 8 ++ .../include/arch/exception_handling/assert.hpp | 11 +++ .../x86_64/include/arch/memory/frame_allocator.hpp | 7 ++ arch/x86_64/include/arch/memory/paging.hpp | 99 ++++++---------------- arch/x86_64/src/exception_handling/assert.cpp | 24 ++++++ arch/x86_64/src/kernel/main.cpp | 42 ++------- arch/x86_64/src/memory/frame_allocator.cpp | 12 ++- arch/x86_64/src/memory/paging.cpp | 36 +++----- 9 files changed, 113 insertions(+), 136 deletions(-) create mode 100644 arch/x86_64/include/arch/exception_handling/assert.hpp create mode 100644 arch/x86_64/src/exception_handling/assert.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f5cc7ea..3586669 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,12 +101,19 @@ add_library("_video" OBJECT) add_library("teachos::video" ALIAS "_video") #[============================================================================[ -# The memory Library +# THE Memory Library #]============================================================================] add_library("_memory" OBJECT) add_library("teachos::memory" ALIAS "_memory") +#[============================================================================[ +# The Exception handling Library +#]============================================================================] + +add_library("_exception" OBJECT) +add_library("teachos::exception" ALIAS "_exception") + #[============================================================================[ # The Kernel #]============================================================================] @@ -120,6 +127,7 @@ target_link_libraries("_kernel" PRIVATE "teachos::boot" "teachos::video" "teachos::memory" + "teachos::exception" ) #[============================================================================[ diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 25f8634..603393c 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -46,6 +46,14 @@ target_sources("_memory" PRIVATE "src/memory/paging.cpp" ) +#[============================================================================[ +# The Exception handling Library +#]============================================================================] + +target_sources("_exception" PRIVATE + "src/exception_handling/assert.cpp" +) + #[============================================================================[ # The Bootable ISO Image #]============================================================================] diff --git a/arch/x86_64/include/arch/exception_handling/assert.hpp b/arch/x86_64/include/arch/exception_handling/assert.hpp new file mode 100644 index 0000000..eba43ac --- /dev/null +++ b/arch/x86_64/include/arch/exception_handling/assert.hpp @@ -0,0 +1,11 @@ +namespace teachos::arch::exception_handling +{ + /** + * @brief assert a condition to be true, if not do not continue + * execution of the code and print message to screen + * + * @param condition + * @param message + */ + auto assert(bool condition, char const * message) -> void; +} // namespace teachos::arch::exception_handling \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp index ab93231..69c108c 100644 --- a/arch/x86_64/include/arch/memory/frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/frame_allocator.hpp @@ -31,6 +31,13 @@ namespace teachos::arch::memory */ static auto containing_address(std::size_t address) -> physical_frame; + /** + * @brief TODO + * + * @return uint64_t + */ + auto start_address() const -> uint64_t; + /** * @brief Defaulted equals operator. */ diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp index a5408e1..1870c28 100644 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -42,72 +42,6 @@ namespace teachos::arch::memory */ auto set_unused() -> void; - /** - * @brief Whether the current page is in memory and therefore present or not. Read from bit index 0. - * - * @return Current page is in memory. - */ - auto present() const -> bool; - - /** - * @brief Whether it is possible to write to the current page or not. Read from bit index 1. - * - * @return Current page can be written too. - */ - auto writable() const -> bool; - - /** - * @brief Whether the current page can be accessed in user mode, or only in kernel mode code. Read from bit index 2. - * - * @return Current page can be accessed in user mode. - */ - auto user_accessible() const -> bool; - - /** - * @brief Whether any write to the current page go directly to memory instead of the cache or not. Read from bit - * index 3. - * - * @return Writes to the current page go directly to memory. - */ - auto write_through_caching() const -> bool; - - /** - * @brief Whether the current page uses caching or not. Read from bit index 4. - * - * @return Current page does not use caching. - */ - auto disabled_caching() const -> bool; - - /** - * @brief Whether the current page is currently being used or not. Read from bit index 5. - * - * @return Current page is currently being used. - */ - auto is_accessing() const -> bool; - - /** - * @brief Whether the current page has been writen too or not. Read from bit index 6. - * - * @return Current page has been writen too. - */ - auto is_diry() const -> bool; - - /** - * @brief Whether the current page is huge or not (2 MiB page size in P2 page table and 1 GiB in P3 page table, - * instead of 4 KiB). Has to be false for P1 and P4 page tables. Read from bit index 7. - * - * @return Current page is huge - */ - auto is_huge_page() const -> bool; - - /** - * @brief Whether the current page is not flushed from caches on address space switches or not (PGE bit of CR4 - * register has to be set). Read from bit index 8. - * - * @return Current page is not flushed from caches on address space switches. - */ - auto is_global() const -> bool; - /** * @brief Whether the current page is forbidden from executing code or not (NXE bit in the EFER register has to be * set). Read from bit index 63. @@ -124,6 +58,22 @@ namespace teachos::arch::memory */ auto calculate_pointed_to_frame() const -> std::optional; + /** + * @brief TODO + * + * @param frame + */ + auto set(physical_frame frame) -> void; + + /** + * @brief TODO + * + * @param b + * @return true + * @return false + */ + auto contains_flags(std::bitset<64U> b) const -> bool; + private: /** * @brief Extracts the physical address from the underlying bitset read from bit index 12 - 51. Is a 52 bit page @@ -134,17 +84,18 @@ namespace teachos::arch::memory */ auto calculate_physical_address() const -> std::size_t; - /** - * @brief Checks the underlying std::bitset if the bit at the specific index is set, meaning a value of 1 - * - * @param index Specific index we want to check at - * @return Bit value 1 is set and will return true - */ - auto is_bit_set(uint8_t index) const -> bool; - std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be freely ///< used for additional flagsby the operating system. }; + + /** + * @brief TODO + * + */ + struct page_table + { + entry entries[PAGE_TABLE_ENTRY_COUNT]; + }; } // namespace teachos::arch::memory #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_HPP diff --git a/arch/x86_64/src/exception_handling/assert.cpp b/arch/x86_64/src/exception_handling/assert.cpp new file mode 100644 index 0000000..b55da49 --- /dev/null +++ b/arch/x86_64/src/exception_handling/assert.cpp @@ -0,0 +1,24 @@ +#include "arch/video/vga/text.hpp" + +namespace teachos::arch::exception_handling +{ + auto assert(bool condition, char const * message) -> void + { + if (condition) + { + return; + } + + video::vga::text::write("Assert failed: ", video::vga::text::common_attributes::green_on_black); + video::vga::text::write(message, video::vga::text::common_attributes::green_on_black); + for (;;) + { + // Trick the compiler into thinking the variable is changes at run time, + // to prevent the while loop being optimized away + // See + // https://stackoverflow.com/questions/9495856/how-to-prevent-g-from-optimizing-out-a-loop-controlled-by-a-variable-that-can + // for more information. + asm volatile("" : "+g"(condition)); + } + } +} // namespace teachos::arch::exception_handling \ No newline at end of file diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 7e4a336..c8981a8 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,6 +1,7 @@ #include "arch/kernel/main.hpp" #include "arch/boot/pointers.hpp" +#include "arch/exception_handling/assert.hpp" #include "arch/memory/frame_allocator.hpp" #include "arch/memory/multiboot.hpp" #include "arch/video/vga/text.hpp" @@ -9,31 +10,12 @@ namespace teachos::arch::kernel { - auto assert(bool condition) -> void - { - if (condition) - { - return; - } - - video::vga::text::write("Assert failed", video::vga::text::common_attributes::green_on_black); - for (;;) - { - // Trick the compiler into thinking the variable is changes at run time, - // to prevent the while loop being optimized away - // See - // https://stackoverflow.com/questions/9495856/how-to-prevent-g-from-optimizing-out-a-loop-controlled-by-a-variable-that-can - // for more information. - asm volatile("" : "+g"(condition)); - } - } - auto process_memory_map(arch::memory::memory_map * mminfo, arch::memory::memory_area *& memory_areas, uint8_t & area_count) -> void { auto expected_entry_size = mminfo->entry_size; constexpr auto actual_entry_size = sizeof(arch::memory::memory_area); - assert(expected_entry_size == actual_entry_size); + arch::exception_handling::assert(expected_entry_size == actual_entry_size, "Unexpected memoryarea entry size"); auto total_size = mminfo->tag.size; auto total_entries_size = total_size - sizeof(arch::memory::memory_map) + actual_entry_size; @@ -48,17 +30,18 @@ namespace teachos::arch::kernel { auto expected_entry_size = symbol->entry_size; constexpr auto actual_entry_size = sizeof(arch::memory::elf_section_header); - assert(expected_entry_size == actual_entry_size); + arch::exception_handling::assert(expected_entry_size == actual_entry_size, + "Unexpected elf_section_header entry size"); auto expected_total_size = symbol->tag.size; auto actual_total_entry_size = actual_entry_size * symbol->number_of_sections; constexpr auto actual_total_section_size = sizeof(arch::memory::elf_symbols_section) - sizeof(uint32_t); auto actual_total_size = actual_total_entry_size + actual_total_section_size; - assert(expected_total_size == actual_total_size); + arch::exception_handling::assert(expected_total_size == actual_total_size, "Unexpected elf_symbols total size"); auto begin = reinterpret_cast(&symbol->end); auto end = begin + symbol->number_of_sections; - assert(begin->is_null()); + arch::exception_handling::assert(begin->is_null(), "Missing elf_section_header begin"); std::size_t symbol_table_section_count = 0U; std::size_t dynamic_section_count = 0U; @@ -115,8 +98,8 @@ namespace teachos::arch::kernel } } - assert(symbol_table_section_count == 1U); - assert(dynamic_section_count <= 1U); + arch::exception_handling::assert(symbol_table_section_count == 1U, "Unexpected symbol_table_count value"); + arch::exception_handling::assert(dynamic_section_count <= 1U, "Unexpected dynamic_section_count value"); } template @@ -173,15 +156,6 @@ namespace teachos::arch::kernel } } - // Kernel start 0x100000 - // Kernel end 0x23E943 - // Kernel Size 0x13E943 -> 1'304'899 - // Multiboot start 0x241AA0 - // Multiboot end 0x242280 - // Multiboot Size 0x7E0 -> 2'016 - // Memory area start 0x241b10 - // - // Address of Frame: 0x203F00 auto allocator = arch::memory::area_frame_allocator(kernel_start, kernel_end, multiboot_start, multiboot_end, memory_areas, area_count); diff --git a/arch/x86_64/src/memory/frame_allocator.cpp b/arch/x86_64/src/memory/frame_allocator.cpp index 3733cc3..01dcc88 100644 --- a/arch/x86_64/src/memory/frame_allocator.cpp +++ b/arch/x86_64/src/memory/frame_allocator.cpp @@ -1,7 +1,11 @@ #include "arch/memory/frame_allocator.hpp" +#include "arch/exception_handling/assert.hpp" + namespace teachos::arch::memory { + uint64_t PAGE_SIZE; + physical_frame::physical_frame(std::size_t frame_number) : frame_number(frame_number) { @@ -13,6 +17,8 @@ namespace teachos::arch::memory return physical_frame{address / PAGE_FRAME_SIZE}; } + auto physical_frame::start_address() const -> uint64_t { return frame_number * PAGE_SIZE; } + memory_area_iterator::memory_area_iterator(memory_area * p) : ptr(p) { @@ -103,10 +109,8 @@ namespace teachos::arch::memory auto area_frame_allocator::deallocate_frame(physical_frame physical_frame) -> void { - // TODO: Fix, simply done because compiler will complain if physical_frame is unused and not compile - if (physical_frame.frame_number == 3) - { - } + arch::exception_handling::assert(false && physical_frame.frame_number == 0, + "[deallocate_frame] Not implemented Exception"); } auto area_frame_allocator::begin() -> memory_area_iterator { return area_begin; } diff --git a/arch/x86_64/src/memory/paging.cpp b/arch/x86_64/src/memory/paging.cpp index 555357c..90c4199 100644 --- a/arch/x86_64/src/memory/paging.cpp +++ b/arch/x86_64/src/memory/paging.cpp @@ -1,34 +1,16 @@ #include "arch/memory/paging.hpp" +#include "arch/exception_handling/assert.hpp" + namespace teachos::arch::memory { auto entry::is_unused() const -> bool { return flags == 0U; } auto entry::set_unused() -> void { flags = 0U; } - auto entry::present() const -> bool { return is_bit_set(0U); } - - auto entry::writable() const -> bool { return is_bit_set(1U); } - - auto entry::user_accessible() const -> bool { return is_bit_set(2U); } - - auto entry::write_through_caching() const -> bool { return is_bit_set(3U); } - - auto entry::disabled_caching() const -> bool { return is_bit_set(4U); } - - auto entry::is_accessing() const -> bool { return is_bit_set(5U); } - - auto entry::is_diry() const -> bool { return is_bit_set(6U); } - - auto entry::is_huge_page() const -> bool { return is_bit_set(7U); } - - auto entry::is_global() const -> bool { return is_bit_set(8U); } - - auto entry::executing_code_forbidden() const -> bool { return is_bit_set(63U); } - auto entry::calculate_pointed_to_frame() const -> std::optional { - if (present()) + if (contains_flags(1)) { auto physical_address = calculate_physical_address(); return physical_frame::containing_address(physical_address); @@ -39,7 +21,7 @@ namespace teachos::arch::memory auto entry::calculate_physical_address() const -> std::size_t { constexpr std::size_t start_bit = 12U; - constexpr std::size_t end_bit = 51U; + constexpr std::size_t end_bit = 52U; size_t value = 0U; for (auto i = start_bit; i < end_bit; i++) @@ -49,5 +31,13 @@ namespace teachos::arch::memory return value; } - auto entry::is_bit_set(uint8_t index) const -> bool { return flags[index] == 1U; } + auto entry::set(physical_frame frame) -> void + { + arch::exception_handling::assert((frame.start_address() & ~0x000fffff'fffff000) == 0, + "Start address is not aligned with Page"); + flags = std::bitset<64U>(frame.start_address()) | flags; + } + + auto entry::contains_flags(std::bitset<64U> b) const -> bool { return (flags & b) == b; } + } // namespace teachos::arch::memory -- cgit v1.2.3 From 03d3dec4807d6adcfc5e21bd13992014900b4eac Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 15 Oct 2024 08:40:56 +0000 Subject: implement page table members --- arch/x86_64/include/arch/memory/frame_allocator.hpp | 4 ++-- arch/x86_64/include/arch/memory/paging.hpp | 21 +++++++++++++++++++-- arch/x86_64/src/memory/paging.cpp | 11 +++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp index 69c108c..3d1f826 100644 --- a/arch/x86_64/include/arch/memory/frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/frame_allocator.hpp @@ -32,9 +32,9 @@ namespace teachos::arch::memory static auto containing_address(std::size_t address) -> physical_frame; /** - * @brief TODO + * @brief Evaluates the start address of the physical frame * - * @return uint64_t + * @return start address of the physical frame */ auto start_address() const -> uint64_t; diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp index 1870c28..43f13e0 100644 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -89,11 +89,28 @@ namespace teachos::arch::memory }; /** - * @brief TODO - * + * @brief A Page table containing 512 entries */ struct page_table { + /** + * @brief Set every entry of the page to unused + */ + auto zero_entries() -> void; + + /** + * @brief Index operator overload to access specific entries directy + * + * @param index + * @return The address of the accessed entry + */ + entry & operator[](size_t index) + { + arch::exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] index out of bounds"); + return entries[index]; + } + + private: entry entries[PAGE_TABLE_ENTRY_COUNT]; }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/memory/paging.cpp b/arch/x86_64/src/memory/paging.cpp index 90c4199..58a2b99 100644 --- a/arch/x86_64/src/memory/paging.cpp +++ b/arch/x86_64/src/memory/paging.cpp @@ -40,4 +40,15 @@ namespace teachos::arch::memory auto entry::contains_flags(std::bitset<64U> b) const -> bool { return (flags & b) == b; } + auto page_table::zero_entries() -> void + { + auto begin = &entries[0]; + auto end = &entries[PAGE_TABLE_ENTRY_COUNT]; + + for (auto entry = begin; entry < end; ++entry) + { + entry->set_unused(); + } + } + } // namespace teachos::arch::memory -- cgit v1.2.3 From 11f9c91e602bd0231e6bc402418dedf445e47402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 15 Oct 2024 08:45:29 +0000 Subject: Adding enum flags --- arch/x86_64/include/arch/memory/multiboot.hpp | 146 +++++++------------------- arch/x86_64/include/arch/memory/paging.hpp | 47 ++++++--- arch/x86_64/src/kernel/main.cpp | 34 +++--- arch/x86_64/src/memory/multiboot.cpp | 36 +------ arch/x86_64/src/memory/paging.cpp | 7 +- 5 files changed, 94 insertions(+), 176 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index 93d214c..6fc10df 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -133,6 +133,35 @@ namespace teachos::arch::memory */ struct elf_section_flags { + /** + * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + */ + enum bitset : uint32_t + { + WRITABLE = 1 << 0, ///< (SHF_WRITE) Section is writable at runtime. If it isn't then the section + ///< is assumed to be READONLY and only that flag is shown in the objdump. + OCCUPIES_MEMORY = 1 << 1, ///< (SHF_ALLOC) Section occupies memory during execution. + ///< ALLOC flag is shown in the objdump. + EXECUTABLE_CODE = 1 << 2, ///< (SHF_EXECINSTR) Section is executable. CODE flag is shown in the object dump. + DUPLICATE_DATA = 1 << 4, ///< (SHF_MERGE) Section might be merged with another section. + CONTAINS_STRING = 1 << 5, ///< (SHF_STRINGS) Section contains null-terminated strings. + SECTION_HEADER_INFO_IS_SECTION_HEADER_TABLE_INDEX = + 1 << 6, ///< (SHF_INFO_LINK) Section contains the section header table index in the (sh_info) + ///< additional_information variable. + PRESERVE_ORDERING_AFTER_COMBINATION = + 1 << 7, ///< (SHF_LINK_ORDER) Section preserves order after combining with another section. + REQUIRES_SPECIAL_OS_PROCESSING = + 1 << 8, ///< (SHF_OS_NONCONFORMING) Section requires non-standard OS specific handling of its code or + ///< data, which does not confirm to standard ELF specifications. + SECTION_GROUP_MEMBER = 1 << 9, ///< (SHF_GROUP) Section is a member of a section group. + HOLDS_THREAD_LOCAL_DATA = 1 << 10, ///< (SHF_TLS) Section holds thread-local data. + COMPRESSED = 1 << 11, ///< (SHF_COMPRESSED) Section contains compressed data. + SPECIAL_ORDERING_REQUIREMENTS = 1 << 30, ///< (SHF_ORDERED) Section has special ordering requirements, meaning it + ///< should be ordered in relation to other sections of the same type + EXCLUDED_UNLESS_REFERENCED_OR_ALLOCATED = 1 << 31, ///< (SHF_EXCLUDE)Section is excluded unless referenced or + ///< allocated, used for LTO (Link-Time Optimizations) + }; + /** * @brief Constructor. * @@ -146,109 +175,14 @@ namespace teachos::arch::memory } /** - * @brief (SHF_WRITE) Wether the current section is writable at runtime or not. If it isn't then the section is - * assumed to be READONLY and only that flag is shown in the objdump -h of the kernel file. Read from bit index - * 0. - * - * @return Current section is writable. - */ - auto writable() const -> bool; - - /** - * @brief (SHF_ALLOC) Whether the current section occupies memory during execution or not. ALLOC flag is shown in - * the objdump -h of the kernel file. Read from bit index 1. - * - * @return Current section occupies memory during execution. - */ - auto occupies_memory() const -> bool; - - /** - * @brief (SHF_EXECINSTR) Whether the current section is executable or not. CODE flag is shown in the object dump. - * Read from bit index 2. - * - * @return Current section is executable. - */ - auto is_executable() const -> bool; - - /** - * @brief (SHF_MERGE) Whether the current section might be merged with another section or not. Read from bit - * index 4. - * - * @return Current section might be merged with another section - */ - auto contains_duplicate_data() const -> bool; - - /** - * @brief (SHF_STRINGS) Whether the current section contains null-terminated strings or not. Read from bit - * index 5. - * - * @return Current section contains null-terminated strings - */ - auto contains_strings() const -> bool; - - /** - * @brief (SHF_INFO_LINK) Whether the current section contains the section header table index in the (sh_info) - * additional_information variable or not. Read from bit index 6. - * - * @return Current section contains the section header table index in the (sh_info) - * additional_information variable - */ - auto section_header_info_is_section_header_table_index() const -> bool; - - /** - * @brief (SHF_LINK_ORDER) Whether the current section preserves order after combining with another section or not. - * Read from bit index 7. + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all + * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits + * that are set are not relevant. * - * @return Current section preserves order after combining with another section + * @param flags Flags that we want to compare against and check if the underlying std::bitset has the same bits set. + * @return Whether the given flags are a subset or equivalent with the underlying std::bitset */ - auto preserve_ordering_after_combination() const -> bool; - - /** - * @brief (SHF_OS_NONCONFORMING) Whether the current section requires non-standard OS specific handling of its code - * or data, which does not confirm to standard ELF specifications. Read from bit index 8. - * - * @return Current section requires non-standard OS specific handling - */ - auto requires_special_os_processing() const -> bool; - - /** - * @brief (SHF_GROUP) Whether the current section is a member of a section group or not. Read from bit index 9. - * - * @return Current section is a member of a section group - */ - auto is_section_group_member() const -> bool; - - /** - * @brief (SHF_TLS) Whether the current section holds thread-local data or not. Read from bit - * index 10. - * - * @return Current section holds thread-local data - */ - auto holds_thread_local_data() const -> bool; - - /** - * @brief (SHF_COMPRESSED) Whether the current section contains compressed data or not. Read from bit - * index 11. - * - * @return Current section contains compressed data - */ - auto is_compressed() const -> bool; - - /** - * @brief (SHF_ORDERED) Whether the current section has special ordering requirements, meaning it should be ordered - * in relation to other sections of the same type. Read from bit index 30. - * - * @return current section has special ordering requirements - */ - auto has_special_ordering_requirements() const -> bool; - - /** - * @brief (SHF_EXCLUDE) Whether the current section is excluded unless refereenced or allocated, used for LTO - * (Link-Time Optimizations). Read from bit index 31. - * - * @return Current section is excluded unless refereenced or allocated - */ - auto is_excluded_unless_referenced_or_allocated() const -> bool; + auto contains_flags(std::bitset<64U> b) const -> bool; /** * @brief Allows to compare the underlying std::bitset of two instances @@ -256,17 +190,9 @@ namespace teachos::arch::memory * @param other Other instance that we want to compare with * @return Whether the underlying std::bitset of both types is the same */ - auto operator==(elf_section_flags const & other) const -> bool; + auto operator==(elf_section_flags const & other) const -> bool = default; private: - /** - * @brief Checks the underlying std::bitset if the bit at the specific index is set, meaning a value of 1 - * - * @param index Specific index we want to check at - * @return Bit value 1 is set and will return true - */ - auto is_bit_set(uint8_t index) const -> bool; - std::bitset<64U> flags; }; diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp index 43f13e0..aa20da7 100644 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -30,6 +30,27 @@ namespace teachos::arch::memory */ struct entry { + /** + * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + */ + enum bitset : uint64_t + { + PRESENT = 1 << 0, ///< Page is in memory and therefore present. + ///< is assumed to be READONLY and only that flag is shown in the objdump. + WRITABLE = 1 << 1, ///< It is possible to write to the page. + USER_ACCESIBLE = 1 << 2, ///< Page can be accessed in user mode instead of only in kernel mode code. + WRITE_THROUGH_CACHING = 1 << 3, ///< Write to the page go directly to memory instead of the cache. + DISABLED_CACHING = 1 << 4, ///< Page uses caching. + ACCESSED = 1 << 5, ///< Page is currently in use. + DIRTY = 1 << 6, ///< Page has been writen too. + HUGE_PAGE = 1 << 7, ///< Page is huge (2 MiB page size in P2 page table and 1 GiB in P3 page table, + ///< instead of 4 KiB). Has to be false for P1 and P4 page tables. + GLOBAL = 1 << 8, ///< Page is not flushed from caches on address space switches (PGE bit of CR4 register + ///< has to be set) + EXECUTING_CODE_FORBIDDEN = + 1 << 63, ///< Page is forbidden from executing code (NXE bit in the EFER register has to be set) + }; + /** * @brief Whether the current page is unused, meaning the underlying std::bitset is 0. * @@ -42,14 +63,6 @@ namespace teachos::arch::memory */ auto set_unused() -> void; - /** - * @brief Whether the current page is forbidden from executing code or not (NXE bit in the EFER register has to be - * set). Read from bit index 63. - * - * @return Current page is forbidden from executing code. - */ - auto executing_code_forbidden() const -> bool; - /** * @brief Calculates the physical frame this entry is pointing too, can be null if the page is not present in * memory. @@ -59,18 +72,20 @@ namespace teachos::arch::memory auto calculate_pointed_to_frame() const -> std::optional; /** - * @brief TODO + * @brief Copies the address from the given physical frame into the underlying std::bitset so future calls to + * calculate_physical_address() will return the new address instead of the old one. * - * @param frame + * @param frame Physical frame that contains the address we want to copy into our underlying std::bitset. */ - auto set(physical_frame frame) -> void; + auto set_address(physical_frame frame) -> void; /** - * @brief TODO + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all + * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits + * that are set are not relevant. * - * @param b - * @return true - * @return false + * @param flags Flags that we want to compare against and check if the underlying std::bitset has the same bits set. + * @return Whether the given flags are a subset or equivalent with the underlying std::bitset */ auto contains_flags(std::bitset<64U> b) const -> bool; @@ -85,7 +100,7 @@ namespace teachos::arch::memory auto calculate_physical_address() const -> std::size_t; std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be freely - ///< used for additional flagsby the operating system. + ///< used for additional flags by the operating system. }; /** diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index c8981a8..12498d0 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -48,21 +48,27 @@ namespace teachos::arch::kernel for (auto section = begin; section != end; ++section) { - bool const writable = section->flags.writable(); - bool const occupies_memory = section->flags.occupies_memory(); - bool const is_executable = section->flags.is_executable(); - bool const contains_duplicate_data = section->flags.contains_duplicate_data(); - bool const contains_strings = section->flags.contains_strings(); - bool const section_header_info_is_section_header_table_index = - section->flags.section_header_info_is_section_header_table_index(); - bool const preserve_ordering_after_combination = section->flags.preserve_ordering_after_combination(); - bool const requires_special_os_processing = section->flags.requires_special_os_processing(); - bool const is_section_group_member = section->flags.is_section_group_member(); - bool const holds_thread_local_data = section->flags.holds_thread_local_data(); - bool const is_compressed = section->flags.is_compressed(); - bool const has_special_ordering_requirements = section->flags.has_special_ordering_requirements(); + bool const writable = section->flags.contains_flags(arch::memory::elf_section_flags::WRITABLE); + bool const occupies_memory = section->flags.contains_flags(arch::memory::elf_section_flags::OCCUPIES_MEMORY); + bool const is_executable = section->flags.contains_flags(arch::memory::elf_section_flags::EXECUTABLE_CODE); + bool const contains_duplicate_data = + section->flags.contains_flags(arch::memory::elf_section_flags::DUPLICATE_DATA); + bool const contains_strings = section->flags.contains_flags(arch::memory::elf_section_flags::CONTAINS_STRING); + bool const section_header_info_is_section_header_table_index = section->flags.contains_flags( + arch::memory::elf_section_flags::SECTION_HEADER_INFO_IS_SECTION_HEADER_TABLE_INDEX); + bool const preserve_ordering_after_combination = + section->flags.contains_flags(arch::memory::elf_section_flags::PRESERVE_ORDERING_AFTER_COMBINATION); + bool const requires_special_os_processing = + section->flags.contains_flags(arch::memory::elf_section_flags::REQUIRES_SPECIAL_OS_PROCESSING); + bool const is_section_group_member = + section->flags.contains_flags(arch::memory::elf_section_flags::SECTION_GROUP_MEMBER); + bool const holds_thread_local_data = + section->flags.contains_flags(arch::memory::elf_section_flags::HOLDS_THREAD_LOCAL_DATA); + bool const is_compressed = section->flags.contains_flags(arch::memory::elf_section_flags::COMPRESSED); + bool const has_special_ordering_requirements = + section->flags.contains_flags(arch::memory::elf_section_flags::SPECIAL_ORDERING_REQUIREMENTS); bool const is_excluded_unless_referenced_or_allocated = - section->flags.is_excluded_unless_referenced_or_allocated(); + section->flags.contains_flags(arch::memory::elf_section_flags::EXCLUDED_UNLESS_REFERENCED_OR_ALLOCATED); if (writable && occupies_memory && is_executable && contains_duplicate_data && contains_strings && section_header_info_is_section_header_table_index && preserve_ordering_after_combination && diff --git a/arch/x86_64/src/memory/multiboot.cpp b/arch/x86_64/src/memory/multiboot.cpp index bd3b00b..b0432a9 100644 --- a/arch/x86_64/src/memory/multiboot.cpp +++ b/arch/x86_64/src/memory/multiboot.cpp @@ -2,40 +2,12 @@ namespace teachos::arch::memory { - auto elf_section_flags::writable() const -> bool { return is_bit_set(0U); } - - auto elf_section_flags::occupies_memory() const -> bool { return is_bit_set(1U); } - - auto elf_section_flags::is_executable() const -> bool { return is_bit_set(2U); } - - auto elf_section_flags::contains_duplicate_data() const -> bool { return is_bit_set(4U); } - - auto elf_section_flags::contains_strings() const -> bool { return is_bit_set(5U); } - - auto elf_section_flags::section_header_info_is_section_header_table_index() const -> bool { return is_bit_set(6U); } - - auto elf_section_flags::preserve_ordering_after_combination() const -> bool { return is_bit_set(7U); } - - auto elf_section_flags::requires_special_os_processing() const -> bool { return is_bit_set(8U); } - - auto elf_section_flags::is_section_group_member() const -> bool { return is_bit_set(9U); } - - auto elf_section_flags::holds_thread_local_data() const -> bool { return is_bit_set(10U); } - - auto elf_section_flags::is_compressed() const -> bool { return is_bit_set(11U); } - - auto elf_section_flags::has_special_ordering_requirements() const -> bool { return is_bit_set(30U); } - - auto elf_section_flags::is_excluded_unless_referenced_or_allocated() const -> bool { return is_bit_set(31U); } - - auto elf_section_flags::operator==(elf_section_flags const & other) const -> bool { return flags == other.flags; } - - auto elf_section_flags::is_bit_set(uint8_t index) const -> bool { return flags[index] == 1U; } + auto elf_section_flags::contains_flags(std::bitset<64U> b) const -> bool { return (flags & b) == b; } auto elf_section_header::is_null() const -> bool { - return name_table_index == 0U && type == elf_section_type::INACTIVE && - flags == teachos::arch::memory::elf_section_flags{0U} && virtual_address == 0U && file_offset == 0U && - additional_information == 0U && address_alignment == 0U && fixed_table_entry_size == 0U; + return name_table_index == 0U && type == elf_section_type::INACTIVE && flags == elf_section_flags(0U) && + virtual_address == 0U && file_offset == 0U && additional_information == 0U && address_alignment == 0U && + fixed_table_entry_size == 0U; } } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/memory/paging.cpp b/arch/x86_64/src/memory/paging.cpp index 58a2b99..6fef339 100644 --- a/arch/x86_64/src/memory/paging.cpp +++ b/arch/x86_64/src/memory/paging.cpp @@ -31,15 +31,15 @@ namespace teachos::arch::memory return value; } - auto entry::set(physical_frame frame) -> void + auto entry::contains_flags(std::bitset<64U> b) const -> bool { return (flags & b) == b; } + + auto entry::set_address(physical_frame frame) -> void { arch::exception_handling::assert((frame.start_address() & ~0x000fffff'fffff000) == 0, "Start address is not aligned with Page"); flags = std::bitset<64U>(frame.start_address()) | flags; } - auto entry::contains_flags(std::bitset<64U> b) const -> bool { return (flags & b) == b; } - auto page_table::zero_entries() -> void { auto begin = &entries[0]; @@ -50,5 +50,4 @@ namespace teachos::arch::memory entry->set_unused(); } } - } // namespace teachos::arch::memory -- cgit v1.2.3 From 8524564b240d9859655603d1fb3717faf3cf558c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 15 Oct 2024 08:51:32 +0000 Subject: Fix problems with calculations inside enum (uses int32_t by default) --- arch/x86_64/include/arch/memory/multiboot.hpp | 39 ++++++++++++++------------- arch/x86_64/include/arch/memory/paging.hpp | 26 +++++++++--------- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index 6fc10df..c070e85 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -138,28 +138,29 @@ namespace teachos::arch::memory */ enum bitset : uint32_t { - WRITABLE = 1 << 0, ///< (SHF_WRITE) Section is writable at runtime. If it isn't then the section - ///< is assumed to be READONLY and only that flag is shown in the objdump. - OCCUPIES_MEMORY = 1 << 1, ///< (SHF_ALLOC) Section occupies memory during execution. - ///< ALLOC flag is shown in the objdump. - EXECUTABLE_CODE = 1 << 2, ///< (SHF_EXECINSTR) Section is executable. CODE flag is shown in the object dump. - DUPLICATE_DATA = 1 << 4, ///< (SHF_MERGE) Section might be merged with another section. - CONTAINS_STRING = 1 << 5, ///< (SHF_STRINGS) Section contains null-terminated strings. + WRITABLE = 1U << 0U, ///< (SHF_WRITE) Section is writable at runtime. If it isn't then the section + ///< is assumed to be READONLY and only that flag is shown in the objdump. + OCCUPIES_MEMORY = 1U << 1U, ///< (SHF_ALLOC) Section occupies memory during execution. + ///< ALLOC flag is shown in the objdump. + EXECUTABLE_CODE = 1U << 2U, ///< (SHF_EXECINSTR) Section is executable. CODE flag is shown in the object dump. + DUPLICATE_DATA = 1U << 4U, ///< (SHF_MERGE) Section might be merged with another section. + CONTAINS_STRING = 1U << 5U, ///< (SHF_STRINGS) Section contains null-terminated strings. SECTION_HEADER_INFO_IS_SECTION_HEADER_TABLE_INDEX = - 1 << 6, ///< (SHF_INFO_LINK) Section contains the section header table index in the (sh_info) - ///< additional_information variable. + 1U << 6U, ///< (SHF_INFO_LINK) Section contains the section header table index in the (sh_info) + ///< additional_information variable. PRESERVE_ORDERING_AFTER_COMBINATION = - 1 << 7, ///< (SHF_LINK_ORDER) Section preserves order after combining with another section. + 1U << 7U, ///< (SHF_LINK_ORDER) Section preserves order after combining with another section. REQUIRES_SPECIAL_OS_PROCESSING = - 1 << 8, ///< (SHF_OS_NONCONFORMING) Section requires non-standard OS specific handling of its code or - ///< data, which does not confirm to standard ELF specifications. - SECTION_GROUP_MEMBER = 1 << 9, ///< (SHF_GROUP) Section is a member of a section group. - HOLDS_THREAD_LOCAL_DATA = 1 << 10, ///< (SHF_TLS) Section holds thread-local data. - COMPRESSED = 1 << 11, ///< (SHF_COMPRESSED) Section contains compressed data. - SPECIAL_ORDERING_REQUIREMENTS = 1 << 30, ///< (SHF_ORDERED) Section has special ordering requirements, meaning it - ///< should be ordered in relation to other sections of the same type - EXCLUDED_UNLESS_REFERENCED_OR_ALLOCATED = 1 << 31, ///< (SHF_EXCLUDE)Section is excluded unless referenced or - ///< allocated, used for LTO (Link-Time Optimizations) + 1U << 8U, ///< (SHF_OS_NONCONFORMING) Section requires non-standard OS specific handling of its code or + ///< data, which does not confirm to standard ELF specifications. + SECTION_GROUP_MEMBER = 1U << 9U, ///< (SHF_GROUP) Section is a member of a section group. + HOLDS_THREAD_LOCAL_DATA = 1U << 10U, ///< (SHF_TLS) Section holds thread-local data. + COMPRESSED = 1U << 11U, ///< (SHF_COMPRESSED) Section contains compressed data. + SPECIAL_ORDERING_REQUIREMENTS = + 1U << 30U, ///< (SHF_ORDERED) Section has special ordering requirements, meaning it + ///< should be ordered in relation to other sections of the same type + EXCLUDED_UNLESS_REFERENCED_OR_ALLOCATED = 1U << 31U, ///< (SHF_EXCLUDE)Section is excluded unless referenced or + ///< allocated, used for LTO (Link-Time Optimizations) }; /** diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp index aa20da7..25246f6 100644 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -35,20 +35,20 @@ namespace teachos::arch::memory */ enum bitset : uint64_t { - PRESENT = 1 << 0, ///< Page is in memory and therefore present. - ///< is assumed to be READONLY and only that flag is shown in the objdump. - WRITABLE = 1 << 1, ///< It is possible to write to the page. - USER_ACCESIBLE = 1 << 2, ///< Page can be accessed in user mode instead of only in kernel mode code. - WRITE_THROUGH_CACHING = 1 << 3, ///< Write to the page go directly to memory instead of the cache. - DISABLED_CACHING = 1 << 4, ///< Page uses caching. - ACCESSED = 1 << 5, ///< Page is currently in use. - DIRTY = 1 << 6, ///< Page has been writen too. - HUGE_PAGE = 1 << 7, ///< Page is huge (2 MiB page size in P2 page table and 1 GiB in P3 page table, - ///< instead of 4 KiB). Has to be false for P1 and P4 page tables. - GLOBAL = 1 << 8, ///< Page is not flushed from caches on address space switches (PGE bit of CR4 register - ///< has to be set) + PRESENT = 1UL << 0UL, ///< Page is in memory and therefore present. + ///< is assumed to be READONLY and only that flag is shown in the objdump. + WRITABLE = 1UL << 1UL, ///< It is possible to write to the page. + USER_ACCESIBLE = 1UL << 2UL, ///< Page can be accessed in user mode instead of only in kernel mode code. + WRITE_THROUGH_CACHING = 1UL << 3UL, ///< Write to the page go directly to memory instead of the cache. + DISABLED_CACHING = 1UL << 4UL, ///< Page uses caching. + ACCESSED = 1UL << 5UL, ///< Page is currently in use. + DIRTY = 1UL << 6UL, ///< Page has been writen too. + HUGE_PAGE = 1UL << 7UL, ///< Page is huge (2 MiB page size in P2 page table and 1 GiB in P3 page table, + ///< instead of 4 KiB). Has to be false for P1 and P4 page tables. + GLOBAL = 1UL << 8UL, ///< Page is not flushed from caches on address space switches (PGE bit of CR4 register + ///< has to be set) EXECUTING_CODE_FORBIDDEN = - 1 << 63, ///< Page is forbidden from executing code (NXE bit in the EFER register has to be set) + 1UL << 63UL, ///< Page is forbidden from executing code (NXE bit in the EFER register has to be set) }; /** -- cgit v1.2.3 From 1d533cc10d926dde641af05537b540427c27bf64 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 15 Oct 2024 08:54:21 +0000 Subject: add assert import --- arch/x86_64/include/arch/memory/paging.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp index 25246f6..0b928b0 100644 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -1,6 +1,8 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_HPP +#include "arch/exception_handling/assert.hpp" + #include "frame_allocator.hpp" namespace teachos::arch::memory -- cgit v1.2.3 From 0fac2d5f7a868b5d65db6fb42ce256485e651206 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 15 Oct 2024 09:02:52 +0000 Subject: replace standalone value with enum --- arch/x86_64/src/memory/paging.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/src/memory/paging.cpp b/arch/x86_64/src/memory/paging.cpp index 6fef339..4603e74 100644 --- a/arch/x86_64/src/memory/paging.cpp +++ b/arch/x86_64/src/memory/paging.cpp @@ -10,7 +10,7 @@ namespace teachos::arch::memory auto entry::calculate_pointed_to_frame() const -> std::optional { - if (contains_flags(1)) + if (contains_flags(PRESENT)) { auto physical_address = calculate_physical_address(); return physical_frame::containing_address(physical_address); -- cgit v1.2.3 From 429d99ca40254e9e19da938ff9f2065a543708cd Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 15 Oct 2024 09:05:37 +0000 Subject: rename contains_flags parameter --- arch/x86_64/include/arch/memory/multiboot.hpp | 4 ++-- arch/x86_64/include/arch/memory/paging.hpp | 4 ++-- arch/x86_64/src/memory/multiboot.cpp | 2 +- arch/x86_64/src/memory/paging.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index c070e85..9a753fa 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -180,10 +180,10 @@ namespace teachos::arch::memory * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits * that are set are not relevant. * - * @param flags Flags that we want to compare against and check if the underlying std::bitset has the same bits set. + * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. * @return Whether the given flags are a subset or equivalent with the underlying std::bitset */ - auto contains_flags(std::bitset<64U> b) const -> bool; + auto contains_flags(std::bitset<64U> other) const -> bool; /** * @brief Allows to compare the underlying std::bitset of two instances diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp index 0b928b0..16fa476 100644 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -86,10 +86,10 @@ namespace teachos::arch::memory * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits * that are set are not relevant. * - * @param flags Flags that we want to compare against and check if the underlying std::bitset has the same bits set. + * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. * @return Whether the given flags are a subset or equivalent with the underlying std::bitset */ - auto contains_flags(std::bitset<64U> b) const -> bool; + auto contains_flags(std::bitset<64U> other) const -> bool; private: /** diff --git a/arch/x86_64/src/memory/multiboot.cpp b/arch/x86_64/src/memory/multiboot.cpp index b0432a9..8c6793e 100644 --- a/arch/x86_64/src/memory/multiboot.cpp +++ b/arch/x86_64/src/memory/multiboot.cpp @@ -2,7 +2,7 @@ namespace teachos::arch::memory { - auto elf_section_flags::contains_flags(std::bitset<64U> b) const -> bool { return (flags & b) == b; } + auto elf_section_flags::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } auto elf_section_header::is_null() const -> bool { diff --git a/arch/x86_64/src/memory/paging.cpp b/arch/x86_64/src/memory/paging.cpp index 4603e74..445c796 100644 --- a/arch/x86_64/src/memory/paging.cpp +++ b/arch/x86_64/src/memory/paging.cpp @@ -31,7 +31,7 @@ namespace teachos::arch::memory return value; } - auto entry::contains_flags(std::bitset<64U> b) const -> bool { return (flags & b) == b; } + auto entry::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } auto entry::set_address(physical_frame frame) -> void { -- cgit v1.2.3 From 0c4fd9eaed4a71975879aa83cd2da4b6266a64b5 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 15 Oct 2024 15:48:43 +0000 Subject: add 4th level page table --- arch/x86_64/include/arch/memory/paging.hpp | 26 +++++++++++++++++++++++--- arch/x86_64/src/boot/boot.s | 6 ++++++ arch/x86_64/src/memory/paging.cpp | 27 +++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp index 16fa476..7b705ac 100644 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -91,6 +91,9 @@ namespace teachos::arch::memory */ auto contains_flags(std::bitset<64U> other) const -> bool; + std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be freely + ///< used for additional flags by the operating system. + private: /** * @brief Extracts the physical address from the underlying bitset read from bit index 12 - 51. Is a 52 bit page @@ -100,9 +103,6 @@ namespace teachos::arch::memory * @return Extracted physical address of the next page or of the frame for P1 page tables. */ auto calculate_physical_address() const -> std::size_t; - - std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be freely - ///< used for additional flags by the operating system. }; /** @@ -115,6 +115,25 @@ namespace teachos::arch::memory */ auto zero_entries() -> void; + /** + * @brief Find and return the next table address + * + * The next table address is only valid if the corresponding entry is present + * and does not create a huge page + * + * @param index + * @return An optional of the address of the next page table or null + */ + auto next_table_address(std::size_t index) const -> std::optional; + + /** + * @brief Convert the address of a page_table into a page_table + * + * @param index + * @return An optional of the next page table or null + */ + auto next_table(size_t index) const -> std::optional; + /** * @brief Index operator overload to access specific entries directy * @@ -129,6 +148,7 @@ namespace teachos::arch::memory private: entry entries[PAGE_TABLE_ENTRY_COUNT]; + page_table const * p4 = reinterpret_cast(0xfffffffffffff000); }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 0c21c66..29ac58d 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -264,6 +264,12 @@ enable_paging: mov $page_map_level_4, %eax mov %eax, %cr3 + /* Map the P4 table recursively */ + mov $page_map_level_4, %eax + or 0b11, %eax + // TODO: WHY THIS THROW ERROR? + mov %eax, [$page_map_level_4 + 511 * 8] + /* Enable Physical Address Extension */ mov %cr4, %eax or $(1 << 5), %eax diff --git a/arch/x86_64/src/memory/paging.cpp b/arch/x86_64/src/memory/paging.cpp index 445c796..61d9d0f 100644 --- a/arch/x86_64/src/memory/paging.cpp +++ b/arch/x86_64/src/memory/paging.cpp @@ -50,4 +50,31 @@ namespace teachos::arch::memory entry->set_unused(); } } + + auto page_table::next_table_address(std::size_t index) const -> std::optional + { + auto entry = entries[index]; + + if (entry.contains_flags(entry.PRESENT) && !entry.contains_flags(entry.HUGE_PAGE)) + { + std::size_t table_address = reinterpret_cast(this); + return (table_address << 9) | (index << 12); + } + else + { + return std::nullopt; + } + } + + auto page_table::next_table(size_t index) const -> std::optional + { + auto address = next_table_address(index); + + if (address.has_value()) + { + return reinterpret_cast(*address); + } + + return std::nullopt; + } } // namespace teachos::arch::memory -- cgit v1.2.3 From f56004a77314d4b4d68bfaf496fd7c6013ba7a27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 16 Oct 2024 11:52:01 +0000 Subject: Adjust types --- arch/x86_64/include/arch/memory/paging.hpp | 10 +++++----- arch/x86_64/src/boot/boot.s | 2 +- arch/x86_64/src/memory/paging.cpp | 10 ++++------ 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp index 7b705ac..c13c3fe 100644 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -91,9 +91,6 @@ namespace teachos::arch::memory */ auto contains_flags(std::bitset<64U> other) const -> bool; - std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be freely - ///< used for additional flags by the operating system. - private: /** * @brief Extracts the physical address from the underlying bitset read from bit index 12 - 51. Is a 52 bit page @@ -103,6 +100,9 @@ namespace teachos::arch::memory * @return Extracted physical address of the next page or of the frame for P1 page tables. */ auto calculate_physical_address() const -> std::size_t; + + std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be freely + ///< used for additional flags by the operating system. }; /** @@ -132,7 +132,7 @@ namespace teachos::arch::memory * @param index * @return An optional of the next page table or null */ - auto next_table(size_t index) const -> std::optional; + auto next_table(std::size_t index) const -> std::optional; /** * @brief Index operator overload to access specific entries directy @@ -140,7 +140,7 @@ namespace teachos::arch::memory * @param index * @return The address of the accessed entry */ - entry & operator[](size_t index) + entry & operator[](std::size_t index) { arch::exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] index out of bounds"); return entries[index]; diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 29ac58d..e3d9c37 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -268,7 +268,7 @@ enable_paging: mov $page_map_level_4, %eax or 0b11, %eax // TODO: WHY THIS THROW ERROR? - mov %eax, [$page_map_level_4 + 511 * 8] + //mov %eax, [$page_map_level_4 + 511 * 8] /* Enable Physical Address Extension */ mov %cr4, %eax diff --git a/arch/x86_64/src/memory/paging.cpp b/arch/x86_64/src/memory/paging.cpp index 61d9d0f..2f78da8 100644 --- a/arch/x86_64/src/memory/paging.cpp +++ b/arch/x86_64/src/memory/paging.cpp @@ -60,19 +60,17 @@ namespace teachos::arch::memory std::size_t table_address = reinterpret_cast(this); return (table_address << 9) | (index << 12); } - else - { - return std::nullopt; - } + // TODO: Implement behaviour for huge pages currently not done + return std::nullopt; } - auto page_table::next_table(size_t index) const -> std::optional + auto page_table::next_table(std::size_t index) const -> std::optional { auto address = next_table_address(index); if (address.has_value()) { - return reinterpret_cast(*address); + return reinterpret_cast(*address); } return std::nullopt; -- cgit v1.2.3 From 934822e48a7c5a3e65ed74261ce5ab4315595f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 16 Oct 2024 13:33:23 +0000 Subject: Fix compilation issues with assigning values to page_map_variable address --- .../x86_64/include/arch/memory/frame_allocator.hpp | 27 ++++++++-------------- arch/x86_64/include/arch/memory/paging.hpp | 6 +---- arch/x86_64/src/boot/boot.s | 5 ++-- arch/x86_64/src/memory/frame_allocator.cpp | 19 ++++++++++++--- arch/x86_64/src/memory/paging.cpp | 13 +++++++---- 5 files changed, 36 insertions(+), 34 deletions(-) diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp index 3d1f826..89f2570 100644 --- a/arch/x86_64/include/arch/memory/frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/frame_allocator.hpp @@ -119,16 +119,7 @@ namespace teachos::arch::memory * @param area_count Amount of total entries in the memory_areas array. */ area_frame_allocator(std::size_t kernel_start, std::size_t kernel_end, std::size_t multiboot_start, - std::size_t multiboot_end, memory_area * memory_areas, uint8_t area_count) - : area_begin(memory_areas) - , area_end(memory_areas + area_count) - , kernel_start(physical_frame::containing_address(kernel_start)) - , kernel_end(physical_frame::containing_address(kernel_end)) - , multiboot_start(physical_frame::containing_address(multiboot_start)) - , multiboot_end(physical_frame::containing_address(multiboot_end)) - { - choose_next_area(); - } + std::size_t multiboot_end, memory_area * memory_areas, uint8_t area_count); /** * @brief Allocate memory by finding and returning a free physical_frame. @@ -171,14 +162,14 @@ namespace teachos::arch::memory */ auto choose_next_area() -> void; - physical_frame next_free_frame{0}; ///< The physical_frame after the last allocated one. - std::optional current_area{std::nullopt}; ///< The current memory area. - memory_area_iterator area_begin; ///< Pointer to the first element of all memory areas. - memory_area_iterator area_end; ///< Pointer to one pas the last element of all memory areas. - physical_frame const kernel_start; ///< The start address of the kernel code in memory. - physical_frame const kernel_end; ///< The end address of the kernel code in memory. - physical_frame const multiboot_start; ///< The start address of the multiboot code in memory. - physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. + physical_frame next_free_frame; ///< The physical_frame after the last allocated one. + std::optional current_area; ///< The current memory area. + memory_area_iterator area_begin; ///< Pointer to the first element of all memory areas. + memory_area_iterator area_end; ///< Pointer to one pas the last element of all memory areas. + physical_frame const kernel_start; ///< The start address of the kernel code in memory. + physical_frame const kernel_end; ///< The end address of the kernel code in memory. + physical_frame const multiboot_start; ///< The start address of the multiboot code in memory. + physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp index c13c3fe..4092d18 100644 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -140,11 +140,7 @@ namespace teachos::arch::memory * @param index * @return The address of the accessed entry */ - entry & operator[](std::size_t index) - { - arch::exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] index out of bounds"); - return entries[index]; - } + entry & operator[](std::size_t index); private: entry entries[PAGE_TABLE_ENTRY_COUNT]; diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index e3d9c37..2aa30c6 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -266,9 +266,8 @@ enable_paging: /* Map the P4 table recursively */ mov $page_map_level_4, %eax - or 0b11, %eax - // TODO: WHY THIS THROW ERROR? - //mov %eax, [$page_map_level_4 + 511 * 8] + or 0b11, %eax /* Write present + writable flags into eax register */ + mov %eax, (page_map_level_4 + 511 * 8) /* Enable Physical Address Extension */ mov %cr4, %eax diff --git a/arch/x86_64/src/memory/frame_allocator.cpp b/arch/x86_64/src/memory/frame_allocator.cpp index 01dcc88..70276ae 100644 --- a/arch/x86_64/src/memory/frame_allocator.cpp +++ b/arch/x86_64/src/memory/frame_allocator.cpp @@ -4,8 +4,6 @@ namespace teachos::arch::memory { - uint64_t PAGE_SIZE; - physical_frame::physical_frame(std::size_t frame_number) : frame_number(frame_number) { @@ -17,7 +15,7 @@ namespace teachos::arch::memory return physical_frame{address / PAGE_FRAME_SIZE}; } - auto physical_frame::start_address() const -> uint64_t { return frame_number * PAGE_SIZE; } + auto physical_frame::start_address() const -> uint64_t { return frame_number * PAGE_FRAME_SIZE; } memory_area_iterator::memory_area_iterator(memory_area * p) : ptr(p) @@ -39,6 +37,21 @@ namespace teachos::arch::memory return *this; } + area_frame_allocator::area_frame_allocator(std::size_t kernel_start, std::size_t kernel_end, + std::size_t multiboot_start, std::size_t multiboot_end, + memory_area * memory_areas, uint8_t area_count) + : next_free_frame(0) + , current_area(std::nullopt) + , area_begin(memory_areas) + , area_end(memory_areas + area_count) + , kernel_start(physical_frame::containing_address(kernel_start)) + , kernel_end(physical_frame::containing_address(kernel_end)) + , multiboot_start(physical_frame::containing_address(multiboot_start)) + , multiboot_end(physical_frame::containing_address(multiboot_end)) + { + choose_next_area(); + } + auto area_frame_allocator::choose_next_area() -> void { current_area = std::nullopt; diff --git a/arch/x86_64/src/memory/paging.cpp b/arch/x86_64/src/memory/paging.cpp index 2f78da8..a07b2c0 100644 --- a/arch/x86_64/src/memory/paging.cpp +++ b/arch/x86_64/src/memory/paging.cpp @@ -42,12 +42,9 @@ namespace teachos::arch::memory auto page_table::zero_entries() -> void { - auto begin = &entries[0]; - auto end = &entries[PAGE_TABLE_ENTRY_COUNT]; - - for (auto entry = begin; entry < end; ++entry) + for (size_t i = 0; i < sizeof(entries) / sizeof(entries[0]); ++i) { - entry->set_unused(); + entries[i].set_unused(); } } @@ -75,4 +72,10 @@ namespace teachos::arch::memory return std::nullopt; } + + entry & page_table::operator[](std::size_t index) + { + arch::exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] index out of bounds"); + return entries[index]; + } } // namespace teachos::arch::memory -- cgit v1.2.3 From 35e25757b6cffbcb2ff1eea8daf4c5f1ca421cb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 16 Oct 2024 14:10:32 +0000 Subject: Adjust table accessing code to make it safer (always out of bounds checked) --- arch/x86_64/include/arch/memory/multiboot.hpp | 4 ++- arch/x86_64/include/arch/memory/paging.hpp | 43 +++++++++++++++--------- arch/x86_64/src/memory/paging.cpp | 47 +++++++++++++++++++-------- 3 files changed, 64 insertions(+), 30 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index 9a753fa..9cca8bc 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -194,7 +194,9 @@ namespace teachos::arch::memory auto operator==(elf_section_flags const & other) const -> bool = default; private: - std::bitset<64U> flags; + std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 21 - 28 are reserved for operating + ///< system specific semantics and bits 29 - 32 are reserved for processor specific + ///< semantics. Bits 33 - 64 are unused for compatability with ELF32. }; /** diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp index 4092d18..d55835e 100644 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -110,41 +110,54 @@ namespace teachos::arch::memory */ struct page_table { + /** + * @brief Constructor. + */ + page_table(); + /** * @brief Set every entry of the page to unused */ auto zero_entries() -> void; /** - * @brief Find and return the next table address + * @brief Convert the address of a page_table into a page_table * - * The next table address is only valid if the corresponding entry is present - * and does not create a huge page + * @param index Index of the entry we want to access + * @return An optional of the next page table or null + */ + auto next_table(std::size_t index) const -> std::optional; + + /** + * @brief Index operator overload to access specific mutable entry directy * - * @param index - * @return An optional of the address of the next page table or null + * @param index Index of the entry we want to access and change + * @return Entry at the given table index */ - auto next_table_address(std::size_t index) const -> std::optional; + auto operator[](std::size_t index) -> entry &; /** - * @brief Convert the address of a page_table into a page_table + * @brief Index operator overload to access specific immutable entry directy * - * @param index - * @return An optional of the next page table or null + * @param index Index of the entry we want to access and only read + * @return Entry at the given table index */ - auto next_table(std::size_t index) const -> std::optional; + auto operator[](std::size_t index) const -> entry const &; + private: /** - * @brief Index operator overload to access specific entries directy + * @brief Find and return the next table address + * + * The next table address is only valid if the corresponding entry is present + * and does not create a huge page * * @param index - * @return The address of the accessed entry + * @return An optional of the address of the next page table or null */ - entry & operator[](std::size_t index); + auto next_table_address(std::size_t index) const -> std::optional; - private: entry entries[PAGE_TABLE_ENTRY_COUNT]; - page_table const * p4 = reinterpret_cast(0xfffffffffffff000); + page_table const * p4; }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/memory/paging.cpp b/arch/x86_64/src/memory/paging.cpp index a07b2c0..a8f2c40 100644 --- a/arch/x86_64/src/memory/paging.cpp +++ b/arch/x86_64/src/memory/paging.cpp @@ -40,25 +40,21 @@ namespace teachos::arch::memory flags = std::bitset<64U>(frame.start_address()) | flags; } - auto page_table::zero_entries() -> void + page_table::page_table() + : entries() + , p4(reinterpret_cast(0xfffffffffffff000)) { - for (size_t i = 0; i < sizeof(entries) / sizeof(entries[0]); ++i) - { - entries[i].set_unused(); - } + // Nothing to do } - auto page_table::next_table_address(std::size_t index) const -> std::optional + auto page_table::zero_entries() -> void { - auto entry = entries[index]; - - if (entry.contains_flags(entry.PRESENT) && !entry.contains_flags(entry.HUGE_PAGE)) + constexpr size_t entry_amount = sizeof(entries) / sizeof(entries[0]); + for (size_t i = 0; i < entry_amount; ++i) { - std::size_t table_address = reinterpret_cast(this); - return (table_address << 9) | (index << 12); + auto entry = this->operator[](i); + entry.set_unused(); } - // TODO: Implement behaviour for huge pages currently not done - return std::nullopt; } auto page_table::next_table(std::size_t index) const -> std::optional @@ -73,9 +69,32 @@ namespace teachos::arch::memory return std::nullopt; } - entry & page_table::operator[](std::size_t index) + auto page_table::operator[](std::size_t index) -> entry & + { + // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which + // could be incredibly hard to debug later. + arch::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 & { + // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which + // could be incredibly hard to debug later. arch::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 index) const -> std::optional + { + auto entry = this->operator[](index); + + if (entry.contains_flags(entry::PRESENT) && !entry.contains_flags(entry::HUGE_PAGE)) + { + std::size_t const table_address = reinterpret_cast(this); + return (table_address << 9) | (index << 12); + } + // TODO: Implement behaviour for huge pages currently not done + return std::nullopt; + } } // namespace teachos::arch::memory -- cgit v1.2.3 From d539ed1f4f26a42959bcae6ea3050b7f99f5f872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 16 Oct 2024 14:30:04 +0000 Subject: Attempt to implement page table checks using templates --- arch/x86_64/include/arch/memory/paging.hpp | 83 ++++++++++++++++++++++++------ arch/x86_64/src/memory/paging.cpp | 58 --------------------- 2 files changed, 67 insertions(+), 74 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp index d55835e..4bbb0e0 100644 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -105,28 +105,63 @@ namespace teachos::arch::memory ///< used for additional flags by the operating system. }; + enum level : uint8_t; + /** - * @brief A Page table containing 512 entries + * @brief A Page table containing 512 entries. */ + template struct page_table { + enum level : uint8_t + { + LEVEL1, + LEVEL2, + LEVEL3, + LEVEL4 + }; + /** * @brief Constructor. */ - page_table(); + page_table() + : entries() + , p4(reinterpret_cast(0xfffffffffffff000)) + { + // Nothing to do + } /** * @brief Set every entry of the page to unused */ - auto zero_entries() -> void; + auto zero_entries() -> void + { + constexpr size_t entry_amount = sizeof(entries) / sizeof(entries[0]); + for (size_t i = 0; i < entry_amount; ++i) + { + auto entry = entry.set_unused(); + } + } /** - * @brief Convert the address of a page_table into a page_table + * @brief Gets the complete next page table level from the given page table index. Meaning we use an index into a + * Level 4 page table to get the according Level 3 page table. * - * @param index Index of the entry we want to access - * @return An optional of the next page table or null + * @param table_index Index of this page table in the page table one level higher. + * @return Entire page table of the next level. */ - auto next_table(std::size_t index) const -> std::optional; + auto next_table(std::size_t table_index) const -> std::optional + requires(page_table_level > 0) + { + auto address = next_table_address(table_index); + + if (address.has_value()) + { + return reinterpret_cast(*address); + } + + return std::nullopt; + } /** * @brief Index operator overload to access specific mutable entry directy @@ -134,7 +169,13 @@ namespace teachos::arch::memory * @param index Index of the entry we want to access and change * @return Entry at the given table index */ - auto operator[](std::size_t index) -> entry &; + auto operator[](std::size_t index) -> entry & + { + // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which + // could be incredibly hard to debug later. + arch::exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] index out of bounds"); + return entries[index]; + } /** * @brief Index operator overload to access specific immutable entry directy @@ -142,22 +183,32 @@ namespace teachos::arch::memory * @param index Index of the entry we want to access and only read * @return Entry at the given table index */ - auto operator[](std::size_t index) const -> entry const &; + auto operator[](std::size_t index) const -> entry const & { return this->operator[](index); } private: /** - * @brief Find and return the next table address + * @brief Calculates the address of the next page table level for the given table index. 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. * - * The next table address is only valid if the corresponding entry is present - * and does not create a huge page - * - * @param index + * @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 index) const -> std::optional; + auto next_table_address(std::size_t table_index) const -> std::optional + { + auto entry = this->operator[](table_index); + + if (entry.contains_flags(entry::PRESENT) && !entry.contains_flags(entry::HUGE_PAGE)) + { + std::size_t const table_address = reinterpret_cast(this); + return (table_address << 9) | (table_index << 12); + } + // TODO: Implement behaviour for huge pages currently not done + return std::nullopt; + } entry entries[PAGE_TABLE_ENTRY_COUNT]; - page_table const * p4; + page_table const * p4; }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/memory/paging.cpp b/arch/x86_64/src/memory/paging.cpp index a8f2c40..9774132 100644 --- a/arch/x86_64/src/memory/paging.cpp +++ b/arch/x86_64/src/memory/paging.cpp @@ -39,62 +39,4 @@ namespace teachos::arch::memory "Start address is not aligned with Page"); flags = std::bitset<64U>(frame.start_address()) | flags; } - - page_table::page_table() - : entries() - , p4(reinterpret_cast(0xfffffffffffff000)) - { - // Nothing to do - } - - auto page_table::zero_entries() -> void - { - constexpr size_t entry_amount = sizeof(entries) / sizeof(entries[0]); - for (size_t i = 0; i < entry_amount; ++i) - { - auto entry = this->operator[](i); - entry.set_unused(); - } - } - - auto page_table::next_table(std::size_t index) const -> std::optional - { - auto address = next_table_address(index); - - if (address.has_value()) - { - return reinterpret_cast(*address); - } - - return std::nullopt; - } - - auto page_table::operator[](std::size_t index) -> entry & - { - // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which - // could be incredibly hard to debug later. - arch::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 & - { - // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which - // could be incredibly hard to debug later. - arch::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 index) const -> std::optional - { - auto entry = this->operator[](index); - - if (entry.contains_flags(entry::PRESENT) && !entry.contains_flags(entry::HUGE_PAGE)) - { - std::size_t const table_address = reinterpret_cast(this); - return (table_address << 9) | (index << 12); - } - // TODO: Implement behaviour for huge pages currently not done - return std::nullopt; - } } // namespace teachos::arch::memory -- cgit v1.2.3 From b865b36b38d951de28cc4df5fa67338b8245a1c3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 17 Oct 2024 13:12:29 +0200 Subject: Implement support for `std::terminate` via `::abort` --- arch/x86_64/CMakeLists.txt | 2 ++ .../include/arch/exception_handling/assert.hpp | 7 ++++++- .../include/arch/exception_handling/panic.hpp | 13 ++++++++++++ arch/x86_64/include/arch/kernel/halt.hpp | 9 +++++++++ arch/x86_64/include/arch/video/vga/text.hpp | 5 +++++ arch/x86_64/src/boot/boot.s | 13 +++++++++--- arch/x86_64/src/exception_handling/abort.cpp | 17 ++++++++++++++++ arch/x86_64/src/exception_handling/assert.cpp | 16 ++++----------- arch/x86_64/src/exception_handling/panic.cpp | 23 ++++++++++++++++++++++ arch/x86_64/src/kernel/main.cpp | 3 +-- arch/x86_64/src/video/vga/text.cpp | 22 +++++++++++++++++++++ src/kernel/main.cpp | 8 +++++++- 12 files changed, 119 insertions(+), 19 deletions(-) create mode 100644 arch/x86_64/include/arch/exception_handling/panic.hpp create mode 100644 arch/x86_64/include/arch/kernel/halt.hpp create mode 100644 arch/x86_64/src/exception_handling/abort.cpp create mode 100644 arch/x86_64/src/exception_handling/panic.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 603393c..3f67d71 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -51,7 +51,9 @@ target_sources("_memory" PRIVATE #]============================================================================] target_sources("_exception" PRIVATE + "src/exception_handling/abort.cpp" "src/exception_handling/assert.cpp" + "src/exception_handling/panic.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/exception_handling/assert.hpp b/arch/x86_64/include/arch/exception_handling/assert.hpp index eba43ac..f355a61 100644 --- a/arch/x86_64/include/arch/exception_handling/assert.hpp +++ b/arch/x86_64/include/arch/exception_handling/assert.hpp @@ -1,3 +1,6 @@ +#ifndef TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP +#define TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP + namespace teachos::arch::exception_handling { /** @@ -8,4 +11,6 @@ namespace teachos::arch::exception_handling * @param message */ auto assert(bool condition, char const * message) -> void; -} // namespace teachos::arch::exception_handling \ No newline at end of file +} // namespace teachos::arch::exception_handling + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/exception_handling/panic.hpp b/arch/x86_64/include/arch/exception_handling/panic.hpp new file mode 100644 index 0000000..9566159 --- /dev/null +++ b/arch/x86_64/include/arch/exception_handling/panic.hpp @@ -0,0 +1,13 @@ +#ifndef TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_PANIC_HPP +#define TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_PANIC_HPP + +namespace teachos::arch::exception_handling +{ + /** + * @brief Print a kernel panic message and then halt the system. + */ + [[noreturn]] auto panic(char const * reason) -> void; + [[noreturn]] auto panic(char const * prefix, char const * reason) -> void; +} // namespace teachos::arch::exception_handling + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/kernel/halt.hpp b/arch/x86_64/include/arch/kernel/halt.hpp new file mode 100644 index 0000000..6c58938 --- /dev/null +++ b/arch/x86_64/include/arch/kernel/halt.hpp @@ -0,0 +1,9 @@ +#ifndef TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP +#define TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP + +namespace teachos::arch::kernel +{ + extern "C" [[noreturn]] auto halt() -> void; +} + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/video/vga/text.hpp b/arch/x86_64/include/arch/video/vga/text.hpp index cfafce0..690f4aa 100644 --- a/arch/x86_64/include/arch/video/vga/text.hpp +++ b/arch/x86_64/include/arch/video/vga/text.hpp @@ -99,6 +99,11 @@ namespace teachos::arch::video::vga::text */ auto cursor(bool enabled) -> void; + /** + * @brief Move the cursor to a new line, scrolling the buffer if necessary. + */ + auto newline() -> void; + /** * @brief Write a string of code points to the VGA text buffer. * diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 2aa30c6..710d4ce 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -82,6 +82,7 @@ global_descriptor_table_pointer: * 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: @@ -109,6 +110,12 @@ vga_buffer_pointer: .long 0xb8000 .align 16 .code32 +.global halt +halt: +1: + hlt + jmp 1b + /** * Print a given panic message and then halt the machine. * @@ -129,7 +136,7 @@ _panic: call _print add $8, %esp - hlt + call halt /** * Print a message via the VGA buffer. @@ -189,7 +196,7 @@ _start: lgdt (global_descriptor_table_pointer) jmp $global_descriptor_table_code,$_transition_to_long_mode - hlt + call halt /** * Assert that the CPU supports going into long mode. @@ -354,4 +361,4 @@ _transition_to_long_mode: call _init call kernel_main - hlt + call halt diff --git a/arch/x86_64/src/exception_handling/abort.cpp b/arch/x86_64/src/exception_handling/abort.cpp new file mode 100644 index 0000000..dc40008 --- /dev/null +++ b/arch/x86_64/src/exception_handling/abort.cpp @@ -0,0 +1,17 @@ +#include "arch/exception_handling/panic.hpp" + +#include + +namespace teachos::arch::exception_handling +{ + + /** + * @brief Override for the newlib abort function. + * + * 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 \ No newline at end of file diff --git a/arch/x86_64/src/exception_handling/assert.cpp b/arch/x86_64/src/exception_handling/assert.cpp index b55da49..86696f8 100644 --- a/arch/x86_64/src/exception_handling/assert.cpp +++ b/arch/x86_64/src/exception_handling/assert.cpp @@ -1,4 +1,6 @@ -#include "arch/video/vga/text.hpp" +#include "arch/exception_handling/assert.hpp" + +#include "arch/exception_handling/panic.hpp" namespace teachos::arch::exception_handling { @@ -9,16 +11,6 @@ namespace teachos::arch::exception_handling return; } - video::vga::text::write("Assert failed: ", video::vga::text::common_attributes::green_on_black); - video::vga::text::write(message, video::vga::text::common_attributes::green_on_black); - for (;;) - { - // Trick the compiler into thinking the variable is changes at run time, - // to prevent the while loop being optimized away - // See - // https://stackoverflow.com/questions/9495856/how-to-prevent-g-from-optimizing-out-a-loop-controlled-by-a-variable-that-can - // for more information. - asm volatile("" : "+g"(condition)); - } + panic("Assertion Violation: ", message); } } // namespace teachos::arch::exception_handling \ No newline at end of file diff --git a/arch/x86_64/src/exception_handling/panic.cpp b/arch/x86_64/src/exception_handling/panic.cpp new file mode 100644 index 0000000..56edfd5 --- /dev/null +++ b/arch/x86_64/src/exception_handling/panic.cpp @@ -0,0 +1,23 @@ +#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 \ No newline at end of file diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 12498d0..babe251 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -165,7 +165,6 @@ namespace teachos::arch::kernel auto allocator = arch::memory::area_frame_allocator(kernel_start, kernel_end, multiboot_start, multiboot_end, memory_areas, area_count); - // WATCH OUT: using optional::value() crashes the build... I think its because of missing exception handling auto last_allocated = allocator.allocate_frame(); auto allocated = last_allocated; do @@ -174,6 +173,6 @@ namespace teachos::arch::kernel allocated = allocator.allocate_frame(); } while (allocated.has_value()); video::vga::text::write("Allocated Frames", video::vga::text::common_attributes::green_on_black); - video::vga::text::write_number(allocated->frame_number, video::vga::text::common_attributes::green_on_black); + video::vga::text::write_number(allocated.value().frame_number, video::vga::text::common_attributes::green_on_black); } } // namespace teachos::arch::kernel diff --git a/arch/x86_64/src/video/vga/text.cpp b/arch/x86_64/src/video/vga/text.cpp index a613c3b..c14de16 100644 --- a/arch/x86_64/src/video/vga/text.cpp +++ b/arch/x86_64/src/video/vga/text.cpp @@ -13,6 +13,8 @@ namespace teachos::arch::video::vga::text namespace { auto constexpr default_text_buffer_address = 0xb8000; + auto constexpr default_text_buffer_width = 80; + auto constexpr default_text_buffer_height = 25; extern "C" std::pair * vga_buffer_pointer; auto constinit text_buffer = teachos::memory::asm_pointer{vga_buffer_pointer}; @@ -32,6 +34,26 @@ namespace teachos::arch::video::vga::text crtc::data_port::write(vga::crtc::data_port::read() | cursor_disable_byte); } + auto newline() -> void + { + auto base = reinterpret_cast(default_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; diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 4799b29..36c6d92 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -1,3 +1,9 @@ #include "arch/kernel/main.hpp" -extern "C" auto kernel_main() -> void { teachos::arch::kernel::main(); } +#include "arch/exception_handling/panic.hpp" + +extern "C" auto kernel_main() -> void +{ + teachos::arch::kernel::main(); + teachos::arch::exception_handling::panic("Architecture specific main returned!"); +} -- cgit v1.2.3 From b6ce3a41fb53eabc6fde12c13f598d228435642a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 19 Oct 2024 11:25:08 +0000 Subject: Adjust memory_area structure to grub2 code --- arch/x86_64/include/arch/memory/multiboot.hpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp index 9cca8bc..8ecb1b5 100644 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ b/arch/x86_64/include/arch/memory/multiboot.hpp @@ -81,14 +81,24 @@ namespace teachos::arch::memory }; /** - * @brief Defines an entry in the entries array of the memory_map struct. + * @brief Defines an entry in the entries array of the memory_map struct. Has to have all padding stripped between the + * individual values, because the size of the entry needs to be exactly 24 bytes and not one byte more. See + * https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Packed-Structures.html for more information on the + * used attribute. */ - struct memory_area + struct __attribute__((packed)) memory_area { + uint32_t size; ///< TODO: Not clear what exactly the size signifies uint64_t base_address; ///< Base address the memory region starts at uint64_t area_length; ///< Size of the memory region, added to base_address results in the final address - alignas(8) memory_area_type type; ///< Specific type of memory the region can contain + memory_area_type type; ///< Specific type of memory the region can contain }; + /*struct memory_area + { + uint64_t base_address; ///< Base address the memory region starts at + uint64_t area_length; ///< Size of the memory region, added to base_address results in the final address + memory_area_type type; ///< Specific type of memory the region can contain + };*/ /** * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type -- cgit v1.2.3 From a2fdcea0d7615f8933401e45e0c64a2f618bb730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 19 Oct 2024 13:15:45 +0000 Subject: Move compelte multiboot2 code into seperate files and behaviour into seperate static class --- arch/x86_64/CMakeLists.txt | 4 +- .../x86_64/include/arch/memory/frame_allocator.hpp | 84 ++----- arch/x86_64/include/arch/memory/multiboot.hpp | 262 --------------------- .../arch/memory/multiboot/elf_sybols_section.hpp | 157 ++++++++++++ arch/x86_64/include/arch/memory/multiboot/info.hpp | 62 +++++ .../include/arch/memory/multiboot/memory_map.hpp | 93 ++++++++ .../include/arch/memory/multiboot/reader.hpp | 50 ++++ arch/x86_64/include/arch/memory/paging.hpp | 5 + arch/x86_64/src/kernel/main.cpp | 151 +----------- arch/x86_64/src/memory/frame_allocator.cpp | 44 +--- arch/x86_64/src/memory/multiboot.cpp | 13 - .../src/memory/multiboot/elf_symbols_section.cpp | 13 + arch/x86_64/src/memory/multiboot/memory_map.cpp | 24 ++ arch/x86_64/src/memory/multiboot/reader.cpp | 117 +++++++++ 14 files changed, 555 insertions(+), 524 deletions(-) delete mode 100644 arch/x86_64/include/arch/memory/multiboot.hpp create mode 100644 arch/x86_64/include/arch/memory/multiboot/elf_sybols_section.hpp create mode 100644 arch/x86_64/include/arch/memory/multiboot/info.hpp create mode 100644 arch/x86_64/include/arch/memory/multiboot/memory_map.hpp create mode 100644 arch/x86_64/include/arch/memory/multiboot/reader.hpp delete mode 100644 arch/x86_64/src/memory/multiboot.cpp create mode 100644 arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp create mode 100644 arch/x86_64/src/memory/multiboot/memory_map.cpp create mode 100644 arch/x86_64/src/memory/multiboot/reader.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 3f67d71..7ddf303 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -41,7 +41,9 @@ target_sources("_video" PRIVATE #]============================================================================] target_sources("_memory" PRIVATE - "src/memory/multiboot.cpp" + "src/memory/multiboot/elf_symbols_section.cpp" + "src/memory/multiboot/memory_map.cpp" + "src/memory/multiboot/reader.cpp" "src/memory/frame_allocator.cpp" "src/memory/paging.cpp" ) diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp index 89f2570..f1096d1 100644 --- a/arch/x86_64/include/arch/memory/frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/frame_allocator.hpp @@ -1,7 +1,8 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP #define TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP -#include "multiboot.hpp" +#include "multiboot/reader.hpp" + #include #include #include @@ -17,7 +18,7 @@ namespace teachos::arch::memory struct physical_frame { /** - * @brief Constructor + * @brief Constructor. * * @param frame_number Index number that should be assigned to this physical_frame. */ @@ -32,9 +33,9 @@ namespace teachos::arch::memory static auto containing_address(std::size_t address) -> physical_frame; /** - * @brief Evaluates the start address of the physical frame + * @brief Evaluates the start address of the physical frame. * - * @return start address of the physical frame + * @return start address of the physical frame. */ auto start_address() const -> uint64_t; @@ -58,51 +59,6 @@ namespace teachos::arch::memory { t.deallocate_frame() } -> std::same_as; }; - /** - * @brief Iterator for memory areas. - */ - struct memory_area_iterator - { - /** - * @brief Constructor. - * - * @param p Underlying address the iterator should point too, ensure to not pass an invalid pointer. - */ - explicit memory_area_iterator(memory_area * p); - - /** - * @brief Dereferences the initally given pointer to its value. - * - * @return Reference to the value. - */ - memory_area & operator*() const; - - /** - * @brief Post increment operator. Returns a copy of the value - * - * @return Copy of the incremented underlying address. - */ - memory_area_iterator operator++(int); - - /** - * @brief Pre increment operator. Returns a reference to the changed value. - * - * @return Reference to the incremented underlying address. - */ - memory_area_iterator & operator++(); - - /** - * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. - * - * @param other Other iterator to compare to. - * @return Whether poith iterators point to the same underlying address in memory. - */ - bool operator==(memory_area_iterator const & other) const = default; - - private: - memory_area * ptr; ///< Underlying address the iterator is currently pointing too. - }; - /** * @brief Allocates memory using memory areas read from the multiboot2 information pointer. */ @@ -111,15 +67,9 @@ namespace teachos::arch::memory /** * @brief Constructor * - * @param kernel_start Start address of the kernel code in memory. - * @param kernel_end End address of the kernel code in memory. - * @param multiboot_start Start address of the multiboot code in memory. - * @param multiboot_end End address of the multiboot code in memory. - * @param memory_areas Pointer to the first element of all memory areas. - * @param area_count Amount of total entries in the memory_areas array. + * @param mem_info Structure containg all relevant information to map and allocate memory */ - area_frame_allocator(std::size_t kernel_start, std::size_t kernel_end, std::size_t multiboot_start, - std::size_t multiboot_end, memory_area * memory_areas, uint8_t area_count); + area_frame_allocator(multiboot::memory_information mem_info); /** * @brief Allocate memory by finding and returning a free physical_frame. @@ -146,7 +96,7 @@ namespace teachos::arch::memory * * @return Iterator pointing to first element of the memory area. */ - auto begin() -> memory_area_iterator; + auto begin() -> multiboot::memory_area_iterator; /** * @brief Returns the iterator pointing to one past the last element of the memory area. @@ -154,7 +104,7 @@ namespace teachos::arch::memory * * @return Iterator pointing to one past the last element of the memory area. */ - auto end() -> memory_area_iterator; + auto end() -> multiboot::memory_area_iterator; private: /** @@ -162,14 +112,14 @@ namespace teachos::arch::memory */ auto choose_next_area() -> void; - physical_frame next_free_frame; ///< The physical_frame after the last allocated one. - std::optional current_area; ///< The current memory area. - memory_area_iterator area_begin; ///< Pointer to the first element of all memory areas. - memory_area_iterator area_end; ///< Pointer to one pas the last element of all memory areas. - physical_frame const kernel_start; ///< The start address of the kernel code in memory. - physical_frame const kernel_end; ///< The end address of the kernel code in memory. - physical_frame const multiboot_start; ///< The start address of the multiboot code in memory. - physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. + physical_frame next_free_frame; ///< The physical_frame after the last allocated one. + std::optional current_area; ///< The current memory area. + multiboot::memory_area_iterator area_begin; ///< Pointer to the first element of all memory areas. + multiboot::memory_area_iterator area_end; ///< Pointer to one pas the last element of all memory areas. + physical_frame const kernel_start; ///< The start address of the kernel code in memory. + physical_frame const kernel_end; ///< The end address of the kernel code in memory. + physical_frame const multiboot_start; ///< The start address of the multiboot code in memory. + physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. }; } // namespace teachos::arch::memory diff --git a/arch/x86_64/include/arch/memory/multiboot.hpp b/arch/x86_64/include/arch/memory/multiboot.hpp deleted file mode 100644 index 8ecb1b5..0000000 --- a/arch/x86_64/include/arch/memory/multiboot.hpp +++ /dev/null @@ -1,262 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_HPP - -#include -#include - -namespace teachos::arch::memory -{ - /** - * @brief Defines all possible types a multiboot2 tag structure can have. - * See - * https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html#Boot-information-format for more information. - */ - enum class multi_boot_tag_type : uint32_t - { - END, ///< Signals final tag for the multiboot2 information structure - CMDLINE, ///< Contains the command line string - BOOT_LOADER_NAME, ///< Contains the name of the boot loader booting the kernel - MODULE, ///< Indicates the boot module which was loaded along the kernel image - BASIC_MEMORY_INFO, ///< Contains the amount of lower (0MB start address) and upper memory (1MB start address) - BOOTDEV, ///< Indicates which BIOS disk device the hoot loader has loaded the OS image from - MEMORY_MAP, ///< Describes the memory layout of the system with individual areas and their flags - VBE_INFO, ///< Includes information to access and utilize the device GPU - FRAMEBUFFER, ///< VBE framebuffer information - ELF_SECTIONS, ///< Includes list of all section headers from the loaded ELF kernel - APM_INFO, ///< Advanced Power Management information - EFI32, ///< EFI 32 bit system table pointer - EFI64, ///< EFI 64 bit system table pointer - SMBIOS, ///< Contains copy of all Sytem Management BIOS tables - ACPI_OLD, ///< Contains copy of RSDP as defined per ACPI1.0 specification - ACPI_NEW, ///< Contains copy of RSDP as defined per ACPI2.0 or later specification - NETWORK, ///< Contains network information specified specified as DHCP - EFI_MEMORY_MAP, ///< Contains EFI memory map - EFI_BS_NOT_TERMINATED, ///< Indicated ExitBootServies wasn't called - EFI32_IMAGE_HANDLE, ///< EFI 32 bit image handle pointer - EFI64_IMAGE_HANDLE, ///< EFI 64 bit imae handle pointer - LOAD_BASE_ADDRESS ///< Contains image load base physical address - }; - - /** - * @brief Basic structure that every entry in the multi_boot_tag array of the multi_boot_info struct has to begin - * with. - */ - struct multi_boot_tag - { - multi_boot_tag_type type; ///< Specific type of this multi_boot_tag entry, used to differentiate handling - uint32_t size; ///< Total size of this multi_boot_tag entry with all fields of the actual type - }; - - /** - * @brief Basic structure the multiboot_information_pointer points too and which contains all information of - * multiboot2 in the tags array of different types. The start as well as the content has to be 8 byte aligned. - */ - struct multi_boot_info - { - uint32_t total_size; ///< Total size of all multi_boot_tags and their data - alignas(8) struct multi_boot_tag tags; ///< Specific tags - }; - - /** - * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type - * multi_boot_tag_type::BASIC_MEMORY_INFO. - */ - struct memory_info - { - multi_boot_tag tag; ///< Basic multi_boot_tag information - uint32_t mem_lower; ///< Amount of lower memory (0MB start address) - uint32_t mem_upper; ///< Amount of upper memory (1MB start address) - }; - - /** - * @brief Defines all memory area types possible that the memory region can be in. - */ - enum class memory_area_type : uint32_t - { - AVAILABLE = 1, ///< Region is available for use by the OS - RESERVED, ///< Region is reserved by firmware or bootloader and should not be used by OS - ACPI_AVAILABLE, ///< Region is reclaimable by OS after ACPI event - RESERVED_HIBERNATION, ///< Region is used for Non-volatile Storage (NVS) - DEFECTIVE ///< Region is defective or unusable - }; - - /** - * @brief Defines an entry in the entries array of the memory_map struct. Has to have all padding stripped between the - * individual values, because the size of the entry needs to be exactly 24 bytes and not one byte more. See - * https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Packed-Structures.html for more information on the - * used attribute. - */ - struct __attribute__((packed)) memory_area - { - uint32_t size; ///< TODO: Not clear what exactly the size signifies - uint64_t base_address; ///< Base address the memory region starts at - uint64_t area_length; ///< Size of the memory region, added to base_address results in the final address - memory_area_type type; ///< Specific type of memory the region can contain - }; - /*struct memory_area - { - uint64_t base_address; ///< Base address the memory region starts at - uint64_t area_length; ///< Size of the memory region, added to base_address results in the final address - memory_area_type type; ///< Specific type of memory the region can contain - };*/ - - /** - * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type - * multi_boot_tag_type::MEMORY_MAP. - */ - struct memory_map - { - multi_boot_tag tag; ///< Basic multi_boot_tag information - uint32_t entry_size; ///< Size of each entry in the memory_area array. Guaranteed multiple of 8 - uint32_t entry_version; ///< Version of the entries, currently 0 - struct memory_area entries; ///< Specific memory regions - }; - - /** - * @brief Defines all elf section types an elf section header can have. See - * https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. - */ - enum class elf_section_type : uint32_t - { - INACTIVE, ///< (SHT_NULL) Unused, meaning all values are zeroed out - PROGRAMM, ///< (SHT_PROGBITS) Program data (DATA, CODE) - SYMBOL_TABLE, ///< (SHT_SYMBTAB) Contains actual entries pointed to in symbol hash table - STRING_TABLE, ///< (SHT_STRTAB) Contains symbols, section and deubbging null-terminated strings - RELOCATION_ENTRY_WITH_ADDENDS, ///< (SHT_RELA) Only used on 64 bit systems - SYMBOL_HASH_TABLE, ///< (SHT_HASH) Hash table used by dynamic linker to locate symbols - DYNAMIC, ///< (SHT_DYNAMIC) Contains dynamic linking information - NOTE, ///< (SHT_NOTE) Stores information that marks files in some way - EMPTY, ///< (SHT_NOBITS) Program data section, that occupies no space in the file (.bss) - RELOCATION_ENTRY_WITHOUT_ADDENDS, ///< (SHT_REL) Only used on 32 bit systems - UNSPECIFIED, ///< (SHT_SHLIB) Reserved but has unspecified semantics - DYNAMIC_SYMBOL_TABLE, ///< (SHT_DYNSYM) Holds minimal set of symbols adequate for dynamic linking - INITALIZATION_FUNCTION_ARRAY = 14, ///< (SHT_INIT_ARRAY) Array of pointers to intialization functions () -> void - TERMINATION_FUNCTION_ARRAY, ///< (SHT_FINI_ARRAY) Array of pointers to termination functions () -> void - PRE_INITALIZATION_FUNCTION_ARRAY ///< (SHT_PRE_INIT_ARRAY) Array of pointers to functions invoked before other - ///< initalization functions () -> void - }; - - /** - * @brief Defines helper function for all states that the elf section flags of an elf section header can - * have. See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html - * See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. - */ - struct elf_section_flags - { - /** - * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. - */ - enum bitset : uint32_t - { - WRITABLE = 1U << 0U, ///< (SHF_WRITE) Section is writable at runtime. If it isn't then the section - ///< is assumed to be READONLY and only that flag is shown in the objdump. - OCCUPIES_MEMORY = 1U << 1U, ///< (SHF_ALLOC) Section occupies memory during execution. - ///< ALLOC flag is shown in the objdump. - EXECUTABLE_CODE = 1U << 2U, ///< (SHF_EXECINSTR) Section is executable. CODE flag is shown in the object dump. - DUPLICATE_DATA = 1U << 4U, ///< (SHF_MERGE) Section might be merged with another section. - CONTAINS_STRING = 1U << 5U, ///< (SHF_STRINGS) Section contains null-terminated strings. - SECTION_HEADER_INFO_IS_SECTION_HEADER_TABLE_INDEX = - 1U << 6U, ///< (SHF_INFO_LINK) Section contains the section header table index in the (sh_info) - ///< additional_information variable. - PRESERVE_ORDERING_AFTER_COMBINATION = - 1U << 7U, ///< (SHF_LINK_ORDER) Section preserves order after combining with another section. - REQUIRES_SPECIAL_OS_PROCESSING = - 1U << 8U, ///< (SHF_OS_NONCONFORMING) Section requires non-standard OS specific handling of its code or - ///< data, which does not confirm to standard ELF specifications. - SECTION_GROUP_MEMBER = 1U << 9U, ///< (SHF_GROUP) Section is a member of a section group. - HOLDS_THREAD_LOCAL_DATA = 1U << 10U, ///< (SHF_TLS) Section holds thread-local data. - COMPRESSED = 1U << 11U, ///< (SHF_COMPRESSED) Section contains compressed data. - SPECIAL_ORDERING_REQUIREMENTS = - 1U << 30U, ///< (SHF_ORDERED) Section has special ordering requirements, meaning it - ///< should be ordered in relation to other sections of the same type - EXCLUDED_UNLESS_REFERENCED_OR_ALLOCATED = 1U << 31U, ///< (SHF_EXCLUDE)Section is excluded unless referenced or - ///< allocated, used for LTO (Link-Time Optimizations) - }; - - /** - * @brief Constructor. - * - * @param flags Actual value read from the elf section header, which should be converted into a std::bitset, to - * allow reading the state of single bits more easily. - */ - explicit elf_section_flags(uint64_t flags) - : flags(flags) - { - // Nothing to do - } - - /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all - * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits - * that are set are not relevant. - * - * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying std::bitset - */ - auto contains_flags(std::bitset<64U> other) const -> bool; - - /** - * @brief Allows to compare the underlying std::bitset of two instances - * - * @param other Other instance that we want to compare with - * @return Whether the underlying std::bitset of both types is the same - */ - auto operator==(elf_section_flags const & other) const -> bool = default; - - private: - std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 21 - 28 are reserved for operating - ///< system specific semantics and bits 29 - 32 are reserved for processor specific - ///< semantics. Bits 33 - 64 are unused for compatability with ELF32. - }; - - /** - * @brief Defines the data included in a section header, where each section has exactly one section header. - * See https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html for more information - */ - struct elf_section_header - { - uint32_t name_table_index; ///< Index into the section header string table, specifies the name of the section - elf_section_type type; ///< Categorizes the sections content and semantics - elf_section_flags flags; ///< 1-bit flgas that describe section attributes - uint64_t virtual_address; ///< If section appears in memory image of a process, gives address at which the sections - ///< first byte should reside, otherwise 0 - uint64_t file_offset; ///< Offset from the beginning of the file to the first byte in the section. SHT_NOBITS - ///< contains the conceptual placement instead (because it occupies no space in the file) - uint64_t section_size; ///< Complete section size in bytes, SHT_NOBITS may have non-zero value but will always - ///< occupy no space in the file - uint32_t other_section; ///< Section header table index link, behaviour varies on type - ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link - uint32_t additional_information; ///< Extra information, behaviour varies on type - ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link - uint64_t address_alignment; ///< Possible address alignment constraints. Value of virutal_address must be 0 % value - ///< of address_alignment. Value 0 or 1 mean no alignment constraints - uint64_t fixed_table_entry_size; ///< If sections holds table with fixed-sized entries, this gives the size in - ///< bytes of each entry - - /** - * @brief Detect whether a section header is inactive or not, should always be the case for the first entry in the - * sections table - * @return Whether the current section header is actually null or not, requires all fields besides section_size and - * other_section to contain 0 - */ - auto is_null() const -> bool; - }; - - /** - * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type - * multi_boot_tag_type::ELF_SECTIONS. - * The first section in the sections array will always be INACTIVE, there can only ever be one DYNAMIC section and - * only either one DYNAMIC_SYMBOL_TABLE or SYMBOL_TABLE. - */ - struct elf_symbols_section - { - multi_boot_tag tag; ///< Basic multi_boot_tag information - uint32_t number_of_sections; ///< Number of sections in the sections array - uint32_t entry_size; ///< Size of each entry in the sections array - uint32_t section_index; ///< Index to the string table used for symbol names - std::byte end; ///< Marks the end of the tag, used to mark the beginning of any additional data - ///< contained in the section, to ensure byte alignment is actually 4 byte - }; -} // namespace teachos::arch::memory - -#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/elf_sybols_section.hpp b/arch/x86_64/include/arch/memory/multiboot/elf_sybols_section.hpp new file mode 100644 index 0000000..88d211e --- /dev/null +++ b/arch/x86_64/include/arch/memory/multiboot/elf_sybols_section.hpp @@ -0,0 +1,157 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP + +#include "info.hpp" +#include +#include + +namespace teachos::arch::memory::multiboot +{ + /** + * @brief Defines all elf section types an elf section header can have. See + * https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. + */ + enum class elf_section_type : uint32_t + { + INACTIVE, ///< (SHT_NULL) Unused, meaning all values are zeroed out + PROGRAMM, ///< (SHT_PROGBITS) Program data (DATA, CODE) + SYMBOL_TABLE, ///< (SHT_SYMBTAB) Contains actual entries pointed to in symbol hash table + STRING_TABLE, ///< (SHT_STRTAB) Contains symbols, section and deubbging null-terminated strings + RELOCATION_ENTRY_WITH_ADDENDS, ///< (SHT_RELA) Only used on 64 bit systems + SYMBOL_HASH_TABLE, ///< (SHT_HASH) Hash table used by dynamic linker to locate symbols + DYNAMIC, ///< (SHT_DYNAMIC) Contains dynamic linking information + NOTE, ///< (SHT_NOTE) Stores information that marks files in some way + EMPTY, ///< (SHT_NOBITS) Program data section, that occupies no space in the file (.bss) + RELOCATION_ENTRY_WITHOUT_ADDENDS, ///< (SHT_REL) Only used on 32 bit systems + UNSPECIFIED, ///< (SHT_SHLIB) Reserved but has unspecified semantics + DYNAMIC_SYMBOL_TABLE, ///< (SHT_DYNSYM) Holds minimal set of symbols adequate for dynamic linking + INITALIZATION_FUNCTION_ARRAY = 14, ///< (SHT_INIT_ARRAY) Array of pointers to intialization functions () -> void + TERMINATION_FUNCTION_ARRAY, ///< (SHT_FINI_ARRAY) Array of pointers to termination functions () -> void + PRE_INITALIZATION_FUNCTION_ARRAY ///< (SHT_PRE_INIT_ARRAY) Array of pointers to functions invoked before other + ///< initalization functions () -> void + }; + + /** + * @brief Defines helper function for all states that the elf section flags of an elf section header can + * have. See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html + * See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. + */ + struct elf_section_flags + { + /** + * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + */ + enum bitset : uint32_t + { + WRITABLE = 1U << 0U, ///< (SHF_WRITE) Section is writable at runtime. If it isn't then the section + ///< is assumed to be READONLY and only that flag is shown in the objdump. + OCCUPIES_MEMORY = 1U << 1U, ///< (SHF_ALLOC) Section occupies memory during execution. + ///< ALLOC flag is shown in the objdump. + EXECUTABLE_CODE = 1U << 2U, ///< (SHF_EXECINSTR) Section is executable. CODE flag is shown in the object dump. + DUPLICATE_DATA = 1U << 4U, ///< (SHF_MERGE) Section might be merged with another section. + CONTAINS_STRING = 1U << 5U, ///< (SHF_STRINGS) Section contains null-terminated strings. + SECTION_HEADER_INFO_IS_SECTION_HEADER_TABLE_INDEX = + 1U << 6U, ///< (SHF_INFO_LINK) Section contains the section header table index in the (sh_info) + ///< additional_information variable. + PRESERVE_ORDERING_AFTER_COMBINATION = + 1U << 7U, ///< (SHF_LINK_ORDER) Section preserves order after combining with another section. + REQUIRES_SPECIAL_OS_PROCESSING = + 1U << 8U, ///< (SHF_OS_NONCONFORMING) Section requires non-standard OS specific handling of its code or + ///< data, which does not confirm to standard ELF specifications. + SECTION_GROUP_MEMBER = 1U << 9U, ///< (SHF_GROUP) Section is a member of a section group. + HOLDS_THREAD_LOCAL_DATA = 1U << 10U, ///< (SHF_TLS) Section holds thread-local data. + COMPRESSED = 1U << 11U, ///< (SHF_COMPRESSED) Section contains compressed data. + SPECIAL_ORDERING_REQUIREMENTS = + 1U << 30U, ///< (SHF_ORDERED) Section has special ordering requirements, meaning it + ///< should be ordered in relation to other sections of the same type + EXCLUDED_UNLESS_REFERENCED_OR_ALLOCATED = 1U << 31U, ///< (SHF_EXCLUDE)Section is excluded unless referenced or + ///< allocated, used for LTO (Link-Time Optimizations) + }; + + /** + * @brief Constructor. + * + * @param flags Actual value read from the elf section header, which should be converted into a std::bitset, to + * allow reading the state of single bits more easily. + */ + explicit elf_section_flags(uint64_t flags) + : flags(flags) + { + // Nothing to do + } + + /** + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all + * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits + * that are set are not relevant. + * + * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. + * @return Whether the given flags are a subset or equivalent with the underlying std::bitset + */ + auto contains_flags(std::bitset<64U> other) const -> bool; + + /** + * @brief Allows to compare the underlying std::bitset of two instances + * + * @param other Other instance that we want to compare with + * @return Whether the underlying std::bitset of both types is the same + */ + auto operator==(elf_section_flags const & other) const -> bool = default; + + private: + std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 21 - 28 are reserved for operating + ///< system specific semantics and bits 29 - 32 are reserved for processor specific + ///< semantics. Bits 33 - 64 are unused for compatability with ELF32. + }; + + /** + * @brief Defines the data included in a section header, where each section has exactly one section header. + * See https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html for more information + */ + struct elf_section_header + { + uint32_t name_table_index; ///< Index into the section header string table, specifies the name of the section + elf_section_type type; ///< Categorizes the sections content and semantics + elf_section_flags flags; ///< 1-bit flgas that describe section attributes + uint64_t virtual_address; ///< If section appears in memory image of a process, gives address at which the sections + ///< first byte should reside, otherwise 0 + uint64_t file_offset; ///< Offset from the beginning of the file to the first byte in the section. SHT_NOBITS + ///< contains the conceptual placement instead (because it occupies no space in the file) + uint64_t section_size; ///< Complete section size in bytes, SHT_NOBITS may have non-zero value but will always + ///< occupy no space in the file + uint32_t other_section; ///< Section header table index link, behaviour varies on type + ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link + uint32_t additional_information; ///< Extra information, behaviour varies on type + ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link + uint64_t address_alignment; ///< Possible address alignment constraints. Value of virutal_address must be 0 % value + ///< of address_alignment. Value 0 or 1 mean no alignment constraints + uint64_t fixed_table_entry_size; ///< If sections holds table with fixed-sized entries, this gives the size in + ///< bytes of each entry + + /** + * @brief Detect whether a section header is inactive or not, should always be the case for the first entry in the + * sections table + * @return Whether the current section header is actually null or not, requires all fields besides section_size and + * other_section to contain 0 + */ + auto is_null() const -> bool; + }; + + /** + * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type + * multi_boot_tag_type::ELF_SECTIONS. + * The first section in the sections array will always be INACTIVE, there can only ever be one DYNAMIC section and + * only either one DYNAMIC_SYMBOL_TABLE or SYMBOL_TABLE. + */ + struct elf_symbols_section_header + { + tag info; ///< Basic multi_boot_tag information + uint32_t number_of_sections; ///< Number of sections in the sections array + uint32_t entry_size; ///< Size of each entry in the sections array + uint32_t section_index; ///< Index to the string table used for symbol names + std::byte end; ///< Marks the end of the tag, used to mark the beginning of any additional data + ///< contained in the section, to ensure byte alignment is actually 4 byte + }; +} // namespace teachos::arch::memory::multiboot + +#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/info.hpp b/arch/x86_64/include/arch/memory/multiboot/info.hpp new file mode 100644 index 0000000..ca87834 --- /dev/null +++ b/arch/x86_64/include/arch/memory/multiboot/info.hpp @@ -0,0 +1,62 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_INFO_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_INFO_HPP + +#include + +namespace teachos::arch::memory::multiboot +{ + /** + * @brief Defines all possible types a multiboot2 tag structure can have. + * See + * https://github.com/rhboot/grub2/blob/fedora-39/include/multiboot2.h for more information on the structure of the + * tag headers and see https://github.com/rhboot/grub2/blob/fedora-39/include/multiboot.h for more information on the + * actual header contents and their following data. + */ + enum class tag_type : uint32_t + { + END, ///< Signals final tag for the multiboot2 information structure + CMDLINE, ///< Contains the command line string + BOOT_LOADER_NAME, ///< Contains the name of the boot loader booting the kernel + MODULE, ///< Indicates the boot module which was loaded along the kernel image + BASIC_MEMORY_INFO, ///< Contains the amount of lower (0MB start address) and upper memory (1MB start address) + BOOTDEV, ///< Indicates which BIOS disk device the hoot loader has loaded the OS image from + MEMORY_MAP, ///< Describes the memory layout of the system with individual areas and their flags + VBE_INFO, ///< Includes information to access and utilize the device GPU + FRAMEBUFFER, ///< VBE framebuffer information + ELF_SECTIONS, ///< Includes list of all section headers from the loaded ELF kernel + APM_INFO, ///< Advanced Power Management information + EFI32, ///< EFI 32 bit system table pointer + EFI64, ///< EFI 64 bit system table pointer + SMBIOS, ///< Contains copy of all Sytem Management BIOS tables + ACPI_OLD, ///< Contains copy of RSDP as defined per ACPI1.0 specification + ACPI_NEW, ///< Contains copy of RSDP as defined per ACPI2.0 or later specification + NETWORK, ///< Contains network information specified specified as DHCP + EFI_MEMORY_MAP, ///< Contains EFI memory map + EFI_BS_NOT_TERMINATED, ///< Indicated ExitBootServies wasn't called + EFI32_IMAGE_HANDLE, ///< EFI 32 bit image handle pointer + EFI64_IMAGE_HANDLE, ///< EFI 64 bit imae handle pointer + LOAD_BASE_ADDRESS ///< Contains image load base physical address + }; + + /** + * @brief Basic structure that every entry in the multi_boot_tag array of the multi_boot_info struct has to begin + * with. + */ + struct tag + { + tag_type type; ///< Specific type of this multi_boot_tag entry, used to differentiate handling + uint32_t size; ///< Total size of this multi_boot_tag entry with all fields of the actual type + }; + + /** + * @brief Basic structure the multiboot_information_pointer points too and which contains all information of + * multiboot2 in the tags array of different types. The start as well as the content has to be 8 byte aligned. + */ + struct info_header + { + uint32_t total_size; ///< Total size of all multiboot::tags and their data + alignas(8) struct tag tags; ///< Specific tags + }; +} // namespace teachos::arch::memory::multiboot + +#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_INFO_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp new file mode 100644 index 0000000..4dc11cf --- /dev/null +++ b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp @@ -0,0 +1,93 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP + +#include "info.hpp" +#include + +namespace teachos::arch::memory::multiboot +{ + /** + * @brief Defines all memory area types possible that the memory region can be in. + */ + enum class memory_area_type : uint32_t + { + AVAILABLE = 1, ///< Region is available for use by the OS + RESERVED, ///< Region is reserved by firmware or bootloader and should not be used by OS + ACPI_AVAILABLE, ///< Region is reclaimable by OS after ACPI event + RESERVED_HIBERNATION, ///< Region is used for Non-volatile Storage (NVS) + DEFECTIVE ///< Region is defective or unusable + }; + + /** + * @brief Defines an entry in the entries array of the memory_map struct. Has to have all padding stripped between the + * individual values, because the size of the entry needs to be exactly 24 bytes and not one byte more. See + * https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Packed-Structures.html for more information on the + * used attribute. + */ + struct __attribute__((packed)) memory_area + { + uint32_t size; ///< Size of this structure in bytes + uint64_t base_address; ///< Base address the memory region starts at + uint64_t area_length; ///< Size of the memory region, added to base_address results in the final address + memory_area_type type; ///< Specific type of memory the region can contain + }; + + /** + * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type + * multi_boot_tag_type::MEMORY_MAP. + */ + struct memory_map_header + { + tag info; ///< Basic multi_boot_tag information + uint32_t entry_size; ///< Size of each entry in the memory_area array. Guaranteed multiple of 8 + uint32_t entry_version; ///< Version of the entries, currently 0 + struct memory_area entries; ///< Specific memory regions + }; + + /** + * @brief Iterator for memory areas. + */ + struct memory_area_iterator + { + /** + * @brief Constructor. + * + * @param p Underlying address the iterator should point too, ensure to not pass an invalid pointer. + */ + explicit memory_area_iterator(memory_area * p); + + /** + * @brief Dereferences the initally given pointer to its value. + * + * @return Reference to the value. + */ + memory_area & operator*() const; + + /** + * @brief Post increment operator. Returns a copy of the value + * + * @return Copy of the incremented underlying address. + */ + memory_area_iterator operator++(int); + + /** + * @brief Pre increment operator. Returns a reference to the changed value. + * + * @return Reference to the incremented underlying address. + */ + memory_area_iterator & operator++(); + + /** + * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. + * + * @param other Other iterator to compare to. + * @return Whether poith iterators point to the same underlying address in memory. + */ + bool operator==(memory_area_iterator const & other) const = default; + + private: + memory_area * ptr; ///< Underlying address the iterator is currently pointing too. + }; +} // namespace teachos::arch::memory::multiboot + +#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/reader.hpp b/arch/x86_64/include/arch/memory/multiboot/reader.hpp new file mode 100644 index 0000000..14086a7 --- /dev/null +++ b/arch/x86_64/include/arch/memory/multiboot/reader.hpp @@ -0,0 +1,50 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP + +#include "elf_sybols_section.hpp" +#include "memory_map.hpp" +#include + +namespace teachos::arch::memory::multiboot +{ + /** + * @brief Contains all relevant information to map and allocate memory that is read from the multiboot2 information + * structure. + */ + struct memory_information + { + std::size_t kernel_start; ///< Start address of the kernel code in memory. + std::size_t kernel_end; ///< End address of the kernel code in memory. + std::size_t multiboot_start; ///< Start address of the multiboot code in memory. + std::size_t multiboot_end; ///< End address of the multiboot code in memory. + memory_area * memory_areas; ///< Non-owning pointer to the first element of all memory areas. + uint8_t area_count; ///< Amount of total entries in the memory_areas array. + }; + + /** + * @brief Reads the relevant multiboot2 information data from memory. This is done using the + * multiboot_information_pointer, which marks the start of the multiboot2 data. The indivdual headers we have to read + * are 8 byte aligned, whereas the data contained in those headers does not have to be. All sections that are read + * additionaly receive some sanity to ensure the read address is actually pointing to the expected structure, if they + * are not this method will assert. + * + * The memory_information variables are calcualted like this: + * - kernel_start: Calculated by getting the lowest address specified in the elf symbols headers. + * - kernel_end: Calculated by getting the highest address specified in the elf symbols headers and adding the length + * of that section. + * - multiboot_start: Calcualted by simply getting the value of the multiboot information pointer, because it already + * contains the address pointint to the start of the multiboot2 data. + * - multiboot_end: Calcualted by getting the value of the multiboot information pointer and adding the total size of + * the complete multiboot2 data + * - memory_areas: Calculated by simply accessing the address of the entries variable in the memory map header + * structure. + * - area_count: Calculated by subtracing the memory map header size from the total tag size, which results in the + * remaining size (size of the entries array), this size is then divided by the size of one entry in that array, which + * should be 24 bytes. + * + * @return Relevant data read from multiboot2. + */ + auto read_multiboot2() -> memory_information; +} // namespace teachos::arch::memory::multiboot + +#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp index 4bbb0e0..04c2065 100644 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ b/arch/x86_64/include/arch/memory/paging.hpp @@ -4,6 +4,7 @@ #include "arch/exception_handling/assert.hpp" #include "frame_allocator.hpp" +#include namespace teachos::arch::memory { @@ -113,6 +114,10 @@ namespace teachos::arch::memory template struct page_table { + /** + * @brief Level of the page table, level 1 should not be able to call next_table anymore, because it would result in + * attempting to access memory that it should not. + */ enum level : uint8_t { LEVEL1, diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index babe251..c0d4aed 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,120 +1,14 @@ #include "arch/kernel/main.hpp" -#include "arch/boot/pointers.hpp" #include "arch/exception_handling/assert.hpp" #include "arch/memory/frame_allocator.hpp" -#include "arch/memory/multiboot.hpp" +#include "arch/memory/multiboot/reader.hpp" #include "arch/video/vga/text.hpp" #include namespace teachos::arch::kernel { - auto process_memory_map(arch::memory::memory_map * mminfo, arch::memory::memory_area *& memory_areas, - uint8_t & area_count) -> void - { - auto expected_entry_size = mminfo->entry_size; - constexpr auto actual_entry_size = sizeof(arch::memory::memory_area); - arch::exception_handling::assert(expected_entry_size == actual_entry_size, "Unexpected memoryarea entry size"); - - auto total_size = mminfo->tag.size; - auto total_entries_size = total_size - sizeof(arch::memory::memory_map) + actual_entry_size; - auto number_of_entries = total_entries_size / actual_entry_size; - - memory_areas = &mminfo->entries; - area_count = number_of_entries; - } - - auto process_elf_sections(arch::memory::elf_symbols_section * symbol, uint64_t & kernel_start, - uint64_t & kernel_end) -> void - { - auto expected_entry_size = symbol->entry_size; - constexpr auto actual_entry_size = sizeof(arch::memory::elf_section_header); - arch::exception_handling::assert(expected_entry_size == actual_entry_size, - "Unexpected elf_section_header entry size"); - - auto expected_total_size = symbol->tag.size; - auto actual_total_entry_size = actual_entry_size * symbol->number_of_sections; - constexpr auto actual_total_section_size = sizeof(arch::memory::elf_symbols_section) - sizeof(uint32_t); - auto actual_total_size = actual_total_entry_size + actual_total_section_size; - arch::exception_handling::assert(expected_total_size == actual_total_size, "Unexpected elf_symbols total size"); - - auto begin = reinterpret_cast(&symbol->end); - auto end = begin + symbol->number_of_sections; - arch::exception_handling::assert(begin->is_null(), "Missing elf_section_header begin"); - - std::size_t symbol_table_section_count = 0U; - std::size_t dynamic_section_count = 0U; - - for (auto section = begin; section != end; ++section) - { - bool const writable = section->flags.contains_flags(arch::memory::elf_section_flags::WRITABLE); - bool const occupies_memory = section->flags.contains_flags(arch::memory::elf_section_flags::OCCUPIES_MEMORY); - bool const is_executable = section->flags.contains_flags(arch::memory::elf_section_flags::EXECUTABLE_CODE); - bool const contains_duplicate_data = - section->flags.contains_flags(arch::memory::elf_section_flags::DUPLICATE_DATA); - bool const contains_strings = section->flags.contains_flags(arch::memory::elf_section_flags::CONTAINS_STRING); - bool const section_header_info_is_section_header_table_index = section->flags.contains_flags( - arch::memory::elf_section_flags::SECTION_HEADER_INFO_IS_SECTION_HEADER_TABLE_INDEX); - bool const preserve_ordering_after_combination = - section->flags.contains_flags(arch::memory::elf_section_flags::PRESERVE_ORDERING_AFTER_COMBINATION); - bool const requires_special_os_processing = - section->flags.contains_flags(arch::memory::elf_section_flags::REQUIRES_SPECIAL_OS_PROCESSING); - bool const is_section_group_member = - section->flags.contains_flags(arch::memory::elf_section_flags::SECTION_GROUP_MEMBER); - bool const holds_thread_local_data = - section->flags.contains_flags(arch::memory::elf_section_flags::HOLDS_THREAD_LOCAL_DATA); - bool const is_compressed = section->flags.contains_flags(arch::memory::elf_section_flags::COMPRESSED); - bool const has_special_ordering_requirements = - section->flags.contains_flags(arch::memory::elf_section_flags::SPECIAL_ORDERING_REQUIREMENTS); - bool const is_excluded_unless_referenced_or_allocated = - section->flags.contains_flags(arch::memory::elf_section_flags::EXCLUDED_UNLESS_REFERENCED_OR_ALLOCATED); - - if (writable && occupies_memory && is_executable && contains_duplicate_data && contains_strings && - section_header_info_is_section_header_table_index && preserve_ordering_after_combination && - requires_special_os_processing && is_section_group_member && holds_thread_local_data && is_compressed && - has_special_ordering_requirements && is_excluded_unless_referenced_or_allocated) - { - } - - switch (section->type) - { - case arch::memory::elf_section_type::PROGRAMM: { - if (section->virtual_address < kernel_start) - { - kernel_start = section->virtual_address; - } - auto virtual_address_end = section->virtual_address + section->section_size; - if (virtual_address_end > kernel_end) - { - kernel_end = virtual_address_end; - } - break; - } - case arch::memory::elf_section_type::DYNAMIC_SYMBOL_TABLE: - case arch::memory::elf_section_type::SYMBOL_TABLE: - symbol_table_section_count++; - break; - case arch::memory::elf_section_type::DYNAMIC: - dynamic_section_count++; - break; - default: - // All other cases are not important and can be ignored - break; - } - } - - arch::exception_handling::assert(symbol_table_section_count == 1U, "Unexpected symbol_table_count value"); - arch::exception_handling::assert(dynamic_section_count <= 1U, "Unexpected dynamic_section_count value"); - } - - 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 main() -> void { using namespace video::vga; @@ -123,47 +17,8 @@ namespace teachos::arch::kernel text::cursor(false); text::write("TeachOS is starting up...", text::common_attributes::green_on_black); - auto * multiboot_information_pointer = - reinterpret_cast(arch::boot::multiboot_information_pointer); - auto multiboot_tag = &(multiboot_information_pointer->tags); - - uint64_t kernel_start = UINT64_MAX; - uint64_t kernel_end = 0; - uint64_t multiboot_start = arch::boot::multiboot_information_pointer; - uint64_t multiboot_end = multiboot_start + multiboot_information_pointer->total_size; - arch::memory::memory_area * memory_areas = nullptr; - uint8_t area_count = 0; - - /* - * Loop over the multiboot2 tags to access the information needed. - * Tags are defined in the header file and are padded so that each - * Tag starts at an 8-bytes aligned adress. - * - * The increment part aligns the size to an 8-byte address. - */ - for (auto tag = multiboot_tag; tag->type != arch::memory::multi_boot_tag_type::END; - tag = align_to_8_byte_boundary(tag, tag->size)) - { - switch (tag->type) - { - case arch::memory::multi_boot_tag_type::ELF_SECTIONS: { - auto symbol = reinterpret_cast(tag); - process_elf_sections(symbol, kernel_start, kernel_end); - break; - } - case arch::memory::multi_boot_tag_type::MEMORY_MAP: { - auto mminfo = reinterpret_cast(tag); - process_memory_map(mminfo, memory_areas, area_count); - break; - } - default: - // All other cases are not important and can be ignored - break; - } - } - - auto allocator = arch::memory::area_frame_allocator(kernel_start, kernel_end, multiboot_start, multiboot_end, - memory_areas, area_count); + auto memory_information = memory::multiboot::read_multiboot2(); + auto allocator = memory::area_frame_allocator(memory_information); auto last_allocated = allocator.allocate_frame(); auto allocated = last_allocated; diff --git a/arch/x86_64/src/memory/frame_allocator.cpp b/arch/x86_64/src/memory/frame_allocator.cpp index 70276ae..7776082 100644 --- a/arch/x86_64/src/memory/frame_allocator.cpp +++ b/arch/x86_64/src/memory/frame_allocator.cpp @@ -17,37 +17,15 @@ namespace teachos::arch::memory auto physical_frame::start_address() const -> uint64_t { return frame_number * PAGE_FRAME_SIZE; } - memory_area_iterator::memory_area_iterator(memory_area * p) - : ptr(p) - { - // Nothing to do - } - - memory_area & memory_area_iterator::operator*() const { return *ptr; } - - auto memory_area_iterator::operator++(int) -> memory_area_iterator - { - ++(*this); - return *this; - } - - auto memory_area_iterator::operator++() -> memory_area_iterator & - { - ++ptr; - return *this; - } - - area_frame_allocator::area_frame_allocator(std::size_t kernel_start, std::size_t kernel_end, - std::size_t multiboot_start, std::size_t multiboot_end, - memory_area * memory_areas, uint8_t area_count) + area_frame_allocator::area_frame_allocator(multiboot::memory_information mem_info) : next_free_frame(0) , current_area(std::nullopt) - , area_begin(memory_areas) - , area_end(memory_areas + area_count) - , kernel_start(physical_frame::containing_address(kernel_start)) - , kernel_end(physical_frame::containing_address(kernel_end)) - , multiboot_start(physical_frame::containing_address(multiboot_start)) - , multiboot_end(physical_frame::containing_address(multiboot_end)) + , area_begin(mem_info.memory_areas) + , area_end(mem_info.memory_areas + mem_info.area_count) + , 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(); } @@ -56,9 +34,9 @@ namespace teachos::arch::memory { current_area = std::nullopt; - for (memory_area_iterator it = begin(); it != end(); ++it) + for (multiboot::memory_area_iterator it = begin(); it != end(); ++it) { - memory_area & area = *it; + multiboot::memory_area & area = *it; std::size_t address = area.base_address + area.area_length - 1; if (physical_frame::containing_address(address) >= next_free_frame) @@ -126,7 +104,7 @@ namespace teachos::arch::memory "[deallocate_frame] Not implemented Exception"); } - auto area_frame_allocator::begin() -> memory_area_iterator { return area_begin; } + auto area_frame_allocator::begin() -> multiboot::memory_area_iterator { return area_begin; } - auto area_frame_allocator::end() -> memory_area_iterator { return area_end; } + auto area_frame_allocator::end() -> multiboot::memory_area_iterator { return area_end; } } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/memory/multiboot.cpp b/arch/x86_64/src/memory/multiboot.cpp deleted file mode 100644 index 8c6793e..0000000 --- a/arch/x86_64/src/memory/multiboot.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "arch/memory/multiboot.hpp" - -namespace teachos::arch::memory -{ - 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) && - virtual_address == 0U && file_offset == 0U && additional_information == 0U && address_alignment == 0U && - fixed_table_entry_size == 0U; - } -} // 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 new file mode 100644 index 0000000..78ab952 --- /dev/null +++ b/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp @@ -0,0 +1,13 @@ +#include "arch/memory/multiboot/elf_sybols_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) && + virtual_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/memory_map.cpp b/arch/x86_64/src/memory/multiboot/memory_map.cpp new file mode 100644 index 0000000..6b1d1d4 --- /dev/null +++ b/arch/x86_64/src/memory/multiboot/memory_map.cpp @@ -0,0 +1,24 @@ +#include "arch/memory/multiboot/memory_map.hpp" + +namespace teachos::arch::memory::multiboot +{ + memory_area_iterator::memory_area_iterator(multiboot::memory_area * p) + : ptr(p) + { + // Nothing to do + } + + multiboot::memory_area & memory_area_iterator::operator*() const { return *ptr; } + + auto memory_area_iterator::operator++(int) -> memory_area_iterator + { + ++(*this); + return *this; + } + + auto memory_area_iterator::operator++() -> memory_area_iterator & + { + ++ptr; + return *this; + } +} // 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 new file mode 100644 index 0000000..8741b44 --- /dev/null +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -0,0 +1,117 @@ +#include "arch/memory/multiboot/reader.hpp" + +#include "arch/boot/pointers.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/memory/multiboot/info.hpp" + +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 *& memory_areas, uint8_t & area_count) -> void + { + auto expected_entry_size = mminfo->entry_size; + constexpr auto actual_entry_size = sizeof(memory_area); + arch::exception_handling::assert(expected_entry_size == actual_entry_size, "Unexpected memory_area entry size"); + + auto total_size = mminfo->info.size; + auto total_entries_size = total_size - sizeof(memory_map_header) + actual_entry_size; + auto number_of_entries = total_entries_size / actual_entry_size; + + memory_areas = &mminfo->entries; + area_count = number_of_entries; + } + + auto process_elf_sections(elf_symbols_section_header * symbol, uint64_t & kernel_start, + uint64_t & kernel_end) -> void + { + auto expected_entry_size = symbol->entry_size; + constexpr auto actual_entry_size = sizeof(elf_section_header); + arch::exception_handling::assert(expected_entry_size == actual_entry_size, + "Unexpected elf_section_header entry size"); + + auto expected_total_size = symbol->info.size; + auto actual_total_entry_size = actual_entry_size * symbol->number_of_sections; + constexpr auto actual_total_section_size = sizeof(elf_symbols_section_header) - sizeof(uint32_t); + auto actual_total_size = actual_total_entry_size + actual_total_section_size; + arch::exception_handling::assert(expected_total_size == actual_total_size, + "Unexpected elf_symbols_section_header total size"); + + auto begin = reinterpret_cast(&symbol->end); + auto end = begin + symbol->number_of_sections; + arch::exception_handling::assert(begin->is_null(), "Missing elf_section_header begin"); + + std::size_t symbol_table_section_count = 0U; + std::size_t dynamic_section_count = 0U; + + for (auto section = begin; section != end; ++section) + { + switch (section->type) + { + case elf_section_type::PROGRAMM: { + if (section->virtual_address < kernel_start) + { + kernel_start = section->virtual_address; + } + auto virtual_address_end = section->virtual_address + section->section_size; + if (virtual_address_end > kernel_end) + { + kernel_end = virtual_address_end; + } + break; + } + case elf_section_type::DYNAMIC_SYMBOL_TABLE: + case elf_section_type::SYMBOL_TABLE: + symbol_table_section_count++; + break; + case elf_section_type::DYNAMIC: + dynamic_section_count++; + break; + default: + // All other cases are not important and can be ignored + break; + } + } + + arch::exception_handling::assert(symbol_table_section_count == 1U, "Unexpected symbol_table_count value"); + arch::exception_handling::assert(dynamic_section_count <= 1U, "Unexpected dynamic_section_count value"); + } + } // namespace + + auto read_multiboot2() -> memory_information + { + memory_information mem_info{UINT64_MAX, 0U, boot::multiboot_information_pointer, 0U, nullptr, 0U}; + + auto * multiboot_information_pointer = reinterpret_cast(boot::multiboot_information_pointer); + auto 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 symbol = reinterpret_cast(tag); + process_elf_sections(symbol, mem_info.kernel_start, mem_info.kernel_end); + break; + } + case tag_type::MEMORY_MAP: { + auto mminfo = reinterpret_cast(tag); + process_memory_map(mminfo, mem_info.memory_areas, mem_info.area_count); + break; + } + default: + // All other cases are not important and can be ignored + break; + } + } + return mem_info; + } +} // namespace teachos::arch::memory::multiboot -- cgit v1.2.3 From 675f38d6733fb19b4ffc7e9fbddb93acdd1d1e31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 19 Oct 2024 14:40:25 +0000 Subject: Seperate allocation and paging code into multiple files as well --- arch/x86_64/CMakeLists.txt | 6 +- .../arch/memory/allocator/area_frame_allocator.hpp | 75 +++++++ .../arch/memory/allocator/physical_frame.hpp | 52 +++++ .../x86_64/include/arch/memory/frame_allocator.hpp | 126 ------------ arch/x86_64/include/arch/memory/paging.hpp | 220 --------------------- .../include/arch/memory/paging/page_entry.hpp | 90 +++++++++ .../include/arch/memory/paging/page_table.hpp | 100 ++++++++++ .../include/arch/memory/paging/virtual_page.hpp | 27 +++ arch/x86_64/src/kernel/main.cpp | 4 +- .../src/memory/allocator/area_frame_allocator.cpp | 97 +++++++++ .../x86_64/src/memory/allocator/physical_frame.cpp | 22 +++ arch/x86_64/src/memory/frame_allocator.cpp | 110 ----------- arch/x86_64/src/memory/paging.cpp | 42 ---- arch/x86_64/src/memory/paging/page_entry.cpp | 42 ++++ arch/x86_64/src/memory/paging/page_table.cpp | 65 ++++++ 15 files changed, 576 insertions(+), 502 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp create mode 100644 arch/x86_64/include/arch/memory/allocator/physical_frame.hpp delete mode 100644 arch/x86_64/include/arch/memory/frame_allocator.hpp delete mode 100644 arch/x86_64/include/arch/memory/paging.hpp create mode 100644 arch/x86_64/include/arch/memory/paging/page_entry.hpp create mode 100644 arch/x86_64/include/arch/memory/paging/page_table.hpp create mode 100644 arch/x86_64/include/arch/memory/paging/virtual_page.hpp create mode 100644 arch/x86_64/src/memory/allocator/area_frame_allocator.cpp create mode 100644 arch/x86_64/src/memory/allocator/physical_frame.cpp delete mode 100644 arch/x86_64/src/memory/frame_allocator.cpp delete mode 100644 arch/x86_64/src/memory/paging.cpp create mode 100644 arch/x86_64/src/memory/paging/page_entry.cpp create mode 100644 arch/x86_64/src/memory/paging/page_table.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 7ddf303..016215b 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -44,8 +44,10 @@ target_sources("_memory" PRIVATE "src/memory/multiboot/elf_symbols_section.cpp" "src/memory/multiboot/memory_map.cpp" "src/memory/multiboot/reader.cpp" - "src/memory/frame_allocator.cpp" - "src/memory/paging.cpp" + "src/memory/allocator/area_frame_allocator.cpp" + "src/memory/allocator/physical_frame.cpp" + "src/memory/paging/page_entry.cpp" + "src/memory/paging/page_table.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp new file mode 100644 index 0000000..c9d4e7f --- /dev/null +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -0,0 +1,75 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP + +#include "arch/memory/multiboot/reader.hpp" + +#include "physical_frame.hpp" +#include + +namespace teachos::arch::memory::allocator +{ + /** + * @brief Allocates memory using memory areas read from the multiboot2 information pointer. + */ + struct area_frame_allocator + { + /** + * @brief Constructor + * + * @param mem_info Structure containg all relevant information to map and allocate memory + */ + area_frame_allocator(multiboot::memory_information mem_info); + + /** + * @brief Allocate memory by finding and returning a free physical_frame. + * + * The physical_frame allocation executes multiple checks before returning + * the physical_frame that is available to allocate. It must at least + * do the following: + * - check if the next_free_frame is within the current_area + * - check if the next_free_frame is actually free + * - update the next_free_frame after finding a free physical_frame + */ + auto allocate_frame() -> std::optional; + + /** + * @brief Deallocates a previously allocated physical_frame. + * + * @param physical_frame Previously allocated physical_frame that should be allocated. + */ + auto deallocate_frame(physical_frame physical_frame) -> void; + + /** + * @brief Returns the iterator pointing to the first element of the memory area. + * Allows using this class in the for each loop, because it follows the InputIterator template scheme. + * + * @return Iterator pointing to first element of the memory area. + */ + auto begin() -> multiboot::memory_area_iterator; + + /** + * @brief Returns the iterator pointing to one past the last element of the memory area. + * Allows using this class in the for each loop, because it follows the InputIterator template scheme. + * + * @return Iterator pointing to one past the last element of the memory area. + */ + auto end() -> multiboot::memory_area_iterator; + + private: + /** + * @brief Find the next memory area and write it into current_area. + */ + auto choose_next_area() -> void; + + physical_frame next_free_frame; ///< The physical_frame after the last allocated one. + std::optional current_area; ///< The current memory area. + multiboot::memory_area_iterator area_begin; ///< Pointer to the first element of all memory areas. + multiboot::memory_area_iterator area_end; ///< Pointer to one pas the last element of all memory areas. + physical_frame const kernel_start; ///< The start address of the kernel code in memory. + physical_frame const kernel_end; ///< The end address of the kernel code in memory. + physical_frame const multiboot_start; ///< The start address of the multiboot code in memory. + physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. + }; +} // namespace teachos::arch::memory::allocator + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp new file mode 100644 index 0000000..5e99d10 --- /dev/null +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -0,0 +1,52 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP + +#include +#include + +namespace teachos::arch::memory::allocator +{ + /** + * @brief Specific physical frame containing helper functions to determine if a specific address is in that + * physical frame or not. + */ + struct physical_frame + { + /** + * @brief Constructor. + * + * @param frame_number Index number that should be assigned to this physical_frame. + */ + explicit physical_frame(std::size_t frame_number); + + /** + * @brief Returns the physical_frame the given address is contained in. + * + * @param address Address we want to get the corresponding physical_frame for. + * @return Frame the given address is contained in. + */ + static auto containing_address(std::size_t address) -> physical_frame; + + /** + * @brief Evaluates the start address of the physical frame. + * + * @return start address of the physical frame. + */ + auto start_address() const -> uint64_t; + + /** + * @brief Defaulted equals operator. + */ + constexpr auto operator==(const physical_frame & other) const -> bool = default; + + /** + * @brief Defaulted three-way comparsion operator. + */ + constexpr auto operator<=>(const physical_frame & other) const -> std::partial_ordering = default; + + std::size_t + frame_number; ///< Index number of the current physical frame, used to distinguish it from other frames. + }; +} // namespace teachos::arch::memory::allocator + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP diff --git a/arch/x86_64/include/arch/memory/frame_allocator.hpp b/arch/x86_64/include/arch/memory/frame_allocator.hpp deleted file mode 100644 index f1096d1..0000000 --- a/arch/x86_64/include/arch/memory/frame_allocator.hpp +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP - -#include "multiboot/reader.hpp" - -#include -#include -#include - -namespace teachos::arch::memory -{ - constexpr std::size_t PAGE_FRAME_SIZE = 4096U; ///< Default page size of x86_84 is always 4KiB. - - /** - * @brief Specific physical_frame containing helper functions to determine if a specific address is in that - * physical_frame or not. - */ - struct physical_frame - { - /** - * @brief Constructor. - * - * @param frame_number Index number that should be assigned to this physical_frame. - */ - explicit physical_frame(std::size_t frame_number); - - /** - * @brief Returns the physical_frame the given address is contained in. - * - * @param address Address we want to get the corresponding physical_frame for. - * @return Frame the given address is contained in. - */ - static auto containing_address(std::size_t address) -> physical_frame; - - /** - * @brief Evaluates the start address of the physical frame. - * - * @return start address of the physical frame. - */ - auto start_address() const -> uint64_t; - - /** - * @brief Defaulted equals operator. - */ - constexpr auto operator==(const physical_frame & other) const -> bool = default; - - /** - * @brief Defaulted three-way comparsion operator. - */ - constexpr auto operator<=>(const physical_frame & other) const -> std::partial_ordering = default; - - std::size_t - frame_number; ///< Index number of the current physical frame, used to distinguish it from other frames. - }; - - template - concept FrameAllocator = requires(T t) { - { t.allocate_frame() } -> std::same_as>; - { t.deallocate_frame() } -> std::same_as; - }; - - /** - * @brief Allocates memory using memory areas read from the multiboot2 information pointer. - */ - struct area_frame_allocator - { - /** - * @brief Constructor - * - * @param mem_info Structure containg all relevant information to map and allocate memory - */ - area_frame_allocator(multiboot::memory_information mem_info); - - /** - * @brief Allocate memory by finding and returning a free physical_frame. - * - * The physical_frame allocation executes multiple checks before returning - * the physical_frame that is available to allocate. It must at least - * do the following: - * - check if the next_free_frame is within the current_area - * - check if the next_free_frame is actually free - * - update the next_free_frame after finding a free physical_frame - */ - auto allocate_frame() -> std::optional; - - /** - * @brief Deallocates a previously allocated physical_frame. - * - * @param physical_frame Previously allocated physical_frame that should be allocated. - */ - auto deallocate_frame(physical_frame physical_frame) -> void; - - /** - * @brief Returns the iterator pointing to the first element of the memory area. - * Allows using this class in the for each loop, because it follows the InputIterator template scheme. - * - * @return Iterator pointing to first element of the memory area. - */ - auto begin() -> multiboot::memory_area_iterator; - - /** - * @brief Returns the iterator pointing to one past the last element of the memory area. - * Allows using this class in the for each loop, because it follows the InputIterator template scheme. - * - * @return Iterator pointing to one past the last element of the memory area. - */ - auto end() -> multiboot::memory_area_iterator; - - private: - /** - * @brief Find the next memory area and write it into current_area. - */ - auto choose_next_area() -> void; - - physical_frame next_free_frame; ///< The physical_frame after the last allocated one. - std::optional current_area; ///< The current memory area. - multiboot::memory_area_iterator area_begin; ///< Pointer to the first element of all memory areas. - multiboot::memory_area_iterator area_end; ///< Pointer to one pas the last element of all memory areas. - physical_frame const kernel_start; ///< The start address of the kernel code in memory. - physical_frame const kernel_end; ///< The end address of the kernel code in memory. - physical_frame const multiboot_start; ///< The start address of the multiboot code in memory. - physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. - }; -} // namespace teachos::arch::memory - -#endif // TEACHOS_ARCH_X86_64_MEMORY_FRAME_HPP diff --git a/arch/x86_64/include/arch/memory/paging.hpp b/arch/x86_64/include/arch/memory/paging.hpp deleted file mode 100644 index 04c2065..0000000 --- a/arch/x86_64/include/arch/memory/paging.hpp +++ /dev/null @@ -1,220 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_HPP - -#include "arch/exception_handling/assert.hpp" - -#include "frame_allocator.hpp" -#include - -namespace teachos::arch::memory -{ - constexpr std::size_t PAGE_TABLE_ENTRY_COUNT = 512U; ///< Default entry count of a page table in x86_84 is 512. - - /** - * @brief Virtual page entry contained in P1 page tables - */ - struct virtual_page - { - std::size_t number; ///< Index number of the current virtual page, used to distinguish it from other pages. - - /** - * @brief Defaulted equals operator. - */ - constexpr auto operator==(const virtual_page & other) const -> bool = default; - - /** - * @brief Defaulted three-way comparsion operator. - */ - constexpr auto operator<=>(const virtual_page & other) const -> std::partial_ordering = default; - }; - - /** - * @brief Marks a specific entry in an actual page table. - */ - struct entry - { - /** - * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. - */ - enum bitset : uint64_t - { - PRESENT = 1UL << 0UL, ///< Page is in memory and therefore present. - ///< is assumed to be READONLY and only that flag is shown in the objdump. - WRITABLE = 1UL << 1UL, ///< It is possible to write to the page. - USER_ACCESIBLE = 1UL << 2UL, ///< Page can be accessed in user mode instead of only in kernel mode code. - WRITE_THROUGH_CACHING = 1UL << 3UL, ///< Write to the page go directly to memory instead of the cache. - DISABLED_CACHING = 1UL << 4UL, ///< Page uses caching. - ACCESSED = 1UL << 5UL, ///< Page is currently in use. - DIRTY = 1UL << 6UL, ///< Page has been writen too. - HUGE_PAGE = 1UL << 7UL, ///< Page is huge (2 MiB page size in P2 page table and 1 GiB in P3 page table, - ///< instead of 4 KiB). Has to be false for P1 and P4 page tables. - GLOBAL = 1UL << 8UL, ///< Page is not flushed from caches on address space switches (PGE bit of CR4 register - ///< has to be set) - EXECUTING_CODE_FORBIDDEN = - 1UL << 63UL, ///< Page is forbidden from executing code (NXE bit in the EFER register has to be set) - }; - - /** - * @brief Whether the current page is unused, meaning the underlying std::bitset is 0. - * - * @return Current page is in memory. - */ - auto is_unused() const -> bool; - - /** - * @brief Marks the page as unused, meaning the underlying std::bitset is set to 0. - */ - auto set_unused() -> void; - - /** - * @brief Calculates the physical frame this entry is pointing too, can be null if the page is not present in - * memory. - * - * @return Calculated physical frame entry is pointing too. - */ - auto calculate_pointed_to_frame() const -> std::optional; - - /** - * @brief Copies the address from the given physical frame into the underlying std::bitset so future calls to - * calculate_physical_address() will return the new address instead of the old one. - * - * @param frame Physical frame that contains the address we want to copy into our underlying std::bitset. - */ - auto set_address(physical_frame frame) -> void; - - /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all - * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits - * that are set are not relevant. - * - * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying std::bitset - */ - auto contains_flags(std::bitset<64U> other) const -> bool; - - private: - /** - * @brief Extracts the physical address from the underlying bitset read from bit index 12 - 51. Is a 52 bit page - * aligned physical address of the frame of the next page table or the pyhscial address of the frame for P1 page - * tables. - * - * @return Extracted physical address of the next page or of the frame for P1 page tables. - */ - auto calculate_physical_address() const -> std::size_t; - - std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be freely - ///< used for additional flags by the operating system. - }; - - enum level : uint8_t; - - /** - * @brief A Page table containing 512 entries. - */ - template - struct page_table - { - /** - * @brief Level of the page table, level 1 should not be able to call next_table anymore, because it would result in - * attempting to access memory that it should not. - */ - enum level : uint8_t - { - LEVEL1, - LEVEL2, - LEVEL3, - LEVEL4 - }; - - /** - * @brief Constructor. - */ - page_table() - : entries() - , p4(reinterpret_cast(0xfffffffffffff000)) - { - // Nothing to do - } - - /** - * @brief Set every entry of the page to unused - */ - auto zero_entries() -> void - { - constexpr size_t entry_amount = sizeof(entries) / sizeof(entries[0]); - for (size_t i = 0; i < entry_amount; ++i) - { - auto entry = entry.set_unused(); - } - } - - /** - * @brief Gets the complete next page table level from the given page table index. Meaning we use an index into a - * Level 4 page table to get the according Level 3 page table. - * - * @param table_index Index of this page table in the page table one level higher. - * @return Entire page table of the next level. - */ - auto next_table(std::size_t table_index) const -> std::optional - requires(page_table_level > 0) - { - auto address = next_table_address(table_index); - - if (address.has_value()) - { - return reinterpret_cast(*address); - } - - return std::nullopt; - } - - /** - * @brief Index operator overload to access specific mutable entry directy - * - * @param index Index of the entry we want to access and change - * @return Entry at the given table index - */ - auto operator[](std::size_t index) -> entry & - { - // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which - // could be incredibly hard to debug later. - arch::exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] index out of bounds"); - return entries[index]; - } - - /** - * @brief Index operator overload to access specific immutable entry directy - * - * @param index Index of the entry we want to access and only read - * @return Entry at the given table index - */ - auto operator[](std::size_t index) const -> entry const & { return this->operator[](index); } - - private: - /** - * @brief Calculates the address of the next page table level for the given table index. 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 - { - auto entry = this->operator[](table_index); - - if (entry.contains_flags(entry::PRESENT) && !entry.contains_flags(entry::HUGE_PAGE)) - { - std::size_t const table_address = reinterpret_cast(this); - return (table_address << 9) | (table_index << 12); - } - // TODO: Implement behaviour for huge pages currently not done - return std::nullopt; - } - - entry entries[PAGE_TABLE_ENTRY_COUNT]; - page_table const * p4; - }; -} // namespace teachos::arch::memory - -#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_HPP diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp new file mode 100644 index 0000000..a40e764 --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -0,0 +1,90 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_ENTRY_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_ENTRY_HPP + +#include "arch/memory/allocator/physical_frame.hpp" + +#include +#include + +namespace teachos::arch::memory::paging +{ + /** + * @brief Marks a specific entry in an actual page table. + */ + struct entry + { + /** + * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + */ + enum bitset : uint64_t + { + PRESENT = 1UL << 0UL, ///< Page is in memory and therefore present. + ///< is assumed to be READONLY and only that flag is shown in the objdump. + WRITABLE = 1UL << 1UL, ///< It is possible to write to the page. + USER_ACCESIBLE = 1UL << 2UL, ///< Page can be accessed in user mode instead of only in kernel mode code. + WRITE_THROUGH_CACHING = 1UL << 3UL, ///< Write to the page go directly to memory instead of the cache. + DISABLED_CACHING = 1UL << 4UL, ///< Page uses caching. + ACCESSED = 1UL << 5UL, ///< Page is currently in use. + DIRTY = 1UL << 6UL, ///< Page has been writen too. + HUGE_PAGE = 1UL << 7UL, ///< Page is huge (2 MiB page size in P2 page table and 1 GiB in P3 page table, + ///< instead of 4 KiB). Has to be false for P1 and P4 page tables. + GLOBAL = 1UL << 8UL, ///< Page is not flushed from caches on address space switches (PGE bit of CR4 register + ///< has to be set) + EXECUTING_CODE_FORBIDDEN = + 1UL << 63UL, ///< Page is forbidden from executing code (NXE bit in the EFER register has to be set) + }; + + /** + * @brief Whether the current page is unused, meaning the underlying std::bitset is 0. + * + * @return Current page is in memory. + */ + auto is_unused() const -> bool; + + /** + * @brief Marks the page as unused, meaning the underlying std::bitset is set to 0. + */ + auto set_unused() -> void; + + /** + * @brief Calculates the physical frame this entry is pointing too, can be null if the page is not present in + * memory. + * + * @return Calculated physical frame entry is pointing too. + */ + auto calculate_pointed_to_frame() const -> std::optional; + + /** + * @brief Copies the address from the given physical frame into the underlying std::bitset so future calls to + * calculate_physical_address() will return the new address instead of the old one. + * + * @param frame Physical frame that contains the address we want to copy into our underlying std::bitset. + */ + auto set_address(allocator::physical_frame frame) -> void; + + /** + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all + * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits + * that are set are not relevant. + * + * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. + * @return Whether the given flags are a subset or equivalent with the underlying std::bitset + */ + auto contains_flags(std::bitset<64U> other) const -> bool; + + private: + /** + * @brief Extracts the physical address from the underlying bitset read from bit index 12 - 51. Is a 52 bit page + * aligned physical address of the frame of the next page table or the pyhscial address of the frame for P1 page + * tables. + * + * @return Extracted physical address of the next page or of the frame for P1 page tables. + */ + auto calculate_physical_address() const -> std::size_t; + + std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be freely + ///< used for additional flags by the operating system. + }; +} // namespace teachos::arch::memory::paging + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_ENTRY_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp new file mode 100644 index 0000000..32e49e5 --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -0,0 +1,100 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP + +#include "page_entry.hpp" + +namespace teachos::arch::memory::paging +{ + namespace + { + constexpr std::size_t PAGE_TABLE_ENTRY_COUNT = 512U; ///< Default entry count of a page table in x86_84 is 512. + } + + /** + * @brief Actual data that is contained in every page table, this is the structure we cast a specific address too, + * because it consists of x amount os entries, which is a simple address. + */ + struct table_content + { + entry entries[PAGE_TABLE_ENTRY_COUNT]; ///< Entries containing addresses to page tables of a level below or actual + ///< virtual addresses for the level 1 page table. + }; + + /** + * @brief A Page table containing 512 entries. + */ + struct page_table + { + /** + * @brief Level of the page table, level 1 should not be able to call next_table anymore, because it would result in + * attempting to access memory that it should not. + */ + enum level : uint8_t + { + LEVEL1, + LEVEL2, + LEVEL3, + LEVEL4 + }; + + /** + * @brief Constructor. Automatically starts on the fixed address of the Level 4 page table. + */ + page_table(); + + /** + * @brief Set every entry of the page to unused. + */ + auto zero_entries() -> void; + + /** + * @brief Gets the complete next page table level from the given page table index. Meaning we use an index into a + * Level 4 page table to get the according Level 3 page table. When using this on an a level 1 page table it will + * cause an assertion. + * + * @param table_index Index of this page table in the page table one level higher. + */ + auto next_table(std::size_t table_index) -> void; + + /** + * @brief Index operator overload to access specific mutable entry directy. + * + * @param index Index of the entry we want to access and change. + * @return Entry at the given table index. + */ + auto operator[](std::size_t index) -> entry &; + + /** + * @brief Index operator overload to access specific immutable entry directy. + * + * @param index Index of the entry we want to access and only read. + * @return Entry at the given table index. + */ + auto operator[](std::size_t index) const -> entry const &; + + private: + /** + * @brief Constructor. Used internally to create new page tables. + * + * @param new_level New level of the page table. + * @param new_table New table data contained in the page table. + */ + page_table(level new_level, table_content * new_table); + + /** + * @brief Calculates the address of the next page table level for the given table index. 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; + + level current_level; ///< Current level of the page table, used to ensure next_table() is never called with a level + ///< 1 page table + table_content * current_table; ///< Current table we are accessing and indexing. + }; +} // namespace teachos::arch::memory::paging + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp new file mode 100644 index 0000000..12af510 --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -0,0 +1,27 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP + +#include + +namespace teachos::arch::memory::paging +{ + /** + * @brief Virtual page entry contained in P1 page tables + */ + struct virtual_page + { + std::size_t number; ///< Index number of the current virtual page, used to distinguish it from other pages. + + /** + * @brief Defaulted equals operator. + */ + constexpr auto operator==(const virtual_page & other) const -> bool = default; + + /** + * @brief Defaulted three-way comparsion operator. + */ + constexpr auto operator<=>(const virtual_page & other) const -> std::partial_ordering = default; + }; +} // namespace teachos::arch::memory::paging + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP \ No newline at end of file diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index c0d4aed..09fc2a2 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,7 +1,7 @@ #include "arch/kernel/main.hpp" #include "arch/exception_handling/assert.hpp" -#include "arch/memory/frame_allocator.hpp" +#include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/multiboot/reader.hpp" #include "arch/video/vga/text.hpp" @@ -18,7 +18,7 @@ namespace teachos::arch::kernel text::write("TeachOS is starting up...", text::common_attributes::green_on_black); auto memory_information = memory::multiboot::read_multiboot2(); - auto allocator = memory::area_frame_allocator(memory_information); + memory::allocator::area_frame_allocator allocator(memory_information); auto last_allocated = allocator.allocate_frame(); auto allocated = last_allocated; diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp new file mode 100644 index 0000000..9c344d8 --- /dev/null +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -0,0 +1,97 @@ +#include "arch/memory/allocator/area_frame_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" + +namespace teachos::arch::memory::allocator +{ + area_frame_allocator::area_frame_allocator(multiboot::memory_information mem_info) + : next_free_frame(0) + , current_area(std::nullopt) + , area_begin(mem_info.memory_areas) + , area_end(mem_info.memory_areas + mem_info.area_count) + , 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; + + for (multiboot::memory_area_iterator it = begin(); it != end(); ++it) + { + multiboot::memory_area & area = *it; + + std::size_t address = area.base_address + area.area_length - 1; + if (physical_frame::containing_address(address) >= next_free_frame) + { + // The `next_free_frame` address is smaller than the last address of the current area + if (!current_area || area.base_address < current_area->base_address) + { + current_area = area; + } + } + } + + if (current_area) + { + // Update the `next_free_frame` according to the new memory area + physical_frame start_frame = physical_frame::containing_address(current_area->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) + { + physical_frame physical_frame{next_free_frame.frame_number}; + + struct physical_frame current_area_last_frame = { + physical_frame::containing_address(current_area->base_address + current_area->area_length - 1)}; + + if (next_free_frame > current_area_last_frame) + { + // All frames of current area are used, switch to next area + choose_next_area(); + } + else if (physical_frame >= multiboot_start && physical_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 + { + // Frame is unused, increment `next_free_frame` and return it + next_free_frame.frame_number += 1; + return physical_frame; + } + + // `physical_frame` was not valid, try it again with the updated `next_free_frame` + return allocate_frame(); + } + + // no free frames left + return std::nullopt; + } + + auto area_frame_allocator::deallocate_frame(physical_frame physical_frame) -> void + { + arch::exception_handling::assert(false && physical_frame.frame_number == 0, + "[deallocate_frame] Not implemented Exception"); + } + + auto area_frame_allocator::begin() -> multiboot::memory_area_iterator { return area_begin; } + + auto area_frame_allocator::end() -> multiboot::memory_area_iterator { return area_end; } +} // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/allocator/physical_frame.cpp b/arch/x86_64/src/memory/allocator/physical_frame.cpp new file mode 100644 index 0000000..03ec193 --- /dev/null +++ b/arch/x86_64/src/memory/allocator/physical_frame.cpp @@ -0,0 +1,22 @@ +#include "arch/memory/allocator/physical_frame.hpp" + +namespace teachos::arch::memory::allocator +{ + namespace + { + constexpr std::size_t PAGE_FRAME_SIZE = 4096U; ///< Default page size of x86_84 is always 4KiB. + } + + physical_frame::physical_frame(std::size_t frame_number) + : frame_number(frame_number) + { + // Nothing to do + } + + auto physical_frame::containing_address(std::size_t address) -> physical_frame + { + return physical_frame{address / PAGE_FRAME_SIZE}; + } + + auto physical_frame::start_address() const -> uint64_t { return frame_number * PAGE_FRAME_SIZE; } +} // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/frame_allocator.cpp b/arch/x86_64/src/memory/frame_allocator.cpp deleted file mode 100644 index 7776082..0000000 --- a/arch/x86_64/src/memory/frame_allocator.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "arch/memory/frame_allocator.hpp" - -#include "arch/exception_handling/assert.hpp" - -namespace teachos::arch::memory -{ - physical_frame::physical_frame(std::size_t frame_number) - : frame_number(frame_number) - { - // Nothing to do - } - - auto physical_frame::containing_address(std::size_t address) -> physical_frame - { - return physical_frame{address / PAGE_FRAME_SIZE}; - } - - auto physical_frame::start_address() const -> uint64_t { return frame_number * PAGE_FRAME_SIZE; } - - area_frame_allocator::area_frame_allocator(multiboot::memory_information mem_info) - : next_free_frame(0) - , current_area(std::nullopt) - , area_begin(mem_info.memory_areas) - , area_end(mem_info.memory_areas + mem_info.area_count) - , 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; - - for (multiboot::memory_area_iterator it = begin(); it != end(); ++it) - { - multiboot::memory_area & area = *it; - - std::size_t address = area.base_address + area.area_length - 1; - if (physical_frame::containing_address(address) >= next_free_frame) - { - // The `next_free_frame` address is smaller than the last address of the current area - if (!current_area || area.base_address < current_area->base_address) - { - current_area = area; - } - } - } - - if (current_area) - { - // Update the `next_free_frame` according to the new memory area - physical_frame start_frame = physical_frame::containing_address(current_area->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) - { - physical_frame physical_frame{next_free_frame.frame_number}; - - struct physical_frame current_area_last_frame = { - physical_frame::containing_address(current_area->base_address + current_area->area_length - 1)}; - - if (next_free_frame > current_area_last_frame) - { - // All frames of current area are used, switch to next area - choose_next_area(); - } - else if (physical_frame >= multiboot_start && physical_frame <= kernel_end) - { - // `physical_frame` is used by the kernel or multiboot information structure - next_free_frame = arch::memory::physical_frame{kernel_end.frame_number + 1}; - } - else - { - // Frame is unused, increment `next_free_frame` and return it - next_free_frame.frame_number += 1; - return physical_frame; - } - - // `physical_frame` was not valid, try it again with the updated `next_free_frame` - return allocate_frame(); - } - - // no free frames left - return std::nullopt; - } - - auto area_frame_allocator::deallocate_frame(physical_frame physical_frame) -> void - { - arch::exception_handling::assert(false && physical_frame.frame_number == 0, - "[deallocate_frame] Not implemented Exception"); - } - - auto area_frame_allocator::begin() -> multiboot::memory_area_iterator { return area_begin; } - - auto area_frame_allocator::end() -> multiboot::memory_area_iterator { return area_end; } -} // namespace teachos::arch::memory diff --git a/arch/x86_64/src/memory/paging.cpp b/arch/x86_64/src/memory/paging.cpp deleted file mode 100644 index 9774132..0000000 --- a/arch/x86_64/src/memory/paging.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "arch/memory/paging.hpp" - -#include "arch/exception_handling/assert.hpp" - -namespace teachos::arch::memory -{ - auto entry::is_unused() const -> bool { return flags == 0U; } - - auto entry::set_unused() -> void { flags = 0U; } - - auto entry::calculate_pointed_to_frame() const -> std::optional - { - if (contains_flags(PRESENT)) - { - auto physical_address = calculate_physical_address(); - return physical_frame::containing_address(physical_address); - } - return std::nullopt; - } - - auto entry::calculate_physical_address() const -> std::size_t - { - constexpr std::size_t start_bit = 12U; - constexpr std::size_t end_bit = 52U; - size_t value = 0U; - - for (auto i = start_bit; i < end_bit; i++) - { - value |= (flags[i] ? (1 << (i - start_bit)) : 0); - } - return value; - } - - auto entry::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } - - auto entry::set_address(physical_frame frame) -> void - { - arch::exception_handling::assert((frame.start_address() & ~0x000fffff'fffff000) == 0, - "Start address is not aligned with Page"); - flags = std::bitset<64U>(frame.start_address()) | flags; - } -} // namespace teachos::arch::memory diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp new file mode 100644 index 0000000..43c0b71 --- /dev/null +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -0,0 +1,42 @@ +#include "arch/memory/paging/page_entry.hpp" + +#include "arch/exception_handling/assert.hpp" + +namespace teachos::arch::memory::paging +{ + auto entry::is_unused() const -> bool { return flags == 0U; } + + auto entry::set_unused() -> void { flags = 0U; } + + auto entry::calculate_pointed_to_frame() const -> std::optional + { + if (contains_flags(PRESENT)) + { + auto physical_address = calculate_physical_address(); + return allocator::physical_frame::containing_address(physical_address); + } + return std::nullopt; + } + + auto entry::calculate_physical_address() const -> std::size_t + { + constexpr std::size_t start_bit = 12U; + constexpr std::size_t end_bit = 52U; + size_t value = 0U; + + for (auto i = start_bit; i < end_bit; i++) + { + value |= (flags[i] ? (1 << (i - start_bit)) : 0); + } + return value; + } + + auto entry::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } + + auto entry::set_address(allocator::physical_frame frame) -> void + { + arch::exception_handling::assert((frame.start_address() & ~0x000fffff'fffff000) == 0, + "Start address is not aligned with Page"); + flags = std::bitset<64U>(frame.start_address()) | flags; + } +} // 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 new file mode 100644 index 0000000..a1cbc72 --- /dev/null +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -0,0 +1,65 @@ +#include "arch/memory/paging/page_table.hpp" + +#include "arch/exception_handling/assert.hpp" + +namespace teachos::arch::memory::paging +{ + page_table::page_table() + : current_level(LEVEL4) + , current_table(reinterpret_cast(0xfffffffffffff000)) + { + // Nothing to do + } + + auto page_table::zero_entries() -> void + { + constexpr size_t entry_amount = sizeof(current_table->entries) / sizeof(current_table->entries[0]); + for (size_t i = 0; i < entry_amount; ++i) + { + auto entry = this->operator[](i); + entry.set_unused(); + } + } + + auto page_table::next_table(std::size_t table_index) -> void + { + arch::exception_handling::assert(current_level != LEVEL1, + "[Page Table] Attempted to call next_table on level 1 page table"); + auto address = next_table_address(table_index); + + if (address.has_value()) + { + current_table = reinterpret_cast(*address); + current_level = static_cast(current_level - 1U); + } + } + + auto page_table::operator[](std::size_t index) -> entry & + { + // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which + // could be incredibly hard to debug later. + arch::exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] index out of bounds"); + return current_table->entries[index]; + } + + auto page_table::operator[](std::size_t index) const -> entry const & + { + // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which + // could be incredibly hard to debug later. + arch::exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] index out of bounds"); + return current_table->entries[index]; + } + + auto page_table::next_table_address(std::size_t table_index) const -> std::optional + { + auto entry = this->operator[](table_index); + + if (entry.contains_flags(entry::PRESENT) && !entry.contains_flags(entry::HUGE_PAGE)) + { + std::size_t const table_address = reinterpret_cast(this); + return (table_address << 9) | (table_index << 12); + } + // TODO: Implement behaviour for huge pages currently not done + return std::nullopt; + } +} // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 779154223c6d220bbfe56b5b14e5fafcccb55781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 19 Oct 2024 14:48:25 +0000 Subject: Fix printing of wrong allocated frame --- arch/x86_64/src/kernel/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 09fc2a2..40dd117 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -28,6 +28,7 @@ namespace teachos::arch::kernel allocated = allocator.allocate_frame(); } while (allocated.has_value()); video::vga::text::write("Allocated Frames", video::vga::text::common_attributes::green_on_black); - video::vga::text::write_number(allocated.value().frame_number, video::vga::text::common_attributes::green_on_black); + video::vga::text::write_number(last_allocated.value().frame_number, + video::vga::text::common_attributes::green_on_black); } } // namespace teachos::arch::kernel -- cgit v1.2.3 From 7ca089125b8c5e55dd584648cd33612883cc004d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 20 Oct 2024 06:26:58 +0000 Subject: Fix typo in file name --- .../arch/memory/multiboot/elf_sybols_section.hpp | 157 --------------------- .../arch/memory/multiboot/elf_symbols_section.hpp | 157 +++++++++++++++++++++ .../include/arch/memory/multiboot/reader.hpp | 2 +- .../include/arch/memory/paging/page_table.hpp | 6 +- .../src/memory/multiboot/elf_symbols_section.cpp | 2 +- 5 files changed, 162 insertions(+), 162 deletions(-) delete mode 100644 arch/x86_64/include/arch/memory/multiboot/elf_sybols_section.hpp create mode 100644 arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp diff --git a/arch/x86_64/include/arch/memory/multiboot/elf_sybols_section.hpp b/arch/x86_64/include/arch/memory/multiboot/elf_sybols_section.hpp deleted file mode 100644 index 88d211e..0000000 --- a/arch/x86_64/include/arch/memory/multiboot/elf_sybols_section.hpp +++ /dev/null @@ -1,157 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP - -#include "info.hpp" -#include -#include - -namespace teachos::arch::memory::multiboot -{ - /** - * @brief Defines all elf section types an elf section header can have. See - * https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. - */ - enum class elf_section_type : uint32_t - { - INACTIVE, ///< (SHT_NULL) Unused, meaning all values are zeroed out - PROGRAMM, ///< (SHT_PROGBITS) Program data (DATA, CODE) - SYMBOL_TABLE, ///< (SHT_SYMBTAB) Contains actual entries pointed to in symbol hash table - STRING_TABLE, ///< (SHT_STRTAB) Contains symbols, section and deubbging null-terminated strings - RELOCATION_ENTRY_WITH_ADDENDS, ///< (SHT_RELA) Only used on 64 bit systems - SYMBOL_HASH_TABLE, ///< (SHT_HASH) Hash table used by dynamic linker to locate symbols - DYNAMIC, ///< (SHT_DYNAMIC) Contains dynamic linking information - NOTE, ///< (SHT_NOTE) Stores information that marks files in some way - EMPTY, ///< (SHT_NOBITS) Program data section, that occupies no space in the file (.bss) - RELOCATION_ENTRY_WITHOUT_ADDENDS, ///< (SHT_REL) Only used on 32 bit systems - UNSPECIFIED, ///< (SHT_SHLIB) Reserved but has unspecified semantics - DYNAMIC_SYMBOL_TABLE, ///< (SHT_DYNSYM) Holds minimal set of symbols adequate for dynamic linking - INITALIZATION_FUNCTION_ARRAY = 14, ///< (SHT_INIT_ARRAY) Array of pointers to intialization functions () -> void - TERMINATION_FUNCTION_ARRAY, ///< (SHT_FINI_ARRAY) Array of pointers to termination functions () -> void - PRE_INITALIZATION_FUNCTION_ARRAY ///< (SHT_PRE_INIT_ARRAY) Array of pointers to functions invoked before other - ///< initalization functions () -> void - }; - - /** - * @brief Defines helper function for all states that the elf section flags of an elf section header can - * have. See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html - * See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. - */ - struct elf_section_flags - { - /** - * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. - */ - enum bitset : uint32_t - { - WRITABLE = 1U << 0U, ///< (SHF_WRITE) Section is writable at runtime. If it isn't then the section - ///< is assumed to be READONLY and only that flag is shown in the objdump. - OCCUPIES_MEMORY = 1U << 1U, ///< (SHF_ALLOC) Section occupies memory during execution. - ///< ALLOC flag is shown in the objdump. - EXECUTABLE_CODE = 1U << 2U, ///< (SHF_EXECINSTR) Section is executable. CODE flag is shown in the object dump. - DUPLICATE_DATA = 1U << 4U, ///< (SHF_MERGE) Section might be merged with another section. - CONTAINS_STRING = 1U << 5U, ///< (SHF_STRINGS) Section contains null-terminated strings. - SECTION_HEADER_INFO_IS_SECTION_HEADER_TABLE_INDEX = - 1U << 6U, ///< (SHF_INFO_LINK) Section contains the section header table index in the (sh_info) - ///< additional_information variable. - PRESERVE_ORDERING_AFTER_COMBINATION = - 1U << 7U, ///< (SHF_LINK_ORDER) Section preserves order after combining with another section. - REQUIRES_SPECIAL_OS_PROCESSING = - 1U << 8U, ///< (SHF_OS_NONCONFORMING) Section requires non-standard OS specific handling of its code or - ///< data, which does not confirm to standard ELF specifications. - SECTION_GROUP_MEMBER = 1U << 9U, ///< (SHF_GROUP) Section is a member of a section group. - HOLDS_THREAD_LOCAL_DATA = 1U << 10U, ///< (SHF_TLS) Section holds thread-local data. - COMPRESSED = 1U << 11U, ///< (SHF_COMPRESSED) Section contains compressed data. - SPECIAL_ORDERING_REQUIREMENTS = - 1U << 30U, ///< (SHF_ORDERED) Section has special ordering requirements, meaning it - ///< should be ordered in relation to other sections of the same type - EXCLUDED_UNLESS_REFERENCED_OR_ALLOCATED = 1U << 31U, ///< (SHF_EXCLUDE)Section is excluded unless referenced or - ///< allocated, used for LTO (Link-Time Optimizations) - }; - - /** - * @brief Constructor. - * - * @param flags Actual value read from the elf section header, which should be converted into a std::bitset, to - * allow reading the state of single bits more easily. - */ - explicit elf_section_flags(uint64_t flags) - : flags(flags) - { - // Nothing to do - } - - /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all - * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits - * that are set are not relevant. - * - * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying std::bitset - */ - auto contains_flags(std::bitset<64U> other) const -> bool; - - /** - * @brief Allows to compare the underlying std::bitset of two instances - * - * @param other Other instance that we want to compare with - * @return Whether the underlying std::bitset of both types is the same - */ - auto operator==(elf_section_flags const & other) const -> bool = default; - - private: - std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 21 - 28 are reserved for operating - ///< system specific semantics and bits 29 - 32 are reserved for processor specific - ///< semantics. Bits 33 - 64 are unused for compatability with ELF32. - }; - - /** - * @brief Defines the data included in a section header, where each section has exactly one section header. - * See https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html for more information - */ - struct elf_section_header - { - uint32_t name_table_index; ///< Index into the section header string table, specifies the name of the section - elf_section_type type; ///< Categorizes the sections content and semantics - elf_section_flags flags; ///< 1-bit flgas that describe section attributes - uint64_t virtual_address; ///< If section appears in memory image of a process, gives address at which the sections - ///< first byte should reside, otherwise 0 - uint64_t file_offset; ///< Offset from the beginning of the file to the first byte in the section. SHT_NOBITS - ///< contains the conceptual placement instead (because it occupies no space in the file) - uint64_t section_size; ///< Complete section size in bytes, SHT_NOBITS may have non-zero value but will always - ///< occupy no space in the file - uint32_t other_section; ///< Section header table index link, behaviour varies on type - ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link - uint32_t additional_information; ///< Extra information, behaviour varies on type - ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link - uint64_t address_alignment; ///< Possible address alignment constraints. Value of virutal_address must be 0 % value - ///< of address_alignment. Value 0 or 1 mean no alignment constraints - uint64_t fixed_table_entry_size; ///< If sections holds table with fixed-sized entries, this gives the size in - ///< bytes of each entry - - /** - * @brief Detect whether a section header is inactive or not, should always be the case for the first entry in the - * sections table - * @return Whether the current section header is actually null or not, requires all fields besides section_size and - * other_section to contain 0 - */ - auto is_null() const -> bool; - }; - - /** - * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type - * multi_boot_tag_type::ELF_SECTIONS. - * The first section in the sections array will always be INACTIVE, there can only ever be one DYNAMIC section and - * only either one DYNAMIC_SYMBOL_TABLE or SYMBOL_TABLE. - */ - struct elf_symbols_section_header - { - tag info; ///< Basic multi_boot_tag information - uint32_t number_of_sections; ///< Number of sections in the sections array - uint32_t entry_size; ///< Size of each entry in the sections array - uint32_t section_index; ///< Index to the string table used for symbol names - std::byte end; ///< Marks the end of the tag, used to mark the beginning of any additional data - ///< contained in the section, to ensure byte alignment is actually 4 byte - }; -} // namespace teachos::arch::memory::multiboot - -#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp new file mode 100644 index 0000000..88d211e --- /dev/null +++ b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp @@ -0,0 +1,157 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP + +#include "info.hpp" +#include +#include + +namespace teachos::arch::memory::multiboot +{ + /** + * @brief Defines all elf section types an elf section header can have. See + * https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. + */ + enum class elf_section_type : uint32_t + { + INACTIVE, ///< (SHT_NULL) Unused, meaning all values are zeroed out + PROGRAMM, ///< (SHT_PROGBITS) Program data (DATA, CODE) + SYMBOL_TABLE, ///< (SHT_SYMBTAB) Contains actual entries pointed to in symbol hash table + STRING_TABLE, ///< (SHT_STRTAB) Contains symbols, section and deubbging null-terminated strings + RELOCATION_ENTRY_WITH_ADDENDS, ///< (SHT_RELA) Only used on 64 bit systems + SYMBOL_HASH_TABLE, ///< (SHT_HASH) Hash table used by dynamic linker to locate symbols + DYNAMIC, ///< (SHT_DYNAMIC) Contains dynamic linking information + NOTE, ///< (SHT_NOTE) Stores information that marks files in some way + EMPTY, ///< (SHT_NOBITS) Program data section, that occupies no space in the file (.bss) + RELOCATION_ENTRY_WITHOUT_ADDENDS, ///< (SHT_REL) Only used on 32 bit systems + UNSPECIFIED, ///< (SHT_SHLIB) Reserved but has unspecified semantics + DYNAMIC_SYMBOL_TABLE, ///< (SHT_DYNSYM) Holds minimal set of symbols adequate for dynamic linking + INITALIZATION_FUNCTION_ARRAY = 14, ///< (SHT_INIT_ARRAY) Array of pointers to intialization functions () -> void + TERMINATION_FUNCTION_ARRAY, ///< (SHT_FINI_ARRAY) Array of pointers to termination functions () -> void + PRE_INITALIZATION_FUNCTION_ARRAY ///< (SHT_PRE_INIT_ARRAY) Array of pointers to functions invoked before other + ///< initalization functions () -> void + }; + + /** + * @brief Defines helper function for all states that the elf section flags of an elf section header can + * have. See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html + * See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. + */ + struct elf_section_flags + { + /** + * @brief Possible set bits in our underlying std::bitset and the meaning when they are set. + */ + enum bitset : uint32_t + { + WRITABLE = 1U << 0U, ///< (SHF_WRITE) Section is writable at runtime. If it isn't then the section + ///< is assumed to be READONLY and only that flag is shown in the objdump. + OCCUPIES_MEMORY = 1U << 1U, ///< (SHF_ALLOC) Section occupies memory during execution. + ///< ALLOC flag is shown in the objdump. + EXECUTABLE_CODE = 1U << 2U, ///< (SHF_EXECINSTR) Section is executable. CODE flag is shown in the object dump. + DUPLICATE_DATA = 1U << 4U, ///< (SHF_MERGE) Section might be merged with another section. + CONTAINS_STRING = 1U << 5U, ///< (SHF_STRINGS) Section contains null-terminated strings. + SECTION_HEADER_INFO_IS_SECTION_HEADER_TABLE_INDEX = + 1U << 6U, ///< (SHF_INFO_LINK) Section contains the section header table index in the (sh_info) + ///< additional_information variable. + PRESERVE_ORDERING_AFTER_COMBINATION = + 1U << 7U, ///< (SHF_LINK_ORDER) Section preserves order after combining with another section. + REQUIRES_SPECIAL_OS_PROCESSING = + 1U << 8U, ///< (SHF_OS_NONCONFORMING) Section requires non-standard OS specific handling of its code or + ///< data, which does not confirm to standard ELF specifications. + SECTION_GROUP_MEMBER = 1U << 9U, ///< (SHF_GROUP) Section is a member of a section group. + HOLDS_THREAD_LOCAL_DATA = 1U << 10U, ///< (SHF_TLS) Section holds thread-local data. + COMPRESSED = 1U << 11U, ///< (SHF_COMPRESSED) Section contains compressed data. + SPECIAL_ORDERING_REQUIREMENTS = + 1U << 30U, ///< (SHF_ORDERED) Section has special ordering requirements, meaning it + ///< should be ordered in relation to other sections of the same type + EXCLUDED_UNLESS_REFERENCED_OR_ALLOCATED = 1U << 31U, ///< (SHF_EXCLUDE)Section is excluded unless referenced or + ///< allocated, used for LTO (Link-Time Optimizations) + }; + + /** + * @brief Constructor. + * + * @param flags Actual value read from the elf section header, which should be converted into a std::bitset, to + * allow reading the state of single bits more easily. + */ + explicit elf_section_flags(uint64_t flags) + : flags(flags) + { + // Nothing to do + } + + /** + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all + * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits + * that are set are not relevant. + * + * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. + * @return Whether the given flags are a subset or equivalent with the underlying std::bitset + */ + auto contains_flags(std::bitset<64U> other) const -> bool; + + /** + * @brief Allows to compare the underlying std::bitset of two instances + * + * @param other Other instance that we want to compare with + * @return Whether the underlying std::bitset of both types is the same + */ + auto operator==(elf_section_flags const & other) const -> bool = default; + + private: + std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 21 - 28 are reserved for operating + ///< system specific semantics and bits 29 - 32 are reserved for processor specific + ///< semantics. Bits 33 - 64 are unused for compatability with ELF32. + }; + + /** + * @brief Defines the data included in a section header, where each section has exactly one section header. + * See https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html for more information + */ + struct elf_section_header + { + uint32_t name_table_index; ///< Index into the section header string table, specifies the name of the section + elf_section_type type; ///< Categorizes the sections content and semantics + elf_section_flags flags; ///< 1-bit flgas that describe section attributes + uint64_t virtual_address; ///< If section appears in memory image of a process, gives address at which the sections + ///< first byte should reside, otherwise 0 + uint64_t file_offset; ///< Offset from the beginning of the file to the first byte in the section. SHT_NOBITS + ///< contains the conceptual placement instead (because it occupies no space in the file) + uint64_t section_size; ///< Complete section size in bytes, SHT_NOBITS may have non-zero value but will always + ///< occupy no space in the file + uint32_t other_section; ///< Section header table index link, behaviour varies on type + ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link + uint32_t additional_information; ///< Extra information, behaviour varies on type + ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link + uint64_t address_alignment; ///< Possible address alignment constraints. Value of virutal_address must be 0 % value + ///< of address_alignment. Value 0 or 1 mean no alignment constraints + uint64_t fixed_table_entry_size; ///< If sections holds table with fixed-sized entries, this gives the size in + ///< bytes of each entry + + /** + * @brief Detect whether a section header is inactive or not, should always be the case for the first entry in the + * sections table + * @return Whether the current section header is actually null or not, requires all fields besides section_size and + * other_section to contain 0 + */ + auto is_null() const -> bool; + }; + + /** + * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type + * multi_boot_tag_type::ELF_SECTIONS. + * The first section in the sections array will always be INACTIVE, there can only ever be one DYNAMIC section and + * only either one DYNAMIC_SYMBOL_TABLE or SYMBOL_TABLE. + */ + struct elf_symbols_section_header + { + tag info; ///< Basic multi_boot_tag information + uint32_t number_of_sections; ///< Number of sections in the sections array + uint32_t entry_size; ///< Size of each entry in the sections array + uint32_t section_index; ///< Index to the string table used for symbol names + std::byte end; ///< Marks the end of the tag, used to mark the beginning of any additional data + ///< contained in the section, to ensure byte alignment is actually 4 byte + }; +} // namespace teachos::arch::memory::multiboot + +#endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/reader.hpp b/arch/x86_64/include/arch/memory/multiboot/reader.hpp index 14086a7..2f72980 100644 --- a/arch/x86_64/include/arch/memory/multiboot/reader.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/reader.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP #define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP -#include "elf_sybols_section.hpp" +#include "elf_symbols_section.hpp" #include "memory_map.hpp" #include diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 32e49e5..da63d8c 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -48,9 +48,9 @@ namespace teachos::arch::memory::paging auto zero_entries() -> void; /** - * @brief Gets the complete next page table level from the given page table index. Meaning we use an index into a - * Level 4 page table to get the according Level 3 page table. When using this on an a level 1 page table it will - * cause an assertion. + * @brief Turn this page table into the next page table level from the given page table index. Meaning we + * use an index into a Level 4 page table to get the according Level 3 page table. When using this on an a level 1 + * page table it will cause an assertion. * * @param table_index Index of this page table in the page table one level higher. */ diff --git a/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp b/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp index 78ab952..953a57d 100644 --- a/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp +++ b/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp @@ -1,4 +1,4 @@ -#include "arch/memory/multiboot/elf_sybols_section.hpp" +#include "arch/memory/multiboot/elf_symbols_section.hpp" namespace teachos::arch::memory::multiboot { -- cgit v1.2.3 From 7ebfe9e09efa84044d1470132b7f55ebf53a7f89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 20 Oct 2024 06:32:02 +0000 Subject: Fix next_table_address --- arch/x86_64/include/arch/memory/paging/page_table.hpp | 2 +- arch/x86_64/src/memory/paging/page_table.cpp | 14 +++----------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index da63d8c..73b75ad 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -89,7 +89,7 @@ namespace teachos::arch::memory::paging * @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; + auto next_table_address(std::size_t table_index) -> std::optional; level current_level; ///< Current level of the page table, used to ensure next_table() is never called with a level ///< 1 page table diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index a1cbc72..786ff69 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -29,7 +29,7 @@ namespace teachos::arch::memory::paging if (address.has_value()) { - current_table = reinterpret_cast(*address); + current_table = reinterpret_cast(address.value()); current_level = static_cast(current_level - 1U); } } @@ -42,21 +42,13 @@ namespace teachos::arch::memory::paging return current_table->entries[index]; } - auto page_table::operator[](std::size_t index) const -> entry const & - { - // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which - // could be incredibly hard to debug later. - arch::exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] index out of bounds"); - return current_table->entries[index]; - } - - auto page_table::next_table_address(std::size_t table_index) const -> std::optional + auto page_table::next_table_address(std::size_t table_index) -> std::optional { auto entry = this->operator[](table_index); if (entry.contains_flags(entry::PRESENT) && !entry.contains_flags(entry::HUGE_PAGE)) { - std::size_t const table_address = reinterpret_cast(this); + std::size_t const table_address = reinterpret_cast(current_table); return (table_address << 9) | (table_index << 12); } // TODO: Implement behaviour for huge pages currently not done -- cgit v1.2.3 From d728052d62470799f73f6d9a2b8baa2b0b357383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 20 Oct 2024 07:01:53 +0000 Subject: Add helper methods to phyisca frame --- arch/x86_64/CMakeLists.txt | 1 + .../arch/memory/allocator/physical_frame.hpp | 12 ++++++----- .../include/arch/memory/paging/virtual_page.hpp | 25 +++++++++++++++++++++- .../src/memory/allocator/area_frame_allocator.cpp | 4 ++-- .../x86_64/src/memory/allocator/physical_frame.cpp | 5 ----- arch/x86_64/src/memory/multiboot/reader.cpp | 15 ++++++------- arch/x86_64/src/memory/paging/page_entry.cpp | 4 ++-- arch/x86_64/src/memory/paging/page_table.cpp | 6 +++--- arch/x86_64/src/memory/paging/virtual_page.cpp | 22 +++++++++++++++++++ 9 files changed, 68 insertions(+), 26 deletions(-) create mode 100644 arch/x86_64/src/memory/paging/virtual_page.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 016215b..fe83548 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -48,6 +48,7 @@ target_sources("_memory" PRIVATE "src/memory/allocator/physical_frame.cpp" "src/memory/paging/page_entry.cpp" "src/memory/paging/page_table.cpp" + "src/memory/paging/virtual_page.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp index 5e99d10..e013e0d 100644 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -6,6 +6,8 @@ namespace teachos::arch::memory::allocator { + constexpr std::size_t PAGE_FRAME_SIZE = 4096U; ///< Default page size of x86_84 is always 4KiB. + /** * @brief Specific physical frame containing helper functions to determine if a specific address is in that * physical frame or not. @@ -15,22 +17,22 @@ namespace teachos::arch::memory::allocator /** * @brief Constructor. * - * @param frame_number Index number that should be assigned to this physical_frame. + * @param frame_number Index number that should be assigned to this physical frame. */ explicit physical_frame(std::size_t frame_number); /** - * @brief Returns the physical_frame the given address is contained in. + * @brief Returns the physical frame the given address is contained in. * - * @param address Address we want to get the corresponding physical_frame for. + * @param physical_address Physical address we want to get the corresponding physical frame for. * @return Frame the given address is contained in. */ - static auto containing_address(std::size_t address) -> physical_frame; + static auto containing_address(std::size_t physical_address) -> physical_frame; /** * @brief Evaluates the start address of the physical frame. * - * @return start address of the physical frame. + * @return Start address of the physical frame. */ auto start_address() const -> uint64_t; diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index 12af510..7871e4b 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -2,6 +2,7 @@ #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP #include +#include namespace teachos::arch::memory::paging { @@ -10,7 +11,27 @@ namespace teachos::arch::memory::paging */ struct virtual_page { - std::size_t number; ///< Index number of the current virtual page, used to distinguish it from other pages. + /** + * @brief Constructor. + * + * @param page_number Index number of the current virtual page, used to distinguish it from other pages. + */ + explicit virtual_page(std::size_t page_number); + + /** + * @brief Returns the virtual page the given address is contained in. + * + * @param virtual_address Virtual address we want to get the corresponding virtual page for. + * @return Frame the given address is contained in. + */ + static auto containing_address(std::size_t virtual_address) -> virtual_page; + + /** + * @brief Evaluates the start address of the virtual page. + * + * @return Start address of the virtual page. + */ + auto start_address() const -> uint64_t; /** * @brief Defaulted equals operator. @@ -21,6 +42,8 @@ namespace teachos::arch::memory::paging * @brief Defaulted three-way comparsion operator. */ constexpr auto operator<=>(const virtual_page & other) const -> std::partial_ordering = default; + + std::size_t page_number; ///< Index number of the current virtual page, used to distinguish it from other pages. }; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index 9c344d8..c2cafce 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -87,8 +87,8 @@ namespace teachos::arch::memory::allocator auto area_frame_allocator::deallocate_frame(physical_frame physical_frame) -> void { - arch::exception_handling::assert(false && physical_frame.frame_number == 0, - "[deallocate_frame] Not implemented Exception"); + exception_handling::assert(false && physical_frame.frame_number == 0, + "[deallocate_frame] Not implemented Exception"); } auto area_frame_allocator::begin() -> multiboot::memory_area_iterator { return area_begin; } diff --git a/arch/x86_64/src/memory/allocator/physical_frame.cpp b/arch/x86_64/src/memory/allocator/physical_frame.cpp index 03ec193..03bd965 100644 --- a/arch/x86_64/src/memory/allocator/physical_frame.cpp +++ b/arch/x86_64/src/memory/allocator/physical_frame.cpp @@ -2,11 +2,6 @@ namespace teachos::arch::memory::allocator { - namespace - { - constexpr std::size_t PAGE_FRAME_SIZE = 4096U; ///< Default page size of x86_84 is always 4KiB. - } - physical_frame::physical_frame(std::size_t frame_number) : frame_number(frame_number) { diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp index 8741b44..156b437 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -19,7 +19,7 @@ namespace teachos::arch::memory::multiboot { auto expected_entry_size = mminfo->entry_size; constexpr auto actual_entry_size = sizeof(memory_area); - arch::exception_handling::assert(expected_entry_size == actual_entry_size, "Unexpected memory_area entry size"); + exception_handling::assert(expected_entry_size == actual_entry_size, "Unexpected memory_area entry size"); auto total_size = mminfo->info.size; auto total_entries_size = total_size - sizeof(memory_map_header) + actual_entry_size; @@ -34,19 +34,18 @@ namespace teachos::arch::memory::multiboot { auto expected_entry_size = symbol->entry_size; constexpr auto actual_entry_size = sizeof(elf_section_header); - arch::exception_handling::assert(expected_entry_size == actual_entry_size, - "Unexpected elf_section_header entry size"); + exception_handling::assert(expected_entry_size == actual_entry_size, "Unexpected elf_section_header entry size"); auto expected_total_size = symbol->info.size; auto actual_total_entry_size = actual_entry_size * symbol->number_of_sections; constexpr auto actual_total_section_size = sizeof(elf_symbols_section_header) - sizeof(uint32_t); auto actual_total_size = actual_total_entry_size + actual_total_section_size; - arch::exception_handling::assert(expected_total_size == actual_total_size, - "Unexpected elf_symbols_section_header total size"); + exception_handling::assert(expected_total_size == actual_total_size, + "Unexpected elf_symbols_section_header total size"); auto begin = reinterpret_cast(&symbol->end); auto end = begin + symbol->number_of_sections; - arch::exception_handling::assert(begin->is_null(), "Missing elf_section_header begin"); + exception_handling::assert(begin->is_null(), "Missing elf_section_header begin"); std::size_t symbol_table_section_count = 0U; std::size_t dynamic_section_count = 0U; @@ -80,8 +79,8 @@ namespace teachos::arch::memory::multiboot } } - arch::exception_handling::assert(symbol_table_section_count == 1U, "Unexpected symbol_table_count value"); - arch::exception_handling::assert(dynamic_section_count <= 1U, "Unexpected dynamic_section_count value"); + exception_handling::assert(symbol_table_section_count == 1U, "Unexpected symbol_table_count value"); + exception_handling::assert(dynamic_section_count <= 1U, "Unexpected dynamic_section_count value"); } } // namespace diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 43c0b71..692f8ae 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -35,8 +35,8 @@ namespace teachos::arch::memory::paging auto entry::set_address(allocator::physical_frame frame) -> void { - arch::exception_handling::assert((frame.start_address() & ~0x000fffff'fffff000) == 0, - "Start address is not aligned with Page"); + exception_handling::assert((frame.start_address() & ~0x000fffff'fffff000) == 0, + "Start address is not aligned with Page"); flags = std::bitset<64U>(frame.start_address()) | flags; } } // 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 index 786ff69..8345161 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -23,8 +23,8 @@ namespace teachos::arch::memory::paging auto page_table::next_table(std::size_t table_index) -> void { - arch::exception_handling::assert(current_level != LEVEL1, - "[Page Table] Attempted to call next_table on level 1 page table"); + exception_handling::assert(current_level != LEVEL1, + "[Page Table] Attempted to call next_table on level 1 page table"); auto address = next_table_address(table_index); if (address.has_value()) @@ -38,7 +38,7 @@ namespace teachos::arch::memory::paging { // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which // could be incredibly hard to debug later. - arch::exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] index out of bounds"); + exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] index out of bounds"); return current_table->entries[index]; } diff --git a/arch/x86_64/src/memory/paging/virtual_page.cpp b/arch/x86_64/src/memory/paging/virtual_page.cpp new file mode 100644 index 0000000..3fb6caf --- /dev/null +++ b/arch/x86_64/src/memory/paging/virtual_page.cpp @@ -0,0 +1,22 @@ +#include "arch/memory/paging/virtual_page.hpp" + +#include "arch/exception_handling/assert.hpp" +#include "arch/memory/allocator/physical_frame.hpp" + +namespace teachos::arch::memory::paging +{ + virtual_page::virtual_page(std::size_t page_number) + : page_number(page_number) + { + // Nothing to do + } + + auto virtual_page::containing_address(std::size_t virtual_address) -> virtual_page + { + exception_handling::assert(virtual_address < 0x0000800000000000 || virtual_address >= 0xffff800000000000, + "[Virtual Page] Attempted to create virtual page from invalid address"); + return virtual_page{virtual_address / allocator::PAGE_FRAME_SIZE}; + } + + auto virtual_page::start_address() const -> uint64_t { return page_number * allocator::PAGE_FRAME_SIZE; } +} // namespace teachos::arch::memory::paging -- cgit v1.2.3 From e5206b3bf1883fd9601a37f5cce392d8080b8791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 20 Oct 2024 07:43:00 +0000 Subject: Add get level index method to virtual page --- arch/x86_64/include/arch/memory/paging/page_entry.hpp | 2 +- arch/x86_64/include/arch/memory/paging/page_table.hpp | 10 +--------- arch/x86_64/include/arch/memory/paging/virtual_page.hpp | 11 ++++++++++- arch/x86_64/src/memory/paging/page_table.cpp | 8 ++------ arch/x86_64/src/memory/paging/virtual_page.cpp | 5 +++++ 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index a40e764..016e054 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -87,4 +87,4 @@ namespace teachos::arch::memory::paging }; } // namespace teachos::arch::memory::paging -#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_ENTRY_HPP \ No newline at end of file +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_ENTRY_HPP diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 73b75ad..bbee477 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -73,14 +73,6 @@ namespace teachos::arch::memory::paging auto operator[](std::size_t index) const -> entry const &; private: - /** - * @brief Constructor. Used internally to create new page tables. - * - * @param new_level New level of the page table. - * @param new_table New table data contained in the page table. - */ - page_table(level new_level, table_content * new_table); - /** * @brief Calculates the address of the next page table level for the given table index. 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 @@ -97,4 +89,4 @@ namespace teachos::arch::memory::paging }; } // namespace teachos::arch::memory::paging -#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP \ No newline at end of file +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index 7871e4b..a2e5316 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP +#include "page_table.hpp" #include #include @@ -33,6 +34,14 @@ namespace teachos::arch::memory::paging */ auto start_address() const -> uint64_t; + /** + * @brief Calculates the index into the page table with the given level, which leads to this virtual page. + * + * @param level Level of the page table we want to calculate the index for. + * @return Index into the page table with the given level. + */ + auto get_level_index(page_table::level level) const -> uint64_t; + /** * @brief Defaulted equals operator. */ @@ -47,4 +56,4 @@ namespace teachos::arch::memory::paging }; } // namespace teachos::arch::memory::paging -#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP \ No newline at end of file +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 8345161..9857294 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -26,12 +26,8 @@ namespace teachos::arch::memory::paging exception_handling::assert(current_level != LEVEL1, "[Page Table] Attempted to call next_table on level 1 page table"); auto address = next_table_address(table_index); - - if (address.has_value()) - { - current_table = reinterpret_cast(address.value()); - current_level = static_cast(current_level - 1U); - } + current_table = reinterpret_cast(address.value()); + current_level = static_cast(current_level - 1U); } auto page_table::operator[](std::size_t index) -> entry & diff --git a/arch/x86_64/src/memory/paging/virtual_page.cpp b/arch/x86_64/src/memory/paging/virtual_page.cpp index 3fb6caf..dcdec7f 100644 --- a/arch/x86_64/src/memory/paging/virtual_page.cpp +++ b/arch/x86_64/src/memory/paging/virtual_page.cpp @@ -19,4 +19,9 @@ namespace teachos::arch::memory::paging } auto virtual_page::start_address() const -> uint64_t { return page_number * allocator::PAGE_FRAME_SIZE; } + + auto virtual_page::get_level_index(page_table::level level) const -> uint64_t + { + return (start_address() >> (level * 9U)) & 0x1FF; + } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From f8928c877c48b5beba9bb42876f70213aba68f88 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 20 Oct 2024 07:46:51 +0000 Subject: translate --- .../include/arch/memory/paging/virtual_page.hpp | 63 +++++++++++++++++++++- arch/x86_64/src/memory/multiboot/reader.cpp | 1 + arch/x86_64/src/memory/paging/page_table.cpp | 2 +- arch/x86_64/src/memory/paging/virtual_page.cpp | 1 - 4 files changed, 64 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index a2e5316..b2adca3 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -1,12 +1,73 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP -#include "page_table.hpp" +#include "arch/memory/allocator/physical_frame.hpp" +#include "arch/memory/paging/page_table.hpp" + #include #include +#include namespace teachos::arch::memory::paging { + /** + * @brief Translate virtual into phyical address + * + * @param virtual_address Address to translate into physical + * @return Physical address + */ + auto static translate_address(std::size_t virtual_address) -> std::optional + { + std::size_t offset = virtual_address % allocator::PAGE_FRAME_SIZE; + virtual_page page = virtual_page::containing_address(virtual_address); + allocator::physical_frame frame = paging::translate_page(page); + + if (frame.value()) + { + return frame->number * allocator::PAGE_FRAME_SIZE + offset; + } + + return std::nullopt; + } + + /** + * @brief Translate page into physical_frame + * + * @param page Page to translate into physical_frame + * @return Physical frame corresponding to the provided page_table + */ + auto static translate_page(virtual_page page) -> std::optional + { + auto level3 = + reinterpret_cast(page_table::LEVEL4)->next_table(page.get_level_index(page_table::LEVEL4)); + + auto huge_page = []() { + // TODO + }; + + if (level3.value()) + { + auto level2 = level3->next_table(page.get_level_index(page_table::LEVEL3)); + + if (level2.value()) + { + auto level1 = level2->next_table(page.get_level_index(page_table::LEVEL2)); + + if (level1.value()) + { + auto frame = level1[page.get_level_index(page_table::LEVEL1)].calculate_pointed_to_frame(); + + if (frame.value()) + { + return frame; + } + } + } + } + + return huge_page(); + } + /** * @brief Virtual page entry contained in P1 page tables */ diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp index 156b437..565f604 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -111,6 +111,7 @@ namespace teachos::arch::memory::multiboot break; } } + return mem_info; } } // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 9857294..3fb7a3f 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -45,7 +45,7 @@ namespace teachos::arch::memory::paging if (entry.contains_flags(entry::PRESENT) && !entry.contains_flags(entry::HUGE_PAGE)) { std::size_t const table_address = reinterpret_cast(current_table); - return (table_address << 9) | (table_index << 12); + return ((table_address << 9) | (table_index << 12)); } // TODO: Implement behaviour for huge pages currently not done return std::nullopt; diff --git a/arch/x86_64/src/memory/paging/virtual_page.cpp b/arch/x86_64/src/memory/paging/virtual_page.cpp index dcdec7f..9b803d2 100644 --- a/arch/x86_64/src/memory/paging/virtual_page.cpp +++ b/arch/x86_64/src/memory/paging/virtual_page.cpp @@ -1,7 +1,6 @@ #include "arch/memory/paging/virtual_page.hpp" #include "arch/exception_handling/assert.hpp" -#include "arch/memory/allocator/physical_frame.hpp" namespace teachos::arch::memory::paging { -- cgit v1.2.3 From 882ccdcc0e3c19fbcc595c6a371ef79587f63648 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 20 Oct 2024 08:11:19 +0000 Subject: implement translate_page --- .../include/arch/memory/paging/page_table.hpp | 2 +- .../include/arch/memory/paging/virtual_page.hpp | 121 +++++++++++---------- arch/x86_64/src/memory/paging/page_table.cpp | 2 +- 3 files changed, 64 insertions(+), 61 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index bbee477..aa8bd5e 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -54,7 +54,7 @@ namespace teachos::arch::memory::paging * * @param table_index Index of this page table in the page table one level higher. */ - auto next_table(std::size_t table_index) -> void; + auto next_table(std::size_t table_index) -> bool; /** * @brief Index operator overload to access specific mutable entry directy. diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index b2adca3..5a025fa 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -2,72 +2,14 @@ #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP #include "arch/memory/allocator/physical_frame.hpp" -#include "arch/memory/paging/page_table.hpp" +#include "page_table.hpp" #include #include #include namespace teachos::arch::memory::paging { - /** - * @brief Translate virtual into phyical address - * - * @param virtual_address Address to translate into physical - * @return Physical address - */ - auto static translate_address(std::size_t virtual_address) -> std::optional - { - std::size_t offset = virtual_address % allocator::PAGE_FRAME_SIZE; - virtual_page page = virtual_page::containing_address(virtual_address); - allocator::physical_frame frame = paging::translate_page(page); - - if (frame.value()) - { - return frame->number * allocator::PAGE_FRAME_SIZE + offset; - } - - return std::nullopt; - } - - /** - * @brief Translate page into physical_frame - * - * @param page Page to translate into physical_frame - * @return Physical frame corresponding to the provided page_table - */ - auto static translate_page(virtual_page page) -> std::optional - { - auto level3 = - reinterpret_cast(page_table::LEVEL4)->next_table(page.get_level_index(page_table::LEVEL4)); - - auto huge_page = []() { - // TODO - }; - - if (level3.value()) - { - auto level2 = level3->next_table(page.get_level_index(page_table::LEVEL3)); - - if (level2.value()) - { - auto level1 = level2->next_table(page.get_level_index(page_table::LEVEL2)); - - if (level1.value()) - { - auto frame = level1[page.get_level_index(page_table::LEVEL1)].calculate_pointed_to_frame(); - - if (frame.value()) - { - return frame; - } - } - } - } - - return huge_page(); - } - /** * @brief Virtual page entry contained in P1 page tables */ @@ -115,6 +57,67 @@ namespace teachos::arch::memory::paging std::size_t page_number; ///< Index number of the current virtual page, used to distinguish it from other pages. }; + + /** + * @brief Translate page into physical_frame + * + * @param page Page to translate into physical_frame + * @return Physical frame corresponding to the provided page_table + */ + auto translate_page(virtual_page page) -> std::optional + { + page_table page_table{}; + bool is_valid = page_table.next_table(page.get_level_index(page_table::LEVEL4)); + + auto huge_page = []() -> std::optional { + // TODO + return std::nullopt; + }; + + if (is_valid) + { + is_valid = page_table.next_table(page.get_level_index(page_table::LEVEL3)); + + if (is_valid) + { + is_valid = page_table.next_table(page.get_level_index(page_table::LEVEL2)); + + if (is_valid) + { + auto level1_index = page.get_level_index(page_table::LEVEL1); + auto frame = page_table[level1_index].calculate_pointed_to_frame(); + + if (frame.has_value()) + { + return frame; + } + } + } + } + + return huge_page(); + } + + /** + * @brief Translate virtual into phyical address + * + * @param virtual_address Address to translate into physical + * @return Physical address + */ + auto translate_address(std::size_t virtual_address) -> std::optional + { + std::size_t offset = virtual_address % allocator::PAGE_FRAME_SIZE; + virtual_page page = virtual_page::containing_address(virtual_address); + std::optional frame = translate_page(page); + + if (frame.has_value()) + { + return frame.value().frame_number * allocator::PAGE_FRAME_SIZE + offset; + } + + return std::nullopt; + } + } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 3fb7a3f..3c4f6d8 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -21,7 +21,7 @@ namespace teachos::arch::memory::paging } } - auto page_table::next_table(std::size_t table_index) -> void + auto page_table::next_table(std::size_t table_index) -> bool { exception_handling::assert(current_level != LEVEL1, "[Page Table] Attempted to call next_table on level 1 page table"); -- cgit v1.2.3 From 89ad7a0b60ce74c70fc3865e0967c601a6050674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 20 Oct 2024 08:13:31 +0000 Subject: Make next table return boolean --- arch/x86_64/src/memory/paging/page_table.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 3c4f6d8..ab7331a 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -26,8 +26,13 @@ namespace teachos::arch::memory::paging exception_handling::assert(current_level != LEVEL1, "[Page Table] Attempted to call next_table on level 1 page table"); auto address = next_table_address(table_index); - current_table = reinterpret_cast(address.value()); - current_level = static_cast(current_level - 1U); + bool const success = address.has_value(); + if (success) + { + current_table = reinterpret_cast(address.value()); + current_level = static_cast(current_level - 1U); + } + return success; } auto page_table::operator[](std::size_t index) -> entry & @@ -47,7 +52,6 @@ namespace teachos::arch::memory::paging std::size_t const table_address = reinterpret_cast(current_table); return ((table_address << 9) | (table_index << 12)); } - // TODO: Implement behaviour for huge pages currently not done return std::nullopt; } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 5b5e8dec97f6f619faa13ee813df21837fe83a57 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 20 Oct 2024 08:13:33 +0000 Subject: add types --- arch/x86_64/include/arch/memory/paging/virtual_page.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index 5a025fa..1ba0f7c 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -84,8 +84,8 @@ namespace teachos::arch::memory::paging if (is_valid) { - auto level1_index = page.get_level_index(page_table::LEVEL1); - auto frame = page_table[level1_index].calculate_pointed_to_frame(); + std::size_t level1_index = page.get_level_index(page_table::LEVEL1); + std::optional frame = page_table[level1_index].calculate_pointed_to_frame(); if (frame.has_value()) { -- cgit v1.2.3 From fba2fc4ce3d4bf4997eb42c9b5b2ac1de8692150 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 20 Oct 2024 08:14:54 +0000 Subject: remove faulty if statement --- arch/x86_64/include/arch/memory/paging/virtual_page.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index 1ba0f7c..46140ff 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -87,10 +87,7 @@ namespace teachos::arch::memory::paging std::size_t level1_index = page.get_level_index(page_table::LEVEL1); std::optional frame = page_table[level1_index].calculate_pointed_to_frame(); - if (frame.has_value()) - { - return frame; - } + return frame; } } } -- cgit v1.2.3 From d934ea6875932a7139eba77bb5248fca8be7fd01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 20 Oct 2024 08:37:49 +0000 Subject: =?UTF-8?q?Implement=20translate=20page=20in=20a=20big=20brain=20w?= =?UTF-8?q?ay=20=F0=9F=A4=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../include/arch/memory/paging/page_table.hpp | 2 ++ .../include/arch/memory/paging/virtual_page.hpp | 32 +++++++++------------- arch/x86_64/src/memory/paging/page_table.cpp | 8 ++++++ 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index aa8bd5e..0fe667c 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -87,6 +87,8 @@ namespace teachos::arch::memory::paging ///< 1 page table table_content * current_table; ///< Current table we are accessing and indexing. }; + + auto operator--(page_table::level & level, int) -> page_table::level; } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index 46140ff..705de29 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -67,31 +67,25 @@ namespace teachos::arch::memory::paging auto translate_page(virtual_page page) -> std::optional { page_table page_table{}; - bool is_valid = page_table.next_table(page.get_level_index(page_table::LEVEL4)); + bool is_valid = false; + auto huge_page = []() -> std::optional { return std::nullopt; }; - auto huge_page = []() -> std::optional { - // TODO - return std::nullopt; - }; - - if (is_valid) + for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) { - is_valid = page_table.next_table(page.get_level_index(page_table::LEVEL3)); - - if (is_valid) + is_valid = page_table.next_table(page.get_level_index(level)); + if (!is_valid) { - is_valid = page_table.next_table(page.get_level_index(page_table::LEVEL2)); - - if (is_valid) - { - std::size_t level1_index = page.get_level_index(page_table::LEVEL1); - std::optional frame = page_table[level1_index].calculate_pointed_to_frame(); - - return frame; - } + break; } } + if (is_valid) + { + auto level1_index = page.get_level_index(page_table::LEVEL1); + auto frame = page_table[level1_index].calculate_pointed_to_frame(); + return frame; + } + return huge_page(); } diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index ab7331a..02ababe 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -54,4 +54,12 @@ namespace teachos::arch::memory::paging } return std::nullopt; } + + auto operator--(page_table::level & level, int) -> page_table::level + { + exception_handling::assert(level != page_table::LEVEL1, + "[Page table] Attemptd to decrement enum to value outside of range"); + auto value = static_cast::type>(level); + return static_cast(--value); + } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 1d157101eb550f99dac9ec943053f85bbf6c7644 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 20 Oct 2024 09:03:30 +0000 Subject: create page_mapper --- arch/x86_64/CMakeLists.txt | 1 + .../include/arch/memory/paging/page_mapper.hpp | 30 ++++++++++++ .../include/arch/memory/paging/virtual_page.hpp | 51 ------------------- arch/x86_64/src/memory/paging/page_mapper.cpp | 57 ++++++++++++++++++++++ 4 files changed, 88 insertions(+), 51 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/paging/page_mapper.hpp create mode 100644 arch/x86_64/src/memory/paging/page_mapper.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index fe83548..018fe61 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -49,6 +49,7 @@ target_sources("_memory" PRIVATE "src/memory/paging/page_entry.cpp" "src/memory/paging/page_table.cpp" "src/memory/paging/virtual_page.cpp" + "src/memory/paging/page_mapper.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp new file mode 100644 index 0000000..b151a7f --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -0,0 +1,30 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP + +#include "arch/memory/paging/virtual_page.hpp" + +#include + +namespace teachos::arch::memory::paging +{ + /** + * @brief Translate page into physical_frame + * + * @param page Page to translate into physical_frame + * @return Physical frame corresponding to the provided page_table + */ + auto translate_page(virtual_page page) -> std::optional; + + /** + * @brief Translate virtual into phyical address + * + * @param virtual_address Address to translate into physical + * @return Physical address + */ + auto translate_address(std::size_t virtual_address) -> std::optional; + + auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, const Page & page, const Frame & frame, + EntryFlags flags) -> void; +} // namespace teachos::arch::memory::paging + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index 705de29..6b9a641 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -58,57 +58,6 @@ namespace teachos::arch::memory::paging std::size_t page_number; ///< Index number of the current virtual page, used to distinguish it from other pages. }; - /** - * @brief Translate page into physical_frame - * - * @param page Page to translate into physical_frame - * @return Physical frame corresponding to the provided page_table - */ - auto translate_page(virtual_page page) -> std::optional - { - page_table page_table{}; - bool is_valid = false; - auto huge_page = []() -> std::optional { return std::nullopt; }; - - for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) - { - is_valid = page_table.next_table(page.get_level_index(level)); - if (!is_valid) - { - break; - } - } - - if (is_valid) - { - auto level1_index = page.get_level_index(page_table::LEVEL1); - auto frame = page_table[level1_index].calculate_pointed_to_frame(); - return frame; - } - - return huge_page(); - } - - /** - * @brief Translate virtual into phyical address - * - * @param virtual_address Address to translate into physical - * @return Physical address - */ - auto translate_address(std::size_t virtual_address) -> std::optional - { - std::size_t offset = virtual_address % allocator::PAGE_FRAME_SIZE; - virtual_page page = virtual_page::containing_address(virtual_address); - std::optional frame = translate_page(page); - - if (frame.has_value()) - { - return frame.value().frame_number * allocator::PAGE_FRAME_SIZE + offset; - } - - return std::nullopt; - } - } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp new file mode 100644 index 0000000..5372561 --- /dev/null +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -0,0 +1,57 @@ +#include "arch/exception_handling/assert.hpp" +#include "arch/memory/allocator/area_frame_allocator.hpp" +#include "arch/memory/paging/virtual_page.hpp" + +namespace teachos::arch::memory::paging +{ + auto translate_page(virtual_page page) -> std::optional + { + page_table page_table{}; + bool is_valid = false; + auto huge_page = []() -> std::optional { return std::nullopt; }; + + for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) + { + is_valid = page_table.next_table(page.get_level_index(level)); + if (!is_valid) + { + break; + } + } + + if (is_valid) + { + auto level1_index = page.get_level_index(page_table::LEVEL1); + auto frame = page_table[level1_index].calculate_pointed_to_frame(); + return frame; + } + + return huge_page(); + } + + auto translate_address(std::size_t virtual_address) -> std::optional + { + std::size_t offset = virtual_address % allocator::PAGE_FRAME_SIZE; + virtual_page page = virtual_page::containing_address(virtual_address); + std::optional frame = translate_page(page); + + if (frame.has_value()) + { + return frame.value().frame_number * allocator::PAGE_FRAME_SIZE + offset; + } + + return std::nullopt; + } + + auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, const virtual_page & page, + const memory::allocator::physical_frame & frame, entry::bitset flags) -> void + { + auto p4 = reinterpret_cast(P4); // Assuming P4 is defined somewhere + auto p3 = p4->next_table_create(page.p4_index(), allocator); + auto p2 = p3->next_table_create(page.p3_index(), allocator); + auto p1 = p2->next_table_create(page.p2_index(), allocator); + + assert(p1[page.p1_index()].is_unused()); + p1[page.p1_index()].set(frame, flags | PRESENT); + } +} // namespace teachos::arch::memory::paging \ No newline at end of file -- cgit v1.2.3 From 04bd6a059b9eb105024044d74122b0cb76cebf14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 20 Oct 2024 09:34:03 +0000 Subject: Add translate huge page method --- .../include/arch/memory/paging/page_mapper.hpp | 21 ++++++++--- arch/x86_64/src/memory/paging/page_mapper.cpp | 44 ++++++++++++++++++++-- 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index b151a7f..ad9db52 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -8,18 +8,27 @@ namespace teachos::arch::memory::paging { /** - * @brief Translate page into physical_frame + * @brief Translates page into physical frame, will first attempt to parse normally using default page size and if it + * failed attempt to parse using huge pages. * - * @param page Page to translate into physical_frame - * @return Physical frame corresponding to the provided page_table + * @param page Page to translate into physical frame. + * @return Physical frame corresponding to the provided virtual page. */ auto translate_page(virtual_page page) -> std::optional; /** - * @brief Translate virtual into phyical address + * @brief Translates huge page into actual physical frame. * - * @param virtual_address Address to translate into physical - * @return Physical address + * @param page Page to translate into physical frame. + * @return Physical frame corresponding to the provided virtual page. + */ + auto translate_huge_page(virtual_page page) -> std::optional; + + /** + * @brief Translate virtual into phyical address. + * + * @param virtual_address Address to translate into physical. + * @return Physical address. */ auto translate_address(std::size_t virtual_address) -> std::optional; diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 5372561..e68bc68 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -8,7 +8,8 @@ namespace teachos::arch::memory::paging { page_table page_table{}; bool is_valid = false; - auto huge_page = []() -> std::optional { return std::nullopt; }; + + auto huge_page = [&]() -> std::optional {}; for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) { @@ -22,11 +23,46 @@ namespace teachos::arch::memory::paging if (is_valid) { auto level1_index = page.get_level_index(page_table::LEVEL1); - auto frame = page_table[level1_index].calculate_pointed_to_frame(); - return frame; + auto level1_frame = page_table[level1_index].calculate_pointed_to_frame(); + return level1_frame; } - return huge_page(); + return translate_huge_page(page); + } + + auto translate_huge_page(virtual_page page) -> std::optional + { + page_table page_table{}; + bool is_valid = page_table.next_table(page.get_level_index(page_table::LEVEL3)); + + if (is_valid) + { + auto level3_entry = page_table[page.get_level_index(page_table::LEVEL3)]; + auto level3_optional_frame = level3_entry.calculate_pointed_to_frame(); + if (level3_optional_frame.has_value() && level3_entry.contains_flags(entry::HUGE_PAGE)) + { + auto level3_frame = level3_optional_frame.value(); + exception_handling::assert(level3_frame.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.frame_number + + page.get_level_index(page_table::LEVEL2) * PAGE_TABLE_ENTRY_COUNT + + page.get_level_index(page_table::LEVEL1)}; + } + } + is_valid = page_table.next_table(page.get_level_index(page_table::LEVEL3)); + if (is_valid) + { + auto level2_entry = page_table[page.get_level_index(page_table::LEVEL2)]; + auto level2_optional_frame = level2_entry.calculate_pointed_to_frame(); + if (level2_optional_frame.has_value() && level2_entry.contains_flags(entry::HUGE_PAGE)) + { + auto level2_frame = level2_optional_frame.value(); + exception_handling::assert(level2_frame.frame_number % PAGE_TABLE_ENTRY_COUNT == 0U, + "[Page Mapper] Physical address must be 2 MiB aligned"); + return allocator::physical_frame{level2_frame.frame_number + page.get_level_index(page_table::LEVEL1)}; + } + } + return std::nullopt; } auto translate_address(std::size_t virtual_address) -> std::optional -- cgit v1.2.3 From 4c0f7c2179622d9221af8860d610d8192dee3707 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 20 Oct 2024 09:37:08 +0000 Subject: update page_mapper --- .../include/arch/memory/paging/page_entry.hpp | 2 +- .../include/arch/memory/paging/page_mapper.hpp | 4 +- arch/x86_64/src/memory/paging/page_entry.cpp | 4 +- arch/x86_64/src/memory/paging/page_mapper.cpp | 43 +++++++++++++++++++--- 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 016e054..8dd061f 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -60,7 +60,7 @@ namespace teachos::arch::memory::paging * * @param frame Physical frame that contains the address we want to copy into our underlying std::bitset. */ - auto set_address(allocator::physical_frame frame) -> void; + auto entry::set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void; /** * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index ad9db52..fcaba26 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -32,8 +32,8 @@ namespace teachos::arch::memory::paging */ auto translate_address(std::size_t virtual_address) -> std::optional; - auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, const Page & page, const Frame & frame, - EntryFlags flags) -> void; + auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, const virtual_page & page, + const memory::allocator::physical_frame & frame, entry::bitset flags) -> void } // namespace teachos::arch::memory::paging #endif \ No newline at end of file diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 692f8ae..0dbbae1 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -33,10 +33,10 @@ namespace teachos::arch::memory::paging auto entry::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } - auto entry::set_address(allocator::physical_frame frame) -> void + auto entry::set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void { exception_handling::assert((frame.start_address() & ~0x000fffff'fffff000) == 0, "Start address is not aligned with Page"); - flags = std::bitset<64U>(frame.start_address()) | flags; + flags = std::bitset<64U>(frame.start_address()) | additional_flags; } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index e68bc68..32567be 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -1,15 +1,37 @@ +#include "arch/memory/paging/page_mapper.hpp" + #include "arch/exception_handling/assert.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" -#include "arch/memory/paging/virtual_page.hpp" namespace teachos::arch::memory::paging { - auto translate_page(virtual_page page) -> std::optional + auto generate_page_table(virtual_page page) -> page_table * { page_table page_table{}; bool is_valid = false; + auto huge_page = []() -> arch::memory::paging::page_table { return std::nullopt; }; - auto huge_page = [&]() -> std::optional {}; + for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) + { + is_valid = page_table.next_table(page.get_level_index(level)); + if (!is_valid) + { + break; + } + } + + if (is_valid) + { + return &page_table; + } + + return &huge_page(); + } + + auto translate_page(virtual_page page) -> std::optional + { + page_table page_table{}; + bool is_valid = false; for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) { @@ -82,12 +104,21 @@ namespace teachos::arch::memory::paging auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, const virtual_page & page, const memory::allocator::physical_frame & frame, entry::bitset flags) -> void { - auto p4 = reinterpret_cast(P4); // Assuming P4 is defined somewhere + std::optional frame = + + page_table page_table{}; + + bool is_valid = page_table.next_table(page_table::LEVEL3); + page_table = page_table.next_table(page_table::LEVEL2); + page_table = page_table.next_table(page_table::LEVEL1); + auto p3 = p4->next_table_create(page.p4_index(), allocator); auto p2 = p3->next_table_create(page.p3_index(), allocator); auto p1 = p2->next_table_create(page.p2_index(), allocator); - assert(p1[page.p1_index()].is_unused()); - p1[page.p1_index()].set(frame, flags | PRESENT); + page_table::level level1_index{page.get_level_index(page_table::LEVEL1)}; + arch::exception_handling::assert(p1[level1_index].is_unused(), ""); + + p1[page.p1_index()].set(frame, flags | entry::bitset::PRESENT); } } // namespace teachos::arch::memory::paging \ No newline at end of file -- cgit v1.2.3 From ecf89844100248db3ad08d5c76091de563488b95 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 20 Oct 2024 09:37:08 +0000 Subject: implement map_page_to_frame --- .../include/arch/memory/paging/page_entry.hpp | 2 +- .../include/arch/memory/paging/page_mapper.hpp | 13 +++++++-- arch/x86_64/src/memory/paging/page_entry.cpp | 4 +-- arch/x86_64/src/memory/paging/page_mapper.cpp | 32 +++++++++++++++------- 4 files changed, 36 insertions(+), 15 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 016e054..8dd061f 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -60,7 +60,7 @@ namespace teachos::arch::memory::paging * * @param frame Physical frame that contains the address we want to copy into our underlying std::bitset. */ - auto set_address(allocator::physical_frame frame) -> void; + auto entry::set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void; /** * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index ad9db52..5960aaf 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP +#include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/paging/virtual_page.hpp" #include @@ -32,8 +33,16 @@ namespace teachos::arch::memory::paging */ auto translate_address(std::size_t virtual_address) -> std::optional; - auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, const Page & page, const Frame & frame, - EntryFlags flags) -> void; + /** + * @brief TODO + * + * @param allocator + * @param page + * @param frame + * @param flags + */ + auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, const virtual_page & page, + const memory::allocator::physical_frame & frame, entry::bitset flags) -> void; } // namespace teachos::arch::memory::paging #endif \ No newline at end of file diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 692f8ae..0dbbae1 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -33,10 +33,10 @@ namespace teachos::arch::memory::paging auto entry::contains_flags(std::bitset<64U> other) const -> bool { return (flags & other) == other; } - auto entry::set_address(allocator::physical_frame frame) -> void + auto entry::set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void { exception_handling::assert((frame.start_address() & ~0x000fffff'fffff000) == 0, "Start address is not aligned with Page"); - flags = std::bitset<64U>(frame.start_address()) | flags; + flags = std::bitset<64U>(frame.start_address()) | additional_flags; } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index e68bc68..ec1d5d5 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -1,6 +1,6 @@ +#include "arch/memory/paging/page_mapper.hpp" + #include "arch/exception_handling/assert.hpp" -#include "arch/memory/allocator/area_frame_allocator.hpp" -#include "arch/memory/paging/virtual_page.hpp" namespace teachos::arch::memory::paging { @@ -9,8 +9,6 @@ namespace teachos::arch::memory::paging page_table page_table{}; bool is_valid = false; - auto huge_page = [&]() -> std::optional {}; - for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) { is_valid = page_table.next_table(page.get_level_index(level)); @@ -82,12 +80,26 @@ namespace teachos::arch::memory::paging auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, const virtual_page & page, const memory::allocator::physical_frame & frame, entry::bitset flags) -> void { - auto p4 = reinterpret_cast(P4); // Assuming P4 is defined somewhere - auto p3 = p4->next_table_create(page.p4_index(), allocator); - auto p2 = p3->next_table_create(page.p3_index(), allocator); - auto p1 = p2->next_table_create(page.p2_index(), allocator); + page_table page_table{}; + bool is_valid = false; + + for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) + { + std::size_t level_index = page.get_level_index(level); + is_valid = page_table.next_table(level_index); + page_table[level_index].set_entry(frame, entry::PRESENT | entry::WRITABLE); + page_table.zero_entries(); + + if (!is_valid) + { + break; + } + } - assert(p1[page.p1_index()].is_unused()); - p1[page.p1_index()].set(frame, flags | PRESENT); + entry page_table_entry = page_table[page.get_level_index(page_table::LEVEL1)]; + arch::exception_handling::assert(!page_table_entry.contains_flags(entry::HUGE_PAGE), + "[Page Mapper]: Unable to map huge pages"); + arch::exception_handling::assert(!page_table_entry.is_unused(), "[Page Mapper]: Page table entry is already used"); + page_table_entry.set_entry(frame, flags | entry::PRESENT); } } // namespace teachos::arch::memory::paging \ No newline at end of file -- cgit v1.2.3 From f47f1468c8c281ee9603b7669f5e685e5f36fa3f Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 20 Oct 2024 11:23:02 +0000 Subject: finalize map_page_to_frame --- arch/x86_64/include/arch/memory/paging/page_entry.hpp | 2 +- arch/x86_64/src/memory/paging/page_mapper.cpp | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 8dd061f..109735d 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -60,7 +60,7 @@ namespace teachos::arch::memory::paging * * @param frame Physical frame that contains the address we want to copy into our underlying std::bitset. */ - auto entry::set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void; + auto set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void; /** * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index ec1d5d5..6b01548 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -77,8 +77,8 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, const virtual_page & page, - const memory::allocator::physical_frame & frame, entry::bitset flags) -> void + auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, virtual_page const & page, + memory::allocator::physical_frame const & frame, entry::bitset flags) -> void { page_table page_table{}; bool is_valid = false; @@ -87,7 +87,10 @@ namespace teachos::arch::memory::paging { std::size_t level_index = page.get_level_index(level); is_valid = page_table.next_table(level_index); - page_table[level_index].set_entry(frame, entry::PRESENT | entry::WRITABLE); + + std::optional allocated_frame = allocator.allocate_frame(); + exception_handling::assert(!allocated_frame.has_value(), "[Page mapper]: Unable to allocate frame"); + page_table[level_index].set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); page_table.zero_entries(); if (!is_valid) -- cgit v1.2.3 From f4a14572a661b1f2bac283615d5b070408b382f7 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 20 Oct 2024 11:24:58 +0000 Subject: fix syntax --- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 4 ++-- arch/x86_64/src/memory/paging/page_mapper.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 5960aaf..c82b08c 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -41,8 +41,8 @@ namespace teachos::arch::memory::paging * @param frame * @param flags */ - auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, const virtual_page & page, - const memory::allocator::physical_frame & frame, entry::bitset flags) -> void; + auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, virtual_page const & page, + memory::allocator::physical_frame const & frame, entry::bitset flags) -> void; } // namespace teachos::arch::memory::paging #endif \ No newline at end of file diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 6b01548..eaafafa 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -77,8 +77,8 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, virtual_page const & page, - memory::allocator::physical_frame const & frame, entry::bitset flags) -> void + auto map_page_to_frame(allocator::area_frame_allocator & allocator, virtual_page const & page, + allocator::physical_frame const & frame, entry::bitset flags) -> void { page_table page_table{}; bool is_valid = false; @@ -88,7 +88,7 @@ namespace teachos::arch::memory::paging std::size_t level_index = page.get_level_index(level); is_valid = page_table.next_table(level_index); - std::optional allocated_frame = allocator.allocate_frame(); + std::optional allocated_frame = allocator.allocate_frame(); exception_handling::assert(!allocated_frame.has_value(), "[Page mapper]: Unable to allocate frame"); page_table[level_index].set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); page_table.zero_entries(); -- cgit v1.2.3 From 0d42fed17834a21d29032dd2d8e56e11596056bc Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 20 Oct 2024 11:29:53 +0000 Subject: fix logic --- arch/x86_64/src/memory/paging/page_mapper.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index eaafafa..eb1e18c 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -88,15 +88,15 @@ namespace teachos::arch::memory::paging std::size_t level_index = page.get_level_index(level); is_valid = page_table.next_table(level_index); - std::optional allocated_frame = allocator.allocate_frame(); - exception_handling::assert(!allocated_frame.has_value(), "[Page mapper]: Unable to allocate frame"); - page_table[level_index].set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); - page_table.zero_entries(); - if (!is_valid) { break; } + + auto allocated_frame = allocator.allocate_frame(); + exception_handling::assert(!allocated_frame.has_value(), "[Page mapper]: Unable to allocate frame"); + page_table[level_index].set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); + page_table.zero_entries(); } entry page_table_entry = page_table[page.get_level_index(page_table::LEVEL1)]; -- cgit v1.2.3 From da2341ec12128d3b4983a67d39aeaf76b1781fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 20 Oct 2024 12:02:20 +0000 Subject: Add printf like behaviour to assert --- arch/x86_64/CMakeLists.txt | 1 - .../include/arch/exception_handling/assert.hpp | 52 +++++++++++++++++++--- arch/x86_64/src/exception_handling/abort.cpp | 3 +- arch/x86_64/src/exception_handling/assert.cpp | 16 ------- arch/x86_64/src/exception_handling/panic.cpp | 3 +- arch/x86_64/src/memory/multiboot/reader.cpp | 24 +++++++--- arch/x86_64/src/memory/paging/page_entry.cpp | 2 +- arch/x86_64/src/memory/paging/page_mapper.cpp | 24 +++++----- arch/x86_64/src/memory/paging/page_table.cpp | 2 +- 9 files changed, 79 insertions(+), 48 deletions(-) delete mode 100644 arch/x86_64/src/exception_handling/assert.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 018fe61..645660a 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -58,7 +58,6 @@ target_sources("_memory" PRIVATE target_sources("_exception" PRIVATE "src/exception_handling/abort.cpp" - "src/exception_handling/assert.cpp" "src/exception_handling/panic.cpp" ) diff --git a/arch/x86_64/include/arch/exception_handling/assert.hpp b/arch/x86_64/include/arch/exception_handling/assert.hpp index f355a61..152e653 100644 --- a/arch/x86_64/include/arch/exception_handling/assert.hpp +++ b/arch/x86_64/include/arch/exception_handling/assert.hpp @@ -1,16 +1,56 @@ #ifndef TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP #define TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP +#include "arch/exception_handling/panic.hpp" + +#include + namespace teachos::arch::exception_handling { + namespace + { + char constexpr FAILED_MESSAGE[] = "Invalid arguments passed to format specifiers (%) in exception_handling::assert"; + } + /** - * @brief assert a condition to be true, if not do not continue - * execution of the code and print message to screen + * @brief Assert a condition to be true, if not do not continue + * execution of the code and print the formatted message to screen. * - * @param condition - * @param message + * @param condition Condition we want to be true. + * @param format Formatting message that the given arguments will be inserted into. + * @param ...args Arguments that will be formatted and inserted into the resulting string, replacing their respective + * specifiers. Uses the printf specifiers see https://cplusplus.com/reference/cstdio/printf/ for more information. */ - auto assert(bool condition, char const * message) -> void; + template + auto assert(bool condition, char const * format, Args const &... args) -> void + { + if (condition) + { + return; + } + else if constexpr (sizeof...(args) == 0) + { + panic("Assertion Violation: ", format); + } + + // Result is what would have been written if the passed buffer would have been large enough not counting null + // character, or if an error occured while creating the string a negative number is returned instead. To ensure this + // will not crash the system when creating an array with negative size we assert beforehand with a clear error + // message. + int const size = snprintf(nullptr, 0U, format, args...) + 1U; + if (size < 0) + { + panic("Assertion Violation: ", FAILED_MESSAGE); + } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvla" + char arguments[size] = {}; +#pragma GCC diagnostic pop + int const written_characters = snprintf(arguments, size, format, args...); + // Written characters is expected to be one less, because of the null termination character. + bool const result = (written_characters == (size - 1)); + panic("Assertion Violation: ", result ? arguments : FAILED_MESSAGE); + } } // namespace teachos::arch::exception_handling -#endif \ No newline at end of file +#endif diff --git a/arch/x86_64/src/exception_handling/abort.cpp b/arch/x86_64/src/exception_handling/abort.cpp index dc40008..77576b1 100644 --- a/arch/x86_64/src/exception_handling/abort.cpp +++ b/arch/x86_64/src/exception_handling/abort.cpp @@ -4,7 +4,6 @@ namespace teachos::arch::exception_handling { - /** * @brief Override for the newlib abort function. * @@ -14,4 +13,4 @@ namespace teachos::arch::exception_handling */ extern "C" auto abort() -> void { panic("Terminate was called, possibly due to an unhandled exception"); } -} // namespace teachos::arch::exception_handling \ No newline at end of file +} // 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 86696f8..0000000 --- a/arch/x86_64/src/exception_handling/assert.cpp +++ /dev/null @@ -1,16 +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 \ No newline at end of file diff --git a/arch/x86_64/src/exception_handling/panic.cpp b/arch/x86_64/src/exception_handling/panic.cpp index 56edfd5..8e3802a 100644 --- a/arch/x86_64/src/exception_handling/panic.cpp +++ b/arch/x86_64/src/exception_handling/panic.cpp @@ -5,7 +5,6 @@ namespace teachos::arch::exception_handling { - extern "C" char const message_prefix_panic[]; auto panic(char const * reason) -> void { panic(message_prefix_panic, reason); } @@ -20,4 +19,4 @@ namespace teachos::arch::exception_handling kernel::halt(); }; -} // namespace teachos::arch::exception_handling \ No newline at end of file +} // namespace teachos::arch::exception_handling diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp index 565f604..4e78a06 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -19,7 +19,9 @@ namespace teachos::arch::memory::multiboot { auto expected_entry_size = mminfo->entry_size; constexpr auto actual_entry_size = sizeof(memory_area); - exception_handling::assert(expected_entry_size == actual_entry_size, "Unexpected memory_area entry size"); + exception_handling::assert(expected_entry_size == actual_entry_size, + "[Multiboot Reader] Expected memory area entry size (%u) but got (%u)", + expected_entry_size, actual_entry_size); auto total_size = mminfo->info.size; auto total_entries_size = total_size - sizeof(memory_map_header) + actual_entry_size; @@ -34,18 +36,22 @@ namespace teachos::arch::memory::multiboot { auto expected_entry_size = symbol->entry_size; constexpr auto actual_entry_size = sizeof(elf_section_header); - exception_handling::assert(expected_entry_size == actual_entry_size, "Unexpected elf_section_header entry size"); + exception_handling::assert(expected_entry_size == actual_entry_size, + "[Multiboot Reader] Expected elf section header entry size (%u) but got (%u)", + expected_entry_size, actual_entry_size); auto expected_total_size = symbol->info.size; auto actual_total_entry_size = actual_entry_size * symbol->number_of_sections; constexpr auto actual_total_section_size = sizeof(elf_symbols_section_header) - sizeof(uint32_t); auto actual_total_size = actual_total_entry_size + actual_total_section_size; exception_handling::assert(expected_total_size == actual_total_size, - "Unexpected elf_symbols_section_header total size"); + "[Multiboot Reader] Expected elf symbols section header total size (%u) but got (%u)", + expected_total_size, actual_total_size); auto begin = reinterpret_cast(&symbol->end); auto end = begin + symbol->number_of_sections; - exception_handling::assert(begin->is_null(), "Missing elf_section_header begin"); + exception_handling::assert(begin->is_null(), + "[Multiboot Reader] Elf symbols section not starting with SHT_NULL section"); std::size_t symbol_table_section_count = 0U; std::size_t dynamic_section_count = 0U; @@ -79,8 +85,14 @@ namespace teachos::arch::memory::multiboot } } - exception_handling::assert(symbol_table_section_count == 1U, "Unexpected symbol_table_count value"); - exception_handling::assert(dynamic_section_count <= 1U, "Unexpected dynamic_section_count value"); + exception_handling::assert( + symbol_table_section_count == 1U, + "[Multiboot Reader] ELF Specifications allows only (1) symbol table section, but got (%u)", + symbol_table_section_count); + exception_handling::assert( + dynamic_section_count <= 1U, + "[Multiboot Reader] ELF Specifications allows only (1) or less dynamic sections, but got (%u)", + dynamic_section_count); } } // namespace diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 0dbbae1..30a8961 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -36,7 +36,7 @@ namespace teachos::arch::memory::paging auto entry::set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void { exception_handling::assert((frame.start_address() & ~0x000fffff'fffff000) == 0, - "Start address is not aligned with Page"); + "[Paging Entry] Start address is not aligned with page"); flags = std::bitset<64U>(frame.start_address()) | additional_flags; } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index eb1e18c..8c64f22 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -81,28 +81,26 @@ namespace teachos::arch::memory::paging allocator::physical_frame const & frame, entry::bitset flags) -> void { page_table page_table{}; - bool is_valid = false; + bool table_exists = false; for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) { std::size_t level_index = page.get_level_index(level); - is_valid = page_table.next_table(level_index); + table_exists = page_table.next_table(level_index); - if (!is_valid) + if (!table_exists) { - break; + auto allocated_frame = allocator.allocate_frame(); + exception_handling::assert(!allocated_frame.has_value(), "[Page mapper]: Unable to allocate frame"); + page_table[level_index].set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); + page_table.zero_entries(); } - - auto allocated_frame = allocator.allocate_frame(); - exception_handling::assert(!allocated_frame.has_value(), "[Page mapper]: Unable to allocate frame"); - page_table[level_index].set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); - page_table.zero_entries(); } - entry page_table_entry = page_table[page.get_level_index(page_table::LEVEL1)]; - arch::exception_handling::assert(!page_table_entry.contains_flags(entry::HUGE_PAGE), + auto level1_entry = page_table[page.get_level_index(page_table::LEVEL1)]; + arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), "[Page Mapper]: Unable to map huge pages"); - arch::exception_handling::assert(!page_table_entry.is_unused(), "[Page Mapper]: Page table entry is already used"); - page_table_entry.set_entry(frame, flags | entry::PRESENT); + arch::exception_handling::assert(!level1_entry.is_unused(), "[Page Mapper]: Page table entry is already used"); + level1_entry.set_entry(frame, flags | entry::PRESENT); } } // namespace teachos::arch::memory::paging \ No newline at end of file diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 02ababe..ea2e9c2 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -39,7 +39,7 @@ namespace teachos::arch::memory::paging { // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which // could be incredibly hard to debug later. - exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] index out of bounds"); + exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] Index out of bounds"); return current_table->entries[index]; } -- cgit v1.2.3 From 2129bdb22bab7dc5a9d23a31c23f38e847511a46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 20 Oct 2024 12:17:44 +0000 Subject: =?UTF-8?q?Revert=20assert=20with=20printf=20functionality,=20requ?= =?UTF-8?q?ires=20malloc=20=F0=9F=98=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- arch/x86_64/CMakeLists.txt | 1 + .../include/arch/exception_handling/assert.hpp | 44 ++-------------------- arch/x86_64/src/exception_handling/abort.cpp | 1 - arch/x86_64/src/exception_handling/assert.cpp | 13 +++++++ arch/x86_64/src/memory/multiboot/reader.cpp | 15 +++----- 5 files changed, 22 insertions(+), 52 deletions(-) create mode 100644 arch/x86_64/src/exception_handling/assert.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 645660a..8658ed7 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -57,6 +57,7 @@ target_sources("_memory" PRIVATE #]============================================================================] target_sources("_exception" PRIVATE + "src/exception_handling/assert.cpp" "src/exception_handling/abort.cpp" "src/exception_handling/panic.cpp" ) diff --git a/arch/x86_64/include/arch/exception_handling/assert.hpp b/arch/x86_64/include/arch/exception_handling/assert.hpp index 152e653..bfc205c 100644 --- a/arch/x86_64/include/arch/exception_handling/assert.hpp +++ b/arch/x86_64/include/arch/exception_handling/assert.hpp @@ -3,54 +3,16 @@ #include "arch/exception_handling/panic.hpp" -#include - namespace teachos::arch::exception_handling { - namespace - { - char constexpr FAILED_MESSAGE[] = "Invalid arguments passed to format specifiers (%) in exception_handling::assert"; - } - /** * @brief Assert a condition to be true, if not do not continue * execution of the code and print the formatted message to screen. * - * @param condition Condition we want to be true. - * @param format Formatting message that the given arguments will be inserted into. - * @param ...args Arguments that will be formatted and inserted into the resulting string, replacing their respective - * specifiers. Uses the printf specifiers see https://cplusplus.com/reference/cstdio/printf/ for more information. + * @param condition Condition we want to be true or else halt execution. + * @param message Message that should be printed before halting the execution if the condition is not met. */ - template - auto assert(bool condition, char const * format, Args const &... args) -> void - { - if (condition) - { - return; - } - else if constexpr (sizeof...(args) == 0) - { - panic("Assertion Violation: ", format); - } - - // Result is what would have been written if the passed buffer would have been large enough not counting null - // character, or if an error occured while creating the string a negative number is returned instead. To ensure this - // will not crash the system when creating an array with negative size we assert beforehand with a clear error - // message. - int const size = snprintf(nullptr, 0U, format, args...) + 1U; - if (size < 0) - { - panic("Assertion Violation: ", FAILED_MESSAGE); - } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wvla" - char arguments[size] = {}; -#pragma GCC diagnostic pop - int const written_characters = snprintf(arguments, size, format, args...); - // Written characters is expected to be one less, because of the null termination character. - bool const result = (written_characters == (size - 1)); - panic("Assertion Violation: ", result ? arguments : FAILED_MESSAGE); - } + auto assert(bool condition, char const * message) -> void; } // namespace teachos::arch::exception_handling #endif diff --git a/arch/x86_64/src/exception_handling/abort.cpp b/arch/x86_64/src/exception_handling/abort.cpp index 77576b1..e331d34 100644 --- a/arch/x86_64/src/exception_handling/abort.cpp +++ b/arch/x86_64/src/exception_handling/abort.cpp @@ -12,5 +12,4 @@ namespace teachos::arch::exception_handling * 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 new file mode 100644 index 0000000..b36f52d --- /dev/null +++ b/arch/x86_64/src/exception_handling/assert.cpp @@ -0,0 +1,13 @@ +#include "arch/exception_handling/assert.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/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp index 4e78a06..545e517 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -20,8 +20,7 @@ namespace teachos::arch::memory::multiboot auto expected_entry_size = mminfo->entry_size; constexpr auto actual_entry_size = sizeof(memory_area); exception_handling::assert(expected_entry_size == actual_entry_size, - "[Multiboot Reader] Expected memory area entry size (%u) but got (%u)", - expected_entry_size, actual_entry_size); + "[Multiboot Reader] Unexpected memory area entry size"); auto total_size = mminfo->info.size; auto total_entries_size = total_size - sizeof(memory_map_header) + actual_entry_size; @@ -37,16 +36,14 @@ namespace teachos::arch::memory::multiboot auto expected_entry_size = symbol->entry_size; constexpr auto actual_entry_size = sizeof(elf_section_header); exception_handling::assert(expected_entry_size == actual_entry_size, - "[Multiboot Reader] Expected elf section header entry size (%u) but got (%u)", - expected_entry_size, actual_entry_size); + "[Multiboot Reader] Unexpected elf section header entry size"); auto expected_total_size = symbol->info.size; auto actual_total_entry_size = actual_entry_size * symbol->number_of_sections; constexpr auto actual_total_section_size = sizeof(elf_symbols_section_header) - sizeof(uint32_t); auto actual_total_size = actual_total_entry_size + actual_total_section_size; exception_handling::assert(expected_total_size == actual_total_size, - "[Multiboot Reader] Expected elf symbols section header total size (%u) but got (%u)", - expected_total_size, actual_total_size); + "[Multiboot Reader] Unexpected elf symbols section header total size"); auto begin = reinterpret_cast(&symbol->end); auto end = begin + symbol->number_of_sections; @@ -87,12 +84,10 @@ namespace teachos::arch::memory::multiboot exception_handling::assert( symbol_table_section_count == 1U, - "[Multiboot Reader] ELF Specifications allows only (1) symbol table section, but got (%u)", - symbol_table_section_count); + "[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 (%u)", - dynamic_section_count); + "[Multiboot Reader] ELF Specifications allows only (1) or less dynamic sections, but got more"); } } // namespace -- cgit v1.2.3 From aa0634589cb7d51f57e3e555bb15ebca99bc162e Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 20 Oct 2024 12:17:58 +0000 Subject: document page mapping and entry --- arch/x86_64/include/arch/memory/paging/page_entry.hpp | 3 ++- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 12 +++++++----- arch/x86_64/src/memory/paging/page_entry.cpp | 4 ++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 109735d..2d97d77 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -59,8 +59,9 @@ namespace teachos::arch::memory::paging * calculate_physical_address() will return the new address instead of the old one. * * @param frame Physical frame that contains the address we want to copy into our underlying std::bitset. + * @param flags Entry flags which will be set on the entry */ - auto set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void; + auto set_entry(allocator::physical_frame frame, std::bitset<64U> flags) -> void; /** * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index c82b08c..069161f 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -34,13 +34,15 @@ namespace teachos::arch::memory::paging auto translate_address(std::size_t virtual_address) -> std::optional; /** - * @brief TODO + * @brief Maps a virtual page to a physical frame in the page table with the specified flags. * - * @param allocator - * @param page - * @param frame - * @param flags + * @param allocator Reference to the area frame allocator, which is used to allocate frames when a new page table is + * required. + * @param page Reference to the virtual page that is being mapped. + * @param frame The physical frame that the virtual page will be mapped to. + * @param flags A bitset of flags that configure the page table entry for this mapping. */ + auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, virtual_page const & page, memory::allocator::physical_frame const & frame, entry::bitset flags) -> void; } // 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 index 30a8961..8a7442e 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -33,10 +33,10 @@ namespace teachos::arch::memory::paging 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 + auto entry::set_entry(allocator::physical_frame frame, std::bitset<64U> flags) -> void { exception_handling::assert((frame.start_address() & ~0x000fffff'fffff000) == 0, "[Paging Entry] Start address is not aligned with page"); - flags = std::bitset<64U>(frame.start_address()) | additional_flags; + flags = std::bitset<64U>(frame.start_address()) | flags; } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 8e9a924f9fba18de9a5e37b1baf1d97e9b008251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 20 Oct 2024 12:21:57 +0000 Subject: Fix useless copy by reference --- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 7 +++---- arch/x86_64/src/memory/paging/page_mapper.cpp | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 069161f..699d517 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -42,9 +42,8 @@ namespace teachos::arch::memory::paging * @param frame The physical frame that the virtual page will be mapped to. * @param flags A bitset of flags that configure the page table entry for this mapping. */ - - auto map_page_to_frame(memory::allocator::area_frame_allocator & allocator, virtual_page const & page, - memory::allocator::physical_frame const & frame, entry::bitset flags) -> void; + auto map_page_to_frame(allocator::area_frame_allocator & allocator, virtual_page page, + allocator::physical_frame frame, entry::bitset flags) -> void; } // namespace teachos::arch::memory::paging -#endif \ No newline at end of file +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 8c64f22..1912174 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -77,8 +77,8 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto map_page_to_frame(allocator::area_frame_allocator & allocator, virtual_page const & page, - allocator::physical_frame const & frame, entry::bitset flags) -> void + auto map_page_to_frame(allocator::area_frame_allocator & allocator, virtual_page page, + allocator::physical_frame frame, entry::bitset flags) -> void { page_table page_table{}; bool table_exists = false; -- cgit v1.2.3 From dd5dab7fd34c6745a16ac572ecd099e4bc26c1fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 20 Oct 2024 12:35:39 +0000 Subject: Fix set_entry flags usage --- arch/x86_64/include/arch/memory/paging/page_entry.hpp | 6 +++--- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 2 +- arch/x86_64/src/memory/paging/page_entry.cpp | 2 +- arch/x86_64/src/memory/paging/page_mapper.cpp | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 2d97d77..158af2e 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -55,11 +55,11 @@ namespace teachos::arch::memory::paging auto calculate_pointed_to_frame() const -> std::optional; /** - * @brief Copies the address from the given physical frame into the underlying std::bitset so future calls to - * calculate_physical_address() will return the new address instead of the old one. + * @brief Copies the address and flags from the given physical frame into the underlying std::bitset so future calls + * to calculate_physical_address() will return the new address and flags instead of the old one. * * @param frame Physical frame that contains the address we want to copy into our underlying std::bitset. - * @param flags Entry flags which will be set on the entry + * @param flags Entry flags which will be copied into our underlying std::bitset. */ auto set_entry(allocator::physical_frame frame, std::bitset<64U> flags) -> void; diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 699d517..635a848 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -43,7 +43,7 @@ namespace teachos::arch::memory::paging * @param flags A bitset of flags that configure the page table entry for this mapping. */ auto map_page_to_frame(allocator::area_frame_allocator & allocator, virtual_page page, - allocator::physical_frame frame, entry::bitset flags) -> void; + allocator::physical_frame frame, std::bitset<64U> flags) -> void; } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 8a7442e..a172ca8 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -37,6 +37,6 @@ namespace teachos::arch::memory::paging { exception_handling::assert((frame.start_address() & ~0x000fffff'fffff000) == 0, "[Paging Entry] Start address is not aligned with page"); - flags = std::bitset<64U>(frame.start_address()) | flags; + flags = std::bitset<64U>{frame.start_address()} | flags; } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 1912174..0874230 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -78,7 +78,7 @@ namespace teachos::arch::memory::paging } auto map_page_to_frame(allocator::area_frame_allocator & allocator, virtual_page page, - allocator::physical_frame frame, entry::bitset flags) -> void + allocator::physical_frame frame, std::bitset<64U> flags) -> void { page_table page_table{}; bool table_exists = false; @@ -101,6 +101,6 @@ namespace teachos::arch::memory::paging arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), "[Page Mapper]: Unable to map huge pages"); arch::exception_handling::assert(!level1_entry.is_unused(), "[Page Mapper]: Page table entry is already used"); - level1_entry.set_entry(frame, flags | entry::PRESENT); + level1_entry.set_entry(frame, flags | std::bitset<64U>{entry::PRESENT}); } -} // namespace teachos::arch::memory::paging \ No newline at end of file +} // namespace teachos::arch::memory::paging -- cgit v1.2.3 From bb8b3f9c0734220702e3e930e7acb4906aa13db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 20 Oct 2024 12:48:51 +0000 Subject: Make map_page_to_frame use concept --- .../arch/memory/allocator/area_frame_allocator.hpp | 6 +++ .../include/arch/memory/paging/page_mapper.hpp | 43 ++++++++++++++++++---- arch/x86_64/src/memory/paging/page_mapper.cpp | 29 --------------- 3 files changed, 42 insertions(+), 36 deletions(-) diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp index c9d4e7f..f99b7c8 100644 --- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -8,6 +8,12 @@ namespace teachos::arch::memory::allocator { + template + concept FrameAllocator = requires(T t) { + { t.allocate_frame() } -> std::same_as>; + { t.deallocate_frame() } -> std::same_as; + }; + /** * @brief Allocates memory using memory areas read from the multiboot2 information pointer. */ diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 635a848..5bdd82a 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP +#include "arch/exception_handling/assert.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/paging/virtual_page.hpp" @@ -34,16 +35,44 @@ namespace teachos::arch::memory::paging auto translate_address(std::size_t virtual_address) -> std::optional; /** - * @brief Maps a virtual page to a physical frame in the page table with the specified flags. + * @brief Maps a virtual page to a physical frame in the page table with the specified flags. Allocates and maps an + * entry in every page level if it does not exists yet down to level 1. If the level 1 page table already exists it + * halts execution instead. * - * @param allocator Reference to the area frame allocator, which is used to allocate frames when a new page table is - * required. - * @param page Reference to the virtual page that is being mapped. - * @param frame The physical frame that the virtual page will be mapped to. + * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate entries + * when a new page table is required. + * @param page Virtual page that is being mapped. + * @param frame Physical frame that the virtual page will be mapped to. * @param flags A bitset of flags that configure the page table entry for this mapping. */ - auto map_page_to_frame(allocator::area_frame_allocator & allocator, virtual_page page, - allocator::physical_frame frame, std::bitset<64U> flags) -> void; + template + auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, + std::bitset<64U> flags) -> void + + { + page_table page_table{}; + bool table_exists = false; + + for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) + { + std::size_t level_index = page.get_level_index(level); + table_exists = page_table.next_table(level_index); + + if (!table_exists) + { + auto allocated_frame = allocator.allocate_frame(); + exception_handling::assert(!allocated_frame.has_value(), "[Page mapper]: Unable to allocate frame"); + page_table[level_index].set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); + page_table.zero_entries(); + } + } + + auto level1_entry = page_table[page.get_level_index(page_table::LEVEL1)]; + arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), + "[Page Mapper]: Unable to map huge pages"); + arch::exception_handling::assert(!level1_entry.is_unused(), "[Page Mapper]: Page table entry is already used"); + level1_entry.set_entry(frame, flags | std::bitset<64U>{entry::PRESENT}); + } } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 0874230..5b72a63 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -1,7 +1,5 @@ #include "arch/memory/paging/page_mapper.hpp" -#include "arch/exception_handling/assert.hpp" - namespace teachos::arch::memory::paging { auto translate_page(virtual_page page) -> std::optional @@ -76,31 +74,4 @@ namespace teachos::arch::memory::paging return std::nullopt; } - - auto map_page_to_frame(allocator::area_frame_allocator & allocator, virtual_page page, - allocator::physical_frame frame, std::bitset<64U> flags) -> void - { - page_table page_table{}; - bool table_exists = false; - - for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) - { - std::size_t level_index = page.get_level_index(level); - table_exists = page_table.next_table(level_index); - - if (!table_exists) - { - auto allocated_frame = allocator.allocate_frame(); - exception_handling::assert(!allocated_frame.has_value(), "[Page mapper]: Unable to allocate frame"); - page_table[level_index].set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); - page_table.zero_entries(); - } - } - - auto level1_entry = page_table[page.get_level_index(page_table::LEVEL1)]; - arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), - "[Page Mapper]: Unable to map huge pages"); - arch::exception_handling::assert(!level1_entry.is_unused(), "[Page Mapper]: Page table entry is already used"); - level1_entry.set_entry(frame, flags | std::bitset<64U>{entry::PRESENT}); - } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 1b03bcecac1276b486e17daf0384de7fa203d974 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 20 Oct 2024 12:57:21 +0000 Subject: create active_page_table --- .../arch/memory/paging/active_page_table.hpp | 31 ++++++++++++++++++++++ .../include/arch/memory/paging/page_mapper.hpp | 1 - .../x86_64/src/memory/paging/active_page_table.cpp | 31 ++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 arch/x86_64/include/arch/memory/paging/active_page_table.hpp create mode 100644 arch/x86_64/src/memory/paging/active_page_table.cpp diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp new file mode 100644 index 0000000..4a94b40 --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -0,0 +1,31 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP + +#include "arch/memory/paging/page_table.hpp" + +namespace teachos::arch::memory::paging +{ + + struct active_page_table + { + /** + * @brief Ensures only one instance of active_page_table exists. + * + * @param level4_page_table A pointer to the level 4 page table. + * @return The only instance of active_page_table. + */ + auto create(page_table * level4_page_table) -> active_page_table *; + + private: + /** + * @brief Construct a new active page table object. + * + * @param level4_page_table A pointer to the level 4 page table. + */ + active_page_table(page_table * level4_page_table); + + bool instantiated = false; ///< Indicates wether an instance already exists. + page_table * level4_page_table; ///< The active level4 page table. + }; +} // namespace teachos::arch::memory::paging +#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 5bdd82a..ae3502e 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -48,7 +48,6 @@ namespace teachos::arch::memory::paging template auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, std::bitset<64U> flags) -> void - { page_table page_table{}; bool table_exists = false; diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp new file mode 100644 index 0000000..eb85c34 --- /dev/null +++ b/arch/x86_64/src/memory/paging/active_page_table.cpp @@ -0,0 +1,31 @@ +#include "arch/memory/paging/active_page_table.hpp" + +namespace teachos::arch::memory::paging +{ + struct active_page_table + { + auto create(page_table * level4_page_table) -> active_page_table * + { + if (instantiated) + { + return this; + } + + instantiated = true; + return &active_page_table(level4_page_table); + } + + active_page_table(const active_page_table &) = delete; + active_page_table & operator=(const active_page_table &) = delete; + + private: + active_page_table(page_table * level4_page_table) + : level4_page_table(level4_page_table) + { + // Nothing to do + } + + bool instantiated = false; + page_table * level4_page_table; + }; +} // namespace teachos::arch::memory::paging \ No newline at end of file -- cgit v1.2.3 From 49ae81912f3a440f1958e86296d468ec669f71a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 20 Oct 2024 13:17:24 +0000 Subject: Fix active page table cpp --- .../arch/memory/paging/active_page_table.hpp | 3 +- .../x86_64/src/memory/paging/active_page_table.cpp | 34 ++++++++-------------- 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index 4a94b40..3933d5a 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -28,4 +28,5 @@ namespace teachos::arch::memory::paging page_table * level4_page_table; ///< The active level4 page table. }; } // namespace teachos::arch::memory::paging -#endif \ No newline at end of file + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp index eb85c34..ec89e0e 100644 --- a/arch/x86_64/src/memory/paging/active_page_table.cpp +++ b/arch/x86_64/src/memory/paging/active_page_table.cpp @@ -2,30 +2,20 @@ namespace teachos::arch::memory::paging { - struct active_page_table + auto active_page_table::create(page_table * level4_page_table) -> active_page_table * { - auto create(page_table * level4_page_table) -> active_page_table * + if (instantiated) { - if (instantiated) - { - return this; - } - - instantiated = true; - return &active_page_table(level4_page_table); + return this; } - active_page_table(const active_page_table &) = delete; - active_page_table & operator=(const active_page_table &) = delete; + instantiated = true; + return &active_page_table(level4_page_table); + } - private: - active_page_table(page_table * level4_page_table) - : level4_page_table(level4_page_table) - { - // Nothing to do - } - - bool instantiated = false; - page_table * level4_page_table; - }; -} // namespace teachos::arch::memory::paging \ No newline at end of file + active_page_table::active_page_table(page_table * level4_page_table) + : level4_page_table(level4_page_table) + { + // Nothing to do + } +} // namespace teachos::arch::memory::paging -- cgit v1.2.3 From f171efed99684bf03c315405efda34e36d7db82c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 21 Oct 2024 09:31:58 +0000 Subject: Ensure only one instance of global page table can exist --- .../arch/memory/paging/active_page_table.hpp | 32 -------- .../include/arch/memory/paging/page_mapper.hpp | 41 +++++++--- .../include/arch/memory/paging/page_table.hpp | 28 +++---- arch/x86_64/src/kernel/main.cpp | 2 +- .../x86_64/src/memory/paging/active_page_table.cpp | 21 ----- arch/x86_64/src/memory/paging/page_mapper.cpp | 91 +++++++++++++--------- arch/x86_64/src/memory/paging/page_table.cpp | 28 +++---- 7 files changed, 104 insertions(+), 139 deletions(-) delete mode 100644 arch/x86_64/include/arch/memory/paging/active_page_table.hpp delete mode 100644 arch/x86_64/src/memory/paging/active_page_table.cpp diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp deleted file mode 100644 index 3933d5a..0000000 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP - -#include "arch/memory/paging/page_table.hpp" - -namespace teachos::arch::memory::paging -{ - - struct active_page_table - { - /** - * @brief Ensures only one instance of active_page_table exists. - * - * @param level4_page_table A pointer to the level 4 page table. - * @return The only instance of active_page_table. - */ - auto create(page_table * level4_page_table) -> active_page_table *; - - private: - /** - * @brief Construct a new active page table object. - * - * @param level4_page_table A pointer to the level 4 page table. - */ - active_page_table(page_table * level4_page_table); - - bool instantiated = false; ///< Indicates wether an instance already exists. - page_table * level4_page_table; ///< The active level4 page table. - }; -} // namespace teachos::arch::memory::paging - -#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index ae3502e..ebd044a 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -9,6 +9,15 @@ namespace teachos::arch::memory::paging { + /** + * @brief Creates a single instance of the level 4 page table table and returns it or alternatively returns the + * previously created instance. The instance is owned by this method and is static, meaning it lives on for the + * complete lifetime of the program. + * + * @return Single unique instance of the level 4 page table. + */ + auto create_or_get() -> page_table *; + /** * @brief Translates page into physical frame, will first attempt to parse normally using default page size and if it * failed attempt to parse using huge pages. @@ -49,27 +58,35 @@ namespace teachos::arch::memory::paging auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, std::bitset<64U> flags) -> void { - page_table page_table{}; - bool table_exists = false; + page_table * current_page_table = create_or_get(); for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) { - std::size_t level_index = page.get_level_index(level); - table_exists = page_table.next_table(level_index); - - if (!table_exists) + auto level_index = page.get_level_index(level); + auto next_page_table = current_page_table->next_table(level_index); + // If the next table method failed then it means that the page level of the frame we want allocate has not yet + // been created itself. So we have to do that before we are able to allocate the wanted frame. This has to be done + // for every level, meaning we potenitally create a level 4, level 3 and level 2 page entry, each pointing to a + // page table one level below. + if (!next_page_table) { auto allocated_frame = allocator.allocate_frame(); - exception_handling::assert(!allocated_frame.has_value(), "[Page mapper]: Unable to allocate frame"); - page_table[level_index].set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); - page_table.zero_entries(); + exception_handling::assert(!allocated_frame.has_value(), "[Page mapper] Unable to allocate frame"); + current_page_table->operator[](level_index) + .set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); + // There should now be an entry at the previously not existent index, therefore we can simply access it again. + next_page_table = current_page_table->next_table(page.get_level_index(level)); + exception_handling::assert(!next_page_table.has_value(), + "[Page mapper] Unable to create new entry into page table"); + next_page_table.value()->zero_entries(); } + current_page_table = next_page_table.value(); } - auto level1_entry = page_table[page.get_level_index(page_table::LEVEL1)]; + auto level1_entry = current_page_table->operator[](page.get_level_index(page_table::LEVEL1)); arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), - "[Page Mapper]: Unable to map huge pages"); - arch::exception_handling::assert(!level1_entry.is_unused(), "[Page Mapper]: Page table entry is already used"); + "[Page Mapper] Unable to map huge pages"); + arch::exception_handling::assert(!level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); level1_entry.set_entry(frame, flags | std::bitset<64U>{entry::PRESENT}); } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 0fe667c..3439127 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -10,16 +10,6 @@ namespace teachos::arch::memory::paging constexpr std::size_t PAGE_TABLE_ENTRY_COUNT = 512U; ///< Default entry count of a page table in x86_84 is 512. } - /** - * @brief Actual data that is contained in every page table, this is the structure we cast a specific address too, - * because it consists of x amount os entries, which is a simple address. - */ - struct table_content - { - entry entries[PAGE_TABLE_ENTRY_COUNT]; ///< Entries containing addresses to page tables of a level below or actual - ///< virtual addresses for the level 1 page table. - }; - /** * @brief A Page table containing 512 entries. */ @@ -38,9 +28,10 @@ namespace teachos::arch::memory::paging }; /** - * @brief Constructor. Automatically starts on the fixed address of the Level 4 page table. + * @brief Deleted constructor. Object can only be created by casting from the fixed Level 4 + * page table address `reinterpret_cast(0xfffffffffffff000)`. */ - page_table(); + page_table() = delete; /** * @brief Set every entry of the page to unused. @@ -48,13 +39,13 @@ namespace teachos::arch::memory::paging auto zero_entries() -> void; /** - * @brief Turn this page table into the next page table level from the given page table index. Meaning we - * use an index into a Level 4 page table to get the according Level 3 page table. When using this on an a level 1 - * page table it will cause an assertion. + * @brief Returns the next page table level from the given page table index. Meaning we + * use an index into a Level 4 page table to get the according Level 3 page table. This method should not be called + * on a Level 1 page table or it will return invalid addresses and cause hard to debug issues. * * @param table_index Index of this page table in the page table one level higher. */ - auto next_table(std::size_t table_index) -> bool; + auto next_table(std::size_t table_index) -> std::optional; /** * @brief Index operator overload to access specific mutable entry directy. @@ -83,9 +74,8 @@ namespace teachos::arch::memory::paging */ auto next_table_address(std::size_t table_index) -> std::optional; - level current_level; ///< Current level of the page table, used to ensure next_table() is never called with a level - ///< 1 page table - table_content * current_table; ///< Current table we are accessing and indexing. + entry entries[PAGE_TABLE_ENTRY_COUNT]; ///< Entries containing addresses to page tables of a level below or actual + ///< virtual addresses for the level 1 page table. }; auto operator--(page_table::level & level, int) -> page_table::level; diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 40dd117..db0a9ef 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -26,7 +26,7 @@ namespace teachos::arch::kernel { last_allocated = allocated; allocated = allocator.allocate_frame(); - } while (allocated.has_value()); + } while (allocated); video::vga::text::write("Allocated Frames", video::vga::text::common_attributes::green_on_black); video::vga::text::write_number(last_allocated.value().frame_number, video::vga::text::common_attributes::green_on_black); 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 ec89e0e..0000000 --- a/arch/x86_64/src/memory/paging/active_page_table.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "arch/memory/paging/active_page_table.hpp" - -namespace teachos::arch::memory::paging -{ - auto active_page_table::create(page_table * level4_page_table) -> active_page_table * - { - if (instantiated) - { - return this; - } - - instantiated = true; - return &active_page_table(level4_page_table); - } - - active_page_table::active_page_table(page_table * level4_page_table) - : level4_page_table(level4_page_table) - { - // Nothing to do - } -} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 5b72a63..cedda54 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -2,60 +2,79 @@ namespace teachos::arch::memory::paging { + namespace + { + constexpr size_t PAGE_TABLE_LEVEL_4_ADDRESS = 0xfffffffffffff000; + } + + auto create_or_get() -> page_table * + { + static bool instantiated = false; + static page_table * active_page = nullptr; + + if (instantiated) + { + return active_page; + } + + instantiated = true; + active_page = reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS); + return active_page; + } + auto translate_page(virtual_page page) -> std::optional { - page_table page_table{}; - bool is_valid = false; + page_table * current_page_table = create_or_get(); for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) { - is_valid = page_table.next_table(page.get_level_index(level)); - if (!is_valid) + auto next_page_table = current_page_table->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_page_table) { - break; + return translate_huge_page(page); } + current_page_table = next_page_table.value(); } - if (is_valid) - { - auto level1_index = page.get_level_index(page_table::LEVEL1); - auto level1_frame = page_table[level1_index].calculate_pointed_to_frame(); - return level1_frame; - } - - return translate_huge_page(page); + auto level1_index = page.get_level_index(page_table::LEVEL1); + auto level1_frame = current_page_table->operator[](level1_index).calculate_pointed_to_frame(); + return level1_frame; } auto translate_huge_page(virtual_page page) -> std::optional { - page_table page_table{}; - bool is_valid = page_table.next_table(page.get_level_index(page_table::LEVEL3)); + page_table * current_page_table = create_or_get(); + auto level3_page_table = current_page_table->next_table(page.get_level_index(page_table::LEVEL4)); - if (is_valid) + if (!level3_page_table) { - auto level3_entry = page_table[page.get_level_index(page_table::LEVEL3)]; - auto level3_optional_frame = level3_entry.calculate_pointed_to_frame(); - if (level3_optional_frame.has_value() && level3_entry.contains_flags(entry::HUGE_PAGE)) - { - auto level3_frame = level3_optional_frame.value(); - exception_handling::assert(level3_frame.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.frame_number + - page.get_level_index(page_table::LEVEL2) * PAGE_TABLE_ENTRY_COUNT + - page.get_level_index(page_table::LEVEL1)}; - } + return std::nullopt; } - is_valid = page_table.next_table(page.get_level_index(page_table::LEVEL3)); - if (is_valid) + + auto level3_entry = level3_page_table.value()->operator[](page.get_level_index(page_table::LEVEL3)); + auto level3_frame = level3_entry.calculate_pointed_to_frame(); + if (level3_frame && 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::LEVEL2) * PAGE_TABLE_ENTRY_COUNT + + page.get_level_index(page_table::LEVEL1)}; + } + + auto level2_page_table = level3_page_table.value()->next_table(page.get_level_index(page_table::LEVEL3)); + if (level2_page_table) { - auto level2_entry = page_table[page.get_level_index(page_table::LEVEL2)]; - auto level2_optional_frame = level2_entry.calculate_pointed_to_frame(); - if (level2_optional_frame.has_value() && level2_entry.contains_flags(entry::HUGE_PAGE)) + auto level2_entry = level2_page_table.value()->operator[](page.get_level_index(page_table::LEVEL2)); + auto level2_frame = level2_entry.calculate_pointed_to_frame(); + if (level2_frame && level2_entry.contains_flags(entry::HUGE_PAGE)) { - auto level2_frame = level2_optional_frame.value(); - exception_handling::assert(level2_frame.frame_number % PAGE_TABLE_ENTRY_COUNT == 0U, + 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.frame_number + page.get_level_index(page_table::LEVEL1)}; + return allocator::physical_frame{level2_frame.value().frame_number + page.get_level_index(page_table::LEVEL1)}; } } return std::nullopt; @@ -67,7 +86,7 @@ namespace teachos::arch::memory::paging virtual_page page = virtual_page::containing_address(virtual_address); std::optional frame = translate_page(page); - if (frame.has_value()) + if (frame) { return frame.value().frame_number * allocator::PAGE_FRAME_SIZE + offset; } diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index ea2e9c2..5daf8bb 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -4,16 +4,9 @@ namespace teachos::arch::memory::paging { - page_table::page_table() - : current_level(LEVEL4) - , current_table(reinterpret_cast(0xfffffffffffff000)) - { - // Nothing to do - } - auto page_table::zero_entries() -> void { - constexpr size_t entry_amount = sizeof(current_table->entries) / sizeof(current_table->entries[0]); + constexpr size_t entry_amount = sizeof(entries) / sizeof(entries[0]); for (size_t i = 0; i < entry_amount; ++i) { auto entry = this->operator[](i); @@ -21,18 +14,17 @@ namespace teachos::arch::memory::paging } } - auto page_table::next_table(std::size_t table_index) -> bool + auto page_table::next_table(std::size_t table_index) -> std::optional { - exception_handling::assert(current_level != LEVEL1, - "[Page Table] Attempted to call next_table on level 1 page table"); + // TODO: Find another way to ensure the current page table is not LEVEL1 + // exception_handling::assert(current_level != LEVEL1, "[Page Table] Attempted to call next_table on level 1 page + // table"); auto address = next_table_address(table_index); - bool const success = address.has_value(); - if (success) + if (address) { - current_table = reinterpret_cast(address.value()); - current_level = static_cast(current_level - 1U); + return reinterpret_cast(address.value()); } - return success; + return std::nullopt; } auto page_table::operator[](std::size_t index) -> entry & @@ -40,7 +32,7 @@ namespace teachos::arch::memory::paging // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which // could be incredibly hard to debug later. exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] Index out of bounds"); - return current_table->entries[index]; + return entries[index]; } auto page_table::next_table_address(std::size_t table_index) -> std::optional @@ -49,7 +41,7 @@ namespace teachos::arch::memory::paging if (entry.contains_flags(entry::PRESENT) && !entry.contains_flags(entry::HUGE_PAGE)) { - std::size_t const table_address = reinterpret_cast(current_table); + std::size_t const table_address = reinterpret_cast(this); return ((table_address << 9) | (table_index << 12)); } return std::nullopt; -- cgit v1.2.3 From 72cb015567cb65527e9105e653c001be3c04eab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 21 Oct 2024 12:03:21 +0000 Subject: Use handle struct to ensure next_table is not called on page table level 1 --- .../include/arch/exception_handling/assert.hpp | 2 - .../arch/memory/allocator/area_frame_allocator.hpp | 6 +- .../include/arch/memory/paging/page_mapper.hpp | 29 +++++----- .../include/arch/memory/paging/page_table.hpp | 65 ++++++++++++++++------ .../include/arch/memory/paging/virtual_page.hpp | 2 +- arch/x86_64/src/exception_handling/assert.cpp | 2 + arch/x86_64/src/kernel/main.cpp | 8 +-- arch/x86_64/src/memory/paging/page_mapper.cpp | 37 +++++------- arch/x86_64/src/memory/paging/page_table.cpp | 34 ++++++++--- 9 files changed, 114 insertions(+), 71 deletions(-) diff --git a/arch/x86_64/include/arch/exception_handling/assert.hpp b/arch/x86_64/include/arch/exception_handling/assert.hpp index bfc205c..58c1f33 100644 --- a/arch/x86_64/include/arch/exception_handling/assert.hpp +++ b/arch/x86_64/include/arch/exception_handling/assert.hpp @@ -1,8 +1,6 @@ #ifndef TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP #define TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP -#include "arch/exception_handling/panic.hpp" - namespace teachos::arch::exception_handling { /** diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp index f99b7c8..7b1bb16 100644 --- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -1,17 +1,17 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP #define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP +#include "arch/memory/allocator/physical_frame.hpp" #include "arch/memory/multiboot/reader.hpp" -#include "physical_frame.hpp" #include namespace teachos::arch::memory::allocator { template - concept FrameAllocator = requires(T t) { + concept FrameAllocator = requires(T t, physical_frame a) { { t.allocate_frame() } -> std::same_as>; - { t.deallocate_frame() } -> std::same_as; + { t.deallocate_frame(a) } -> std::same_as; }; /** diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index ebd044a..a874f75 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -10,13 +10,13 @@ namespace teachos::arch::memory::paging { /** - * @brief Creates a single instance of the level 4 page table table and returns it or alternatively returns the - * previously created instance. The instance is owned by this method and is static, meaning it lives on for the - * complete lifetime of the program. + * @brief Creates a single instance of the level 4 page table table and returns handle to it or alternatively returns + * the previously created handle instead. The instance is owned by this method and is static, meaning it lives on for + * the complete lifetime of the program. * - * @return Single unique instance of the level 4 page table. + * @return Handle to the single unique instance of the level 4 page table. */ - auto create_or_get() -> page_table *; + auto create_or_get() -> page_table_handle; /** * @brief Translates page into physical frame, will first attempt to parse normally using default page size and if it @@ -58,32 +58,31 @@ namespace teachos::arch::memory::paging auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, std::bitset<64U> flags) -> void { - page_table * current_page_table = create_or_get(); + auto current_handle = create_or_get(); for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) { auto level_index = page.get_level_index(level); - auto next_page_table = current_page_table->next_table(level_index); + auto next_handle = current_handle.next_table(level_index); // If the next table method failed then it means that the page level of the frame we want allocate has not yet // been created itself. So we have to do that before we are able to allocate the wanted frame. This has to be done // for every level, meaning we potenitally create a level 4, level 3 and level 2 page entry, each pointing to a // page table one level below. - if (!next_page_table) + if (!next_handle) { auto allocated_frame = allocator.allocate_frame(); exception_handling::assert(!allocated_frame.has_value(), "[Page mapper] Unable to allocate frame"); - current_page_table->operator[](level_index) - .set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); + current_handle[level_index].set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); // There should now be an entry at the previously not existent index, therefore we can simply access it again. - next_page_table = current_page_table->next_table(page.get_level_index(level)); - exception_handling::assert(!next_page_table.has_value(), + next_handle = current_handle.next_table(page.get_level_index(level)); + exception_handling::assert(!next_handle.has_value(), "[Page mapper] Unable to create new entry into page table"); - next_page_table.value()->zero_entries(); + next_handle.value().zero_entries(); } - current_page_table = next_page_table.value(); + current_handle = next_handle.value(); } - auto level1_entry = current_page_table->operator[](page.get_level_index(page_table::LEVEL1)); + auto level1_entry = current_handle[page.get_level_index(page_table::LEVEL1)]; arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), "[Page Mapper] Unable to map huge pages"); arch::exception_handling::assert(!level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 3439127..a1c8abe 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP -#include "page_entry.hpp" +#include "arch/memory/paging/page_entry.hpp" namespace teachos::arch::memory::paging { @@ -41,27 +41,20 @@ namespace teachos::arch::memory::paging /** * @brief Returns the next page table level from the given page table index. Meaning we * use an index into a Level 4 page table to get the according Level 3 page table. This method should not be called - * on a Level 1 page table or it will return invalid addresses and cause hard to debug issues. + * on a Level 1 page table, because there is no furthere page table and mangeling up and returning the physical + * address would cause hard to debug issues. * - * @param table_index Index of this page table in the page table one level higher. + * @param table_index Index of this page table in the page table one level lower. */ - auto next_table(std::size_t table_index) -> std::optional; + auto next_table(std::size_t table_index) const -> std::optional; /** - * @brief Index operator overload to access specific mutable entry directy. + * @brief Index operator overload to access specific entries directy. * - * @param index Index of the entry we want to access and change. + * @param index Index of the entry we want to access and read or write too. * @return Entry at the given table index. */ - auto operator[](std::size_t index) -> entry &; - - /** - * @brief Index operator overload to access specific immutable entry directy. - * - * @param index Index of the entry we want to access and only read. - * @return Entry at the given table index. - */ - auto operator[](std::size_t index) const -> entry const &; + auto operator[](std::size_t index) const -> entry; private: /** @@ -72,13 +65,53 @@ namespace teachos::arch::memory::paging * @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) -> std::optional; + auto next_table_address(std::size_t table_index) const -> std::optional; entry entries[PAGE_TABLE_ENTRY_COUNT]; ///< Entries containing addresses to page tables of a level below or actual ///< virtual addresses for the level 1 page table. }; auto operator--(page_table::level & level, int) -> page_table::level; + + /** + * @brief Handle that ensures accessing the page table is safe because it adds additional checks to the next_table + * method and ensures it can only be called if the table level is not LEVEL1. + */ + struct page_table_handle + { + /** + * @brief Constructor. + */ + page_table_handle(page_table * handle, page_table::level handle_level); + + /** + * @brief Set every entry of the page to unused. + */ + auto zero_entries() -> void; + + /** + * @brief Returns the next page table level from the given page table index. Meaning we + * use an index into a Level 4 page table to get the according Level 3 page table. If this method is called with a + * Level 1 page table it will instead assert and halt execution, because there is no furthere page table and + * mangeling up and returning the physical address would cause hard to debug issues. + * + * @param table_index Index of this page table in the page table one level lower. + */ + auto next_table(std::size_t table_index) const -> std::optional; + + /** + * @brief Index operator overload to access specific immutable entry directy. + * + * @param index Index of the entry we want to access and only read. + * @return Entry at the given table index. + */ + auto operator[](std::size_t index) const -> entry; + + private: + page_table * handle; ///< Handle to underlying page table, can never be null (invariant ensured by constructor) + page_table::level handle_level; ///< Level page table is currently on, depends on how often next_level was + ///< called successfully. + }; } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index 6b9a641..f8dfbf0 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -2,8 +2,8 @@ #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP #include "arch/memory/allocator/physical_frame.hpp" +#include "arch/memory/paging/page_table.hpp" -#include "page_table.hpp" #include #include #include diff --git a/arch/x86_64/src/exception_handling/assert.cpp b/arch/x86_64/src/exception_handling/assert.cpp index b36f52d..b2963de 100644 --- a/arch/x86_64/src/exception_handling/assert.cpp +++ b/arch/x86_64/src/exception_handling/assert.cpp @@ -1,5 +1,7 @@ #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 diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index db0a9ef..88f6329 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -11,11 +11,9 @@ namespace teachos::arch::kernel { auto main() -> void { - using namespace video::vga; - - text::clear(); - text::cursor(false); - text::write("TeachOS is starting up...", text::common_attributes::green_on_black); + 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); auto memory_information = memory::multiboot::read_multiboot2(); memory::allocator::area_frame_allocator allocator(memory_information); diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index cedda54..01c39ca 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -7,53 +7,46 @@ namespace teachos::arch::memory::paging constexpr size_t PAGE_TABLE_LEVEL_4_ADDRESS = 0xfffffffffffff000; } - auto create_or_get() -> page_table * + auto create_or_get() -> page_table_handle { - static bool instantiated = false; - static page_table * active_page = nullptr; + static page_table_handle active_page{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS), + page_table::LEVEL4}; - if (instantiated) - { - return active_page; - } - - instantiated = true; - active_page = reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS); return active_page; } auto translate_page(virtual_page page) -> std::optional { - page_table * current_page_table = create_or_get(); + auto current_handle = create_or_get(); for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) { - auto next_page_table = current_page_table->next_table(page.get_level_index(level)); + auto 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_page_table) + if (!next_handle) { return translate_huge_page(page); } - current_page_table = next_page_table.value(); + current_handle = next_handle.value(); } auto level1_index = page.get_level_index(page_table::LEVEL1); - auto level1_frame = current_page_table->operator[](level1_index).calculate_pointed_to_frame(); + auto level1_frame = current_handle[level1_index].calculate_pointed_to_frame(); return level1_frame; } auto translate_huge_page(virtual_page page) -> std::optional { - page_table * current_page_table = create_or_get(); - auto level3_page_table = current_page_table->next_table(page.get_level_index(page_table::LEVEL4)); + auto current_handle = create_or_get(); + auto level3_handle = current_handle.next_table(page.get_level_index(page_table::LEVEL4)); - if (!level3_page_table) + if (!level3_handle) { return std::nullopt; } - auto level3_entry = level3_page_table.value()->operator[](page.get_level_index(page_table::LEVEL3)); + auto level3_entry = level3_handle.value()[page.get_level_index(page_table::LEVEL3)]; auto level3_frame = level3_entry.calculate_pointed_to_frame(); if (level3_frame && level3_entry.contains_flags(entry::HUGE_PAGE)) { @@ -65,10 +58,10 @@ namespace teachos::arch::memory::paging page.get_level_index(page_table::LEVEL1)}; } - auto level2_page_table = level3_page_table.value()->next_table(page.get_level_index(page_table::LEVEL3)); - if (level2_page_table) + auto level2_handle = level3_handle.value().next_table(page.get_level_index(page_table::LEVEL3)); + if (level2_handle) { - auto level2_entry = level2_page_table.value()->operator[](page.get_level_index(page_table::LEVEL2)); + auto level2_entry = level2_handle.value()[page.get_level_index(page_table::LEVEL2)]; auto level2_frame = level2_entry.calculate_pointed_to_frame(); if (level2_frame && level2_entry.contains_flags(entry::HUGE_PAGE)) { diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 5daf8bb..907b64f 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -14,11 +14,8 @@ namespace teachos::arch::memory::paging } } - auto page_table::next_table(std::size_t table_index) -> std::optional + auto page_table::next_table(std::size_t table_index) const -> std::optional { - // TODO: Find another way to ensure the current page table is not LEVEL1 - // exception_handling::assert(current_level != LEVEL1, "[Page Table] Attempted to call next_table on level 1 page - // table"); auto address = next_table_address(table_index); if (address) { @@ -27,7 +24,7 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto page_table::operator[](std::size_t index) -> entry & + auto page_table::operator[](std::size_t index) const -> entry { // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which // could be incredibly hard to debug later. @@ -35,7 +32,7 @@ namespace teachos::arch::memory::paging return entries[index]; } - auto page_table::next_table_address(std::size_t table_index) -> std::optional + auto page_table::next_table_address(std::size_t table_index) const -> std::optional { auto entry = this->operator[](table_index); @@ -47,11 +44,34 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto operator--(page_table::level & level, int) -> page_table::level + auto operator--(page_table::level level, int) -> page_table::level { exception_handling::assert(level != page_table::LEVEL1, "[Page table] Attemptd to decrement enum to value outside of range"); auto value = static_cast::type>(level); return static_cast(--value); } + + page_table_handle::page_table_handle(page_table * handle, page_table::level handle_level) + : handle(handle) + , handle_level(handle_level) + { + exception_handling::assert(handle, "[Page table] Attemptd to pass nullptr as handle to page table handle method"); + } + + auto page_table_handle::zero_entries() -> void { handle->zero_entries(); } + + auto page_table_handle::next_table(std::size_t table_index) const -> std::optional + { + exception_handling::assert(handle_level != page_table::LEVEL1, + "[Page Table] Attempted to call next_table on level 1 page table"); + auto next_table = handle->next_table(table_index); + if (next_table) + { + return page_table_handle{next_table.value(), handle_level--}; + } + return std::nullopt; + } + + auto page_table_handle::operator[](std::size_t index) const -> entry { return handle->operator[](index); } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 4b6e66f686a0341613a303b45e16e5bc744c32dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 21 Oct 2024 12:37:36 +0000 Subject: Fix weird linker error --- arch/x86_64/src/memory/paging/page_mapper.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 01c39ca..28e248b 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -9,10 +9,9 @@ namespace teachos::arch::memory::paging auto create_or_get() -> page_table_handle { - static page_table_handle active_page{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS), - page_table::LEVEL4}; - - return active_page; + static page_table * const active_page{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS)}; + // We can not save page_table_handle as a static variable directly, if we do the program will fail to link. + return page_table_handle{active_page, page_table::LEVEL4}; } auto translate_page(virtual_page page) -> std::optional -- cgit v1.2.3 From 552477a12a1163f0f80801b4055dcb5ab3f79e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 21 Oct 2024 12:53:23 +0000 Subject: Use forward declaration to hide actual page_table --- .../include/arch/memory/paging/page_mapper.hpp | 4 +- .../include/arch/memory/paging/page_table.hpp | 77 ++++++---------------- .../include/arch/memory/paging/virtual_page.hpp | 2 +- arch/x86_64/src/memory/paging/page_mapper.cpp | 21 +++--- arch/x86_64/src/memory/paging/page_table.cpp | 63 +++++++++++++++--- arch/x86_64/src/memory/paging/virtual_page.cpp | 2 +- 6 files changed, 87 insertions(+), 82 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index a874f75..0806f58 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -60,7 +60,7 @@ namespace teachos::arch::memory::paging { auto current_handle = create_or_get(); - for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; level--) { auto level_index = page.get_level_index(level); auto next_handle = current_handle.next_table(level_index); @@ -82,7 +82,7 @@ namespace teachos::arch::memory::paging current_handle = next_handle.value(); } - auto level1_entry = current_handle[page.get_level_index(page_table::LEVEL1)]; + auto level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), "[Page Mapper] Unable to map huge pages"); arch::exception_handling::assert(!level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index a1c8abe..91ce81c 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -11,12 +11,20 @@ namespace teachos::arch::memory::paging } /** - * @brief A Page table containing 512 entries. + * @brief Forward delcaration of the page_table, because it should only be accessible over the handle, the actual + * methods or constructor are not defined meaning they are not callable from outside. Instead the struct is only fully + * defined in the implementation (.cpp) file of the page table, and therefore also only accesible in that file. */ - struct page_table + struct page_table; + + /** + * @brief Handle that ensures accessing the page table is safe because it adds additional checks to the next_table + * method and ensures it can only be called if the table level is not LEVEL1. + */ + struct page_table_handle { /** - * @brief Level of the page table, level 1 should not be able to call next_table anymore, because it would result in + * @brief Level of the page table, level 1 will not be able to call next_table anymore, because it would result in * attempting to access memory that it should not. */ enum level : uint8_t @@ -27,62 +35,13 @@ namespace teachos::arch::memory::paging LEVEL4 }; - /** - * @brief Deleted constructor. Object can only be created by casting from the fixed Level 4 - * page table address `reinterpret_cast(0xfffffffffffff000)`. - */ - page_table() = delete; - - /** - * @brief Set every entry of the page to unused. - */ - auto zero_entries() -> void; - - /** - * @brief Returns the next page table level from the given page table index. Meaning we - * use an index into a Level 4 page table to get the according Level 3 page table. This method should not be called - * on a Level 1 page table, because there is no furthere page table and mangeling up and returning the physical - * address would cause hard to debug issues. - * - * @param table_index Index of this page table in the page table one level lower. - */ - auto next_table(std::size_t table_index) const -> std::optional; - - /** - * @brief Index operator overload to access specific entries directy. - * - * @param index Index of the entry we want to access and read or write too. - * @return Entry at the given table index. - */ - auto operator[](std::size_t index) const -> entry; - - private: - /** - * @brief Calculates the address of the next page table level for the given table index. 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; - - entry entries[PAGE_TABLE_ENTRY_COUNT]; ///< Entries containing addresses to page tables of a level below or actual - ///< virtual addresses for the level 1 page table. - }; - - auto operator--(page_table::level & level, int) -> page_table::level; - - /** - * @brief Handle that ensures accessing the page table is safe because it adds additional checks to the next_table - * method and ensures it can only be called if the table level is not LEVEL1. - */ - struct page_table_handle - { /** * @brief Constructor. + * + * @param handle Underlying page table the handle should point to. + * @param handle_level Level the underlying page table is on, used to ensure safety. */ - page_table_handle(page_table * handle, page_table::level handle_level); + page_table_handle(page_table * handle, level handle_level); /** * @brief Set every entry of the page to unused. @@ -109,9 +68,11 @@ namespace teachos::arch::memory::paging private: page_table * handle; ///< Handle to underlying page table, can never be null (invariant ensured by constructor) - page_table::level handle_level; ///< Level page table is currently on, depends on how often next_level was - ///< called successfully. + level handle_level; ///< Level page table is currently on, depends on how often next_level was + ///< called successfully. }; + + auto operator--(page_table_handle::level & level, int) -> page_table_handle::level; } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index f8dfbf0..ca11b3c 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -43,7 +43,7 @@ namespace teachos::arch::memory::paging * @param level Level of the page table we want to calculate the index for. * @return Index into the page table with the given level. */ - auto get_level_index(page_table::level level) const -> uint64_t; + auto get_level_index(page_table_handle::level level) const -> uint64_t; /** * @brief Defaulted equals operator. diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 28e248b..b8f6b89 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -11,14 +11,14 @@ namespace teachos::arch::memory::paging { static page_table * const active_page{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS)}; // We can not save page_table_handle as a static variable directly, if we do the program will fail to link. - return page_table_handle{active_page, page_table::LEVEL4}; + return page_table_handle{active_page, page_table_handle::LEVEL4}; } auto translate_page(virtual_page page) -> std::optional { auto current_handle = create_or_get(); - for (auto level = page_table::LEVEL4; level != page_table::LEVEL1; level--) + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; level--) { auto 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 @@ -30,7 +30,7 @@ namespace teachos::arch::memory::paging current_handle = next_handle.value(); } - auto level1_index = page.get_level_index(page_table::LEVEL1); + auto level1_index = page.get_level_index(page_table_handle::LEVEL1); auto level1_frame = current_handle[level1_index].calculate_pointed_to_frame(); return level1_frame; } @@ -38,14 +38,14 @@ namespace teachos::arch::memory::paging auto translate_huge_page(virtual_page page) -> std::optional { auto current_handle = create_or_get(); - auto level3_handle = current_handle.next_table(page.get_level_index(page_table::LEVEL4)); + auto level3_handle = current_handle.next_table(page.get_level_index(page_table_handle::LEVEL4)); if (!level3_handle) { return std::nullopt; } - auto level3_entry = level3_handle.value()[page.get_level_index(page_table::LEVEL3)]; + auto level3_entry = level3_handle.value()[page.get_level_index(page_table_handle::LEVEL3)]; auto level3_frame = level3_entry.calculate_pointed_to_frame(); if (level3_frame && level3_entry.contains_flags(entry::HUGE_PAGE)) { @@ -53,20 +53,21 @@ namespace teachos::arch::memory::paging 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::LEVEL2) * PAGE_TABLE_ENTRY_COUNT + - page.get_level_index(page_table::LEVEL1)}; + 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::LEVEL3)); + auto level2_handle = level3_handle.value().next_table(page.get_level_index(page_table_handle::LEVEL3)); if (level2_handle) { - auto level2_entry = level2_handle.value()[page.get_level_index(page_table::LEVEL2)]; + auto level2_entry = level2_handle.value()[page.get_level_index(page_table_handle::LEVEL2)]; auto level2_frame = level2_entry.calculate_pointed_to_frame(); if (level2_frame && 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::LEVEL1)}; + return allocator::physical_frame{level2_frame.value().frame_number + + page.get_level_index(page_table_handle::LEVEL1)}; } } return std::nullopt; diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 907b64f..852bbd5 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -4,6 +4,57 @@ namespace teachos::arch::memory::paging { + /** + * @brief A Page table containing 512 entries. + */ + struct page_table + { + /** + * @brief Set every entry of the page to unused. + */ + auto zero_entries() -> void; + + /** + * @brief Returns the next page table level from the given page table index. Meaning we + * use an index into a Level 4 page table to get the according Level 3 page table. This method should not be called + * on a Level 1 page table, because there is no furthere page table and mangeling up and returning the physical + * address would cause hard to debug issues. + * + * @param table_index Index of this page table in the page table one level lower. + */ + auto next_table(std::size_t table_index) const -> std::optional; + + /** + * @brief Index operator overload to access specific entries directy. + * + * @param index Index of the entry we want to access and read or write too. + * @return Entry at the given table index. + */ + auto operator[](std::size_t index) const -> entry; + + private: + /** + * @brief Calculates the address of the next page table level for the given table index. 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; + + entry entries[PAGE_TABLE_ENTRY_COUNT]; ///< Entries containing addresses to page tables of a level below or actual + ///< virtual addresses for the level 1 page table. + }; + + auto operator--(page_table_handle::level level, int) -> page_table_handle::level + { + exception_handling::assert(level != page_table_handle::LEVEL1, + "[Page table] Attemptd to decrement enum to value outside of range"); + auto value = static_cast::type>(level); + return static_cast(--value); + } + auto page_table::zero_entries() -> void { constexpr size_t entry_amount = sizeof(entries) / sizeof(entries[0]); @@ -44,15 +95,7 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto operator--(page_table::level level, int) -> page_table::level - { - exception_handling::assert(level != page_table::LEVEL1, - "[Page table] Attemptd to decrement enum to value outside of range"); - auto value = static_cast::type>(level); - return static_cast(--value); - } - - page_table_handle::page_table_handle(page_table * handle, page_table::level handle_level) + page_table_handle::page_table_handle(page_table * handle, page_table_handle::level handle_level) : handle(handle) , handle_level(handle_level) { @@ -63,7 +106,7 @@ namespace teachos::arch::memory::paging auto page_table_handle::next_table(std::size_t table_index) const -> std::optional { - exception_handling::assert(handle_level != page_table::LEVEL1, + exception_handling::assert(handle_level != page_table_handle::LEVEL1, "[Page Table] Attempted to call next_table on level 1 page table"); auto next_table = handle->next_table(table_index); if (next_table) diff --git a/arch/x86_64/src/memory/paging/virtual_page.cpp b/arch/x86_64/src/memory/paging/virtual_page.cpp index 9b803d2..fd2085b 100644 --- a/arch/x86_64/src/memory/paging/virtual_page.cpp +++ b/arch/x86_64/src/memory/paging/virtual_page.cpp @@ -19,7 +19,7 @@ namespace teachos::arch::memory::paging auto virtual_page::start_address() const -> uint64_t { return page_number * allocator::PAGE_FRAME_SIZE; } - auto virtual_page::get_level_index(page_table::level level) const -> uint64_t + auto virtual_page::get_level_index(page_table_handle::level level) const -> uint64_t { return (start_address() >> (level * 9U)) & 0x1FF; } -- cgit v1.2.3 From 039f12eb2f5785357ab1745201c8d420ab644165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 21 Oct 2024 13:35:10 +0000 Subject: Adding more mapping methods --- .../include/arch/memory/paging/page_mapper.hpp | 60 ++++++++++++++++++++++ arch/x86_64/src/kernel/main.cpp | 5 ++ 2 files changed, 65 insertions(+) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 0806f58..0f226e2 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -48,6 +48,8 @@ namespace teachos::arch::memory::paging * entry in every page level if it does not exists yet down to level 1. If the level 1 page table already exists it * halts execution instead. * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate entries * when a new page table is required. * @param page Virtual page that is being mapped. @@ -88,6 +90,64 @@ namespace teachos::arch::memory::paging arch::exception_handling::assert(!level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); level1_entry.set_entry(frame, flags | std::bitset<64U>{entry::PRESENT}); } + + /** + * @brief Allocates the next free frame and then uses that frame to call map_page_to_frame. + */ + template + auto map_next_free_page_to_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void + { + auto frame = allocator.allocate_frame(); + exception_handling::assert(!frame.has_value(), "[Page mapper] Out of memory exception"); + map_page_to_frame(allocator, page, frame.value(), flags); + } + + /** + * @brief Gets the corresponding page the given frame has to be contained in and uses that to call map_page_to_frame. + */ + template + auto identity_map(T & allocator, allocator::physical_frame frame, std::bitset<64U> flags) -> void + { + auto page = virtual_page::containing_address(frame.start_address()); + map_page_to_frame(allocator, page, frame, flags); + } + + /** + * @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags. Deallocates and + * unmaps the entry in every page level if this page was the last one up to level 4. + * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. + * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate entries + * when a new page table is required. + * @param page Virtual page that is being unmapped. + */ + template + auto unmap_page(T & allocator, virtual_page page) -> void + { + exception_handling::assert(translate_page(page).has_value(), + "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); + + auto current_handle = create_or_get(); + + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; level--) + { + auto level_index = page.get_level_index(level); + auto next_handle = current_handle.next_table(level_index); + // The next table method failed even tough the page has to be mapped already, because translate_page did not fail. + // This can only mean that we attempted to unmap a huge page, which is not supported in the first place. + exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); + current_handle = next_handle.value(); + } + + auto level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; + auto level1_frame = level1_entry.calculate_pointed_to_frame(); + exception_handling::assert(level1_frame.has_value(), + "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); + level1_entry.set_unused(); + // TODO: Deallocate and unmap level 1, 2, 3 page table entry if this was the last page in them. + allocator.deallocate_frame(level1_frame.value()); + } } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 88f6329..8e5aa05 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -3,6 +3,7 @@ #include "arch/exception_handling/assert.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/multiboot/reader.hpp" +#include "arch/memory/paging/page_mapper.hpp" #include "arch/video/vga/text.hpp" #include @@ -28,5 +29,9 @@ namespace teachos::arch::kernel video::vga::text::write("Allocated Frames", video::vga::text::common_attributes::green_on_black); video::vga::text::write_number(last_allocated.value().frame_number, video::vga::text::common_attributes::green_on_black); + memory::paging::map_page_to_frame(allocator, memory::paging::virtual_page{0U}, last_allocated.value(), 0U); + memory::paging::map_next_free_page_to_frame(allocator, memory::paging::virtual_page{0U}, 0U); + memory::paging::identity_map(allocator, last_allocated.value(), 0U); + memory::paging::unmap_page(allocator, memory::paging::virtual_page{0U}); } } // namespace teachos::arch::kernel -- cgit v1.2.3 From 8502cc9b19a9e934e3a4c0b3190b690ee0407a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 21 Oct 2024 14:48:03 +0000 Subject: =?UTF-8?q?Fix=20linker=20error=20using=20friend=20method=20?= =?UTF-8?q?=F0=9F=91=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../arch/memory/allocator/physical_frame.hpp | 2 +- .../include/arch/memory/paging/page_mapper.hpp | 2 ++ .../include/arch/memory/paging/page_table.hpp | 22 +++++++++++++----- .../include/arch/memory/paging/virtual_page.hpp | 2 +- arch/x86_64/src/kernel/main.cpp | 27 ++++++++++++++++++---- arch/x86_64/src/memory/paging/page_mapper.cpp | 14 ++++++++--- arch/x86_64/src/memory/paging/page_table.cpp | 16 ++++++------- 7 files changed, 61 insertions(+), 24 deletions(-) diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp index e013e0d..e33c77a 100644 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -27,7 +27,7 @@ namespace teachos::arch::memory::allocator * @param physical_address Physical address we want to get the corresponding physical frame for. * @return Frame the given address is contained in. */ - static auto containing_address(std::size_t physical_address) -> physical_frame; + auto static containing_address(std::size_t physical_address) -> physical_frame; /** * @brief Evaluates the start address of the physical frame. diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 0f226e2..a8cca4c 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -145,7 +145,9 @@ namespace teachos::arch::memory::paging exception_handling::assert(level1_frame.has_value(), "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); level1_entry.set_unused(); + // TODO: Flush the translation lookaside buffer to clear the entry from cache as well. (mov cr3, cr3) // TODO: Deallocate and unmap level 1, 2, 3 page table entry if this was the last page in them. + // TODO: Fix deallocate because it is not yet implemented. allocator.deallocate_frame(level1_frame.value()); } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 91ce81c..3a31dc5 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -5,10 +5,7 @@ namespace teachos::arch::memory::paging { - namespace - { - constexpr std::size_t PAGE_TABLE_ENTRY_COUNT = 512U; ///< Default entry count of a page table in x86_84 is 512. - } + constexpr std::size_t PAGE_TABLE_ENTRY_COUNT = 512U; ///< Default entry count of a page table in x86_84 is 512. /** * @brief Forward delcaration of the page_table, because it should only be accessible over the handle, the actual @@ -66,13 +63,26 @@ namespace teachos::arch::memory::paging */ auto operator[](std::size_t index) const -> entry; + /** + * @brief Decrements the page table handle level enum by one, is defined so we can use it as a replacement for an + * int index in a range based for loop. Will halt execution if called with page_table_handle::LEVEL1, because there + * is no level below. Has to be defined as either a friend function or inline header method, because we define an + * operator of another type. In this instance friend function was choosen, because the struct itself also requires + * the operator, but declaring before the struct is not possible, because the enum is in the struct. This is + * inpossible because the struct requires the operator declared before itself to work, and the operator requires the + * struct declared before itself to work. Furthermore this allows the defintion of the method to be done in the cpp, + * avoiding includes in the header file. + * + * @param value Value we want to decrement on + * @return level New level value decrement by one, meaning the level is also decrement by one Level4 --> Level3, ... + */ + friend auto operator--(level value, int) -> level; + private: page_table * handle; ///< Handle to underlying page table, can never be null (invariant ensured by constructor) level handle_level; ///< Level page table is currently on, depends on how often next_level was ///< called successfully. }; - - auto operator--(page_table_handle::level & level, int) -> page_table_handle::level; } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index ca11b3c..79801ee 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -28,7 +28,7 @@ namespace teachos::arch::memory::paging * @param virtual_address Virtual address we want to get the corresponding virtual page for. * @return Frame the given address is contained in. */ - static auto containing_address(std::size_t virtual_address) -> virtual_page; + auto static containing_address(std::size_t virtual_address) -> virtual_page; /** * @brief Evaluates the start address of the virtual page. diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 8e5aa05..3e25d2d 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -10,6 +10,7 @@ namespace teachos::arch::kernel { + auto main() -> void { video::vga::text::clear(); @@ -19,6 +20,25 @@ namespace teachos::arch::kernel auto memory_information = memory::multiboot::read_multiboot2(); memory::allocator::area_frame_allocator allocator(memory_information); + size_t address = 42 * memory::paging::PAGE_TABLE_ENTRY_COUNT * memory::paging::PAGE_TABLE_ENTRY_COUNT * + memory::allocator::PAGE_FRAME_SIZE; // 42th P3 entry + auto page = memory::paging::virtual_page::containing_address(address); + auto frame = allocator.allocate_frame(); + exception_handling::assert(frame.has_value(), "[Main] Out of memory exception"); + auto optional_frame = memory::paging::translate_page(page); + memory::paging::map_page_to_frame(allocator, page, frame.value(), 0U); + optional_frame = memory::paging::translate_page(page); + video::vga::text::newline(); + video::vga::text::write("Mapped physical frame: ", video::vga::text::common_attributes::green_on_black); + video::vga::text::write_number(optional_frame.value().frame_number, + video::vga::text::common_attributes::green_on_black); + + memory::paging::unmap_page(allocator, page); + video::vga::text::write("Unapped physical page: ", video::vga::text::common_attributes::green_on_black); + optional_frame = memory::paging::translate_page(page); + exception_handling::assert(!optional_frame.has_value(), "[Main] Ummapping failed"); + video::vga::text::write_number(page.page_number, video::vga::text::common_attributes::green_on_black); + auto last_allocated = allocator.allocate_frame(); auto allocated = last_allocated; do @@ -26,12 +46,9 @@ namespace teachos::arch::kernel last_allocated = allocated; allocated = allocator.allocate_frame(); } while (allocated); - video::vga::text::write("Allocated Frames", video::vga::text::common_attributes::green_on_black); + video::vga::text::newline(); + video::vga::text::write("Allocated Frames: ", video::vga::text::common_attributes::green_on_black); video::vga::text::write_number(last_allocated.value().frame_number, video::vga::text::common_attributes::green_on_black); - memory::paging::map_page_to_frame(allocator, memory::paging::virtual_page{0U}, last_allocated.value(), 0U); - memory::paging::map_next_free_page_to_frame(allocator, memory::paging::virtual_page{0U}, 0U); - memory::paging::identity_map(allocator, last_allocated.value(), 0U); - memory::paging::unmap_page(allocator, memory::paging::virtual_page{0U}); } } // namespace teachos::arch::kernel diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index b8f6b89..75b17ff 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -14,15 +14,23 @@ namespace teachos::arch::memory::paging return page_table_handle{active_page, page_table_handle::LEVEL4}; } + auto subtract_level(page_table_handle::level level) -> page_table_handle::level + { + exception_handling::assert(level != page_table_handle::LEVEL1, + "[Page table] Attemptd to decrement enum to value outside of range"); + auto value = static_cast::type>(level); + return static_cast(--value); + } + auto translate_page(virtual_page page) -> std::optional { auto current_handle = create_or_get(); - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; level--) + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; level = subtract_level(level)) { auto 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 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) { return translate_huge_page(page); diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 852bbd5..9c9ca76 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -47,14 +47,6 @@ namespace teachos::arch::memory::paging ///< virtual addresses for the level 1 page table. }; - auto operator--(page_table_handle::level level, int) -> page_table_handle::level - { - exception_handling::assert(level != page_table_handle::LEVEL1, - "[Page table] Attemptd to decrement enum to value outside of range"); - auto value = static_cast::type>(level); - return static_cast(--value); - } - auto page_table::zero_entries() -> void { constexpr size_t entry_amount = sizeof(entries) / sizeof(entries[0]); @@ -117,4 +109,12 @@ namespace teachos::arch::memory::paging } auto page_table_handle::operator[](std::size_t index) const -> entry { return handle->operator[](index); } + + auto operator--(page_table_handle::level value, int) -> page_table_handle::level + { + exception_handling::assert(value != page_table_handle::LEVEL1, + "[Page table] Attemptd to decrement enum to value outside of range"); + auto new_value = static_cast::type>(value); + return static_cast(--new_value); + } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From f9cc4f123e224b28ac2d879ab92cf60f1df351e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 21 Oct 2024 14:52:03 +0000 Subject: Use enum struct instead of class for uniformity --- arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp | 2 +- arch/x86_64/include/arch/memory/multiboot/info.hpp | 2 +- arch/x86_64/include/arch/memory/multiboot/memory_map.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp index 88d211e..72767a8 100644 --- a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp @@ -11,7 +11,7 @@ namespace teachos::arch::memory::multiboot * @brief Defines all elf section types an elf section header can have. See * https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. */ - enum class elf_section_type : uint32_t + enum struct elf_section_type : uint32_t { INACTIVE, ///< (SHT_NULL) Unused, meaning all values are zeroed out PROGRAMM, ///< (SHT_PROGBITS) Program data (DATA, CODE) diff --git a/arch/x86_64/include/arch/memory/multiboot/info.hpp b/arch/x86_64/include/arch/memory/multiboot/info.hpp index ca87834..a0f095f 100644 --- a/arch/x86_64/include/arch/memory/multiboot/info.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/info.hpp @@ -12,7 +12,7 @@ namespace teachos::arch::memory::multiboot * tag headers and see https://github.com/rhboot/grub2/blob/fedora-39/include/multiboot.h for more information on the * actual header contents and their following data. */ - enum class tag_type : uint32_t + enum struct tag_type : uint32_t { END, ///< Signals final tag for the multiboot2 information structure CMDLINE, ///< Contains the command line string diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp index 4dc11cf..ecf3975 100644 --- a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp @@ -9,7 +9,7 @@ namespace teachos::arch::memory::multiboot /** * @brief Defines all memory area types possible that the memory region can be in. */ - enum class memory_area_type : uint32_t + enum struct memory_area_type : uint32_t { AVAILABLE = 1, ///< Region is available for use by the OS RESERVED, ///< Region is reserved by firmware or bootloader and should not be used by OS -- cgit v1.2.3 From 7d1d7c5f63791506049cc188740cc4956fc8d14c Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 22 Oct 2024 05:37:28 +0000 Subject: update comments --- .../include/arch/memory/paging/page_table.hpp | 30 ++++++++++++---------- arch/x86_64/src/memory/paging/page_table.cpp | 21 ++++++++------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 3a31dc5..9aaaafb 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -21,7 +21,9 @@ namespace teachos::arch::memory::paging struct page_table_handle { /** - * @brief Level of the page table, level 1 will not be able to call next_table anymore, because it would result in + * @brief Level of the page table. + * + * Level 1 will not be able to call next_table anymore, because it would result in * attempting to access memory that it should not. */ enum level : uint8_t @@ -46,10 +48,11 @@ namespace teachos::arch::memory::paging auto zero_entries() -> void; /** - * @brief Returns the next page table level from the given page table index. Meaning we - * use an index into a Level 4 page table to get the according Level 3 page table. If this method is called with a - * Level 1 page table it will instead assert and halt execution, because there is no furthere page table and - * mangeling up and returning the physical address would cause hard to debug issues. + * @brief Returns the next page table level from the given page table index. + * + * Meaning we use an index into a Level 4 page table to get the according Level 3 page table. If this method is + * called with a Level 1 page table it will instead assert and halt execution, because there is no furthere page + * table and mangeling up and returning the physical address would cause hard to debug issues. * * @param table_index Index of this page table in the page table one level lower. */ @@ -64,14 +67,15 @@ namespace teachos::arch::memory::paging auto operator[](std::size_t index) const -> entry; /** - * @brief Decrements the page table handle level enum by one, is defined so we can use it as a replacement for an - * int index in a range based for loop. Will halt execution if called with page_table_handle::LEVEL1, because there - * is no level below. Has to be defined as either a friend function or inline header method, because we define an - * operator of another type. In this instance friend function was choosen, because the struct itself also requires - * the operator, but declaring before the struct is not possible, because the enum is in the struct. This is - * inpossible because the struct requires the operator declared before itself to work, and the operator requires the - * struct declared before itself to work. Furthermore this allows the defintion of the method to be done in the cpp, - * avoiding includes in the header file. + * @brief Decrements the page table handle level enum by one. + * + * Is defined so we can use it as a replacement for an int index in a range based for loop. Will halt execution if + * called with page_table_handle::LEVEL1, because there is no level below. Has to be defined as either a friend + * function or inline header method, because we define an operator of another type. In this instance friend function + * was choosen, because the struct itself also requires the operator, but declaring before the struct is not + * possible, because the enum is in the struct. This is inpossible because the struct requires the operator declared + * before itself to work, and the operator requires the struct declared before itself to work. Furthermore this + * allows the defintion of the method to be done in the cpp, avoiding includes in the header file. * * @param value Value we want to decrement on * @return level New level value decrement by one, meaning the level is also decrement by one Level4 --> Level3, ... diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 9c9ca76..939f3b1 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -15,10 +15,11 @@ namespace teachos::arch::memory::paging auto zero_entries() -> void; /** - * @brief Returns the next page table level from the given page table index. Meaning we - * use an index into a Level 4 page table to get the according Level 3 page table. This method should not be called - * on a Level 1 page table, because there is no furthere page table and mangeling up and returning the physical - * address would cause hard to debug issues. + * @brief Returns the next page table level from the given page table index. + * + * Meaning we use an index into a Level 4 page table to get the according Level 3 page table. This method should not + * be called on a Level 1 page table, because there is no furthere page table and mangeling up and returning the + * physical address would cause hard to debug issues. * * @param table_index Index of this page table in the page table one level lower. */ @@ -34,7 +35,9 @@ namespace teachos::arch::memory::paging private: /** - * @brief Calculates the address of the next page table level for the given table index. The next page table address + * @brief Calculates the address of the next page table level for the given table index. + * + * 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. * @@ -43,8 +46,8 @@ namespace teachos::arch::memory::paging */ auto next_table_address(std::size_t table_index) const -> std::optional; - entry entries[PAGE_TABLE_ENTRY_COUNT]; ///< Entries containing addresses to page tables of a level below or actual - ///< virtual addresses for the level 1 page table. + entry entries[PAGE_TABLE_ENTRY_COUNT]; ///< 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 @@ -91,7 +94,7 @@ namespace teachos::arch::memory::paging : handle(handle) , handle_level(handle_level) { - exception_handling::assert(handle, "[Page table] Attemptd to pass nullptr as handle to page table handle method"); + exception_handling::assert(handle, "[Page table] Attempted to pass nullptr as handle to page table handle method"); } auto page_table_handle::zero_entries() -> void { handle->zero_entries(); } @@ -113,7 +116,7 @@ namespace teachos::arch::memory::paging auto operator--(page_table_handle::level value, int) -> page_table_handle::level { exception_handling::assert(value != page_table_handle::LEVEL1, - "[Page table] Attemptd to decrement enum to value outside of range"); + "[Page table] Attempted to decrement enum to value outside of range"); auto new_value = static_cast::type>(value); return static_cast(--new_value); } -- cgit v1.2.3 From ba054441f93a30e2042a71d632a6a5fb04007d15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 22 Oct 2024 06:16:51 +0000 Subject: Adjust all briefs --- .../arch/memory/allocator/area_frame_allocator.hpp | 2 +- .../arch/memory/multiboot/elf_symbols_section.hpp | 108 +++++++++++---------- arch/x86_64/include/arch/memory/multiboot/info.hpp | 55 +++++------ .../include/arch/memory/multiboot/memory_map.hpp | 34 ++++--- .../include/arch/memory/multiboot/reader.hpp | 11 ++- .../include/arch/memory/paging/page_entry.hpp | 16 +-- .../include/arch/memory/paging/page_mapper.hpp | 17 +++- .../include/arch/memory/paging/page_table.hpp | 33 ++++--- arch/x86_64/include/arch/video/vga/text.hpp | 26 ++--- arch/x86_64/src/exception_handling/abort.cpp | 4 +- arch/x86_64/src/kernel/main.cpp | 1 - arch/x86_64/src/memory/paging/page_table.cpp | 14 +-- include/memory/asm_pointer.hpp | 4 + 13 files changed, 175 insertions(+), 150 deletions(-) diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp index 7b1bb16..a1b771e 100644 --- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -29,7 +29,7 @@ namespace teachos::arch::memory::allocator /** * @brief Allocate memory by finding and returning a free physical_frame. * - * The physical_frame allocation executes multiple checks before returning + * @note The physical_frame allocation executes multiple checks before returning * the physical_frame that is available to allocate. It must at least * do the following: * - check if the next_free_frame is within the current_area diff --git a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp index 72767a8..fc8cb15 100644 --- a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp @@ -8,33 +8,35 @@ namespace teachos::arch::memory::multiboot { /** - * @brief Defines all elf section types an elf section header can have. See - * https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. + * @brief Defines all elf section types an elf section header can have. + * + * @note See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. */ enum struct elf_section_type : uint32_t { - INACTIVE, ///< (SHT_NULL) Unused, meaning all values are zeroed out - PROGRAMM, ///< (SHT_PROGBITS) Program data (DATA, CODE) - SYMBOL_TABLE, ///< (SHT_SYMBTAB) Contains actual entries pointed to in symbol hash table - STRING_TABLE, ///< (SHT_STRTAB) Contains symbols, section and deubbging null-terminated strings - RELOCATION_ENTRY_WITH_ADDENDS, ///< (SHT_RELA) Only used on 64 bit systems - SYMBOL_HASH_TABLE, ///< (SHT_HASH) Hash table used by dynamic linker to locate symbols - DYNAMIC, ///< (SHT_DYNAMIC) Contains dynamic linking information - NOTE, ///< (SHT_NOTE) Stores information that marks files in some way - EMPTY, ///< (SHT_NOBITS) Program data section, that occupies no space in the file (.bss) - RELOCATION_ENTRY_WITHOUT_ADDENDS, ///< (SHT_REL) Only used on 32 bit systems - UNSPECIFIED, ///< (SHT_SHLIB) Reserved but has unspecified semantics - DYNAMIC_SYMBOL_TABLE, ///< (SHT_DYNSYM) Holds minimal set of symbols adequate for dynamic linking - INITALIZATION_FUNCTION_ARRAY = 14, ///< (SHT_INIT_ARRAY) Array of pointers to intialization functions () -> void - TERMINATION_FUNCTION_ARRAY, ///< (SHT_FINI_ARRAY) Array of pointers to termination functions () -> void + INACTIVE, ///< (SHT_NULL) Unused, meaning all values are zeroed out. + PROGRAMM, ///< (SHT_PROGBITS) Program data (DATA, CODE). + SYMBOL_TABLE, ///< (SHT_SYMBTAB) Contains actual entries pointed to in symbol hash table. + STRING_TABLE, ///< (SHT_STRTAB) Contains symbols, section and deubbging null-terminated strings. + RELOCATION_ENTRY_WITH_ADDENDS, ///< (SHT_RELA) Only used on 64 bit systems. + SYMBOL_HASH_TABLE, ///< (SHT_HASH) Hash table used by dynamic linker to locate symbols. + DYNAMIC, ///< (SHT_DYNAMIC) Contains dynamic linking information. + NOTE, ///< (SHT_NOTE) Stores information that marks files in some way. + EMPTY, ///< (SHT_NOBITS) Program data section, that occupies no space in the file (.bss). + RELOCATION_ENTRY_WITHOUT_ADDENDS, ///< (SHT_REL) Only used on 32 bit systems. + UNSPECIFIED, ///< (SHT_SHLIB) Reserved but has unspecified semantics. + DYNAMIC_SYMBOL_TABLE, ///< (SHT_DYNSYM) Holds minimal set of symbols adequate for dynamic linking. + INITALIZATION_FUNCTION_ARRAY = 14, ///< (SHT_INIT_ARRAY) Array of pointers to intialization functions () -> void. + TERMINATION_FUNCTION_ARRAY, ///< (SHT_FINI_ARRAY) Array of pointers to termination functions () -> void. PRE_INITALIZATION_FUNCTION_ARRAY ///< (SHT_PRE_INIT_ARRAY) Array of pointers to functions invoked before other - ///< initalization functions () -> void + ///< initalization functions () -> void. }; /** * @brief Defines helper function for all states that the elf section flags of an elf section header can - * have. See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html - * See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. + * have. + * + * @note See https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html for more information. */ struct elf_section_flags { @@ -63,9 +65,9 @@ namespace teachos::arch::memory::multiboot COMPRESSED = 1U << 11U, ///< (SHF_COMPRESSED) Section contains compressed data. SPECIAL_ORDERING_REQUIREMENTS = 1U << 30U, ///< (SHF_ORDERED) Section has special ordering requirements, meaning it - ///< should be ordered in relation to other sections of the same type + ///< should be ordered in relation to other sections of the same type. EXCLUDED_UNLESS_REFERENCED_OR_ALLOCATED = 1U << 31U, ///< (SHF_EXCLUDE)Section is excluded unless referenced or - ///< allocated, used for LTO (Link-Time Optimizations) + ///< allocated, used for LTO (Link-Time Optimizations). }; /** @@ -81,20 +83,21 @@ namespace teachos::arch::memory::multiboot } /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all - * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits - * that are set are not relevant. + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. + * + * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng + * std::bitset. Any additional bits that are set are not relevant. * * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying std::bitset + * @return Whether the given flags are a subset or equivalent with the underlying std::bitset. */ auto contains_flags(std::bitset<64U> other) const -> bool; /** - * @brief Allows to compare the underlying std::bitset of two instances + * @brief Allows to compare the underlying std::bitset of two instances. * - * @param other Other instance that we want to compare with - * @return Whether the underlying std::bitset of both types is the same + * @param other Other instance that we want to compare with. + * @return Whether the underlying std::bitset of both types is the same. */ auto operator==(elf_section_flags const & other) const -> bool = default; @@ -106,33 +109,35 @@ namespace teachos::arch::memory::multiboot /** * @brief Defines the data included in a section header, where each section has exactly one section header. - * See https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html for more information + * + * @note See https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html for more information. */ struct elf_section_header { - uint32_t name_table_index; ///< Index into the section header string table, specifies the name of the section - elf_section_type type; ///< Categorizes the sections content and semantics - elf_section_flags flags; ///< 1-bit flgas that describe section attributes + uint32_t name_table_index; ///< Index into the section header string table, specifies the name of the section. + elf_section_type type; ///< Categorizes the sections content and semantics. + elf_section_flags flags; ///< 1-bit flgas that describe section attributes. uint64_t virtual_address; ///< If section appears in memory image of a process, gives address at which the sections - ///< first byte should reside, otherwise 0 + ///< first byte should reside, otherwise 0. uint64_t file_offset; ///< Offset from the beginning of the file to the first byte in the section. SHT_NOBITS - ///< contains the conceptual placement instead (because it occupies no space in the file) - uint64_t section_size; ///< Complete section size in bytes, SHT_NOBITS may have non-zero value but will always - ///< occupy no space in the file - uint32_t other_section; ///< Section header table index link, behaviour varies on type - ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link + ///< contains the conceptual placement instead (because it occupies no space in the file). + uint64_t section_size; ///< Complete section size in bytes, SHT_NOBITS may have non-zero value but will always + ///< occupy no space in the file. + uint32_t other_section; ///< Section header table index link, behaviour varies on type + ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link. uint32_t additional_information; ///< Extra information, behaviour varies on type - ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link + ///< https://refspecs.linuxbase.org/elf/gabi4+/ch4.sheader.html#sh_link. uint64_t address_alignment; ///< Possible address alignment constraints. Value of virutal_address must be 0 % value - ///< of address_alignment. Value 0 or 1 mean no alignment constraints + ///< of address_alignment. Value 0 or 1 mean no alignment constraints. uint64_t fixed_table_entry_size; ///< If sections holds table with fixed-sized entries, this gives the size in - ///< bytes of each entry + ///< bytes of each entry. /** * @brief Detect whether a section header is inactive or not, should always be the case for the first entry in the - * sections table + * sections table. + * * @return Whether the current section header is actually null or not, requires all fields besides section_size and - * other_section to contain 0 + * other_section to contain 0. */ auto is_null() const -> bool; }; @@ -140,17 +145,18 @@ namespace teachos::arch::memory::multiboot /** * @brief Defines an entry in the multi_boot_tag array of the multi_boot_info struct, of type * multi_boot_tag_type::ELF_SECTIONS. - * The first section in the sections array will always be INACTIVE, there can only ever be one DYNAMIC section and - * only either one DYNAMIC_SYMBOL_TABLE or SYMBOL_TABLE. + * + * @note The first section in the sections array will always be INACTIVE, there can only ever be one DYNAMIC section + * and only either one DYNAMIC_SYMBOL_TABLE or SYMBOL_TABLE. */ struct elf_symbols_section_header { - tag info; ///< Basic multi_boot_tag information - uint32_t number_of_sections; ///< Number of sections in the sections array - uint32_t entry_size; ///< Size of each entry in the sections array - uint32_t section_index; ///< Index to the string table used for symbol names - std::byte end; ///< Marks the end of the tag, used to mark the beginning of any additional data - ///< contained in the section, to ensure byte alignment is actually 4 byte + tag info; ///< Basic multi_boot_tag information. + uint32_t number_of_sections; ///< Number of sections in the sections array. + uint32_t entry_size; ///< Size of each entry in the sections array. + uint32_t section_index; ///< Index to the string table used for symbol names. + std::byte end; ///< Marks the end of the tag, used to mark the beginning of any additional data. + ///< contained in the section, to ensure byte alignment is actually 4 byte. }; } // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/include/arch/memory/multiboot/info.hpp b/arch/x86_64/include/arch/memory/multiboot/info.hpp index a0f095f..7924993 100644 --- a/arch/x86_64/include/arch/memory/multiboot/info.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/info.hpp @@ -7,35 +7,36 @@ namespace teachos::arch::memory::multiboot { /** * @brief Defines all possible types a multiboot2 tag structure can have. - * See + * + * @note See * https://github.com/rhboot/grub2/blob/fedora-39/include/multiboot2.h for more information on the structure of the * tag headers and see https://github.com/rhboot/grub2/blob/fedora-39/include/multiboot.h for more information on the * actual header contents and their following data. */ enum struct tag_type : uint32_t { - END, ///< Signals final tag for the multiboot2 information structure - CMDLINE, ///< Contains the command line string - BOOT_LOADER_NAME, ///< Contains the name of the boot loader booting the kernel - MODULE, ///< Indicates the boot module which was loaded along the kernel image - BASIC_MEMORY_INFO, ///< Contains the amount of lower (0MB start address) and upper memory (1MB start address) - BOOTDEV, ///< Indicates which BIOS disk device the hoot loader has loaded the OS image from - MEMORY_MAP, ///< Describes the memory layout of the system with individual areas and their flags - VBE_INFO, ///< Includes information to access and utilize the device GPU - FRAMEBUFFER, ///< VBE framebuffer information - ELF_SECTIONS, ///< Includes list of all section headers from the loaded ELF kernel - APM_INFO, ///< Advanced Power Management information - EFI32, ///< EFI 32 bit system table pointer - EFI64, ///< EFI 64 bit system table pointer - SMBIOS, ///< Contains copy of all Sytem Management BIOS tables - ACPI_OLD, ///< Contains copy of RSDP as defined per ACPI1.0 specification - ACPI_NEW, ///< Contains copy of RSDP as defined per ACPI2.0 or later specification - NETWORK, ///< Contains network information specified specified as DHCP - EFI_MEMORY_MAP, ///< Contains EFI memory map - EFI_BS_NOT_TERMINATED, ///< Indicated ExitBootServies wasn't called - EFI32_IMAGE_HANDLE, ///< EFI 32 bit image handle pointer - EFI64_IMAGE_HANDLE, ///< EFI 64 bit imae handle pointer - LOAD_BASE_ADDRESS ///< Contains image load base physical address + END, ///< Signals final tag for the multiboot2 information structure. + CMDLINE, ///< Contains the command line string. + BOOT_LOADER_NAME, ///< Contains the name of the boot loader booting the kernel. + MODULE, ///< Indicates the boot module which was loaded along the kernel image. + BASIC_MEMORY_INFO, ///< Contains the amount of lower (0MB start address) and upper memory (1MB start address). + BOOTDEV, ///< Indicates which BIOS disk device the hoot loader has loaded the OS image from. + MEMORY_MAP, ///< Describes the memory layout of the system with individual areas and their flags. + VBE_INFO, ///< Includes information to access and utilize the device GPU. + FRAMEBUFFER, ///< VBE framebuffer information. + ELF_SECTIONS, ///< Includes list of all section headers from the loaded ELF kernel. + APM_INFO, ///< Advanced Power Management information. + EFI32, ///< EFI 32 bit system table pointer. + EFI64, ///< EFI 64 bit system table pointer. + SMBIOS, ///< Contains copy of all Sytem Management BIOS tables. + ACPI_OLD, ///< Contains copy of RSDP as defined per ACPI1.0 specification. + ACPI_NEW, ///< Contains copy of RSDP as defined per ACPI2.0 or later specification. + NETWORK, ///< Contains network information specified specified as DHCP. + EFI_MEMORY_MAP, ///< Contains EFI memory map. + EFI_BS_NOT_TERMINATED, ///< Indicated ExitBootServies wasn't called. + EFI32_IMAGE_HANDLE, ///< EFI 32 bit image handle pointer. + EFI64_IMAGE_HANDLE, ///< EFI 64 bit imae handle pointer. + LOAD_BASE_ADDRESS ///< Contains image load base physical address. }; /** @@ -44,8 +45,8 @@ namespace teachos::arch::memory::multiboot */ struct tag { - tag_type type; ///< Specific type of this multi_boot_tag entry, used to differentiate handling - uint32_t size; ///< Total size of this multi_boot_tag entry with all fields of the actual type + tag_type type; ///< Specific type of this multi_boot_tag entry, used to differentiate handling. + uint32_t size; ///< Total size of this multi_boot_tag entry with all fields of the actual type. }; /** @@ -54,8 +55,8 @@ namespace teachos::arch::memory::multiboot */ struct info_header { - uint32_t total_size; ///< Total size of all multiboot::tags and their data - alignas(8) struct tag tags; ///< Specific tags + uint32_t total_size; ///< Total size of all multiboot::tags and their data. + alignas(8) struct tag tags; ///< Specific tags. }; } // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp index ecf3975..1a38a30 100644 --- a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp @@ -11,25 +11,27 @@ namespace teachos::arch::memory::multiboot */ enum struct memory_area_type : uint32_t { - AVAILABLE = 1, ///< Region is available for use by the OS - RESERVED, ///< Region is reserved by firmware or bootloader and should not be used by OS - ACPI_AVAILABLE, ///< Region is reclaimable by OS after ACPI event - RESERVED_HIBERNATION, ///< Region is used for Non-volatile Storage (NVS) - DEFECTIVE ///< Region is defective or unusable + AVAILABLE = 1, ///< Region is available for use by the OS. + RESERVED, ///< Region is reserved by firmware or bootloader and should not be used by OS. + ACPI_AVAILABLE, ///< Region is reclaimable by OS after ACPI event. + RESERVED_HIBERNATION, ///< Region is used for Non-volatile Storage (NVS). + DEFECTIVE ///< Region is defective or unusable. }; /** - * @brief Defines an entry in the entries array of the memory_map struct. Has to have all padding stripped between the - * individual values, because the size of the entry needs to be exactly 24 bytes and not one byte more. See + * @brief Defines an entry in the entries array of the memory_map struct. + * + * @note Has to have all padding stripped between the individual values, because the size of the entry needs to be + * exactly 24 bytes and not one byte more. See * https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Packed-Structures.html for more information on the * used attribute. */ struct __attribute__((packed)) memory_area { - uint32_t size; ///< Size of this structure in bytes - uint64_t base_address; ///< Base address the memory region starts at - uint64_t area_length; ///< Size of the memory region, added to base_address results in the final address - memory_area_type type; ///< Specific type of memory the region can contain + uint32_t size; ///< Size of this structure in bytes. + uint64_t base_address; ///< Base address the memory region starts at. + uint64_t area_length; ///< Size of the memory region, added to base_address results in the final address. + memory_area_type type; ///< Specific type of memory the region can contain. }; /** @@ -38,10 +40,10 @@ namespace teachos::arch::memory::multiboot */ struct memory_map_header { - tag info; ///< Basic multi_boot_tag information - uint32_t entry_size; ///< Size of each entry in the memory_area array. Guaranteed multiple of 8 - uint32_t entry_version; ///< Version of the entries, currently 0 - struct memory_area entries; ///< Specific memory regions + tag info; ///< Basic multi_boot_tag information. + uint32_t entry_size; ///< Size of each entry in the memory_area array. Guaranteed multiple of 8. + uint32_t entry_version; ///< Version of the entries, currently 0. + struct memory_area entries; ///< Specific memory regions. }; /** @@ -64,7 +66,7 @@ namespace teachos::arch::memory::multiboot memory_area & operator*() const; /** - * @brief Post increment operator. Returns a copy of the value + * @brief Post increment operator. Returns a copy of the value. * * @return Copy of the incremented underlying address. */ diff --git a/arch/x86_64/include/arch/memory/multiboot/reader.hpp b/arch/x86_64/include/arch/memory/multiboot/reader.hpp index 2f72980..393db8b 100644 --- a/arch/x86_64/include/arch/memory/multiboot/reader.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/reader.hpp @@ -22,11 +22,12 @@ namespace teachos::arch::memory::multiboot }; /** - * @brief Reads the relevant multiboot2 information data from memory. This is done using the - * multiboot_information_pointer, which marks the start of the multiboot2 data. The indivdual headers we have to read - * are 8 byte aligned, whereas the data contained in those headers does not have to be. All sections that are read - * additionaly receive some sanity to ensure the read address is actually pointing to the expected structure, if they - * are not this method will assert. + * @brief Reads the relevant multiboot2 information data from memory. + * + * @note This is done using the multiboot_information_pointer, which marks the start of the multiboot2 data. The + * indivdual headers we have to read are 8 byte aligned, whereas the data contained in those headers does not have to + * be. All sections that are read additionaly receive some sanity to ensure the read address is actually pointing to + * the expected structure, if they are not this method will assert. * * The memory_information variables are calcualted like this: * - kernel_start: Calculated by getting the lowest address specified in the elf symbols headers. diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 158af2e..2b3b3f3 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -64,20 +64,22 @@ namespace teachos::arch::memory::paging auto set_entry(allocator::physical_frame frame, std::bitset<64U> flags) -> void; /** - * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset, meaning that all - * bits that are set in the given std::bitset also have to be set in the underlyng std::bitset. Any additional bits - * that are set are not relevant. + * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. + * + * @note Meaning that all bits that are set in the given std::bitset also have to be set in the underlyng + * std::bitset. Any additional bits that are set are not relevant. * * @param other Flags that we want to compare against and check if the underlying std::bitset has the same bits set. - * @return Whether the given flags are a subset or equivalent with the underlying std::bitset + * @return Whether the given flags are a subset or equivalent with the underlying std::bitset. */ auto contains_flags(std::bitset<64U> other) const -> bool; private: /** - * @brief Extracts the physical address from the underlying bitset read from bit index 12 - 51. Is a 52 bit page - * aligned physical address of the frame of the next page table or the pyhscial address of the frame for P1 page - * tables. + * @brief Extracts the physical address from the underlying bitset read from bit index 12 - 51. + * + * @note Is a 52 bit page aligned physical address of the frame of the next page table or the pyhscial address of + * the frame for P1 page tables. * * @return Extracted physical address of the next page or of the frame for P1 page tables. */ diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index a8cca4c..df232ea 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -44,9 +44,10 @@ namespace teachos::arch::memory::paging auto translate_address(std::size_t virtual_address) -> std::optional; /** - * @brief Maps a virtual page to a physical frame in the page table with the specified flags. Allocates and maps an - * entry in every page level if it does not exists yet down to level 1. If the level 1 page table already exists it - * halts execution instead. + * @brief Maps a virtual page to a physical frame in the page table with the specified flags. + * + * @note Allocates and maps an entry in every page level if it does not exists yet down to level 1. If the level 1 + * page table already exists it halts execution instead. * * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and * deallocate method. @@ -93,6 +94,8 @@ namespace teachos::arch::memory::paging /** * @brief Allocates the next free frame and then uses that frame to call map_page_to_frame. + * + * @see map_page_to_frame */ template auto map_next_free_page_to_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void @@ -104,6 +107,8 @@ namespace teachos::arch::memory::paging /** * @brief Gets the corresponding page the given frame has to be contained in and uses that to call map_page_to_frame. + * + * @see map_page_to_frame */ template auto identity_map(T & allocator, allocator::physical_frame frame, std::bitset<64U> flags) -> void @@ -113,8 +118,10 @@ namespace teachos::arch::memory::paging } /** - * @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags. Deallocates and - * unmaps the entry in every page level if this page was the last one up to level 4. + * @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags. + * + * @note Deallocates and unmaps the entry in every page level if this page was the last one up to level 4 and ensures + * to clear the Translation Lookaside Buffer, so that the unmapped value is removed from cache as well. * * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and * deallocate method. diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 9aaaafb..feb327a 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -8,9 +8,11 @@ namespace teachos::arch::memory::paging constexpr std::size_t PAGE_TABLE_ENTRY_COUNT = 512U; ///< Default entry count of a page table in x86_84 is 512. /** - * @brief Forward delcaration of the page_table, because it should only be accessible over the handle, the actual - * methods or constructor are not defined meaning they are not callable from outside. Instead the struct is only fully - * defined in the implementation (.cpp) file of the page table, and therefore also only accesible in that file. + * @brief Forward delcaration of the page_table, because it should only be accessible over the handle. + * + * @note The actual methods or constructor are not defined meaning they are not callable from outside. Instead the + * struct is only fully defined in the implementation (.cpp) file of the page table, and therefore the memthods are + * only accesible in that file. */ struct page_table; @@ -48,11 +50,11 @@ namespace teachos::arch::memory::paging auto zero_entries() -> void; /** - * @brief Returns the next page table level from the given page table index. + * @brief Returns the next page table level from the given page table index. Meaning we + * use an index into a Level 4 page table to get the according Level 3 page table. * - * Meaning we use an index into a Level 4 page table to get the according Level 3 page table. If this method is - * called with a Level 1 page table it will instead assert and halt execution, because there is no furthere page - * table and mangeling up and returning the physical address would cause hard to debug issues. + * @note If this method is called with a Level 1 page table it will instead assert and halt execution, because there + * is no furthere page table and mangeling up and returning the physical address would cause hard to debug issues. * * @param table_index Index of this page table in the page table one level lower. */ @@ -67,15 +69,16 @@ namespace teachos::arch::memory::paging auto operator[](std::size_t index) const -> entry; /** - * @brief Decrements the page table handle level enum by one. + * @brief Decrements the page table handle level enum by one, is defined so we can use it as a replacement for an + * int index in a range based for loop. * - * Is defined so we can use it as a replacement for an int index in a range based for loop. Will halt execution if - * called with page_table_handle::LEVEL1, because there is no level below. Has to be defined as either a friend - * function or inline header method, because we define an operator of another type. In this instance friend function - * was choosen, because the struct itself also requires the operator, but declaring before the struct is not - * possible, because the enum is in the struct. This is inpossible because the struct requires the operator declared - * before itself to work, and the operator requires the struct declared before itself to work. Furthermore this - * allows the defintion of the method to be done in the cpp, avoiding includes in the header file. + * @note Will halt execution if called with page_table_handle::LEVEL1, because there is no level below. Has to be + * defined as either a friend function or inline header method, because we define an operator of another type. In + * this instance friend function was choosen, because the struct itself also requires the operator, but declaring + * before the struct is not possible, because the enum is in the struct. This is inpossible because the struct + * requires the operator declared before itself to work, and the operator requires the struct declared before itself + * to work. Furthermore this allows the defintion of the method to be done in the cpp, avoiding includes in the + * header file. * * @param value Value we want to decrement on * @return level New level value decrement by one, meaning the level is also decrement by one Level4 --> Level3, ... diff --git a/arch/x86_64/include/arch/video/vga/text.hpp b/arch/x86_64/include/arch/video/vga/text.hpp index 690f4aa..f200da4 100644 --- a/arch/x86_64/include/arch/video/vga/text.hpp +++ b/arch/x86_64/include/arch/video/vga/text.hpp @@ -12,14 +12,14 @@ namespace teachos::arch::video::vga::text */ enum struct color : std::uint8_t { - black, ///< Equivalent to HTML color \#000000 - blue, ///< Equivalent to HTML color \#0000AA - green, ///< Equivalent to HTML color \#00AA00 - cyan, ///< Equivalent to HTML color \#00AAAA - red, ///< Equivalent to HTML color \#AA0000 - purple, ///< Equivalent to HTML color \#AA00AA - brown, ///< Equivalent to HTML color \#AA5500 - gray, ///< Equivalent to HTML color \#AAAAAA + black, ///< Equivalent to HTML color \#000000. + blue, ///< Equivalent to HTML color \#0000AA. + green, ///< Equivalent to HTML color \#00AA00. + cyan, ///< Equivalent to HTML color \#00AAAA. + red, ///< Equivalent to HTML color \#AA0000. + purple, ///< Equivalent to HTML color \#AA00AA. + brown, ///< Equivalent to HTML color \#AA5500. + gray, ///< Equivalent to HTML color \#AAAAAA. }; /** @@ -37,21 +37,21 @@ namespace teachos::arch::video::vga::text enum struct background_flag : bool { none, ///< Apply no flag e.g., keep color as is. - blink_or_bright, ///< Make the cell blink or more intense, dependent on the VGA configuration + blink_or_bright, ///< Make the cell blink or more intense, dependent on the VGA configuration. }; /** * @brief The VGA text mode attribute. * - * In the text mode of VGA, every code point being presented is followed by an attribute description. This allows for - * the modification of how the relevant "cell" is presented. + * @note In the text mode of VGA, every code point being presented is followed by an attribute description. This + * allows for the modification of how the relevant "cell" is presented. * * @see vga::text::foreground_flag * @see vga::text::background_flag */ struct attribute { - color foreground_color : 3; ///< The foreground color of the cell, e.g. the color of the code point + color foreground_color : 3; ///< The foreground color of the cell, e.g. the color of the code point. enum foreground_flag foreground_flag : 1; ///< The foreground color modification flag of the cell. color bacground_color : 3; ///< The background color of the cell. enum background_flag background_flag : 1; ///< The background color modification flag of the cell. @@ -60,7 +60,7 @@ namespace teachos::arch::video::vga::text static_assert(sizeof(attribute) == 1, "The VGA text mode attribute must fit inside a single byte."); /** - * @brief Commonly used VGA text mode attributes + * @brief Commonly used VGA text mode attributes. */ namespace common_attributes { diff --git a/arch/x86_64/src/exception_handling/abort.cpp b/arch/x86_64/src/exception_handling/abort.cpp index e331d34..e12e4cb 100644 --- a/arch/x86_64/src/exception_handling/abort.cpp +++ b/arch/x86_64/src/exception_handling/abort.cpp @@ -7,8 +7,8 @@ namespace teachos::arch::exception_handling /** * @brief Override for the newlib abort function. * - * 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 + * @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"); } diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 3e25d2d..ad1eb39 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -10,7 +10,6 @@ namespace teachos::arch::kernel { - auto main() -> void { video::vga::text::clear(); diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 939f3b1..555d38a 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -15,11 +15,12 @@ namespace teachos::arch::memory::paging auto zero_entries() -> void; /** - * @brief Returns the next page table level from the given page table index. + * @brief Returns the next page table level from the given page table index. Meaning we use an index into a Level 4 + * page table to get the according Level 3 page table. * - * Meaning we use an index into a Level 4 page table to get the according Level 3 page table. This method should not - * be called on a Level 1 page table, because there is no furthere page table and mangeling up and returning the - * physical address would cause hard to debug issues. + * @note This method + * should not be called on a Level 1 page table, because there is no furthere page table and mangeling up and + * returning the physical address would cause hard to debug issues. * * @param table_index Index of this page table in the page table one level lower. */ @@ -37,9 +38,8 @@ namespace teachos::arch::memory::paging /** * @brief Calculates the address of the next page table level for the given table index. * - * 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. + * @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. diff --git a/include/memory/asm_pointer.hpp b/include/memory/asm_pointer.hpp index 9ec2218..71dfcf7 100644 --- a/include/memory/asm_pointer.hpp +++ b/include/memory/asm_pointer.hpp @@ -20,21 +20,25 @@ namespace teachos::memory /** * @brief Construct a new asm_pointer for a given assembly-defined pointer. + * * @param pointer A pointer defined in assembly. */ constexpr asm_pointer(Type *& pointer) : m_pointer{&pointer} { + // Nothing to do } /** * @brief Access the underlying pointer. + * * @return The pointer wrapped by this asm_pointer. */ auto constexpr operator*() -> pointer & { return *m_pointer; } /** * @brief Access the underlying pointer. + * * @return The pointer wrapped by this asm_pointer. */ auto constexpr operator*() const -> pointer const & { return *m_pointer; } -- cgit v1.2.3 From 5a2892f65abe13c32bb07de697826f374c1d2b1d Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 22 Oct 2024 07:40:35 +0000 Subject: change table level 4 address --- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 5 ++--- arch/x86_64/src/memory/paging/page_mapper.cpp | 15 ++++----------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index a8cca4c..24d8cde 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -73,12 +73,11 @@ namespace teachos::arch::memory::paging if (!next_handle) { auto allocated_frame = allocator.allocate_frame(); - exception_handling::assert(!allocated_frame.has_value(), "[Page mapper] Unable to allocate frame"); + exception_handling::assert(allocated_frame.has_value(), "[Page mapper] Unable to allocate frame"); current_handle[level_index].set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); // There should now be an entry at the previously not existent index, therefore we can simply access it again. next_handle = current_handle.next_table(page.get_level_index(level)); - exception_handling::assert(!next_handle.has_value(), - "[Page mapper] Unable to create new entry into page table"); + exception_handling::assert(next_handle.has_value(), "[Page mapper] Unable to create new entry into page table"); next_handle.value().zero_entries(); } current_handle = next_handle.value(); diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 75b17ff..1371868 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -4,8 +4,9 @@ namespace teachos::arch::memory::paging { namespace { - constexpr size_t PAGE_TABLE_LEVEL_4_ADDRESS = 0xfffffffffffff000; - } + // TODO: Set the address to a sensible location, this is merely a placeholder + constexpr size_t PAGE_TABLE_LEVEL_4_ADDRESS = 0x27AC40; + } // namespace auto create_or_get() -> page_table_handle { @@ -14,19 +15,11 @@ namespace teachos::arch::memory::paging return page_table_handle{active_page, page_table_handle::LEVEL4}; } - auto subtract_level(page_table_handle::level level) -> page_table_handle::level - { - exception_handling::assert(level != page_table_handle::LEVEL1, - "[Page table] Attemptd to decrement enum to value outside of range"); - auto value = static_cast::type>(level); - return static_cast(--value); - } - auto translate_page(virtual_page page) -> std::optional { auto current_handle = create_or_get(); - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; level = subtract_level(level)) + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; level--) { auto 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 -- cgit v1.2.3 From 7d4139b6fa0214604f467a782951cdc0f90e903f Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 22 Oct 2024 08:00:57 +0000 Subject: fix page level -- operator --- arch/x86_64/include/arch/memory/paging/page_table.hpp | 4 ++-- arch/x86_64/src/memory/paging/page_table.cpp | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index feb327a..e6542a2 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -58,7 +58,7 @@ namespace teachos::arch::memory::paging * * @param table_index Index of this page table in the page table one level lower. */ - auto next_table(std::size_t table_index) const -> std::optional; + auto next_table(std::size_t table_index) -> std::optional; /** * @brief Index operator overload to access specific immutable entry directy. @@ -83,7 +83,7 @@ namespace teachos::arch::memory::paging * @param value Value we want to decrement on * @return level New level value decrement by one, meaning the level is also decrement by one Level4 --> Level3, ... */ - friend auto operator--(level value, int) -> level; + friend auto operator--(level & value, int) -> level; private: page_table * handle; ///< Handle to underlying page table, can never be null (invariant ensured by constructor) diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 555d38a..b229ff7 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -99,25 +99,30 @@ namespace teachos::arch::memory::paging auto page_table_handle::zero_entries() -> void { handle->zero_entries(); } - auto page_table_handle::next_table(std::size_t table_index) const -> std::optional + auto page_table_handle::next_table(std::size_t table_index) -> std::optional { exception_handling::assert(handle_level != page_table_handle::LEVEL1, "[Page Table] Attempted to call next_table on level 1 page table"); auto next_table = handle->next_table(table_index); if (next_table) { - return page_table_handle{next_table.value(), handle_level--}; + handle_level--; + return page_table_handle{next_table.value(), handle_level}; } return std::nullopt; } auto page_table_handle::operator[](std::size_t index) const -> entry { return handle->operator[](index); } - auto operator--(page_table_handle::level value, int) -> page_table_handle::level + auto operator--(page_table_handle::level & value, int) -> page_table_handle::level { exception_handling::assert(value != page_table_handle::LEVEL1, "[Page table] Attempted to decrement enum to value outside of range"); + + page_table_handle::level original_value = value; auto new_value = static_cast::type>(value); - return static_cast(--new_value); + value = static_cast(--new_value); + + return original_value; } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 9a1f3e66b6c860fdca689241e78f85bdbb5b4da5 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 22 Oct 2024 08:01:40 +0000 Subject: add previous state to comment --- arch/x86_64/src/memory/paging/page_mapper.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 1371868..03f9f10 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -5,6 +5,7 @@ namespace teachos::arch::memory::paging namespace { // TODO: Set the address to a sensible location, this is merely a placeholder + // constexpr size_t PAGE_TABLE_LEVEL_4_ADDRESS = 0xfffffffffffff000; constexpr size_t PAGE_TABLE_LEVEL_4_ADDRESS = 0x27AC40; } // namespace -- cgit v1.2.3 From d43f5cb4c13b39b89951434e73078859d121cd4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 22 Oct 2024 08:13:13 +0000 Subject: Implement precrement instead --- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 4 ++-- arch/x86_64/include/arch/memory/paging/page_table.hpp | 2 +- arch/x86_64/src/memory/paging/page_mapper.cpp | 2 +- arch/x86_64/src/memory/paging/page_table.cpp | 10 +++------- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 173db9b..a2d076a 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -63,7 +63,7 @@ namespace teachos::arch::memory::paging { auto current_handle = create_or_get(); - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; level--) + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) { auto level_index = page.get_level_index(level); auto next_handle = current_handle.next_table(level_index); @@ -136,7 +136,7 @@ namespace teachos::arch::memory::paging auto current_handle = create_or_get(); - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; level--) + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) { auto level_index = page.get_level_index(level); auto next_handle = current_handle.next_table(level_index); diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index e6542a2..1fd6f61 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -83,7 +83,7 @@ namespace teachos::arch::memory::paging * @param value Value we want to decrement on * @return level New level value decrement by one, meaning the level is also decrement by one Level4 --> Level3, ... */ - friend auto operator--(level & value, int) -> level; + friend auto operator--(level & value) -> level &; private: page_table * handle; ///< Handle to underlying page table, can never be null (invariant ensured by constructor) diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 03f9f10..e9c6766 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -20,7 +20,7 @@ namespace teachos::arch::memory::paging { auto current_handle = create_or_get(); - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; level--) + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) { auto 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 diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index b229ff7..c735a62 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -106,23 +106,19 @@ namespace teachos::arch::memory::paging auto next_table = handle->next_table(table_index); if (next_table) { - handle_level--; - return page_table_handle{next_table.value(), handle_level}; + return page_table_handle{next_table.value(), --handle_level}; } return std::nullopt; } auto page_table_handle::operator[](std::size_t index) const -> entry { return handle->operator[](index); } - auto operator--(page_table_handle::level & value, int) -> page_table_handle::level + 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"); - - page_table_handle::level original_value = value; auto new_value = static_cast::type>(value); value = static_cast(--new_value); - - return original_value; + return value; } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From c29d8c3b65f63bfd54031412d9c2975ef7571460 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 22 Oct 2024 08:58:48 +0000 Subject: use actual page_table address --- arch/x86_64/include/arch/boot/pointers.hpp | 3 +++ arch/x86_64/include/arch/memory/paging/page_entry.hpp | 4 ++-- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 2 +- arch/x86_64/include/arch/memory/paging/page_table.hpp | 2 +- arch/x86_64/src/boot/boot.s | 2 +- arch/x86_64/src/memory/paging/page_entry.cpp | 4 ++-- arch/x86_64/src/memory/paging/page_mapper.cpp | 9 ++++----- arch/x86_64/src/memory/paging/page_table.cpp | 14 +++++++------- 8 files changed, 21 insertions(+), 19 deletions(-) diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index 25800f4..37840b6 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -1,11 +1,14 @@ #ifndef TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP #define TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP +#include "arch/memory/paging/page_table.hpp" + #include namespace teachos::arch::boot { extern "C" size_t const multiboot_information_pointer; + extern "C" memory::paging::page_table * page_map_level_4; } // namespace teachos::arch::boot #endif diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 2b3b3f3..33126f0 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -59,9 +59,9 @@ namespace teachos::arch::memory::paging * to calculate_physical_address() will return the new address and flags instead of the old one. * * @param frame Physical frame that contains the address we want to copy into our underlying std::bitset. - * @param flags Entry flags which will be copied into our underlying std::bitset. + * @param additional_flags Entry flags which will be copied into our underlying std::bitset. */ - auto set_entry(allocator::physical_frame frame, std::bitset<64U> flags) -> void; + auto set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void; /** * @brief Checks if the given std::bitset is a subset or equivalent to the underlying std::bitset. diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 173db9b..358b90c 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -77,7 +77,7 @@ namespace teachos::arch::memory::paging exception_handling::assert(allocated_frame.has_value(), "[Page mapper] Unable to allocate frame"); current_handle[level_index].set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); // There should now be an entry at the previously not existent index, therefore we can simply access it again. - next_handle = current_handle.next_table(page.get_level_index(level)); + next_handle = current_handle.next_table(level_index); exception_handling::assert(next_handle.has_value(), "[Page mapper] Unable to create new entry into page table"); next_handle.value().zero_entries(); } diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index e6542a2..ad5c794 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -66,7 +66,7 @@ namespace teachos::arch::memory::paging * @param index Index of the entry we want to access and only read. * @return Entry at the given table index. */ - auto operator[](std::size_t index) const -> entry; + auto operator[](std::size_t index) -> entry &; /** * @brief Decrements the page table handle level enum by one, is defined so we can use it as a replacement for an diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 710d4ce..7d6b322 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -10,7 +10,7 @@ .align 4096 /** - * Reserve space for the page maps we are going to used during startup. + * 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. diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index a172ca8..5d597ab 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -33,10 +33,10 @@ namespace teachos::arch::memory::paging 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> flags) -> void + auto entry::set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void { exception_handling::assert((frame.start_address() & ~0x000fffff'fffff000) == 0, "[Paging Entry] Start address is not aligned with page"); - flags = std::bitset<64U>{frame.start_address()} | flags; + flags = std::bitset<64U>{frame.start_address()} | additional_flags; } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 03f9f10..1fe72e3 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -1,19 +1,18 @@ #include "arch/memory/paging/page_mapper.hpp" +#include "arch/boot/pointers.hpp" + namespace teachos::arch::memory::paging { namespace { - // TODO: Set the address to a sensible location, this is merely a placeholder - // constexpr size_t PAGE_TABLE_LEVEL_4_ADDRESS = 0xfffffffffffff000; - constexpr size_t PAGE_TABLE_LEVEL_4_ADDRESS = 0x27AC40; + page_table * PAGE_TABLE_LEVEL_4_ADDRESS = boot::page_map_level_4; } // namespace auto create_or_get() -> page_table_handle { - static page_table * const active_page{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS)}; // We can not save page_table_handle as a static variable directly, if we do the program will fail to link. - return page_table_handle{active_page, page_table_handle::LEVEL4}; + return page_table_handle{PAGE_TABLE_LEVEL_4_ADDRESS, page_table_handle::LEVEL4}; } auto translate_page(virtual_page page) -> std::optional diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index b229ff7..8971209 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -24,7 +24,7 @@ namespace teachos::arch::memory::paging * * @param table_index Index of this page table in the page table one level lower. */ - auto next_table(std::size_t table_index) const -> std::optional; + auto next_table(std::size_t table_index) -> std::optional; /** * @brief Index operator overload to access specific entries directy. @@ -32,7 +32,7 @@ namespace teachos::arch::memory::paging * @param index Index of the entry we want to access and read or write too. * @return Entry at the given table index. */ - auto operator[](std::size_t index) const -> entry; + auto operator[](std::size_t index) -> entry &; private: /** @@ -44,7 +44,7 @@ namespace teachos::arch::memory::paging * @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; + auto next_table_address(std::size_t table_index) -> std::optional; entry entries[PAGE_TABLE_ENTRY_COUNT]; ///< Entries containing addresses to page tables of a level below or ///< actual virtual addresses for the level 1 page table. @@ -60,7 +60,7 @@ namespace teachos::arch::memory::paging } } - auto page_table::next_table(std::size_t table_index) const -> std::optional + auto page_table::next_table(std::size_t table_index) -> std::optional { auto address = next_table_address(table_index); if (address) @@ -70,7 +70,7 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto page_table::operator[](std::size_t index) const -> entry + auto page_table::operator[](std::size_t index) -> entry & { // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which // could be incredibly hard to debug later. @@ -78,7 +78,7 @@ namespace teachos::arch::memory::paging return entries[index]; } - auto page_table::next_table_address(std::size_t table_index) const -> std::optional + auto page_table::next_table_address(std::size_t table_index) -> std::optional { auto entry = this->operator[](table_index); @@ -112,7 +112,7 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto page_table_handle::operator[](std::size_t index) const -> entry { return handle->operator[](index); } + auto page_table_handle::operator[](std::size_t index) -> entry & { return handle->operator[](index); } auto operator--(page_table_handle::level & value, int) -> page_table_handle::level { -- cgit v1.2.3 From d42ef85dbc3786fb45b8b4625b3f07446f51390d Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 22 Oct 2024 09:19:57 +0000 Subject: add todos --- arch/x86_64/include/arch/memory/paging/page_entry.hpp | 4 ++-- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 2 ++ arch/x86_64/src/memory/paging/page_table.cpp | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 33126f0..73aa554 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -85,8 +85,8 @@ namespace teachos::arch::memory::paging */ auto calculate_physical_address() const -> std::size_t; - std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be freely - ///< used for additional flags by the operating system. + std::bitset<64U> flags = {}; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be + ///< freely used for additional flags by the operating system. }; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index cd71c73..4735c13 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -79,6 +79,8 @@ namespace teachos::arch::memory::paging // There should now be an entry at the previously not existent index, therefore we can simply access it again. next_handle = current_handle.next_table(level_index); exception_handling::assert(next_handle.has_value(), "[Page mapper] Unable to create new entry into page table"); + + // TODO: Crashes here! next_handle.value().zero_entries(); } current_handle = next_handle.value(); diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 33d0b75..5faad24 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -46,8 +46,8 @@ namespace teachos::arch::memory::paging */ auto next_table_address(std::size_t table_index) -> std::optional; - entry entries[PAGE_TABLE_ENTRY_COUNT]; ///< Entries containing addresses to page tables of a level below or - ///< actual virtual addresses for the level 1 page table. + entry entries[PAGE_TABLE_ENTRY_COUNT] = {}; ///< 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 @@ -55,6 +55,7 @@ namespace teachos::arch::memory::paging constexpr size_t entry_amount = sizeof(entries) / sizeof(entries[0]); for (size_t i = 0; i < entry_amount; ++i) { + // TODO: Crashes when trying to access entry! auto entry = this->operator[](i); entry.set_unused(); } -- cgit v1.2.3 From ef22c9394534014dbda3e2a070df3d02a9fd041e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 22 Oct 2024 09:22:04 +0000 Subject: Remove default initalization of member variables --- arch/x86_64/include/arch/memory/paging/page_entry.hpp | 4 ++-- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 3 +-- arch/x86_64/src/memory/paging/page_table.cpp | 5 ++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 73aa554..9ca5469 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -85,8 +85,8 @@ namespace teachos::arch::memory::paging */ auto calculate_physical_address() const -> std::size_t; - std::bitset<64U> flags = {}; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be - ///< freely used for additional flags by the operating system. + std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be + ///< freely used for additional flags by the operating system. }; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 4735c13..80f6eb4 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -79,8 +79,7 @@ namespace teachos::arch::memory::paging // There should now be an entry at the previously not existent index, therefore we can simply access it again. next_handle = current_handle.next_table(level_index); exception_handling::assert(next_handle.has_value(), "[Page mapper] Unable to create new entry into page table"); - - // TODO: Crashes here! + // TODO: Crashes when trying to access underlying entries array. next_handle.value().zero_entries(); } current_handle = next_handle.value(); diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 5faad24..33d0b75 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -46,8 +46,8 @@ namespace teachos::arch::memory::paging */ auto next_table_address(std::size_t table_index) -> std::optional; - entry entries[PAGE_TABLE_ENTRY_COUNT] = {}; ///< Entries containing addresses to page tables of a level below or - ///< actual virtual addresses for the level 1 page table. + entry entries[PAGE_TABLE_ENTRY_COUNT]; ///< 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 @@ -55,7 +55,6 @@ namespace teachos::arch::memory::paging constexpr size_t entry_amount = sizeof(entries) / sizeof(entries[0]); for (size_t i = 0; i < entry_amount; ++i) { - // TODO: Crashes when trying to access entry! auto entry = this->operator[](i); entry.set_unused(); } -- cgit v1.2.3 From 61db7fa6097a9e3784f8fb18a8d3de47d7d7c007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 23 Oct 2024 13:28:07 +0000 Subject: Extract next_table_or_create into page_table --- .../include/arch/memory/paging/page_mapper.hpp | 19 +------------ .../include/arch/memory/paging/page_table.hpp | 32 ++++++++++++++++++++++ arch/x86_64/src/memory/paging/page_table.cpp | 2 -- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 80f6eb4..3590dda 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -65,24 +65,7 @@ namespace teachos::arch::memory::paging for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) { - auto level_index = page.get_level_index(level); - auto next_handle = current_handle.next_table(level_index); - // If the next table method failed then it means that the page level of the frame we want allocate has not yet - // been created itself. So we have to do that before we are able to allocate the wanted frame. This has to be done - // for every level, meaning we potenitally create a level 4, level 3 and level 2 page entry, each pointing to a - // page table one level below. - if (!next_handle) - { - auto allocated_frame = allocator.allocate_frame(); - exception_handling::assert(allocated_frame.has_value(), "[Page mapper] Unable to allocate frame"); - current_handle[level_index].set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); - // There should now be an entry at the previously not existent index, therefore we can simply access it again. - next_handle = current_handle.next_table(level_index); - exception_handling::assert(next_handle.has_value(), "[Page mapper] Unable to create new entry into page table"); - // TODO: Crashes when trying to access underlying entries array. - next_handle.value().zero_entries(); - } - current_handle = next_handle.value(); + current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level)); } auto level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index eb0b984..8250e30 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -1,6 +1,8 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP +#include "arch/exception_handling/assert.hpp" +#include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/paging/page_entry.hpp" namespace teachos::arch::memory::paging @@ -60,6 +62,36 @@ namespace teachos::arch::memory::paging */ auto next_table(std::size_t table_index) -> std::optional; + /** + * @brief Call next_table and then checks if the table already exists, if it does not it will use the given + * allocator to get the next free frame and set the entry to that instead. + * + * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate + * entries when a new page table is required. + * @param table_index Index of this page table in the page table one level lower. + */ + template + auto next_table_or_create(T & allocator, std::size_t table_index) -> page_table_handle + { + auto next_handle = next_table(table_index); + // If the next table method failed then it means that the page level of the frame we want allocate has not yet + // been created itself. So we have to do that before we are able to allocate the wanted frame. This has to be done + // for every level, meaning we potenitally create a level 4, level 3 and level 2 page entry, each pointing to a + // page table one level below. + if (!next_handle) + { + auto allocated_frame = allocator.allocate_frame(); + exception_handling::assert(allocated_frame.has_value(), "[Page mapper] Unable to allocate frame"); + this->operator[](table_index).set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); + // There should now be an entry at the previously not existent index, therefore we can simply access it again. + next_handle = next_table(table_index); + exception_handling::assert(next_handle.has_value(), "[Page mapper] Unable to create new entry into page table"); + // TODO: Crashes when trying to access underlying entries array. + next_handle.value().zero_entries(); + } + return next_handle.value(); + } + /** * @brief Index operator overload to access specific immutable entry directy. * diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 33d0b75..40662e3 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -1,7 +1,5 @@ #include "arch/memory/paging/page_table.hpp" -#include "arch/exception_handling/assert.hpp" - namespace teachos::arch::memory::paging { /** -- cgit v1.2.3 From c373109b4912e857273c30b3ebd2d25296da85fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 23 Oct 2024 13:40:02 +0000 Subject: Ensure page table is static --- arch/x86_64/src/memory/paging/page_mapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index b89b637..995f2c3 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -6,7 +6,7 @@ namespace teachos::arch::memory::paging { namespace { - page_table * PAGE_TABLE_LEVEL_4_ADDRESS = boot::page_map_level_4; + static page_table * PAGE_TABLE_LEVEL_4_ADDRESS = boot::page_map_level_4; } // namespace auto create_or_get() -> page_table_handle -- cgit v1.2.3 From 355993d16fcdb2d020d6f1ff02adfa191f8f4d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 23 Oct 2024 13:42:32 +0000 Subject: Initalize page table on first call --- arch/x86_64/src/memory/paging/page_mapper.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 995f2c3..39b5e64 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -4,15 +4,11 @@ namespace teachos::arch::memory::paging { - namespace - { - static page_table * PAGE_TABLE_LEVEL_4_ADDRESS = boot::page_map_level_4; - } // namespace - auto create_or_get() -> page_table_handle { + static page_table * table = boot::page_map_level_4; // We can not save page_table_handle as a static variable directly, if we do the program will fail to link. - return page_table_handle{PAGE_TABLE_LEVEL_4_ADDRESS, page_table_handle::LEVEL4}; + return page_table_handle{table, page_table_handle::LEVEL4}; } auto translate_page(virtual_page page) -> std::optional -- cgit v1.2.3 From cf52909d11fba4e81e77f264abe1f7055399793a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 23 Oct 2024 13:55:23 +0000 Subject: Revert "Initalize page table on first call" This reverts commit 355993d16fcdb2d020d6f1ff02adfa191f8f4d48. --- arch/x86_64/src/memory/paging/page_mapper.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 39b5e64..995f2c3 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -4,11 +4,15 @@ namespace teachos::arch::memory::paging { + namespace + { + static page_table * PAGE_TABLE_LEVEL_4_ADDRESS = boot::page_map_level_4; + } // namespace + auto create_or_get() -> page_table_handle { - static page_table * table = boot::page_map_level_4; // We can not save page_table_handle as a static variable directly, if we do the program will fail to link. - return page_table_handle{table, page_table_handle::LEVEL4}; + return page_table_handle{PAGE_TABLE_LEVEL_4_ADDRESS, page_table_handle::LEVEL4}; } auto translate_page(virtual_page page) -> std::optional -- cgit v1.2.3 From c7bc900ef9293045265f503696277b0405119c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 23 Oct 2024 14:29:08 +0000 Subject: Use virtual level 4 address again --- arch/x86_64/src/memory/paging/page_mapper.cpp | 6 ++++-- arch/x86_64/src/memory/paging/page_table.cpp | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 995f2c3..687bffd 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -6,13 +6,15 @@ namespace teachos::arch::memory::paging { namespace { - static page_table * PAGE_TABLE_LEVEL_4_ADDRESS = boot::page_map_level_4; + constexpr size_t PAGE_TABLE_LEVEL_4_ADDRESS = 0xfffffffffffff000; } // namespace auto create_or_get() -> page_table_handle { + // Perhaps we need to access boot::page_map_level_4; so we do not crash when returning entry? + static page_table * const active_page = reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS); // We can not save page_table_handle as a static variable directly, if we do the program will fail to link. - return page_table_handle{PAGE_TABLE_LEVEL_4_ADDRESS, page_table_handle::LEVEL4}; + return page_table_handle{active_page, page_table_handle::LEVEL4}; } auto translate_page(virtual_page page) -> std::optional diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 40662e3..bfd91da 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -51,6 +51,7 @@ namespace teachos::arch::memory::paging auto page_table::zero_entries() -> void { constexpr size_t entry_amount = sizeof(entries) / sizeof(entries[0]); + static_assert(entry_amount == PAGE_TABLE_ENTRY_COUNT); for (size_t i = 0; i < entry_amount; ++i) { auto entry = this->operator[](i); @@ -73,7 +74,8 @@ namespace teachos::arch::memory::paging // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which // could be incredibly hard to debug later. exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] Index out of bounds"); - return entries[index]; + auto & entry = entries[index]; + return entry; } auto page_table::next_table_address(std::size_t table_index) -> std::optional -- cgit v1.2.3 From 97fe123c2d5bd0c49e8d360a989fcee8971c61ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 23 Oct 2024 14:32:27 +0000 Subject: Add todo comment on why code crashes --- arch/x86_64/src/memory/paging/page_table.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index bfd91da..21611e1 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -74,6 +74,7 @@ namespace teachos::arch::memory::paging // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which // could be incredibly hard to debug later. exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] Index out of bounds"); + // TODO: This section seems to return completly invalid entry, debugger doesn't even show a value? Revert once fixed auto & entry = entries[index]; return entry; } -- cgit v1.2.3 From 4c97a4e1e2055ce63a0d16d1e5be880792a5e7eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 23 Oct 2024 15:08:10 +0000 Subject: Replace uint64_t with size_t --- arch/x86_64/include/arch/memory/paging/virtual_page.hpp | 4 ++-- arch/x86_64/src/memory/paging/virtual_page.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index 79801ee..f01073d 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -35,7 +35,7 @@ namespace teachos::arch::memory::paging * * @return Start address of the virtual page. */ - auto start_address() const -> uint64_t; + auto start_address() const -> size_t; /** * @brief Calculates the index into the page table with the given level, which leads to this virtual page. @@ -43,7 +43,7 @@ namespace teachos::arch::memory::paging * @param level Level of the page table we want to calculate the index for. * @return Index into the page table with the given level. */ - auto get_level_index(page_table_handle::level level) const -> uint64_t; + auto get_level_index(page_table_handle::level level) const -> size_t; /** * @brief Defaulted equals operator. diff --git a/arch/x86_64/src/memory/paging/virtual_page.cpp b/arch/x86_64/src/memory/paging/virtual_page.cpp index fd2085b..91f63b4 100644 --- a/arch/x86_64/src/memory/paging/virtual_page.cpp +++ b/arch/x86_64/src/memory/paging/virtual_page.cpp @@ -17,9 +17,9 @@ namespace teachos::arch::memory::paging return virtual_page{virtual_address / allocator::PAGE_FRAME_SIZE}; } - auto virtual_page::start_address() const -> uint64_t { return page_number * allocator::PAGE_FRAME_SIZE; } + auto virtual_page::start_address() const -> size_t { return page_number * allocator::PAGE_FRAME_SIZE; } - auto virtual_page::get_level_index(page_table_handle::level level) const -> uint64_t + auto virtual_page::get_level_index(page_table_handle::level level) const -> size_t { return (start_address() >> (level * 9U)) & 0x1FF; } -- cgit v1.2.3 From c2c7503fec31c07645fdc087dbf1ef487e90912e Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 26 Oct 2024 07:03:01 +0000 Subject: fix mmap type, adjust linker, use std::array --- arch/x86_64/include/arch/memory/multiboot/memory_map.hpp | 2 +- arch/x86_64/scripts/kernel.ld | 3 +++ arch/x86_64/src/memory/paging/page_table.cpp | 7 +++++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp index 1a38a30..858ae52 100644 --- a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp @@ -28,10 +28,10 @@ namespace teachos::arch::memory::multiboot */ struct __attribute__((packed)) memory_area { - uint32_t size; ///< Size of this structure in bytes. uint64_t base_address; ///< Base address the memory region starts at. uint64_t area_length; ///< Size of the memory region, added to base_address results in the final address. memory_area_type type; ///< Specific type of memory the region can contain. + uint32_t zero; ///< }; /** diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 31d8be3..c777d10 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -59,6 +59,9 @@ SECTIONS *(.boot_stack) } + . = ALIGN(4K); + _end_of_image = .; + /*************************************************************************** * Now it is time to load the 64-bit kernel code. We virtually load it into * the upper 2GiB, while adjusting the linear load address appropriately. We diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 21611e1..1d7b8a0 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -1,5 +1,7 @@ #include "arch/memory/paging/page_table.hpp" +#include + namespace teachos::arch::memory::paging { /** @@ -44,8 +46,9 @@ namespace teachos::arch::memory::paging */ auto next_table_address(std::size_t table_index) -> std::optional; - entry entries[PAGE_TABLE_ENTRY_COUNT]; ///< Entries containing addresses to page tables of a level below or - ///< actual virtual addresses for the level 1 page table. + 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 -- cgit v1.2.3 From 873f8c52699c6d4e3d32e5df253ae8ec0266a501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 26 Oct 2024 07:10:37 +0000 Subject: Use alignas instead of reserved keyword --- arch/x86_64/include/arch/memory/multiboot/memory_map.hpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp index 858ae52..e30d2c4 100644 --- a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp @@ -21,17 +21,14 @@ namespace teachos::arch::memory::multiboot /** * @brief Defines an entry in the entries array of the memory_map struct. * - * @note Has to have all padding stripped between the individual values, because the size of the entry needs to be - * exactly 24 bytes and not one byte more. See - * https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Packed-Structures.html for more information on the - * used attribute. + * @note Last value needs to be padded, because the size of the entry needs to be + * exactly 24 bytes and not one byte more. */ - struct __attribute__((packed)) memory_area + struct memory_area { uint64_t base_address; ///< Base address the memory region starts at. uint64_t area_length; ///< Size of the memory region, added to base_address results in the final address. - memory_area_type type; ///< Specific type of memory the region can contain. - uint32_t zero; ///< + alignas(8) memory_area_type type; ///< Specific type of memory the region can contain. }; /** -- cgit v1.2.3 From e44a16e45a309aa96375a2215d0d2405cf467dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 26 Oct 2024 07:37:50 +0000 Subject: Use construct at to zero memory before using it. --- arch/x86_64/src/memory/paging/page_mapper.cpp | 11 ++--------- arch/x86_64/src/memory/paging/page_table.cpp | 15 +++++++++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 687bffd..cd77366 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -4,17 +4,10 @@ namespace teachos::arch::memory::paging { - namespace - { - constexpr size_t PAGE_TABLE_LEVEL_4_ADDRESS = 0xfffffffffffff000; - } // namespace - auto create_or_get() -> page_table_handle { - // Perhaps we need to access boot::page_map_level_4; so we do not crash when returning entry? - static page_table * const active_page = reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS); - // We can not save page_table_handle as a static variable directly, if we do the program will fail to link. - return page_table_handle{active_page, page_table_handle::LEVEL4}; + // TODO: As soon as linker error is fixed in toolchain make handle static and return that. + return page_table_handle{arch::boot::page_map_level_4, page_table_handle::LEVEL4}; } auto translate_page(virtual_page page) -> std::optional diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 1d7b8a0..2f97a80 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -1,6 +1,7 @@ #include "arch/memory/paging/page_table.hpp" #include +#include namespace teachos::arch::memory::paging { @@ -9,6 +10,11 @@ namespace teachos::arch::memory::paging */ struct page_table { + /** + * @brief Defaulted constructor. + */ + page_table() = default; + /** * @brief Set every entry of the page to unused. */ @@ -46,9 +52,9 @@ namespace teachos::arch::memory::paging */ auto next_table_address(std::size_t table_index) -> 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. + 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 @@ -67,7 +73,8 @@ namespace teachos::arch::memory::paging auto address = next_table_address(table_index); if (address) { - return reinterpret_cast(address.value()); + // TODO: Probably erases the data even if the page table already existed previously and had values. + return std::construct_at(reinterpret_cast(address.value())); } return std::nullopt; } -- cgit v1.2.3 From b00ec1f863e330d2c4ae1d1ef4d352ab73861f17 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 26 Oct 2024 07:47:27 +0000 Subject: move paging alignment --- arch/x86_64/scripts/kernel.ld | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index c777d10..e244ce1 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -59,9 +59,6 @@ SECTIONS *(.boot_stack) } - . = ALIGN(4K); - _end_of_image = .; - /*************************************************************************** * Now it is time to load the 64-bit kernel code. We virtually load it into * the upper 2GiB, while adjusting the linear load address appropriately. We @@ -129,6 +126,9 @@ SECTIONS *(.bss*) } + . = ALIGN(4K); + _end_of_image = .; + /*************************************************************************** * In accordance with the symbol definitions at the start, we generate some * symbols to mark the end of our loaded image. -- cgit v1.2.3 From bca36b0c10fcae447c90e211e83987fea28eecdc Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 26 Oct 2024 08:47:26 +0000 Subject: wip --- arch/x86_64/include/arch/boot/pointers.hpp | 2 ++ arch/x86_64/include/arch/memory/paging/page_table.hpp | 5 +++++ arch/x86_64/scripts/kernel.ld | 8 +++----- arch/x86_64/src/boot/boot.s | 16 ++++++++-------- arch/x86_64/src/memory/paging/page_mapper.cpp | 12 +++++++++++- arch/x86_64/src/memory/paging/page_table.cpp | 15 +++++++++------ 6 files changed, 38 insertions(+), 20 deletions(-) diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index 37840b6..2c42605 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -9,6 +9,8 @@ namespace teachos::arch::boot { extern "C" size_t const multiboot_information_pointer; extern "C" memory::paging::page_table * page_map_level_4; + extern "C" memory::paging::page_table * page_map_level_3; + extern "C" memory::paging::page_table * page_map_level_2; } // namespace teachos::arch::boot #endif diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 8250e30..5a072d0 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -46,6 +46,11 @@ namespace teachos::arch::memory::paging */ page_table_handle(page_table * handle, level handle_level); + /** + * @brief Initializes one page table level 3 entry. + */ + void initialize_page_table(); + /** * @brief Set every entry of the page to unused. */ diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index e244ce1..3449828 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -59,13 +59,14 @@ SECTIONS *(.boot_stack) } + . = ALIGN(4K); + _end_of_image = .; + /*************************************************************************** * Now it is time to load the 64-bit kernel code. We virtually load it into * the upper 2GiB, while adjusting the linear load address appropriately. We * also make sure to align the loaded data onto a page boundary. ***************************************************************************/ - . = ALIGN(4K); - .init ALIGN(4K) : AT(ADDR (.init)) { /* @@ -126,9 +127,6 @@ SECTIONS *(.bss*) } - . = ALIGN(4K); - _end_of_image = .; - /*************************************************************************** * In accordance with the symbol definitions at the start, we generate some * symbols to mark the end of our loaded image. diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 7d6b322..6ed1e0a 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -24,11 +24,11 @@ .global page_map_level_4 page_map_level_4: .skip 512 * 8 -.global page_map_level_3_low -page_map_level_3_low: .skip 512 * 8 +.global page_map_level_3 +page_map_level_3: .skip 512 * 8 -.global page_map_level_2_low -page_map_level_2_low: .skip 512 * 8 +.global page_map_level_2 +page_map_level_2: .skip 512 * 8 /** * Reserve some space for the Multiboot 2 information pointer. @@ -318,14 +318,14 @@ enable_sse: */ prepare_page_maps: /* Add an entry to the PML4, pointing to the low PML3 */ - mov $page_map_level_3_low, %eax + mov $page_map_level_3, %eax or $0x3, %eax mov %eax, (page_map_level_4 + ((0x0000000000100000 >> 39) & 0x1ff) * 8) /* Add an entry to the low PML3, pointing to the low PML2 */ - mov $page_map_level_2_low, %eax + mov $page_map_level_2, %eax or $0x3, %eax - mov %eax, (page_map_level_3_low + ((0x0000000000100000 >> 30) & 0x1ff) * 8) + mov %eax, (page_map_level_3 + ((0x0000000000100000 >> 30) & 0x1ff) * 8) xor %ecx, %ecx @@ -337,7 +337,7 @@ prepare_page_maps: mov $(1 << 21), %eax mul %ecx or $((1 << 0) | (1 << 1) | (1 << 7)), %eax - mov %eax, page_map_level_2_low(,%ecx,8) + mov %eax, page_map_level_2(,%ecx,8) inc %ecx cmp %esi, %ecx diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index cd77366..dff9ae4 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -4,10 +4,20 @@ namespace teachos::arch::memory::paging { + auto create_or_get() -> page_table_handle { + static auto initialized = false; // TODO: As soon as linker error is fixed in toolchain make handle static and return that. - return page_table_handle{arch::boot::page_map_level_4, page_table_handle::LEVEL4}; + page_table_handle active_handle{boot::page_map_level_4, page_table_handle::LEVEL4}; + + if (!initialized) + { + active_handle.initialize_page_tables(); + initialized = true; + } + + return active_handle; } auto translate_page(virtual_page page) -> std::optional diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 2f97a80..b5315a0 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -10,11 +10,6 @@ namespace teachos::arch::memory::paging */ struct page_table { - /** - * @brief Defaulted constructor. - */ - page_table() = default; - /** * @brief Set every entry of the page to unused. */ @@ -105,7 +100,15 @@ namespace teachos::arch::memory::paging : handle(handle) , handle_level(handle_level) { - exception_handling::assert(handle, "[Page table] Attempted to pass nullptr as handle to page table handle method"); + exception_handling::assert(handle, "[Page Table] Attempted to pass nullptr as handle to page table handle method"); + } + + auto page_table_handle::initialize_page_table() -> void + { + exception_handling::assert(handle_level == page_table_handle::LEVEL4, + "[Page Table] Attempted to initialize a page table of level 3 or lower"); + + auto level_3_page_table = boot::page_map_level_3; } auto page_table_handle::zero_entries() -> void { handle->zero_entries(); } -- cgit v1.2.3 From 878751001c3de6e7fb24c6212957cd5d753a62d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 26 Oct 2024 08:47:56 +0000 Subject: Commit TLB flush --- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 3590dda..4905e9e 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -9,6 +9,17 @@ namespace teachos::arch::memory::paging { + namespace + { + /** + * @brief Invalidates any translation lookaside buffer (TLB) entries into the page table the given entry is cotained + * in. See https://www.felixcloutier.com/x86/invlpg for more information int he used x86 instruction. + * + * @param entry Any entry into the page table we want to invalidate all cached entries in. + */ + auto invalidate_page_cache(entry * entry) -> void { asm volatile("invlpg (%0)" ::"r"(entry) : "memory"); } + } // namespace + /** * @brief Creates a single instance of the level 4 page table table and returns handle to it or alternatively returns * the previously created handle instead. The instance is owned by this method and is static, meaning it lives on for @@ -135,7 +146,7 @@ namespace teachos::arch::memory::paging exception_handling::assert(level1_frame.has_value(), "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); level1_entry.set_unused(); - // TODO: Flush the translation lookaside buffer to clear the entry from cache as well. (mov cr3, cr3) + invalidate_page_cache(&level1_entry); // TODO: Deallocate and unmap level 1, 2, 3 page table entry if this was the last page in them. // TODO: Fix deallocate because it is not yet implemented. allocator.deallocate_frame(level1_frame.value()); -- cgit v1.2.3 From e56964da2dd54e598d3a7fca20fc0071f32026a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 26 Oct 2024 09:20:53 +0000 Subject: Adjust to toolchain updates --- .vscode/tasks.json | 4 ++++ arch/x86_64/include/arch/boot/pointers.hpp | 2 -- arch/x86_64/include/arch/memory/paging/page_table.hpp | 4 ++-- arch/x86_64/src/memory/paging/page_mapper.cpp | 3 +-- arch/x86_64/src/memory/paging/page_table.cpp | 5 ++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 83b2248..70c8159 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -9,6 +9,8 @@ "-S", "-s", "-m", + "-display", + "curses", "32M", "-cdrom", "${workspaceFolder}/build/teachos-${input:build_type}.iso" @@ -37,6 +39,8 @@ "type": "shell", "args": [ "-m", + "-display", + "curses", "32M", "-cdrom", "${workspaceFolder}/build/teachos-${input:build_type}.iso" diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index 2c42605..37840b6 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -9,8 +9,6 @@ namespace teachos::arch::boot { extern "C" size_t const multiboot_information_pointer; extern "C" memory::paging::page_table * page_map_level_4; - extern "C" memory::paging::page_table * page_map_level_3; - extern "C" memory::paging::page_table * page_map_level_2; } // namespace teachos::arch::boot #endif diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 5a072d0..291ea8d 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -47,9 +47,9 @@ namespace teachos::arch::memory::paging page_table_handle(page_table * handle, level handle_level); /** - * @brief Initializes one page table level 3 entry. + * @brief Initializes one page table level 4 entry. */ - void initialize_page_table(); + void initialize_page_tables(); /** * @brief Set every entry of the page to unused. diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index dff9ae4..75d6759 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -8,8 +8,7 @@ namespace teachos::arch::memory::paging auto create_or_get() -> page_table_handle { static auto initialized = false; - // TODO: As soon as linker error is fixed in toolchain make handle static and return that. - page_table_handle active_handle{boot::page_map_level_4, page_table_handle::LEVEL4}; + static page_table_handle active_handle{boot::page_map_level_4, page_table_handle::LEVEL4}; if (!initialized) { diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index b5315a0..808fbbc 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -103,12 +103,11 @@ namespace teachos::arch::memory::paging exception_handling::assert(handle, "[Page Table] Attempted to pass nullptr as handle to page table handle method"); } - auto page_table_handle::initialize_page_table() -> void + auto page_table_handle::initialize_page_tables() -> void { exception_handling::assert(handle_level == page_table_handle::LEVEL4, "[Page Table] Attempted to initialize a page table of level 3 or lower"); - - auto level_3_page_table = boot::page_map_level_3; + // std::construct_at(reinterpret_cast(_end_of_image)); } auto page_table_handle::zero_entries() -> void { handle->zero_entries(); } -- cgit v1.2.3 From 8bc46560bf201dc6919d6fb72f7880812d7ecc98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 26 Oct 2024 09:39:26 +0000 Subject: Add automatic fetching of newest image to devcontainer rebuild --- .devcontainer/x86-64/devcontainer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.devcontainer/x86-64/devcontainer.json b/.devcontainer/x86-64/devcontainer.json index 6899c4c..1eb5859 100644 --- a/.devcontainer/x86-64/devcontainer.json +++ b/.devcontainer/x86-64/devcontainer.json @@ -10,5 +10,6 @@ "zixuanwang.linkerscript" ] } - } + }, + "initializeCommand": "docker pull registry.gitlab.ost.ch:45023/teachos/devcontainers/x86-64:14.2.0", } -- cgit v1.2.3 From 86dcd6d56a5a1d59f52eddd94fccbe0d0c41d743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 26 Oct 2024 09:44:58 +0000 Subject: Fix wrong args order in taks --- .vscode/tasks.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 70c8159..6b5368c 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -9,9 +9,9 @@ "-S", "-s", "-m", + "32M", "-display", "curses", - "32M", "-cdrom", "${workspaceFolder}/build/teachos-${input:build_type}.iso" ], @@ -39,9 +39,9 @@ "type": "shell", "args": [ "-m", + "32M", "-display", "curses", - "32M", "-cdrom", "${workspaceFolder}/build/teachos-${input:build_type}.iso" ], -- cgit v1.2.3 From 4a3df3a36f4843ee5738e816811aa456fe82acaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 26 Oct 2024 09:58:27 +0000 Subject: Fix debug task --- .vscode/tasks.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 6b5368c..2e076e4 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -10,8 +10,6 @@ "-s", "-m", "32M", - "-display", - "curses", "-cdrom", "${workspaceFolder}/build/teachos-${input:build_type}.iso" ], -- cgit v1.2.3 From 47ec911e3b3624d875da5b9cc0102e3d17a6d54a Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 26 Oct 2024 10:09:46 +0000 Subject: use linker variable --- .vscode/tasks.json | 2 -- arch/x86_64/src/memory/paging/page_table.cpp | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 6b5368c..2e076e4 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -10,8 +10,6 @@ "-s", "-m", "32M", - "-display", - "curses", "-cdrom", "${workspaceFolder}/build/teachos-${input:build_type}.iso" ], diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 808fbbc..059ada2 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -3,6 +3,8 @@ #include #include +extern char _end_of_image; + namespace teachos::arch::memory::paging { /** @@ -107,7 +109,7 @@ namespace teachos::arch::memory::paging { exception_handling::assert(handle_level == page_table_handle::LEVEL4, "[Page Table] Attempted to initialize a page table of level 3 or lower"); - // std::construct_at(reinterpret_cast(_end_of_image)); + auto level3_page_table = std::construct_at(reinterpret_cast(_end_of_image)); } auto page_table_handle::zero_entries() -> void { handle->zero_entries(); } -- cgit v1.2.3 From ffb6507d565585bb2a817ff01317b7643bd6d981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 26 Oct 2024 11:23:58 +0000 Subject: Create for loops to construct base level 3 page table --- arch/x86_64/src/memory/paging/page_table.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 059ada2..935dd8c 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -70,8 +70,7 @@ namespace teachos::arch::memory::paging auto address = next_table_address(table_index); if (address) { - // TODO: Probably erases the data even if the page table already existed previously and had values. - return std::construct_at(reinterpret_cast(address.value())); + return reinterpret_cast(address.value()); } return std::nullopt; } @@ -109,7 +108,17 @@ namespace teachos::arch::memory::paging { exception_handling::assert(handle_level == page_table_handle::LEVEL4, "[Page Table] Attempted to initialize a page table of level 3 or lower"); - auto level3_page_table = std::construct_at(reinterpret_cast(_end_of_image)); + auto level3_page_table = std::construct_at(reinterpret_cast(&_end_of_image)); + for (size_t n = 1; n <= PAGE_TABLE_ENTRY_COUNT; ++n) + { + size_t offset = sizeof(page_table) * n; + std::construct_at(reinterpret_cast(&_end_of_image + offset)); + for (size_t m = 0; m < PAGE_TABLE_ENTRY_COUNT; ++m) + { + size_t offset = sizeof(page_table) * (n + m); + std::construct_at(reinterpret_cast(&_end_of_image + offset)); + } + } } auto page_table_handle::zero_entries() -> void { handle->zero_entries(); } -- cgit v1.2.3 From bc993ccf7c5a80a8f4b1cd05437701efb81beec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 26 Oct 2024 11:24:13 +0000 Subject: Fix typo --- arch/x86_64/src/memory/paging/page_table.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 935dd8c..38d5025 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -113,7 +113,7 @@ namespace teachos::arch::memory::paging { size_t offset = sizeof(page_table) * n; std::construct_at(reinterpret_cast(&_end_of_image + offset)); - for (size_t m = 0; m < PAGE_TABLE_ENTRY_COUNT; ++m) + for (size_t m = 1; m <= PAGE_TABLE_ENTRY_COUNT; ++m) { size_t offset = sizeof(page_table) * (n + m); std::construct_at(reinterpret_cast(&_end_of_image + offset)); -- cgit v1.2.3 From 454dcb6f2033ee80a43f99d23323b02e8fd0a115 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 26 Oct 2024 11:30:01 +0000 Subject: add doc --- arch/x86_64/src/memory/paging/page_table.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 059ada2..14ead9e 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -3,6 +3,10 @@ #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 -- cgit v1.2.3 From f4ab51df7f9ed783dbcfbecffc0a9d919c501135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 26 Oct 2024 11:44:12 +0000 Subject: Write P3 table into P4 table at index 0 --- arch/x86_64/include/arch/memory/paging/page_entry.hpp | 8 ++++++++ arch/x86_64/src/memory/paging/page_entry.cpp | 6 ++++++ arch/x86_64/src/memory/paging/page_table.cpp | 2 ++ 3 files changed, 16 insertions(+) diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 9ca5469..ba972d6 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -34,6 +34,14 @@ namespace teachos::arch::memory::paging 1UL << 63UL, ///< Page is forbidden from executing code (NXE bit in the EFER register has to be set) }; + /** + * @brief Creates a new entry object from a 64bit address. Should follow the scheme where bit index 12 - 51 are the + * actual address and the other bits are flags. + * + * @param flags Flags that will be passed to underlying std::bitset. + */ + explicit entry(uint64_t flags); + /** * @brief Whether the current page is unused, meaning the underlying std::bitset is 0. * diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 5d597ab..09d048b 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -4,6 +4,12 @@ namespace teachos::arch::memory::paging { + entry::entry(uint64_t flags) + : flags(flags) + { + // Nothing to do. + } + auto entry::is_unused() const -> bool { return flags == 0U; } auto entry::set_unused() -> void { flags = 0U; } diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index c0f199a..4747e0b 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -123,6 +123,8 @@ namespace teachos::arch::memory::paging std::construct_at(reinterpret_cast(&_end_of_image + offset)); } } + size_t const flags = reinterpret_cast(level3_page_table); + this->operator[](0U) = entry{flags}; } auto page_table_handle::zero_entries() -> void { handle->zero_entries(); } -- cgit v1.2.3 From 6eec9c34a83fc5c0d93bc485c2ee0252824c2201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 26 Oct 2024 11:57:11 +0000 Subject: Fix missing default constructor. --- arch/x86_64/include/arch/memory/paging/page_entry.hpp | 5 +++++ arch/x86_64/src/memory/paging/page_table.cpp | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index ba972d6..bfb0184 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -34,6 +34,11 @@ namespace teachos::arch::memory::paging 1UL << 63UL, ///< Page is forbidden from executing code (NXE bit in the EFER register has to be set) }; + /** + * @brief Defaulted constructor. + */ + entry() = default; + /** * @brief Creates a new entry object from a 64bit address. Should follow the scheme where bit index 12 - 51 are the * actual address and the other bits are flags. diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 4747e0b..c9b4a37 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -85,8 +85,7 @@ namespace teachos::arch::memory::paging // could be incredibly hard to debug later. exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] Index out of bounds"); // TODO: This section seems to return completly invalid entry, debugger doesn't even show a value? Revert once fixed - auto & entry = entries[index]; - return entry; + return entries[index]; } auto page_table::next_table_address(std::size_t table_index) -> std::optional -- cgit v1.2.3 From d86af47f0b62cb3ae302fb292747944620542db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 26 Oct 2024 12:19:16 +0000 Subject: Attempt to fix initalize_page_tables, crashes on n = 1, m = 507 --- arch/x86_64/src/memory/paging/page_table.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index c9b4a37..93cc0de 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -118,7 +118,7 @@ namespace teachos::arch::memory::paging std::construct_at(reinterpret_cast(&_end_of_image + offset)); for (size_t m = 1; m <= PAGE_TABLE_ENTRY_COUNT; ++m) { - size_t offset = sizeof(page_table) * (n + m); + size_t offset = sizeof(page_table) * ((PAGE_TABLE_ENTRY_COUNT * n) + m); std::construct_at(reinterpret_cast(&_end_of_image + offset)); } } -- cgit v1.2.3 From ca17ed52ea768f1e1c837207f7d27afa6ed99cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 26 Oct 2024 13:43:51 +0000 Subject: Update boot.s comments and comment initalize page tables out --- arch/x86_64/src/boot/boot.s | 8 ++++---- arch/x86_64/src/memory/paging/page_table.cpp | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 6ed1e0a..f04ae44 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -17,8 +17,8 @@ * * We need: * - A single PML 4 (since we will only use 4-level paging) - * - 2 PML 3s (since we need to map low (1+MiB) memory) - * - 2 PML 2s (since we need to map low (1+MiB) memory) + * - 1 PML 3 + * - 1 PML 2 */ .global page_map_level_4 @@ -317,12 +317,12 @@ enable_sse: * page map entries. */ prepare_page_maps: - /* Add an entry to the PML4, pointing to the low PML3 */ + /* Add an entry to the PML4, pointing to the PML3 */ mov $page_map_level_3, %eax or $0x3, %eax mov %eax, (page_map_level_4 + ((0x0000000000100000 >> 39) & 0x1ff) * 8) - /* Add an entry to the low PML3, pointing to the low PML2 */ + /* Add an entry to the PML3, pointing to the PML2 */ mov $page_map_level_2, %eax or $0x3, %eax mov %eax, (page_map_level_3 + ((0x0000000000100000 >> 30) & 0x1ff) * 8) diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 93cc0de..868cf86 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -109,6 +109,8 @@ namespace teachos::arch::memory::paging auto page_table_handle::initialize_page_tables() -> void { + // TODO: This should be done differently and only once the other methods are working see Rempaing the Kernel + /* exception_handling::assert(handle_level == page_table_handle::LEVEL4, "[Page Table] Attempted to initialize a page table of level 3 or lower"); auto level3_page_table = std::construct_at(reinterpret_cast(&_end_of_image)); @@ -124,6 +126,7 @@ namespace teachos::arch::memory::paging } size_t const flags = reinterpret_cast(level3_page_table); this->operator[](0U) = entry{flags}; + */ } auto page_table_handle::zero_entries() -> void { handle->zero_entries(); } -- cgit v1.2.3 From a29e823c6ead21fa7c8f6445411d52f57c4518fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Oct 2024 09:21:25 +0000 Subject: Attempt to start using C++20 algorithm calls. --- .../arch/memory/allocator/area_frame_allocator.hpp | 28 +++----------- .../include/arch/memory/multiboot/memory_map.hpp | 45 +++++++++++++++++++++- arch/x86_64/src/kernel/main.cpp | 13 +++++-- .../src/memory/allocator/area_frame_allocator.cpp | 24 +++++++----- arch/x86_64/src/memory/multiboot/memory_map.cpp | 15 +++++++- 5 files changed, 87 insertions(+), 38 deletions(-) diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp index a1b771e..8e971f0 100644 --- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -45,22 +45,6 @@ namespace teachos::arch::memory::allocator */ auto deallocate_frame(physical_frame physical_frame) -> void; - /** - * @brief Returns the iterator pointing to the first element of the memory area. - * Allows using this class in the for each loop, because it follows the InputIterator template scheme. - * - * @return Iterator pointing to first element of the memory area. - */ - auto begin() -> multiboot::memory_area_iterator; - - /** - * @brief Returns the iterator pointing to one past the last element of the memory area. - * Allows using this class in the for each loop, because it follows the InputIterator template scheme. - * - * @return Iterator pointing to one past the last element of the memory area. - */ - auto end() -> multiboot::memory_area_iterator; - private: /** * @brief Find the next memory area and write it into current_area. @@ -69,12 +53,12 @@ namespace teachos::arch::memory::allocator physical_frame next_free_frame; ///< The physical_frame after the last allocated one. std::optional current_area; ///< The current memory area. - multiboot::memory_area_iterator area_begin; ///< Pointer to the first element of all memory areas. - multiboot::memory_area_iterator area_end; ///< Pointer to one pas the last element of all memory areas. - physical_frame const kernel_start; ///< The start address of the kernel code in memory. - physical_frame const kernel_end; ///< The end address of the kernel code in memory. - physical_frame const multiboot_start; ///< The start address of the multiboot code in memory. - physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. + multiboot::memory_area_container const + memory_areas; ///< All memory areas in custom container allows to use std::ranges + physical_frame const kernel_start; ///< The start address of the kernel code in memory. + physical_frame const kernel_end; ///< The end address of the kernel code in memory. + physical_frame const multiboot_start; ///< The start address of the multiboot code in memory. + physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. }; } // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp index e30d2c4..3801e57 100644 --- a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp @@ -48,10 +48,16 @@ namespace teachos::arch::memory::multiboot */ struct memory_area_iterator { + /** + * @brief Defaulted constructor. + */ + memory_area_iterator() = default; + /** * @brief Constructor. * - * @param p Underlying address the iterator should point too, ensure to not pass an invalid pointer. + * @param p Underlying address the iterator should point too, ensure to not pass an invalid pointer or the + * constructo will halt execution. */ explicit memory_area_iterator(memory_area * p); @@ -80,13 +86,48 @@ namespace teachos::arch::memory::multiboot * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. * * @param other Other iterator to compare to. - * @return Whether poith iterators point to the same underlying address in memory. + * @return Whether both iterators point to the same underlying address in memory. */ bool operator==(memory_area_iterator const & other) const = default; private: memory_area * ptr; ///< Underlying address the iterator is currently pointing too. }; + + /** + * @brief Read-only container for memory areas, that allow to easily use the memory_area_iterator in C++20 ranges + * calls. + */ + struct memory_area_container + { + /** + * @brief Constructor. + * + * @param begin Pointer to the first memory area, will be used to construct the begin iterator. + * @param size Amount of entries in the container we want to construct. + */ + memory_area_container(memory_area * begin, std::size_t size); + + /** + * @brief Returns the iterator pointing to the first element of the memory area. + * Allows using this class in the for each loop, because it follows the InputIterator template scheme. + * + * @return Iterator pointing to first element of the memory area. + */ + auto begin() const -> memory_area_iterator; + + /** + * @brief Returns the iterator pointing to one past the last element of the memory area. + * Allows using this class in the for each loop, because it follows the InputIterator template scheme. + * + * @return Iterator pointing to one past the last element of the memory area. + */ + auto end() const -> memory_area_iterator; + + private: + memory_area_iterator area_begin; ///< Pointer to the first element of all memory areas. + memory_area_iterator area_end; ///< Pointer to one pas the last element of all memory areas. + }; } // namespace teachos::arch::memory::multiboot #endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index ad1eb39..3f768ee 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -19,14 +19,19 @@ namespace teachos::arch::kernel auto memory_information = memory::multiboot::read_multiboot2(); memory::allocator::area_frame_allocator allocator(memory_information); + auto test2 = allocator.allocate_frame(); + auto test1 = test2.value().start_address(); + auto test3 = test2.value().frame_number; + + if (test1 > test3) + { + } + size_t address = 42 * memory::paging::PAGE_TABLE_ENTRY_COUNT * memory::paging::PAGE_TABLE_ENTRY_COUNT * memory::allocator::PAGE_FRAME_SIZE; // 42th P3 entry auto page = memory::paging::virtual_page::containing_address(address); - auto frame = allocator.allocate_frame(); - exception_handling::assert(frame.has_value(), "[Main] Out of memory exception"); + memory::paging::map_next_free_page_to_frame(allocator, page, 0U); auto optional_frame = memory::paging::translate_page(page); - memory::paging::map_page_to_frame(allocator, page, frame.value(), 0U); - optional_frame = memory::paging::translate_page(page); video::vga::text::newline(); video::vga::text::write("Mapped physical frame: ", video::vga::text::common_attributes::green_on_black); video::vga::text::write_number(optional_frame.value().frame_number, diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index c2cafce..c3f77e1 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -2,13 +2,16 @@ #include "arch/exception_handling/assert.hpp" +#include +#include +#include + namespace teachos::arch::memory::allocator { area_frame_allocator::area_frame_allocator(multiboot::memory_information mem_info) : next_free_frame(0) , current_area(std::nullopt) - , area_begin(mem_info.memory_areas) - , area_end(mem_info.memory_areas + mem_info.area_count) + , memory_areas(mem_info.memory_areas, mem_info.area_count) , 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)) @@ -21,10 +24,17 @@ namespace teachos::arch::memory::allocator { current_area = std::nullopt; - for (multiboot::memory_area_iterator it = begin(); it != end(); ++it) - { - multiboot::memory_area & area = *it; + /**auto filtered_areas = memory_areas | std::views::filter([this](multiboot::memory_area area) { + auto address = area.base_address + area.area_length - 1; + return physical_frame::containing_address(address) >= next_free_frame; + });**/ + + std::ranges::min_element(memory_areas, [](multiboot::memory_area a, multiboot::memory_area b) { + return a.base_address < b.base_address; + }); + for (auto area : memory_areas) + { std::size_t address = area.base_address + area.area_length - 1; if (physical_frame::containing_address(address) >= next_free_frame) { @@ -90,8 +100,4 @@ namespace teachos::arch::memory::allocator exception_handling::assert(false && physical_frame.frame_number == 0, "[deallocate_frame] Not implemented Exception"); } - - auto area_frame_allocator::begin() -> multiboot::memory_area_iterator { return area_begin; } - - auto area_frame_allocator::end() -> multiboot::memory_area_iterator { return area_end; } } // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/multiboot/memory_map.cpp b/arch/x86_64/src/memory/multiboot/memory_map.cpp index 6b1d1d4..da7f05d 100644 --- a/arch/x86_64/src/memory/multiboot/memory_map.cpp +++ b/arch/x86_64/src/memory/multiboot/memory_map.cpp @@ -1,11 +1,13 @@ #include "arch/memory/multiboot/memory_map.hpp" +#include "arch/exception_handling/assert.hpp" + namespace teachos::arch::memory::multiboot { memory_area_iterator::memory_area_iterator(multiboot::memory_area * p) : ptr(p) { - // Nothing to do + exception_handling::assert(ptr, "[Memory Area] Attempted to pass nullptr as iterator"); } multiboot::memory_area & memory_area_iterator::operator*() const { return *ptr; } @@ -21,4 +23,15 @@ namespace teachos::arch::memory::multiboot ++ptr; return *this; } + + memory_area_container::memory_area_container(memory_area * begin, std::size_t size) + : area_begin(begin) + , area_end(begin + size) + { + // Nothing to do + } + + auto memory_area_container::begin() const -> multiboot::memory_area_iterator { return area_begin; } + + auto memory_area_container::end() const -> multiboot::memory_area_iterator { return area_end; } } // namespace teachos::arch::memory::multiboot -- cgit v1.2.3 From 3fb2780f665eb3514ef07d2d4a83820653e35b52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Oct 2024 11:20:46 +0000 Subject: Use container and C++20 range algorithms for allocator. --- .../include/arch/memory/multiboot/memory_map.hpp | 113 ++++++++++++++++++--- .../src/memory/allocator/area_frame_allocator.cpp | 86 +++++++--------- arch/x86_64/src/memory/multiboot/memory_map.cpp | 44 +++++++- 3 files changed, 178 insertions(+), 65 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp index 3801e57..f9c902a 100644 --- a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp @@ -3,6 +3,7 @@ #include "info.hpp" #include +#include namespace teachos::arch::memory::multiboot { @@ -44,10 +45,14 @@ namespace teachos::arch::memory::multiboot }; /** - * @brief Iterator for memory areas. + * @brief Random access iterator for memory areas. */ struct memory_area_iterator { + using iterator_category = std::random_access_iterator_tag; ///< Iterator category of this type. + using difference_type = std::ptrdiff_t; ///< Type when diving one instance of this iterator by another. + using value_type = memory_area; ///< Underlying value pointed to by this iterator. + /** * @brief Defaulted constructor. */ @@ -57,30 +62,86 @@ namespace teachos::arch::memory::multiboot * @brief Constructor. * * @param p Underlying address the iterator should point too, ensure to not pass an invalid pointer or the - * constructo will halt execution. + * constructor will halt execution. */ - explicit memory_area_iterator(memory_area * p); + explicit memory_area_iterator(value_type * p); /** * @brief Dereferences the initally given pointer to its value. * * @return Reference to the value. */ - memory_area & operator*() const; + auto operator*() const -> value_type &; + + /** + * @brief Get underlying value, which is the intially passed pointer. + * + * @return Underlying value passed intially. + */ + auto operator->() const -> value_type *; /** * @brief Post increment operator. Returns a copy of the value. * * @return Copy of the incremented underlying address. */ - memory_area_iterator operator++(int); + auto operator++(int) -> memory_area_iterator; /** * @brief Pre increment operator. Returns a reference to the changed value. * * @return Reference to the incremented underlying address. */ - memory_area_iterator & operator++(); + auto operator++() -> memory_area_iterator &; + + /** + * @brief Addition assignment operator. Returns a reference to the changed value. + * + * @param value Value we want to add to the underlying address. + * @return Reference to the changed underlying address. + */ + auto operator+=(difference_type value) -> memory_area_iterator &; + + /** + * @brief Subtraction assignment operator. Returns a reference to the changed value. + * + * @param value Value we want to subtract from the underlying address. + * @return Reference to the changed underlying address. + */ + auto operator-=(difference_type value) -> memory_area_iterator &; + + /** + * @brief Addition operator. Returns the changed value. + * + * @param value Value we want to add to a copy of the underlying address. + * @return Copy of underlying address incremented by the given value. + */ + auto operator+(difference_type value) const -> memory_area_iterator; + + /** + * @brief Subtraction operator. Returns the changed value. + * + * @param value Value we want to subtrcat from a copy of the underlying address. + * @return Copy of underlying address decremented by the given value. + */ + auto operator-(difference_type value) const -> memory_area_iterator; + + /** + * @brief Subtraction operator. Returns the size difference between two iterators. + * + * @param other Other iterator we want to substract the underlying address with ours. + * @return Size difference between the underlying address of this instance and the given iterator. + */ + auto operator-(const memory_area_iterator & other) const -> difference_type; + + /** + * @brief Index operator overload. Returns a reference to the value at the given index. Simply returns the + * dereferenced underlying pointer incremented by the given index. + * + * @param index Index we want to access and get the value from. + * @return Reference to the value at the given index. + */ + auto operator[](difference_type index) const -> value_type &; /** * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. @@ -88,10 +149,18 @@ namespace teachos::arch::memory::multiboot * @param other Other iterator to compare to. * @return Whether both iterators point to the same underlying address in memory. */ - bool operator==(memory_area_iterator const & other) const = default; + auto operator==(memory_area_iterator const & other) const -> bool = default; + + /** + * @brief Defaulted threeway comparsion operator. Simply compares the memory address of both iterators. + * + * @param other Other iterator to compare to. + * @return Whether the given iterator is smaller or larger than this iterator. + */ + auto operator<=>(memory_area_iterator const & other) const -> std::strong_ordering = default; private: - memory_area * ptr; ///< Underlying address the iterator is currently pointing too. + value_type * ptr; ///< Underlying address the iterator is currently pointing too. }; /** @@ -100,13 +169,16 @@ namespace teachos::arch::memory::multiboot */ struct memory_area_container { + using iterator = memory_area_iterator; ///< Iterators used by this container. + using size_type = std::size_t; ///< Maximum size of this container. + /** * @brief Constructor. * * @param begin Pointer to the first memory area, will be used to construct the begin iterator. * @param size Amount of entries in the container we want to construct. */ - memory_area_container(memory_area * begin, std::size_t size); + memory_area_container(memory_area_iterator::value_type * begin, size_type size); /** * @brief Returns the iterator pointing to the first element of the memory area. @@ -114,7 +186,7 @@ namespace teachos::arch::memory::multiboot * * @return Iterator pointing to first element of the memory area. */ - auto begin() const -> memory_area_iterator; + auto begin() const -> iterator; /** * @brief Returns the iterator pointing to one past the last element of the memory area. @@ -122,11 +194,26 @@ namespace teachos::arch::memory::multiboot * * @return Iterator pointing to one past the last element of the memory area. */ - auto end() const -> memory_area_iterator; + auto end() const -> iterator; + + /** + * @brief Calculates the size of this container, simply subtracts the iterator pointing to the first element by the + * last. + * + * @return Actual size of this container. + */ + auto size() const -> size_type; + + /** + * @brief Calcualtes the size and returns true if the size is 0 and the container therefore emtpy. + * + * @return Whether the container is empty, size being 0 or not + */ + auto empty() const -> bool; private: - memory_area_iterator area_begin; ///< Pointer to the first element of all memory areas. - memory_area_iterator area_end; ///< Pointer to one pas the last element of all memory areas. + iterator area_begin; ///< Pointer to the first element of all memory areas. + iterator area_end; ///< Pointer to one pas the last element of all memory areas. }; } // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index c3f77e1..d91b7f4 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -23,33 +23,21 @@ namespace teachos::arch::memory::allocator auto area_frame_allocator::choose_next_area() -> void { current_area = std::nullopt; + auto next_area_with_free_frames = memory_areas | std::views::filter([this](multiboot::memory_area const & area) { + auto address = area.base_address + area.area_length - 1; + return physical_frame::containing_address(address) >= next_free_frame; + }); - /**auto filtered_areas = memory_areas | std::views::filter([this](multiboot::memory_area area) { - auto address = area.base_address + area.area_length - 1; - return physical_frame::containing_address(address) >= next_free_frame; - });**/ + auto lowest_area_with_free_frames = + std::ranges::min_element(next_area_with_free_frames, [](multiboot::memory_area a, multiboot::memory_area b) { + return a.base_address < b.base_address; + }); - std::ranges::min_element(memory_areas, [](multiboot::memory_area a, multiboot::memory_area b) { - return a.base_address < b.base_address; - }); - - for (auto area : memory_areas) - { - std::size_t address = area.base_address + area.area_length - 1; - if (physical_frame::containing_address(address) >= next_free_frame) - { - // The `next_free_frame` address is smaller than the last address of the current area - if (!current_area || area.base_address < current_area->base_address) - { - current_area = area; - } - } - } - - if (current_area) + 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 - physical_frame start_frame = physical_frame::containing_address(current_area->base_address); + auto start_frame = physical_frame::containing_address(current_area.value().base_address); if (next_free_frame < start_frame) { next_free_frame = start_frame; @@ -63,36 +51,38 @@ namespace teachos::arch::memory::allocator * 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) + if (!current_area) { - physical_frame physical_frame{next_free_frame.frame_number}; + return std::nullopt; + } - struct physical_frame current_area_last_frame = { - physical_frame::containing_address(current_area->base_address + current_area->area_length - 1)}; + auto 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 (physical_frame >= multiboot_start && physical_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 - { - // Frame is unused, increment `next_free_frame` and return it - next_free_frame.frame_number += 1; - return physical_frame; - } - - // `physical_frame` was not valid, try it again with the updated `next_free_frame` - return allocate_frame(); + 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; } - // no free frames left - return std::nullopt; + // `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 physical_frame) -> void diff --git a/arch/x86_64/src/memory/multiboot/memory_map.cpp b/arch/x86_64/src/memory/multiboot/memory_map.cpp index da7f05d..b5e2759 100644 --- a/arch/x86_64/src/memory/multiboot/memory_map.cpp +++ b/arch/x86_64/src/memory/multiboot/memory_map.cpp @@ -4,18 +4,21 @@ namespace teachos::arch::memory::multiboot { - memory_area_iterator::memory_area_iterator(multiboot::memory_area * p) + memory_area_iterator::memory_area_iterator(value_type * p) : ptr(p) { exception_handling::assert(ptr, "[Memory Area] Attempted to pass nullptr as iterator"); } - multiboot::memory_area & memory_area_iterator::operator*() const { return *ptr; } + auto memory_area_iterator::operator*() const -> value_type & { return *ptr; } + + auto memory_area_iterator::operator->() const -> value_type * { return ptr; } auto memory_area_iterator::operator++(int) -> memory_area_iterator { - ++(*this); - return *this; + memory_area_iterator old_value = *this; + ++ptr; + return old_value; } auto memory_area_iterator::operator++() -> memory_area_iterator & @@ -24,6 +27,35 @@ namespace teachos::arch::memory::multiboot return *this; } + auto memory_area_iterator::operator+=(difference_type value) -> memory_area_iterator & + { + ptr += value; + return *this; + } + + auto memory_area_iterator::operator-=(difference_type value) -> memory_area_iterator & + { + ptr -= value; + return *this; + } + + auto memory_area_iterator::operator+(difference_type value) const -> memory_area_iterator + { + return memory_area_iterator{ptr + value}; + } + + auto memory_area_iterator::operator-(difference_type value) const -> memory_area_iterator + { + return memory_area_iterator{ptr - value}; + } + + auto memory_area_iterator::operator-(const memory_area_iterator & other) const -> difference_type + { + return ptr - other.ptr; + } + + auto memory_area_iterator::operator[](difference_type index) const -> value_type & { return *(ptr + index); } + memory_area_container::memory_area_container(memory_area * begin, std::size_t size) : area_begin(begin) , area_end(begin + size) @@ -34,4 +66,8 @@ namespace teachos::arch::memory::multiboot auto memory_area_container::begin() const -> multiboot::memory_area_iterator { return area_begin; } auto memory_area_container::end() const -> multiboot::memory_area_iterator { return area_end; } + + auto memory_area_container::size() const -> size_type { return std::distance(begin(), end()); } + + auto memory_area_container::empty() const -> bool { return size() == 0; } } // namespace teachos::arch::memory::multiboot -- cgit v1.2.3 From f8b1a0d9e8431393e1b47af87780c96729100a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Oct 2024 11:23:33 +0000 Subject: Remove redundant code --- arch/x86_64/src/kernel/main.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 3f768ee..5186c21 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -19,14 +19,6 @@ namespace teachos::arch::kernel auto memory_information = memory::multiboot::read_multiboot2(); memory::allocator::area_frame_allocator allocator(memory_information); - auto test2 = allocator.allocate_frame(); - auto test1 = test2.value().start_address(); - auto test3 = test2.value().frame_number; - - if (test1 > test3) - { - } - size_t address = 42 * memory::paging::PAGE_TABLE_ENTRY_COUNT * memory::paging::PAGE_TABLE_ENTRY_COUNT * memory::allocator::PAGE_FRAME_SIZE; // 42th P3 entry auto page = memory::paging::virtual_page::containing_address(address); -- cgit v1.2.3 From becb1ce0abdaf4e6ad08bb6db7c706dd13a1294b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Oct 2024 11:29:36 +0000 Subject: Fix typo --- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 4905e9e..7a8e2c9 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -95,7 +95,7 @@ namespace teachos::arch::memory::paging auto map_next_free_page_to_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void { auto frame = allocator.allocate_frame(); - exception_handling::assert(!frame.has_value(), "[Page mapper] Out of memory exception"); + exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); map_page_to_frame(allocator, page, frame.value(), flags); } -- cgit v1.2.3 From 1518177efac38961a36db0bc40152d00c38e6281 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Oct 2024 13:27:33 +0000 Subject: add correct optional handling --- arch/x86_64/include/arch/memory/paging/page_table.hpp | 2 +- .../src/memory/allocator/area_frame_allocator.cpp | 17 +++++++++++------ arch/x86_64/src/memory/paging/page_mapper.cpp | 12 ++++++------ arch/x86_64/src/memory/paging/page_table.cpp | 4 ++-- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 291ea8d..8fcde9f 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -83,7 +83,7 @@ namespace teachos::arch::memory::paging // been created itself. So we have to do that before we are able to allocate the wanted frame. This has to be done // for every level, meaning we potenitally create a level 4, level 3 and level 2 page entry, each pointing to a // page table one level below. - if (!next_handle) + if (!next_handle.has_value()) { auto allocated_frame = allocator.allocate_frame(); exception_handling::assert(allocated_frame.has_value(), "[Page mapper] Unable to allocate frame"); diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index c2cafce..05b828c 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -29,14 +29,14 @@ namespace teachos::arch::memory::allocator if (physical_frame::containing_address(address) >= next_free_frame) { // The `next_free_frame` address is smaller than the last address of the current area - if (!current_area || area.base_address < current_area->base_address) + if (!current_area.has_value() || area.base_address < current_area.value().base_address) { - current_area = area; + current_area.emplace(area); } } } - if (current_area) + if (current_area.has_value()) { // Update the `next_free_frame` according to the new memory area physical_frame start_frame = physical_frame::containing_address(current_area->base_address); @@ -53,7 +53,7 @@ namespace teachos::arch::memory::allocator * 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) + if (current_area.has_value()) { physical_frame physical_frame{next_free_frame.frame_number}; @@ -65,11 +65,16 @@ namespace teachos::arch::memory::allocator // All frames of current area are used, switch to next area choose_next_area(); } - else if (physical_frame >= multiboot_start && physical_frame <= kernel_end) + else if (physical_frame >= kernel_start && physical_frame <= kernel_end) { - // `physical_frame` is used by the kernel or multiboot information structure + // `physical_frame` is used by the kernel next_free_frame = allocator::physical_frame{kernel_end.frame_number + 1}; } + else if (physical_frame >= multiboot_start && physical_frame <= multiboot_end) + { + // `physical_frame` is used by the 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 diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 75d6759..bc0c0d9 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -28,7 +28,7 @@ namespace teachos::arch::memory::paging auto 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) + if (!next_handle.has_value()) { return translate_huge_page(page); } @@ -45,14 +45,14 @@ namespace teachos::arch::memory::paging auto current_handle = create_or_get(); auto level3_handle = current_handle.next_table(page.get_level_index(page_table_handle::LEVEL4)); - if (!level3_handle) + if (!level3_handle.has_value()) { return std::nullopt; } auto level3_entry = level3_handle.value()[page.get_level_index(page_table_handle::LEVEL3)]; auto level3_frame = level3_entry.calculate_pointed_to_frame(); - if (level3_frame && level3_entry.contains_flags(entry::HUGE_PAGE)) + 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, @@ -63,11 +63,11 @@ namespace teachos::arch::memory::paging } auto level2_handle = level3_handle.value().next_table(page.get_level_index(page_table_handle::LEVEL3)); - if (level2_handle) + if (level2_handle.has_value()) { auto level2_entry = level2_handle.value()[page.get_level_index(page_table_handle::LEVEL2)]; auto level2_frame = level2_entry.calculate_pointed_to_frame(); - if (level2_frame && level2_entry.contains_flags(entry::HUGE_PAGE)) + 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"); @@ -84,7 +84,7 @@ namespace teachos::arch::memory::paging virtual_page page = virtual_page::containing_address(virtual_address); std::optional frame = translate_page(page); - if (frame) + if (frame.has_value()) { return frame.value().frame_number * allocator::PAGE_FRAME_SIZE + offset; } diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 868cf86..f1df31d 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -72,7 +72,7 @@ namespace teachos::arch::memory::paging auto page_table::next_table(std::size_t table_index) -> std::optional { auto address = next_table_address(table_index); - if (address) + if (address.has_value()) { return reinterpret_cast(address.value()); } @@ -136,7 +136,7 @@ namespace teachos::arch::memory::paging exception_handling::assert(handle_level != page_table_handle::LEVEL1, "[Page Table] Attempted to call next_table on level 1 page table"); auto next_table = handle->next_table(table_index); - if (next_table) + if (next_table.has_value()) { return page_table_handle{next_table.value(), --handle_level}; } -- cgit v1.2.3 From d0f47ef0cd8cb2f5079808a261dd724b3eb1a3a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Oct 2024 14:12:35 +0000 Subject: Fix typos --- arch/x86_64/src/memory/multiboot/reader.cpp | 22 ++++++++++------------ arch/x86_64/src/memory/paging/page_entry.cpp | 2 +- arch/x86_64/src/memory/paging/virtual_page.cpp | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp index 545e517..c750ae1 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -55,20 +55,18 @@ namespace teachos::arch::memory::multiboot for (auto section = begin; section != end; ++section) { + if (section->virtual_address < kernel_start) + { + kernel_start = section->virtual_address; + } + auto virtual_address_end = section->virtual_address + section->section_size; + if (virtual_address_end > kernel_end) + { + kernel_end = virtual_address_end; + } + switch (section->type) { - case elf_section_type::PROGRAMM: { - if (section->virtual_address < kernel_start) - { - kernel_start = section->virtual_address; - } - auto virtual_address_end = section->virtual_address + section->section_size; - if (virtual_address_end > kernel_end) - { - kernel_end = virtual_address_end; - } - break; - } case elf_section_type::DYNAMIC_SYMBOL_TABLE: case elf_section_type::SYMBOL_TABLE: symbol_table_section_count++; diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 09d048b..8b4aa36 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -19,7 +19,7 @@ namespace teachos::arch::memory::paging if (contains_flags(PRESENT)) { auto physical_address = calculate_physical_address(); - return allocator::physical_frame::containing_address(physical_address); + return allocator::physical_frame::containing_address(physical_address & 0x000ffffffffff000); } return std::nullopt; } diff --git a/arch/x86_64/src/memory/paging/virtual_page.cpp b/arch/x86_64/src/memory/paging/virtual_page.cpp index 91f63b4..db0d96c 100644 --- a/arch/x86_64/src/memory/paging/virtual_page.cpp +++ b/arch/x86_64/src/memory/paging/virtual_page.cpp @@ -21,6 +21,6 @@ namespace teachos::arch::memory::paging auto virtual_page::get_level_index(page_table_handle::level level) const -> size_t { - return (start_address() >> (level * 9U)) & 0x1FF; + return (page_number >> (level * 9U)) & 0x1FF; } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 38e87d52891429d56d20a54ce205d1e421068f36 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Oct 2024 14:16:35 +0000 Subject: update gas --- arch/x86_64/include/arch/memory/paging/page_entry.hpp | 13 +------------ arch/x86_64/src/boot/boot.s | 10 +++++----- arch/x86_64/src/memory/paging/page_entry.cpp | 17 ++--------------- 3 files changed, 8 insertions(+), 32 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index bfb0184..5959801 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -68,8 +68,7 @@ namespace teachos::arch::memory::paging auto calculate_pointed_to_frame() const -> std::optional; /** - * @brief Copies the address and flags from the given physical frame into the underlying std::bitset so future calls - * to calculate_physical_address() will return the new address and flags instead of the old one. + * @brief Copies the address and flags from the given physical frame into the underlying std::bitset * * @param frame Physical frame that contains the address we want to copy into our underlying std::bitset. * @param additional_flags Entry flags which will be copied into our underlying std::bitset. @@ -88,16 +87,6 @@ namespace teachos::arch::memory::paging auto contains_flags(std::bitset<64U> other) const -> bool; private: - /** - * @brief Extracts the physical address from the underlying bitset read from bit index 12 - 51. - * - * @note Is a 52 bit page aligned physical address of the frame of the next page table or the pyhscial address of - * the frame for P1 page tables. - * - * @return Extracted physical address of the next page or of the frame for P1 page tables. - */ - auto calculate_physical_address() const -> std::size_t; - std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be ///< freely used for additional flags by the operating system. }; diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index f04ae44..c1b3203 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -271,11 +271,6 @@ enable_paging: mov $page_map_level_4, %eax mov %eax, %cr3 - /* Map the P4 table recursively */ - mov $page_map_level_4, %eax - or 0b11, %eax /* Write present + writable flags into eax register */ - mov %eax, (page_map_level_4 + 511 * 8) - /* Enable Physical Address Extension */ mov %cr4, %eax or $(1 << 5), %eax @@ -317,6 +312,11 @@ enable_sse: * page map entries. */ prepare_page_maps: + /* Map the P4 table recursively */ + mov $page_map_level_4, %eax + or $0b11, %eax /* Write present + writable flags into eax register */ + mov %eax, (page_map_level_4 + 511 * 8) + /* Add an entry to the PML4, pointing to the PML3 */ mov $page_map_level_3, %eax or $0x3, %eax diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 8b4aa36..f3b5be1 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -18,25 +18,12 @@ namespace teachos::arch::memory::paging { if (contains_flags(PRESENT)) { - auto physical_address = calculate_physical_address(); - return allocator::physical_frame::containing_address(physical_address & 0x000ffffffffff000); + constexpr std::size_t mask = 0x000fffff'fffff000; + return allocator::physical_frame::containing_address(flags.to_ullong() & mask); } return std::nullopt; } - auto entry::calculate_physical_address() const -> std::size_t - { - constexpr std::size_t start_bit = 12U; - constexpr std::size_t end_bit = 52U; - size_t value = 0U; - - for (auto i = start_bit; i < end_bit; i++) - { - value |= (flags[i] ? (1 << (i - start_bit)) : 0); - } - return value; - } - 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 -- cgit v1.2.3 From acbd91c9898808a928af0b1bdd9d5058e8a91f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 27 Oct 2024 14:55:52 +0000 Subject: Add typedef for virtual / physical addresses --- .../arch/memory/allocator/physical_frame.hpp | 6 +++-- .../include/arch/memory/paging/page_mapper.hpp | 20 ++++++++-------- .../include/arch/memory/paging/virtual_page.hpp | 6 +++-- .../x86_64/src/memory/allocator/physical_frame.cpp | 2 +- arch/x86_64/src/memory/paging/page_mapper.cpp | 28 +++++++++++----------- arch/x86_64/src/memory/paging/virtual_page.cpp | 6 ++--- 6 files changed, 36 insertions(+), 32 deletions(-) diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp index e33c77a..87c14ac 100644 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -6,6 +6,8 @@ namespace teachos::arch::memory::allocator { + typedef std::size_t physical_address; + constexpr std::size_t PAGE_FRAME_SIZE = 4096U; ///< Default page size of x86_84 is always 4KiB. /** @@ -24,10 +26,10 @@ namespace teachos::arch::memory::allocator /** * @brief Returns the physical frame the given address is contained in. * - * @param physical_address Physical address we want to get the corresponding physical frame for. + * @param address Physical address we want to get the corresponding physical frame for. * @return Frame the given address is contained in. */ - auto static containing_address(std::size_t physical_address) -> physical_frame; + auto static containing_address(physical_address address) -> physical_frame; /** * @brief Evaluates the start address of the physical frame. diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 7a8e2c9..5b74bd2 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -30,8 +30,16 @@ namespace teachos::arch::memory::paging auto create_or_get() -> page_table_handle; /** - * @brief Translates page into physical frame, will first attempt to parse normally using default page size and if it - * failed attempt to parse using huge pages. + * @brief Translates virtual address into corresponding physical address. Calls translate_page under the hood. + * + * @param address Virtual address we want to translate into physical one. + * @return Physical address corresponding to the provided virtual address. + */ + auto translate_address(virtual_address address) -> std::optional; + + /** + * @brief Translates page into physical frame, will first attempt to parse normally using default page size and if + * it failed attempt to parse using huge pages. * * @param page Page to translate into physical frame. * @return Physical frame corresponding to the provided virtual page. @@ -46,14 +54,6 @@ namespace teachos::arch::memory::paging */ auto translate_huge_page(virtual_page page) -> std::optional; - /** - * @brief Translate virtual into phyical address. - * - * @param virtual_address Address to translate into physical. - * @return Physical address. - */ - auto translate_address(std::size_t virtual_address) -> std::optional; - /** * @brief Maps a virtual page to a physical frame in the page table with the specified flags. * diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index f01073d..b9e2195 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -10,6 +10,8 @@ namespace teachos::arch::memory::paging { + typedef std::size_t virtual_address; + /** * @brief Virtual page entry contained in P1 page tables */ @@ -25,10 +27,10 @@ namespace teachos::arch::memory::paging /** * @brief Returns the virtual page the given address is contained in. * - * @param virtual_address Virtual address we want to get the corresponding virtual page for. + * @param address Virtual address we want to get the corresponding virtual page for. * @return Frame the given address is contained in. */ - auto static containing_address(std::size_t virtual_address) -> virtual_page; + auto static containing_address(virtual_address address) -> virtual_page; /** * @brief Evaluates the start address of the virtual page. diff --git a/arch/x86_64/src/memory/allocator/physical_frame.cpp b/arch/x86_64/src/memory/allocator/physical_frame.cpp index 03bd965..b05254b 100644 --- a/arch/x86_64/src/memory/allocator/physical_frame.cpp +++ b/arch/x86_64/src/memory/allocator/physical_frame.cpp @@ -8,7 +8,7 @@ namespace teachos::arch::memory::allocator // Nothing to do } - auto physical_frame::containing_address(std::size_t address) -> physical_frame + auto physical_frame::containing_address(physical_address address) -> physical_frame { return physical_frame{address / PAGE_FRAME_SIZE}; } diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index bc0c0d9..00c27b0 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -19,6 +19,20 @@ namespace teachos::arch::memory::paging return active_handle; } + auto translate_address(virtual_address address) -> std::optional + { + auto offset = address % allocator::PAGE_FRAME_SIZE; + auto page = virtual_page::containing_address(address); + auto frame = translate_page(page); + + if (frame.has_value()) + { + return frame.value().frame_number * allocator::PAGE_FRAME_SIZE + offset; + } + + return std::nullopt; + } + auto translate_page(virtual_page page) -> std::optional { auto current_handle = create_or_get(); @@ -77,18 +91,4 @@ namespace teachos::arch::memory::paging } return std::nullopt; } - - auto translate_address(std::size_t virtual_address) -> std::optional - { - std::size_t offset = virtual_address % allocator::PAGE_FRAME_SIZE; - virtual_page page = virtual_page::containing_address(virtual_address); - std::optional frame = translate_page(page); - - if (frame.has_value()) - { - return frame.value().frame_number * allocator::PAGE_FRAME_SIZE + offset; - } - - return std::nullopt; - } } // 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 index db0d96c..d39bb7f 100644 --- a/arch/x86_64/src/memory/paging/virtual_page.cpp +++ b/arch/x86_64/src/memory/paging/virtual_page.cpp @@ -10,11 +10,11 @@ namespace teachos::arch::memory::paging // Nothing to do } - auto virtual_page::containing_address(std::size_t virtual_address) -> virtual_page + auto virtual_page::containing_address(virtual_address address) -> virtual_page { - exception_handling::assert(virtual_address < 0x0000800000000000 || virtual_address >= 0xffff800000000000, + exception_handling::assert(address < 0x0000800000000000 || address >= 0xffff800000000000, "[Virtual Page] Attempted to create virtual page from invalid address"); - return virtual_page{virtual_address / allocator::PAGE_FRAME_SIZE}; + return virtual_page{address / allocator::PAGE_FRAME_SIZE}; } auto virtual_page::start_address() const -> size_t { return page_number * allocator::PAGE_FRAME_SIZE; } -- cgit v1.2.3 From 58d01f6aae80a66faa5163602c399c28dcf30cb6 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 27 Oct 2024 15:25:57 +0000 Subject: revert p4 address update --- arch/x86_64/include/arch/boot/pointers.hpp | 1 - arch/x86_64/src/memory/paging/page_entry.cpp | 10 +++++++--- arch/x86_64/src/memory/paging/page_mapper.cpp | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index 37840b6..18c41ce 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -8,7 +8,6 @@ namespace teachos::arch::boot { extern "C" size_t const multiboot_information_pointer; - extern "C" memory::paging::page_table * page_map_level_4; } // namespace teachos::arch::boot #endif diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index f3b5be1..c3e9614 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -4,6 +4,11 @@ namespace teachos::arch::memory::paging { + namespace + { + constexpr std::size_t PHYSICAL_ADDRESS_MASK = 0x000fffff'fffff000; + } + entry::entry(uint64_t flags) : flags(flags) { @@ -18,8 +23,7 @@ namespace teachos::arch::memory::paging { if (contains_flags(PRESENT)) { - constexpr std::size_t mask = 0x000fffff'fffff000; - return allocator::physical_frame::containing_address(flags.to_ullong() & mask); + return allocator::physical_frame::containing_address(flags.to_ullong() & PHYSICAL_ADDRESS_MASK); } return std::nullopt; } @@ -28,7 +32,7 @@ namespace teachos::arch::memory::paging auto entry::set_entry(allocator::physical_frame frame, std::bitset<64U> additional_flags) -> void { - exception_handling::assert((frame.start_address() & ~0x000fffff'fffff000) == 0, + exception_handling::assert((frame.start_address() & ~PHYSICAL_ADDRESS_MASK) == 0, "[Paging Entry] Start address is not aligned with page"); flags = std::bitset<64U>{frame.start_address()} | additional_flags; } diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 00c27b0..fb9ea39 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -8,7 +8,8 @@ namespace teachos::arch::memory::paging auto create_or_get() -> page_table_handle { static auto initialized = false; - static page_table_handle active_handle{boot::page_map_level_4, page_table_handle::LEVEL4}; + static page_table_handle active_handle{reinterpret_cast(0xffffffff'fffff000), + page_table_handle::LEVEL4}; if (!initialized) { -- cgit v1.2.3 From 04b0285d8329e45cea426aa1a8e69203685a4467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 28 Oct 2024 10:15:18 +0000 Subject: Move iterator and container into generic template classes. Use algorithms instead of raw pointer for loops --- arch/x86_64/CMakeLists.txt | 1 - .../arch/memory/multiboot/elf_symbols_section.hpp | 7 +- .../include/arch/memory/multiboot/memory_map.hpp | 178 +-------------------- .../include/arch/memory/multiboot/reader.hpp | 9 +- arch/x86_64/include/arch/shared/container.hpp | 73 +++++++++ .../include/arch/shared/random_access_iterator.hpp | 167 +++++++++++++++++++ .../src/memory/allocator/area_frame_allocator.cpp | 4 +- arch/x86_64/src/memory/multiboot/memory_map.cpp | 73 --------- arch/x86_64/src/memory/multiboot/reader.cpp | 79 ++++----- 9 files changed, 300 insertions(+), 291 deletions(-) create mode 100644 arch/x86_64/include/arch/shared/container.hpp create mode 100644 arch/x86_64/include/arch/shared/random_access_iterator.hpp delete mode 100644 arch/x86_64/src/memory/multiboot/memory_map.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 8658ed7..e1b7352 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -42,7 +42,6 @@ target_sources("_video" PRIVATE target_sources("_memory" PRIVATE "src/memory/multiboot/elf_symbols_section.cpp" - "src/memory/multiboot/memory_map.cpp" "src/memory/multiboot/reader.cpp" "src/memory/allocator/area_frame_allocator.cpp" "src/memory/allocator/physical_frame.cpp" diff --git a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp index fc8cb15..c9989ae 100644 --- a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp @@ -1,7 +1,10 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP #define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP -#include "info.hpp" +#include "arch/memory/multiboot/info.hpp" +#include "arch/shared/container.hpp" +#include "arch/shared/random_access_iterator.hpp" + #include #include @@ -158,6 +161,8 @@ namespace teachos::arch::memory::multiboot std::byte end; ///< Marks the end of the tag, used to mark the beginning of any additional data. ///< contained in the section, to ensure byte alignment is actually 4 byte. }; + + typedef shared::container> elf_section_header_container; } // namespace teachos::arch::memory::multiboot #endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp index f9c902a..910eecb 100644 --- a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp @@ -1,9 +1,11 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP #define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP -#include "info.hpp" +#include "arch/memory/multiboot/info.hpp" +#include "arch/shared/container.hpp" +#include "arch/shared/random_access_iterator.hpp" + #include -#include namespace teachos::arch::memory::multiboot { @@ -44,177 +46,7 @@ namespace teachos::arch::memory::multiboot struct memory_area entries; ///< Specific memory regions. }; - /** - * @brief Random access iterator for memory areas. - */ - struct memory_area_iterator - { - using iterator_category = std::random_access_iterator_tag; ///< Iterator category of this type. - using difference_type = std::ptrdiff_t; ///< Type when diving one instance of this iterator by another. - using value_type = memory_area; ///< Underlying value pointed to by this iterator. - - /** - * @brief Defaulted constructor. - */ - memory_area_iterator() = default; - - /** - * @brief Constructor. - * - * @param p Underlying address the iterator should point too, ensure to not pass an invalid pointer or the - * constructor will halt execution. - */ - explicit memory_area_iterator(value_type * p); - - /** - * @brief Dereferences the initally given pointer to its value. - * - * @return Reference to the value. - */ - auto operator*() const -> value_type &; - - /** - * @brief Get underlying value, which is the intially passed pointer. - * - * @return Underlying value passed intially. - */ - auto operator->() const -> value_type *; - - /** - * @brief Post increment operator. Returns a copy of the value. - * - * @return Copy of the incremented underlying address. - */ - auto operator++(int) -> memory_area_iterator; - - /** - * @brief Pre increment operator. Returns a reference to the changed value. - * - * @return Reference to the incremented underlying address. - */ - auto operator++() -> memory_area_iterator &; - - /** - * @brief Addition assignment operator. Returns a reference to the changed value. - * - * @param value Value we want to add to the underlying address. - * @return Reference to the changed underlying address. - */ - auto operator+=(difference_type value) -> memory_area_iterator &; - - /** - * @brief Subtraction assignment operator. Returns a reference to the changed value. - * - * @param value Value we want to subtract from the underlying address. - * @return Reference to the changed underlying address. - */ - auto operator-=(difference_type value) -> memory_area_iterator &; - - /** - * @brief Addition operator. Returns the changed value. - * - * @param value Value we want to add to a copy of the underlying address. - * @return Copy of underlying address incremented by the given value. - */ - auto operator+(difference_type value) const -> memory_area_iterator; - - /** - * @brief Subtraction operator. Returns the changed value. - * - * @param value Value we want to subtrcat from a copy of the underlying address. - * @return Copy of underlying address decremented by the given value. - */ - auto operator-(difference_type value) const -> memory_area_iterator; - - /** - * @brief Subtraction operator. Returns the size difference between two iterators. - * - * @param other Other iterator we want to substract the underlying address with ours. - * @return Size difference between the underlying address of this instance and the given iterator. - */ - auto operator-(const memory_area_iterator & other) const -> difference_type; - - /** - * @brief Index operator overload. Returns a reference to the value at the given index. Simply returns the - * dereferenced underlying pointer incremented by the given index. - * - * @param index Index we want to access and get the value from. - * @return Reference to the value at the given index. - */ - auto operator[](difference_type index) const -> value_type &; - - /** - * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. - * - * @param other Other iterator to compare to. - * @return Whether both iterators point to the same underlying address in memory. - */ - auto operator==(memory_area_iterator const & other) const -> bool = default; - - /** - * @brief Defaulted threeway comparsion operator. Simply compares the memory address of both iterators. - * - * @param other Other iterator to compare to. - * @return Whether the given iterator is smaller or larger than this iterator. - */ - auto operator<=>(memory_area_iterator const & other) const -> std::strong_ordering = default; - - private: - value_type * ptr; ///< Underlying address the iterator is currently pointing too. - }; - - /** - * @brief Read-only container for memory areas, that allow to easily use the memory_area_iterator in C++20 ranges - * calls. - */ - struct memory_area_container - { - using iterator = memory_area_iterator; ///< Iterators used by this container. - using size_type = std::size_t; ///< Maximum size of this container. - - /** - * @brief Constructor. - * - * @param begin Pointer to the first memory area, will be used to construct the begin iterator. - * @param size Amount of entries in the container we want to construct. - */ - memory_area_container(memory_area_iterator::value_type * begin, size_type size); - - /** - * @brief Returns the iterator pointing to the first element of the memory area. - * Allows using this class in the for each loop, because it follows the InputIterator template scheme. - * - * @return Iterator pointing to first element of the memory area. - */ - auto begin() const -> iterator; - - /** - * @brief Returns the iterator pointing to one past the last element of the memory area. - * Allows using this class in the for each loop, because it follows the InputIterator template scheme. - * - * @return Iterator pointing to one past the last element of the memory area. - */ - auto end() const -> iterator; - - /** - * @brief Calculates the size of this container, simply subtracts the iterator pointing to the first element by the - * last. - * - * @return Actual size of this container. - */ - auto size() const -> size_type; - - /** - * @brief Calcualtes the size and returns true if the size is 0 and the container therefore emtpy. - * - * @return Whether the container is empty, size being 0 or not - */ - auto empty() const -> bool; - - private: - iterator area_begin; ///< Pointer to the first element of all memory areas. - iterator area_end; ///< Pointer to one pas the last element of all memory areas. - }; + typedef shared::container> memory_area_container; } // namespace teachos::arch::memory::multiboot #endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/reader.hpp b/arch/x86_64/include/arch/memory/multiboot/reader.hpp index 393db8b..baa49c9 100644 --- a/arch/x86_64/include/arch/memory/multiboot/reader.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/reader.hpp @@ -1,8 +1,8 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP #define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP -#include "elf_symbols_section.hpp" -#include "memory_map.hpp" +#include "arch/memory/multiboot/memory_map.hpp" + #include namespace teachos::arch::memory::multiboot @@ -17,8 +17,9 @@ namespace teachos::arch::memory::multiboot std::size_t kernel_end; ///< End address of the kernel code in memory. std::size_t multiboot_start; ///< Start address of the multiboot code in memory. std::size_t multiboot_end; ///< End address of the multiboot code in memory. - memory_area * memory_areas; ///< Non-owning pointer to the first element of all memory areas. - uint8_t area_count; ///< Amount of total entries in the memory_areas array. + memory_area_container::iterator + begin_area; ///< Iterator containing non-owning pointer to the first element of all memory areas. + memory_area_container::iterator end_area; ///< Iterator pointing to one past the last element of all memory areas. }; /** diff --git a/arch/x86_64/include/arch/shared/container.hpp b/arch/x86_64/include/arch/shared/container.hpp new file mode 100644 index 0000000..8ea0d08 --- /dev/null +++ b/arch/x86_64/include/arch/shared/container.hpp @@ -0,0 +1,73 @@ +#ifndef TEACHOS_ARCH_X86_64_SHARED_CONTAINER_HPP +#define TEACHOS_ARCH_X86_64_SHARED_CONTAINER_HPP + +#include "arch/exception_handling/assert.hpp" + +#include + +namespace teachos::arch::shared +{ + /** + * @brief Read-only container for given template type, that allow to easily use this container instance in C++20 + * ranges calls. + * + * @tparam T Iterator the container uses to signal the start and end of it's data. + */ + template + struct container + { + using iterator = T; ///< Iterators used by this container. + using size_type = std::size_t; ///< Maximum size of this container. + + /** + * @brief Constructor. + * + * @param begin Iterator containing non-owning pointer to the first element of all memory areas. + * @param end Iterator pointing to one past the last element of all memory areas. + */ + container(iterator begin, iterator end) + : begin_itr(begin) + , end_itr(end) + { + exception_handling::assert(begin != iterator{}, "[Memory Area] Attempted to pass nullptr as begin iterator"); + exception_handling::assert(end != iterator{}, "[Memory Area] Attempted to pass nullptr as end iterator"); + } + + /** + * @brief Returns the iterator pointing to the first element of the memory area. + * Allows using this class in the for each loop, because it follows the InputIterator template scheme. + * + * @return Iterator pointing to first element of the memory area. + */ + auto begin() const -> iterator { return begin_itr; } + + /** + * @brief Returns the iterator pointing to one past the last element of the memory area. + * Allows using this class in the for each loop, because it follows the InputIterator template scheme. + * + * @return Iterator pointing to one past the last element of the memory area. + */ + auto end() const -> iterator { return end_itr; } + + /** + * @brief Calculates the size of this container, simply subtracts the iterator pointing to the first element by the + * last. + * + * @return Actual size of this container. + */ + auto size() const -> size_type { return std::distance(begin(), end()); } + + /** + * @brief Calcualtes the size and returns true if the size is 0 and the container therefore emtpy. + * + * @return Whether the container is empty, size being 0 or not + */ + auto empty() const -> bool { return size() == 0; } + + private: + iterator begin_itr; ///< Pointer to the first element of the given template type. + iterator end_itr; ///< Pointer to one pas the last element of the given template type. + }; +} // namespace teachos::arch::shared + +#endif // TEACHOS_ARCH_X86_64_SHARED_CONTAINER_HPP diff --git a/arch/x86_64/include/arch/shared/random_access_iterator.hpp b/arch/x86_64/include/arch/shared/random_access_iterator.hpp new file mode 100644 index 0000000..392b925 --- /dev/null +++ b/arch/x86_64/include/arch/shared/random_access_iterator.hpp @@ -0,0 +1,167 @@ +#ifndef TEACHOS_ARCH_X86_64_SHARED_RANDOM_ACCESS_ITERATOR_HPP +#define TEACHOS_ARCH_X86_64_SHARED_RANDOM_ACCESS_ITERATOR_HPP + +#include + +namespace teachos::arch::shared +{ + /** + * @brief Generic random access iterator for given template type. Can be a nullptr, ensure to check when using this + * iterator. Allows to easily use this iterator instance in algorithm calls. + * + * @tparam T Value the iterator points too. + */ + template + struct random_access_iterator + { + using iterator_category = std::random_access_iterator_tag; ///< Iterator category of this type. + using difference_type = std::ptrdiff_t; ///< Type when diving one instance of this iterator by another. + using value_type = T; ///< Underlying value pointed to by this iterator. + + /** + * @brief Defaulted constructor. + */ + random_access_iterator() = default; + + /** + * @brief Constructor. + * + * @param p Underlying address the iterator should point too, ensure to not pass an invalid pointer or the + * constructor will halt execution. + */ + explicit random_access_iterator(value_type * p) + : ptr(p) + { + // Nothing to do + } + + /** + * @brief Dereferences the initally given pointer to its value. + * + * @return Reference to the value. + */ + auto operator*() const -> value_type & { return *ptr; } + + /** + * @brief Get underlying value, which is the intially passed pointer. + * + * @return Underlying value passed intially. + */ + auto operator->() const -> value_type * { return ptr; } + + /** + * @brief Post increment operator. Returns a copy of the value. + * + * @return Copy of the incremented underlying address. + */ + auto operator++(int) -> random_access_iterator + { + random_access_iterator old_value = *this; + ++ptr; + return old_value; + } + + /** + * @brief Pre increment operator. Returns a reference to the changed value. + * + * @return Reference to the incremented underlying address. + */ + auto operator++() -> random_access_iterator & + { + ++ptr; + return *this; + } + + /** + * @brief Addition assignment operator. Returns a reference to the changed value. + * + * @param value Value we want to add to the underlying address. + * @return Reference to the changed underlying address. + */ + auto operator+=(difference_type value) -> random_access_iterator & + { + ptr += value; + return *this; + } + + /** + * @brief Subtraction assignment operator. Returns a reference to the changed value. + * + * @param value Value we want to subtract from the underlying address. + * @return Reference to the changed underlying address. + */ + auto operator-=(difference_type value) -> random_access_iterator & + { + ptr -= value; + return *this; + } + + /** + * @brief Addition operator. Returns the changed value. + * + * @param value Value we want to add to a copy of the underlying address. + * @return Copy of underlying address incremented by the given value. + */ + auto operator+(difference_type value) const -> random_access_iterator + { + return random_access_iterator{ptr + value}; + } + + /** + * @brief Subtraction operator. Returns the changed value. + * + * @param value Value we want to subtrcat from a copy of the underlying address. + * @return Copy of underlying address decremented by the given value. + */ + auto operator-(difference_type value) const -> random_access_iterator + { + return random_access_iterator{ptr - value}; + } + + /** + * @brief Subtraction operator. Returns the size difference between two iterators. + * + * @param other Other iterator we want to substract the underlying address with ours. + * @return Size difference between the underlying address of this instance and the given iterator. + */ + auto operator-(const random_access_iterator & other) const -> difference_type { return ptr - other.ptr; } + + /** + * @brief Index operator overload. Returns a reference to the value at the given index. Simply returns the + * dereferenced underlying pointer incremented by the given index. + * + * @param index Index we want to access and get the value from. + * @return Reference to the value at the given index. + */ + auto operator[](difference_type index) const -> value_type & { return *(ptr + index); } + + /** + * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. + * + * @param other Other iterator to compare to. + * @return Whether both iterators point to the same underlying address in memory. + */ + auto operator==(random_access_iterator const & other) const -> bool = default; + + /** + * @brief Defaulted negated comparsion operator. Simply compares the memory address of both iterators. + * + * @param other Other iterator to compare to. + * @return Whether both iterators don't point to the same underlying address in memory. + */ + auto operator!=(random_access_iterator const & other) const -> bool = default; + + /** + * @brief Defaulted threeway comparsion operator. Simply compares the memory address of both iterators. + * + * @param other Other iterator to compare to. + * @return Whether the given iterator is smaller or larger than this iterator. + */ + auto operator<=>(random_access_iterator const & other) const -> std::strong_ordering = default; + + private: + value_type * ptr = {}; ///< Underlying address the iterator is currently pointing too. + }; +} // namespace teachos::arch::shared + +#endif // TEACHOS_ARCH_X86_64_SHARED_RANDOM_ACCESS_ITERATOR_HPP diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index 6ed4f28..e03c66a 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -9,9 +9,9 @@ namespace teachos::arch::memory::allocator { area_frame_allocator::area_frame_allocator(multiboot::memory_information mem_info) - : next_free_frame(0) + : next_free_frame(0U) , current_area(std::nullopt) - , memory_areas(mem_info.memory_areas, mem_info.area_count) + , memory_areas(mem_info.begin_area, mem_info.end_area) , 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)) diff --git a/arch/x86_64/src/memory/multiboot/memory_map.cpp b/arch/x86_64/src/memory/multiboot/memory_map.cpp deleted file mode 100644 index b5e2759..0000000 --- a/arch/x86_64/src/memory/multiboot/memory_map.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "arch/memory/multiboot/memory_map.hpp" - -#include "arch/exception_handling/assert.hpp" - -namespace teachos::arch::memory::multiboot -{ - memory_area_iterator::memory_area_iterator(value_type * p) - : ptr(p) - { - exception_handling::assert(ptr, "[Memory Area] Attempted to pass nullptr as iterator"); - } - - auto memory_area_iterator::operator*() const -> value_type & { return *ptr; } - - auto memory_area_iterator::operator->() const -> value_type * { return ptr; } - - auto memory_area_iterator::operator++(int) -> memory_area_iterator - { - memory_area_iterator old_value = *this; - ++ptr; - return old_value; - } - - auto memory_area_iterator::operator++() -> memory_area_iterator & - { - ++ptr; - return *this; - } - - auto memory_area_iterator::operator+=(difference_type value) -> memory_area_iterator & - { - ptr += value; - return *this; - } - - auto memory_area_iterator::operator-=(difference_type value) -> memory_area_iterator & - { - ptr -= value; - return *this; - } - - auto memory_area_iterator::operator+(difference_type value) const -> memory_area_iterator - { - return memory_area_iterator{ptr + value}; - } - - auto memory_area_iterator::operator-(difference_type value) const -> memory_area_iterator - { - return memory_area_iterator{ptr - value}; - } - - auto memory_area_iterator::operator-(const memory_area_iterator & other) const -> difference_type - { - return ptr - other.ptr; - } - - auto memory_area_iterator::operator[](difference_type index) const -> value_type & { return *(ptr + index); } - - memory_area_container::memory_area_container(memory_area * begin, std::size_t size) - : area_begin(begin) - , area_end(begin + size) - { - // Nothing to do - } - - auto memory_area_container::begin() const -> multiboot::memory_area_iterator { return area_begin; } - - auto memory_area_container::end() const -> multiboot::memory_area_iterator { return area_end; } - - auto memory_area_container::size() const -> size_type { return std::distance(begin(), end()); } - - auto memory_area_container::empty() const -> bool { return size() == 0; } -} // 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 index c750ae1..228aa09 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -2,8 +2,11 @@ #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 + namespace teachos::arch::memory::multiboot { namespace @@ -15,7 +18,8 @@ namespace teachos::arch::memory::multiboot return reinterpret_cast(reinterpret_cast(ptr) + ((size + 7) & ~7)); } - auto process_memory_map(memory_map_header * mminfo, memory_area *& memory_areas, uint8_t & area_count) -> void + auto process_memory_map(memory_map_header * mminfo, memory_area_container::iterator & begin_area, + memory_area_container::iterator & end_area) -> void { auto expected_entry_size = mminfo->entry_size; constexpr auto actual_entry_size = sizeof(memory_area); @@ -26,8 +30,8 @@ namespace teachos::arch::memory::multiboot auto total_entries_size = total_size - sizeof(memory_map_header) + actual_entry_size; auto number_of_entries = total_entries_size / actual_entry_size; - memory_areas = &mminfo->entries; - area_count = number_of_entries; + begin_area = memory_area_container::iterator{&mminfo->entries}; + end_area = begin_area + number_of_entries; } auto process_elf_sections(elf_symbols_section_header * symbol, uint64_t & kernel_start, @@ -45,40 +49,30 @@ namespace teachos::arch::memory::multiboot exception_handling::assert(expected_total_size == actual_total_size, "[Multiboot Reader] Unexpected elf symbols section header total size"); - auto begin = reinterpret_cast(&symbol->end); + auto begin = elf_section_header_container::iterator{reinterpret_cast(&symbol->end)}; auto end = begin + symbol->number_of_sections; exception_handling::assert(begin->is_null(), "[Multiboot Reader] Elf symbols section not starting with SHT_NULL section"); - std::size_t symbol_table_section_count = 0U; - std::size_t dynamic_section_count = 0U; + elf_section_header_container container{begin, end}; - for (auto section = begin; section != end; ++section) - { - if (section->virtual_address < kernel_start) - { - kernel_start = section->virtual_address; - } - auto virtual_address_end = section->virtual_address + section->section_size; - if (virtual_address_end > kernel_end) - { - kernel_end = virtual_address_end; - } + auto elf_section_with_lowest_virtual_address = + std::ranges::min_element(container, [](elf_section_header const & a, elf_section_header const & b) { + return a.virtual_address < b.virtual_address; + }); - switch (section->type) - { - case elf_section_type::DYNAMIC_SYMBOL_TABLE: - case elf_section_type::SYMBOL_TABLE: - symbol_table_section_count++; - break; - case elf_section_type::DYNAMIC: - dynamic_section_count++; - break; - default: - // All other cases are not important and can be ignored - break; - } - } + auto elf_section_with_highest_virtual_address = + std::ranges::max_element(container, [](elf_section_header const & a, elf_section_header const & b) { + auto a_virtual_address_end = a.virtual_address + a.section_size; + auto b_virtual_address_end = b.virtual_address + b.section_size; + return a_virtual_address_end < b_virtual_address_end; + }); + + auto symbol_table_section_count = std::ranges::count_if(container, [](elf_section_header const & section) { + return section.type == elf_section_type::DYNAMIC_SYMBOL_TABLE || section.type == elf_section_type::SYMBOL_TABLE; + }); + auto dynamic_section_count = std::ranges::count_if( + container, [](elf_section_header const & section) { return section.type == elf_section_type::DYNAMIC; }); exception_handling::assert( symbol_table_section_count == 1U, @@ -86,15 +80,26 @@ namespace teachos::arch::memory::multiboot exception_handling::assert( dynamic_section_count <= 1U, "[Multiboot Reader] ELF Specifications allows only (1) or less dynamic sections, but got more"); + + auto lowest_elf_section = *elf_section_with_lowest_virtual_address; + kernel_start = lowest_elf_section.virtual_address; + + auto highest_elf_section = *elf_section_with_highest_virtual_address; + kernel_end = highest_elf_section.virtual_address + highest_elf_section.section_size; } } // namespace auto read_multiboot2() -> memory_information { - memory_information mem_info{UINT64_MAX, 0U, boot::multiboot_information_pointer, 0U, nullptr, 0U}; - - auto * multiboot_information_pointer = reinterpret_cast(boot::multiboot_information_pointer); - auto multiboot_tag = &(multiboot_information_pointer->tags); + memory_information mem_info{UINT64_MAX, + 0U, + boot::multiboot_information_pointer, + 0U, + memory_area_container::iterator{}, + memory_area_container::iterator{}}; + + auto multiboot_information_pointer = reinterpret_cast(boot::multiboot_information_pointer); + auto 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)) @@ -108,11 +113,11 @@ namespace teachos::arch::memory::multiboot } case tag_type::MEMORY_MAP: { auto mminfo = reinterpret_cast(tag); - process_memory_map(mminfo, mem_info.memory_areas, mem_info.area_count); + process_memory_map(mminfo, mem_info.begin_area, mem_info.end_area); break; } default: - // All other cases are not important and can be ignored + // All other cases are not important and can be ignored. break; } } -- cgit v1.2.3 From 58680f7d84ca5771be31c0037e8caf5791d79b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 28 Oct 2024 12:29:39 +0000 Subject: Fix invalid assertion --- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 2 +- arch/x86_64/include/arch/memory/paging/page_table.hpp | 1 - arch/x86_64/src/memory/paging/page_table.cpp | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 5b74bd2..c07c73c 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -82,7 +82,7 @@ namespace teachos::arch::memory::paging auto level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), "[Page Mapper] Unable to map huge pages"); - arch::exception_handling::assert(!level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); + arch::exception_handling::assert(level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); level1_entry.set_entry(frame, flags | std::bitset<64U>{entry::PRESENT}); } diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 8fcde9f..765e9bb 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -91,7 +91,6 @@ namespace teachos::arch::memory::paging // There should now be an entry at the previously not existent index, therefore we can simply access it again. next_handle = next_table(table_index); exception_handling::assert(next_handle.has_value(), "[Page mapper] Unable to create new entry into page table"); - // TODO: Crashes when trying to access underlying entries array. next_handle.value().zero_entries(); } return next_handle.value(); diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index f1df31d..e919a1e 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -84,7 +84,6 @@ namespace teachos::arch::memory::paging // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which // could be incredibly hard to debug later. exception_handling::assert(index < PAGE_TABLE_ENTRY_COUNT, "[Page Table] Index out of bounds"); - // TODO: This section seems to return completly invalid entry, debugger doesn't even show a value? Revert once fixed return entries[index]; } -- cgit v1.2.3 From efcb913196ccf0386a557e8c1053c430e5896179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 28 Oct 2024 12:45:46 +0000 Subject: Convert bitset to uint64_t instead of uint64_t to bitset --- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 2 +- arch/x86_64/src/memory/paging/page_entry.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index c07c73c..e08f195 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -83,7 +83,7 @@ namespace teachos::arch::memory::paging arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), "[Page Mapper] Unable to map huge pages"); arch::exception_handling::assert(level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); - level1_entry.set_entry(frame, flags | std::bitset<64U>{entry::PRESENT}); + level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT); } /** diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index c3e9614..dbf23e2 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -23,7 +23,7 @@ namespace teachos::arch::memory::paging { if (contains_flags(PRESENT)) { - return allocator::physical_frame::containing_address(flags.to_ullong() & PHYSICAL_ADDRESS_MASK); + return allocator::physical_frame::containing_address(flags.to_ulong() & PHYSICAL_ADDRESS_MASK); } return std::nullopt; } @@ -34,6 +34,6 @@ namespace teachos::arch::memory::paging { exception_handling::assert((frame.start_address() & ~PHYSICAL_ADDRESS_MASK) == 0, "[Paging Entry] Start address is not aligned with page"); - flags = std::bitset<64U>{frame.start_address()} | additional_flags; + flags = frame.start_address() | additional_flags.to_ulong(); } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From e5925df93411429340d2887594004aaa690d2ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 28 Oct 2024 13:32:09 +0000 Subject: Adjust constant and make all possible variables const --- .../arch/memory/allocator/physical_frame.hpp | 6 +-- .../include/arch/memory/paging/page_mapper.hpp | 10 ++--- .../include/arch/memory/paging/page_table.hpp | 4 +- .../include/arch/memory/paging/virtual_page.hpp | 4 +- .../include/arch/shared/random_access_iterator.hpp | 2 +- arch/x86_64/src/kernel/main.cpp | 4 +- .../src/memory/allocator/area_frame_allocator.cpp | 12 +++--- arch/x86_64/src/memory/multiboot/reader.cpp | 47 +++++++++++----------- arch/x86_64/src/memory/paging/page_entry.cpp | 2 +- arch/x86_64/src/memory/paging/page_mapper.cpp | 26 +++++++----- arch/x86_64/src/memory/paging/page_table.cpp | 22 +++++----- arch/x86_64/src/memory/paging/virtual_page.cpp | 2 +- include/memory/asm_pointer.hpp | 2 +- 13 files changed, 72 insertions(+), 71 deletions(-) diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp index 87c14ac..39406af 100644 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -8,7 +8,7 @@ namespace teachos::arch::memory::allocator { typedef std::size_t physical_address; - constexpr std::size_t PAGE_FRAME_SIZE = 4096U; ///< Default page size of x86_84 is always 4KiB. + std::size_t constexpr PAGE_FRAME_SIZE = 4096U; ///< Default page size of x86_84 is always 4KiB. /** * @brief Specific physical frame containing helper functions to determine if a specific address is in that @@ -41,12 +41,12 @@ namespace teachos::arch::memory::allocator /** * @brief Defaulted equals operator. */ - constexpr auto operator==(const physical_frame & other) const -> bool = default; + auto operator==(const physical_frame & other) const -> bool = default; /** * @brief Defaulted three-way comparsion operator. */ - constexpr auto operator<=>(const physical_frame & other) const -> std::partial_ordering = default; + auto operator<=>(const physical_frame & other) const -> std::partial_ordering = default; std::size_t frame_number; ///< Index number of the current physical frame, used to distinguish it from other frames. diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index e08f195..4edcea9 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -94,7 +94,7 @@ namespace teachos::arch::memory::paging template auto map_next_free_page_to_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void { - auto frame = allocator.allocate_frame(); + auto const frame = allocator.allocate_frame(); exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); map_page_to_frame(allocator, page, frame.value(), flags); } @@ -107,7 +107,7 @@ namespace teachos::arch::memory::paging template auto identity_map(T & allocator, allocator::physical_frame frame, std::bitset<64U> flags) -> void { - auto page = virtual_page::containing_address(frame.start_address()); + auto const page = virtual_page::containing_address(frame.start_address()); map_page_to_frame(allocator, page, frame, flags); } @@ -133,8 +133,8 @@ namespace teachos::arch::memory::paging for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) { - auto level_index = page.get_level_index(level); - auto next_handle = current_handle.next_table(level_index); + auto const level_index = page.get_level_index(level); + auto const next_handle = current_handle.next_table(level_index); // The next table method failed even tough the page has to be mapped already, because translate_page did not fail. // This can only mean that we attempted to unmap a huge page, which is not supported in the first place. exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); @@ -142,7 +142,7 @@ namespace teachos::arch::memory::paging } auto level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; - auto level1_frame = level1_entry.calculate_pointed_to_frame(); + auto const level1_frame = level1_entry.calculate_pointed_to_frame(); exception_handling::assert(level1_frame.has_value(), "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); level1_entry.set_unused(); diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 765e9bb..e4847e3 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -7,7 +7,7 @@ namespace teachos::arch::memory::paging { - constexpr std::size_t PAGE_TABLE_ENTRY_COUNT = 512U; ///< Default entry count of a page table in x86_84 is 512. + std::size_t constexpr PAGE_TABLE_ENTRY_COUNT = 512U; ///< Default entry count of a page table in x86_84 is 512. /** * @brief Forward delcaration of the page_table, because it should only be accessible over the handle. @@ -85,7 +85,7 @@ namespace teachos::arch::memory::paging // page table one level below. if (!next_handle.has_value()) { - auto allocated_frame = allocator.allocate_frame(); + auto const allocated_frame = allocator.allocate_frame(); exception_handling::assert(allocated_frame.has_value(), "[Page mapper] Unable to allocate frame"); this->operator[](table_index).set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); // There should now be an entry at the previously not existent index, therefore we can simply access it again. diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index b9e2195..934ecf2 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -50,12 +50,12 @@ namespace teachos::arch::memory::paging /** * @brief Defaulted equals operator. */ - constexpr auto operator==(const virtual_page & other) const -> bool = default; + auto operator==(const virtual_page & other) const -> bool = default; /** * @brief Defaulted three-way comparsion operator. */ - constexpr auto operator<=>(const virtual_page & other) const -> std::partial_ordering = default; + auto operator<=>(const virtual_page & other) const -> std::partial_ordering = default; std::size_t page_number; ///< Index number of the current virtual page, used to distinguish it from other pages. }; diff --git a/arch/x86_64/include/arch/shared/random_access_iterator.hpp b/arch/x86_64/include/arch/shared/random_access_iterator.hpp index 392b925..13deb68 100644 --- a/arch/x86_64/include/arch/shared/random_access_iterator.hpp +++ b/arch/x86_64/include/arch/shared/random_access_iterator.hpp @@ -56,7 +56,7 @@ namespace teachos::arch::shared */ auto operator++(int) -> random_access_iterator { - random_access_iterator old_value = *this; + random_access_iterator const old_value = *this; ++ptr; return old_value; } diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 5186c21..e067b48 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -16,12 +16,12 @@ namespace teachos::arch::kernel video::vga::text::cursor(false); video::vga::text::write("TeachOS is starting up...", video::vga::text::common_attributes::green_on_black); - auto memory_information = memory::multiboot::read_multiboot2(); + auto const memory_information = memory::multiboot::read_multiboot2(); memory::allocator::area_frame_allocator allocator(memory_information); size_t address = 42 * memory::paging::PAGE_TABLE_ENTRY_COUNT * memory::paging::PAGE_TABLE_ENTRY_COUNT * memory::allocator::PAGE_FRAME_SIZE; // 42th P3 entry - auto page = memory::paging::virtual_page::containing_address(address); + auto const page = memory::paging::virtual_page::containing_address(address); memory::paging::map_next_free_page_to_frame(allocator, page, 0U); auto optional_frame = memory::paging::translate_page(page); video::vga::text::newline(); diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index e03c66a..6ec3e95 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -28,7 +28,7 @@ namespace teachos::arch::memory::allocator return physical_frame::containing_address(address) >= next_free_frame; }); - auto lowest_area_with_free_frames = + auto const lowest_area_with_free_frames = std::ranges::min_element(next_area_with_free_frames, [](multiboot::memory_area a, multiboot::memory_area b) { return a.base_address < b.base_address; }); @@ -37,7 +37,7 @@ namespace teachos::arch::memory::allocator { current_area = *lowest_area_with_free_frames; // Update the `next_free_frame` according to the new memory area - auto start_frame = physical_frame::containing_address(current_area.value().base_address); + auto const start_frame = physical_frame::containing_address(current_area.value().base_address); if (next_free_frame < start_frame) { next_free_frame = start_frame; @@ -47,16 +47,14 @@ namespace teachos::arch::memory::allocator 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. - */ + // 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 address = current_area.value().base_address + current_area.value().area_length - 1; + 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) diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp index 228aa09..c3a78df 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -21,14 +21,14 @@ namespace teachos::arch::memory::multiboot auto process_memory_map(memory_map_header * mminfo, memory_area_container::iterator & begin_area, memory_area_container::iterator & end_area) -> void { - auto expected_entry_size = mminfo->entry_size; - constexpr auto actual_entry_size = sizeof(memory_area); + 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 total_size = mminfo->info.size; - auto total_entries_size = total_size - sizeof(memory_map_header) + actual_entry_size; - auto number_of_entries = total_entries_size / actual_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; begin_area = memory_area_container::iterator{&mminfo->entries}; end_area = begin_area + number_of_entries; @@ -37,41 +37,41 @@ namespace teachos::arch::memory::multiboot auto process_elf_sections(elf_symbols_section_header * symbol, uint64_t & kernel_start, uint64_t & kernel_end) -> void { - auto expected_entry_size = symbol->entry_size; - constexpr auto actual_entry_size = sizeof(elf_section_header); + 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 expected_total_size = symbol->info.size; - auto actual_total_entry_size = actual_entry_size * symbol->number_of_sections; - constexpr auto actual_total_section_size = sizeof(elf_symbols_section_header) - sizeof(uint32_t); - auto actual_total_size = actual_total_entry_size + actual_total_section_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 begin = elf_section_header_container::iterator{reinterpret_cast(&symbol->end)}; - auto end = begin + symbol->number_of_sections; + 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 container{begin, end}; - auto elf_section_with_lowest_virtual_address = + auto const elf_section_with_lowest_virtual_address = std::ranges::min_element(container, [](elf_section_header const & a, elf_section_header const & b) { return a.virtual_address < b.virtual_address; }); - auto elf_section_with_highest_virtual_address = + auto const elf_section_with_highest_virtual_address = std::ranges::max_element(container, [](elf_section_header const & a, elf_section_header const & b) { auto a_virtual_address_end = a.virtual_address + a.section_size; auto b_virtual_address_end = b.virtual_address + b.section_size; return a_virtual_address_end < b_virtual_address_end; }); - auto symbol_table_section_count = std::ranges::count_if(container, [](elf_section_header const & section) { + auto const symbol_table_section_count = std::ranges::count_if(container, [](elf_section_header const & section) { return section.type == elf_section_type::DYNAMIC_SYMBOL_TABLE || section.type == elf_section_type::SYMBOL_TABLE; }); - auto dynamic_section_count = std::ranges::count_if( + auto const dynamic_section_count = std::ranges::count_if( container, [](elf_section_header const & section) { return section.type == elf_section_type::DYNAMIC; }); exception_handling::assert( @@ -81,10 +81,10 @@ namespace teachos::arch::memory::multiboot dynamic_section_count <= 1U, "[Multiboot Reader] ELF Specifications allows only (1) or less dynamic sections, but got more"); - auto lowest_elf_section = *elf_section_with_lowest_virtual_address; + auto const lowest_elf_section = *elf_section_with_lowest_virtual_address; kernel_start = lowest_elf_section.virtual_address; - auto highest_elf_section = *elf_section_with_highest_virtual_address; + auto const highest_elf_section = *elf_section_with_highest_virtual_address; kernel_end = highest_elf_section.virtual_address + highest_elf_section.section_size; } } // namespace @@ -98,8 +98,8 @@ namespace teachos::arch::memory::multiboot memory_area_container::iterator{}, memory_area_container::iterator{}}; - auto multiboot_information_pointer = reinterpret_cast(boot::multiboot_information_pointer); - auto multiboot_tag = &multiboot_information_pointer->tags; + 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)) @@ -107,12 +107,12 @@ namespace teachos::arch::memory::multiboot switch (tag->type) { case tag_type::ELF_SECTIONS: { - auto symbol = reinterpret_cast(tag); + auto const symbol = reinterpret_cast(tag); process_elf_sections(symbol, mem_info.kernel_start, mem_info.kernel_end); break; } case tag_type::MEMORY_MAP: { - auto mminfo = reinterpret_cast(tag); + auto const mminfo = reinterpret_cast(tag); process_memory_map(mminfo, mem_info.begin_area, mem_info.end_area); break; } @@ -121,7 +121,6 @@ namespace teachos::arch::memory::multiboot break; } } - return mem_info; } } // namespace teachos::arch::memory::multiboot diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index dbf23e2..8923fea 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -6,7 +6,7 @@ namespace teachos::arch::memory::paging { namespace { - constexpr std::size_t PHYSICAL_ADDRESS_MASK = 0x000fffff'fffff000; + std::size_t constexpr PHYSICAL_ADDRESS_MASK = 0x000fffff'fffff000; } entry::entry(uint64_t flags) diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index fb9ea39..3baf6ae 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -4,11 +4,15 @@ namespace teachos::arch::memory::paging { + namespace + { + std::size_t constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; + } // namespace auto create_or_get() -> page_table_handle { static auto initialized = false; - static page_table_handle active_handle{reinterpret_cast(0xffffffff'fffff000), + static page_table_handle active_handle{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS), page_table_handle::LEVEL4}; if (!initialized) @@ -22,9 +26,9 @@ namespace teachos::arch::memory::paging auto translate_address(virtual_address address) -> std::optional { - auto offset = address % allocator::PAGE_FRAME_SIZE; - auto page = virtual_page::containing_address(address); - auto frame = translate_page(page); + 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()) { @@ -40,7 +44,7 @@ namespace teachos::arch::memory::paging for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) { - auto next_handle = current_handle.next_table(page.get_level_index(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()) @@ -50,8 +54,8 @@ namespace teachos::arch::memory::paging current_handle = next_handle.value(); } - auto level1_index = page.get_level_index(page_table_handle::LEVEL1); - auto level1_frame = current_handle[level1_index].calculate_pointed_to_frame(); + auto const level1_index = page.get_level_index(page_table_handle::LEVEL1); + auto const level1_frame = current_handle[level1_index].calculate_pointed_to_frame(); return level1_frame; } @@ -65,8 +69,8 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto level3_entry = level3_handle.value()[page.get_level_index(page_table_handle::LEVEL3)]; - auto level3_frame = level3_entry.calculate_pointed_to_frame(); + 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( @@ -80,8 +84,8 @@ namespace teachos::arch::memory::paging auto level2_handle = level3_handle.value().next_table(page.get_level_index(page_table_handle::LEVEL3)); if (level2_handle.has_value()) { - auto level2_entry = level2_handle.value()[page.get_level_index(page_table_handle::LEVEL2)]; - auto level2_frame = level2_entry.calculate_pointed_to_frame(); + 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, diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index e919a1e..a01c431 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -60,9 +60,9 @@ namespace teachos::arch::memory::paging auto page_table::zero_entries() -> void { - constexpr size_t entry_amount = sizeof(entries) / sizeof(entries[0]); + std::size_t constexpr entry_amount = sizeof(entries) / sizeof(entries[0]); static_assert(entry_amount == PAGE_TABLE_ENTRY_COUNT); - for (size_t i = 0; i < entry_amount; ++i) + for (std::size_t i = 0; i < entry_amount; ++i) { auto entry = this->operator[](i); entry.set_unused(); @@ -71,7 +71,7 @@ namespace teachos::arch::memory::paging auto page_table::next_table(std::size_t table_index) -> std::optional { - auto address = next_table_address(table_index); + auto const address = next_table_address(table_index); if (address.has_value()) { return reinterpret_cast(address.value()); @@ -89,11 +89,11 @@ namespace teachos::arch::memory::paging auto page_table::next_table_address(std::size_t table_index) -> std::optional { - auto entry = this->operator[](table_index); + auto const entry = this->operator[](table_index); if (entry.contains_flags(entry::PRESENT) && !entry.contains_flags(entry::HUGE_PAGE)) { - std::size_t const table_address = reinterpret_cast(this); + auto const table_address = reinterpret_cast(this); return ((table_address << 9) | (table_index << 12)); } return std::nullopt; @@ -113,17 +113,17 @@ namespace teachos::arch::memory::paging exception_handling::assert(handle_level == page_table_handle::LEVEL4, "[Page Table] Attempted to initialize a page table of level 3 or lower"); auto level3_page_table = std::construct_at(reinterpret_cast(&_end_of_image)); - for (size_t n = 1; n <= PAGE_TABLE_ENTRY_COUNT; ++n) + for (std::size_t n = 1; n <= PAGE_TABLE_ENTRY_COUNT; ++n) { - size_t offset = sizeof(page_table) * n; + std::size_t offset = sizeof(page_table) * n; std::construct_at(reinterpret_cast(&_end_of_image + offset)); - for (size_t m = 1; m <= PAGE_TABLE_ENTRY_COUNT; ++m) + for (std::size_t m = 1; m <= PAGE_TABLE_ENTRY_COUNT; ++m) { - size_t offset = sizeof(page_table) * ((PAGE_TABLE_ENTRY_COUNT * n) + m); + std::size_t offset = sizeof(page_table) * ((PAGE_TABLE_ENTRY_COUNT * n) + m); std::construct_at(reinterpret_cast(&_end_of_image + offset)); } } - size_t const flags = reinterpret_cast(level3_page_table); + std::size_t const flags = reinterpret_cast(level3_page_table); this->operator[](0U) = entry{flags}; */ } @@ -134,7 +134,7 @@ namespace teachos::arch::memory::paging { exception_handling::assert(handle_level != page_table_handle::LEVEL1, "[Page Table] Attempted to call next_table on level 1 page table"); - auto next_table = handle->next_table(table_index); + auto const next_table = handle->next_table(table_index); if (next_table.has_value()) { return page_table_handle{next_table.value(), --handle_level}; diff --git a/arch/x86_64/src/memory/paging/virtual_page.cpp b/arch/x86_64/src/memory/paging/virtual_page.cpp index d39bb7f..4221335 100644 --- a/arch/x86_64/src/memory/paging/virtual_page.cpp +++ b/arch/x86_64/src/memory/paging/virtual_page.cpp @@ -12,7 +12,7 @@ namespace teachos::arch::memory::paging auto virtual_page::containing_address(virtual_address address) -> virtual_page { - exception_handling::assert(address < 0x0000800000000000 || address >= 0xffff800000000000, + 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}; } diff --git a/include/memory/asm_pointer.hpp b/include/memory/asm_pointer.hpp index 71dfcf7..4c25658 100644 --- a/include/memory/asm_pointer.hpp +++ b/include/memory/asm_pointer.hpp @@ -73,4 +73,4 @@ namespace teachos::memory } // namespace teachos::memory -#endif \ No newline at end of file +#endif // TEACHOS_MEMORY_ASM_POINTER_HPP -- cgit v1.2.3 From aa981cad951c4aa2a5e2f7a7f8f1b7b9a0ff4bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 28 Oct 2024 14:41:31 +0000 Subject: Fix lost updates, because of writing into copies instead of references --- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 4 ++-- arch/x86_64/src/kernel/main.cpp | 6 +++++- arch/x86_64/src/memory/allocator/area_frame_allocator.cpp | 8 ++++++-- arch/x86_64/src/memory/paging/page_entry.cpp | 3 ++- arch/x86_64/src/memory/paging/page_mapper.cpp | 4 ++-- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 4edcea9..d852fbc 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -79,7 +79,7 @@ namespace teachos::arch::memory::paging current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level)); } - auto level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; + auto & level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), "[Page Mapper] Unable to map huge pages"); arch::exception_handling::assert(level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); @@ -141,7 +141,7 @@ namespace teachos::arch::memory::paging current_handle = next_handle.value(); } - auto level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; + auto & level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; auto const level1_frame = level1_entry.calculate_pointed_to_frame(); exception_handling::assert(level1_frame.has_value(), "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index e067b48..5c55213 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -28,9 +28,13 @@ namespace teachos::arch::kernel video::vga::text::write("Mapped physical frame: ", video::vga::text::common_attributes::green_on_black); video::vga::text::write_number(optional_frame.value().frame_number, video::vga::text::common_attributes::green_on_black); + video::vga::text::write(" to virtual page: ", video::vga::text::common_attributes::green_on_black); + video::vga::text::write_number(page.page_number, video::vga::text::common_attributes::green_on_black); memory::paging::unmap_page(allocator, page); - video::vga::text::write("Unapped physical page: ", video::vga::text::common_attributes::green_on_black); + video::vga::text::newline(); + video::vga::text::write("Unapped virtual page from physical frame: ", + video::vga::text::common_attributes::green_on_black); optional_frame = memory::paging::translate_page(page); exception_handling::assert(!optional_frame.has_value(), "[Main] Ummapping failed"); video::vga::text::write_number(page.page_number, video::vga::text::common_attributes::green_on_black); diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index 6ec3e95..fecc6cd 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -85,7 +85,11 @@ namespace teachos::arch::memory::allocator auto area_frame_allocator::deallocate_frame(physical_frame physical_frame) -> void { - exception_handling::assert(false && physical_frame.frame_number == 0, - "[deallocate_frame] Not implemented Exception"); + // TODO: Implement deallocation to make unmap actually work. + if (physical_frame.frame_number == 0) + { + } + /*exception_handling::assert(false && physical_frame.frame_number == 0, + "[deallocate_frame] Not implemented Exception");*/ } } // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 8923fea..23c700f 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -23,7 +23,8 @@ namespace teachos::arch::memory::paging { if (contains_flags(PRESENT)) { - return allocator::physical_frame::containing_address(flags.to_ulong() & PHYSICAL_ADDRESS_MASK); + auto const address = flags.to_ulong() & PHYSICAL_ADDRESS_MASK; + return allocator::physical_frame::containing_address(address); } return std::nullopt; } diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 3baf6ae..0a1fc65 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -55,8 +55,8 @@ namespace teachos::arch::memory::paging } auto const level1_index = page.get_level_index(page_table_handle::LEVEL1); - auto const level1_frame = current_handle[level1_index].calculate_pointed_to_frame(); - return level1_frame; + auto const level1_entry = current_handle[level1_index]; + return level1_entry.calculate_pointed_to_frame(); } auto translate_huge_page(virtual_page page) -> std::optional -- cgit v1.2.3 From bd3ae51093b504bd035cb698c637ef6f82994ba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 28 Oct 2024 14:48:32 +0000 Subject: Remove not required includes --- arch/x86_64/include/arch/boot/pointers.hpp | 2 -- arch/x86_64/src/memory/paging/page_mapper.cpp | 2 -- arch/x86_64/src/video/vga/text.cpp | 1 - 3 files changed, 5 deletions(-) diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index 18c41ce..25800f4 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -1,8 +1,6 @@ #ifndef TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP #define TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP -#include "arch/memory/paging/page_table.hpp" - #include namespace teachos::arch::boot diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 0a1fc65..be4b259 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -1,7 +1,5 @@ #include "arch/memory/paging/page_mapper.hpp" -#include "arch/boot/pointers.hpp" - namespace teachos::arch::memory::paging { namespace diff --git a/arch/x86_64/src/video/vga/text.cpp b/arch/x86_64/src/video/vga/text.cpp index c14de16..9eef288 100644 --- a/arch/x86_64/src/video/vga/text.cpp +++ b/arch/x86_64/src/video/vga/text.cpp @@ -1,6 +1,5 @@ #include "arch/video/vga/text.hpp" -#include "arch/boot/pointers.hpp" #include "arch/video/vga/io.hpp" #include "memory/asm_pointer.hpp" -- cgit v1.2.3 From f9f047f519d0100c40b914d3ce777ac2f8430b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 28 Oct 2024 15:18:31 +0000 Subject: Add is empty check method for page table --- .../include/arch/memory/paging/page_mapper.hpp | 2 +- .../include/arch/memory/paging/page_table.hpp | 15 +++++- .../src/memory/allocator/area_frame_allocator.cpp | 9 ++-- arch/x86_64/src/memory/paging/page_table.cpp | 55 +++++++++------------- 4 files changed, 41 insertions(+), 40 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index d852fbc..6a0c989 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -146,10 +146,10 @@ namespace teachos::arch::memory::paging exception_handling::assert(level1_frame.has_value(), "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); level1_entry.set_unused(); - invalidate_page_cache(&level1_entry); // TODO: Deallocate and unmap level 1, 2, 3 page table entry if this was the last page in them. // TODO: Fix deallocate because it is not yet implemented. allocator.deallocate_frame(level1_frame.value()); + invalidate_page_cache(&level1_entry); } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index e4847e3..07e7e22 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -56,6 +56,11 @@ namespace teachos::arch::memory::paging */ auto zero_entries() -> void; + /** + * @brief Checks if all entries of this page are unused. + */ + auto is_empty() const -> bool; + /** * @brief Returns the next page table level from the given page table index. Meaning we * use an index into a Level 4 page table to get the according Level 3 page table. @@ -97,13 +102,21 @@ namespace teachos::arch::memory::paging } /** - * @brief Index operator overload to access specific immutable entry directy. + * @brief Index operator overload to access specific mutable entry directy. * * @param index Index of the entry we want to access and only read. * @return Entry at the given table index. */ auto operator[](std::size_t index) -> entry &; + /** + * @brief Index operator overload to access specific immutable entry directy. + * + * @param index Index of the entry we want to access and read or write. + * @return Entry at the given table index. + */ + auto operator[](std::size_t index) const -> entry const &; + /** * @brief Decrements the page table handle level enum by one, is defined so we can use it as a replacement for an * int index in a range based for loop. diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index fecc6cd..e79cd8b 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -85,11 +85,8 @@ namespace teachos::arch::memory::allocator auto area_frame_allocator::deallocate_frame(physical_frame physical_frame) -> void { - // TODO: Implement deallocation to make unmap actually work. - if (physical_frame.frame_number == 0) - { - } - /*exception_handling::assert(false && physical_frame.frame_number == 0, - "[deallocate_frame] Not implemented Exception");*/ + // TODO: Fix create acutal deallocation of frames if it is even possible. Can the area frame allocator even + // deallocate in the first place? + next_free_frame = physical_frame; } } // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index a01c431..64a4fd9 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -1,5 +1,6 @@ #include "arch/memory/paging/page_table.hpp" +#include #include #include @@ -16,31 +17,16 @@ namespace teachos::arch::memory::paging */ struct page_table { - /** - * @brief Set every entry of the page to unused. - */ auto zero_entries() -> void; - /** - * @brief Returns the next page table level from the given page table index. Meaning we use an index into a Level 4 - * page table to get the according Level 3 page table. - * - * @note This method - * should not be called on a Level 1 page table, because there is no furthere page table and mangeling up and - * returning the physical address would cause hard to debug issues. - * - * @param table_index Index of this page table in the page table one level lower. - */ - auto next_table(std::size_t table_index) -> std::optional; + auto is_empty() const -> bool; + + auto next_table(std::size_t table_index) const -> std::optional; - /** - * @brief Index operator overload to access specific entries directy. - * - * @param index Index of the entry we want to access and read or write too. - * @return Entry at the given table index. - */ 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. @@ -51,7 +37,7 @@ namespace teachos::arch::memory::paging * @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) -> std::optional; + 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 @@ -60,16 +46,15 @@ namespace teachos::arch::memory::paging auto page_table::zero_entries() -> void { - std::size_t constexpr entry_amount = sizeof(entries) / sizeof(entries[0]); - static_assert(entry_amount == PAGE_TABLE_ENTRY_COUNT); - for (std::size_t i = 0; i < entry_amount; ++i) - { - auto entry = this->operator[](i); - entry.set_unused(); - } + std::ranges::for_each(entries, [](entry & 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) -> std::optional + 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()) @@ -81,13 +66,17 @@ namespace teachos::arch::memory::paging auto page_table::operator[](std::size_t index) -> entry & { - // C array is not bounds checked, therefore we have to check ourselves, to ensure no out of bounds reads, which - // could be incredibly hard to debug later. 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) -> std::optional + 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); @@ -130,6 +119,8 @@ namespace teachos::arch::memory::paging auto page_table_handle::zero_entries() -> void { handle->zero_entries(); } + auto page_table_handle::is_empty() const -> bool { return handle->is_empty(); } + auto page_table_handle::next_table(std::size_t table_index) -> std::optional { exception_handling::assert(handle_level != page_table_handle::LEVEL1, -- cgit v1.2.3 From 0d16592c8dce876d8e621c73dea41c33339f3173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 29 Oct 2024 06:55:36 +0000 Subject: Use more virtual and physical address typedef where useful --- .../include/arch/memory/allocator/physical_frame.hpp | 2 +- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 14 +++++++++----- arch/x86_64/include/arch/memory/paging/virtual_page.hpp | 2 +- arch/x86_64/src/memory/allocator/physical_frame.cpp | 2 +- arch/x86_64/src/memory/paging/virtual_page.cpp | 2 +- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp index 39406af..146e557 100644 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -36,7 +36,7 @@ namespace teachos::arch::memory::allocator * * @return Start address of the physical frame. */ - auto start_address() const -> uint64_t; + auto start_address() const -> physical_address; /** * @brief Defaulted equals operator. diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 6a0c989..0ef552a 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -12,12 +12,16 @@ namespace teachos::arch::memory::paging namespace { /** - * @brief Invalidates any translation lookaside buffer (TLB) entries into the page table the given entry is cotained - * in. See https://www.felixcloutier.com/x86/invlpg for more information int he used x86 instruction. + * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained + * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. * - * @param entry Any entry into the page table we want to invalidate all cached entries in. + * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for + * that page. */ - auto invalidate_page_cache(entry * entry) -> void { asm volatile("invlpg (%0)" ::"r"(entry) : "memory"); } + auto invalidate_page_cache(virtual_address address) -> void + { + asm volatile("invlpg (%0)" ::"r"(address) : "memory"); + } } // namespace /** @@ -149,7 +153,7 @@ namespace teachos::arch::memory::paging // TODO: Deallocate and unmap level 1, 2, 3 page table entry if this was the last page in them. // TODO: Fix deallocate because it is not yet implemented. allocator.deallocate_frame(level1_frame.value()); - invalidate_page_cache(&level1_entry); + invalidate_page_cache(page.start_address()); } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index 934ecf2..8c5613d 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -37,7 +37,7 @@ namespace teachos::arch::memory::paging * * @return Start address of the virtual page. */ - auto start_address() const -> size_t; + auto start_address() const -> virtual_address; /** * @brief Calculates the index into the page table with the given level, which leads to this virtual page. diff --git a/arch/x86_64/src/memory/allocator/physical_frame.cpp b/arch/x86_64/src/memory/allocator/physical_frame.cpp index b05254b..bef9322 100644 --- a/arch/x86_64/src/memory/allocator/physical_frame.cpp +++ b/arch/x86_64/src/memory/allocator/physical_frame.cpp @@ -13,5 +13,5 @@ namespace teachos::arch::memory::allocator return physical_frame{address / PAGE_FRAME_SIZE}; } - auto physical_frame::start_address() const -> uint64_t { return frame_number * PAGE_FRAME_SIZE; } + auto physical_frame::start_address() const -> physical_address { return frame_number * PAGE_FRAME_SIZE; } } // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/paging/virtual_page.cpp b/arch/x86_64/src/memory/paging/virtual_page.cpp index 4221335..c0ec88d 100644 --- a/arch/x86_64/src/memory/paging/virtual_page.cpp +++ b/arch/x86_64/src/memory/paging/virtual_page.cpp @@ -17,7 +17,7 @@ namespace teachos::arch::memory::paging return virtual_page{address / allocator::PAGE_FRAME_SIZE}; } - auto virtual_page::start_address() const -> size_t { return page_number * 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 { -- cgit v1.2.3 From 4c4479a4b728fd7eaf007649e946f9435ee1e402 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 29 Oct 2024 07:32:24 +0000 Subject: implement page_table unmapping --- .../include/arch/memory/paging/page_mapper.hpp | 41 +++++++++++++++++----- .../include/arch/memory/paging/page_table.hpp | 7 ++++ arch/x86_64/src/memory/paging/page_table.cpp | 5 ++- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 0ef552a..801ccfb 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -5,6 +5,8 @@ #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/paging/virtual_page.hpp" +#include +#include #include namespace teachos::arch::memory::paging @@ -22,6 +24,28 @@ namespace teachos::arch::memory::paging { asm volatile("invlpg (%0)" ::"r"(address) : "memory"); } + + /** + * @brief Unmaps specific page at the current internal handle level. + * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. + * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate + * entries *when a new page table is required. + * @param page Virtual page that is being unmapped. + * @param handle Page Table handle we want to access the entry that should be cleared on. + */ + template + auto unmap_page_table_entry(T & allocator, virtual_page page, page_table_handle & handle) -> void + { + auto level_index = page.get_level_index(handle.get_level()); + auto & entry = handle[level_index]; + auto const frame = entry.calculate_pointed_to_frame(); + exception_handling::assert(frame.has_value(), + "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); + entry.set_unused(); + allocator.deallocate_frame(frame.value()); + } } // namespace /** @@ -135,8 +159,12 @@ namespace teachos::arch::memory::paging auto current_handle = create_or_get(); + std::array handles{}; + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) { + handles[level] = *current_handle; + auto const level_index = page.get_level_index(level); auto const next_handle = current_handle.next_table(level_index); // The next table method failed even tough the page has to be mapped already, because translate_page did not fail. @@ -145,14 +173,11 @@ namespace teachos::arch::memory::paging current_handle = next_handle.value(); } - auto & level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; - auto const level1_frame = level1_entry.calculate_pointed_to_frame(); - exception_handling::assert(level1_frame.has_value(), - "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); - level1_entry.set_unused(); - // TODO: Deallocate and unmap level 1, 2, 3 page table entry if this was the last page in them. - // TODO: Fix deallocate because it is not yet implemented. - allocator.deallocate_frame(level1_frame.value()); + std::ranges::for_each(handles, [&allocator, page](page_table_handle * handle) { + exception_handling::assert(handle != nullptr, "[Page Mapper] Attempted to unmap page behind nullpointer"); + unmap_page_table_entry(allocator, page, *handle); + }); + invalidate_page_cache(page.start_address()); } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 07e7e22..02ed099 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -61,6 +61,13 @@ namespace teachos::arch::memory::paging */ auto is_empty() const -> bool; + /** + * @brief Get the current handle level. + * + * @return Current handle level. + */ + auto get_level() const -> level; + /** * @brief Returns the next page table level from the given page table index. Meaning we * use an index into a Level 4 page table to get the according Level 3 page table. diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 64a4fd9..0121e95 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -92,7 +92,8 @@ namespace teachos::arch::memory::paging : handle(handle) , handle_level(handle_level) { - exception_handling::assert(handle, "[Page Table] Attempted to pass nullptr as handle to page table handle method"); + exception_handling::assert(handle != nullptr, + "[Page Table] Attempted to pass nullptr as handle to page table handle method"); } auto page_table_handle::initialize_page_tables() -> void @@ -133,6 +134,8 @@ namespace teachos::arch::memory::paging return std::nullopt; } + auto page_table_handle::get_level() const -> page_table_handle::level { return handle_level; } + auto page_table_handle::operator[](std::size_t index) -> entry & { return handle->operator[](index); } auto operator--(page_table_handle::level & value) -> page_table_handle::level & -- cgit v1.2.3 From 5334a63e7fc3959536f4f443c86f8913f7cb2451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 29 Oct 2024 08:05:22 +0000 Subject: Unmap all empty page tables in unmap function. --- .../arch/memory/allocator/area_frame_allocator.hpp | 4 ++++ .../include/arch/memory/paging/page_mapper.hpp | 26 ++++++++++++++-------- .../src/memory/allocator/area_frame_allocator.cpp | 7 +----- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp index 8e971f0..599723f 100644 --- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -41,6 +41,10 @@ namespace teachos::arch::memory::allocator /** * @brief Deallocates a previously allocated physical_frame. * + * @note Simply does nothing, because the simply area frame + * allocator implementation does not keep track of free or used frames and can therefore not deallocate, because it + * does not know which frames have ben alocated in the first place. + * * @param physical_frame Previously allocated physical_frame that should be allocated. */ auto deallocate_frame(physical_frame physical_frame) -> void; diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 801ccfb..a9f8eb8 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -158,26 +158,34 @@ namespace teachos::arch::memory::paging "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); auto current_handle = create_or_get(); - - std::array handles{}; + std::array handles{current_handle, current_handle, current_handle, current_handle}; for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) { - handles[level] = *current_handle; - auto const level_index = page.get_level_index(level); auto const next_handle = current_handle.next_table(level_index); // The next table method failed even tough the page has to be mapped already, because translate_page did not fail. // This can only mean that we attempted to unmap a huge page, which is not supported in the first place. exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); current_handle = next_handle.value(); + // The level is used as the index, because it ensures the first level is the lowest one and then the remaining + // levels in ascending order. This is required, because we first have to clear the Level 1 page entry to check if + // the Level 1 page is now empty, to clear the Level 2 page entry, which will then also check if the Level 2 page + // is empty and clear the Level 3 page entry and so on. + handles.at(level - 1U) = current_handle; } - std::ranges::for_each(handles, [&allocator, page](page_table_handle * handle) { - exception_handling::assert(handle != nullptr, "[Page Mapper] Attempted to unmap page behind nullpointer"); - unmap_page_table_entry(allocator, page, *handle); - }); - + // Unmaps all entries starting from the Level 1 page table, and unmaps higher levels as well if that entry was the + // last one. We check if it was the last one using is empty on the page table handle, when we have removed the page + // to be unmapped. + for (auto & handle : handles) + { + unmap_page_table_entry(allocator, page, handle); + if (!handle.is_empty()) + { + break; + } + } invalidate_page_cache(page.start_address()); } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index e79cd8b..1e87147 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -83,10 +83,5 @@ namespace teachos::arch::memory::allocator return allocate_frame(); } - auto area_frame_allocator::deallocate_frame(physical_frame physical_frame) -> void - { - // TODO: Fix create acutal deallocation of frames if it is even possible. Can the area frame allocator even - // deallocate in the first place? - next_free_frame = physical_frame; - } + auto area_frame_allocator::deallocate_frame(physical_frame physical_frame) -> void { (void)physical_frame; } } // namespace teachos::arch::memory::allocator -- cgit v1.2.3 From 4e9338075cf30702b922e5aecbc33c18bfd3f759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 29 Oct 2024 08:11:13 +0000 Subject: Remove not required methods --- .../include/arch/memory/paging/page_table.hpp | 5 ----- arch/x86_64/src/memory/paging/page_mapper.cpp | 8 -------- arch/x86_64/src/memory/paging/page_table.cpp | 22 ---------------------- 3 files changed, 35 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 02ed099..31fb58c 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -46,11 +46,6 @@ namespace teachos::arch::memory::paging */ page_table_handle(page_table * handle, level handle_level); - /** - * @brief Initializes one page table level 4 entry. - */ - void initialize_page_tables(); - /** * @brief Set every entry of the page to unused. */ diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index be4b259..2f2ee6a 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -9,16 +9,8 @@ namespace teachos::arch::memory::paging auto create_or_get() -> page_table_handle { - static auto initialized = false; static page_table_handle active_handle{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS), page_table_handle::LEVEL4}; - - if (!initialized) - { - active_handle.initialize_page_tables(); - initialized = true; - } - return active_handle; } diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 0121e95..3ad1d54 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -96,28 +96,6 @@ namespace teachos::arch::memory::paging "[Page Table] Attempted to pass nullptr as handle to page table handle method"); } - auto page_table_handle::initialize_page_tables() -> void - { - // TODO: This should be done differently and only once the other methods are working see Rempaing the Kernel - /* - exception_handling::assert(handle_level == page_table_handle::LEVEL4, - "[Page Table] Attempted to initialize a page table of level 3 or lower"); - auto level3_page_table = std::construct_at(reinterpret_cast(&_end_of_image)); - for (std::size_t n = 1; n <= PAGE_TABLE_ENTRY_COUNT; ++n) - { - std::size_t offset = sizeof(page_table) * n; - std::construct_at(reinterpret_cast(&_end_of_image + offset)); - for (std::size_t m = 1; m <= PAGE_TABLE_ENTRY_COUNT; ++m) - { - std::size_t offset = sizeof(page_table) * ((PAGE_TABLE_ENTRY_COUNT * n) + m); - std::construct_at(reinterpret_cast(&_end_of_image + offset)); - } - } - std::size_t const flags = reinterpret_cast(level3_page_table); - this->operator[](0U) = entry{flags}; - */ - } - auto page_table_handle::zero_entries() -> void { handle->zero_entries(); } auto page_table_handle::is_empty() const -> bool { return handle->is_empty(); } -- cgit v1.2.3 From dfb0ea2fd7525dd12addf295aef4d642e93ea22a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 29 Oct 2024 09:31:36 +0000 Subject: Create tiny frame allocator which holds only 3 frames --- arch/x86_64/CMakeLists.txt | 1 + .../arch/memory/allocator/area_frame_allocator.hpp | 8 ++-- .../arch/memory/allocator/tiny_frame_allocator.hpp | 44 ++++++++++++++++++++++ .../src/memory/allocator/tiny_frame_allocator.cpp | 34 +++++++++++++++++ 4 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp create mode 100644 arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index e1b7352..496752f 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -44,6 +44,7 @@ target_sources("_memory" PRIVATE "src/memory/multiboot/elf_symbols_section.cpp" "src/memory/multiboot/reader.cpp" "src/memory/allocator/area_frame_allocator.cpp" + "src/memory/allocator/tiny_frame_allocator.cpp" "src/memory/allocator/physical_frame.cpp" "src/memory/paging/page_entry.cpp" "src/memory/paging/page_table.cpp" diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp index 599723f..6135184 100644 --- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -27,7 +27,7 @@ namespace teachos::arch::memory::allocator area_frame_allocator(multiboot::memory_information mem_info); /** - * @brief Allocate memory by finding and returning a free physical_frame. + * @brief Allocate memory by finding and returning a free physical frame. * * @note The physical_frame allocation executes multiple checks before returning * the physical_frame that is available to allocate. It must at least @@ -35,17 +35,19 @@ namespace teachos::arch::memory::allocator * - check if the next_free_frame is within the current_area * - check if the next_free_frame is actually free * - update the next_free_frame after finding a free physical_frame + * + * @return next free physical frame or nullopt if none was found. */ auto allocate_frame() -> std::optional; /** - * @brief Deallocates a previously allocated physical_frame. + * @brief Deallocates a previously allocated physical frame. * * @note Simply does nothing, because the simply area frame * allocator implementation does not keep track of free or used frames and can therefore not deallocate, because it * does not know which frames have ben alocated in the first place. * - * @param physical_frame Previously allocated physical_frame that should be allocated. + * @param physical_frame Previously allocated physical_frame that should be deallocated. */ auto deallocate_frame(physical_frame physical_frame) -> void; diff --git a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp new file mode 100644 index 0000000..70c7de6 --- /dev/null +++ b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -0,0 +1,44 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP + +#include "arch/memory/allocator/physical_frame.hpp" + +#include +#include + +namespace teachos::arch::memory::allocator +{ + /** + * @brief Allocates memory using memory areas read from the multiboot2 information pointer. + */ + struct tiny_frame_allocator + { + /** + * @brief Defaulted constructor. + */ + tiny_frame_allocator() = default; + + /** + * @brief Allocate memory by finding and returning one of the three free physical frames. + * + * @return First free physical frames of the three frames held by this allocator or nullopt if we used up all three + * frames already. + */ + auto allocate_frame() -> std::optional; + + /** + * @brief Deallocates one of the three previously allocated physical frames. + * + * @note If more than the three frames are deallocated the method will halt execution, because it can only hold 3 + * frames. + * + * @param physical_frame Previously allocated physical_frame that should be deallocated. + */ + auto deallocate_frame(physical_frame physical_frame) -> void; + + private: + std::array, 3U> frames = {}; + }; +} // namespace teachos::arch::memory::allocator + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP diff --git a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp new file mode 100644 index 0000000..d07398a --- /dev/null +++ b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp @@ -0,0 +1,34 @@ +#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 = std::nullopt; + return value; + } + } + return std::nullopt; + } + + auto tiny_frame_allocator::deallocate_frame(physical_frame physical_frame) -> void + { + for (auto & frame_option : frames) + { + if (!frame_option.has_value()) + { + frame_option = 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 -- cgit v1.2.3 From 98edc76893b2e22ccdbd81a4a3f1e1113c712cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 1 Nov 2024 07:44:28 +0000 Subject: Extract contract into seperate file and create tinyallocator constructor --- .../arch/memory/allocator/area_frame_allocator.hpp | 6 ------ arch/x86_64/include/arch/memory/allocator/concept.hpp | 17 +++++++++++++++++ .../arch/memory/allocator/tiny_frame_allocator.hpp | 9 +++++++-- arch/x86_64/include/arch/memory/paging/page_mapper.hpp | 2 +- arch/x86_64/include/arch/memory/paging/page_table.hpp | 2 +- 5 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/allocator/concept.hpp diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp index 6135184..4b6c2d4 100644 --- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -8,12 +8,6 @@ namespace teachos::arch::memory::allocator { - template - concept FrameAllocator = requires(T t, physical_frame a) { - { t.allocate_frame() } -> std::same_as>; - { t.deallocate_frame(a) } -> std::same_as; - }; - /** * @brief Allocates memory using memory areas read from the multiboot2 information pointer. */ diff --git a/arch/x86_64/include/arch/memory/allocator/concept.hpp b/arch/x86_64/include/arch/memory/allocator/concept.hpp new file mode 100644 index 0000000..0aa45c6 --- /dev/null +++ b/arch/x86_64/include/arch/memory/allocator/concept.hpp @@ -0,0 +1,17 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP + +#include "arch/memory/allocator/physical_frame.hpp" + +#include + +namespace teachos::arch::memory::allocator +{ + template + concept FrameAllocator = requires(T t, physical_frame a) { + { t.allocate_frame() } -> std::same_as>; + { t.deallocate_frame(a) } -> std::same_as; + }; +} // namespace teachos::arch::memory::allocator + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP diff --git a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp index 70c7de6..a028e30 100644 --- a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -1,10 +1,10 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP #define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP +#include "arch/memory/allocator/concept.hpp" #include "arch/memory/allocator/physical_frame.hpp" #include -#include namespace teachos::arch::memory::allocator { @@ -16,7 +16,12 @@ namespace teachos::arch::memory::allocator /** * @brief Defaulted constructor. */ - tiny_frame_allocator() = default; + template + tiny_frame_allocator(T & allocator) + : frames{allocator.allocate_frame(), allocator.allocate_frame(), allocator.allocate_frame()} + { + // Nothing to do + } /** * @brief Allocate memory by finding and returning one of the three free physical frames. diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index a9f8eb8..26b8171 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -2,7 +2,7 @@ #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP #include "arch/exception_handling/assert.hpp" -#include "arch/memory/allocator/area_frame_allocator.hpp" +#include "arch/memory/allocator/concept.hpp" #include "arch/memory/paging/virtual_page.hpp" #include diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 31fb58c..b9ea44b 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -2,7 +2,7 @@ #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP #include "arch/exception_handling/assert.hpp" -#include "arch/memory/allocator/area_frame_allocator.hpp" +#include "arch/memory/allocator/concept.hpp" #include "arch/memory/paging/page_entry.hpp" namespace teachos::arch::memory::paging -- cgit v1.2.3 From b0f666ba15ff2db3178ca54242308e3dd5dd6faa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 1 Nov 2024 09:34:19 +0000 Subject: Fix comment --- arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp index a028e30..9417c37 100644 --- a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -14,7 +14,12 @@ namespace teachos::arch::memory::allocator struct tiny_frame_allocator { /** - * @brief Defaulted constructor. + * @brief Constructor. + * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. + * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate + * entries *when a new page table is required. */ template tiny_frame_allocator(T & allocator) -- cgit v1.2.3 From 29c51a2cc30060bd904b06cbe6913755352c48c7 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Fri, 1 Nov 2024 10:08:50 +0000 Subject: create temporary page implementation --- arch/x86_64/CMakeLists.txt | 1 + .../arch/memory/allocator/tiny_frame_allocator.hpp | 14 ++++- .../include/arch/memory/paging/page_table.hpp | 18 +++--- .../include/arch/memory/paging/temporary_page.hpp | 68 ++++++++++++++++++++++ arch/x86_64/src/kernel/main.cpp | 35 ++++++----- arch/x86_64/src/memory/paging/page_table.cpp | 24 ++++---- arch/x86_64/src/memory/paging/temporary_page.cpp | 35 +++++++++++ 7 files changed, 156 insertions(+), 39 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/paging/temporary_page.hpp create mode 100644 arch/x86_64/src/memory/paging/temporary_page.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 496752f..8d64985 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -48,6 +48,7 @@ target_sources("_memory" PRIVATE "src/memory/allocator/physical_frame.cpp" "src/memory/paging/page_entry.cpp" "src/memory/paging/page_table.cpp" + "src/memory/paging/temporary_page.cpp" "src/memory/paging/virtual_page.cpp" "src/memory/paging/page_mapper.cpp" ) diff --git a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp index a028e30..77d1b43 100644 --- a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP #define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP +#include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/allocator/concept.hpp" #include "arch/memory/allocator/physical_frame.hpp" @@ -16,10 +17,17 @@ namespace teachos::arch::memory::allocator /** * @brief Defaulted constructor. */ - template - tiny_frame_allocator(T & allocator) - : frames{allocator.allocate_frame(), allocator.allocate_frame(), allocator.allocate_frame()} + tiny_frame_allocator(area_frame_allocator & allocator) + : frames{} { + for (auto & frame : frames) + { + auto temp_frame = allocator.allocate_frame(); + if (temp_frame.has_value()) + { + frame.emplace(temp_frame.value()); + } + } // Nothing to do } diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index b9ea44b..9449ef2 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -41,10 +41,10 @@ namespace teachos::arch::memory::paging /** * @brief Constructor. * - * @param handle Underlying page table the handle should point to. - * @param handle_level Level the underlying page table is on, used to ensure safety. + * @param table Underlying page table the handle should point to. + * @param table_level Level the underlying page table is on, used to ensure safety. */ - page_table_handle(page_table * handle, level handle_level); + page_table_handle(page_table * table, level table_level); /** * @brief Set every entry of the page to unused. @@ -57,9 +57,9 @@ namespace teachos::arch::memory::paging auto is_empty() const -> bool; /** - * @brief Get the current handle level. + * @brief Get the current table level. * - * @return Current handle level. + * @return Current table level. */ auto get_level() const -> level; @@ -120,7 +120,7 @@ namespace teachos::arch::memory::paging auto operator[](std::size_t index) const -> entry const &; /** - * @brief Decrements the page table handle level enum by one, is defined so we can use it as a replacement for an + * @brief Decrements the page table level enum by one, is defined so we can use it as a replacement for an * int index in a range based for loop. * * @note Will halt execution if called with page_table_handle::LEVEL1, because there is no level below. Has to be @@ -137,9 +137,9 @@ namespace teachos::arch::memory::paging friend auto operator--(level & value) -> level &; private: - page_table * handle; ///< Handle to underlying page table, can never be null (invariant ensured by constructor) - level handle_level; ///< Level page table is currently on, depends on how often next_level was - ///< called successfully. + page_table * table; ///< Handle to underlying page table, can never be null (invariant ensured by constructor) + level table_level; ///< Level page table is currently on, depends on how often next_level was + ///< called successfully. }; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp new file mode 100644 index 0000000..ae806c8 --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -0,0 +1,68 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_TEMPORARY_PAGE_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_TEMPORARY_PAGE_HPP + +#include "arch/memory/allocator/physical_frame.hpp" +#include "arch/memory/allocator/tiny_frame_allocator.hpp" +#include "arch/memory/paging/page_table.hpp" +#include "arch/memory/paging/virtual_page.hpp" + +namespace teachos::arch::memory::paging +{ + + /** + * @brief + * + */ + struct temporary_page + { + /** + * @brief Construct a new temporary page object + * + * @tparam T + * @param page + * @param allocator + */ + template + temporary_page(virtual_page page, T & allocator) + : page{page} + , allocator{allocator} + { + // Nothing to do + } + + /** + * @brief + * + * @param frame + */ + auto zero_entries() -> void; + + private: + /** + * @brief + * + * @param frame + * @return virtual_address + */ + auto map_to_frame(allocator::physical_frame frame) -> virtual_address; + + /** + * @brief + * + */ + auto unmap() -> void; + + /** + * @brief + * + * @param frame + * @return page_table_handle + */ + auto map_table_frame(allocator::physical_frame frame) -> page_table_handle; + + virtual_page page; + allocator::tiny_frame_allocator allocator; + }; +} // namespace teachos::arch::memory::paging + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_TEMPORARY_PAGE_HPP \ No newline at end of file diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 5c55213..a27631f 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -4,6 +4,7 @@ #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/multiboot/reader.hpp" #include "arch/memory/paging/page_mapper.hpp" +#include "arch/memory/paging/temporary_page.hpp" #include "arch/video/vga/text.hpp" #include @@ -22,22 +23,26 @@ namespace teachos::arch::kernel size_t address = 42 * memory::paging::PAGE_TABLE_ENTRY_COUNT * memory::paging::PAGE_TABLE_ENTRY_COUNT * memory::allocator::PAGE_FRAME_SIZE; // 42th P3 entry auto const page = memory::paging::virtual_page::containing_address(address); - memory::paging::map_next_free_page_to_frame(allocator, page, 0U); - auto optional_frame = memory::paging::translate_page(page); - video::vga::text::newline(); - video::vga::text::write("Mapped physical frame: ", video::vga::text::common_attributes::green_on_black); - video::vga::text::write_number(optional_frame.value().frame_number, - video::vga::text::common_attributes::green_on_black); - video::vga::text::write(" to virtual page: ", video::vga::text::common_attributes::green_on_black); - video::vga::text::write_number(page.page_number, video::vga::text::common_attributes::green_on_black); - memory::paging::unmap_page(allocator, page); - video::vga::text::newline(); - video::vga::text::write("Unapped virtual page from physical frame: ", - video::vga::text::common_attributes::green_on_black); - optional_frame = memory::paging::translate_page(page); - exception_handling::assert(!optional_frame.has_value(), "[Main] Ummapping failed"); - video::vga::text::write_number(page.page_number, video::vga::text::common_attributes::green_on_black); + memory::paging::temporary_page temp_page{page, allocator}; + temp_page.zero_entries(); + + // memory::paging::map_next_free_page_to_frame(allocator, page, 0U); + // auto optional_frame = memory::paging::translate_page(page); + // video::vga::text::newline(); + // video::vga::text::write("Mapped physical frame: ", video::vga::text::common_attributes::green_on_black); + // video::vga::text::write_number(optional_frame.value().frame_number, + // video::vga::text::common_attributes::green_on_black); + // video::vga::text::write(" to virtual page: ", video::vga::text::common_attributes::green_on_black); + // video::vga::text::write_number(page.page_number, video::vga::text::common_attributes::green_on_black); + + // memory::paging::unmap_page(allocator, page); + // video::vga::text::newline(); + // video::vga::text::write("Unapped virtual page from physical frame: ", + // video::vga::text::common_attributes::green_on_black); + // optional_frame = memory::paging::translate_page(page); + // exception_handling::assert(!optional_frame.has_value(), "[Main] Ummapping failed"); + // video::vga::text::write_number(page.page_number, video::vga::text::common_attributes::green_on_black); auto last_allocated = allocator.allocate_frame(); auto allocated = last_allocated; diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 3ad1d54..3c9942a 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -88,33 +88,33 @@ namespace teachos::arch::memory::paging return std::nullopt; } - page_table_handle::page_table_handle(page_table * handle, page_table_handle::level handle_level) - : handle(handle) - , handle_level(handle_level) + page_table_handle::page_table_handle(page_table * table, page_table_handle::level table_level) + : table(table) + , table_level(table_level) { - exception_handling::assert(handle != nullptr, - "[Page Table] Attempted to pass nullptr as handle to page table handle method"); + 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 { handle->zero_entries(); } + auto page_table_handle::zero_entries() -> void { table->zero_entries(); } - auto page_table_handle::is_empty() const -> bool { return handle->is_empty(); } + auto page_table_handle::is_empty() const -> bool { return table->is_empty(); } auto page_table_handle::next_table(std::size_t table_index) -> std::optional { - exception_handling::assert(handle_level != page_table_handle::LEVEL1, + 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 = handle->next_table(table_index); + auto const next_table = table->next_table(table_index); if (next_table.has_value()) { - return page_table_handle{next_table.value(), --handle_level}; + return page_table_handle{next_table.value(), --table_level}; } return std::nullopt; } - auto page_table_handle::get_level() const -> page_table_handle::level { return handle_level; } + 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 handle->operator[](index); } + 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 & { diff --git a/arch/x86_64/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp new file mode 100644 index 0000000..433f0ce --- /dev/null +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -0,0 +1,35 @@ +#include "arch/memory/paging/temporary_page.hpp" + +#include "arch/memory/paging/page_entry.hpp" +#include "arch/memory/paging/page_mapper.hpp" + +namespace teachos::arch::memory::paging +{ + auto temporary_page::map_to_frame(allocator::physical_frame frame) -> virtual_address + { + exception_handling::assert(!translate_page(page).has_value(), "[Temporary page] Page is already mapped"); + + map_page_to_frame(allocator, page, frame, entry::WRITABLE); + return page.start_address(); + } + + auto temporary_page::unmap() -> void { unmap_page(allocator, page); } + + auto temporary_page::map_table_frame(allocator::physical_frame frame) -> page_table_handle + { + page_table_handle handle{reinterpret_cast(map_to_frame(frame)), page_table_handle::LEVEL1}; + return handle; + } + + auto temporary_page::zero_entries() -> void + { + auto frame = allocator.allocate_frame(); + exception_handling::assert(!frame.has_value(), "[Temporary Page] Tiny allocator could not allocate a frame"); + + page_table_handle handle = map_table_frame(frame.value()); + handle.zero_entries(); + handle[511].set_entry(frame.value(), entry::PRESENT | entry::WRITABLE); + + unmap(); + } +} // namespace teachos::arch::memory::paging \ No newline at end of file -- cgit v1.2.3 From defb727b2d0ac902e10e9736440779495b8b51a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 1 Nov 2024 12:56:22 +0000 Subject: Move methods into seperate class. --- .../include/arch/memory/paging/page_mapper.hpp | 314 +++++++++++---------- arch/x86_64/src/memory/paging/page_mapper.cpp | 21 +- 2 files changed, 184 insertions(+), 151 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp index 26b8171..20d9afc 100644 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp @@ -11,8 +11,173 @@ namespace teachos::arch::memory::paging { - namespace + /** + * @brief Currently active level 4 page table, is used to ensure there is only ever one valid instance and it cannot + * be copied or constructed again. + */ + struct active_page_table { + /** + * @brief Creates a single instance of an active level 4 page table table and returns the created instance or + * alternatively returns the previously created instance instead. The instance is owned by this method and is + * static, meaning it lives on for the complete lifetime of the program. + * + * @return Active single unique instance of the level 4 page table. + */ + static auto create_or_get() -> active_page_table &; + + /** + * @brief Translates virtual address into corresponding physical address. Calls translate_page under the hood. + * + * @param address Virtual address we want to translate into physical one. + * @return Physical address corresponding to the provided virtual address. + */ + auto translate_address(virtual_address address) -> std::optional; + + /** + * @brief Translates page into physical frame, will first attempt to parse normally using default page size and if + * it failed attempt to parse using huge pages. + * + * @param page Page to translate into physical frame. + * @return Physical frame corresponding to the provided virtual page. + */ + auto translate_page(virtual_page page) -> std::optional; + + /** + * @brief Translates huge page into actual physical frame. + * + * @param page Page to translate into physical frame. + * @return Physical frame corresponding to the provided virtual page. + */ + auto translate_huge_page(virtual_page page) -> std::optional; + + /** + * @brief Maps a virtual page to a physical frame in the page table with the specified flags. + * + * @note Allocates and maps an entry in every page level if it does not exists yet down to level 1. If the level 1 + * page table already exists it halts execution instead. + * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. + * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate + * entries when a new page table is required. + * @param page Virtual page that is being mapped. + * @param frame Physical frame that the virtual page will be mapped to. + * @param flags A bitset of flags that configure the page table entry for this mapping. + */ + template + auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, + std::bitset<64U> flags) -> void + { + auto current_handle = active_handle; + + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) + { + current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level)); + } + + auto & level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; + arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), + "[Page Mapper] Unable to map huge pages"); + arch::exception_handling::assert(level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); + level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT); + } + + /** + * @brief Allocates the next free frame and then uses that frame to call map_page_to_frame. + * + * @see map_page_to_frame + */ + template + auto map_next_free_page_to_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void + { + auto const frame = allocator.allocate_frame(); + exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); + map_page_to_frame(allocator, page, frame.value(), flags); + } + + /** + * @brief Gets the corresponding page the given frame has to be contained in and uses that to call + * map_page_to_frame. + * + * @see map_page_to_frame + */ + template + auto identity_map(T & allocator, allocator::physical_frame frame, std::bitset<64U> flags) -> void + { + auto const page = virtual_page::containing_address(frame.start_address()); + map_page_to_frame(allocator, page, frame, flags); + } + + /** + * @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags. + * + * @note Deallocates and unmaps the entry in every page level if this page was the last one up to level 4 and + * ensures to clear the Translation Lookaside Buffer, so that the unmapped value is removed from cache as well. + * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. + * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate + * entries when a new page table is required. + * @param page Virtual page that is being unmapped. + */ + template + auto unmap_page(T & allocator, virtual_page page) -> void + { + exception_handling::assert(translate_page(page).has_value(), + "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); + + auto current_handle = active_handle; + std::array handles{current_handle, current_handle, current_handle, current_handle}; + + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) + { + auto const level_index = page.get_level_index(level); + auto const next_handle = current_handle.next_table(level_index); + // The next table method failed even tough the page has to be mapped already, because translate_page did not + // fail. This can only mean that we attempted to unmap a huge page, which is not supported in the first place. + exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); + current_handle = next_handle.value(); + // The level is used as the index, because it ensures the first level is the lowest one and then the remaining + // levels in ascending order. This is required, because we first have to clear the Level 1 page entry to check + // if the Level 1 page is now empty, to clear the Level 2 page entry, which will then also check if the Level 2 + // page is empty and clear the Level 3 page entry and so on. + handles.at(level - 1U) = current_handle; + } + + // Unmaps all entries starting from the Level 1 page table, and unmaps higher levels as well if that entry was the + // last one. We check if it was the last one using is empty on the page table handle, when we have removed the + // page to be unmapped. + for (auto & handle : handles) + { + unmap_page_table_entry(allocator, page, handle); + if (!handle.is_empty()) + { + break; + } + } + invalidate_page_cache(page.start_address()); + } + + private: + /** + * @brief Private constructor should only be used by create or get method, which ensures to create only ever one + * instance. + * + * @param active_handle Handle to the underlying currently active level 4 page table. + */ + active_page_table(page_table_handle active_handle); + + /** + * @brief Deleted copy constructor. + */ + active_page_table(active_page_table const &) = delete; + + /** + * @brief Deleted copy assignment operator. + */ + active_page_table & operator=(active_page_table const &) = delete; + /** * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. @@ -20,7 +185,7 @@ namespace teachos::arch::memory::paging * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for * that page. */ - auto invalidate_page_cache(virtual_address address) -> void + static auto invalidate_page_cache(virtual_address address) -> void { asm volatile("invlpg (%0)" ::"r"(address) : "memory"); } @@ -36,7 +201,7 @@ namespace teachos::arch::memory::paging * @param handle Page Table handle we want to access the entry that should be cleared on. */ template - auto unmap_page_table_entry(T & allocator, virtual_page page, page_table_handle & handle) -> void + static auto unmap_page_table_entry(T & allocator, virtual_page page, page_table_handle & handle) -> void { auto level_index = page.get_level_index(handle.get_level()); auto & entry = handle[level_index]; @@ -46,148 +211,9 @@ namespace teachos::arch::memory::paging entry.set_unused(); allocator.deallocate_frame(frame.value()); } - } // namespace - - /** - * @brief Creates a single instance of the level 4 page table table and returns handle to it or alternatively returns - * the previously created handle instead. The instance is owned by this method and is static, meaning it lives on for - * the complete lifetime of the program. - * - * @return Handle to the single unique instance of the level 4 page table. - */ - auto create_or_get() -> page_table_handle; - - /** - * @brief Translates virtual address into corresponding physical address. Calls translate_page under the hood. - * - * @param address Virtual address we want to translate into physical one. - * @return Physical address corresponding to the provided virtual address. - */ - auto translate_address(virtual_address address) -> std::optional; - - /** - * @brief Translates page into physical frame, will first attempt to parse normally using default page size and if - * it failed attempt to parse using huge pages. - * - * @param page Page to translate into physical frame. - * @return Physical frame corresponding to the provided virtual page. - */ - auto translate_page(virtual_page page) -> std::optional; - - /** - * @brief Translates huge page into actual physical frame. - * - * @param page Page to translate into physical frame. - * @return Physical frame corresponding to the provided virtual page. - */ - auto translate_huge_page(virtual_page page) -> std::optional; - - /** - * @brief Maps a virtual page to a physical frame in the page table with the specified flags. - * - * @note Allocates and maps an entry in every page level if it does not exists yet down to level 1. If the level 1 - * page table already exists it halts execution instead. - * - * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and - * deallocate method. - * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate entries - * when a new page table is required. - * @param page Virtual page that is being mapped. - * @param frame Physical frame that the virtual page will be mapped to. - * @param flags A bitset of flags that configure the page table entry for this mapping. - */ - template - auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, - std::bitset<64U> flags) -> void - { - auto current_handle = create_or_get(); - - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) - { - current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level)); - } - auto & level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; - arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), - "[Page Mapper] Unable to map huge pages"); - arch::exception_handling::assert(level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); - level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT); - } - - /** - * @brief Allocates the next free frame and then uses that frame to call map_page_to_frame. - * - * @see map_page_to_frame - */ - template - auto map_next_free_page_to_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void - { - auto const frame = allocator.allocate_frame(); - exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); - map_page_to_frame(allocator, page, frame.value(), flags); - } - - /** - * @brief Gets the corresponding page the given frame has to be contained in and uses that to call map_page_to_frame. - * - * @see map_page_to_frame - */ - template - auto identity_map(T & allocator, allocator::physical_frame frame, std::bitset<64U> flags) -> void - { - auto const page = virtual_page::containing_address(frame.start_address()); - map_page_to_frame(allocator, page, frame, flags); - } - - /** - * @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags. - * - * @note Deallocates and unmaps the entry in every page level if this page was the last one up to level 4 and ensures - * to clear the Translation Lookaside Buffer, so that the unmapped value is removed from cache as well. - * - * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and - * deallocate method. - * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate entries - * when a new page table is required. - * @param page Virtual page that is being unmapped. - */ - template - auto unmap_page(T & allocator, virtual_page page) -> void - { - exception_handling::assert(translate_page(page).has_value(), - "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); - - auto current_handle = create_or_get(); - std::array handles{current_handle, current_handle, current_handle, current_handle}; - - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) - { - auto const level_index = page.get_level_index(level); - auto const next_handle = current_handle.next_table(level_index); - // The next table method failed even tough the page has to be mapped already, because translate_page did not fail. - // This can only mean that we attempted to unmap a huge page, which is not supported in the first place. - exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); - current_handle = next_handle.value(); - // The level is used as the index, because it ensures the first level is the lowest one and then the remaining - // levels in ascending order. This is required, because we first have to clear the Level 1 page entry to check if - // the Level 1 page is now empty, to clear the Level 2 page entry, which will then also check if the Level 2 page - // is empty and clear the Level 3 page entry and so on. - handles.at(level - 1U) = current_handle; - } - - // Unmaps all entries starting from the Level 1 page table, and unmaps higher levels as well if that entry was the - // last one. We check if it was the last one using is empty on the page table handle, when we have removed the page - // to be unmapped. - for (auto & handle : handles) - { - unmap_page_table_entry(allocator, page, handle); - if (!handle.is_empty()) - { - break; - } - } - invalidate_page_cache(page.start_address()); - } + page_table_handle active_handle; + }; } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp index 2f2ee6a..30055e8 100644 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ b/arch/x86_64/src/memory/paging/page_mapper.cpp @@ -7,14 +7,15 @@ namespace teachos::arch::memory::paging std::size_t constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; } // namespace - auto create_or_get() -> page_table_handle + 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}; - return active_handle; + static active_page_table active_page{active_handle}; + return active_page; } - auto translate_address(virtual_address address) -> std::optional + 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); @@ -28,9 +29,9 @@ namespace teachos::arch::memory::paging return std::nullopt; } - auto translate_page(virtual_page page) -> std::optional + auto active_page_table::translate_page(virtual_page page) -> std::optional { - auto current_handle = create_or_get(); + auto current_handle = active_handle; for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) { @@ -49,9 +50,9 @@ namespace teachos::arch::memory::paging return level1_entry.calculate_pointed_to_frame(); } - auto translate_huge_page(virtual_page page) -> std::optional + auto active_page_table::translate_huge_page(virtual_page page) -> std::optional { - auto current_handle = create_or_get(); + 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()) @@ -86,4 +87,10 @@ namespace teachos::arch::memory::paging } 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 -- cgit v1.2.3 From b0d917bc8ad95e282f25949c489dfc1c06b91b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 1 Nov 2024 13:02:14 +0000 Subject: Adjust temporary page to changes --- .../include/arch/memory/paging/temporary_page.hpp | 10 ++++----- arch/x86_64/src/kernel/main.cpp | 3 ++- arch/x86_64/src/memory/paging/temporary_page.cpp | 25 ++++++++++++---------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp index ae806c8..0293dd9 100644 --- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -3,12 +3,12 @@ #include "arch/memory/allocator/physical_frame.hpp" #include "arch/memory/allocator/tiny_frame_allocator.hpp" +#include "arch/memory/paging/page_mapper.hpp" #include "arch/memory/paging/page_table.hpp" #include "arch/memory/paging/virtual_page.hpp" namespace teachos::arch::memory::paging { - /** * @brief * @@ -35,7 +35,7 @@ namespace teachos::arch::memory::paging * * @param frame */ - auto zero_entries() -> void; + auto zero_entries(active_page_table & active_table) -> void; private: /** @@ -44,13 +44,13 @@ namespace teachos::arch::memory::paging * @param frame * @return virtual_address */ - auto map_to_frame(allocator::physical_frame frame) -> virtual_address; + auto map_to_frame(allocator::physical_frame frame, active_page_table & active_table) -> virtual_address; /** * @brief * */ - auto unmap() -> void; + auto unmap(active_page_table & active_table) -> void; /** * @brief @@ -58,7 +58,7 @@ namespace teachos::arch::memory::paging * @param frame * @return page_table_handle */ - auto map_table_frame(allocator::physical_frame frame) -> page_table_handle; + auto map_table_frame(allocator::physical_frame frame, active_page_table & active_table) -> page_table_handle; virtual_page page; allocator::tiny_frame_allocator allocator; diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index a27631f..22335d1 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -24,8 +24,9 @@ namespace teachos::arch::kernel memory::allocator::PAGE_FRAME_SIZE; // 42th P3 entry auto const page = memory::paging::virtual_page::containing_address(address); + auto & active_table = memory::paging::active_page_table::create_or_get(); memory::paging::temporary_page temp_page{page, allocator}; - temp_page.zero_entries(); + temp_page.zero_entries(active_table); // memory::paging::map_next_free_page_to_frame(allocator, page, 0U); // auto optional_frame = memory::paging::translate_page(page); diff --git a/arch/x86_64/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp index 433f0ce..4a8f4da 100644 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -1,35 +1,38 @@ #include "arch/memory/paging/temporary_page.hpp" #include "arch/memory/paging/page_entry.hpp" -#include "arch/memory/paging/page_mapper.hpp" namespace teachos::arch::memory::paging { - auto temporary_page::map_to_frame(allocator::physical_frame frame) -> virtual_address + auto temporary_page::map_to_frame(allocator::physical_frame frame, + active_page_table & active_table) -> virtual_address { - exception_handling::assert(!translate_page(page).has_value(), "[Temporary page] Page is already mapped"); + exception_handling::assert(!active_table.translate_page(page).has_value(), + "[Temporary page] Page is already mapped"); - map_page_to_frame(allocator, page, frame, entry::WRITABLE); + active_table.map_page_to_frame(allocator, page, frame, entry::WRITABLE); return page.start_address(); } - auto temporary_page::unmap() -> void { unmap_page(allocator, page); } + auto temporary_page::unmap(active_page_table & active_table) -> void { active_table.unmap_page(allocator, page); } - auto temporary_page::map_table_frame(allocator::physical_frame frame) -> page_table_handle + 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)), page_table_handle::LEVEL1}; + page_table_handle handle{reinterpret_cast(map_to_frame(frame, active_table)), + page_table_handle::LEVEL1}; return handle; } - auto temporary_page::zero_entries() -> void + auto temporary_page::zero_entries(active_page_table & active_table) -> void { auto frame = allocator.allocate_frame(); exception_handling::assert(!frame.has_value(), "[Temporary Page] Tiny allocator could not allocate a frame"); - page_table_handle handle = map_table_frame(frame.value()); + page_table_handle handle = map_table_frame(frame.value(), active_table); handle.zero_entries(); handle[511].set_entry(frame.value(), entry::PRESENT | entry::WRITABLE); - unmap(); + unmap(active_table); } -} // namespace teachos::arch::memory::paging \ No newline at end of file +} // namespace teachos::arch::memory::paging -- cgit v1.2.3 From b38ce5e24222ec97b45e1f87da4a392859947064 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Fri, 1 Nov 2024 13:16:13 +0000 Subject: add doxygen comments --- .../include/arch/memory/allocator/concept.hpp | 5 ++++ .../include/arch/memory/paging/temporary_page.hpp | 30 ++++++++++++---------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/arch/x86_64/include/arch/memory/allocator/concept.hpp b/arch/x86_64/include/arch/memory/allocator/concept.hpp index 0aa45c6..4a7ab72 100644 --- a/arch/x86_64/include/arch/memory/allocator/concept.hpp +++ b/arch/x86_64/include/arch/memory/allocator/concept.hpp @@ -7,6 +7,11 @@ namespace teachos::arch::memory::allocator { + /** + * @brief Frame allocator concept + * + * @tparam T + */ template concept FrameAllocator = requires(T t, physical_frame a) { { t.allocate_frame() } -> std::same_as>; diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp index 0293dd9..c42745a 100644 --- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -10,17 +10,16 @@ namespace teachos::arch::memory::paging { /** - * @brief - * + * @brief A temporary page used to remap the kernel. */ struct temporary_page { /** * @brief Construct a new temporary page object * - * @tparam T - * @param page - * @param allocator + * @tparam FrameAllocator concept + * @param page Page to turn into temporary page + * @param allocator Frame allocator used to fill page */ template temporary_page(virtual_page page, T & allocator) @@ -31,32 +30,35 @@ namespace teachos::arch::memory::paging } /** - * @brief + * @brief Set all page table entries to unused. * - * @param frame + * @param active_table the page table whose values are set to unused. */ auto zero_entries(active_page_table & active_table) -> void; private: /** - * @brief + * @brief Map the temporary page to a frame. * - * @param frame - * @return virtual_address + * @param frame The frame to which the page is mapped. + * @param active_table The current active page table. + * @return The virtual address of the page. */ auto map_to_frame(allocator::physical_frame frame, active_page_table & active_table) -> virtual_address; /** - * @brief + * @brief Unmap the current page. * + * @param active_table The current active page table. */ auto unmap(active_page_table & active_table) -> void; /** - * @brief + * @brief Map the temporary page to a frame. * - * @param frame - * @return page_table_handle + * @param frame The frame to which the page is mapped. + * @param active_table The current active page table. + * @return level1 page table handle containing the mapped page. */ auto map_table_frame(allocator::physical_frame frame, active_page_table & active_table) -> page_table_handle; -- cgit v1.2.3 From 31e1ac359eb4b84bdd81f768b2de327193976a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 1 Nov 2024 13:22:02 +0000 Subject: Remove static page mapper and replace with unique active and inactive page table classes. --- arch/x86_64/CMakeLists.txt | 3 +- .../arch/memory/allocator/tiny_frame_allocator.hpp | 10 +- .../arch/memory/paging/active_page_table.hpp | 218 ++++++++++++++++++++ .../arch/memory/paging/inactive_page_table.hpp | 15 ++ .../include/arch/memory/paging/page_mapper.hpp | 219 --------------------- .../include/arch/memory/paging/temporary_page.hpp | 2 +- arch/x86_64/src/kernel/main.cpp | 2 +- .../x86_64/src/memory/paging/active_page_table.cpp | 96 +++++++++ .../src/memory/paging/inactive_page_table.cpp | 5 + arch/x86_64/src/memory/paging/page_mapper.cpp | 96 --------- arch/x86_64/src/memory/paging/temporary_page.cpp | 2 +- 11 files changed, 340 insertions(+), 328 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/paging/active_page_table.hpp create mode 100644 arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp delete mode 100644 arch/x86_64/include/arch/memory/paging/page_mapper.hpp create mode 100644 arch/x86_64/src/memory/paging/active_page_table.cpp create mode 100644 arch/x86_64/src/memory/paging/inactive_page_table.cpp delete mode 100644 arch/x86_64/src/memory/paging/page_mapper.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 8d64985..a97abaa 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -50,7 +50,8 @@ target_sources("_memory" PRIVATE "src/memory/paging/page_table.cpp" "src/memory/paging/temporary_page.cpp" "src/memory/paging/virtual_page.cpp" - "src/memory/paging/page_mapper.cpp" + "src/memory/paging/active_page_table.cpp" + "src/memory/paging/inactive_page_table.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp index 4bcec1c..e55b376 100644 --- a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -23,16 +23,8 @@ namespace teachos::arch::memory::allocator * entries *when a new page table is required. */ tiny_frame_allocator(area_frame_allocator & allocator) - : frames{} + : frames{allocator.allocate_frame(), allocator.allocate_frame(), allocator.allocate_frame()} { - for (auto & frame : frames) - { - auto temp_frame = allocator.allocate_frame(); - if (temp_frame.has_value()) - { - frame.emplace(temp_frame.value()); - } - } // Nothing to do } diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp new file mode 100644 index 0000000..8011ee0 --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -0,0 +1,218 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP + +#include "arch/exception_handling/assert.hpp" +#include "arch/memory/allocator/concept.hpp" +#include "arch/memory/paging/virtual_page.hpp" + +#include +#include + +namespace teachos::arch::memory::paging +{ + /** + * @brief Currently active level 4 page table, is used to ensure there is only ever one valid instance and it cannot + * be copied or constructed again. + */ + struct active_page_table + { + /** + * @brief Creates a single instance of an active level 4 page table table and returns the created instance or + * alternatively returns the previously created instance instead. The instance is owned by this method and is + * static, meaning it lives on for the complete lifetime of the program. + * + * @return Active single unique instance of the level 4 page table. + */ + static auto create_or_get() -> active_page_table &; + + /** + * @brief Translates virtual address into corresponding physical address. Calls translate_page under the hood. + * + * @param address Virtual address we want to translate into physical one. + * @return Physical address corresponding to the provided virtual address. + */ + auto translate_address(virtual_address address) -> std::optional; + + /** + * @brief Translates page into physical frame, will first attempt to parse normally using default page size and if + * it failed attempt to parse using huge pages. + * + * @param page Page to translate into physical frame. + * @return Physical frame corresponding to the provided virtual page. + */ + auto translate_page(virtual_page page) -> std::optional; + + /** + * @brief Translates huge page into actual physical frame. + * + * @param page Page to translate into physical frame. + * @return Physical frame corresponding to the provided virtual page. + */ + auto translate_huge_page(virtual_page page) -> std::optional; + + /** + * @brief Maps a virtual page to a physical frame in the page table with the specified flags. + * + * @note Allocates and maps an entry in every page level if it does not exists yet down to level 1. If the level 1 + * page table already exists it halts execution instead. + * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. + * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate + * entries when a new page table is required. + * @param page Virtual page that is being mapped. + * @param frame Physical frame that the virtual page will be mapped to. + * @param flags A bitset of flags that configure the page table entry for this mapping. + */ + template + auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, + std::bitset<64U> flags) -> void + { + auto current_handle = active_handle; + + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) + { + current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level)); + } + + auto & level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; + arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), + "[Page Mapper] Unable to map huge pages"); + arch::exception_handling::assert(level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); + level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT); + } + + /** + * @brief Allocates the next free frame and then uses that frame to call map_page_to_frame. + * + * @see map_page_to_frame + */ + template + auto map_next_free_page_to_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void + { + auto const frame = allocator.allocate_frame(); + exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); + map_page_to_frame(allocator, page, frame.value(), flags); + } + + /** + * @brief Gets the corresponding page the given frame has to be contained in and uses that to call + * map_page_to_frame. + * + * @see map_page_to_frame + */ + template + auto identity_map(T & allocator, allocator::physical_frame frame, std::bitset<64U> flags) -> void + { + auto const page = virtual_page::containing_address(frame.start_address()); + map_page_to_frame(allocator, page, frame, flags); + } + + /** + * @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags. + * + * @note Deallocates and unmaps the entry in every page level if this page was the last one up to level 4 and + * ensures to clear the Translation Lookaside Buffer, so that the unmapped value is removed from cache as well. + * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. + * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate + * entries when a new page table is required. + * @param page Virtual page that is being unmapped. + */ + template + auto unmap_page(T & allocator, virtual_page page) -> void + { + exception_handling::assert(translate_page(page).has_value(), + "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); + + auto current_handle = active_handle; + std::array handles{current_handle, current_handle, current_handle, current_handle}; + + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) + { + auto const level_index = page.get_level_index(level); + auto const next_handle = current_handle.next_table(level_index); + // The next table method failed even tough the page has to be mapped already, because translate_page did not + // fail. This can only mean that we attempted to unmap a huge page, which is not supported in the first place. + exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); + current_handle = next_handle.value(); + // The level is used as the index, because it ensures the first level is the lowest one and then the remaining + // levels in ascending order. This is required, because we first have to clear the Level 1 page entry to check + // if the Level 1 page is now empty, to clear the Level 2 page entry, which will then also check if the Level 2 + // page is empty and clear the Level 3 page entry and so on. + handles.at(level - 1U) = current_handle; + } + + // Unmaps all entries starting from the Level 1 page table, and unmaps higher levels as well if that entry was the + // last one. We check if it was the last one using is empty on the page table handle, when we have removed the + // page to be unmapped. + for (auto & handle : handles) + { + unmap_page_table_entry(allocator, page, handle); + if (!handle.is_empty()) + { + break; + } + } + invalidate_page_cache(page.start_address()); + } + + private: + /** + * @brief Private constructor should only be used by create or get method, which ensures to create only ever one + * instance. + * + * @param active_handle Handle to the underlying currently active level 4 page table. + */ + active_page_table(page_table_handle active_handle); + + /** + * @brief Deleted copy constructor. + */ + active_page_table(active_page_table const &) = delete; + + /** + * @brief Deleted copy assignment operator. + */ + active_page_table & operator=(active_page_table const &) = delete; + + /** + * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained + * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. + * + * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for + * that page. + */ + static auto invalidate_page_cache(virtual_address address) -> void + { + asm volatile("invlpg (%0)" ::"r"(address) : "memory"); + } + + /** + * @brief Unmaps specific page at the current internal handle level. + * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. + * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate + * entries *when a new page table is required. + * @param page Virtual page that is being unmapped. + * @param handle Page Table handle we want to access the entry that should be cleared on. + */ + template + static auto unmap_page_table_entry(T & allocator, virtual_page page, page_table_handle & handle) -> void + { + auto level_index = page.get_level_index(handle.get_level()); + auto & entry = handle[level_index]; + auto const frame = entry.calculate_pointed_to_frame(); + exception_handling::assert(frame.has_value(), + "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); + entry.set_unused(); + allocator.deallocate_frame(frame.value()); + } + + page_table_handle active_handle; + }; +} // namespace teachos::arch::memory::paging + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP diff --git a/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp new file mode 100644 index 0000000..4285fc2 --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp @@ -0,0 +1,15 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_INACTIVE_PAGE_TABLE_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_INACTIVE_PAGE_TABLE_HPP + +#include "arch/memory/allocator/physical_frame.hpp" + +namespace teachos::arch::memory::paging +{ + struct inactive_page_table + { + private: + allocator::physical_frame page_table_level_4_frame; + }; +} // namespace teachos::arch::memory::paging + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_INACTIVE_PAGE_TABLE_HPP diff --git a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp b/arch/x86_64/include/arch/memory/paging/page_mapper.hpp deleted file mode 100644 index 20d9afc..0000000 --- a/arch/x86_64/include/arch/memory/paging/page_mapper.hpp +++ /dev/null @@ -1,219 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP - -#include "arch/exception_handling/assert.hpp" -#include "arch/memory/allocator/concept.hpp" -#include "arch/memory/paging/virtual_page.hpp" - -#include -#include -#include - -namespace teachos::arch::memory::paging -{ - /** - * @brief Currently active level 4 page table, is used to ensure there is only ever one valid instance and it cannot - * be copied or constructed again. - */ - struct active_page_table - { - /** - * @brief Creates a single instance of an active level 4 page table table and returns the created instance or - * alternatively returns the previously created instance instead. The instance is owned by this method and is - * static, meaning it lives on for the complete lifetime of the program. - * - * @return Active single unique instance of the level 4 page table. - */ - static auto create_or_get() -> active_page_table &; - - /** - * @brief Translates virtual address into corresponding physical address. Calls translate_page under the hood. - * - * @param address Virtual address we want to translate into physical one. - * @return Physical address corresponding to the provided virtual address. - */ - auto translate_address(virtual_address address) -> std::optional; - - /** - * @brief Translates page into physical frame, will first attempt to parse normally using default page size and if - * it failed attempt to parse using huge pages. - * - * @param page Page to translate into physical frame. - * @return Physical frame corresponding to the provided virtual page. - */ - auto translate_page(virtual_page page) -> std::optional; - - /** - * @brief Translates huge page into actual physical frame. - * - * @param page Page to translate into physical frame. - * @return Physical frame corresponding to the provided virtual page. - */ - auto translate_huge_page(virtual_page page) -> std::optional; - - /** - * @brief Maps a virtual page to a physical frame in the page table with the specified flags. - * - * @note Allocates and maps an entry in every page level if it does not exists yet down to level 1. If the level 1 - * page table already exists it halts execution instead. - * - * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and - * deallocate method. - * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate - * entries when a new page table is required. - * @param page Virtual page that is being mapped. - * @param frame Physical frame that the virtual page will be mapped to. - * @param flags A bitset of flags that configure the page table entry for this mapping. - */ - template - auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, - std::bitset<64U> flags) -> void - { - auto current_handle = active_handle; - - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) - { - current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level)); - } - - auto & level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; - arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), - "[Page Mapper] Unable to map huge pages"); - arch::exception_handling::assert(level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); - level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT); - } - - /** - * @brief Allocates the next free frame and then uses that frame to call map_page_to_frame. - * - * @see map_page_to_frame - */ - template - auto map_next_free_page_to_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void - { - auto const frame = allocator.allocate_frame(); - exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); - map_page_to_frame(allocator, page, frame.value(), flags); - } - - /** - * @brief Gets the corresponding page the given frame has to be contained in and uses that to call - * map_page_to_frame. - * - * @see map_page_to_frame - */ - template - auto identity_map(T & allocator, allocator::physical_frame frame, std::bitset<64U> flags) -> void - { - auto const page = virtual_page::containing_address(frame.start_address()); - map_page_to_frame(allocator, page, frame, flags); - } - - /** - * @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags. - * - * @note Deallocates and unmaps the entry in every page level if this page was the last one up to level 4 and - * ensures to clear the Translation Lookaside Buffer, so that the unmapped value is removed from cache as well. - * - * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and - * deallocate method. - * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate - * entries when a new page table is required. - * @param page Virtual page that is being unmapped. - */ - template - auto unmap_page(T & allocator, virtual_page page) -> void - { - exception_handling::assert(translate_page(page).has_value(), - "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); - - auto current_handle = active_handle; - std::array handles{current_handle, current_handle, current_handle, current_handle}; - - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) - { - auto const level_index = page.get_level_index(level); - auto const next_handle = current_handle.next_table(level_index); - // The next table method failed even tough the page has to be mapped already, because translate_page did not - // fail. This can only mean that we attempted to unmap a huge page, which is not supported in the first place. - exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); - current_handle = next_handle.value(); - // The level is used as the index, because it ensures the first level is the lowest one and then the remaining - // levels in ascending order. This is required, because we first have to clear the Level 1 page entry to check - // if the Level 1 page is now empty, to clear the Level 2 page entry, which will then also check if the Level 2 - // page is empty and clear the Level 3 page entry and so on. - handles.at(level - 1U) = current_handle; - } - - // Unmaps all entries starting from the Level 1 page table, and unmaps higher levels as well if that entry was the - // last one. We check if it was the last one using is empty on the page table handle, when we have removed the - // page to be unmapped. - for (auto & handle : handles) - { - unmap_page_table_entry(allocator, page, handle); - if (!handle.is_empty()) - { - break; - } - } - invalidate_page_cache(page.start_address()); - } - - private: - /** - * @brief Private constructor should only be used by create or get method, which ensures to create only ever one - * instance. - * - * @param active_handle Handle to the underlying currently active level 4 page table. - */ - active_page_table(page_table_handle active_handle); - - /** - * @brief Deleted copy constructor. - */ - active_page_table(active_page_table const &) = delete; - - /** - * @brief Deleted copy assignment operator. - */ - active_page_table & operator=(active_page_table const &) = delete; - - /** - * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained - * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. - * - * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for - * that page. - */ - static auto invalidate_page_cache(virtual_address address) -> void - { - asm volatile("invlpg (%0)" ::"r"(address) : "memory"); - } - - /** - * @brief Unmaps specific page at the current internal handle level. - * - * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and - * deallocate method. - * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate - * entries *when a new page table is required. - * @param page Virtual page that is being unmapped. - * @param handle Page Table handle we want to access the entry that should be cleared on. - */ - template - static auto unmap_page_table_entry(T & allocator, virtual_page page, page_table_handle & handle) -> void - { - auto level_index = page.get_level_index(handle.get_level()); - auto & entry = handle[level_index]; - auto const frame = entry.calculate_pointed_to_frame(); - exception_handling::assert(frame.has_value(), - "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); - entry.set_unused(); - allocator.deallocate_frame(frame.value()); - } - - page_table_handle active_handle; - }; -} // namespace teachos::arch::memory::paging - -#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_MAPPER_HPP diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp index c42745a..b658f7a 100644 --- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -3,7 +3,7 @@ #include "arch/memory/allocator/physical_frame.hpp" #include "arch/memory/allocator/tiny_frame_allocator.hpp" -#include "arch/memory/paging/page_mapper.hpp" +#include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/page_table.hpp" #include "arch/memory/paging/virtual_page.hpp" diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 22335d1..f1d6496 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -3,7 +3,7 @@ #include "arch/exception_handling/assert.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/multiboot/reader.hpp" -#include "arch/memory/paging/page_mapper.hpp" +#include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/temporary_page.hpp" #include "arch/video/vga/text.hpp" diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp new file mode 100644 index 0000000..38696f8 --- /dev/null +++ b/arch/x86_64/src/memory/paging/active_page_table.cpp @@ -0,0 +1,96 @@ +#include "arch/memory/paging/active_page_table.hpp" + +namespace teachos::arch::memory::paging +{ + namespace + { + std::size_t constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; + } // namespace + + 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::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 new file mode 100644 index 0000000..1f36aa3 --- /dev/null +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -0,0 +1,5 @@ +#include "arch/memory/paging/inactive_page_table.hpp" + +namespace teachos::arch::memory::paging +{ +} // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/page_mapper.cpp b/arch/x86_64/src/memory/paging/page_mapper.cpp deleted file mode 100644 index 30055e8..0000000 --- a/arch/x86_64/src/memory/paging/page_mapper.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "arch/memory/paging/page_mapper.hpp" - -namespace teachos::arch::memory::paging -{ - namespace - { - std::size_t constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; - } // namespace - - 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::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/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp index 4a8f4da..180b4a8 100644 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -27,7 +27,7 @@ namespace teachos::arch::memory::paging auto temporary_page::zero_entries(active_page_table & active_table) -> void { auto frame = allocator.allocate_frame(); - exception_handling::assert(!frame.has_value(), "[Temporary Page] Tiny allocator could not allocate a frame"); + exception_handling::assert(frame.has_value(), "[Temporary Page] Tiny allocator could not allocate a frame"); page_table_handle handle = map_table_frame(frame.value(), active_table); handle.zero_entries(); -- cgit v1.2.3 From b9fdcc729c1875858297c0f3fb9d8e6feff71374 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Fri, 1 Nov 2024 14:29:58 +0000 Subject: implement temporary_page and update active/inactive page tables --- .../include/arch/memory/paging/active_page_table.hpp | 8 ++++++++ .../include/arch/memory/paging/inactive_page_table.hpp | 6 +++++- .../include/arch/memory/paging/temporary_page.hpp | 18 +++++++++--------- arch/x86_64/src/memory/paging/active_page_table.cpp | 10 ++++++++++ arch/x86_64/src/memory/paging/inactive_page_table.cpp | 10 ++++++++++ 5 files changed, 42 insertions(+), 10 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index 8011ee0..3fb2e65 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -3,6 +3,8 @@ #include "arch/exception_handling/assert.hpp" #include "arch/memory/allocator/concept.hpp" +#include "arch/memory/paging/inactive_page_table.hpp" +#include "arch/memory/paging/temporary_page.hpp" #include "arch/memory/paging/virtual_page.hpp" #include @@ -10,12 +12,15 @@ namespace teachos::arch::memory::paging { + /** * @brief Currently active level 4 page table, is used to ensure there is only ever one valid instance and it cannot * be copied or constructed again. */ struct active_page_table { + typedef void (*function)(active_page_table * active_page_table); + /** * @brief Creates a single instance of an active level 4 page table table and returns the created instance or * alternatively returns the previously created instance instead. The instance is owned by this method and is @@ -158,6 +163,8 @@ namespace teachos::arch::memory::paging invalidate_page_cache(page.start_address()); } + auto with(inactive_page_table inactive_page_table, temporary_page temporary_page, function f) -> void; + private: /** * @brief Private constructor should only be used by create or get method, which ensures to create only ever one @@ -213,6 +220,7 @@ namespace teachos::arch::memory::paging page_table_handle active_handle; }; + } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP diff --git a/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp index 4285fc2..62c196f 100644 --- a/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp @@ -2,12 +2,16 @@ #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_INACTIVE_PAGE_TABLE_HPP #include "arch/memory/allocator/physical_frame.hpp" +#include "arch/memory/paging/active_page_table.hpp" +#include "arch/memory/paging/temporary_page.hpp" namespace teachos::arch::memory::paging { struct inactive_page_table { - private: + inactive_page_table(allocator::physical_frame frame, active_page_table active_page_table, + temporary_page temporary_page); + allocator::physical_frame page_table_level_4_frame; }; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp index b658f7a..a7552dd 100644 --- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -36,31 +36,31 @@ namespace teachos::arch::memory::paging */ auto zero_entries(active_page_table & active_table) -> void; - private: /** - * @brief Map the temporary page to a frame. + * @brief Unmap the current page. * - * @param frame The frame to which the page is mapped. * @param active_table The current active page table. - * @return The virtual address of the page. */ - auto map_to_frame(allocator::physical_frame frame, active_page_table & active_table) -> virtual_address; + auto unmap(active_page_table & active_table) -> void; /** - * @brief Unmap the current page. + * @brief Map the temporary page to a frame. * + * @param frame The frame to which the page is mapped. * @param active_table The current active page table. + * @return level1 page table handle containing the mapped page. */ - auto unmap(active_page_table & active_table) -> void; + auto map_table_frame(allocator::physical_frame frame, active_page_table & active_table) -> page_table_handle; + private: /** * @brief Map the temporary page to a frame. * * @param frame The frame to which the page is mapped. * @param active_table The current active page table. - * @return level1 page table handle containing the mapped page. + * @return The virtual address of the page. */ - auto map_table_frame(allocator::physical_frame frame, active_page_table & active_table) -> page_table_handle; + auto map_to_frame(allocator::physical_frame frame, active_page_table & active_table) -> virtual_address; virtual_page page; allocator::tiny_frame_allocator allocator; diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp index 38696f8..5f31f75 100644 --- a/arch/x86_64/src/memory/paging/active_page_table.cpp +++ b/arch/x86_64/src/memory/paging/active_page_table.cpp @@ -93,4 +93,14 @@ namespace teachos::arch::memory::paging { // Nothing to do } + + auto active_page_table::with(inactive_page_table inactive_page_table, temporary_page temporary_page, + active_page_table::function f) -> void + { + active_handle[511].set_entry(inactive_page_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); + invalidate_page_cache(PAGE_TABLE_LEVEL_4_ADDRESS); + + f(*mapper); + } + } // 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 index 1f36aa3..afba1f0 100644 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -2,4 +2,14 @@ namespace teachos::arch::memory::paging { + 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(active_page_table); + } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 08875c9c42c94dd23b16baa70b2be60cf35eb253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 1 Nov 2024 14:53:31 +0000 Subject: Fix circular dependency issue --- arch/x86_64/CMakeLists.txt | 1 + .../include/arch/memory/paging/active_page_table.hpp | 4 ---- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 14 ++++++++++++++ arch/x86_64/include/arch/memory/paging/temporary_page.hpp | 1 - arch/x86_64/src/kernel/main.cpp | 1 - arch/x86_64/src/memory/paging/active_page_table.cpp | 10 ---------- arch/x86_64/src/memory/paging/kernel_mapper.cpp | 13 +++++++++++++ 7 files changed, 28 insertions(+), 16 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp create mode 100644 arch/x86_64/src/memory/paging/kernel_mapper.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index a97abaa..22f9ad4 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -52,6 +52,7 @@ target_sources("_memory" PRIVATE "src/memory/paging/virtual_page.cpp" "src/memory/paging/active_page_table.cpp" "src/memory/paging/inactive_page_table.cpp" + "src/memory/paging/kernel_mapper.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index 3fb2e65..e876798 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -3,8 +3,6 @@ #include "arch/exception_handling/assert.hpp" #include "arch/memory/allocator/concept.hpp" -#include "arch/memory/paging/inactive_page_table.hpp" -#include "arch/memory/paging/temporary_page.hpp" #include "arch/memory/paging/virtual_page.hpp" #include @@ -163,8 +161,6 @@ namespace teachos::arch::memory::paging invalidate_page_cache(page.start_address()); } - auto with(inactive_page_table inactive_page_table, temporary_page temporary_page, function f) -> void; - private: /** * @brief Private constructor should only be used by create or get method, which ensures to create only ever one diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp new file mode 100644 index 0000000..085344a --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -0,0 +1,14 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP + +#include "arch/memory/paging/active_page_table.hpp" +#include "arch/memory/paging/inactive_page_table.hpp" +#include "arch/memory/paging/temporary_page.hpp" + +namespace teachos::arch::memory::paging +{ + auto with(inactive_page_table inactive_page_table, temporary_page temporary_page, active_page_table::function f, + active_page_table & active_page_table) -> void; +} // namespace teachos::arch::memory::paging + +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp index a7552dd..0cadc29 100644 --- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -4,7 +4,6 @@ #include "arch/memory/allocator/physical_frame.hpp" #include "arch/memory/allocator/tiny_frame_allocator.hpp" #include "arch/memory/paging/active_page_table.hpp" -#include "arch/memory/paging/page_table.hpp" #include "arch/memory/paging/virtual_page.hpp" namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index f1d6496..c89ae44 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -3,7 +3,6 @@ #include "arch/exception_handling/assert.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/multiboot/reader.hpp" -#include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/temporary_page.hpp" #include "arch/video/vga/text.hpp" diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp index 5f31f75..38696f8 100644 --- a/arch/x86_64/src/memory/paging/active_page_table.cpp +++ b/arch/x86_64/src/memory/paging/active_page_table.cpp @@ -93,14 +93,4 @@ namespace teachos::arch::memory::paging { // Nothing to do } - - auto active_page_table::with(inactive_page_table inactive_page_table, temporary_page temporary_page, - active_page_table::function f) -> void - { - active_handle[511].set_entry(inactive_page_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); - invalidate_page_cache(PAGE_TABLE_LEVEL_4_ADDRESS); - - f(*mapper); - } - } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/kernel_mapper.cpp b/arch/x86_64/src/memory/paging/kernel_mapper.cpp new file mode 100644 index 0000000..9dfc5ad --- /dev/null +++ b/arch/x86_64/src/memory/paging/kernel_mapper.cpp @@ -0,0 +1,13 @@ +#include "arch/memory/paging/kernel_mapper.hpp" + +namespace teachos::arch::memory::paging +{ + auto with(inactive_page_table inactive_page_table, temporary_page temporary_page, + active_page_table::function f) -> void + { + /*active_handle[511].set_entry(inactive_page_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); + invalidate_page_cache(PAGE_TABLE_LEVEL_4_ADDRESS); + + f(*this);*/ + } +} // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 86f19267c7ca4e14ac6169f758130b3c27e62cdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 1 Nov 2024 15:10:30 +0000 Subject: Resolve compilation issues --- .../arch/memory/paging/active_page_table.hpp | 27 +++++++++++----------- .../include/arch/memory/paging/kernel_mapper.hpp | 12 ++++++++-- .../x86_64/src/memory/paging/active_page_table.cpp | 5 ---- arch/x86_64/src/memory/paging/kernel_mapper.cpp | 17 ++++++++++---- 4 files changed, 36 insertions(+), 25 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index e876798..e2c205b 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -10,6 +10,7 @@ namespace teachos::arch::memory::paging { + std::size_t constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; /** * @brief Currently active level 4 page table, is used to ensure there is only ever one valid instance and it cannot @@ -17,7 +18,7 @@ namespace teachos::arch::memory::paging */ struct active_page_table { - typedef void (*function)(active_page_table * active_page_table); + typedef void (*function)(active_page_table & active_page_table); /** * @brief Creates a single instance of an active level 4 page table table and returns the created instance or @@ -53,6 +54,18 @@ namespace teachos::arch::memory::paging */ auto translate_huge_page(virtual_page page) -> std::optional; + /** + * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained + * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. + * + * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for + * that page. + */ + static auto invalidate_page_cache(virtual_address address) -> void + { + asm volatile("invlpg (%0)" ::"r"(address) : "memory"); + } + /** * @brief Maps a virtual page to a physical frame in the page table with the specified flags. * @@ -180,18 +193,6 @@ namespace teachos::arch::memory::paging */ active_page_table & operator=(active_page_table const &) = delete; - /** - * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained - * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. - * - * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for - * that page. - */ - static auto invalidate_page_cache(virtual_address address) -> void - { - asm volatile("invlpg (%0)" ::"r"(address) : "memory"); - } - /** * @brief Unmaps specific page at the current internal handle level. * diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 085344a..0583692 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -7,8 +7,16 @@ namespace teachos::arch::memory::paging { - auto with(inactive_page_table inactive_page_table, temporary_page temporary_page, active_page_table::function f, - active_page_table & active_page_table) -> void; + struct kernel_mapper + { + kernel_mapper(active_page_table & active_table); + + auto with(inactive_page_table inactive_page_table, temporary_page temporary_page, + active_page_table::function f) -> void; + + private: + active_page_table & active_table; + }; } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp index 38696f8..844ae37 100644 --- a/arch/x86_64/src/memory/paging/active_page_table.cpp +++ b/arch/x86_64/src/memory/paging/active_page_table.cpp @@ -2,11 +2,6 @@ namespace teachos::arch::memory::paging { - namespace - { - std::size_t constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; - } // namespace - auto active_page_table::create_or_get() -> active_page_table & { static page_table_handle active_handle{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS), diff --git a/arch/x86_64/src/memory/paging/kernel_mapper.cpp b/arch/x86_64/src/memory/paging/kernel_mapper.cpp index 9dfc5ad..59930fc 100644 --- a/arch/x86_64/src/memory/paging/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/paging/kernel_mapper.cpp @@ -2,12 +2,19 @@ namespace teachos::arch::memory::paging { - auto with(inactive_page_table inactive_page_table, temporary_page temporary_page, - active_page_table::function f) -> void + kernel_mapper::kernel_mapper(active_page_table & active_table) + : active_table(active_table) { - /*active_handle[511].set_entry(inactive_page_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); - invalidate_page_cache(PAGE_TABLE_LEVEL_4_ADDRESS); + // Nothing to do + } + + auto kernel_mapper::with(inactive_page_table inactive_page_table, temporary_page temporary_page, + active_page_table::function f) -> void + { + active_table.active_handle[511].set_entry(inactive_page_table.page_table_level_4_frame, + entry::PRESENT | entry::WRITABLE); + active_page_table::invalidate_page_cache(PAGE_TABLE_LEVEL_4_ADDRESS); - f(*this);*/ + f(active_table); } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 1dd691e54ab30b70550ae6197ab252ebd0f8b223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 1 Nov 2024 15:18:02 +0000 Subject: Make page table handle public --- arch/x86_64/include/arch/memory/paging/active_page_table.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index e2c205b..56e0632 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -174,6 +174,7 @@ namespace teachos::arch::memory::paging invalidate_page_cache(page.start_address()); } + page_table_handle active_handle; ///< Underlying active level 4 page table private: /** * @brief Private constructor should only be used by create or get method, which ensures to create only ever one @@ -214,8 +215,6 @@ namespace teachos::arch::memory::paging entry.set_unused(); allocator.deallocate_frame(frame.value()); } - - page_table_handle active_handle; }; } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 38cda6bf579f7b09d06ad73c9f4ab893939727a2 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Fri, 1 Nov 2024 15:32:24 +0000 Subject: extract tlb methods and finish implementation of with --- arch/x86_64/CMakeLists.txt | 1 + .../arch/memory/paging/active_page_table.hpp | 22 +++++------------- arch/x86_64/include/arch/memory/paging/tlb.hpp | 26 ++++++++++++++++++++++ arch/x86_64/src/memory/paging/kernel_mapper.cpp | 13 ++++++++++- arch/x86_64/src/memory/paging/tlb.cpp | 7 ++++++ 5 files changed, 51 insertions(+), 18 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/paging/tlb.hpp create mode 100644 arch/x86_64/src/memory/paging/tlb.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 22f9ad4..1f15c79 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -53,6 +53,7 @@ target_sources("_memory" PRIVATE "src/memory/paging/active_page_table.cpp" "src/memory/paging/inactive_page_table.cpp" "src/memory/paging/kernel_mapper.cpp" + "src/memory/paging/tlb.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index e2c205b..30ae455 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -3,6 +3,7 @@ #include "arch/exception_handling/assert.hpp" #include "arch/memory/allocator/concept.hpp" +#include "arch/memory/paging/tlb.hpp" #include "arch/memory/paging/virtual_page.hpp" #include @@ -10,8 +11,6 @@ namespace teachos::arch::memory::paging { - std::size_t constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; - /** * @brief Currently active level 4 page table, is used to ensure there is only ever one valid instance and it cannot * be copied or constructed again. @@ -54,18 +53,6 @@ namespace teachos::arch::memory::paging */ auto translate_huge_page(virtual_page page) -> std::optional; - /** - * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained - * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. - * - * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for - * that page. - */ - static auto invalidate_page_cache(virtual_address address) -> void - { - asm volatile("invlpg (%0)" ::"r"(address) : "memory"); - } - /** * @brief Maps a virtual page to a physical frame in the page table with the specified flags. * @@ -171,9 +158,12 @@ namespace teachos::arch::memory::paging break; } } - invalidate_page_cache(page.start_address()); + + tlb_flush(page.start_address()); } + page_table_handle active_handle; + private: /** * @brief Private constructor should only be used by create or get method, which ensures to create only ever one @@ -214,8 +204,6 @@ namespace teachos::arch::memory::paging entry.set_unused(); allocator.deallocate_frame(frame.value()); } - - page_table_handle active_handle; }; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/include/arch/memory/paging/tlb.hpp b/arch/x86_64/include/arch/memory/paging/tlb.hpp new file mode 100644 index 0000000..e74eb74 --- /dev/null +++ b/arch/x86_64/include/arch/memory/paging/tlb.hpp @@ -0,0 +1,26 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_TLB_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_TLB_HPP + +#include "arch/memory/paging/virtual_page.hpp" + +namespace teachos::arch::memory::paging +{ + std::size_t constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; + + /** + * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained + * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. + * + * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for + * that page. + */ + auto tlb_flush(virtual_address address) -> void; + + /** + * @brief Invalidates the translation lookaside buffer (TLB) entry for all page tables + */ + auto tlb_flush_all() -> void; + +} // namespace teachos::arch::memory::paging + +#endif \ No newline at end of file diff --git a/arch/x86_64/src/memory/paging/kernel_mapper.cpp b/arch/x86_64/src/memory/paging/kernel_mapper.cpp index 59930fc..07d55ff 100644 --- a/arch/x86_64/src/memory/paging/kernel_mapper.cpp +++ b/arch/x86_64/src/memory/paging/kernel_mapper.cpp @@ -1,5 +1,8 @@ #include "arch/memory/paging/kernel_mapper.hpp" +#include "arch/memory/allocator/physical_frame.hpp" +#include "arch/memory/paging/tlb.hpp" + namespace teachos::arch::memory::paging { kernel_mapper::kernel_mapper(active_page_table & active_table) @@ -11,10 +14,18 @@ namespace teachos::arch::memory::paging auto kernel_mapper::with(inactive_page_table inactive_page_table, temporary_page temporary_page, active_page_table::function f) -> void { + auto backup = allocator::physical_frame::containing_address(PAGE_TABLE_LEVEL_4_ADDRESS); + auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); + active_table.active_handle[511].set_entry(inactive_page_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); - active_page_table::invalidate_page_cache(PAGE_TABLE_LEVEL_4_ADDRESS); + tlb_flush_all(); f(active_table); + + page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); + tlb_flush_all(); + + temporary_page.unmap(active_table); } } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/paging/tlb.cpp b/arch/x86_64/src/memory/paging/tlb.cpp new file mode 100644 index 0000000..b3255e9 --- /dev/null +++ b/arch/x86_64/src/memory/paging/tlb.cpp @@ -0,0 +1,7 @@ +#include "arch/memory/paging/tlb.hpp" + +namespace teachos::arch::memory::paging +{ + auto tlb_flush(virtual_address address) -> void { asm volatile("invlpg (%0)" ::"r"(address) : "memory"); } + auto tlb_flush_all() -> void { flush(PAGE_TABLE_LEVEL_4_ADDRESS); } +} // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 54cdc10862d95ccaf70def277946625d8c721113 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Fri, 1 Nov 2024 15:33:02 +0000 Subject: add spacing --- arch/x86_64/include/arch/memory/paging/active_page_table.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index 83624a9..8e80b51 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -163,6 +163,7 @@ namespace teachos::arch::memory::paging } page_table_handle active_handle; ///< Underlying active level 4 page table + private: /** * @brief Private constructor should only be used by create or get method, which ensures to create only ever one -- cgit v1.2.3 From d488a0709c5a2701482130a3d9c972c0b468a1d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Fri, 1 Nov 2024 15:34:03 +0000 Subject: Fix typo --- arch/x86_64/include/arch/memory/paging/tlb.hpp | 2 +- arch/x86_64/src/memory/paging/tlb.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/tlb.hpp b/arch/x86_64/include/arch/memory/paging/tlb.hpp index e74eb74..1194720 100644 --- a/arch/x86_64/include/arch/memory/paging/tlb.hpp +++ b/arch/x86_64/include/arch/memory/paging/tlb.hpp @@ -23,4 +23,4 @@ namespace teachos::arch::memory::paging } // namespace teachos::arch::memory::paging -#endif \ No newline at end of file +#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_TLB_HPP diff --git a/arch/x86_64/src/memory/paging/tlb.cpp b/arch/x86_64/src/memory/paging/tlb.cpp index b3255e9..c1160dc 100644 --- a/arch/x86_64/src/memory/paging/tlb.cpp +++ b/arch/x86_64/src/memory/paging/tlb.cpp @@ -3,5 +3,5 @@ namespace teachos::arch::memory::paging { auto tlb_flush(virtual_address address) -> void { asm volatile("invlpg (%0)" ::"r"(address) : "memory"); } - auto tlb_flush_all() -> void { flush(PAGE_TABLE_LEVEL_4_ADDRESS); } + auto tlb_flush_all() -> void { tlb_flush(PAGE_TABLE_LEVEL_4_ADDRESS); } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 5ffe7d69545bf098efdd70f105a5df83304b211a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 2 Nov 2024 11:49:38 +0000 Subject: Add physical frame iterator and continue implementing kernel mapping. --- arch/x86_64/CMakeLists.txt | 1 - .../arch/memory/allocator/area_frame_allocator.hpp | 2 +- .../arch/memory/allocator/physical_frame.hpp | 128 ++++++++++++++++++++- .../include/arch/memory/multiboot/reader.hpp | 9 +- .../arch/memory/paging/active_page_table.hpp | 2 - .../arch/memory/paging/inactive_page_table.hpp | 2 +- .../include/arch/memory/paging/kernel_mapper.hpp | 73 +++++++++++- arch/x86_64/include/arch/shared/container.hpp | 12 +- .../include/arch/shared/random_access_iterator.hpp | 11 +- arch/x86_64/src/kernel/main.cpp | 4 + .../src/memory/allocator/area_frame_allocator.cpp | 2 +- .../x86_64/src/memory/allocator/physical_frame.cpp | 123 ++++++++++++++++++++ arch/x86_64/src/memory/multiboot/reader.cpp | 18 +-- .../src/memory/paging/inactive_page_table.cpp | 2 +- arch/x86_64/src/memory/paging/kernel_mapper.cpp | 31 ----- 15 files changed, 353 insertions(+), 67 deletions(-) delete mode 100644 arch/x86_64/src/memory/paging/kernel_mapper.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 1f15c79..42aa6ef 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -52,7 +52,6 @@ target_sources("_memory" PRIVATE "src/memory/paging/virtual_page.cpp" "src/memory/paging/active_page_table.cpp" "src/memory/paging/inactive_page_table.cpp" - "src/memory/paging/kernel_mapper.cpp" "src/memory/paging/tlb.cpp" ) diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp index 4b6c2d4..f2b77f8 100644 --- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -18,7 +18,7 @@ namespace teachos::arch::memory::allocator * * @param mem_info Structure containg all relevant information to map and allocate memory */ - area_frame_allocator(multiboot::memory_information mem_info); + area_frame_allocator(multiboot::memory_information const & mem_info); /** * @brief Allocate memory by finding and returning a free physical frame. diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp index 146e557..b95687c 100644 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace teachos::arch::memory::allocator { @@ -16,6 +17,11 @@ namespace teachos::arch::memory::allocator */ struct physical_frame { + /** + * @brief Defaulted constructor. + */ + physical_frame() = default; + /** * @brief Constructor. * @@ -48,8 +54,126 @@ namespace teachos::arch::memory::allocator */ auto operator<=>(const physical_frame & other) const -> std::partial_ordering = default; - std::size_t - frame_number; ///< Index number of the current physical frame, used to distinguish it from other frames. + std::size_t frame_number = + {}; ///< Index number of the current physical frame, used to distinguish it from other frames. + }; + + /** + * @brief Iterator for the frame number + */ + struct physical_frame_iterator + { + using iterator_category = std::random_access_iterator_tag; ///< Iterator category of this type. + using difference_type = std::ptrdiff_t; ///< Type when diving one instance of this iterator by another. + using value_type = physical_frame; ///< Underlying value pointed to by this iterator. + + /** + * @brief Defaulted constructor. + */ + physical_frame_iterator() = default; + + /** + * @brief Constructor. + * + * @param value Underlying value the iterator should point too + */ + explicit physical_frame_iterator(value_type value); + + /** + * @brief Dereferences the initally given pointer to its value. + * + * @return Reference to the value. + */ + auto operator*() -> value_type &; + + /** + * @brief Get underlying value, which is the intially passed pointer. + * + * @return Underlying value passed intially. + */ + auto operator->() -> value_type *; + + /** + * @brief Post increment operator. Returns a copy of the value. + * + * @return Copy of the incremented underlying address. + */ + auto operator++(int) -> physical_frame_iterator; + + /** + * @brief Pre increment operator. Returns a reference to the changed value. + * + * @return Reference to the incremented underlying address. + */ + auto operator++() -> physical_frame_iterator &; + + /** + * @brief Addition assignment operator. Returns a reference to the changed value. + * + * @param operand Value we want to add to the underlying address. + * @return Reference to the changed underlying address. + */ + auto operator+=(difference_type operand) -> physical_frame_iterator &; + + /** + * @brief Subtraction assignment operator. Returns a reference to the changed value. + * + * @param operand Value we want to subtract from the underlying address. + * @return Reference to the changed underlying address. + */ + auto operator-=(difference_type operand) -> physical_frame_iterator &; + + /** + * @brief Addition operator. Returns the changed value. + * + * @param operand Value we want to add to a copy of the underlying address. + * @return Copy of underlying address incremented by the given value. + */ + auto operator+(difference_type operand) const -> physical_frame_iterator; + + /** + * @brief Subtraction operator. Returns the changed value. + * + * @param operand Value we want to subtrcat from a copy of the underlying address. + * @return Copy of underlying address decremented by the given value. + */ + auto operator-(difference_type operand) const -> physical_frame_iterator; + + /** + * @brief Subtraction operator. Returns the size difference between two iterators. + * + * @param other Other iterator we want to substract the underlying address with ours. + * @return Size difference between the underlying address of this instance and the given iterator. + */ + auto operator-(const physical_frame_iterator & other) const -> difference_type; + + /** + * @brief Index operator overload. Returns a reference to the value at the given index. Simply returns the + * dereferenced underlying pointer incremented by the given index. + * + * @param index Index we want to access and get the value from. + * @return Reference to the value at the given index. + */ + auto operator[](difference_type index) const -> value_type; + + /** + * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. + * + * @param other Other iterator to compare to. + * @return Whether both iterators point to the same underlying address in memory. + */ + auto operator==(physical_frame_iterator const & other) const -> bool = default; + + /** + * @brief Defaulted threeway comparsion operator. Simply compares the memory address of both iterators. + * + * @param other Other iterator to compare to. + * @return Whether the given iterator is smaller or larger than this iterator. + */ + auto operator<=>(physical_frame_iterator const & other) const -> std::strong_ordering = default; + + private: + value_type value = {}; ///< Underlying address the iterator is currently pointing too. }; } // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/include/arch/memory/multiboot/reader.hpp b/arch/x86_64/include/arch/memory/multiboot/reader.hpp index baa49c9..a5c4872 100644 --- a/arch/x86_64/include/arch/memory/multiboot/reader.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/reader.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP #define TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP +#include "arch/memory/multiboot/elf_symbols_section.hpp" #include "arch/memory/multiboot/memory_map.hpp" #include @@ -13,8 +14,12 @@ namespace teachos::arch::memory::multiboot */ struct memory_information { - std::size_t kernel_start; ///< Start address of the kernel code in memory. - std::size_t kernel_end; ///< End address of the kernel code in memory. + std::size_t kernel_start; ///< Start address of the kernel code in memory. + std::size_t kernel_end; ///< End address of the kernel code in memory. + elf_section_header_container::iterator + begin_kernel; ///< Iterator containing non-owning pointer to the first element of all kernel sections. + elf_section_header_container::iterator + end_kernel; ///< Iterator pointing to one past the last element of all kernel sections. std::size_t multiboot_start; ///< Start address of the multiboot code in memory. std::size_t multiboot_end; ///< End address of the multiboot code in memory. memory_area_container::iterator diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index 8e80b51..c183aff 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -17,8 +17,6 @@ namespace teachos::arch::memory::paging */ struct active_page_table { - typedef void (*function)(active_page_table & active_page_table); - /** * @brief Creates a single instance of an active level 4 page table table and returns the created instance or * alternatively returns the previously created instance instead. The instance is owned by this method and is diff --git a/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp index 62c196f..df3ba00 100644 --- a/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp @@ -9,7 +9,7 @@ namespace teachos::arch::memory::paging { struct inactive_page_table { - inactive_page_table(allocator::physical_frame frame, active_page_table active_page_table, + inactive_page_table(allocator::physical_frame frame, active_page_table & active_page_table, temporary_page temporary_page); allocator::physical_frame page_table_level_4_frame; diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 0583692..0e2411a 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -7,15 +7,80 @@ namespace teachos::arch::memory::paging { + namespace + { + std::size_t constexpr UNUSED_VIRTUAL_ADDRESS = 0xCAFEBABE; + } // namespace + + typedef shared::container frame_container; + + template struct kernel_mapper { - kernel_mapper(active_page_table & active_table); + kernel_mapper(T & allocator, multiboot::memory_information const & mem_info) + : allocator(allocator) + , mem_info(mem_info) + { + // Nothing to do + } - auto with(inactive_page_table inactive_page_table, temporary_page temporary_page, - active_page_table::function f) -> void; + auto remap_kernel() -> void + { + temporary_page temp_page{virtual_page{UNUSED_VIRTUAL_ADDRESS}, allocator}; + auto & active_table = active_page_table::create_or_get(); + auto const frame = allocator.allocate_frame(); + exception_handling::assert(frame.has_value(), + "[Kernel Mapper] Frame could not be allocated and therefore kernel not mapped"); + auto const inactive_table = inactive_page_table{frame.value(), active_table, temp_page}; + map_elf_sections(inactive_table, temp_page, active_table); + } private: - active_page_table & active_table; + auto map_elf_sections(inactive_page_table inactive_page_table, temporary_page temporary_page, + active_page_table & active_table) -> void + { + auto const backup = allocator::physical_frame::containing_address(PAGE_TABLE_LEVEL_4_ADDRESS); + auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); + + active_table.active_handle[511].set_entry(inactive_page_table.page_table_level_4_frame, + entry::PRESENT | entry::WRITABLE); + tlb_flush_all(); + map_kernel_sections(active_table); + + page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); + tlb_flush_all(); + temporary_page.unmap(active_table); + } + + auto map_kernel_sections(active_page_table & active_table) -> void + { + multiboot::elf_section_header_container sections{mem_info.begin_kernel, mem_info.end_kernel}; + for (auto const & section : sections) + { + if (!section.flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) + { + continue; + } + exception_handling::assert(section.virtual_address % allocator::PAGE_FRAME_SIZE == 0U, + "[Kernel Mapper] Section must be page aligned"); + auto const start_frame = allocator::physical_frame::containing_address(section.virtual_address); + auto const end_frame = + allocator::physical_frame::containing_address(section.virtual_address + section.section_size); + + allocator::physical_frame_iterator const begin{start_frame}; + allocator::physical_frame_iterator const end{end_frame}; + frame_container frames{begin, end}; + + for (auto frame : frames) + { + // TODO: Use actual elf section flags, convert from one to the other flag type. + active_table.identity_map(allocator, frame, entry::WRITABLE); + } + } + } + + T & allocator; + multiboot::memory_information const & mem_info; }; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/include/arch/shared/container.hpp b/arch/x86_64/include/arch/shared/container.hpp index 8ea0d08..bc2a5f6 100644 --- a/arch/x86_64/include/arch/shared/container.hpp +++ b/arch/x86_64/include/arch/shared/container.hpp @@ -19,6 +19,11 @@ namespace teachos::arch::shared using iterator = T; ///< Iterators used by this container. using size_type = std::size_t; ///< Maximum size of this container. + /** + * @brief Defaulted constructor. + */ + container() = default; + /** * @brief Constructor. * @@ -29,8 +34,7 @@ namespace teachos::arch::shared : begin_itr(begin) , end_itr(end) { - exception_handling::assert(begin != iterator{}, "[Memory Area] Attempted to pass nullptr as begin iterator"); - exception_handling::assert(end != iterator{}, "[Memory Area] Attempted to pass nullptr as end iterator"); + // Nothing to do } /** @@ -65,8 +69,8 @@ namespace teachos::arch::shared auto empty() const -> bool { return size() == 0; } private: - iterator begin_itr; ///< Pointer to the first element of the given template type. - iterator end_itr; ///< Pointer to one pas the last element of the given template type. + iterator begin_itr = {}; ///< Pointer to the first element of the given template type. + iterator end_itr = {}; ///< Pointer to one pas the last element of the given template type. }; } // namespace teachos::arch::shared diff --git a/arch/x86_64/include/arch/shared/random_access_iterator.hpp b/arch/x86_64/include/arch/shared/random_access_iterator.hpp index 13deb68..b1a800c 100644 --- a/arch/x86_64/include/arch/shared/random_access_iterator.hpp +++ b/arch/x86_64/include/arch/shared/random_access_iterator.hpp @@ -26,8 +26,7 @@ namespace teachos::arch::shared /** * @brief Constructor. * - * @param p Underlying address the iterator should point too, ensure to not pass an invalid pointer or the - * constructor will halt execution. + * @param p Underlying address the iterator should point too. */ explicit random_access_iterator(value_type * p) : ptr(p) @@ -143,14 +142,6 @@ namespace teachos::arch::shared */ auto operator==(random_access_iterator const & other) const -> bool = default; - /** - * @brief Defaulted negated comparsion operator. Simply compares the memory address of both iterators. - * - * @param other Other iterator to compare to. - * @return Whether both iterators don't point to the same underlying address in memory. - */ - auto operator!=(random_access_iterator const & other) const -> bool = default; - /** * @brief Defaulted threeway comparsion operator. Simply compares the memory address of both iterators. * diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index c89ae44..59e453a 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -3,6 +3,7 @@ #include "arch/exception_handling/assert.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/multiboot/reader.hpp" +#include "arch/memory/paging/kernel_mapper.hpp" #include "arch/memory/paging/temporary_page.hpp" #include "arch/video/vga/text.hpp" @@ -27,6 +28,9 @@ namespace teachos::arch::kernel memory::paging::temporary_page temp_page{page, allocator}; temp_page.zero_entries(active_table); + memory::paging::kernel_mapper kernel(allocator, memory_information); + kernel.remap_kernel(); + // memory::paging::map_next_free_page_to_frame(allocator, page, 0U); // auto optional_frame = memory::paging::translate_page(page); // video::vga::text::newline(); diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index 1e87147..5d56a2a 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -8,7 +8,7 @@ namespace teachos::arch::memory::allocator { - area_frame_allocator::area_frame_allocator(multiboot::memory_information mem_info) + area_frame_allocator::area_frame_allocator(multiboot::memory_information const & mem_info) : next_free_frame(0U) , current_area(std::nullopt) , memory_areas(mem_info.begin_area, mem_info.end_area) diff --git a/arch/x86_64/src/memory/allocator/physical_frame.cpp b/arch/x86_64/src/memory/allocator/physical_frame.cpp index bef9322..9307602 100644 --- a/arch/x86_64/src/memory/allocator/physical_frame.cpp +++ b/arch/x86_64/src/memory/allocator/physical_frame.cpp @@ -14,4 +14,127 @@ namespace teachos::arch::memory::allocator } auto physical_frame::start_address() const -> physical_address { return frame_number * PAGE_FRAME_SIZE; } + + /** + * @brief Constructor. + * + * @param value Underlying value the iterator should point too + */ + physical_frame_iterator::physical_frame_iterator(physical_frame_iterator::value_type value) + : value(value) + { + // Nothing to do + } + + /** + * @brief Dereferences the initally given pointer to its value. + * + * @return Reference to the value. + */ + auto physical_frame_iterator::operator*() -> physical_frame_iterator::value_type & { return value; } + + /** + * @brief Get underlying value, which is the intially passed pointer. + * + * @return Underlying value passed intially. + */ + auto physical_frame_iterator::operator->() -> physical_frame_iterator::value_type * { return &value; } + + /** + * @brief Post increment operator. Returns a copy of the value. + * + * @return Copy of the incremented underlying address. + */ + auto physical_frame_iterator::operator++(int) -> physical_frame_iterator + { + physical_frame_iterator const old_value = *this; + ++value.frame_number; + return old_value; + } + + /** + * @brief Pre increment operator. Returns a reference to the changed value. + * + * @return Reference to the incremented underlying address. + */ + auto physical_frame_iterator::operator++() -> physical_frame_iterator & + { + ++value.frame_number; + return *this; + } + + /** + * @brief Addition assignment operator. Returns a reference to the changed value. + * + * @param operand Value we want to add to the underlying address. + * @return Reference to the changed underlying address. + */ + auto + physical_frame_iterator::operator+=(physical_frame_iterator::difference_type operand) -> physical_frame_iterator & + { + value.frame_number += operand; + return *this; + } + + /** + * @brief Subtraction assignment operator. Returns a reference to the changed value. + * + * @param operand Value we want to subtract from the underlying address. + * @return Reference to the changed underlying address. + */ + auto + physical_frame_iterator::operator-=(physical_frame_iterator::difference_type operand) -> physical_frame_iterator & + { + value.frame_number -= operand; + return *this; + } + + /** + * @brief Addition operator. Returns the changed value. + * + * @param operand Value we want to add to a copy of the underlying address. + * @return Copy of underlying address incremented by the given value. + */ + auto + physical_frame_iterator::operator+(physical_frame_iterator::difference_type operand) const -> physical_frame_iterator + { + return physical_frame_iterator{physical_frame_iterator::value_type{value.frame_number + operand}}; + } + + /** + * @brief Subtraction operator. Returns the changed value. + * + * @param operand Value we want to subtrcat from a copy of the underlying address. + * @return Copy of underlying address decremented by the given value. + */ + auto + physical_frame_iterator::operator-(physical_frame_iterator::difference_type operand) const -> physical_frame_iterator + { + return physical_frame_iterator{physical_frame_iterator::value_type{value.frame_number - operand}}; + } + + /** + * @brief Subtraction operator. Returns the size difference between two iterators. + * + * @param other Other iterator we want to substract the underlying address with ours. + * @return Size difference between the underlying address of this instance and the given iterator. + */ + auto physical_frame_iterator::operator-(const physical_frame_iterator & other) const + -> physical_frame_iterator::difference_type + { + return value.frame_number - other.value.frame_number; + } + + /** + * @brief Index operator overload. Returns a reference to the value at the given index. Simply returns the + * dereferenced underlying pointer incremented by the given index. + * + * @param index Index we want to access and get the value from. + * @return Reference to the value at the given index. + */ + auto physical_frame_iterator::operator[](physical_frame_iterator::difference_type index) const + -> physical_frame_iterator::value_type + { + return physical_frame_iterator::value_type{value.frame_number + index}; + } } // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp index c3a78df..e35baf3 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -34,8 +34,9 @@ namespace teachos::arch::memory::multiboot end_area = begin_area + number_of_entries; } - auto process_elf_sections(elf_symbols_section_header * symbol, uint64_t & kernel_start, - uint64_t & kernel_end) -> void + auto process_elf_sections(elf_symbols_section_header * symbol, std::size_t & kernel_start, std::size_t & kernel_end, + elf_section_header_container::iterator & begin_kernel, + elf_section_header_container::iterator & end_kernel) -> void { auto const expected_entry_size = symbol->entry_size; auto constexpr actual_entry_size = sizeof(elf_section_header); @@ -49,12 +50,12 @@ namespace teachos::arch::memory::multiboot 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(), + begin_kernel = elf_section_header_container::iterator{reinterpret_cast(&symbol->end)}; + end_kernel = begin_kernel + symbol->number_of_sections; + exception_handling::assert(begin_kernel->is_null(), "[Multiboot Reader] Elf symbols section not starting with SHT_NULL section"); - elf_section_header_container container{begin, end}; + elf_section_header_container container{begin_kernel, end_kernel}; auto const elf_section_with_lowest_virtual_address = std::ranges::min_element(container, [](elf_section_header const & a, elf_section_header const & b) { @@ -93,6 +94,8 @@ namespace teachos::arch::memory::multiboot { memory_information mem_info{UINT64_MAX, 0U, + elf_section_header_container::iterator{}, + elf_section_header_container::iterator{}, boot::multiboot_information_pointer, 0U, memory_area_container::iterator{}, @@ -108,7 +111,8 @@ namespace teachos::arch::memory::multiboot { case tag_type::ELF_SECTIONS: { auto const symbol = reinterpret_cast(tag); - process_elf_sections(symbol, mem_info.kernel_start, mem_info.kernel_end); + process_elf_sections(symbol, mem_info.kernel_start, mem_info.kernel_end, mem_info.begin_kernel, + mem_info.end_kernel); break; } case tag_type::MEMORY_MAP: { diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp index afba1f0..de0421d 100644 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -2,7 +2,7 @@ namespace teachos::arch::memory::paging { - inactive_page_table::inactive_page_table(allocator::physical_frame frame, active_page_table active_page_table, + 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} { diff --git a/arch/x86_64/src/memory/paging/kernel_mapper.cpp b/arch/x86_64/src/memory/paging/kernel_mapper.cpp deleted file mode 100644 index 07d55ff..0000000 --- a/arch/x86_64/src/memory/paging/kernel_mapper.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "arch/memory/paging/kernel_mapper.hpp" - -#include "arch/memory/allocator/physical_frame.hpp" -#include "arch/memory/paging/tlb.hpp" - -namespace teachos::arch::memory::paging -{ - kernel_mapper::kernel_mapper(active_page_table & active_table) - : active_table(active_table) - { - // Nothing to do - } - - auto kernel_mapper::with(inactive_page_table inactive_page_table, temporary_page temporary_page, - active_page_table::function f) -> void - { - auto backup = allocator::physical_frame::containing_address(PAGE_TABLE_LEVEL_4_ADDRESS); - auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); - - active_table.active_handle[511].set_entry(inactive_page_table.page_table_level_4_frame, - entry::PRESENT | entry::WRITABLE); - tlb_flush_all(); - - f(active_table); - - page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); - tlb_flush_all(); - - temporary_page.unmap(active_table); - } -} // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 5ade8e0d5f190f2e439f81232b38b90c49c0cd1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 2 Nov 2024 12:38:22 +0000 Subject: Add comments and improve multiboot information struct usability. --- .../include/arch/memory/multiboot/reader.hpp | 17 +++--- .../arch/memory/paging/active_page_table.hpp | 4 +- .../arch/memory/paging/inactive_page_table.hpp | 14 ++++- .../include/arch/memory/paging/kernel_mapper.hpp | 63 ++++++++++++++++++---- .../src/memory/allocator/area_frame_allocator.cpp | 2 +- arch/x86_64/src/memory/multiboot/reader.cpp | 42 +++++++-------- .../src/memory/paging/inactive_page_table.cpp | 1 - 7 files changed, 94 insertions(+), 49 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot/reader.hpp b/arch/x86_64/include/arch/memory/multiboot/reader.hpp index a5c4872..9707757 100644 --- a/arch/x86_64/include/arch/memory/multiboot/reader.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/reader.hpp @@ -14,17 +14,12 @@ namespace teachos::arch::memory::multiboot */ struct memory_information { - std::size_t kernel_start; ///< Start address of the kernel code in memory. - std::size_t kernel_end; ///< End address of the kernel code in memory. - elf_section_header_container::iterator - begin_kernel; ///< Iterator containing non-owning pointer to the first element of all kernel sections. - elf_section_header_container::iterator - end_kernel; ///< Iterator pointing to one past the last element of all kernel sections. - std::size_t multiboot_start; ///< Start address of the multiboot code in memory. - std::size_t multiboot_end; ///< End address of the multiboot code in memory. - memory_area_container::iterator - begin_area; ///< Iterator containing non-owning pointer to the first element of all memory areas. - memory_area_container::iterator end_area; ///< Iterator pointing to one past the last element of all memory areas. + std::size_t kernel_start; ///< Start address of the kernel code in memory. + std::size_t kernel_end; ///< End address of the kernel code in memory. + elf_section_header_container sections; ///< Contains non-owning pointers to all kernel sections. + std::size_t multiboot_start; ///< Start address of the multiboot code in memory. + std::size_t multiboot_end; ///< End address of the multiboot code in memory. + memory_area_container areas; ///< Contains non-owning pointers to all memory areas. }; /** diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index c183aff..71f70b5 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -12,8 +12,8 @@ namespace teachos::arch::memory::paging { /** - * @brief Currently active level 4 page table, is used to ensure there is only ever one valid instance and it cannot - * be copied or constructed again. + * @brief Currently actively by the CPU used level 4 page table, is used to ensure there is only ever one valid + * instance and it cannot be copied or constructed again. */ struct active_page_table { diff --git a/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp index df3ba00..54a53f4 100644 --- a/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp @@ -7,12 +7,24 @@ namespace teachos::arch::memory::paging { + /** + * @brief By the CPU used level 4 page table. + */ struct inactive_page_table { + /** + * @brief Constructor. + * + * @param frame Frame that should be mapped as the level 4 page table. + * @param active_page_table Actual active page table that should be unmapped so we can map a new level 4 + * page table. + * @param temporary_page Temporary page that should be used to map the given frame as the new level 4 page + * table. + */ inactive_page_table(allocator::physical_frame frame, active_page_table & active_page_table, temporary_page temporary_page); - allocator::physical_frame page_table_level_4_frame; + allocator::physical_frame page_table_level_4_frame; ///< Temporary level 4 page table }; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 0e2411a..5ee4ea8 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -14,9 +14,20 @@ namespace teachos::arch::memory::paging typedef shared::container frame_container; + /** + * @brief Kernel mapper that allows to remap the kernel elf sections in C++. + * + * @tparam T Contract the allocator that should be used to allocate frames for the remapping process has to fulfill. + */ template struct kernel_mapper { + /** + * @brief Constructor. + * + * @param allocator Allocator that should be used to allocate frames for the remapping process. + * @param mem_info Information about elf kernel sections required for remapping process. + */ kernel_mapper(T & allocator, multiboot::memory_information const & mem_info) : allocator(allocator) , mem_info(mem_info) @@ -24,6 +35,14 @@ namespace teachos::arch::memory::paging // Nothing to do } + /** + * @brief Remap the kernel, meaning we map the entire kernel and all of it's elf sections with the correct flags + * into memory and then replace the created mapping with the current one. + * + * @note We have to use a workaround with an + * inactive page table, that is not used by the CPU to ensure we are not changign memory that we are using. Because + * remapping active kernel memory in the kernel wouldn't work. + */ auto remap_kernel() -> void { temporary_page temp_page{virtual_page{UNUSED_VIRTUAL_ADDRESS}, allocator}; @@ -32,30 +51,51 @@ namespace teachos::arch::memory::paging exception_handling::assert(frame.has_value(), "[Kernel Mapper] Frame could not be allocated and therefore kernel not mapped"); auto const inactive_table = inactive_page_table{frame.value(), active_table, temp_page}; - map_elf_sections(inactive_table, temp_page, active_table); + remap_elf_kernel_sections(inactive_table, temp_page, active_table); } private: - auto map_elf_sections(inactive_page_table inactive_page_table, temporary_page temporary_page, - active_page_table & active_table) -> void + /** + * @brief Remaps the kernel elf sections. This is done with switching the current level 4 page table recursive + * mapping to any unmapped address in memory and then actually mapping the level 4 page table on that address. + * Once the remapping process is done we can restore the original recursive mapping with the complete remapped + * kernel. + * + * @note Because we change the entries we also have to ensure we flush the translation lookaside buffer, before we + * map the entries. + * + * @param inactive_table Level 4 page table we temporarily map the kernel into. + * @param temporary_page Temporary page that should be used for the mapping process and then + * unmapped once finished. + * @param active_table Active level 4 page table that has its recursive mapping overwritten temporarily and then + * restored once the process is finished. + */ + auto remap_elf_kernel_sections(inactive_page_table inactive_table, temporary_page & temporary_page, + active_page_table & active_table) -> void { auto const backup = allocator::physical_frame::containing_address(PAGE_TABLE_LEVEL_4_ADDRESS); auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); - active_table.active_handle[511].set_entry(inactive_page_table.page_table_level_4_frame, + active_table.active_handle[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); tlb_flush_all(); - map_kernel_sections(active_table); + map_elf_kernel_sections(active_table); page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); tlb_flush_all(); temporary_page.unmap(active_table); } - auto map_kernel_sections(active_page_table & active_table) -> void + /** + * @brief Maps the required entries according to every elf section and it's contained frames. Additionally each of + * thoose frames gets the correct entry flags according to elf section flags. + * + * @param active_table Active level 4 page table that should be used to map the required elf sections into entries. + * Has had its recursive mapping temporarily replaced and points to unmapped place in memory. + */ + auto map_elf_kernel_sections(active_page_table & active_table) -> void { - multiboot::elf_section_header_container sections{mem_info.begin_kernel, mem_info.end_kernel}; - for (auto const & section : sections) + for (auto const & section : mem_info.sections) { if (!section.flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) { @@ -71,7 +111,7 @@ namespace teachos::arch::memory::paging allocator::physical_frame_iterator const end{end_frame}; frame_container frames{begin, end}; - for (auto frame : frames) + for (auto const & frame : frames) { // TODO: Use actual elf section flags, convert from one to the other flag type. active_table.identity_map(allocator, frame, entry::WRITABLE); @@ -79,8 +119,9 @@ namespace teachos::arch::memory::paging } } - T & allocator; - multiboot::memory_information const & mem_info; + T & allocator; ///< Allocator that should be used to allocate frames for the mapping process. + multiboot::memory_information const & + mem_info; ///< Information about elf kernel sections required for remapping process. }; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index 5d56a2a..da4a919 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -11,7 +11,7 @@ namespace teachos::arch::memory::allocator area_frame_allocator::area_frame_allocator(multiboot::memory_information const & mem_info) : next_free_frame(0U) , current_area(std::nullopt) - , memory_areas(mem_info.begin_area, mem_info.end_area) + , 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)) diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp index e35baf3..7bdf48f 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -18,8 +18,7 @@ namespace teachos::arch::memory::multiboot return reinterpret_cast(reinterpret_cast(ptr) + ((size + 7) & ~7)); } - auto process_memory_map(memory_map_header * mminfo, memory_area_container::iterator & begin_area, - memory_area_container::iterator & end_area) -> void + 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); @@ -30,13 +29,13 @@ namespace teachos::arch::memory::multiboot 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; - begin_area = memory_area_container::iterator{&mminfo->entries}; - end_area = begin_area + number_of_entries; + 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::iterator & begin_kernel, - elf_section_header_container::iterator & end_kernel) -> void + 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); @@ -50,30 +49,30 @@ namespace teachos::arch::memory::multiboot exception_handling::assert(expected_total_size == actual_total_size, "[Multiboot Reader] Unexpected elf symbols section header total size"); - begin_kernel = elf_section_header_container::iterator{reinterpret_cast(&symbol->end)}; - end_kernel = begin_kernel + symbol->number_of_sections; - exception_handling::assert(begin_kernel->is_null(), + 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 container{begin_kernel, end_kernel}; + elf_section_header_container sections{begin, end}; auto const elf_section_with_lowest_virtual_address = - std::ranges::min_element(container, [](elf_section_header const & a, elf_section_header const & b) { + std::ranges::min_element(sections, [](elf_section_header const & a, elf_section_header const & b) { return a.virtual_address < b.virtual_address; }); auto const elf_section_with_highest_virtual_address = - std::ranges::max_element(container, [](elf_section_header const & a, elf_section_header const & b) { + std::ranges::max_element(sections, [](elf_section_header const & a, elf_section_header const & b) { auto a_virtual_address_end = a.virtual_address + a.section_size; auto b_virtual_address_end = b.virtual_address + b.section_size; return a_virtual_address_end < b_virtual_address_end; }); - auto const symbol_table_section_count = std::ranges::count_if(container, [](elf_section_header const & section) { + auto const symbol_table_section_count = std::ranges::count_if(sections, [](elf_section_header 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( - container, [](elf_section_header const & section) { return section.type == elf_section_type::DYNAMIC; }); + sections, [](elf_section_header const & section) { return section.type == elf_section_type::DYNAMIC; }); exception_handling::assert( symbol_table_section_count == 1U, @@ -87,6 +86,8 @@ namespace teachos::arch::memory::multiboot auto const highest_elf_section = *elf_section_with_highest_virtual_address; kernel_end = highest_elf_section.virtual_address + highest_elf_section.section_size; + + return sections; } } // namespace @@ -94,12 +95,10 @@ namespace teachos::arch::memory::multiboot { memory_information mem_info{UINT64_MAX, 0U, - elf_section_header_container::iterator{}, - elf_section_header_container::iterator{}, + elf_section_header_container{}, boot::multiboot_information_pointer, 0U, - memory_area_container::iterator{}, - memory_area_container::iterator{}}; + memory_area_container{}}; auto const multiboot_information_pointer = reinterpret_cast(boot::multiboot_information_pointer); auto const multiboot_tag = &multiboot_information_pointer->tags; @@ -111,13 +110,12 @@ namespace teachos::arch::memory::multiboot { case tag_type::ELF_SECTIONS: { auto const symbol = reinterpret_cast(tag); - process_elf_sections(symbol, mem_info.kernel_start, mem_info.kernel_end, mem_info.begin_kernel, - mem_info.end_kernel); + 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); - process_memory_map(mminfo, mem_info.begin_area, mem_info.end_area); + mem_info.areas = process_memory_map(mminfo); break; } default: diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp index de0421d..0b141e2 100644 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -9,7 +9,6 @@ namespace teachos::arch::memory::paging 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(active_page_table); } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 4d76f412b071a05f0aae1d1307f2b58cb2778569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 2 Nov 2024 14:08:55 +0000 Subject: Attempt to fix crashes --- .../arch/memory/allocator/tiny_frame_allocator.hpp | 19 +++++- .../arch/memory/paging/active_page_table.hpp | 2 +- .../include/arch/memory/paging/kernel_mapper.hpp | 30 ++++----- .../include/arch/memory/paging/temporary_page.hpp | 7 +- arch/x86_64/src/kernel/main.cpp | 76 +++++++++++----------- .../src/memory/allocator/tiny_frame_allocator.cpp | 4 +- 6 files changed, 75 insertions(+), 63 deletions(-) diff --git a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp index e55b376..b8ed506 100644 --- a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -9,6 +9,11 @@ namespace teachos::arch::memory::allocator { + namespace + { + uint8_t constexpr TINY_ALLOCATOR_FRAMES_COUNT = 3U; + } + /** * @brief Allocates memory using memory areas read from the multiboot2 information pointer. */ @@ -23,9 +28,16 @@ namespace teachos::arch::memory::allocator * entries *when a new page table is required. */ tiny_frame_allocator(area_frame_allocator & allocator) - : frames{allocator.allocate_frame(), allocator.allocate_frame(), allocator.allocate_frame()} + : frames{} { - // Nothing to do + for (auto & frame : frames) + { + auto allocated = allocator.allocate_frame(); + if (allocated.has_value()) + { + frame.emplace(allocated.value()); + } + } } /** @@ -47,7 +59,8 @@ namespace teachos::arch::memory::allocator auto deallocate_frame(physical_frame physical_frame) -> void; private: - std::array, 3U> frames = {}; + std::array, TINY_ALLOCATOR_FRAMES_COUNT> frames = + {}; ///< Container that holds the frames allocated by another allocator. }; } // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index 71f70b5..5140c3d 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -128,7 +128,7 @@ namespace teachos::arch::memory::paging "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); auto current_handle = active_handle; - std::array handles{current_handle, current_handle, current_handle, current_handle}; + std::array handles{current_handle, current_handle, current_handle}; for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) { diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 5ee4ea8..a7ae3aa 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -16,21 +16,16 @@ namespace teachos::arch::memory::paging /** * @brief Kernel mapper that allows to remap the kernel elf sections in C++. - * - * @tparam T Contract the allocator that should be used to allocate frames for the remapping process has to fulfill. */ - template struct kernel_mapper { /** * @brief Constructor. * - * @param allocator Allocator that should be used to allocate frames for the remapping process. * @param mem_info Information about elf kernel sections required for remapping process. */ - kernel_mapper(T & allocator, multiboot::memory_information const & mem_info) - : allocator(allocator) - , mem_info(mem_info) + kernel_mapper(multiboot::memory_information const & mem_info) + : mem_info(mem_info) { // Nothing to do } @@ -42,16 +37,22 @@ namespace teachos::arch::memory::paging * @note We have to use a workaround with an * inactive page table, that is not used by the CPU to ensure we are not changign memory that we are using. Because * remapping active kernel memory in the kernel wouldn't work. + * + * @tparam T Contract the allocator that should be used to allocate frames for the remapping process has to fulfill. + * + * @param allocator Allocator that should be used to allocate frames for the remapping process. */ - auto remap_kernel() -> void + template + auto remap_kernel(T & allocator) -> void { - temporary_page temp_page{virtual_page{UNUSED_VIRTUAL_ADDRESS}, allocator}; + virtual_page temporary_address{UNUSED_VIRTUAL_ADDRESS}; + temporary_page temporary_page{temporary_address, allocator}; auto & active_table = active_page_table::create_or_get(); auto const frame = allocator.allocate_frame(); exception_handling::assert(frame.has_value(), "[Kernel Mapper] Frame could not be allocated and therefore kernel not mapped"); - auto const inactive_table = inactive_page_table{frame.value(), active_table, temp_page}; - remap_elf_kernel_sections(inactive_table, temp_page, active_table); + inactive_page_table inactive_table{frame.value(), active_table, temporary_page}; + remap_elf_kernel_sections(inactive_table, temporary_page, active_table); } private: @@ -79,7 +80,7 @@ namespace teachos::arch::memory::paging active_table.active_handle[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); tlb_flush_all(); - map_elf_kernel_sections(active_table); + map_elf_kernel_sections(temporary_page, active_table); page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); tlb_flush_all(); @@ -93,7 +94,7 @@ namespace teachos::arch::memory::paging * @param active_table Active level 4 page table that should be used to map the required elf sections into entries. * Has had its recursive mapping temporarily replaced and points to unmapped place in memory. */ - auto map_elf_kernel_sections(active_page_table & active_table) -> void + auto map_elf_kernel_sections(temporary_page & temporary_page, active_page_table & active_table) -> void { for (auto const & section : mem_info.sections) { @@ -114,12 +115,11 @@ namespace teachos::arch::memory::paging for (auto const & frame : frames) { // TODO: Use actual elf section flags, convert from one to the other flag type. - active_table.identity_map(allocator, frame, entry::WRITABLE); + active_table.identity_map(temporary_page.allocator, frame, entry::WRITABLE); } } } - T & allocator; ///< Allocator that should be used to allocate frames for the mapping process. multiboot::memory_information const & mem_info; ///< Information about elf kernel sections required for remapping process. }; diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp index 0cadc29..6b3bcb6 100644 --- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -51,6 +51,10 @@ namespace teachos::arch::memory::paging */ auto map_table_frame(allocator::physical_frame frame, active_page_table & active_table) -> page_table_handle; + // TODO: Better way to do this? + virtual_page page; + allocator::tiny_frame_allocator allocator; + private: /** * @brief Map the temporary page to a frame. @@ -60,9 +64,6 @@ namespace teachos::arch::memory::paging * @return The virtual address of the page. */ auto map_to_frame(allocator::physical_frame frame, active_page_table & active_table) -> virtual_address; - - virtual_page page; - allocator::tiny_frame_allocator allocator; }; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 59e453a..5cfd9b3 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -20,44 +20,42 @@ namespace teachos::arch::kernel auto const memory_information = memory::multiboot::read_multiboot2(); memory::allocator::area_frame_allocator allocator(memory_information); - size_t address = 42 * memory::paging::PAGE_TABLE_ENTRY_COUNT * memory::paging::PAGE_TABLE_ENTRY_COUNT * - memory::allocator::PAGE_FRAME_SIZE; // 42th P3 entry - auto const page = memory::paging::virtual_page::containing_address(address); - - auto & active_table = memory::paging::active_page_table::create_or_get(); - memory::paging::temporary_page temp_page{page, allocator}; - temp_page.zero_entries(active_table); - - memory::paging::kernel_mapper kernel(allocator, memory_information); - kernel.remap_kernel(); - - // memory::paging::map_next_free_page_to_frame(allocator, page, 0U); - // auto optional_frame = memory::paging::translate_page(page); - // video::vga::text::newline(); - // video::vga::text::write("Mapped physical frame: ", video::vga::text::common_attributes::green_on_black); - // video::vga::text::write_number(optional_frame.value().frame_number, - // video::vga::text::common_attributes::green_on_black); - // video::vga::text::write(" to virtual page: ", video::vga::text::common_attributes::green_on_black); - // video::vga::text::write_number(page.page_number, video::vga::text::common_attributes::green_on_black); - - // memory::paging::unmap_page(allocator, page); - // video::vga::text::newline(); - // video::vga::text::write("Unapped virtual page from physical frame: ", - // video::vga::text::common_attributes::green_on_black); - // optional_frame = memory::paging::translate_page(page); - // exception_handling::assert(!optional_frame.has_value(), "[Main] Ummapping failed"); - // video::vga::text::write_number(page.page_number, video::vga::text::common_attributes::green_on_black); - - auto last_allocated = allocator.allocate_frame(); - auto allocated = last_allocated; - do - { - last_allocated = allocated; - allocated = allocator.allocate_frame(); - } while (allocated); - video::vga::text::newline(); - video::vga::text::write("Allocated Frames: ", video::vga::text::common_attributes::green_on_black); - video::vga::text::write_number(last_allocated.value().frame_number, - video::vga::text::common_attributes::green_on_black); + memory::paging::kernel_mapper kernel(memory_information); + kernel.remap_kernel(allocator); + video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); + + /* + size_t address = 42 * memory::paging::PAGE_TABLE_ENTRY_COUNT * memory::paging::PAGE_TABLE_ENTRY_COUNT * + memory::allocator::PAGE_FRAME_SIZE; // 42th P3 entry + auto const page = memory::paging::virtual_page::containing_address(address); + memory::paging::map_next_free_page_to_frame(allocator, page, 0U); + auto optional_frame = memory::paging::translate_page(page); + video::vga::text::newline(); + video::vga::text::write("Mapped physical frame: ", video::vga::text::common_attributes::green_on_black); + video::vga::text::write_number(optional_frame.value().frame_number, + video::vga::text::common_attributes::green_on_black); + video::vga::text::write(" to virtual page: ", video::vga::text::common_attributes::green_on_black); + video::vga::text::write_number(page.page_number, video::vga::text::common_attributes::green_on_black); + + memory::paging::unmap_page(allocator, page); + video::vga::text::newline(); + video::vga::text::write("Unapped virtual page from physical frame: ", + video::vga::text::common_attributes::green_on_black); + optional_frame = memory::paging::translate_page(page); + exception_handling::assert(!optional_frame.has_value(), "[Main] Ummapping failed"); + video::vga::text::write_number(page.page_number, video::vga::text::common_attributes::green_on_black); + + auto last_allocated = allocator.allocate_frame(); + auto allocated = last_allocated; + do + { + last_allocated = allocated; + allocated = allocator.allocate_frame(); + } while (allocated); + video::vga::text::newline(); + video::vga::text::write("Allocated Frames: ", video::vga::text::common_attributes::green_on_black); + video::vga::text::write_number(last_allocated.value().frame_number, + video::vga::text::common_attributes::green_on_black); + */ } } // namespace teachos::arch::kernel diff --git a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp index d07398a..b9fd2c8 100644 --- a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp @@ -11,7 +11,7 @@ namespace teachos::arch::memory::allocator if (frame_option.has_value()) { auto value = frame_option; - frame_option = std::nullopt; + frame_option.reset(); return value; } } @@ -24,7 +24,7 @@ namespace teachos::arch::memory::allocator { if (!frame_option.has_value()) { - frame_option = physical_frame; + frame_option.emplace(physical_frame); return; } } -- cgit v1.2.3 From d4b1b8a85212f07df47217fe13d86956c7eb064f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 3 Nov 2024 10:47:33 +0000 Subject: Use passed allocator in inactive page instead of tiny. --- .../include/arch/memory/paging/kernel_mapper.hpp | 25 +++++++++++----------- .../include/arch/memory/paging/temporary_page.hpp | 9 ++++---- arch/x86_64/src/kernel/main.cpp | 4 ++-- .../src/memory/paging/inactive_page_table.cpp | 2 +- arch/x86_64/src/memory/paging/temporary_page.cpp | 7 ++++-- 5 files changed, 25 insertions(+), 22 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index a7ae3aa..d7365a0 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -16,16 +16,21 @@ namespace teachos::arch::memory::paging /** * @brief Kernel mapper that allows to remap the kernel elf sections in C++. + * + * @tparam T Contract the allocator that should be used to allocate frames for the remapping process has to fulfill. */ + template struct kernel_mapper { /** * @brief Constructor. * + * @param allocator Allocator that should be used to allocate frames for the remapping process. * @param mem_info Information about elf kernel sections required for remapping process. */ - kernel_mapper(multiboot::memory_information const & mem_info) - : mem_info(mem_info) + kernel_mapper(T & allocator, multiboot::memory_information const & mem_info) + : allocator(allocator) + , mem_info(mem_info) { // Nothing to do } @@ -37,13 +42,8 @@ namespace teachos::arch::memory::paging * @note We have to use a workaround with an * inactive page table, that is not used by the CPU to ensure we are not changign memory that we are using. Because * remapping active kernel memory in the kernel wouldn't work. - * - * @tparam T Contract the allocator that should be used to allocate frames for the remapping process has to fulfill. - * - * @param allocator Allocator that should be used to allocate frames for the remapping process. */ - template - auto remap_kernel(T & allocator) -> void + auto remap_kernel() -> void { virtual_page temporary_address{UNUSED_VIRTUAL_ADDRESS}; temporary_page temporary_page{temporary_address, allocator}; @@ -80,11 +80,11 @@ namespace teachos::arch::memory::paging active_table.active_handle[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); tlb_flush_all(); - map_elf_kernel_sections(temporary_page, active_table); + map_elf_kernel_sections(active_table); page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); tlb_flush_all(); - temporary_page.unmap(active_table); + temporary_page.unmap_page(active_table); } /** @@ -94,7 +94,7 @@ namespace teachos::arch::memory::paging * @param active_table Active level 4 page table that should be used to map the required elf sections into entries. * Has had its recursive mapping temporarily replaced and points to unmapped place in memory. */ - auto map_elf_kernel_sections(temporary_page & temporary_page, active_page_table & active_table) -> void + auto map_elf_kernel_sections(active_page_table & active_table) -> void { for (auto const & section : mem_info.sections) { @@ -115,11 +115,12 @@ namespace teachos::arch::memory::paging for (auto const & frame : frames) { // TODO: Use actual elf section flags, convert from one to the other flag type. - active_table.identity_map(temporary_page.allocator, frame, entry::WRITABLE); + active_table.identity_map(allocator, frame, entry::WRITABLE); } } } + T & allocator; multiboot::memory_information const & mem_info; ///< Information about elf kernel sections required for remapping process. }; diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp index 6b3bcb6..8b49894 100644 --- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -40,7 +40,7 @@ namespace teachos::arch::memory::paging * * @param active_table The current active page table. */ - auto unmap(active_page_table & active_table) -> void; + auto unmap_page(active_page_table & active_table) -> void; /** * @brief Map the temporary page to a frame. @@ -51,10 +51,6 @@ namespace teachos::arch::memory::paging */ auto map_table_frame(allocator::physical_frame frame, active_page_table & active_table) -> page_table_handle; - // TODO: Better way to do this? - virtual_page page; - allocator::tiny_frame_allocator allocator; - private: /** * @brief Map the temporary page to a frame. @@ -64,6 +60,9 @@ namespace teachos::arch::memory::paging * @return The virtual address of the page. */ auto map_to_frame(allocator::physical_frame frame, active_page_table & active_table) -> virtual_address; + + virtual_page page; ///< Underlying virtual page we want to temporarily map a level 4 page table into. + allocator::tiny_frame_allocator allocator; ///< Allocator that should be used to map the temporary page. }; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 5cfd9b3..c111f22 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -20,8 +20,8 @@ namespace teachos::arch::kernel auto const memory_information = memory::multiboot::read_multiboot2(); memory::allocator::area_frame_allocator allocator(memory_information); - memory::paging::kernel_mapper kernel(memory_information); - kernel.remap_kernel(allocator); + memory::paging::kernel_mapper kernel(allocator, memory_information); + kernel.remap_kernel(); video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); /* diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp index 0b141e2..f6ecb8b 100644 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -9,6 +9,6 @@ namespace teachos::arch::memory::paging 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(active_page_table); + temporary_page.unmap_page(active_page_table); } } // 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 index 180b4a8..7b065ab 100644 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -14,7 +14,10 @@ namespace teachos::arch::memory::paging return page.start_address(); } - auto temporary_page::unmap(active_page_table & active_table) -> void { active_table.unmap_page(allocator, page); } + auto temporary_page::unmap_page(active_page_table & active_table) -> void + { + active_table.unmap_page(allocator, page); + } auto temporary_page::map_table_frame(allocator::physical_frame frame, active_page_table & active_table) -> page_table_handle @@ -33,6 +36,6 @@ namespace teachos::arch::memory::paging handle.zero_entries(); handle[511].set_entry(frame.value(), entry::PRESENT | entry::WRITABLE); - unmap(active_table); + unmap_page(active_table); } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 9292814545ab5df5aa69d4f75a6d9230f3e03f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 3 Nov 2024 11:03:34 +0000 Subject: Move possible implementation into cpp --- .../arch/memory/allocator/tiny_frame_allocator.hpp | 13 +------------ .../x86_64/src/memory/allocator/tiny_frame_allocator.cpp | 16 ++++++++++++++++ arch/x86_64/src/memory/paging/temporary_page.cpp | 16 ++++++++-------- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp index b8ed506..a96b743 100644 --- a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -27,18 +27,7 @@ namespace teachos::arch::memory::allocator * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate * entries *when a new page table is required. */ - tiny_frame_allocator(area_frame_allocator & allocator) - : frames{} - { - for (auto & frame : frames) - { - auto allocated = allocator.allocate_frame(); - if (allocated.has_value()) - { - frame.emplace(allocated.value()); - } - } - } + tiny_frame_allocator(area_frame_allocator & allocator); /** * @brief Allocate memory by finding and returning one of the three free physical frames. diff --git a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp index b9fd2c8..d37864e 100644 --- a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp @@ -4,6 +4,22 @@ namespace teachos::arch::memory::allocator { + tiny_frame_allocator::tiny_frame_allocator(area_frame_allocator & allocator) + : frames{} + { + // Has to be done this way, because constructing the constructor with the data from allocator.allocate_frames(), + // does not work because it would set the value correctly but because we pass it as an std::optional it would not + // set the engaged flag. Meaning the has_value() method would still return false. + for (auto & frame : frames) + { + auto allocated = allocator.allocate_frame(); + if (allocated.has_value()) + { + frame.emplace(allocated.value()); + } + } + } + auto tiny_frame_allocator::allocate_frame() -> std::optional { for (auto & frame_option : frames) diff --git a/arch/x86_64/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp index 7b065ab..5f760a5 100644 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -4,6 +4,14 @@ 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 { @@ -19,14 +27,6 @@ namespace teachos::arch::memory::paging active_table.unmap_page(allocator, page); } - 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::zero_entries(active_page_table & active_table) -> void { auto frame = allocator.allocate_frame(); -- cgit v1.2.3 From be546b091795e740e9dd4c35fce6453fafe0319c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 3 Nov 2024 11:56:46 +0000 Subject: Make member variables private again. --- arch/x86_64/include/arch/memory/paging/active_page_table.hpp | 12 ++++++++++-- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 3 +-- arch/x86_64/src/memory/paging/active_page_table.cpp | 2 ++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index 5140c3d..0561420 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -26,6 +26,14 @@ namespace teachos::arch::memory::paging */ static auto create_or_get() -> active_page_table &; + /** + * @brief Index operator overload to access specific mutable entry directy of the level 4 page table. + * + * @param index Index of the entry we want to access and only read. + * @return Entry at the given table index. + */ + auto operator[](std::size_t index) -> entry &; + /** * @brief Translates virtual address into corresponding physical address. Calls translate_page under the hood. * @@ -160,8 +168,6 @@ namespace teachos::arch::memory::paging tlb_flush(page.start_address()); } - page_table_handle active_handle; ///< Underlying active level 4 page table - private: /** * @brief Private constructor should only be used by create or get method, which ensures to create only ever one @@ -202,6 +208,8 @@ namespace teachos::arch::memory::paging entry.set_unused(); allocator.deallocate_frame(frame.value()); } + + page_table_handle active_handle; ///< Underlying active level 4 page table }; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index d7365a0..ede027c 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -77,8 +77,7 @@ namespace teachos::arch::memory::paging auto const backup = allocator::physical_frame::containing_address(PAGE_TABLE_LEVEL_4_ADDRESS); auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); - active_table.active_handle[511].set_entry(inactive_table.page_table_level_4_frame, - entry::PRESENT | entry::WRITABLE); + active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); tlb_flush_all(); map_elf_kernel_sections(active_table); diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp index 844ae37..033a363 100644 --- a/arch/x86_64/src/memory/paging/active_page_table.cpp +++ b/arch/x86_64/src/memory/paging/active_page_table.cpp @@ -10,6 +10,8 @@ namespace teachos::arch::memory::paging 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; -- cgit v1.2.3 From 67be3c58bef94fece14d4e3a79f3559649e9a74c Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 3 Nov 2024 12:12:41 +0000 Subject: rename member and use correct address --- .../arch/memory/multiboot/elf_symbols_section.hpp | 8 ++++---- .../include/arch/memory/paging/kernel_mapper.hpp | 17 ++++++++++++----- arch/x86_64/include/arch/memory/paging/tlb.hpp | 2 +- .../src/memory/multiboot/elf_symbols_section.cpp | 2 +- arch/x86_64/src/memory/multiboot/reader.cpp | 20 ++++++++++---------- 5 files changed, 28 insertions(+), 21 deletions(-) diff --git a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp index c9989ae..e29590d 100644 --- a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp @@ -120,10 +120,10 @@ namespace teachos::arch::memory::multiboot uint32_t name_table_index; ///< Index into the section header string table, specifies the name of the section. elf_section_type type; ///< Categorizes the sections content and semantics. elf_section_flags flags; ///< 1-bit flgas that describe section attributes. - uint64_t virtual_address; ///< If section appears in memory image of a process, gives address at which the sections - ///< first byte should reside, otherwise 0. - uint64_t file_offset; ///< Offset from the beginning of the file to the first byte in the section. SHT_NOBITS - ///< contains the conceptual placement instead (because it occupies no space in the file). + uint64_t physical_address; ///< If section appears in memory image of a process, gives address at which the + ///< sections first byte should reside, otherwise 0. + uint64_t file_offset; ///< Offset from the beginning of the file to the first byte in the section. SHT_NOBITS + ///< contains the conceptual placement instead (because it occupies no space in the file). uint64_t section_size; ///< Complete section size in bytes, SHT_NOBITS may have non-zero value but will always ///< occupy no space in the file. uint32_t other_section; ///< Section header table index link, behaviour varies on type diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index d7365a0..84f0471 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -57,7 +57,9 @@ namespace teachos::arch::memory::paging private: /** - * @brief Remaps the kernel elf sections. This is done with switching the current level 4 page table recursive + * @brief Remaps the kernel elf sections. + * + * This is done with switching the current level 4 page table recursive * mapping to any unmapped address in memory and then actually mapping the level 4 page table on that address. * Once the remapping process is done we can restore the original recursive mapping with the complete remapped * kernel. @@ -74,11 +76,16 @@ namespace teachos::arch::memory::paging auto remap_elf_kernel_sections(inactive_page_table inactive_table, temporary_page & temporary_page, active_page_table & active_table) -> void { - auto const backup = allocator::physical_frame::containing_address(PAGE_TABLE_LEVEL_4_ADDRESS); + auto physical_address = active_table.translate_address(PAGE_TABLE_LEVEL_4_ADDRESS); + exception_handling::assert(!physical_address.has_value(), + "[Kernel Mapper] Physical address for active table not mapped"); + + auto const backup = allocator::physical_frame::containing_address(physical_address.value()); auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); active_table.active_handle[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); + tlb_flush_all(); map_elf_kernel_sections(active_table); @@ -102,11 +109,11 @@ namespace teachos::arch::memory::paging { continue; } - exception_handling::assert(section.virtual_address % allocator::PAGE_FRAME_SIZE == 0U, + exception_handling::assert(section.physical_address % allocator::PAGE_FRAME_SIZE == 0U, "[Kernel Mapper] Section must be page aligned"); - auto const start_frame = allocator::physical_frame::containing_address(section.virtual_address); + auto const start_frame = allocator::physical_frame::containing_address(section.physical_address); auto const end_frame = - allocator::physical_frame::containing_address(section.virtual_address + section.section_size); + allocator::physical_frame::containing_address(section.physical_address + section.section_size); allocator::physical_frame_iterator const begin{start_frame}; allocator::physical_frame_iterator const end{end_frame}; diff --git a/arch/x86_64/include/arch/memory/paging/tlb.hpp b/arch/x86_64/include/arch/memory/paging/tlb.hpp index 1194720..85c4152 100644 --- a/arch/x86_64/include/arch/memory/paging/tlb.hpp +++ b/arch/x86_64/include/arch/memory/paging/tlb.hpp @@ -5,7 +5,7 @@ namespace teachos::arch::memory::paging { - std::size_t constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; + virtual_address constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; /** * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained diff --git a/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp b/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp index 953a57d..f5d126b 100644 --- a/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp +++ b/arch/x86_64/src/memory/multiboot/elf_symbols_section.cpp @@ -7,7 +7,7 @@ namespace teachos::arch::memory::multiboot auto elf_section_header::is_null() const -> bool { return name_table_index == 0U && type == elf_section_type::INACTIVE && flags == elf_section_flags(0U) && - virtual_address == 0U && file_offset == 0U && additional_information == 0U && address_alignment == 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 index 7bdf48f..4576085 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -56,16 +56,16 @@ namespace teachos::arch::memory::multiboot elf_section_header_container sections{begin, end}; - auto const elf_section_with_lowest_virtual_address = + auto const elf_section_with_lowest_physical_address = std::ranges::min_element(sections, [](elf_section_header const & a, elf_section_header const & b) { - return a.virtual_address < b.virtual_address; + return a.physical_address < b.physical_address; }); - auto const elf_section_with_highest_virtual_address = + auto const elf_section_with_highest_physical_address = std::ranges::max_element(sections, [](elf_section_header const & a, elf_section_header const & b) { - auto a_virtual_address_end = a.virtual_address + a.section_size; - auto b_virtual_address_end = b.virtual_address + b.section_size; - return a_virtual_address_end < b_virtual_address_end; + 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, [](elf_section_header const & section) { @@ -81,11 +81,11 @@ namespace teachos::arch::memory::multiboot 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_virtual_address; - kernel_start = lowest_elf_section.virtual_address; + 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_virtual_address; - kernel_end = highest_elf_section.virtual_address + highest_elf_section.section_size; + 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; } -- cgit v1.2.3 From 756ef3a6d6aa61656dddbfea97482c8698807e39 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 3 Nov 2024 12:15:43 +0000 Subject: fix assert --- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index f06c4e2..3931db3 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -77,7 +77,7 @@ namespace teachos::arch::memory::paging active_page_table & active_table) -> void { auto physical_address = active_table.translate_address(PAGE_TABLE_LEVEL_4_ADDRESS); - exception_handling::assert(!physical_address.has_value(), + exception_handling::assert(physical_address.has_value(), "[Kernel Mapper] Physical address for active table not mapped"); auto const backup = allocator::physical_frame::containing_address(physical_address.value()); -- cgit v1.2.3 From 380bc85d1a4fdbef102132c726ef2ac7ac6355da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 3 Nov 2024 12:20:21 +0000 Subject: Make constructor constexpr for basic page and frame types --- arch/x86_64/include/arch/memory/allocator/physical_frame.hpp | 8 ++++++-- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 5 ++--- arch/x86_64/include/arch/memory/paging/virtual_page.hpp | 6 +++++- arch/x86_64/src/memory/allocator/physical_frame.cpp | 6 ------ arch/x86_64/src/memory/paging/virtual_page.cpp | 6 ------ 5 files changed, 13 insertions(+), 18 deletions(-) diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp index b95687c..89e3cf8 100644 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -20,14 +20,18 @@ namespace teachos::arch::memory::allocator /** * @brief Defaulted constructor. */ - physical_frame() = default; + constexpr physical_frame() = default; /** * @brief Constructor. * * @param frame_number Index number that should be assigned to this physical frame. */ - explicit physical_frame(std::size_t frame_number); + explicit constexpr physical_frame(std::size_t frame_number) + : frame_number(frame_number) + { + // Nothing to do + } /** * @brief Returns the physical frame the given address is contained in. diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 3931db3..c62a02e 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -9,7 +9,7 @@ namespace teachos::arch::memory::paging { namespace { - std::size_t constexpr UNUSED_VIRTUAL_ADDRESS = 0xCAFEBABE; + virtual_page constexpr UNUSED_VIRTUAL_PAGE{0xCAFEBABE}; } // namespace typedef shared::container frame_container; @@ -45,8 +45,7 @@ namespace teachos::arch::memory::paging */ auto remap_kernel() -> void { - virtual_page temporary_address{UNUSED_VIRTUAL_ADDRESS}; - temporary_page temporary_page{temporary_address, allocator}; + temporary_page temporary_page{UNUSED_VIRTUAL_PAGE, allocator}; auto & active_table = active_page_table::create_or_get(); auto const frame = allocator.allocate_frame(); exception_handling::assert(frame.has_value(), diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index 8c5613d..c319af2 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -22,7 +22,11 @@ namespace teachos::arch::memory::paging * * @param page_number Index number of the current virtual page, used to distinguish it from other pages. */ - explicit virtual_page(std::size_t page_number); + explicit constexpr virtual_page(std::size_t page_number) + : page_number(page_number) + { + // Nothing to do + } /** * @brief Returns the virtual page the given address is contained in. diff --git a/arch/x86_64/src/memory/allocator/physical_frame.cpp b/arch/x86_64/src/memory/allocator/physical_frame.cpp index 9307602..227745a 100644 --- a/arch/x86_64/src/memory/allocator/physical_frame.cpp +++ b/arch/x86_64/src/memory/allocator/physical_frame.cpp @@ -2,12 +2,6 @@ namespace teachos::arch::memory::allocator { - physical_frame::physical_frame(std::size_t frame_number) - : frame_number(frame_number) - { - // Nothing to do - } - auto physical_frame::containing_address(physical_address address) -> physical_frame { return physical_frame{address / PAGE_FRAME_SIZE}; diff --git a/arch/x86_64/src/memory/paging/virtual_page.cpp b/arch/x86_64/src/memory/paging/virtual_page.cpp index c0ec88d..f798709 100644 --- a/arch/x86_64/src/memory/paging/virtual_page.cpp +++ b/arch/x86_64/src/memory/paging/virtual_page.cpp @@ -4,12 +4,6 @@ namespace teachos::arch::memory::paging { - virtual_page::virtual_page(std::size_t page_number) - : page_number(page_number) - { - // Nothing to do - } - auto virtual_page::containing_address(virtual_address address) -> virtual_page { exception_handling::assert(address < 0x00008000'00000000 || address >= 0xffff8000'00000000, -- cgit v1.2.3 From d971ee4dd26d928d9590ccbf8e39220d81787a98 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 3 Nov 2024 13:22:34 +0000 Subject: align elf sections to 4kb --- arch/x86_64/scripts/kernel.ld | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index 3449828..e9d245f 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -37,31 +37,28 @@ SECTIONS * data, followed by our code, initialized mutable data, and finally our * uninitialized mutable data. ***************************************************************************/ - .boot_rodata : + .boot_rodata ALIGN(4K) : AT(ADDR (.boot_rodata)) { KEEP(*(.boot_mbh)) *(.boot_rodata) } :boot_rodata - .boot_text : + .boot_text ALIGN(4K) : AT(ADDR (.boot_text)) { *(.boot_text) } :boot_text - .boot_data : + .boot_data ALIGN(4K) : AT(ADDR (.boot_data)) { *(.boot_data) } :boot_data - .boot_bss : + .boot_bss ALIGN(4K) : AT(ADDR (.boot_bss)) { *(.boot_bss) *(.boot_stack) } - . = ALIGN(4K); - _end_of_image = .; - /*************************************************************************** * Now it is time to load the 64-bit kernel code. We virtually load it into * the upper 2GiB, while adjusting the linear load address appropriately. We -- cgit v1.2.3 From 74c53bed107b87f064484b926d8ed02018eb3a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 3 Nov 2024 13:23:40 +0000 Subject: Adjust comment --- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 3 ++- arch/x86_64/include/arch/memory/paging/temporary_page.hpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index c62a02e..f30ca24 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -75,7 +75,7 @@ namespace teachos::arch::memory::paging auto remap_elf_kernel_sections(inactive_page_table inactive_table, temporary_page & temporary_page, active_page_table & active_table) -> void { - auto physical_address = active_table.translate_address(PAGE_TABLE_LEVEL_4_ADDRESS); + auto const physical_address = active_table.translate_address(PAGE_TABLE_LEVEL_4_ADDRESS); exception_handling::assert(physical_address.has_value(), "[Kernel Mapper] Physical address for active table not mapped"); @@ -100,6 +100,7 @@ namespace teachos::arch::memory::paging */ auto map_elf_kernel_sections(active_page_table & active_table) -> void { + exception_handling::assert(!mem_info.sections.empty(), "[Kernel Mapper] Kernel elf sections empty"); for (auto const & section : mem_info.sections) { if (!section.flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp index 8b49894..b93a375 100644 --- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -61,7 +61,7 @@ namespace teachos::arch::memory::paging */ auto map_to_frame(allocator::physical_frame frame, active_page_table & active_table) -> virtual_address; - virtual_page page; ///< Underlying virtual page we want to temporarily map a level 4 page table into. + virtual_page page; ///< Underlying virtual page we want to temporarily map. allocator::tiny_frame_allocator allocator; ///< Allocator that should be used to map the temporary page. }; } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From db70018fc76800dd56b4421be797bffd00d7619d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 3 Nov 2024 13:52:22 +0000 Subject: Convert elf section flags to entry flags --- .../include/arch/memory/paging/kernel_mapper.hpp | 4 ++-- .../include/arch/memory/paging/page_entry.hpp | 20 ++++++++++++++++++++ arch/x86_64/src/memory/paging/page_entry.cpp | 22 +++++++++++++++++++++- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index f30ca24..54ec682 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -116,11 +116,11 @@ namespace teachos::arch::memory::paging allocator::physical_frame_iterator const begin{start_frame}; allocator::physical_frame_iterator const end{end_frame}; frame_container frames{begin, end}; + entry entry{section.flags}; for (auto const & frame : frames) { - // TODO: Use actual elf section flags, convert from one to the other flag type. - active_table.identity_map(allocator, frame, entry::WRITABLE); + active_table.identity_map(allocator, frame, entry.get_flags()); } } } diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index 5959801..ab9659d 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -2,6 +2,7 @@ #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_ENTRY_HPP #include "arch/memory/allocator/physical_frame.hpp" +#include "arch/memory/multiboot/elf_symbols_section.hpp" #include #include @@ -47,6 +48,18 @@ namespace teachos::arch::memory::paging */ explicit entry(uint64_t flags); + /** + * @brief Converts the given elf section flags into the corresponding correct entry flags. + * + * @note Enables us to set the correct flags on a entry depending on which elf section it is contained in. For + * example entries of .text sections should be executable and read only or entries of .data sections should be + * writable but not executable. + * + * @param elf_flags Elf section flags we want to convert into entry flags. + * @return Entry that has the corresponding bit flags set. + */ + explicit entry(multiboot::elf_section_flags elf_flags); + /** * @brief Whether the current page is unused, meaning the underlying std::bitset is 0. * @@ -86,6 +99,13 @@ namespace teachos::arch::memory::paging */ auto contains_flags(std::bitset<64U> other) const -> bool; + /** + * @brief Extracts only the flags from the underlying entry and ignores all bits that contain the physical address. + * + * @return Extracted entry flags, without the physical address. + */ + auto get_flags() -> std::bitset<64U>; + private: std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be ///< freely used for additional flags by the operating system. diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 23c700f..5c4bc67 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -7,7 +7,8 @@ namespace teachos::arch::memory::paging namespace { std::size_t constexpr PHYSICAL_ADDRESS_MASK = 0x000fffff'fffff000; - } + std::size_t constexpr ENTRY_FLAGS_MASK = 0xfff00000'00000fff; + } // namespace entry::entry(uint64_t flags) : flags(flags) @@ -15,6 +16,23 @@ namespace teachos::arch::memory::paging // Nothing to do. } + entry::entry(multiboot::elf_section_flags elf_flags) + { + if (elf_flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) + { + flags = flags.to_ulong() | entry::PRESENT; + } + if (elf_flags.contains_flags(multiboot::elf_section_flags::WRITABLE)) + { + flags = flags.to_ulong() | entry::WRITABLE; + } + if (!elf_flags.contains_flags(multiboot::elf_section_flags::EXECUTABLE_CODE)) + { + // TODO: Ensure to set the NXE bit, if we don't using this entry flag causes crashes + // flags = flags.to_ulong() | entry::EXECUTING_CODE_FORBIDDEN; + } + } + auto entry::is_unused() const -> bool { return flags == 0U; } auto entry::set_unused() -> void { flags = 0U; } @@ -37,4 +55,6 @@ namespace teachos::arch::memory::paging "[Paging Entry] Start address is not aligned with page"); flags = frame.start_address() | additional_flags.to_ulong(); } + + auto entry::get_flags() -> std::bitset<64U> { return flags.to_ulong() & ENTRY_FLAGS_MASK; } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From e20b9a2acd77ab6df00ee4a9390aaef8c6941dc6 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 3 Nov 2024 13:55:59 +0000 Subject: remove elf flags mask --- arch/x86_64/src/memory/paging/page_entry.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 5c4bc67..f13e645 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -7,7 +7,6 @@ namespace teachos::arch::memory::paging namespace { std::size_t constexpr PHYSICAL_ADDRESS_MASK = 0x000fffff'fffff000; - std::size_t constexpr ENTRY_FLAGS_MASK = 0xfff00000'00000fff; } // namespace entry::entry(uint64_t flags) @@ -56,5 +55,5 @@ namespace teachos::arch::memory::paging flags = frame.start_address() | additional_flags.to_ulong(); } - auto entry::get_flags() -> std::bitset<64U> { return flags.to_ulong() & ENTRY_FLAGS_MASK; } + auto entry::get_flags() -> std::bitset<64U> { return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 95d8c279bf945c99ef207c12de3ab6a2bc14f380 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 3 Nov 2024 14:57:06 +0000 Subject: construct virtual_page using containing_address --- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 54ec682..2dd0387 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -9,7 +9,7 @@ namespace teachos::arch::memory::paging { namespace { - virtual_page constexpr UNUSED_VIRTUAL_PAGE{0xCAFEBABE}; + virtual_page UNUSED_VIRTUAL_PAGE = virtual_page::containing_address(0xCAFEBABE); } // namespace typedef shared::container frame_container; -- cgit v1.2.3 From 162bea11c7a4f1854cde53920b4c14b4eadf539d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 4 Nov 2024 12:13:44 +0000 Subject: WIP attempt to fix crashes --- .../arch/memory/allocator/physical_frame.hpp | 105 ++++------------ .../arch/memory/multiboot/elf_symbols_section.hpp | 6 +- .../include/arch/memory/multiboot/memory_map.hpp | 2 +- .../include/arch/memory/paging/kernel_mapper.hpp | 25 ++-- arch/x86_64/include/arch/shared/container.hpp | 5 +- .../include/arch/shared/random_access_iterator.hpp | 138 ++++++++++++++------- .../src/memory/allocator/area_frame_allocator.cpp | 12 +- .../x86_64/src/memory/allocator/physical_frame.cpp | 113 +++-------------- arch/x86_64/src/memory/multiboot/reader.cpp | 25 ++-- 9 files changed, 166 insertions(+), 265 deletions(-) diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp index 89e3cf8..43a22a2 100644 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -1,6 +1,9 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP #define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP +#include "arch/shared/container.hpp" +#include "arch/shared/random_access_iterator.hpp" + #include #include #include @@ -48,68 +51,19 @@ namespace teachos::arch::memory::allocator */ auto start_address() const -> physical_address; - /** - * @brief Defaulted equals operator. - */ - auto operator==(const physical_frame & other) const -> bool = default; - - /** - * @brief Defaulted three-way comparsion operator. - */ - auto operator<=>(const physical_frame & other) const -> std::partial_ordering = default; - - std::size_t frame_number = - {}; ///< Index number of the current physical frame, used to distinguish it from other frames. - }; - - /** - * @brief Iterator for the frame number - */ - struct physical_frame_iterator - { - using iterator_category = std::random_access_iterator_tag; ///< Iterator category of this type. - using difference_type = std::ptrdiff_t; ///< Type when diving one instance of this iterator by another. - using value_type = physical_frame; ///< Underlying value pointed to by this iterator. - - /** - * @brief Defaulted constructor. - */ - physical_frame_iterator() = default; - - /** - * @brief Constructor. - * - * @param value Underlying value the iterator should point too - */ - explicit physical_frame_iterator(value_type value); - - /** - * @brief Dereferences the initally given pointer to its value. - * - * @return Reference to the value. - */ - auto operator*() -> value_type &; - - /** - * @brief Get underlying value, which is the intially passed pointer. - * - * @return Underlying value passed intially. - */ - auto operator->() -> value_type *; - /** * @brief Post increment operator. Returns a copy of the value. * * @return Copy of the incremented underlying address. */ - auto operator++(int) -> physical_frame_iterator; + auto operator++(int) -> physical_frame; /** * @brief Pre increment operator. Returns a reference to the changed value. * * @return Reference to the incremented underlying address. */ - auto operator++() -> physical_frame_iterator &; + auto operator++() -> physical_frame &; /** * @brief Addition assignment operator. Returns a reference to the changed value. @@ -117,7 +71,7 @@ namespace teachos::arch::memory::allocator * @param operand Value we want to add to the underlying address. * @return Reference to the changed underlying address. */ - auto operator+=(difference_type operand) -> physical_frame_iterator &; + auto operator+=(std::size_t operand) -> physical_frame &; /** * @brief Subtraction assignment operator. Returns a reference to the changed value. @@ -125,23 +79,21 @@ namespace teachos::arch::memory::allocator * @param operand Value we want to subtract from the underlying address. * @return Reference to the changed underlying address. */ - auto operator-=(difference_type operand) -> physical_frame_iterator &; + auto operator-=(std::size_t operand) -> physical_frame &; /** - * @brief Addition operator. Returns the changed value. + * @brief Post increment operator. Returns a copy of the value. * - * @param operand Value we want to add to a copy of the underlying address. - * @return Copy of underlying address incremented by the given value. + * @return Copy of the incremented underlying address. */ - auto operator+(difference_type operand) const -> physical_frame_iterator; + auto operator+(std::size_t operand) const -> physical_frame; /** - * @brief Subtraction operator. Returns the changed value. + * @brief Pre increment operator. Returns a reference to the changed value. * - * @param operand Value we want to subtrcat from a copy of the underlying address. - * @return Copy of underlying address decremented by the given value. + * @return Reference to the incremented underlying address. */ - auto operator-(difference_type operand) const -> physical_frame_iterator; + auto operator-(std::size_t operand) const -> physical_frame; /** * @brief Subtraction operator. Returns the size difference between two iterators. @@ -149,36 +101,23 @@ namespace teachos::arch::memory::allocator * @param other Other iterator we want to substract the underlying address with ours. * @return Size difference between the underlying address of this instance and the given iterator. */ - auto operator-(const physical_frame_iterator & other) const -> difference_type; - - /** - * @brief Index operator overload. Returns a reference to the value at the given index. Simply returns the - * dereferenced underlying pointer incremented by the given index. - * - * @param index Index we want to access and get the value from. - * @return Reference to the value at the given index. - */ - auto operator[](difference_type index) const -> value_type; + auto operator-(physical_frame const & other) const -> std::size_t; /** - * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. - * - * @param other Other iterator to compare to. - * @return Whether both iterators point to the same underlying address in memory. + * @brief Defaulted equals operator. */ - auto operator==(physical_frame_iterator const & other) const -> bool = default; + auto operator==(physical_frame const & other) const -> bool = default; /** - * @brief Defaulted threeway comparsion operator. Simply compares the memory address of both iterators. - * - * @param other Other iterator to compare to. - * @return Whether the given iterator is smaller or larger than this iterator. + * @brief Defaulted three-way comparsion operator. */ - auto operator<=>(physical_frame_iterator const & other) const -> std::strong_ordering = default; + auto operator<=>(physical_frame const & other) const -> std::partial_ordering = default; - private: - value_type value = {}; ///< Underlying address the iterator is currently pointing too. + std::size_t frame_number = + {}; ///< Index number of the current physical frame, used to distinguish it from other frames. }; + + typedef shared::container> frame_container; } // namespace teachos::arch::memory::allocator #endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp index e29590d..6227fc9 100644 --- a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp @@ -122,8 +122,8 @@ namespace teachos::arch::memory::multiboot elf_section_flags flags; ///< 1-bit flgas that describe section attributes. uint64_t physical_address; ///< If section appears in memory image of a process, gives address at which the ///< sections first byte should reside, otherwise 0. - uint64_t file_offset; ///< Offset from the beginning of the file to the first byte in the section. SHT_NOBITS - ///< contains the conceptual placement instead (because it occupies no space in the file). + uint64_t file_offset; ///< Offset from the beginning of the file to the first byte in the section. SHT_NOBITS + ///< contains the conceptual placement instead (because it occupies no space in the file). uint64_t section_size; ///< Complete section size in bytes, SHT_NOBITS may have non-zero value but will always ///< occupy no space in the file. uint32_t other_section; ///< Section header table index link, behaviour varies on type @@ -162,7 +162,7 @@ namespace teachos::arch::memory::multiboot ///< contained in the section, to ensure byte alignment is actually 4 byte. }; - typedef shared::container> elf_section_header_container; + typedef shared::container> elf_section_header_container; } // namespace teachos::arch::memory::multiboot #endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp index 910eecb..ccd5cf0 100644 --- a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp @@ -46,7 +46,7 @@ namespace teachos::arch::memory::multiboot struct memory_area entries; ///< Specific memory regions. }; - typedef shared::container> memory_area_container; + typedef shared::container> memory_area_container; } // namespace teachos::arch::memory::multiboot #endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 2dd0387..d301c91 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -9,11 +9,9 @@ namespace teachos::arch::memory::paging { namespace { - virtual_page UNUSED_VIRTUAL_PAGE = virtual_page::containing_address(0xCAFEBABE); + virtual_page constexpr UNUSED_VIRTUAL_PAGE(0xCAFEBABE); } // namespace - typedef shared::container frame_container; - /** * @brief Kernel mapper that allows to remap the kernel elf sections in C++. * @@ -103,20 +101,23 @@ namespace teachos::arch::memory::paging exception_handling::assert(!mem_info.sections.empty(), "[Kernel Mapper] Kernel elf sections empty"); for (auto const & section : mem_info.sections) { - if (!section.flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) + if (!section->flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) { continue; } - exception_handling::assert(section.physical_address % allocator::PAGE_FRAME_SIZE == 0U, + exception_handling::assert(section->physical_address % allocator::PAGE_FRAME_SIZE == 0U, "[Kernel Mapper] Section must be page aligned"); - auto const start_frame = allocator::physical_frame::containing_address(section.physical_address); - auto const end_frame = - allocator::physical_frame::containing_address(section.physical_address + section.section_size); + auto const start_frame = allocator::physical_frame::containing_address(section->physical_address); + // End address is exclusive, so that it is not part of the section anymore (one past the last frame of this + // section). But end frame would now point to the actual last frame and not one past the last frame, therefore + // we increment by one to get one past the last frame of this section. + auto end_frame = + ++(allocator::physical_frame::containing_address(section->physical_address + section->section_size - 1)); - allocator::physical_frame_iterator const begin{start_frame}; - allocator::physical_frame_iterator const end{end_frame}; - frame_container frames{begin, end}; - entry entry{section.flags}; + allocator::frame_container::iterator const begin{start_frame}; + allocator::frame_container::iterator const end{end_frame}; + allocator::frame_container frames{begin, end}; + entry entry{section->flags}; for (auto const & frame : frames) { diff --git a/arch/x86_64/include/arch/shared/container.hpp b/arch/x86_64/include/arch/shared/container.hpp index bc2a5f6..9b4192e 100644 --- a/arch/x86_64/include/arch/shared/container.hpp +++ b/arch/x86_64/include/arch/shared/container.hpp @@ -1,12 +1,13 @@ #ifndef TEACHOS_ARCH_X86_64_SHARED_CONTAINER_HPP #define TEACHOS_ARCH_X86_64_SHARED_CONTAINER_HPP -#include "arch/exception_handling/assert.hpp" - #include namespace teachos::arch::shared { + template + concept Iterator = std::contiguous_iterator; + /** * @brief Read-only container for given template type, that allow to easily use this container instance in C++20 * ranges calls. diff --git a/arch/x86_64/include/arch/shared/random_access_iterator.hpp b/arch/x86_64/include/arch/shared/random_access_iterator.hpp index b1a800c..69617f3 100644 --- a/arch/x86_64/include/arch/shared/random_access_iterator.hpp +++ b/arch/x86_64/include/arch/shared/random_access_iterator.hpp @@ -5,18 +5,25 @@ namespace teachos::arch::shared { + template + concept Iterable = std::incrementable && std::three_way_comparable && std::indirectly_readable; + /** - * @brief Generic random access iterator for given template type. Can be a nullptr, ensure to check when using this - * iterator. Allows to easily use this iterator instance in algorithm calls. + * @brief Generic random access iterator for given template type. Allows any value that Allows to easily use this + * iterator instance in algorithm calls. * * @tparam T Value the iterator points too. */ - template + template struct random_access_iterator { - using iterator_category = std::random_access_iterator_tag; ///< Iterator category of this type. - using difference_type = std::ptrdiff_t; ///< Type when diving one instance of this iterator by another. - using value_type = T; ///< Underlying value pointed to by this iterator. + using iterator_category = std::contiguous_iterator_tag; ///< Iterator category of this type. + using difference_type = std::ptrdiff_t; ///< Type when diving one instance of this iterator by another. + using value_type = T; ///< Underlying value pointed to by this iterator. + using reference_type = value_type &; ///< Reference to value returned by dereference * operation. + using pointer_type = value_type *; ///< Pointer to value returned by arrow -> operation. + using const_reference_type = value_type const &; ///< Reference to value returned by const dereference * operation. + using const_pointer_type = value_type const *; ///< Pointer to value returned by const arrow -> operation. /** * @brief Defaulted constructor. @@ -26,124 +33,162 @@ namespace teachos::arch::shared /** * @brief Constructor. * - * @param p Underlying address the iterator should point too. + * @param value Underlying value the iterator should point too and increment or decrement. */ - explicit random_access_iterator(value_type * p) - : ptr(p) + explicit random_access_iterator(value_type value) + : value(value) { // Nothing to do } /** - * @brief Dereferences the initally given pointer to its value. + * @brief Gets a reference to the underlying value. * * @return Reference to the value. */ - auto operator*() const -> value_type & { return *ptr; } + auto operator*() -> reference_type { return value; } /** - * @brief Get underlying value, which is the intially passed pointer. + * @brief Gets a pointer to the underlying value. * * @return Underlying value passed intially. */ - auto operator->() const -> value_type * { return ptr; } + auto operator->() -> pointer_type { return &value; } /** - * @brief Post increment operator. Returns a copy of the value. + * @brief Gets a const reference to the underlying value. * - * @return Copy of the incremented underlying address. + * @return Reference to the value. */ - auto operator++(int) -> random_access_iterator + auto operator*() const -> const_reference_type { return value; } + + /** + * @brief Gets a const pointer to the underlying value. + * + * @return Underlying value passed intially. + */ + auto operator->() const -> const_pointer_type { return &value; } + + /** + * @brief Pre decrement operator. Returns a reference to the changed value. + * + * @return Reference to the decrement underlying value. + */ + auto operator--() -> random_access_iterator & { - random_access_iterator const old_value = *this; - ++ptr; - return old_value; + --value; + return *this; } /** * @brief Pre increment operator. Returns a reference to the changed value. * - * @return Reference to the incremented underlying address. + * @return Reference to the incremented underlying value. */ auto operator++() -> random_access_iterator & { - ++ptr; + ++value; return *this; } + /** + * @brief Post decrement operator. Returns a copy of the value. + * + * @return Copy of the decremented underlying value. + */ + auto operator--(int) -> random_access_iterator + { + auto const old_value = *this; + --value; + return old_value; + } + + /** + * @brief Post increment operator. Returns a copy of the value. + * + * @return Copy of the incremented underlying value. + */ + auto operator++(int) -> random_access_iterator + { + auto const old_value = *this; + ++value; + return old_value; + } + /** * @brief Addition assignment operator. Returns a reference to the changed value. * - * @param value Value we want to add to the underlying address. - * @return Reference to the changed underlying address. + * @param operand Value we want to add to the underlying value the iterator is pointing too. + * @return Reference to the changed underlying value. */ - auto operator+=(difference_type value) -> random_access_iterator & + auto operator+=(difference_type operand) -> random_access_iterator & { - ptr += value; + value += operand; return *this; } /** * @brief Subtraction assignment operator. Returns a reference to the changed value. * - * @param value Value we want to subtract from the underlying address. - * @return Reference to the changed underlying address. + * @param operand Value we want to subtract from the underlying value the iterator is pointing too. + * @return Reference to the changed underlying value. */ - auto operator-=(difference_type value) -> random_access_iterator & + auto operator-=(difference_type operand) -> random_access_iterator & { - ptr -= value; + value -= operand; return *this; } /** * @brief Addition operator. Returns the changed value. * - * @param value Value we want to add to a copy of the underlying address. - * @return Copy of underlying address incremented by the given value. + * @param operand Value we want to add to a copy of the underlying value the iterator is pointing too. + * @return Copy of underlying value incremented by the given value. */ - auto operator+(difference_type value) const -> random_access_iterator + auto operator+(difference_type operand) const -> random_access_iterator { - return random_access_iterator{ptr + value}; + return random_access_iterator{value + operand}; } /** * @brief Subtraction operator. Returns the changed value. * - * @param value Value we want to subtrcat from a copy of the underlying address. - * @return Copy of underlying address decremented by the given value. + * @param operand Value we want to subtract from a copy of the underlying value the iterator is pointing too. + * @return Copy of underlying value decremented by the given value. */ - auto operator-(difference_type value) const -> random_access_iterator + auto operator-(difference_type operand) const -> random_access_iterator { - return random_access_iterator{ptr - value}; + return random_access_iterator{value - operand}; } /** * @brief Subtraction operator. Returns the size difference between two iterators. * - * @param other Other iterator we want to substract the underlying address with ours. - * @return Size difference between the underlying address of this instance and the given iterator. + * @param other Other iterator we want to substract the underlying value with ours. + * @return Size difference between the underlying value of this instance and the given iterator. */ - auto operator-(const random_access_iterator & other) const -> difference_type { return ptr - other.ptr; } + auto operator-(random_access_iterator const & other) const -> difference_type { return value - other.value; } /** * @brief Index operator overload. Returns a reference to the value at the given index. Simply returns the - * dereferenced underlying pointer incremented by the given index. + * underlying value the iterator is pointing too incremented by the given index. * * @param index Index we want to access and get the value from. * @return Reference to the value at the given index. */ - auto operator[](difference_type index) const -> value_type & { return *(ptr + index); } + auto operator[](difference_type index) const -> value_type const & { return value + index; } /** - * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. + * @brief Defaulted comparsion operator. Forwards to the comparsion operator of the given template type. * * @param other Other iterator to compare to. - * @return Whether both iterators point to the same underlying address in memory. + * @return Whether both iterators point to the same underlying value in memory. */ auto operator==(random_access_iterator const & other) const -> bool = default; /** - * @brief Defaulted threeway comparsion operator. Simply compares the memory address of both iterators. + * @brief Defaulted threeway comparsion operator. Forwards to the threeway comparsion operator of the given + * template type. * * @param other Other iterator to compare to. * @return Whether the given iterator is smaller or larger than this iterator. @@ -151,7 +196,8 @@ namespace teachos::arch::shared auto operator<=>(random_access_iterator const & other) const -> std::strong_ordering = default; private: - value_type * ptr = {}; ///< Underlying address the iterator is currently pointing too. + value_type value = + {}; ///< Underlying value the iterator is currently pointing too and should increment or decrement. }; } // namespace teachos::arch::shared diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index da4a919..42aff68 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -23,19 +23,17 @@ namespace teachos::arch::memory::allocator auto area_frame_allocator::choose_next_area() -> void { current_area = std::nullopt; - auto next_area_with_free_frames = memory_areas | std::views::filter([this](multiboot::memory_area const & area) { - auto address = area.base_address + area.area_length - 1; + 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, [](multiboot::memory_area a, multiboot::memory_area b) { - return a.base_address < b.base_address; - }); + 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; + 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) diff --git a/arch/x86_64/src/memory/allocator/physical_frame.cpp b/arch/x86_64/src/memory/allocator/physical_frame.cpp index 227745a..63d84ec 100644 --- a/arch/x86_64/src/memory/allocator/physical_frame.cpp +++ b/arch/x86_64/src/memory/allocator/physical_frame.cpp @@ -9,126 +9,43 @@ namespace teachos::arch::memory::allocator auto physical_frame::start_address() const -> physical_address { return frame_number * PAGE_FRAME_SIZE; } - /** - * @brief Constructor. - * - * @param value Underlying value the iterator should point too - */ - physical_frame_iterator::physical_frame_iterator(physical_frame_iterator::value_type value) - : value(value) + auto physical_frame::operator++(int) -> physical_frame { - // Nothing to do - } - - /** - * @brief Dereferences the initally given pointer to its value. - * - * @return Reference to the value. - */ - auto physical_frame_iterator::operator*() -> physical_frame_iterator::value_type & { return value; } - - /** - * @brief Get underlying value, which is the intially passed pointer. - * - * @return Underlying value passed intially. - */ - auto physical_frame_iterator::operator->() -> physical_frame_iterator::value_type * { return &value; } - - /** - * @brief Post increment operator. Returns a copy of the value. - * - * @return Copy of the incremented underlying address. - */ - auto physical_frame_iterator::operator++(int) -> physical_frame_iterator - { - physical_frame_iterator const old_value = *this; - ++value.frame_number; + physical_frame const old_value = *this; + ++frame_number; return old_value; } - /** - * @brief Pre increment operator. Returns a reference to the changed value. - * - * @return Reference to the incremented underlying address. - */ - auto physical_frame_iterator::operator++() -> physical_frame_iterator & + auto physical_frame::operator++() -> physical_frame & { - ++value.frame_number; + ++frame_number; return *this; } - /** - * @brief Addition assignment operator. Returns a reference to the changed value. - * - * @param operand Value we want to add to the underlying address. - * @return Reference to the changed underlying address. - */ - auto - physical_frame_iterator::operator+=(physical_frame_iterator::difference_type operand) -> physical_frame_iterator & + auto physical_frame::operator+=(std::size_t operand) -> physical_frame & { - value.frame_number += operand; + frame_number += operand; return *this; } - /** - * @brief Subtraction assignment operator. Returns a reference to the changed value. - * - * @param operand Value we want to subtract from the underlying address. - * @return Reference to the changed underlying address. - */ - auto - physical_frame_iterator::operator-=(physical_frame_iterator::difference_type operand) -> physical_frame_iterator & + auto physical_frame::operator-=(std::size_t operand) -> physical_frame & { - value.frame_number -= operand; + frame_number -= operand; return *this; } - /** - * @brief Addition operator. Returns the changed value. - * - * @param operand Value we want to add to a copy of the underlying address. - * @return Copy of underlying address incremented by the given value. - */ - auto - physical_frame_iterator::operator+(physical_frame_iterator::difference_type operand) const -> physical_frame_iterator - { - return physical_frame_iterator{physical_frame_iterator::value_type{value.frame_number + operand}}; - } - - /** - * @brief Subtraction operator. Returns the changed value. - * - * @param operand Value we want to subtrcat from a copy of the underlying address. - * @return Copy of underlying address decremented by the given value. - */ - auto - physical_frame_iterator::operator-(physical_frame_iterator::difference_type operand) const -> physical_frame_iterator + auto physical_frame::operator+(std::size_t operand) const -> physical_frame { - return physical_frame_iterator{physical_frame_iterator::value_type{value.frame_number - operand}}; + return physical_frame{frame_number + operand}; } - /** - * @brief Subtraction operator. Returns the size difference between two iterators. - * - * @param other Other iterator we want to substract the underlying address with ours. - * @return Size difference between the underlying address of this instance and the given iterator. - */ - auto physical_frame_iterator::operator-(const physical_frame_iterator & other) const - -> physical_frame_iterator::difference_type + auto physical_frame::operator-(std::size_t operand) const -> physical_frame { - return value.frame_number - other.value.frame_number; + return physical_frame{frame_number - operand}; } - /** - * @brief Index operator overload. Returns a reference to the value at the given index. Simply returns the - * dereferenced underlying pointer incremented by the given index. - * - * @param index Index we want to access and get the value from. - * @return Reference to the value at the given index. - */ - auto physical_frame_iterator::operator[](physical_frame_iterator::difference_type index) const - -> physical_frame_iterator::value_type + auto physical_frame::operator-(const physical_frame & other) const -> std::size_t { - return physical_frame_iterator::value_type{value.frame_number + index}; + return frame_number - other.frame_number; } } // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp index 4576085..178cc45 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -51,28 +51,27 @@ namespace teachos::arch::memory::multiboot 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(), + 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 const elf_section_with_lowest_physical_address = - std::ranges::min_element(sections, [](elf_section_header const & a, elf_section_header const & b) { - return a.physical_address < b.physical_address; - }); + auto const elf_section_with_lowest_physical_address = std::ranges::min_element( + 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(sections, [](elf_section_header const & a, elf_section_header const & b) { - auto a_physical_address_end = a.physical_address + a.section_size; - auto b_physical_address_end = b.physical_address + b.section_size; + std::ranges::max_element(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, [](elf_section_header const & section) { - return section.type == elf_section_type::DYNAMIC_SYMBOL_TABLE || section.type == elf_section_type::SYMBOL_TABLE; + 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, [](elf_section_header const & section) { return section.type == elf_section_type::DYNAMIC; }); + sections, [](auto const & section) { return section->type == elf_section_type::DYNAMIC; }); exception_handling::assert( symbol_table_section_count == 1U, @@ -82,10 +81,10 @@ namespace teachos::arch::memory::multiboot "[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; + 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; + kernel_end = highest_elf_section->physical_address + highest_elf_section->section_size; return sections; } -- cgit v1.2.3 From 30466aeb3da181c21bd451f32c1ff97e53a55dbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 4 Nov 2024 13:29:03 +0000 Subject: Use more concepts and seperate iterator implementations --- .../arch/memory/allocator/physical_frame.hpp | 42 +---- .../arch/memory/multiboot/elf_symbols_section.hpp | 4 +- .../include/arch/memory/multiboot/memory_map.hpp | 4 +- .../include/arch/memory/paging/kernel_mapper.hpp | 10 +- arch/x86_64/include/arch/shared/container.hpp | 10 +- .../arch/shared/contiguous_pointer_iterator.hpp | 189 +++++++++++++++++++ .../include/arch/shared/forward_value_iterator.hpp | 109 +++++++++++ .../include/arch/shared/random_access_iterator.hpp | 204 --------------------- .../src/memory/allocator/area_frame_allocator.cpp | 6 +- .../x86_64/src/memory/allocator/physical_frame.cpp | 27 --- arch/x86_64/src/memory/multiboot/reader.cpp | 17 +- 11 files changed, 327 insertions(+), 295 deletions(-) create mode 100644 arch/x86_64/include/arch/shared/contiguous_pointer_iterator.hpp create mode 100644 arch/x86_64/include/arch/shared/forward_value_iterator.hpp delete mode 100644 arch/x86_64/include/arch/shared/random_access_iterator.hpp diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp index 43a22a2..a39517a 100644 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -2,7 +2,7 @@ #define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP #include "arch/shared/container.hpp" -#include "arch/shared/random_access_iterator.hpp" +#include "arch/shared/forward_value_iterator.hpp" #include #include @@ -65,44 +65,6 @@ namespace teachos::arch::memory::allocator */ auto operator++() -> physical_frame &; - /** - * @brief Addition assignment operator. Returns a reference to the changed value. - * - * @param operand Value we want to add to the underlying address. - * @return Reference to the changed underlying address. - */ - auto operator+=(std::size_t operand) -> physical_frame &; - - /** - * @brief Subtraction assignment operator. Returns a reference to the changed value. - * - * @param operand Value we want to subtract from the underlying address. - * @return Reference to the changed underlying address. - */ - auto operator-=(std::size_t operand) -> physical_frame &; - - /** - * @brief Post increment operator. Returns a copy of the value. - * - * @return Copy of the incremented underlying address. - */ - auto operator+(std::size_t operand) const -> physical_frame; - - /** - * @brief Pre increment operator. Returns a reference to the changed value. - * - * @return Reference to the incremented underlying address. - */ - auto operator-(std::size_t operand) const -> physical_frame; - - /** - * @brief Subtraction operator. Returns the size difference between two iterators. - * - * @param other Other iterator we want to substract the underlying address with ours. - * @return Size difference between the underlying address of this instance and the given iterator. - */ - auto operator-(physical_frame const & other) const -> std::size_t; - /** * @brief Defaulted equals operator. */ @@ -117,7 +79,7 @@ namespace teachos::arch::memory::allocator {}; ///< Index number of the current physical frame, used to distinguish it from other frames. }; - typedef shared::container> frame_container; + typedef shared::container> frame_container; } // namespace teachos::arch::memory::allocator #endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp index 6227fc9..549839a 100644 --- a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp @@ -3,7 +3,7 @@ #include "arch/memory/multiboot/info.hpp" #include "arch/shared/container.hpp" -#include "arch/shared/random_access_iterator.hpp" +#include "arch/shared/contiguous_pointer_iterator.hpp" #include #include @@ -162,7 +162,7 @@ namespace teachos::arch::memory::multiboot ///< contained in the section, to ensure byte alignment is actually 4 byte. }; - typedef shared::container> elf_section_header_container; + typedef shared::container> elf_section_header_container; } // namespace teachos::arch::memory::multiboot #endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp index ccd5cf0..413f5a1 100644 --- a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp @@ -3,7 +3,7 @@ #include "arch/memory/multiboot/info.hpp" #include "arch/shared/container.hpp" -#include "arch/shared/random_access_iterator.hpp" +#include "arch/shared/contiguous_pointer_iterator.hpp" #include @@ -46,7 +46,7 @@ namespace teachos::arch::memory::multiboot struct memory_area entries; ///< Specific memory regions. }; - typedef shared::container> memory_area_container; + typedef shared::container> memory_area_container; } // namespace teachos::arch::memory::multiboot #endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index d301c91..2eb3c4a 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -101,23 +101,23 @@ namespace teachos::arch::memory::paging exception_handling::assert(!mem_info.sections.empty(), "[Kernel Mapper] Kernel elf sections empty"); for (auto const & section : mem_info.sections) { - if (!section->flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) + if (!section.flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) { continue; } - exception_handling::assert(section->physical_address % allocator::PAGE_FRAME_SIZE == 0U, + exception_handling::assert(section.physical_address % allocator::PAGE_FRAME_SIZE == 0U, "[Kernel Mapper] Section must be page aligned"); - auto const start_frame = allocator::physical_frame::containing_address(section->physical_address); + auto const start_frame = allocator::physical_frame::containing_address(section.physical_address); // End address is exclusive, so that it is not part of the section anymore (one past the last frame of this // section). But end frame would now point to the actual last frame and not one past the last frame, therefore // we increment by one to get one past the last frame of this section. auto end_frame = - ++(allocator::physical_frame::containing_address(section->physical_address + section->section_size - 1)); + ++(allocator::physical_frame::containing_address(section.physical_address + section.section_size - 1)); allocator::frame_container::iterator const begin{start_frame}; allocator::frame_container::iterator const end{end_frame}; allocator::frame_container frames{begin, end}; - entry entry{section->flags}; + entry entry{section.flags}; for (auto const & frame : frames) { diff --git a/arch/x86_64/include/arch/shared/container.hpp b/arch/x86_64/include/arch/shared/container.hpp index 9b4192e..b335e72 100644 --- a/arch/x86_64/include/arch/shared/container.hpp +++ b/arch/x86_64/include/arch/shared/container.hpp @@ -5,16 +5,20 @@ namespace teachos::arch::shared { + /** + * @brief Minimal iterator concept required for usage in container + */ template - concept Iterator = std::contiguous_iterator; + concept Iterator = std::forward_iterator; /** * @brief Read-only container for given template type, that allow to easily use this container instance in C++20 * ranges calls. * - * @tparam T Iterator the container uses to signal the start and end of it's data. + * @tparam T Iterator the container uses to signal the start and end of it's data, has to atleast be a simple forward + * iterator. */ - template + template struct container { using iterator = T; ///< Iterators used by this container. diff --git a/arch/x86_64/include/arch/shared/contiguous_pointer_iterator.hpp b/arch/x86_64/include/arch/shared/contiguous_pointer_iterator.hpp new file mode 100644 index 0000000..7d5019a --- /dev/null +++ b/arch/x86_64/include/arch/shared/contiguous_pointer_iterator.hpp @@ -0,0 +1,189 @@ +#ifndef TEACHOS_ARCH_X86_64_SHARED_CONTIGUOUS_POINTER_ITERATOR_HPP +#define TEACHOS_ARCH_X86_64_SHARED_CONTIGUOUS_POINTER_ITERATOR_HPP + +#include + +namespace teachos::arch::shared +{ + /** + * @brief Generic contiguous iterator for given template type. Allows to easily use this iterator instance in + * algorithm calls. + * + * @note Allows any value that is contained in an array in memory, which is a block of contiguous memory. This is the + * case because we assume we can simply increment or decrement the pointer address to get the next valid instance of + * the given value type. + * + * @tparam T Value the iterator points too. + */ + template + struct contiguous_pointer_iterator + { + using iterator_category = std::contiguous_iterator_tag; ///< Iterator category of this type. + using difference_type = std::ptrdiff_t; ///< Type when diving one instance of this iterator by another. + using value_type = T; ///< Underlying value pointed to by this iterator. + using reference_type = value_type &; ///< Reference to value returned by dereference * operation. + using pointer_type = value_type *; ///< Pointer to value returned by arrow -> operation. + + /** + * @brief Defaulted constructor. + */ + contiguous_pointer_iterator() = default; + + /** + * @brief Constructor. + * + * @param p Underlying address the iterator should point too. + */ + explicit contiguous_pointer_iterator(value_type * p) + : ptr(p) + { + // Nothing to do + } + + /** + * @brief Dereferences the initally given pointer to its value. + * + * @return Reference to the value. + */ + auto operator*() const -> reference_type { return *ptr; } + + /** + * @brief Get underlying value, which is the intially passed pointer. + * + * @return Pointer to the underlying value passed intially. + */ + auto operator->() const -> pointer_type { return ptr; } + + /** + * @brief Pre decrement operator. Returns a reference to the changed address. + * + * @return Reference to the decremented underlying address. + */ + auto operator--() -> contiguous_pointer_iterator & + { + contiguous_pointer_iterator const old_value = *this; + ++ptr; + return old_value; + } + + /** + * @brief Pre increment operator. Returns a reference to the changed address. + * + * @return Reference to the incremented underlying address. + */ + auto operator++() -> contiguous_pointer_iterator & + { + ++ptr; + return *this; + } + + /** + * @brief Post decrement operator. Returns a copy of the address. + * + * @return Copy of the decremented underlying address. + */ + auto operator--(int) -> contiguous_pointer_iterator + { + auto const old_value = *this; + --ptr; + return old_value; + } + + /** + * @brief Post increment operator. Returns a copy of the address. + * + * @return Copy of the incremented underlying address. + */ + auto operator++(int) -> contiguous_pointer_iterator + { + auto const old_value = *this; + ++ptr; + return old_value; + } + + /** + * @brief Addition assignment operator. Returns a reference to the changed address. + * + * @param value Value we want to add to the underlying address. + * @return Reference to the changed underlying address. + */ + auto operator+=(difference_type value) -> contiguous_pointer_iterator & + { + ptr += value; + return *this; + } + + /** + * @brief Subtraction assignment operator. Returns a reference to the changed address. + * + * @param value Value we want to subtract from the underlying address. + * @return Reference to the changed underlying address. + */ + auto operator-=(difference_type value) -> contiguous_pointer_iterator & + { + ptr -= value; + return *this; + } + + /** + * @brief Addition operator. Returns the changed address. + * + * @param value Value we want to add to a copy of the underlying address. + * @return Copy of underlying address incremented by the given value. + */ + auto operator+(difference_type value) const -> contiguous_pointer_iterator + { + return contiguous_pointer_iterator{ptr + value}; + } + + /** + * @brief Subtraction operator. Returns the changed address. + * + * @param value Value we want to subtrcat from a copy of the underlying address. + * @return Copy of underlying address decremented by the given value. + */ + auto operator-(difference_type value) const -> contiguous_pointer_iterator + { + return contiguous_pointer_iterator{ptr - value}; + } + + /** + * @brief Subtraction operator. Returns the size difference between two iterators. + * + * @param other Other iterator we want to substract the underlying address with ours. + * @return Size difference between the underlying address of this instance and the given iterator. + */ + auto operator-(const contiguous_pointer_iterator & other) const -> difference_type { return ptr - other.ptr; } + + /** + * @brief Index operator overload. Returns a reference to the value at the given index. Simply returns the + * dereferenced underlying pointer incremented by the given index. + * + * @param index Index we want to access and get the value from. + * @return Reference to the value at the given index. + */ + auto operator[](difference_type index) const -> value_type & { return *(ptr + index); } + + /** + * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. + * + * @param other Other iterator to compare to. + * @return Whether both iterators point to the same underlying address in memory. + */ + auto operator==(contiguous_pointer_iterator const & other) const -> bool = default; + + /** + * @brief Defaulted threeway comparsion operator. Simply compares the memory address of both iterators. + * + * @param other Other iterator to compare to. + * @return Whether the given iterator is smaller or larger than this iterator. + */ + auto operator<=>(contiguous_pointer_iterator const & other) const -> std::strong_ordering = default; + + private: + pointer_type ptr = + {}; ///< Underlying value the iterator is currently pointing too and should increment or decrement. + }; +} // namespace teachos::arch::shared + +#endif // TEACHOS_ARCH_X86_64_SHARED_CONTIGUOUS_POINTER_ITERATOR_HPP diff --git a/arch/x86_64/include/arch/shared/forward_value_iterator.hpp b/arch/x86_64/include/arch/shared/forward_value_iterator.hpp new file mode 100644 index 0000000..a84d291 --- /dev/null +++ b/arch/x86_64/include/arch/shared/forward_value_iterator.hpp @@ -0,0 +1,109 @@ +#ifndef TEACHOS_ARCH_X86_64_SHARED_FORWARD_VALUE_ITERATOR_HPP +#define TEACHOS_ARCH_X86_64_SHARED_FORWARD_VALUE_ITERATOR_HPP + +#include + +namespace teachos::arch::shared +{ + /** + * @brief Concept for a type to have a post and prefix increment operator, that returns the correct type. + */ + template + concept Incrementable = requires(T t) { + { ++t } -> std::same_as; + { t++ } -> std::same_as; + }; + + /** + * @brief Iterable concept for the forward value iterator, meaning the type itself is incrementable and comparable. + */ + template + concept Iterable = std::regular && Incrementable; + + /** + * @brief Generic forward iterator for given template type. Allows to easily use this iterator + * instance in algorithm calls. + * + * @note Allows any value that itself can be incremented until we have reached the end, does not interact with the + * address of the value in any way. + * + * @tparam T Value the iterator contains. + */ + template + struct forward_value_iterator + { + using iterator_category = std::forward_iterator_tag; ///< Iterator category of this type. + using difference_type = std::ptrdiff_t; ///< Type when diving one instance of this iterator by another. + using value_type = T; ///< Underlying value contained by this iterator. + using const_reference_type = + value_type const &; ///< Constant reference to value returned by dereference * operation. + using const_pointer_type = value_type const *; ///< Constant pointer to value returned by arrow -> operation. + + /** + * @brief Defaulted constructor. + */ + forward_value_iterator() = default; + + /** + * @brief Constructor. + * + * @param value Underlying value the iterator contains. + */ + explicit forward_value_iterator(value_type value) + : value(value) + { + // Nothing to do + } + + /** + * @brief Returns the initally given value. + * + * @return Reference to the value. + */ + auto operator*() const -> const_reference_type { return value; } + + /** + * @brief Gets pointer to the underlying value passed intially. + * + * @return Pointer to the underlying value passed intially. + */ + auto operator->() const -> const_pointer_type { return &value; } + + /** + * @brief Pre increment operator. Returns a reference to the changed value. + * + * @return Reference to the incremented underlying value. + */ + auto operator++() -> forward_value_iterator & + { + ++value; + return *this; + } + + /** + * @brief Post increment operator. Returns a copy of the value. + * + * @return Copy of the incremented underlying value. + */ + auto operator++(int) -> forward_value_iterator + { + auto const old_value = *this; + ++value; + return old_value; + } + + /** + * @brief Defaulted comparsion operator. Simply compares the memory address of both iterators. + * + * @param other Other iterator to compare to. + * @return Whether both iterators point to the same underlying address in memory. + */ + auto operator==(forward_value_iterator const & other) const -> bool = default; + + private: + value_type value = + {}; ///< Underlying value the iterator is currently pointing too and should increment or decrement. + }; +} // namespace teachos::arch::shared + +#endif // TEACHOS_ARCH_X86_64_SHARED_FORWARD_VALUE_ITERATOR_HPP diff --git a/arch/x86_64/include/arch/shared/random_access_iterator.hpp b/arch/x86_64/include/arch/shared/random_access_iterator.hpp deleted file mode 100644 index 69617f3..0000000 --- a/arch/x86_64/include/arch/shared/random_access_iterator.hpp +++ /dev/null @@ -1,204 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_SHARED_RANDOM_ACCESS_ITERATOR_HPP -#define TEACHOS_ARCH_X86_64_SHARED_RANDOM_ACCESS_ITERATOR_HPP - -#include - -namespace teachos::arch::shared -{ - template - concept Iterable = std::incrementable && std::three_way_comparable && std::indirectly_readable; - - /** - * @brief Generic random access iterator for given template type. Allows any value that Allows to easily use this - * iterator instance in algorithm calls. - * - * @tparam T Value the iterator points too. - */ - template - struct random_access_iterator - { - using iterator_category = std::contiguous_iterator_tag; ///< Iterator category of this type. - using difference_type = std::ptrdiff_t; ///< Type when diving one instance of this iterator by another. - using value_type = T; ///< Underlying value pointed to by this iterator. - using reference_type = value_type &; ///< Reference to value returned by dereference * operation. - using pointer_type = value_type *; ///< Pointer to value returned by arrow -> operation. - using const_reference_type = value_type const &; ///< Reference to value returned by const dereference * operation. - using const_pointer_type = value_type const *; ///< Pointer to value returned by const arrow -> operation. - - /** - * @brief Defaulted constructor. - */ - random_access_iterator() = default; - - /** - * @brief Constructor. - * - * @param value Underlying value the iterator should point too and increment or decrement. - */ - explicit random_access_iterator(value_type value) - : value(value) - { - // Nothing to do - } - - /** - * @brief Gets a reference to the underlying value. - * - * @return Reference to the value. - */ - auto operator*() -> reference_type { return value; } - - /** - * @brief Gets a pointer to the underlying value. - * - * @return Underlying value passed intially. - */ - auto operator->() -> pointer_type { return &value; } - - /** - * @brief Gets a const reference to the underlying value. - * - * @return Reference to the value. - */ - auto operator*() const -> const_reference_type { return value; } - - /** - * @brief Gets a const pointer to the underlying value. - * - * @return Underlying value passed intially. - */ - auto operator->() const -> const_pointer_type { return &value; } - - /** - * @brief Pre decrement operator. Returns a reference to the changed value. - * - * @return Reference to the decrement underlying value. - */ - auto operator--() -> random_access_iterator & - { - --value; - return *this; - } - - /** - * @brief Pre increment operator. Returns a reference to the changed value. - * - * @return Reference to the incremented underlying value. - */ - auto operator++() -> random_access_iterator & - { - ++value; - return *this; - } - - /** - * @brief Post decrement operator. Returns a copy of the value. - * - * @return Copy of the decremented underlying value. - */ - auto operator--(int) -> random_access_iterator - { - auto const old_value = *this; - --value; - return old_value; - } - - /** - * @brief Post increment operator. Returns a copy of the value. - * - * @return Copy of the incremented underlying value. - */ - auto operator++(int) -> random_access_iterator - { - auto const old_value = *this; - ++value; - return old_value; - } - - /** - * @brief Addition assignment operator. Returns a reference to the changed value. - * - * @param operand Value we want to add to the underlying value the iterator is pointing too. - * @return Reference to the changed underlying value. - */ - auto operator+=(difference_type operand) -> random_access_iterator & - { - value += operand; - return *this; - } - - /** - * @brief Subtraction assignment operator. Returns a reference to the changed value. - * - * @param operand Value we want to subtract from the underlying value the iterator is pointing too. - * @return Reference to the changed underlying value. - */ - auto operator-=(difference_type operand) -> random_access_iterator & - { - value -= operand; - return *this; - } - - /** - * @brief Addition operator. Returns the changed value. - * - * @param operand Value we want to add to a copy of the underlying value the iterator is pointing too. - * @return Copy of underlying value incremented by the given value. - */ - auto operator+(difference_type operand) const -> random_access_iterator - { - return random_access_iterator{value + operand}; - } - - /** - * @brief Subtraction operator. Returns the changed value. - * - * @param operand Value we want to subtract from a copy of the underlying value the iterator is pointing too. - * @return Copy of underlying value decremented by the given value. - */ - auto operator-(difference_type operand) const -> random_access_iterator - { - return random_access_iterator{value - operand}; - } - - /** - * @brief Subtraction operator. Returns the size difference between two iterators. - * - * @param other Other iterator we want to substract the underlying value with ours. - * @return Size difference between the underlying value of this instance and the given iterator. - */ - auto operator-(random_access_iterator const & other) const -> difference_type { return value - other.value; } - - /** - * @brief Index operator overload. Returns a reference to the value at the given index. Simply returns the - * underlying value the iterator is pointing too incremented by the given index. - * - * @param index Index we want to access and get the value from. - * @return Reference to the value at the given index. - */ - auto operator[](difference_type index) const -> value_type const & { return value + index; } - - /** - * @brief Defaulted comparsion operator. Forwards to the comparsion operator of the given template type. - * - * @param other Other iterator to compare to. - * @return Whether both iterators point to the same underlying value in memory. - */ - auto operator==(random_access_iterator const & other) const -> bool = default; - - /** - * @brief Defaulted threeway comparsion operator. Forwards to the threeway comparsion operator of the given - * template type. - * - * @param other Other iterator to compare to. - * @return Whether the given iterator is smaller or larger than this iterator. - */ - auto operator<=>(random_access_iterator const & other) const -> std::strong_ordering = default; - - private: - value_type value = - {}; ///< Underlying value the iterator is currently pointing too and should increment or decrement. - }; -} // namespace teachos::arch::shared - -#endif // TEACHOS_ARCH_X86_64_SHARED_RANDOM_ACCESS_ITERATOR_HPP diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index 42aff68..3bc9676 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -24,16 +24,16 @@ namespace teachos::arch::memory::allocator { 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; + 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; }); + 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; + 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) diff --git a/arch/x86_64/src/memory/allocator/physical_frame.cpp b/arch/x86_64/src/memory/allocator/physical_frame.cpp index 63d84ec..ec387a1 100644 --- a/arch/x86_64/src/memory/allocator/physical_frame.cpp +++ b/arch/x86_64/src/memory/allocator/physical_frame.cpp @@ -21,31 +21,4 @@ namespace teachos::arch::memory::allocator ++frame_number; return *this; } - - auto physical_frame::operator+=(std::size_t operand) -> physical_frame & - { - frame_number += operand; - return *this; - } - - auto physical_frame::operator-=(std::size_t operand) -> physical_frame & - { - frame_number -= operand; - return *this; - } - - auto physical_frame::operator+(std::size_t operand) const -> physical_frame - { - return physical_frame{frame_number + operand}; - } - - auto physical_frame::operator-(std::size_t operand) const -> physical_frame - { - return physical_frame{frame_number - operand}; - } - - auto physical_frame::operator-(const physical_frame & other) const -> std::size_t - { - return frame_number - other.frame_number; - } } // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp index 178cc45..1dd18ff 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -51,27 +51,26 @@ namespace teachos::arch::memory::multiboot 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(), + 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 const elf_section_with_lowest_physical_address = std::ranges::min_element( - sections, [](auto const & a, auto const & b) { return a->physical_address < b->physical_address; }); + 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(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; + 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; + 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; }); + sections, [](auto const & section) { return section.type == elf_section_type::DYNAMIC; }); exception_handling::assert( symbol_table_section_count == 1U, @@ -81,10 +80,10 @@ namespace teachos::arch::memory::multiboot "[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; + 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; + kernel_end = highest_elf_section.physical_address + highest_elf_section.section_size; return sections; } -- cgit v1.2.3 From c887e22cd7827ae53fd3eab6f5af41969cdd616c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 4 Nov 2024 13:55:22 +0000 Subject: Use auto where possible --- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 2 ++ arch/x86_64/src/memory/paging/page_table.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 2eb3c4a..05a1cf2 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -80,6 +80,8 @@ namespace teachos::arch::memory::paging auto const backup = allocator::physical_frame::containing_address(physical_address.value()); auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); + // TODO: Page Table Level 4 is invalid, all entries point to non-existent memory :( + active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); tlb_flush_all(); map_elf_kernel_sections(active_table); diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 3c9942a..a39c235 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -46,7 +46,7 @@ namespace teachos::arch::memory::paging auto page_table::zero_entries() -> void { - std::ranges::for_each(entries, [](entry & entry) { entry.set_unused(); }); + std::ranges::for_each(entries, [](auto & entry) { entry.set_unused(); }); } auto page_table::is_empty() const -> bool -- cgit v1.2.3 From 77b50aa74e404a7af4b17d05613b21c8e5cd6f49 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 5 Nov 2024 09:54:48 +0000 Subject: remove variable --- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 05a1cf2..23a18dd 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -7,11 +7,6 @@ namespace teachos::arch::memory::paging { - namespace - { - virtual_page constexpr UNUSED_VIRTUAL_PAGE(0xCAFEBABE); - } // namespace - /** * @brief Kernel mapper that allows to remap the kernel elf sections in C++. * @@ -43,7 +38,7 @@ namespace teachos::arch::memory::paging */ auto remap_kernel() -> void { - temporary_page temporary_page{UNUSED_VIRTUAL_PAGE, allocator}; + temporary_page temporary_page{virtual_page{0xCAFEBABE}, allocator}; auto & active_table = active_page_table::create_or_get(); auto const frame = allocator.allocate_frame(); exception_handling::assert(frame.has_value(), -- cgit v1.2.3 From dc80a11864444cae275e9e7be9ae120a92433034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 5 Nov 2024 09:58:05 +0000 Subject: Move tlb into seperate subfolder and create cr3 header for reading and writing. --- arch/x86_64/CMakeLists.txt | 3 ++- arch/x86_64/include/arch/boot/pointers.hpp | 2 +- arch/x86_64/include/arch/memory/cpu/cr3.hpp | 27 ++++++++++++++++++++++ arch/x86_64/include/arch/memory/cpu/tlb.hpp | 26 +++++++++++++++++++++ .../arch/memory/paging/active_page_table.hpp | 4 ++-- .../include/arch/memory/paging/kernel_mapper.hpp | 15 +++++++++--- arch/x86_64/include/arch/memory/paging/tlb.hpp | 26 --------------------- arch/x86_64/src/memory/cpu/cr3.cpp | 23 ++++++++++++++++++ arch/x86_64/src/memory/cpu/tlb.cpp | 8 +++++++ .../x86_64/src/memory/paging/active_page_table.cpp | 2 +- arch/x86_64/src/memory/paging/tlb.cpp | 7 ------ 11 files changed, 102 insertions(+), 41 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/cpu/cr3.hpp create mode 100644 arch/x86_64/include/arch/memory/cpu/tlb.hpp delete mode 100644 arch/x86_64/include/arch/memory/paging/tlb.hpp create mode 100644 arch/x86_64/src/memory/cpu/cr3.cpp create mode 100644 arch/x86_64/src/memory/cpu/tlb.cpp delete mode 100644 arch/x86_64/src/memory/paging/tlb.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 42aa6ef..9fa8181 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -52,7 +52,8 @@ target_sources("_memory" PRIVATE "src/memory/paging/virtual_page.cpp" "src/memory/paging/active_page_table.cpp" "src/memory/paging/inactive_page_table.cpp" - "src/memory/paging/tlb.cpp" + "src/memory/cpu/tlb.cpp" + "src/memory/cpu/cr3.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index 25800f4..1172443 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -8,4 +8,4 @@ namespace teachos::arch::boot extern "C" size_t const multiboot_information_pointer; } // namespace teachos::arch::boot -#endif +#endif // TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP diff --git a/arch/x86_64/include/arch/memory/cpu/cr3.hpp b/arch/x86_64/include/arch/memory/cpu/cr3.hpp new file mode 100644 index 0000000..51d5055 --- /dev/null +++ b/arch/x86_64/include/arch/memory/cpu/cr3.hpp @@ -0,0 +1,27 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP + +#include "arch/memory/allocator/physical_frame.hpp" + +namespace teachos::arch::memory::cpu +{ + /** + * @brief Reads the value of the cr3 register. + * + * @note The cr3 register value represents the physical address of the level 4 page table used for paging in the + * system. Therefore reading this value allows to access the level 4 page table directly. Instead of over the virtual + * address 0xffffffff'fffff000, which then has to be first translated into a physical address. + * + * @return Physical address the level 4 page table is located at. + */ + auto read_cr3_register() -> allocator::physical_address; + + /** + * @brief Writes the given value into the cr3 register. + * + * @param new_p4_table_address Physical address the newly kernel mapped level 4 page table is located at. + */ + auto write_cr3_register(allocator::physical_address new_p4_table_address) -> void; +} // namespace teachos::arch::memory::cpu + +#endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP diff --git a/arch/x86_64/include/arch/memory/cpu/tlb.hpp b/arch/x86_64/include/arch/memory/cpu/tlb.hpp new file mode 100644 index 0000000..dc7ec61 --- /dev/null +++ b/arch/x86_64/include/arch/memory/cpu/tlb.hpp @@ -0,0 +1,26 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_CPU_TLB_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_CPU_TLB_HPP + +#include "arch/memory/paging/virtual_page.hpp" + +namespace teachos::arch::memory::cpu +{ + paging::virtual_address constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; + + /** + * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained + * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. + * + * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for + * that page. + */ + auto tlb_flush(paging::virtual_address address) -> void; + + /** + * @brief Invalidates the translation lookaside buffer (TLB) entry for all page tables + */ + auto tlb_flush_all() -> void; + +} // namespace teachos::arch::memory::cpu + +#endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_TLB_HPP diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index 0561420..09fbc76 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -3,7 +3,7 @@ #include "arch/exception_handling/assert.hpp" #include "arch/memory/allocator/concept.hpp" -#include "arch/memory/paging/tlb.hpp" +#include "arch/memory/cpu/tlb.hpp" #include "arch/memory/paging/virtual_page.hpp" #include @@ -165,7 +165,7 @@ namespace teachos::arch::memory::paging } } - tlb_flush(page.start_address()); + cpu::tlb_flush(page.start_address()); } private: diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 23a18dd..9803050 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP +#include "arch/memory/cpu/cr3.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/inactive_page_table.hpp" #include "arch/memory/paging/temporary_page.hpp" @@ -68,21 +69,29 @@ namespace teachos::arch::memory::paging auto remap_elf_kernel_sections(inactive_page_table inactive_table, temporary_page & temporary_page, active_page_table & active_table) -> void { - auto const physical_address = active_table.translate_address(PAGE_TABLE_LEVEL_4_ADDRESS); + auto const physical_address = active_table.translate_address(cpu::PAGE_TABLE_LEVEL_4_ADDRESS); exception_handling::assert(physical_address.has_value(), "[Kernel Mapper] Physical address for active table not mapped"); auto const backup = allocator::physical_frame::containing_address(physical_address.value()); + auto const backup2 = allocator::physical_frame::containing_address(cpu::read_cr3_register()); + cpu::write_cr3_register(0x221000); + auto const backup3 = cpu::read_cr3_register(); + + if (backup == backup2 && backup3 == 0x221000) + { + } + auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); // TODO: Page Table Level 4 is invalid, all entries point to non-existent memory :( active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); - tlb_flush_all(); + cpu::tlb_flush_all(); map_elf_kernel_sections(active_table); page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); - tlb_flush_all(); + cpu::tlb_flush_all(); temporary_page.unmap_page(active_table); } diff --git a/arch/x86_64/include/arch/memory/paging/tlb.hpp b/arch/x86_64/include/arch/memory/paging/tlb.hpp deleted file mode 100644 index 85c4152..0000000 --- a/arch/x86_64/include/arch/memory/paging/tlb.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_TLB_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_PAGING_TLB_HPP - -#include "arch/memory/paging/virtual_page.hpp" - -namespace teachos::arch::memory::paging -{ - virtual_address constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; - - /** - * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained - * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. - * - * @param address Memory address, which will be used to determine the contained page and flush the TLB entry for - * that page. - */ - auto tlb_flush(virtual_address address) -> void; - - /** - * @brief Invalidates the translation lookaside buffer (TLB) entry for all page tables - */ - auto tlb_flush_all() -> void; - -} // namespace teachos::arch::memory::paging - -#endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_TLB_HPP diff --git a/arch/x86_64/src/memory/cpu/cr3.cpp b/arch/x86_64/src/memory/cpu/cr3.cpp new file mode 100644 index 0000000..7e48d40 --- /dev/null +++ b/arch/x86_64/src/memory/cpu/cr3.cpp @@ -0,0 +1,23 @@ +#include "arch/memory/cpu/cr3.hpp" + +#include "arch/exception_handling/assert.hpp" + +namespace teachos::arch::memory::cpu +{ + auto read_cr3_register() -> allocator::physical_address + { + allocator::physical_address cr3; + asm volatile("movq %%cr3, %[output]" : [output] "=r"(cr3) : /* no input into call */ : "memory"); + return cr3; + } + + auto write_cr3_register(allocator::physical_address new_p4_table_address) -> void + { + exception_handling::assert(new_p4_table_address % allocator::PAGE_FRAME_SIZE == 0U, + "[CR3] Physical address to be written into register must be page aligned"); + asm volatile("movq %[input], %%cr3" + : /* no output from call */ + : [input] "r"(new_p4_table_address) + : "memory"); + } +} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/cpu/tlb.cpp b/arch/x86_64/src/memory/cpu/tlb.cpp new file mode 100644 index 0000000..bac46b7 --- /dev/null +++ b/arch/x86_64/src/memory/cpu/tlb.cpp @@ -0,0 +1,8 @@ +#include "arch/memory/cpu/tlb.hpp" + +namespace teachos::arch::memory::cpu +{ + auto tlb_flush(paging::virtual_address address) -> void { asm volatile("invlpg (%0)" ::"r"(address) : "memory"); } + + auto tlb_flush_all() -> void { tlb_flush(PAGE_TABLE_LEVEL_4_ADDRESS); } +} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp index 033a363..3f62419 100644 --- a/arch/x86_64/src/memory/paging/active_page_table.cpp +++ b/arch/x86_64/src/memory/paging/active_page_table.cpp @@ -4,7 +4,7 @@ namespace teachos::arch::memory::paging { auto active_page_table::create_or_get() -> active_page_table & { - static page_table_handle active_handle{reinterpret_cast(PAGE_TABLE_LEVEL_4_ADDRESS), + static page_table_handle active_handle{reinterpret_cast(cpu::PAGE_TABLE_LEVEL_4_ADDRESS), page_table_handle::LEVEL4}; static active_page_table active_page{active_handle}; return active_page; diff --git a/arch/x86_64/src/memory/paging/tlb.cpp b/arch/x86_64/src/memory/paging/tlb.cpp deleted file mode 100644 index c1160dc..0000000 --- a/arch/x86_64/src/memory/paging/tlb.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "arch/memory/paging/tlb.hpp" - -namespace teachos::arch::memory::paging -{ - auto tlb_flush(virtual_address address) -> void { asm volatile("invlpg (%0)" ::"r"(address) : "memory"); } - auto tlb_flush_all() -> void { tlb_flush(PAGE_TABLE_LEVEL_4_ADDRESS); } -} // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 416f08ee8791aeeb15e216650711f2a84e6f8114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 5 Nov 2024 10:15:25 +0000 Subject: Read cr3 register instead of translating page table level 4 virtual address --- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 9803050..67d1673 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -69,19 +69,7 @@ namespace teachos::arch::memory::paging auto remap_elf_kernel_sections(inactive_page_table inactive_table, temporary_page & temporary_page, active_page_table & active_table) -> void { - auto const physical_address = active_table.translate_address(cpu::PAGE_TABLE_LEVEL_4_ADDRESS); - exception_handling::assert(physical_address.has_value(), - "[Kernel Mapper] Physical address for active table not mapped"); - - auto const backup = allocator::physical_frame::containing_address(physical_address.value()); - auto const backup2 = allocator::physical_frame::containing_address(cpu::read_cr3_register()); - cpu::write_cr3_register(0x221000); - auto const backup3 = cpu::read_cr3_register(); - - if (backup == backup2 && backup3 == 0x221000) - { - } - + auto const backup = allocator::physical_frame::containing_address(cpu::read_cr3_register()); auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); // TODO: Page Table Level 4 is invalid, all entries point to non-existent memory :( -- cgit v1.2.3 From d18cf4a3e4abdea80992b8bba3d1ca50ae215253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 9 Nov 2024 14:51:10 +0000 Subject: Add switch method to kernel --- .../arch/memory/paging/inactive_page_table.hpp | 9 +++++++- .../include/arch/memory/paging/kernel_mapper.hpp | 25 ++++++++++++++++++++-- .../src/memory/paging/inactive_page_table.cpp | 8 ++++++- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp index 54a53f4..a9ab258 100644 --- a/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp @@ -12,6 +12,13 @@ namespace teachos::arch::memory::paging */ struct inactive_page_table { + /** + * @brief Constructor. + * + * @param frame Frame that should be mapped as the level 4 page table. + */ + inactive_page_table(allocator::physical_frame frame); + /** * @brief Constructor. * @@ -22,7 +29,7 @@ namespace teachos::arch::memory::paging * table. */ inactive_page_table(allocator::physical_frame frame, active_page_table & active_page_table, - temporary_page temporary_page); + temporary_page & temporary_page); allocator::physical_frame page_table_level_4_frame; ///< Temporary level 4 page table }; diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 67d1673..0786ec1 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -44,8 +44,12 @@ namespace teachos::arch::memory::paging auto const frame = allocator.allocate_frame(); exception_handling::assert(frame.has_value(), "[Kernel Mapper] Frame could not be allocated and therefore kernel not mapped"); - inactive_page_table inactive_table{frame.value(), active_table, temporary_page}; - remap_elf_kernel_sections(inactive_table, temporary_page, active_table); + inactive_page_table new_table{frame.value(), active_table, temporary_page}; + remap_elf_kernel_sections(new_table, temporary_page, active_table); + auto const old_table = switch_active_page_table(new_table); + auto const old_level_4_page = + virtual_page::containing_address(old_table.page_table_level_4_frame.start_address()); + active_table.unmap_page(allocator, old_level_4_page); } private: @@ -83,6 +87,23 @@ namespace teachos::arch::memory::paging temporary_page.unmap_page(active_table); } + /** + * @brief Switches the current active table pointed to by the CR3 register with another page table that is currently + * inactive. + * + * @param new_table Inactive page table that should now be made active and replace the current active one. + * @return The previous active page table. + */ + auto switch_active_page_table(inactive_page_table new_table) -> inactive_page_table + { + auto const backup = allocator::physical_frame::containing_address(cpu::read_cr3_register()); + auto const old_table = inactive_page_table{backup}; + + auto const new_address = new_table.page_table_level_4_frame.start_address(); + cpu::write_cr3_register(new_address); + return old_table; + } + /** * @brief Maps the required entries according to every elf section and it's contained frames. Additionally each of * thoose frames gets the correct entry flags according to elf section flags. diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp index f6ecb8b..4e0610e 100644 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -2,8 +2,14 @@ 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) + 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); -- cgit v1.2.3 From 022e2555c233c13f990026ea86d164f56a9cd7be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 9 Nov 2024 15:25:33 +0000 Subject: Remove unused method --- arch/x86_64/include/arch/memory/paging/temporary_page.hpp | 7 ------- arch/x86_64/src/memory/paging/temporary_page.cpp | 12 ------------ 2 files changed, 19 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp index b93a375..a850879 100644 --- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -28,13 +28,6 @@ namespace teachos::arch::memory::paging // Nothing to do } - /** - * @brief Set all page table entries to unused. - * - * @param active_table the page table whose values are set to unused. - */ - auto zero_entries(active_page_table & active_table) -> void; - /** * @brief Unmap the current page. * diff --git a/arch/x86_64/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp index 5f760a5..152241d 100644 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -26,16 +26,4 @@ namespace teachos::arch::memory::paging { active_table.unmap_page(allocator, page); } - - auto temporary_page::zero_entries(active_page_table & active_table) -> void - { - auto frame = allocator.allocate_frame(); - exception_handling::assert(frame.has_value(), "[Temporary Page] Tiny allocator could not allocate a frame"); - - page_table_handle handle = map_table_frame(frame.value(), active_table); - handle.zero_entries(); - handle[511].set_entry(frame.value(), entry::PRESENT | entry::WRITABLE); - - unmap_page(active_table); - } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 4c030cbaee174a9f7f42d4f5ca7ddf6debbbe048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sat, 9 Nov 2024 16:25:11 +0000 Subject: Fix flush all method and move crash. --- arch/x86_64/include/arch/memory/cpu/tlb.hpp | 2 -- arch/x86_64/include/arch/memory/paging/active_page_table.hpp | 6 ++++-- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 2 -- arch/x86_64/src/memory/cpu/tlb.cpp | 9 +++++++-- arch/x86_64/src/memory/paging/active_page_table.cpp | 7 ++++++- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/arch/x86_64/include/arch/memory/cpu/tlb.hpp b/arch/x86_64/include/arch/memory/cpu/tlb.hpp index dc7ec61..21f09e5 100644 --- a/arch/x86_64/include/arch/memory/cpu/tlb.hpp +++ b/arch/x86_64/include/arch/memory/cpu/tlb.hpp @@ -5,8 +5,6 @@ namespace teachos::arch::memory::cpu { - paging::virtual_address constexpr PAGE_TABLE_LEVEL_4_ADDRESS = 0xffffffff'fffff000; - /** * @brief Invalidates any translation lookaside buffer (TLB) entry for the page table the given address is cotained * in. See https://www.felixcloutier.com/x86/invlpg for more information on the used x86 instruction. diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index 09fbc76..567a806 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -164,8 +164,10 @@ namespace teachos::arch::memory::paging break; } } - - cpu::tlb_flush(page.start_address()); + // TODO: Flushing only specifc page does not work and cause temporary_page.map_table_frame to return an invalid + // page table (Memory inside buffer shows nothing) + // cpu::tlb_flush(page.start_address()); + cpu::tlb_flush_all(); } private: diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 0786ec1..c91c5f0 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -76,8 +76,6 @@ namespace teachos::arch::memory::paging auto const backup = allocator::physical_frame::containing_address(cpu::read_cr3_register()); auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); - // TODO: Page Table Level 4 is invalid, all entries point to non-existent memory :( - active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); cpu::tlb_flush_all(); map_elf_kernel_sections(active_table); diff --git a/arch/x86_64/src/memory/cpu/tlb.cpp b/arch/x86_64/src/memory/cpu/tlb.cpp index bac46b7..1663e80 100644 --- a/arch/x86_64/src/memory/cpu/tlb.cpp +++ b/arch/x86_64/src/memory/cpu/tlb.cpp @@ -1,8 +1,13 @@ #include "arch/memory/cpu/tlb.hpp" +#include "arch/memory/cpu/cr3.hpp" + namespace teachos::arch::memory::cpu { - auto tlb_flush(paging::virtual_address address) -> void { asm volatile("invlpg (%0)" ::"r"(address) : "memory"); } + auto tlb_flush(paging::virtual_address address) -> void + { + asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); + } - auto tlb_flush_all() -> void { tlb_flush(PAGE_TABLE_LEVEL_4_ADDRESS); } + auto tlb_flush_all() -> void { write_cr3_register(read_cr3_register()); } } // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp index 3f62419..0113869 100644 --- a/arch/x86_64/src/memory/paging/active_page_table.cpp +++ b/arch/x86_64/src/memory/paging/active_page_table.cpp @@ -2,9 +2,14 @@ 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(cpu::PAGE_TABLE_LEVEL_4_ADDRESS), + 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; -- cgit v1.2.3 From edc11135d83ef1f8fcbc1575a290b31ccbdb7e07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 10 Nov 2024 09:34:21 +0000 Subject: Identity map memory map and vga text buffer,w hen setting up kernel --- .../include/arch/memory/paging/kernel_mapper.hpp | 23 +++++++++++++++++++--- .../include/arch/memory/paging/page_entry.hpp | 2 +- arch/x86_64/include/arch/video/vga/text.hpp | 2 ++ arch/x86_64/src/memory/paging/page_entry.cpp | 2 +- arch/x86_64/src/video/vga/text.cpp | 21 ++++++++++---------- 5 files changed, 34 insertions(+), 16 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index c91c5f0..d1b9325 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -5,6 +5,7 @@ #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/inactive_page_table.hpp" #include "arch/memory/paging/temporary_page.hpp" +#include "arch/video/vga/text.hpp" namespace teachos::arch::memory::paging { @@ -124,19 +125,35 @@ namespace teachos::arch::memory::paging // End address is exclusive, so that it is not part of the section anymore (one past the last frame of this // section). But end frame would now point to the actual last frame and not one past the last frame, therefore // we increment by one to get one past the last frame of this section. - auto end_frame = + auto const end_frame = ++(allocator::physical_frame::containing_address(section.physical_address + section.section_size - 1)); allocator::frame_container::iterator const begin{start_frame}; allocator::frame_container::iterator const end{end_frame}; - allocator::frame_container frames{begin, end}; - entry entry{section.flags}; + allocator::frame_container const frames{begin, end}; + entry const entry{section.flags}; for (auto const & frame : frames) { active_table.identity_map(allocator, frame, entry.get_flags()); } } + + auto const vga_buffer_frame = + allocator::physical_frame::containing_address(video::vga::text::DEFAULT_VGA_TEXT_BUFFER_ADDRESS); + active_table.identity_map(allocator, vga_buffer_frame, entry::WRITABLE); + + auto const multiboot_start_frame = allocator::physical_frame::containing_address(mem_info.multiboot_start); + auto const multiboot_end_frame = ++allocator::physical_frame::containing_address(mem_info.multiboot_end - 1); + + allocator::frame_container::iterator const multiboot_begin{multiboot_start_frame}; + allocator::frame_container::iterator const multiboot_end{multiboot_end_frame}; + allocator::frame_container const multiboot_frames{multiboot_begin, multiboot_end}; + + for (auto const & frame : multiboot_frames) + { + active_table.identity_map(allocator, frame, entry::PRESENT); + } } T & allocator; diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index ab9659d..a7ba262 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -104,7 +104,7 @@ namespace teachos::arch::memory::paging * * @return Extracted entry flags, without the physical address. */ - auto get_flags() -> std::bitset<64U>; + auto get_flags() const -> std::bitset<64U>; private: std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be diff --git a/arch/x86_64/include/arch/video/vga/text.hpp b/arch/x86_64/include/arch/video/vga/text.hpp index f200da4..665dc1c 100644 --- a/arch/x86_64/include/arch/video/vga/text.hpp +++ b/arch/x86_64/include/arch/video/vga/text.hpp @@ -7,6 +7,8 @@ namespace teachos::arch::video::vga::text { + auto constexpr DEFAULT_VGA_TEXT_BUFFER_ADDRESS = 0xB8000; + /** * @brief The colors available in the standard VGA text mode. */ diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index f13e645..aae5013 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -55,5 +55,5 @@ namespace teachos::arch::memory::paging flags = frame.start_address() | additional_flags.to_ulong(); } - auto entry::get_flags() -> std::bitset<64U> { return flags.to_ulong() & ~PHYSICAL_ADDRESS_MASK; } + 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/video/vga/text.cpp b/arch/x86_64/src/video/vga/text.cpp index 9eef288..0137ddb 100644 --- a/arch/x86_64/src/video/vga/text.cpp +++ b/arch/x86_64/src/video/vga/text.cpp @@ -11,9 +11,8 @@ namespace teachos::arch::video::vga::text { namespace { - auto constexpr default_text_buffer_address = 0xb8000; - auto constexpr default_text_buffer_width = 80; - auto constexpr default_text_buffer_height = 25; + auto constexpr DEFAULT_TEXT_BUFFER_WIDTH = 80U; + auto constexpr DEFAULT_TEXT_BUFFER_HEIGHT = 25U; extern "C" std::pair * vga_buffer_pointer; auto constinit text_buffer = teachos::memory::asm_pointer{vga_buffer_pointer}; @@ -21,7 +20,7 @@ namespace teachos::arch::video::vga::text auto clear(attribute attribute) -> void { - *text_buffer = reinterpret_cast(default_text_buffer_address); + *text_buffer = reinterpret_cast(DEFAULT_VGA_TEXT_BUFFER_ADDRESS); std::ranges::fill_n(*text_buffer, 2000, std::pair{' ', attribute}); } @@ -35,21 +34,21 @@ namespace teachos::arch::video::vga::text auto newline() -> void { - auto base = reinterpret_cast(default_text_buffer_address); + 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 current_line = (raw_buffer - base) / DEFAULT_TEXT_BUFFER_WIDTH; auto next_line = current_line + 1; - if (next_line >= default_text_buffer_height) + 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; + 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; + raw_buffer = base + current_line * DEFAULT_TEXT_BUFFER_WIDTH; } else { - raw_buffer = base + next_line * default_text_buffer_width; + raw_buffer = base + next_line * DEFAULT_TEXT_BUFFER_WIDTH; } } -- cgit v1.2.3 From 381296c48141e53620281f6f9dfd2aa61723caca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 10 Nov 2024 09:44:42 +0000 Subject: Remove multiboot mapping done in elf section mapping --- arch/x86_64/include/arch/memory/paging/active_page_table.hpp | 4 ++-- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 12 ------------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index 567a806..c7d835a 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -166,8 +166,8 @@ namespace teachos::arch::memory::paging } // TODO: Flushing only specifc page does not work and cause temporary_page.map_table_frame to return an invalid // page table (Memory inside buffer shows nothing) - // cpu::tlb_flush(page.start_address()); - cpu::tlb_flush_all(); + cpu::tlb_flush(page.start_address()); + // cpu::tlb_flush_all(); } private: diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index d1b9325..5e51c64 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -142,18 +142,6 @@ namespace teachos::arch::memory::paging auto const vga_buffer_frame = allocator::physical_frame::containing_address(video::vga::text::DEFAULT_VGA_TEXT_BUFFER_ADDRESS); active_table.identity_map(allocator, vga_buffer_frame, entry::WRITABLE); - - auto const multiboot_start_frame = allocator::physical_frame::containing_address(mem_info.multiboot_start); - auto const multiboot_end_frame = ++allocator::physical_frame::containing_address(mem_info.multiboot_end - 1); - - allocator::frame_container::iterator const multiboot_begin{multiboot_start_frame}; - allocator::frame_container::iterator const multiboot_end{multiboot_end_frame}; - allocator::frame_container const multiboot_frames{multiboot_begin, multiboot_end}; - - for (auto const & frame : multiboot_frames) - { - active_table.identity_map(allocator, frame, entry::PRESENT); - } } T & allocator; -- cgit v1.2.3 From 1275612382c5c9d31ed7b24a2c6d699c14a10081 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 10 Nov 2024 10:59:22 +0000 Subject: implement model specific register calls --- arch/x86_64/include/arch/memory/cpu/msr.hpp | 69 +++++++++++++++++++++++++++++ arch/x86_64/src/memory/cpu/msr.cpp | 29 ++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 arch/x86_64/include/arch/memory/cpu/msr.hpp create mode 100644 arch/x86_64/src/memory/cpu/msr.cpp diff --git a/arch/x86_64/include/arch/memory/cpu/msr.hpp b/arch/x86_64/include/arch/memory/cpu/msr.hpp new file mode 100644 index 0000000..662f3ac --- /dev/null +++ b/arch/x86_64/include/arch/memory/cpu/msr.hpp @@ -0,0 +1,69 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_CPU_NXE_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_CPU_NXE_HPP + +#include +#include + +namespace teachos::arch::memory::cpu +{ + constexpr uint32_t IA32_EFER = 0xC0000080; + + enum class msr_flags : uint64_t + { + SCE = 1U << 0ULL, ///< System Call Extensions + LME = 1U << 8ULL, ///< Long Mode Enabled + LMA = 1U << 10ULL, ///< Long Mode Active + NXE = 1U << 11ULL, ///< No-Execute Enable + SVME = 1U << 12ULL, ///< Secure Virtual Machine Enable + LMSLE = 1U << 13ULL, ///< Secure Virtual Machine Enable + FFXSR = 1U << 14ULL, ///< fast FXSAVE/FXSTOR + TCE = 1U << 15ULL, ///< Translation Cache Extension + }; + + /** + * @brief Reads a 64-bit Model-Specific Register (MSR). + * + * This function reads the value of an MSR specified by the given address. It + * combines the lower and upper 32-bits of the MSR value and returns it as a + * 64-bit unsigned integer. + * + * @param msr The address of the MSR to read. + * @return The 64-bit value read from the MSR. + */ + uint64_t read_msr(uint32_t msr); + + /** + * @brief Writes a 64-bit value to a Model-Specific Register (MSR). + * + * This function writes a 64-bit value to the MSR specified by the given address. + * It splits the 64-bit value into two 32-bit parts and writes them using the + * `wrmsr` instruction. + * + * @param msr The address of the MSR to write to. + * @param value The 64-bit value to write to the MSR. + */ + void write_msr(uint32_t msr, uint64_t value); + + /** + * @brief Sets a specific bit in the MSR register. + * + * This function reads the current value of the EFER register, ORs the specified + * bit with the current value, and writes the updated value back to the EFER register. + * + * @param flag The flag to set in the EFER register. + */ + void set_msr_bit(msr_flags flag); + + /** + * @brief Enables the No-Execute Enable (NXE) bit in the Extended Feature Enable Register (EFER). + * + * This function reads the current value of the EFER register, enables the NXE bit + * (bit 11), and writes the updated value back to the EFER register. Enabling the NXE + * bit allows the processor to support No-Execute memory regions, which are required + * for certain memory protection features like Data Execution Prevention (DEP). + */ + void enable_nxe_bit(); + +} // namespace teachos::arch::memory::cpu + +#endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_NXE_HPP \ No newline at end of file diff --git a/arch/x86_64/src/memory/cpu/msr.cpp b/arch/x86_64/src/memory/cpu/msr.cpp new file mode 100644 index 0000000..3a917c9 --- /dev/null +++ b/arch/x86_64/src/memory/cpu/msr.cpp @@ -0,0 +1,29 @@ +#include "arch/memory/cpu/msr.hpp" + +namespace teachos::arch::memory::cpu +{ + uint64_t read_msr(uint32_t msr) + { + uint32_t low, high; + asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr)); + return (static_cast(high) << 32) | low; + } + + void write_msr(uint32_t msr, uint64_t value) + { + uint32_t low = value & 0xFFFFFFFF; + uint32_t high = value >> 32; + asm volatile("wrmsr" + : /* no output from call */ + : "c"(msr), "a"(low), "d"(high)); + } + + void set_msr_bit(msr_flags flag) + { + uint64_t efer = read_msr(IA32_EFER); + write_msr(IA32_EFER, static_cast(flag) | efer); + } + + void enable_nxe_bit() { set_msr_bit(msr_flags::NXE); } + +} // namespace teachos::arch::memory::cpu -- cgit v1.2.3 From 45e7b24f19b3c4557f98996a44d8857d750ca5b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 10 Nov 2024 11:45:26 +0000 Subject: Adjust comments and constant --- arch/x86_64/CMakeLists.txt | 2 +- .../include/arch/memory/cpu/control_register.hpp | 70 ++++++++++++++++++++++ arch/x86_64/include/arch/memory/cpu/cr3.hpp | 27 --------- arch/x86_64/include/arch/memory/cpu/msr.hpp | 47 ++++++++------- .../include/arch/memory/paging/kernel_mapper.hpp | 10 ++-- arch/x86_64/src/memory/cpu/control_register.cpp | 66 ++++++++++++++++++++ arch/x86_64/src/memory/cpu/cr3.cpp | 23 ------- arch/x86_64/src/memory/cpu/msr.cpp | 18 +++--- arch/x86_64/src/memory/cpu/tlb.cpp | 7 ++- 9 files changed, 185 insertions(+), 85 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/cpu/control_register.hpp delete mode 100644 arch/x86_64/include/arch/memory/cpu/cr3.hpp create mode 100644 arch/x86_64/src/memory/cpu/control_register.cpp delete mode 100644 arch/x86_64/src/memory/cpu/cr3.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 9fa8181..ee0141e 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -53,7 +53,7 @@ target_sources("_memory" PRIVATE "src/memory/paging/active_page_table.cpp" "src/memory/paging/inactive_page_table.cpp" "src/memory/cpu/tlb.cpp" - "src/memory/cpu/cr3.cpp" + "src/memory/cpu/control_register.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/memory/cpu/control_register.hpp b/arch/x86_64/include/arch/memory/cpu/control_register.hpp new file mode 100644 index 0000000..b48e48c --- /dev/null +++ b/arch/x86_64/include/arch/memory/cpu/control_register.hpp @@ -0,0 +1,70 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP + +#include + +namespace teachos::arch::memory::cpu +{ + /** + * @brief Control registers that can be read and written to. + * + * @note CR1 and CR5 - 7 are reserved and will throw an exception if they are accessed, therefore they are not defined + * in the enum. See https://en.wikipedia.org/wiki/Control_register#Control_registers_in_Intel_x86_series for more + * information. + */ + enum struct control_register : uint8_t + { + CR0, ///< Contains various control flags that modify basic operation of the processor, Machine Status World (MSW) + ///< register. + CR2 = 2U, ///< Contains Page Fault Linear Address (PFLA), when page fault occurs address program attended to accces + ///< is stored here. + CR3, ///< Enables process to translate linear addresses into physical addresses using paging, CR0 bit 32 Paging + ///< (PG) needs to be enabled simply contains the register value that represents the physical address of the + ///< level 4 page table used for paging in the system. Therefore reading this value allows to access the level + ///< 4 page table directly. Instead of over the virtual address 0xffffffff'fffff000, which then has to be + ///< first translated into a physical address. + CR4 ///< Used in protected mode to control operations. + }; + + /** + * @brief Control register 2 flags that can be set. + * + * @note Modifies the basic operation of the processor. Only the most important extensions are listed below, the rest + * are excluded for brevity. See https://en.wikipedia.org/wiki/Control_register#CR0 for more information. + */ + enum struct cr2_flags : uint32_t + { + PROTECTED_MODE_ENABLED = 1U << 0U, ///< System is in protected moe else system is in real mode. + TASK_SWITCHED = 1U << 3U, ///< Allows saving x87 task context upon a task switch only after x87 instruction used. + WRITE_PROTECT = 1U << 16U, ///< When set, the CPU cannot write to read-only pages when privilege level is 0. + PAGING = 1U << 31U, // Enable paging using the CR3 register. + }; + + /** + * @brief Reads the value of the given control register. + * + * @note The cr3 register value represents the physical address of the level 4 page table used for paging in the + * system. Therefore reading this value allows to access the level 4 page table directly. Instead of over the virtual + * address 0xffffffff'fffff000, which then has to be first translated into a physical address. + * + * @return Physical address the level 4 page table is located at. + */ + + /** + * @brief Reads the value of the given control register. + * + * @param cr Control register that should be read. + * @return Value of the control register. + */ + auto read_control_register(control_register cr) -> std::size_t; + + /** + * @brief Writes the given value into the given control register. + * + * @param cr Control register that should be written. + * @param new_value New value that should be written. + */ + auto write_control_register(control_register cr, std::size_t new_value) -> void; +} // namespace teachos::arch::memory::cpu + +#endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP diff --git a/arch/x86_64/include/arch/memory/cpu/cr3.hpp b/arch/x86_64/include/arch/memory/cpu/cr3.hpp deleted file mode 100644 index 51d5055..0000000 --- a/arch/x86_64/include/arch/memory/cpu/cr3.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP - -#include "arch/memory/allocator/physical_frame.hpp" - -namespace teachos::arch::memory::cpu -{ - /** - * @brief Reads the value of the cr3 register. - * - * @note The cr3 register value represents the physical address of the level 4 page table used for paging in the - * system. Therefore reading this value allows to access the level 4 page table directly. Instead of over the virtual - * address 0xffffffff'fffff000, which then has to be first translated into a physical address. - * - * @return Physical address the level 4 page table is located at. - */ - auto read_cr3_register() -> allocator::physical_address; - - /** - * @brief Writes the given value into the cr3 register. - * - * @param new_p4_table_address Physical address the newly kernel mapped level 4 page table is located at. - */ - auto write_cr3_register(allocator::physical_address new_p4_table_address) -> void; -} // namespace teachos::arch::memory::cpu - -#endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP diff --git a/arch/x86_64/include/arch/memory/cpu/msr.hpp b/arch/x86_64/include/arch/memory/cpu/msr.hpp index 662f3ac..1403995 100644 --- a/arch/x86_64/include/arch/memory/cpu/msr.hpp +++ b/arch/x86_64/include/arch/memory/cpu/msr.hpp @@ -6,63 +6,68 @@ namespace teachos::arch::memory::cpu { - constexpr uint32_t IA32_EFER = 0xC0000080; - - enum class msr_flags : uint64_t + /** + * @brief Important Flags that can be writen into the Extended Feature Enable Register (EFER). + * + * @note EFER is a model-specific register allowing to configure CPU extensions. Only the most important extensions + * are listed below, the rest are excluded for brevity. See https://en.wikipedia.org/wiki/Control_register#EFER for + * more information. + */ + enum class efer_flags : uint64_t { - SCE = 1U << 0ULL, ///< System Call Extensions - LME = 1U << 8ULL, ///< Long Mode Enabled - LMA = 1U << 10ULL, ///< Long Mode Active - NXE = 1U << 11ULL, ///< No-Execute Enable - SVME = 1U << 12ULL, ///< Secure Virtual Machine Enable - LMSLE = 1U << 13ULL, ///< Secure Virtual Machine Enable - FFXSR = 1U << 14ULL, ///< fast FXSAVE/FXSTOR - TCE = 1U << 15ULL, ///< Translation Cache Extension + SCE = 1UL << 0UL, ///< System Call Extensions + LME = 1UL << 8UL, ///< Long Mode Enabled + LMA = 1UL << 10UL, ///< Long Mode Active + NXE = 1UL << 11UL, ///< No-Execute Enable + SVME = 1UL << 12UL, ///< Secure Virtual Machine Enable + LMSLE = 1UL << 13UL, ///< Long Mode Segment Limit Enable + FFXSR = 1UL << 14UL, ///< Fast FXSAVE/FXSTOR + TCE = 1UL << 15UL, ///< Translation Cache Extension }; /** * @brief Reads a 64-bit Model-Specific Register (MSR). * - * This function reads the value of an MSR specified by the given address. It + * @note This function reads the value of an MSR specified by the given address. It * combines the lower and upper 32-bits of the MSR value and returns it as a * 64-bit unsigned integer. * * @param msr The address of the MSR to read. * @return The 64-bit value read from the MSR. */ - uint64_t read_msr(uint32_t msr); + auto read_msr(uint32_t msr) -> void; /** * @brief Writes a 64-bit value to a Model-Specific Register (MSR). * - * This function writes a 64-bit value to the MSR specified by the given address. + * @note This function writes a 64-bit value to the MSR specified by the given address. * It splits the 64-bit value into two 32-bit parts and writes them using the * `wrmsr` instruction. * * @param msr The address of the MSR to write to. - * @param value The 64-bit value to write to the MSR. + * @param new_value The 64-bit value to write to the MSR. */ - void write_msr(uint32_t msr, uint64_t value); + auto write_msr(uint32_t msr, uint64_t new_value) -> void; /** - * @brief Sets a specific bit in the MSR register. + * @brief Sets a specific bit in the Extended Feature Enable Register (EFER) Model-Specific Register (MSR) register. * - * This function reads the current value of the EFER register, ORs the specified + * @note This function reads the current value of the EFER register, ORs the specified * bit with the current value, and writes the updated value back to the EFER register. * * @param flag The flag to set in the EFER register. */ - void set_msr_bit(msr_flags flag); + auto set_efer_bit(efer_flags flag) -> void; /** * @brief Enables the No-Execute Enable (NXE) bit in the Extended Feature Enable Register (EFER). * - * This function reads the current value of the EFER register, enables the NXE bit + * @note This function reads the current value of the EFER register, enables the NXE bit * (bit 11), and writes the updated value back to the EFER register. Enabling the NXE * bit allows the processor to support No-Execute memory regions, which are required * for certain memory protection features like Data Execution Prevention (DEP). */ - void enable_nxe_bit(); + auto enable_nxe_bit() -> void; } // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 5e51c64..53284b6 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP -#include "arch/memory/cpu/cr3.hpp" +#include "arch/memory/cpu/control_register.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/inactive_page_table.hpp" #include "arch/memory/paging/temporary_page.hpp" @@ -74,7 +74,8 @@ namespace teachos::arch::memory::paging auto remap_elf_kernel_sections(inactive_page_table inactive_table, temporary_page & temporary_page, active_page_table & active_table) -> void { - auto const backup = allocator::physical_frame::containing_address(cpu::read_cr3_register()); + auto const backup = + allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); @@ -95,11 +96,12 @@ namespace teachos::arch::memory::paging */ auto switch_active_page_table(inactive_page_table new_table) -> inactive_page_table { - auto const backup = allocator::physical_frame::containing_address(cpu::read_cr3_register()); + auto const backup = + allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); auto const old_table = inactive_page_table{backup}; auto const new_address = new_table.page_table_level_4_frame.start_address(); - cpu::write_cr3_register(new_address); + cpu::write_control_register(cpu::control_register::CR3, new_address); return old_table; } diff --git a/arch/x86_64/src/memory/cpu/control_register.cpp b/arch/x86_64/src/memory/cpu/control_register.cpp new file mode 100644 index 0000000..38a887c --- /dev/null +++ b/arch/x86_64/src/memory/cpu/control_register.cpp @@ -0,0 +1,66 @@ +#include "arch/memory/cpu/control_register.hpp" + +#include "arch/exception_handling/assert.hpp" + +namespace teachos::arch::memory::cpu +{ + auto read_control_register(control_register cr) -> std::size_t + { + std::size_t current_value; + switch (cr) + { + case control_register::CR0: + asm volatile("movq %%cr0, %[output]" : [output] "=r"(current_value)); + break; + case control_register::CR2: + asm volatile("movq %%cr2, %[output]" : [output] "=r"(current_value)); + break; + case control_register::CR3: + asm volatile("movq %%cr3, %[output]" : [output] "=r"(current_value)); + break; + case control_register::CR4: + asm volatile("movq %%cr4, %[output]" : [output] "=r"(current_value)); + break; + default: + exception_handling::assert(false, + "[Control Register] Attempted to read non-existent or reserved control register"); + break; + } + return current_value; + } + + auto write_control_register(control_register cr, std::size_t new_value) -> void + { + switch (cr) + { + case control_register::CR0: + asm volatile("movq %[input], %%cr0" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + case control_register::CR2: + asm volatile("movq %[input], %%cr2" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + case control_register::CR3: + asm volatile("movq %[input], %%cr3" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + case control_register::CR4: + asm volatile("movq %[input], %%cr4" + : /* no output from call */ + : [input] "r"(new_value) + : "memory"); + break; + default: + exception_handling::assert(false, + "[Control Register] Attempted to write non-existent or reserved control register"); + break; + } + } +} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/cpu/cr3.cpp b/arch/x86_64/src/memory/cpu/cr3.cpp deleted file mode 100644 index 7e48d40..0000000 --- a/arch/x86_64/src/memory/cpu/cr3.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "arch/memory/cpu/cr3.hpp" - -#include "arch/exception_handling/assert.hpp" - -namespace teachos::arch::memory::cpu -{ - auto read_cr3_register() -> allocator::physical_address - { - allocator::physical_address cr3; - asm volatile("movq %%cr3, %[output]" : [output] "=r"(cr3) : /* no input into call */ : "memory"); - return cr3; - } - - auto write_cr3_register(allocator::physical_address new_p4_table_address) -> void - { - exception_handling::assert(new_p4_table_address % allocator::PAGE_FRAME_SIZE == 0U, - "[CR3] Physical address to be written into register must be page aligned"); - asm volatile("movq %[input], %%cr3" - : /* no output from call */ - : [input] "r"(new_p4_table_address) - : "memory"); - } -} // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/cpu/msr.cpp b/arch/x86_64/src/memory/cpu/msr.cpp index 3a917c9..6e3d1d3 100644 --- a/arch/x86_64/src/memory/cpu/msr.cpp +++ b/arch/x86_64/src/memory/cpu/msr.cpp @@ -2,14 +2,19 @@ namespace teachos::arch::memory::cpu { - uint64_t read_msr(uint32_t msr) + namespace + { + constexpr uint32_t 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; } - void write_msr(uint32_t msr, uint64_t value) + auto write_msr(uint32_t msr, uint64_t value) -> void { uint32_t low = value & 0xFFFFFFFF; uint32_t high = value >> 32; @@ -18,12 +23,11 @@ namespace teachos::arch::memory::cpu : "c"(msr), "a"(low), "d"(high)); } - void set_msr_bit(msr_flags flag) + auto set_efer_bit(efer_flags flag) -> void { - uint64_t efer = read_msr(IA32_EFER); - write_msr(IA32_EFER, static_cast(flag) | efer); + uint64_t const efer = read_msr(IA32_EFER_ADDRESS); + write_msr(IA32_EFER_ADDRESS, static_cast(flag) | efer); } - void enable_nxe_bit() { set_msr_bit(msr_flags::NXE); } - + auto enable_nxe_bit() -> void { set_efer_bit(efer_flags::NXE); } } // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/cpu/tlb.cpp b/arch/x86_64/src/memory/cpu/tlb.cpp index 1663e80..591d9fc 100644 --- a/arch/x86_64/src/memory/cpu/tlb.cpp +++ b/arch/x86_64/src/memory/cpu/tlb.cpp @@ -1,6 +1,6 @@ #include "arch/memory/cpu/tlb.hpp" -#include "arch/memory/cpu/cr3.hpp" +#include "arch/memory/cpu/control_register.hpp" namespace teachos::arch::memory::cpu { @@ -9,5 +9,8 @@ namespace teachos::arch::memory::cpu asm volatile("invlpg (%[input])" : /* no output from call */ : [input] "r"(address) : "memory"); } - auto tlb_flush_all() -> void { write_cr3_register(read_cr3_register()); } + auto tlb_flush_all() -> void + { + write_control_register(cpu::control_register::CR3, read_control_register(cpu::control_register::CR3)); + } } // namespace teachos::arch::memory::cpu -- cgit v1.2.3 From 8eb68ccb8837ba867550d16f967d9ef21921abe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 10 Nov 2024 12:08:02 +0000 Subject: Finish control register and adjust msr --- arch/x86_64/CMakeLists.txt | 1 + .../include/arch/memory/cpu/control_register.hpp | 28 ++++++++++---------- arch/x86_64/include/arch/memory/cpu/msr.hpp | 13 +--------- arch/x86_64/src/kernel/main.cpp | 4 +++ arch/x86_64/src/memory/cpu/control_register.cpp | 30 ++++++++++++++-------- arch/x86_64/src/memory/cpu/msr.cpp | 8 +++--- 6 files changed, 42 insertions(+), 42 deletions(-) diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index ee0141e..f868b4e 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -54,6 +54,7 @@ target_sources("_memory" PRIVATE "src/memory/paging/inactive_page_table.cpp" "src/memory/cpu/tlb.cpp" "src/memory/cpu/control_register.cpp" + "src/memory/cpu/msr.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/memory/cpu/control_register.hpp b/arch/x86_64/include/arch/memory/cpu/control_register.hpp index b48e48c..4988036 100644 --- a/arch/x86_64/include/arch/memory/cpu/control_register.hpp +++ b/arch/x86_64/include/arch/memory/cpu/control_register.hpp @@ -32,7 +32,7 @@ namespace teachos::arch::memory::cpu * @note Modifies the basic operation of the processor. Only the most important extensions are listed below, the rest * are excluded for brevity. See https://en.wikipedia.org/wiki/Control_register#CR0 for more information. */ - enum struct cr2_flags : uint32_t + enum struct cr2_flags : uint64_t { PROTECTED_MODE_ENABLED = 1U << 0U, ///< System is in protected moe else system is in real mode. TASK_SWITCHED = 1U << 3U, ///< Allows saving x87 task context upon a task switch only after x87 instruction used. @@ -40,31 +40,31 @@ namespace teachos::arch::memory::cpu PAGING = 1U << 31U, // Enable paging using the CR3 register. }; - /** - * @brief Reads the value of the given control register. - * - * @note The cr3 register value represents the physical address of the level 4 page table used for paging in the - * system. Therefore reading this value allows to access the level 4 page table directly. Instead of over the virtual - * address 0xffffffff'fffff000, which then has to be first translated into a physical address. - * - * @return Physical address the level 4 page table is located at. - */ - /** * @brief Reads the value of the given control register. * * @param cr Control register that should be read. * @return Value of the control register. */ - auto read_control_register(control_register cr) -> std::size_t; + auto read_control_register(control_register cr) -> uint64_t; /** - * @brief Writes the given value into the given control register. + * @brief Sets a specific bit in the Extended Feature Enable Register (EFER) Model-Specific Register (MSR) register. * * @param cr Control register that should be written. * @param new_value New value that should be written. */ - auto write_control_register(control_register cr, std::size_t new_value) -> void; + auto write_control_register(control_register cr, uint64_t new_value) -> void; + + /** + * @brief Sets a specific bit in the CR2. + * + * @note This function reads the current value of the CR2 register, ORs the specified + * bit with the current value, and writes the updated value back to the CR2. + * + * @param flag he flag to set in the CR2. + */ + auto set_cr2_bit(cr2_flags flag) -> void; } // namespace teachos::arch::memory::cpu #endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP diff --git a/arch/x86_64/include/arch/memory/cpu/msr.hpp b/arch/x86_64/include/arch/memory/cpu/msr.hpp index 1403995..49e9bcf 100644 --- a/arch/x86_64/include/arch/memory/cpu/msr.hpp +++ b/arch/x86_64/include/arch/memory/cpu/msr.hpp @@ -35,7 +35,7 @@ namespace teachos::arch::memory::cpu * @param msr The address of the MSR to read. * @return The 64-bit value read from the MSR. */ - auto read_msr(uint32_t msr) -> void; + auto read_msr(uint32_t msr) -> uint64_t; /** * @brief Writes a 64-bit value to a Model-Specific Register (MSR). @@ -58,17 +58,6 @@ namespace teachos::arch::memory::cpu * @param flag The flag to set in the EFER register. */ auto set_efer_bit(efer_flags flag) -> void; - - /** - * @brief Enables the No-Execute Enable (NXE) bit in the Extended Feature Enable Register (EFER). - * - * @note This function reads the current value of the EFER register, enables the NXE bit - * (bit 11), and writes the updated value back to the EFER register. Enabling the NXE - * bit allows the processor to support No-Execute memory regions, which are required - * for certain memory protection features like Data Execution Prevention (DEP). - */ - auto enable_nxe_bit() -> void; - } // namespace teachos::arch::memory::cpu #endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_NXE_HPP \ No newline at end of file diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index c111f22..ea1a157 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -2,6 +2,7 @@ #include "arch/exception_handling/assert.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" +#include "arch/memory/cpu/msr.hpp" #include "arch/memory/multiboot/reader.hpp" #include "arch/memory/paging/kernel_mapper.hpp" #include "arch/memory/paging/temporary_page.hpp" @@ -20,6 +21,9 @@ namespace teachos::arch::kernel auto const memory_information = memory::multiboot::read_multiboot2(); memory::allocator::area_frame_allocator allocator(memory_information); + memory::cpu::set_cr2_bit(memory::cpu::cr2_flags::WRITE_PROTECT); + memory::cpu::set_efer_bit(memory::cpu::efer_flags::NXE); + memory::paging::kernel_mapper kernel(allocator, memory_information); kernel.remap_kernel(); video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); diff --git a/arch/x86_64/src/memory/cpu/control_register.cpp b/arch/x86_64/src/memory/cpu/control_register.cpp index 38a887c..7624244 100644 --- a/arch/x86_64/src/memory/cpu/control_register.cpp +++ b/arch/x86_64/src/memory/cpu/control_register.cpp @@ -2,24 +2,26 @@ #include "arch/exception_handling/assert.hpp" +#include + namespace teachos::arch::memory::cpu { - auto read_control_register(control_register cr) -> std::size_t + auto read_control_register(control_register cr) -> uint64_t { - std::size_t current_value; + uint64_t current_value; switch (cr) { case control_register::CR0: - asm volatile("movq %%cr0, %[output]" : [output] "=r"(current_value)); + asm volatile("mov %%cr0, %[output]" : [output] "=r"(current_value)); break; case control_register::CR2: - asm volatile("movq %%cr2, %[output]" : [output] "=r"(current_value)); + asm volatile("mov %%cr2, %[output]" : [output] "=r"(current_value)); break; case control_register::CR3: - asm volatile("movq %%cr3, %[output]" : [output] "=r"(current_value)); + asm volatile("mov %%cr3, %[output]" : [output] "=r"(current_value)); break; case control_register::CR4: - asm volatile("movq %%cr4, %[output]" : [output] "=r"(current_value)); + asm volatile("mov %%cr4, %[output]" : [output] "=r"(current_value)); break; default: exception_handling::assert(false, @@ -29,30 +31,30 @@ namespace teachos::arch::memory::cpu return current_value; } - auto write_control_register(control_register cr, std::size_t new_value) -> void + auto write_control_register(control_register cr, uint64_t new_value) -> void { switch (cr) { case control_register::CR0: - asm volatile("movq %[input], %%cr0" + asm volatile("mov %[input], %%cr0" : /* no output from call */ : [input] "r"(new_value) : "memory"); break; case control_register::CR2: - asm volatile("movq %[input], %%cr2" + asm volatile("mov %[input], %%cr2" : /* no output from call */ : [input] "r"(new_value) : "memory"); break; case control_register::CR3: - asm volatile("movq %[input], %%cr3" + asm volatile("mov %[input], %%cr3" : /* no output from call */ : [input] "r"(new_value) : "memory"); break; case control_register::CR4: - asm volatile("movq %[input], %%cr4" + asm volatile("mov %[input], %%cr4" : /* no output from call */ : [input] "r"(new_value) : "memory"); @@ -63,4 +65,10 @@ namespace teachos::arch::memory::cpu break; } } + + auto set_cr2_bit(cr2_flags flag) -> void + { + auto const cr2 = read_control_register(control_register::CR2); + write_control_register(control_register::CR2, static_cast::type>(flag) | cr2); + } } // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/cpu/msr.cpp b/arch/x86_64/src/memory/cpu/msr.cpp index 6e3d1d3..b83f902 100644 --- a/arch/x86_64/src/memory/cpu/msr.cpp +++ b/arch/x86_64/src/memory/cpu/msr.cpp @@ -4,7 +4,7 @@ namespace teachos::arch::memory::cpu { namespace { - constexpr uint32_t IA32_EFER_ADDRESS = 0xC0000080; + auto constexpr IA32_EFER_ADDRESS = 0xC0000080; } auto read_msr(uint32_t msr) -> uint64_t @@ -25,9 +25,7 @@ namespace teachos::arch::memory::cpu auto set_efer_bit(efer_flags flag) -> void { - uint64_t const efer = read_msr(IA32_EFER_ADDRESS); - write_msr(IA32_EFER_ADDRESS, static_cast(flag) | efer); + auto const efer = read_msr(IA32_EFER_ADDRESS); + write_msr(IA32_EFER_ADDRESS, static_cast::type>(flag) | efer); } - - auto enable_nxe_bit() -> void { set_efer_bit(efer_flags::NXE); } } // namespace teachos::arch::memory::cpu -- cgit v1.2.3 From 50d99ddaff23f43c3b678021d1ebc0455860d998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 10 Nov 2024 12:09:30 +0000 Subject: Remove fixed todo --- arch/x86_64/src/memory/paging/page_entry.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index aae5013..08702cf 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -27,8 +27,7 @@ namespace teachos::arch::memory::paging } if (!elf_flags.contains_flags(multiboot::elf_section_flags::EXECUTABLE_CODE)) { - // TODO: Ensure to set the NXE bit, if we don't using this entry flag causes crashes - // flags = flags.to_ulong() | entry::EXECUTING_CODE_FORBIDDEN; + flags = flags.to_ulong() | entry::EXECUTING_CODE_FORBIDDEN; } } -- cgit v1.2.3 From 0a299adbb31605cc3018a5f37132113acd19bf4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 10 Nov 2024 13:57:29 +0000 Subject: Use |= operator where possible --- arch/x86_64/src/memory/paging/page_entry.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 08702cf..5aa0982 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -19,15 +19,15 @@ namespace teachos::arch::memory::paging { if (elf_flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) { - flags = flags.to_ulong() | entry::PRESENT; + flags |= entry::PRESENT; } if (elf_flags.contains_flags(multiboot::elf_section_flags::WRITABLE)) { - flags = flags.to_ulong() | entry::WRITABLE; + flags |= entry::WRITABLE; } if (!elf_flags.contains_flags(multiboot::elf_section_flags::EXECUTABLE_CODE)) { - flags = flags.to_ulong() | entry::EXECUTING_CODE_FORBIDDEN; + flags |= entry::EXECUTING_CODE_FORBIDDEN; } } -- cgit v1.2.3 From 325d540236476b50af78e5781e3afead9e910359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 11 Nov 2024 10:10:08 +0000 Subject: Add todos to section that cause the crash --- arch/x86_64/src/memory/paging/inactive_page_table.cpp | 1 + arch/x86_64/src/memory/paging/page_entry.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp index 4e0610e..d2eecb8 100644 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -12,6 +12,7 @@ namespace teachos::arch::memory::paging temporary_page & temporary_page) : page_table_level_4_frame{frame} { + // TODO: Here the exact same mapping code 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); diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index 5aa0982..ba3deb3 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -51,6 +51,7 @@ namespace teachos::arch::memory::paging { exception_handling::assert((frame.start_address() & ~PHYSICAL_ADDRESS_MASK) == 0, "[Paging Entry] Start address is not aligned with page"); + // TODO: Crash when trying to write invalid value at 0xffffff8657f5d5f0 flags = frame.start_address() | additional_flags.to_ulong(); } -- cgit v1.2.3 From 0f3c5c2bc02d7aa48f8edbe42a67dd91821032b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 11 Nov 2024 12:02:35 +0000 Subject: Mark the two methods that first work and then fail --- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 1 + arch/x86_64/src/memory/paging/inactive_page_table.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 53284b6..10fad0c 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -76,6 +76,7 @@ namespace teachos::arch::memory::paging { auto const backup = allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); + // TODO: This creates invalid page table that points to nothing, is it the frame (current level 4 page table) auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp index d2eecb8..8ebc8ce 100644 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -12,7 +12,7 @@ namespace teachos::arch::memory::paging temporary_page & temporary_page) : page_table_level_4_frame{frame} { - // TODO: Here the exact same mapping code + // TODO: Here the exact same mapping code but it actually works?, is it the different 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); -- cgit v1.2.3 From 0ca0c40c197c214288ad2ed1179ae9ae28c50194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 11 Nov 2024 14:16:18 +0000 Subject: Improve calculation of kernel end and start address. --- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 3 ++- arch/x86_64/src/kernel/main.cpp | 4 +++- arch/x86_64/src/memory/multiboot/reader.cpp | 9 +++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 10fad0c..f01bd37 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -38,7 +38,7 @@ namespace teachos::arch::memory::paging * inactive page table, that is not used by the CPU to ensure we are not changign memory that we are using. Because * remapping active kernel memory in the kernel wouldn't work. */ - auto remap_kernel() -> void + auto remap_kernel() -> active_page_table & { temporary_page temporary_page{virtual_page{0xCAFEBABE}, allocator}; auto & active_table = active_page_table::create_or_get(); @@ -51,6 +51,7 @@ namespace teachos::arch::memory::paging auto const old_level_4_page = virtual_page::containing_address(old_table.page_table_level_4_frame.start_address()); active_table.unmap_page(allocator, old_level_4_page); + return active_table; } private: diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index ea1a157..f9b252d 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -25,9 +25,11 @@ namespace teachos::arch::kernel memory::cpu::set_efer_bit(memory::cpu::efer_flags::NXE); memory::paging::kernel_mapper kernel(allocator, memory_information); - kernel.remap_kernel(); + auto & active_table = kernel.remap_kernel(); video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); + // TODO: Map heap virtual pages with active table + /* size_t address = 42 * memory::paging::PAGE_TABLE_ENTRY_COUNT * memory::paging::PAGE_TABLE_ENTRY_COUNT * memory::allocator::PAGE_FRAME_SIZE; // 42th P3 entry diff --git a/arch/x86_64/src/memory/multiboot/reader.cpp b/arch/x86_64/src/memory/multiboot/reader.cpp index 1dd18ff..2bf5b25 100644 --- a/arch/x86_64/src/memory/multiboot/reader.cpp +++ b/arch/x86_64/src/memory/multiboot/reader.cpp @@ -6,6 +6,7 @@ #include "arch/memory/multiboot/info.hpp" #include +#include namespace teachos::arch::memory::multiboot { @@ -56,11 +57,15 @@ namespace teachos::arch::memory::multiboot 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( - sections, [](auto const & a, auto const & b) { return a.physical_address < b.physical_address; }); + 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(sections, [](auto const & a, auto const & b) { + 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; -- cgit v1.2.3 From f45fdae9913a9d8e003cf681621e71516b2054b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 12 Nov 2024 08:50:05 +0000 Subject: Add notes on why system crashes --- arch/x86_64/include/arch/memory/paging/active_page_table.hpp | 7 +++++-- arch/x86_64/src/kernel/main.cpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index c7d835a..c5b972b 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -166,8 +166,11 @@ namespace teachos::arch::memory::paging } // TODO: Flushing only specifc page does not work and cause temporary_page.map_table_frame to return an invalid // page table (Memory inside buffer shows nothing) - cpu::tlb_flush(page.start_address()); - // cpu::tlb_flush_all(); + // cpu::tlb_flush(page.start_address()); + // This is the case, because we have unmapped the active page and it is completly invalid, if we only flush one + // page, the other pages which are huge still exist in the cache and can therefore still be accessed. But because + // they are huge pages the temporary page is not mapped correctly. + cpu::tlb_flush_all(); } private: diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index f9b252d..679fb8d 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -25,7 +25,7 @@ namespace teachos::arch::kernel memory::cpu::set_efer_bit(memory::cpu::efer_flags::NXE); memory::paging::kernel_mapper kernel(allocator, memory_information); - auto & active_table = kernel.remap_kernel(); + kernel.remap_kernel(); video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); // TODO: Map heap virtual pages with active table -- cgit v1.2.3 From 13887617b17d9387e218ce702087b6a7140af9bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 12 Nov 2024 09:26:12 +0000 Subject: Remap kernel inplace. --- .../include/arch/memory/paging/kernel_mapper.hpp | 23 +++++++++++----------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index f01bd37..f673da4 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -40,17 +40,17 @@ namespace teachos::arch::memory::paging */ auto remap_kernel() -> active_page_table & { - temporary_page temporary_page{virtual_page{0xCAFEBABE}, allocator}; + /*temporary_page temporary_page{virtual_page{0xCAFEBABE}, allocator};*/ auto & active_table = active_page_table::create_or_get(); - auto const frame = allocator.allocate_frame(); + /*auto const frame = allocator.allocate_frame(); exception_handling::assert(frame.has_value(), "[Kernel Mapper] Frame could not be allocated and therefore kernel not mapped"); - inactive_page_table new_table{frame.value(), active_table, temporary_page}; - remap_elf_kernel_sections(new_table, temporary_page, active_table); - auto const old_table = switch_active_page_table(new_table); + inactive_page_table new_table{frame.value(), active_table, temporary_page};*/ + remap_elf_kernel_sections(active_table); + /*auto const old_table = switch_active_page_table(new_table); auto const old_level_4_page = virtual_page::containing_address(old_table.page_table_level_4_frame.start_address()); - active_table.unmap_page(allocator, old_level_4_page); + active_table.unmap_page(allocator, old_level_4_page);*/ return active_table; } @@ -72,21 +72,20 @@ namespace teachos::arch::memory::paging * @param active_table Active level 4 page table that has its recursive mapping overwritten temporarily and then * restored once the process is finished. */ - auto remap_elf_kernel_sections(inactive_page_table inactive_table, temporary_page & temporary_page, - active_page_table & active_table) -> void + auto remap_elf_kernel_sections(active_page_table & active_table) -> void { - auto const backup = + /*auto const backup = allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); // TODO: This creates invalid page table that points to nothing, is it the frame (current level 4 page table) auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); - active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); + active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE);*/ cpu::tlb_flush_all(); map_elf_kernel_sections(active_table); - page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); + /*page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE);*/ cpu::tlb_flush_all(); - temporary_page.unmap_page(active_table); + /*temporary_page.unmap_page(active_table);*/ } /** -- cgit v1.2.3 From 7db57d7a47671b4023e34413a2276611e1c65f72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 12 Nov 2024 10:24:12 +0000 Subject: Add comment to flush all and remove now redudant todos. --- arch/x86_64/include/arch/memory/paging/active_page_table.hpp | 9 +++------ arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 1 - arch/x86_64/src/memory/paging/inactive_page_table.cpp | 1 - arch/x86_64/src/memory/paging/page_entry.cpp | 1 - 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index c5b972b..1bc5b74 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -164,12 +164,9 @@ namespace teachos::arch::memory::paging break; } } - // TODO: Flushing only specifc page does not work and cause temporary_page.map_table_frame to return an invalid - // page table (Memory inside buffer shows nothing) - // cpu::tlb_flush(page.start_address()); - // This is the case, because we have unmapped the active page and it is completly invalid, if we only flush one - // page, the other pages which are huge still exist in the cache and can therefore still be accessed. But because - // they are huge pages the temporary page is not mapped correctly. + // Uses flush all instead of cpu::tlb_flush(page.start_address());, because when we unmap the active page and + // only flush one page, the rest of the page which is huge still exist in the cache and + // can therefore still be accessed. But because they are huge pages the new mapping can not be accessed correctly. cpu::tlb_flush_all(); } diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index f673da4..bcc3eba 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -76,7 +76,6 @@ namespace teachos::arch::memory::paging { /*auto const backup = allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); - // TODO: This creates invalid page table that points to nothing, is it the frame (current level 4 page table) auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE);*/ diff --git a/arch/x86_64/src/memory/paging/inactive_page_table.cpp b/arch/x86_64/src/memory/paging/inactive_page_table.cpp index 8ebc8ce..4e0610e 100644 --- a/arch/x86_64/src/memory/paging/inactive_page_table.cpp +++ b/arch/x86_64/src/memory/paging/inactive_page_table.cpp @@ -12,7 +12,6 @@ namespace teachos::arch::memory::paging temporary_page & temporary_page) : page_table_level_4_frame{frame} { - // TODO: Here the exact same mapping code but it actually works?, is it the different 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); diff --git a/arch/x86_64/src/memory/paging/page_entry.cpp b/arch/x86_64/src/memory/paging/page_entry.cpp index ba3deb3..5aa0982 100644 --- a/arch/x86_64/src/memory/paging/page_entry.cpp +++ b/arch/x86_64/src/memory/paging/page_entry.cpp @@ -51,7 +51,6 @@ namespace teachos::arch::memory::paging { exception_handling::assert((frame.start_address() & ~PHYSICAL_ADDRESS_MASK) == 0, "[Paging Entry] Start address is not aligned with page"); - // TODO: Crash when trying to write invalid value at 0xffffff8657f5d5f0 flags = frame.start_address() | additional_flags.to_ulong(); } -- cgit v1.2.3 From 9507633f04e672b3dadf1385b1562fb3101d0ea3 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 12 Nov 2024 10:41:23 +0000 Subject: add debug statements --- .../include/arch/memory/paging/active_page_table.hpp | 1 + arch/x86_64/src/kernel/main.cpp | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index c5b972b..9931711 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -214,6 +214,7 @@ namespace teachos::arch::memory::paging allocator.deallocate_frame(frame.value()); } + public: page_table_handle active_handle; ///< Underlying active level 4 page table }; diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 679fb8d..92d277d 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -25,7 +25,21 @@ namespace teachos::arch::kernel memory::cpu::set_efer_bit(memory::cpu::efer_flags::NXE); memory::paging::kernel_mapper kernel(allocator, memory_information); - kernel.remap_kernel(); + auto & active_table = kernel.remap_kernel(); + auto x = active_table.active_handle.next_table(0); + if (x.has_value()) + { + auto y = x.value().next_table(0); + + if (y.has_value()) + { + auto z = y.value().next_table(0); + if (z.has_value()) + { + } + } + } + video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); // TODO: Map heap virtual pages with active table -- cgit v1.2.3 From d10bc808b29b0b647cbbb6c92d253fbb8c5cf431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 12 Nov 2024 10:59:50 +0000 Subject: Fix next table overwriting old page handle --- arch/x86_64/include/arch/memory/paging/page_table.hpp | 11 ++++++----- arch/x86_64/src/memory/paging/page_table.cpp | 5 +++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 9449ef2..7a15875 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -72,7 +72,7 @@ namespace teachos::arch::memory::paging * * @param table_index Index of this page table in the page table one level lower. */ - auto next_table(std::size_t table_index) -> std::optional; + auto next_table(std::size_t table_index) const -> std::optional; /** * @brief Call next_table and then checks if the table already exists, if it does not it will use the given @@ -120,8 +120,8 @@ namespace teachos::arch::memory::paging auto operator[](std::size_t index) const -> entry const &; /** - * @brief Decrements the page table level enum by one, is defined so we can use it as a replacement for an - * int index in a range based for loop. + * @brief Pre decrement operator on the page table level enum, is defined so we can use it as a replacement + * for an int index in a range based for loop. * * @note Will halt execution if called with page_table_handle::LEVEL1, because there is no level below. Has to be * defined as either a friend function or inline header method, because we define an operator of another type. In @@ -132,12 +132,13 @@ namespace teachos::arch::memory::paging * header file. * * @param value Value we want to decrement on - * @return level New level value decrement by one, meaning the level is also decrement by one Level4 --> Level3, ... + * @return New level value decrement by one, meaning the level is also decrement by one Level4 --> Level3, ... */ friend auto operator--(level & value) -> level &; private: - page_table * table; ///< Handle to underlying page table, can never be null (invariant ensured by constructor) + page_table * table; ///< Handle to underlying page table, can never be null (invariant ensured by + ///< constructor) level table_level; ///< Level page table is currently on, depends on how often next_level was ///< called successfully. }; diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index a39c235..eb11810 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -100,14 +100,15 @@ namespace teachos::arch::memory::paging auto page_table_handle::is_empty() const -> bool { return table->is_empty(); } - auto page_table_handle::next_table(std::size_t table_index) -> std::optional + 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()) { - return page_table_handle{next_table.value(), --table_level}; + auto const new_level = static_cast(table_level - 1); + return page_table_handle{next_table.value(), new_level}; } return std::nullopt; } -- cgit v1.2.3 From 266c01528fdc994e4e326de37f99d67f9a0eb3a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 12 Nov 2024 11:00:08 +0000 Subject: Remove duplicate method --- arch/x86_64/src/kernel/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 92d277d..60fa145 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -40,7 +40,6 @@ namespace teachos::arch::kernel } } video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); - video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); // TODO: Map heap virtual pages with active table -- cgit v1.2.3 From d32130f8a81247e450490d31074ec6501dd4aeb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 13 Nov 2024 12:37:08 +0000 Subject: Note that mapping seems to be working --- arch/x86_64/src/kernel/main.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 60fa145..6c0faf4 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -27,19 +27,15 @@ namespace teachos::arch::kernel memory::paging::kernel_mapper kernel(allocator, memory_information); auto & active_table = kernel.remap_kernel(); auto x = active_table.active_handle.next_table(0); - if (x.has_value()) + auto y = x.value().next_table(0); + auto z = y.value().next_table(0); + if (z.has_value()) { - auto y = x.value().next_table(0); - - if (y.has_value()) - { - auto z = y.value().next_table(0); - if (z.has_value()) - { - } - } + video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); } - video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); + + // TODO: Seems to work correctly, Level 4 Index 0, Level 3 Index 0, Level 2 Index 0, Level 1 Index 184 = 753667 from + // mapping vga is still mapped // TODO: Map heap virtual pages with active table -- cgit v1.2.3 From 52c1979b22c5e66459659a9cda8d69a2c9b148ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 13 Nov 2024 14:59:12 +0000 Subject: Add note on possible options to enable PIC / PIE --- arch/x86_64/src/kernel/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 6c0faf4..5b0f2c3 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -36,6 +36,9 @@ namespace teachos::arch::kernel // TODO: Seems to work correctly, Level 4 Index 0, Level 3 Index 0, Level 2 Index 0, Level 1 Index 184 = 753667 from // mapping vga is still mapped + // set(CMAKE_POSITION_INDEPENDENT_CODE ON), should enable position independent code, but mapping still does not work + // with same error? + // Can we change the gcc call? gcc -fPIC -c mylibrary.cpp // TODO: Map heap virtual pages with active table -- cgit v1.2.3 From fde3f969c5c45d4cdbd5ec92c4d07fd157194300 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 19 Nov 2024 09:38:44 +0100 Subject: memory: fix kernel remapping --- .../arch/memory/paging/active_page_table.hpp | 23 ++-------------------- .../include/arch/memory/paging/kernel_mapper.hpp | 23 +++++++++++----------- 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index a60b3ad..8b12800 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -136,7 +136,6 @@ namespace teachos::arch::memory::paging "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); auto current_handle = active_handle; - std::array handles{current_handle, current_handle, current_handle}; for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) { @@ -146,28 +145,10 @@ namespace teachos::arch::memory::paging // fail. This can only mean that we attempted to unmap a huge page, which is not supported in the first place. exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); current_handle = next_handle.value(); - // The level is used as the index, because it ensures the first level is the lowest one and then the remaining - // levels in ascending order. This is required, because we first have to clear the Level 1 page entry to check - // if the Level 1 page is now empty, to clear the Level 2 page entry, which will then also check if the Level 2 - // page is empty and clear the Level 3 page entry and so on. - handles.at(level - 1U) = current_handle; } - // Unmaps all entries starting from the Level 1 page table, and unmaps higher levels as well if that entry was the - // last one. We check if it was the last one using is empty on the page table handle, when we have removed the - // page to be unmapped. - for (auto & handle : handles) - { - unmap_page_table_entry(allocator, page, handle); - if (!handle.is_empty()) - { - break; - } - } - // Uses flush all instead of cpu::tlb_flush(page.start_address());, because when we unmap the active page and - // only flush one page, the rest of the page which is huge still exist in the cache and - // can therefore still be accessed. But because they are huge pages the new mapping can not be accessed correctly. - cpu::tlb_flush_all(); + unmap_page_table_entry(allocator, page, current_handle); + cpu::tlb_flush(page.start_address()); } private: diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index bcc3eba..f980451 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -40,17 +40,17 @@ namespace teachos::arch::memory::paging */ auto remap_kernel() -> active_page_table & { - /*temporary_page temporary_page{virtual_page{0xCAFEBABE}, allocator};*/ + temporary_page temporary_page{virtual_page{0xCAFEBABE}, allocator}; auto & active_table = active_page_table::create_or_get(); - /*auto const frame = allocator.allocate_frame(); + auto const frame = allocator.allocate_frame(); exception_handling::assert(frame.has_value(), "[Kernel Mapper] Frame could not be allocated and therefore kernel not mapped"); - inactive_page_table new_table{frame.value(), active_table, temporary_page};*/ - remap_elf_kernel_sections(active_table); - /*auto const old_table = switch_active_page_table(new_table); + inactive_page_table new_table{frame.value(), active_table, temporary_page}; + remap_elf_kernel_sections(new_table, temporary_page, active_table); + auto const old_table = switch_active_page_table(new_table); auto const old_level_4_page = virtual_page::containing_address(old_table.page_table_level_4_frame.start_address()); - active_table.unmap_page(allocator, old_level_4_page);*/ + active_table.unmap_page(allocator, old_level_4_page); return active_table; } @@ -72,19 +72,20 @@ namespace teachos::arch::memory::paging * @param active_table Active level 4 page table that has its recursive mapping overwritten temporarily and then * restored once the process is finished. */ - auto remap_elf_kernel_sections(active_page_table & active_table) -> void + auto remap_elf_kernel_sections(inactive_page_table & inactive_table, temporary_page & temporary_page, + active_page_table & active_table) -> void { - /*auto const backup = + auto const backup = allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); - active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE);*/ + active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); cpu::tlb_flush_all(); map_elf_kernel_sections(active_table); - /*page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE);*/ + page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); cpu::tlb_flush_all(); - /*temporary_page.unmap_page(active_table);*/ + temporary_page.unmap_page(active_table); } /** -- cgit v1.2.3 From d1baeb7ec209ddf205dc90d39a5de4c7ecf9fe81 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 19 Nov 2024 17:22:40 +0100 Subject: build: disable RTTI When using virtual functions while RTTI is enabled, the compiler generates code to support the use of dynamic_cast etc. This code requires the use of the free store (heap) which is not yet available. Disabling RTTI also disables the generation of the associated support code, thus making it possible for us to use virtual functions. --- cmake/Platforms/x86_64.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Platforms/x86_64.cmake b/cmake/Platforms/x86_64.cmake index c31150c..6e99b62 100644 --- a/cmake/Platforms/x86_64.cmake +++ b/cmake/Platforms/x86_64.cmake @@ -15,7 +15,7 @@ set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") set(CMAKE_C_COMPILER "x86_64-elf-gcc") set(CMAKE_CXX_COMPILER "x86_64-elf-g++") -set(CMAKE_CXX_FLAGS_INIT "-m64 -mno-red-zone -mcmodel=large -fno-exceptions -ffunction-sections -fdata-sections") +set(CMAKE_CXX_FLAGS_INIT "-m64 -mno-red-zone -mcmodel=large -fno-rtti -fno-exceptions -ffunction-sections -fdata-sections") set(CMAKE_CXX_FLAGS_DEBUG "-ggdb3") set(CMAKE_ASM_FLAGS_DEBUG "-ggdb3") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-ggdb3") -- cgit v1.2.3 From 27cd88e4d39489a845483e574f79fd67ef3d4fcd Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 19 Nov 2024 17:30:53 +0100 Subject: runtime: catch pure virtual function calls --- arch/x86_64/CMakeLists.txt | 1 + arch/x86_64/src/exception_handling/pure_virtual.cpp | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 arch/x86_64/src/exception_handling/pure_virtual.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index f868b4e..1444054 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -65,6 +65,7 @@ target_sources("_exception" PRIVATE "src/exception_handling/assert.cpp" "src/exception_handling/abort.cpp" "src/exception_handling/panic.cpp" + "src/exception_handling/pure_virtual.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/src/exception_handling/pure_virtual.cpp b/arch/x86_64/src/exception_handling/pure_virtual.cpp new file mode 100644 index 0000000..67772f7 --- /dev/null +++ b/arch/x86_64/src/exception_handling/pure_virtual.cpp @@ -0,0 +1,6 @@ +#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!"); +} -- cgit v1.2.3 From 1cd666241b59b800818812220e28b8b8572e4263 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 19 Nov 2024 17:32:02 +0100 Subject: paging: de-templetize implementation --- arch/x86_64/CMakeLists.txt | 1 + .../arch/memory/allocator/area_frame_allocator.hpp | 7 +- .../include/arch/memory/allocator/concept.hpp | 22 ----- .../arch/memory/allocator/frame_allocator.hpp | 19 +++++ .../arch/memory/allocator/tiny_frame_allocator.hpp | 11 ++- .../arch/memory/paging/active_page_table.hpp | 83 +++---------------- .../include/arch/memory/paging/kernel_mapper.hpp | 94 +++------------------- .../include/arch/memory/paging/page_table.hpp | 23 +----- .../include/arch/memory/paging/temporary_page.hpp | 8 +- arch/x86_64/src/kernel/main.cpp | 1 + .../src/memory/allocator/area_frame_allocator.cpp | 2 +- .../src/memory/allocator/tiny_frame_allocator.cpp | 4 +- .../x86_64/src/memory/paging/active_page_table.cpp | 67 +++++++++++++++ arch/x86_64/src/memory/paging/kernel_mapper.cpp | 94 ++++++++++++++++++++++ arch/x86_64/src/memory/paging/page_table.cpp | 21 +++++ arch/x86_64/src/memory/paging/temporary_page.cpp | 9 ++- 16 files changed, 249 insertions(+), 217 deletions(-) delete mode 100644 arch/x86_64/include/arch/memory/allocator/concept.hpp create mode 100644 arch/x86_64/include/arch/memory/allocator/frame_allocator.hpp create mode 100644 arch/x86_64/src/memory/paging/kernel_mapper.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 1444054..7f3a203 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -52,6 +52,7 @@ target_sources("_memory" PRIVATE "src/memory/paging/virtual_page.cpp" "src/memory/paging/active_page_table.cpp" "src/memory/paging/inactive_page_table.cpp" + "src/memory/paging/kernel_mapper.cpp" "src/memory/cpu/tlb.cpp" "src/memory/cpu/control_register.cpp" "src/memory/cpu/msr.cpp" diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp index f2b77f8..f1a3a64 100644 --- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP #define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP +#include "arch/memory/allocator/frame_allocator.hpp" #include "arch/memory/allocator/physical_frame.hpp" #include "arch/memory/multiboot/reader.hpp" @@ -11,7 +12,7 @@ namespace teachos::arch::memory::allocator /** * @brief Allocates memory using memory areas read from the multiboot2 information pointer. */ - struct area_frame_allocator + struct area_frame_allocator : frame_allocator { /** * @brief Constructor @@ -32,7 +33,7 @@ namespace teachos::arch::memory::allocator * * @return next free physical frame or nullopt if none was found. */ - auto allocate_frame() -> std::optional; + auto allocate_frame() -> std::optional override; /** * @brief Deallocates a previously allocated physical frame. @@ -43,7 +44,7 @@ namespace teachos::arch::memory::allocator * * @param physical_frame Previously allocated physical_frame that should be deallocated. */ - auto deallocate_frame(physical_frame physical_frame) -> void; + auto deallocate_frame(physical_frame const & physical_frame) -> void override; private: /** diff --git a/arch/x86_64/include/arch/memory/allocator/concept.hpp b/arch/x86_64/include/arch/memory/allocator/concept.hpp deleted file mode 100644 index 4a7ab72..0000000 --- a/arch/x86_64/include/arch/memory/allocator/concept.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP - -#include "arch/memory/allocator/physical_frame.hpp" - -#include - -namespace teachos::arch::memory::allocator -{ - /** - * @brief Frame allocator concept - * - * @tparam T - */ - template - concept FrameAllocator = requires(T t, physical_frame a) { - { t.allocate_frame() } -> std::same_as>; - { t.deallocate_frame(a) } -> std::same_as; - }; -} // namespace teachos::arch::memory::allocator - -#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP diff --git a/arch/x86_64/include/arch/memory/allocator/frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/frame_allocator.hpp new file mode 100644 index 0000000..9316ca9 --- /dev/null +++ b/arch/x86_64/include/arch/memory/allocator/frame_allocator.hpp @@ -0,0 +1,19 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_FRAME_ALLOCATOR_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_FRAME_ALLOCATOR_HPP + +#include "arch/memory/allocator/physical_frame.hpp" + +#include + +namespace teachos::arch::memory::allocator +{ + + struct frame_allocator + { + auto virtual allocate_frame() -> std::optional = 0; + auto virtual deallocate_frame(physical_frame const & frame) -> void = 0; + }; // namespace teachos::arch::memory::allocator + +} // namespace teachos::arch::memory::allocator + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp index a96b743..c449ac8 100644 --- a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -1,8 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP #define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP -#include "arch/memory/allocator/area_frame_allocator.hpp" -#include "arch/memory/allocator/concept.hpp" +#include "arch/memory/allocator/frame_allocator.hpp" #include "arch/memory/allocator/physical_frame.hpp" #include @@ -17,7 +16,7 @@ namespace teachos::arch::memory::allocator /** * @brief Allocates memory using memory areas read from the multiboot2 information pointer. */ - struct tiny_frame_allocator + struct tiny_frame_allocator : frame_allocator { /** * @brief Constructor. @@ -27,7 +26,7 @@ namespace teachos::arch::memory::allocator * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate * entries *when a new page table is required. */ - tiny_frame_allocator(area_frame_allocator & allocator); + tiny_frame_allocator(frame_allocator & allocator); /** * @brief Allocate memory by finding and returning one of the three free physical frames. @@ -35,7 +34,7 @@ namespace teachos::arch::memory::allocator * @return First free physical frames of the three frames held by this allocator or nullopt if we used up all three * frames already. */ - auto allocate_frame() -> std::optional; + auto allocate_frame() -> std::optional override; /** * @brief Deallocates one of the three previously allocated physical frames. @@ -45,7 +44,7 @@ namespace teachos::arch::memory::allocator * * @param physical_frame Previously allocated physical_frame that should be deallocated. */ - auto deallocate_frame(physical_frame physical_frame) -> void; + auto deallocate_frame(physical_frame const & physical_frame) -> void override; private: std::array, TINY_ALLOCATOR_FRAMES_COUNT> frames = diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index 8b12800..e558fa5 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -1,12 +1,13 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP -#include "arch/exception_handling/assert.hpp" -#include "arch/memory/allocator/concept.hpp" -#include "arch/memory/cpu/tlb.hpp" +#include "arch/memory/allocator/frame_allocator.hpp" +#include "arch/memory/allocator/physical_frame.hpp" +#include "arch/memory/paging/page_table.hpp" #include "arch/memory/paging/virtual_page.hpp" #include +#include #include namespace teachos::arch::memory::paging @@ -65,44 +66,21 @@ namespace teachos::arch::memory::paging * @note Allocates and maps an entry in every page level if it does not exists yet down to level 1. If the level 1 * page table already exists it halts execution instead. * - * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and - * deallocate method. * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate * entries when a new page table is required. * @param page Virtual page that is being mapped. * @param frame Physical frame that the virtual page will be mapped to. * @param flags A bitset of flags that configure the page table entry for this mapping. */ - template - auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, - std::bitset<64U> flags) -> void - { - auto current_handle = active_handle; - - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) - { - current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level)); - } - - auto & level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; - arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), - "[Page Mapper] Unable to map huge pages"); - arch::exception_handling::assert(level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); - level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT); - } - + auto map_page_to_frame(allocator::frame_allocator & allocator, virtual_page page, allocator::physical_frame frame, + std::bitset<64U> flags) -> void; /** * @brief Allocates the next free frame and then uses that frame to call map_page_to_frame. * * @see map_page_to_frame */ - template - auto map_next_free_page_to_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void - { - auto const frame = allocator.allocate_frame(); - exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); - map_page_to_frame(allocator, page, frame.value(), flags); - } + auto map_next_free_page_to_frame(allocator::frame_allocator & allocator, virtual_page page, + std::bitset<64U> flags) -> void; /** * @brief Gets the corresponding page the given frame has to be contained in and uses that to call @@ -110,12 +88,8 @@ namespace teachos::arch::memory::paging * * @see map_page_to_frame */ - template - auto identity_map(T & allocator, allocator::physical_frame frame, std::bitset<64U> flags) -> void - { - auto const page = virtual_page::containing_address(frame.start_address()); - map_page_to_frame(allocator, page, frame, flags); - } + auto identity_map(allocator::frame_allocator & allocator, allocator::physical_frame frame, + std::bitset<64U> flags) -> void; /** * @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags. @@ -129,27 +103,7 @@ namespace teachos::arch::memory::paging * entries when a new page table is required. * @param page Virtual page that is being unmapped. */ - template - auto unmap_page(T & allocator, virtual_page page) -> void - { - exception_handling::assert(translate_page(page).has_value(), - "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); - - auto current_handle = active_handle; - - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) - { - auto const level_index = page.get_level_index(level); - auto const next_handle = current_handle.next_table(level_index); - // The next table method failed even tough the page has to be mapped already, because translate_page did not - // fail. This can only mean that we attempted to unmap a huge page, which is not supported in the first place. - exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); - current_handle = next_handle.value(); - } - - unmap_page_table_entry(allocator, page, current_handle); - cpu::tlb_flush(page.start_address()); - } + auto unmap_page(allocator::frame_allocator & allocator, virtual_page page) -> void; private: /** @@ -173,24 +127,13 @@ namespace teachos::arch::memory::paging /** * @brief Unmaps specific page at the current internal handle level. * - * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and - * deallocate method. * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate * entries *when a new page table is required. * @param page Virtual page that is being unmapped. * @param handle Page Table handle we want to access the entry that should be cleared on. */ - template - static auto unmap_page_table_entry(T & allocator, virtual_page page, page_table_handle & handle) -> void - { - auto level_index = page.get_level_index(handle.get_level()); - auto & entry = handle[level_index]; - auto const frame = entry.calculate_pointed_to_frame(); - exception_handling::assert(frame.has_value(), - "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); - entry.set_unused(); - allocator.deallocate_frame(frame.value()); - } + static auto unmap_page_table_entry(allocator::frame_allocator & allocator, virtual_page page, + page_table_handle & handle) -> void; public: page_table_handle active_handle; ///< Underlying active level 4 page table diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index f980451..2f55a13 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -1,11 +1,11 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP -#include "arch/memory/cpu/control_register.hpp" +#include "arch/memory/allocator/frame_allocator.hpp" +#include "arch/memory/multiboot/reader.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/inactive_page_table.hpp" #include "arch/memory/paging/temporary_page.hpp" -#include "arch/video/vga/text.hpp" namespace teachos::arch::memory::paging { @@ -14,7 +14,6 @@ namespace teachos::arch::memory::paging * * @tparam T Contract the allocator that should be used to allocate frames for the remapping process has to fulfill. */ - template struct kernel_mapper { /** @@ -23,12 +22,7 @@ namespace teachos::arch::memory::paging * @param allocator Allocator that should be used to allocate frames for the remapping process. * @param mem_info Information about elf kernel sections required for remapping process. */ - kernel_mapper(T & allocator, multiboot::memory_information const & mem_info) - : allocator(allocator) - , mem_info(mem_info) - { - // Nothing to do - } + kernel_mapper(allocator::frame_allocator & allocator, multiboot::memory_information const & mem_info); /** * @brief Remap the kernel, meaning we map the entire kernel and all of it's elf sections with the correct flags @@ -38,21 +32,7 @@ namespace teachos::arch::memory::paging * inactive page table, that is not used by the CPU to ensure we are not changign memory that we are using. Because * remapping active kernel memory in the kernel wouldn't work. */ - auto remap_kernel() -> active_page_table & - { - temporary_page temporary_page{virtual_page{0xCAFEBABE}, allocator}; - auto & active_table = active_page_table::create_or_get(); - auto const frame = allocator.allocate_frame(); - exception_handling::assert(frame.has_value(), - "[Kernel Mapper] Frame could not be allocated and therefore kernel not mapped"); - inactive_page_table new_table{frame.value(), active_table, temporary_page}; - remap_elf_kernel_sections(new_table, temporary_page, active_table); - auto const old_table = switch_active_page_table(new_table); - auto const old_level_4_page = - virtual_page::containing_address(old_table.page_table_level_4_frame.start_address()); - active_table.unmap_page(allocator, old_level_4_page); - return active_table; - } + auto remap_kernel() -> active_page_table &; private: /** @@ -63,8 +43,8 @@ namespace teachos::arch::memory::paging * Once the remapping process is done we can restore the original recursive mapping with the complete remapped * kernel. * - * @note Because we change the entries we also have to ensure we flush the translation lookaside buffer, before we - * map the entries. + * @note Because we change the entries we also have to ensure we flush the translation lookaside buffer, before + * we map the entries. * * @param inactive_table Level 4 page table we temporarily map the kernel into. * @param temporary_page Temporary page that should be used for the mapping process and then @@ -73,20 +53,7 @@ namespace teachos::arch::memory::paging * restored once the process is finished. */ auto remap_elf_kernel_sections(inactive_page_table & inactive_table, temporary_page & temporary_page, - active_page_table & active_table) -> void - { - auto const backup = - allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); - auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); - - active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); - cpu::tlb_flush_all(); - map_elf_kernel_sections(active_table); - - page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); - cpu::tlb_flush_all(); - temporary_page.unmap_page(active_table); - } + active_page_table & active_table) -> void; /** * @brief Switches the current active table pointed to by the CR3 register with another page table that is currently @@ -95,16 +62,7 @@ namespace teachos::arch::memory::paging * @param new_table Inactive page table that should now be made active and replace the current active one. * @return The previous active page table. */ - auto switch_active_page_table(inactive_page_table new_table) -> inactive_page_table - { - auto const backup = - allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); - auto const old_table = inactive_page_table{backup}; - - auto const new_address = new_table.page_table_level_4_frame.start_address(); - cpu::write_control_register(cpu::control_register::CR3, new_address); - return old_table; - } + auto switch_active_page_table(inactive_page_table new_table) -> inactive_page_table; /** * @brief Maps the required entries according to every elf section and it's contained frames. Additionally each of @@ -113,41 +71,9 @@ namespace teachos::arch::memory::paging * @param active_table Active level 4 page table that should be used to map the required elf sections into entries. * Has had its recursive mapping temporarily replaced and points to unmapped place in memory. */ - auto map_elf_kernel_sections(active_page_table & active_table) -> void - { - exception_handling::assert(!mem_info.sections.empty(), "[Kernel Mapper] Kernel elf sections empty"); - for (auto const & section : mem_info.sections) - { - if (!section.flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) - { - continue; - } - exception_handling::assert(section.physical_address % allocator::PAGE_FRAME_SIZE == 0U, - "[Kernel Mapper] Section must be page aligned"); - auto const start_frame = allocator::physical_frame::containing_address(section.physical_address); - // End address is exclusive, so that it is not part of the section anymore (one past the last frame of this - // section). But end frame would now point to the actual last frame and not one past the last frame, therefore - // we increment by one to get one past the last frame of this section. - auto const end_frame = - ++(allocator::physical_frame::containing_address(section.physical_address + section.section_size - 1)); - - allocator::frame_container::iterator const begin{start_frame}; - allocator::frame_container::iterator const end{end_frame}; - allocator::frame_container const frames{begin, end}; - entry const entry{section.flags}; - - for (auto const & frame : frames) - { - active_table.identity_map(allocator, frame, entry.get_flags()); - } - } - - auto const vga_buffer_frame = - allocator::physical_frame::containing_address(video::vga::text::DEFAULT_VGA_TEXT_BUFFER_ADDRESS); - active_table.identity_map(allocator, vga_buffer_frame, entry::WRITABLE); - } + auto map_elf_kernel_sections(active_page_table & active_table) -> void; - T & allocator; + allocator::frame_allocator & allocator; multiboot::memory_information const & mem_info; ///< Information about elf kernel sections required for remapping process. }; diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 7a15875..24ff8f4 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -2,7 +2,7 @@ #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP #include "arch/exception_handling/assert.hpp" -#include "arch/memory/allocator/concept.hpp" +#include "arch/memory/allocator/frame_allocator.hpp" #include "arch/memory/paging/page_entry.hpp" namespace teachos::arch::memory::paging @@ -82,26 +82,7 @@ namespace teachos::arch::memory::paging * entries when a new page table is required. * @param table_index Index of this page table in the page table one level lower. */ - template - auto next_table_or_create(T & allocator, std::size_t table_index) -> page_table_handle - { - auto next_handle = next_table(table_index); - // If the next table method failed then it means that the page level of the frame we want allocate has not yet - // been created itself. So we have to do that before we are able to allocate the wanted frame. This has to be done - // for every level, meaning we potenitally create a level 4, level 3 and level 2 page entry, each pointing to a - // page table one level below. - if (!next_handle.has_value()) - { - auto const allocated_frame = allocator.allocate_frame(); - exception_handling::assert(allocated_frame.has_value(), "[Page mapper] Unable to allocate frame"); - this->operator[](table_index).set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); - // There should now be an entry at the previously not existent index, therefore we can simply access it again. - next_handle = next_table(table_index); - exception_handling::assert(next_handle.has_value(), "[Page mapper] Unable to create new entry into page table"); - next_handle.value().zero_entries(); - } - return next_handle.value(); - } + auto next_table_or_create(allocator::frame_allocator & allocator, std::size_t table_index) -> page_table_handle; /** * @brief Index operator overload to access specific mutable entry directy. diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp index a850879..3c4301a 100644 --- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -20,13 +20,7 @@ namespace teachos::arch::memory::paging * @param page Page to turn into temporary page * @param allocator Frame allocator used to fill page */ - template - temporary_page(virtual_page page, T & allocator) - : page{page} - , allocator{allocator} - { - // Nothing to do - } + temporary_page(virtual_page page, allocator::frame_allocator & allocator); /** * @brief Unmap the current page. diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 5b0f2c3..8c68a49 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -2,6 +2,7 @@ #include "arch/exception_handling/assert.hpp" #include "arch/memory/allocator/area_frame_allocator.hpp" +#include "arch/memory/cpu/control_register.hpp" #include "arch/memory/cpu/msr.hpp" #include "arch/memory/multiboot/reader.hpp" #include "arch/memory/paging/kernel_mapper.hpp" diff --git a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp index 3bc9676..cb4fefa 100644 --- a/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/area_frame_allocator.cpp @@ -81,5 +81,5 @@ namespace teachos::arch::memory::allocator return allocate_frame(); } - auto area_frame_allocator::deallocate_frame(physical_frame physical_frame) -> void { (void)physical_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 index d37864e..ed000a0 100644 --- a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp @@ -4,7 +4,7 @@ namespace teachos::arch::memory::allocator { - tiny_frame_allocator::tiny_frame_allocator(area_frame_allocator & allocator) + tiny_frame_allocator::tiny_frame_allocator(frame_allocator & allocator) : frames{} { // Has to be done this way, because constructing the constructor with the data from allocator.allocate_frames(), @@ -34,7 +34,7 @@ namespace teachos::arch::memory::allocator return std::nullopt; } - auto tiny_frame_allocator::deallocate_frame(physical_frame physical_frame) -> void + auto tiny_frame_allocator::deallocate_frame(physical_frame const & physical_frame) -> void { for (auto & frame_option : frames) { diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp index 0113869..d2bf683 100644 --- a/arch/x86_64/src/memory/paging/active_page_table.cpp +++ b/arch/x86_64/src/memory/paging/active_page_table.cpp @@ -1,5 +1,7 @@ #include "arch/memory/paging/active_page_table.hpp" +#include "arch/memory/cpu/tlb.hpp" + namespace teachos::arch::memory::paging { namespace @@ -15,6 +17,71 @@ namespace teachos::arch::memory::paging return active_page; } + auto active_page_table::map_page_to_frame(allocator::frame_allocator & allocator, virtual_page page, + allocator::physical_frame frame, std::bitset<64U> flags) -> void + { + auto current_handle = active_handle; + + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) + { + current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level)); + } + + auto & level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; + arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), + "[Page Mapper] Unable to map huge pages"); + arch::exception_handling::assert(level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); + level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT); + } + + auto active_page_table::identity_map(allocator::frame_allocator & allocator, allocator::physical_frame frame, + std::bitset<64U> flags) -> void + { + auto const page = virtual_page::containing_address(frame.start_address()); + map_page_to_frame(allocator, page, frame, flags); + } + + auto active_page_table::map_next_free_page_to_frame(allocator::frame_allocator & allocator, virtual_page page, + std::bitset<64U> flags) -> void + { + auto const frame = allocator.allocate_frame(); + exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); + map_page_to_frame(allocator, page, frame.value(), flags); + } + + auto active_page_table::unmap_page(allocator::frame_allocator & allocator, virtual_page page) -> void + { + exception_handling::assert(translate_page(page).has_value(), + "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); + + auto current_handle = active_handle; + + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) + { + auto const level_index = page.get_level_index(level); + auto const next_handle = current_handle.next_table(level_index); + // The next table method failed even tough the page has to be mapped already, because translate_page did not + // fail. This can only mean that we attempted to unmap a huge page, which is not supported in the first place. + exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); + current_handle = next_handle.value(); + } + + unmap_page_table_entry(allocator, page, current_handle); + cpu::tlb_flush(page.start_address()); + } + + auto active_page_table::unmap_page_table_entry(allocator::frame_allocator & allocator, virtual_page page, + page_table_handle & handle) -> void + { + auto level_index = page.get_level_index(handle.get_level()); + auto & entry = handle[level_index]; + auto const frame = entry.calculate_pointed_to_frame(); + exception_handling::assert(frame.has_value(), + "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); + entry.set_unused(); + allocator.deallocate_frame(frame.value()); + } + 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 diff --git a/arch/x86_64/src/memory/paging/kernel_mapper.cpp b/arch/x86_64/src/memory/paging/kernel_mapper.cpp new file mode 100644 index 0000000..f938cb3 --- /dev/null +++ b/arch/x86_64/src/memory/paging/kernel_mapper.cpp @@ -0,0 +1,94 @@ +#include "arch/memory/paging/kernel_mapper.hpp" + +#include "arch/memory/cpu/control_register.hpp" +#include "arch/memory/cpu/tlb.hpp" +#include "arch/memory/paging/temporary_page.hpp" +#include "arch/video/vga/text.hpp" + +namespace teachos::arch::memory::paging +{ + + kernel_mapper::kernel_mapper(allocator::frame_allocator & allocator, multiboot::memory_information const & mem_info) + : allocator(allocator) + , mem_info(mem_info) + { + // Nothing to do + } + + auto kernel_mapper::remap_kernel() -> active_page_table & + { + temporary_page temporary_page{virtual_page{0xCAFEBABE}, allocator}; + auto & active_table = active_page_table::create_or_get(); + auto const frame = allocator.allocate_frame(); + exception_handling::assert(frame.has_value(), + "[Kernel Mapper] Frame could not be allocated and therefore kernel not mapped"); + inactive_page_table new_table{frame.value(), active_table, temporary_page}; + remap_elf_kernel_sections(new_table, temporary_page, active_table); + auto const old_table = switch_active_page_table(new_table); + auto const old_level_4_page = virtual_page::containing_address(old_table.page_table_level_4_frame.start_address()); + active_table.unmap_page(allocator, old_level_4_page); + return active_table; + } + + auto kernel_mapper::remap_elf_kernel_sections(inactive_page_table & inactive_table, temporary_page & temporary_page, + active_page_table & active_table) -> void + { + auto const backup = + allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); + auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); + + active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); + cpu::tlb_flush_all(); + map_elf_kernel_sections(active_table); + + page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); + cpu::tlb_flush_all(); + temporary_page.unmap_page(active_table); + } + + auto kernel_mapper::switch_active_page_table(inactive_page_table new_table) -> inactive_page_table + { + auto const backup = + allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); + auto const old_table = inactive_page_table{backup}; + + auto const new_address = new_table.page_table_level_4_frame.start_address(); + cpu::write_control_register(cpu::control_register::CR3, new_address); + return old_table; + } + + auto kernel_mapper::map_elf_kernel_sections(active_page_table & active_table) -> void + { + exception_handling::assert(!mem_info.sections.empty(), "[Kernel Mapper] Kernel elf sections empty"); + for (auto const & section : mem_info.sections) + { + if (!section.flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) + { + continue; + } + exception_handling::assert(section.physical_address % allocator::PAGE_FRAME_SIZE == 0U, + "[Kernel Mapper] Section must be page aligned"); + auto const start_frame = allocator::physical_frame::containing_address(section.physical_address); + // End address is exclusive, so that it is not part of the section anymore (one past the last frame of this + // section). But end frame would now point to the actual last frame and not one past the last frame, therefore + // we increment by one to get one past the last frame of this section. + auto const end_frame = + ++(allocator::physical_frame::containing_address(section.physical_address + section.section_size - 1)); + + allocator::frame_container::iterator const begin{start_frame}; + allocator::frame_container::iterator const end{end_frame}; + allocator::frame_container const frames{begin, end}; + entry const entry{section.flags}; + + for (auto const & frame : frames) + { + active_table.identity_map(allocator, frame, entry.get_flags()); + } + } + + auto const vga_buffer_frame = + allocator::physical_frame::containing_address(video::vga::text::DEFAULT_VGA_TEXT_BUFFER_ADDRESS); + active_table.identity_map(allocator, vga_buffer_frame, entry::WRITABLE); + } + +} // namespace teachos::arch::memory::paging \ No newline at end of file diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index eb11810..48e6d4f 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -96,6 +96,27 @@ namespace teachos::arch::memory::paging "[Page Table] Attempted to pass nullptr as table to page table table method"); } + auto page_table_handle::next_table_or_create(allocator::frame_allocator & allocator, + std::size_t table_index) -> page_table_handle + { + auto next_handle = next_table(table_index); + // If the next table method failed then it means that the page level of the frame we want allocate has not yet + // been created itself. So we have to do that before we are able to allocate the wanted frame. This has to be done + // for every level, meaning we potenitally create a level 4, level 3 and level 2 page entry, each pointing to a + // page table one level below. + if (!next_handle.has_value()) + { + auto const allocated_frame = allocator.allocate_frame(); + exception_handling::assert(allocated_frame.has_value(), "[Page mapper] Unable to allocate frame"); + this->operator[](table_index).set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); + // There should now be an entry at the previously not existent index, therefore we can simply access it again. + next_handle = next_table(table_index); + exception_handling::assert(next_handle.has_value(), "[Page mapper] Unable to create new entry into page table"); + next_handle.value().zero_entries(); + } + return next_handle.value(); + } + auto page_table_handle::zero_entries() -> void { table->zero_entries(); } auto page_table_handle::is_empty() const -> bool { return table->is_empty(); } diff --git a/arch/x86_64/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp index 152241d..8439864 100644 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -4,6 +4,13 @@ namespace teachos::arch::memory::paging { + temporary_page::temporary_page(virtual_page page, allocator::frame_allocator & allocator) + : page{page} + , allocator{allocator} + { + // Nothing to do + } + auto temporary_page::map_table_frame(allocator::physical_frame frame, active_page_table & active_table) -> page_table_handle { @@ -24,6 +31,6 @@ namespace teachos::arch::memory::paging auto temporary_page::unmap_page(active_page_table & active_table) -> void { - active_table.unmap_page(allocator, page); + active_table.unmap_page(this->allocator, page); } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 4c44f822eefa743649693e0a49a978291925ddff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 24 Nov 2024 09:17:53 +0000 Subject: Revert: de-templatize paging implementation --- arch/x86_64/CMakeLists.txt | 1 - .../arch/memory/allocator/area_frame_allocator.hpp | 7 +- .../include/arch/memory/allocator/concept.hpp | 22 +++++ .../arch/memory/allocator/frame_allocator.hpp | 19 ----- .../arch/memory/allocator/tiny_frame_allocator.hpp | 32 ++++++-- .../arch/memory/paging/active_page_table.hpp | 82 ++++++++++++++++--- .../include/arch/memory/paging/kernel_mapper.hpp | 94 +++++++++++++++++++--- .../include/arch/memory/paging/page_table.hpp | 23 +++++- .../include/arch/memory/paging/temporary_page.hpp | 17 ++-- .../src/memory/allocator/tiny_frame_allocator.cpp | 16 ---- .../x86_64/src/memory/paging/active_page_table.cpp | 67 --------------- arch/x86_64/src/memory/paging/kernel_mapper.cpp | 94 ---------------------- arch/x86_64/src/memory/paging/page_table.cpp | 21 ----- arch/x86_64/src/memory/paging/temporary_page.cpp | 9 +-- 14 files changed, 237 insertions(+), 267 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/allocator/concept.hpp delete mode 100644 arch/x86_64/include/arch/memory/allocator/frame_allocator.hpp delete mode 100644 arch/x86_64/src/memory/paging/kernel_mapper.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 7f3a203..1444054 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -52,7 +52,6 @@ target_sources("_memory" PRIVATE "src/memory/paging/virtual_page.cpp" "src/memory/paging/active_page_table.cpp" "src/memory/paging/inactive_page_table.cpp" - "src/memory/paging/kernel_mapper.cpp" "src/memory/cpu/tlb.cpp" "src/memory/cpu/control_register.cpp" "src/memory/cpu/msr.cpp" diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp index f1a3a64..adba4f1 100644 --- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -1,7 +1,6 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP #define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP -#include "arch/memory/allocator/frame_allocator.hpp" #include "arch/memory/allocator/physical_frame.hpp" #include "arch/memory/multiboot/reader.hpp" @@ -12,7 +11,7 @@ namespace teachos::arch::memory::allocator /** * @brief Allocates memory using memory areas read from the multiboot2 information pointer. */ - struct area_frame_allocator : frame_allocator + struct area_frame_allocator { /** * @brief Constructor @@ -33,7 +32,7 @@ namespace teachos::arch::memory::allocator * * @return next free physical frame or nullopt if none was found. */ - auto allocate_frame() -> std::optional override; + auto allocate_frame() -> std::optional; /** * @brief Deallocates a previously allocated physical frame. @@ -44,7 +43,7 @@ namespace teachos::arch::memory::allocator * * @param physical_frame Previously allocated physical_frame that should be deallocated. */ - auto deallocate_frame(physical_frame const & physical_frame) -> void override; + auto deallocate_frame(physical_frame const & physical_frame) -> void; private: /** diff --git a/arch/x86_64/include/arch/memory/allocator/concept.hpp b/arch/x86_64/include/arch/memory/allocator/concept.hpp new file mode 100644 index 0000000..9d58fad --- /dev/null +++ b/arch/x86_64/include/arch/memory/allocator/concept.hpp @@ -0,0 +1,22 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP + +#include "arch/memory/allocator/physical_frame.hpp" + +#include + +namespace teachos::arch::memory::allocator +{ + /** + * @brief Frame allocator concept + * + * @tparam T + */ + template + concept FrameAllocator = requires(T t, physical_frame const & a) { + { t.allocate_frame() } -> std::same_as>; + { t.deallocate_frame(a) } -> std::same_as; + }; +} // namespace teachos::arch::memory::allocator + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP diff --git a/arch/x86_64/include/arch/memory/allocator/frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/frame_allocator.hpp deleted file mode 100644 index 9316ca9..0000000 --- a/arch/x86_64/include/arch/memory/allocator/frame_allocator.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_FRAME_ALLOCATOR_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_FRAME_ALLOCATOR_HPP - -#include "arch/memory/allocator/physical_frame.hpp" - -#include - -namespace teachos::arch::memory::allocator -{ - - struct frame_allocator - { - auto virtual allocate_frame() -> std::optional = 0; - auto virtual deallocate_frame(physical_frame const & frame) -> void = 0; - }; // namespace teachos::arch::memory::allocator - -} // namespace teachos::arch::memory::allocator - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp index c449ac8..8124442 100644 --- a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP #define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP -#include "arch/memory/allocator/frame_allocator.hpp" +#include "arch/memory/allocator/concept.hpp" #include "arch/memory/allocator/physical_frame.hpp" #include @@ -16,17 +16,33 @@ namespace teachos::arch::memory::allocator /** * @brief Allocates memory using memory areas read from the multiboot2 information pointer. */ - struct tiny_frame_allocator : frame_allocator + struct tiny_frame_allocator { /** * @brief Constructor. * - * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and - * deallocate method. + * @tparam T Contract the allocator that should be used to actually allocate and deallocate, the underlying three + * frames has to follow. + * * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate - * entries *when a new page table is required. + * entries when the underlying frames are created. */ - tiny_frame_allocator(frame_allocator & allocator); + template + tiny_frame_allocator(T & allocator) + : frames{} + { + // Has to be done this way, because constructing the constructor with the data from allocator.allocate_frames(), + // does not work because it would set the value correctly but because we pass it as an std::optional it would not + // set the engaged flag. Meaning the has_value() method would still return false. + for (auto & frame : frames) + { + auto allocated = allocator.allocate_frame(); + if (allocated.has_value()) + { + frame.emplace(allocated.value()); + } + } + } /** * @brief Allocate memory by finding and returning one of the three free physical frames. @@ -34,7 +50,7 @@ namespace teachos::arch::memory::allocator * @return First free physical frames of the three frames held by this allocator or nullopt if we used up all three * frames already. */ - auto allocate_frame() -> std::optional override; + auto allocate_frame() -> std::optional; /** * @brief Deallocates one of the three previously allocated physical frames. @@ -44,7 +60,7 @@ namespace teachos::arch::memory::allocator * * @param physical_frame Previously allocated physical_frame that should be deallocated. */ - auto deallocate_frame(physical_frame const & physical_frame) -> void override; + auto deallocate_frame(physical_frame const & physical_frame) -> void; private: std::array, TINY_ALLOCATOR_FRAMES_COUNT> frames = diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index e558fa5..88c1c82 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -1,9 +1,9 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_ACTIVE_PAGE_TABLE_HPP -#include "arch/memory/allocator/frame_allocator.hpp" -#include "arch/memory/allocator/physical_frame.hpp" -#include "arch/memory/paging/page_table.hpp" +#include "arch/exception_handling/assert.hpp" +#include "arch/memory/allocator/concept.hpp" +#include "arch/memory/cpu/tlb.hpp" #include "arch/memory/paging/virtual_page.hpp" #include @@ -66,21 +66,44 @@ namespace teachos::arch::memory::paging * @note Allocates and maps an entry in every page level if it does not exists yet down to level 1. If the level 1 * page table already exists it halts execution instead. * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate * entries when a new page table is required. * @param page Virtual page that is being mapped. * @param frame Physical frame that the virtual page will be mapped to. * @param flags A bitset of flags that configure the page table entry for this mapping. */ - auto map_page_to_frame(allocator::frame_allocator & allocator, virtual_page page, allocator::physical_frame frame, - std::bitset<64U> flags) -> void; + template + auto map_page_to_frame(T & allocator, virtual_page page, allocator::physical_frame frame, + std::bitset<64U> flags) -> void + { + auto current_handle = active_handle; + + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) + { + current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level)); + } + + auto & level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; + arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), + "[Page Mapper] Unable to map huge pages"); + arch::exception_handling::assert(level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); + level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT); + } + /** * @brief Allocates the next free frame and then uses that frame to call map_page_to_frame. * * @see map_page_to_frame */ - auto map_next_free_page_to_frame(allocator::frame_allocator & allocator, virtual_page page, - std::bitset<64U> flags) -> void; + template + auto map_next_free_page_to_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void + { + auto const frame = allocator.allocate_frame(); + exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); + map_page_to_frame(allocator, page, frame.value(), flags); + } /** * @brief Gets the corresponding page the given frame has to be contained in and uses that to call @@ -88,8 +111,12 @@ namespace teachos::arch::memory::paging * * @see map_page_to_frame */ - auto identity_map(allocator::frame_allocator & allocator, allocator::physical_frame frame, - std::bitset<64U> flags) -> void; + template + auto identity_map(T & allocator, allocator::physical_frame frame, std::bitset<64U> flags) -> void + { + auto const page = virtual_page::containing_address(frame.start_address()); + map_page_to_frame(allocator, page, frame, flags); + } /** * @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags. @@ -103,7 +130,27 @@ namespace teachos::arch::memory::paging * entries when a new page table is required. * @param page Virtual page that is being unmapped. */ - auto unmap_page(allocator::frame_allocator & allocator, virtual_page page) -> void; + template + auto unmap_page(T & allocator, virtual_page page) -> void + { + exception_handling::assert(translate_page(page).has_value(), + "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); + + auto current_handle = active_handle; + + for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) + { + auto const level_index = page.get_level_index(level); + auto const next_handle = current_handle.next_table(level_index); + // The next table method failed even tough the page has to be mapped already, because translate_page did not + // fail. This can only mean that we attempted to unmap a huge page, which is not supported in the first place. + exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); + current_handle = next_handle.value(); + } + + unmap_page_table_entry(allocator, page, current_handle); + cpu::tlb_flush(page.start_address()); + } private: /** @@ -127,13 +174,24 @@ namespace teachos::arch::memory::paging /** * @brief Unmaps specific page at the current internal handle level. * + * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. * @param allocator Reference to an allocator following the FrameAllocator concept, which is used to allocate * entries *when a new page table is required. * @param page Virtual page that is being unmapped. * @param handle Page Table handle we want to access the entry that should be cleared on. */ - static auto unmap_page_table_entry(allocator::frame_allocator & allocator, virtual_page page, - page_table_handle & handle) -> void; + template + static auto unmap_page_table_entry(T & allocator, virtual_page page, page_table_handle & handle) -> void + { + auto level_index = page.get_level_index(handle.get_level()); + auto & entry = handle[level_index]; + auto const frame = entry.calculate_pointed_to_frame(); + exception_handling::assert(frame.has_value(), + "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); + entry.set_unused(); + allocator.deallocate_frame(frame.value()); + } public: page_table_handle active_handle; ///< Underlying active level 4 page table diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 2f55a13..f980451 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -1,11 +1,11 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP -#include "arch/memory/allocator/frame_allocator.hpp" -#include "arch/memory/multiboot/reader.hpp" +#include "arch/memory/cpu/control_register.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/inactive_page_table.hpp" #include "arch/memory/paging/temporary_page.hpp" +#include "arch/video/vga/text.hpp" namespace teachos::arch::memory::paging { @@ -14,6 +14,7 @@ namespace teachos::arch::memory::paging * * @tparam T Contract the allocator that should be used to allocate frames for the remapping process has to fulfill. */ + template struct kernel_mapper { /** @@ -22,7 +23,12 @@ namespace teachos::arch::memory::paging * @param allocator Allocator that should be used to allocate frames for the remapping process. * @param mem_info Information about elf kernel sections required for remapping process. */ - kernel_mapper(allocator::frame_allocator & allocator, multiboot::memory_information const & mem_info); + kernel_mapper(T & allocator, multiboot::memory_information const & mem_info) + : allocator(allocator) + , mem_info(mem_info) + { + // Nothing to do + } /** * @brief Remap the kernel, meaning we map the entire kernel and all of it's elf sections with the correct flags @@ -32,7 +38,21 @@ namespace teachos::arch::memory::paging * inactive page table, that is not used by the CPU to ensure we are not changign memory that we are using. Because * remapping active kernel memory in the kernel wouldn't work. */ - auto remap_kernel() -> active_page_table &; + auto remap_kernel() -> active_page_table & + { + temporary_page temporary_page{virtual_page{0xCAFEBABE}, allocator}; + auto & active_table = active_page_table::create_or_get(); + auto const frame = allocator.allocate_frame(); + exception_handling::assert(frame.has_value(), + "[Kernel Mapper] Frame could not be allocated and therefore kernel not mapped"); + inactive_page_table new_table{frame.value(), active_table, temporary_page}; + remap_elf_kernel_sections(new_table, temporary_page, active_table); + auto const old_table = switch_active_page_table(new_table); + auto const old_level_4_page = + virtual_page::containing_address(old_table.page_table_level_4_frame.start_address()); + active_table.unmap_page(allocator, old_level_4_page); + return active_table; + } private: /** @@ -43,8 +63,8 @@ namespace teachos::arch::memory::paging * Once the remapping process is done we can restore the original recursive mapping with the complete remapped * kernel. * - * @note Because we change the entries we also have to ensure we flush the translation lookaside buffer, before - * we map the entries. + * @note Because we change the entries we also have to ensure we flush the translation lookaside buffer, before we + * map the entries. * * @param inactive_table Level 4 page table we temporarily map the kernel into. * @param temporary_page Temporary page that should be used for the mapping process and then @@ -53,7 +73,20 @@ namespace teachos::arch::memory::paging * restored once the process is finished. */ auto remap_elf_kernel_sections(inactive_page_table & inactive_table, temporary_page & temporary_page, - active_page_table & active_table) -> void; + active_page_table & active_table) -> void + { + auto const backup = + allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); + auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); + + active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); + cpu::tlb_flush_all(); + map_elf_kernel_sections(active_table); + + page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); + cpu::tlb_flush_all(); + temporary_page.unmap_page(active_table); + } /** * @brief Switches the current active table pointed to by the CR3 register with another page table that is currently @@ -62,7 +95,16 @@ namespace teachos::arch::memory::paging * @param new_table Inactive page table that should now be made active and replace the current active one. * @return The previous active page table. */ - auto switch_active_page_table(inactive_page_table new_table) -> inactive_page_table; + auto switch_active_page_table(inactive_page_table new_table) -> inactive_page_table + { + auto const backup = + allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); + auto const old_table = inactive_page_table{backup}; + + auto const new_address = new_table.page_table_level_4_frame.start_address(); + cpu::write_control_register(cpu::control_register::CR3, new_address); + return old_table; + } /** * @brief Maps the required entries according to every elf section and it's contained frames. Additionally each of @@ -71,9 +113,41 @@ namespace teachos::arch::memory::paging * @param active_table Active level 4 page table that should be used to map the required elf sections into entries. * Has had its recursive mapping temporarily replaced and points to unmapped place in memory. */ - auto map_elf_kernel_sections(active_page_table & active_table) -> void; + auto map_elf_kernel_sections(active_page_table & active_table) -> void + { + exception_handling::assert(!mem_info.sections.empty(), "[Kernel Mapper] Kernel elf sections empty"); + for (auto const & section : mem_info.sections) + { + if (!section.flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) + { + continue; + } + exception_handling::assert(section.physical_address % allocator::PAGE_FRAME_SIZE == 0U, + "[Kernel Mapper] Section must be page aligned"); + auto const start_frame = allocator::physical_frame::containing_address(section.physical_address); + // End address is exclusive, so that it is not part of the section anymore (one past the last frame of this + // section). But end frame would now point to the actual last frame and not one past the last frame, therefore + // we increment by one to get one past the last frame of this section. + auto const end_frame = + ++(allocator::physical_frame::containing_address(section.physical_address + section.section_size - 1)); + + allocator::frame_container::iterator const begin{start_frame}; + allocator::frame_container::iterator const end{end_frame}; + allocator::frame_container const frames{begin, end}; + entry const entry{section.flags}; + + for (auto const & frame : frames) + { + active_table.identity_map(allocator, frame, entry.get_flags()); + } + } + + auto const vga_buffer_frame = + allocator::physical_frame::containing_address(video::vga::text::DEFAULT_VGA_TEXT_BUFFER_ADDRESS); + active_table.identity_map(allocator, vga_buffer_frame, entry::WRITABLE); + } - allocator::frame_allocator & allocator; + T & allocator; multiboot::memory_information const & mem_info; ///< Information about elf kernel sections required for remapping process. }; diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 24ff8f4..7a15875 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -2,7 +2,7 @@ #define TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP #include "arch/exception_handling/assert.hpp" -#include "arch/memory/allocator/frame_allocator.hpp" +#include "arch/memory/allocator/concept.hpp" #include "arch/memory/paging/page_entry.hpp" namespace teachos::arch::memory::paging @@ -82,7 +82,26 @@ namespace teachos::arch::memory::paging * entries when a new page table is required. * @param table_index Index of this page table in the page table one level lower. */ - auto next_table_or_create(allocator::frame_allocator & allocator, std::size_t table_index) -> page_table_handle; + template + auto next_table_or_create(T & allocator, std::size_t table_index) -> page_table_handle + { + auto next_handle = next_table(table_index); + // If the next table method failed then it means that the page level of the frame we want allocate has not yet + // been created itself. So we have to do that before we are able to allocate the wanted frame. This has to be done + // for every level, meaning we potenitally create a level 4, level 3 and level 2 page entry, each pointing to a + // page table one level below. + if (!next_handle.has_value()) + { + auto const allocated_frame = allocator.allocate_frame(); + exception_handling::assert(allocated_frame.has_value(), "[Page mapper] Unable to allocate frame"); + this->operator[](table_index).set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); + // There should now be an entry at the previously not existent index, therefore we can simply access it again. + next_handle = next_table(table_index); + exception_handling::assert(next_handle.has_value(), "[Page mapper] Unable to create new entry into page table"); + next_handle.value().zero_entries(); + } + return next_handle.value(); + } /** * @brief Index operator overload to access specific mutable entry directy. diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp index 3c4301a..02cb545 100644 --- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -14,13 +14,20 @@ namespace teachos::arch::memory::paging struct temporary_page { /** - * @brief Construct a new temporary page object + * @brief Construct a new temporary page object. * - * @tparam FrameAllocator concept - * @param page Page to turn into temporary page - * @param allocator Frame allocator used to fill page + * @tparam Type constraint of the allocator, being that is follows the given concept and contains an allocate and + * deallocate method. + * @param page Page to turn into temporary page. + * @param allocator Frame allocator used to fill page. */ - temporary_page(virtual_page page, allocator::frame_allocator & allocator); + template + temporary_page(virtual_page page, T & allocator) + : page{page} + , allocator{allocator} + { + // Nothing to do + } /** * @brief Unmap the current page. diff --git a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp index ed000a0..3cdf9c7 100644 --- a/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp +++ b/arch/x86_64/src/memory/allocator/tiny_frame_allocator.cpp @@ -4,22 +4,6 @@ namespace teachos::arch::memory::allocator { - tiny_frame_allocator::tiny_frame_allocator(frame_allocator & allocator) - : frames{} - { - // Has to be done this way, because constructing the constructor with the data from allocator.allocate_frames(), - // does not work because it would set the value correctly but because we pass it as an std::optional it would not - // set the engaged flag. Meaning the has_value() method would still return false. - for (auto & frame : frames) - { - auto allocated = allocator.allocate_frame(); - if (allocated.has_value()) - { - frame.emplace(allocated.value()); - } - } - } - auto tiny_frame_allocator::allocate_frame() -> std::optional { for (auto & frame_option : frames) diff --git a/arch/x86_64/src/memory/paging/active_page_table.cpp b/arch/x86_64/src/memory/paging/active_page_table.cpp index d2bf683..0113869 100644 --- a/arch/x86_64/src/memory/paging/active_page_table.cpp +++ b/arch/x86_64/src/memory/paging/active_page_table.cpp @@ -1,7 +1,5 @@ #include "arch/memory/paging/active_page_table.hpp" -#include "arch/memory/cpu/tlb.hpp" - namespace teachos::arch::memory::paging { namespace @@ -17,71 +15,6 @@ namespace teachos::arch::memory::paging return active_page; } - auto active_page_table::map_page_to_frame(allocator::frame_allocator & allocator, virtual_page page, - allocator::physical_frame frame, std::bitset<64U> flags) -> void - { - auto current_handle = active_handle; - - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) - { - current_handle = current_handle.next_table_or_create(allocator, page.get_level_index(level)); - } - - auto & level1_entry = current_handle[page.get_level_index(page_table_handle::LEVEL1)]; - arch::exception_handling::assert(!level1_entry.contains_flags(entry::HUGE_PAGE), - "[Page Mapper] Unable to map huge pages"); - arch::exception_handling::assert(level1_entry.is_unused(), "[Page Mapper] Page table entry is already used"); - level1_entry.set_entry(frame, flags.to_ulong() | entry::PRESENT); - } - - auto active_page_table::identity_map(allocator::frame_allocator & allocator, allocator::physical_frame frame, - std::bitset<64U> flags) -> void - { - auto const page = virtual_page::containing_address(frame.start_address()); - map_page_to_frame(allocator, page, frame, flags); - } - - auto active_page_table::map_next_free_page_to_frame(allocator::frame_allocator & allocator, virtual_page page, - std::bitset<64U> flags) -> void - { - auto const frame = allocator.allocate_frame(); - exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); - map_page_to_frame(allocator, page, frame.value(), flags); - } - - auto active_page_table::unmap_page(allocator::frame_allocator & allocator, virtual_page page) -> void - { - exception_handling::assert(translate_page(page).has_value(), - "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); - - auto current_handle = active_handle; - - for (auto level = page_table_handle::LEVEL4; level != page_table_handle::LEVEL1; --level) - { - auto const level_index = page.get_level_index(level); - auto const next_handle = current_handle.next_table(level_index); - // The next table method failed even tough the page has to be mapped already, because translate_page did not - // fail. This can only mean that we attempted to unmap a huge page, which is not supported in the first place. - exception_handling::assert(next_handle.has_value(), "[Page Mapper] Unable to unmap huge pages"); - current_handle = next_handle.value(); - } - - unmap_page_table_entry(allocator, page, current_handle); - cpu::tlb_flush(page.start_address()); - } - - auto active_page_table::unmap_page_table_entry(allocator::frame_allocator & allocator, virtual_page page, - page_table_handle & handle) -> void - { - auto level_index = page.get_level_index(handle.get_level()); - auto & entry = handle[level_index]; - auto const frame = entry.calculate_pointed_to_frame(); - exception_handling::assert(frame.has_value(), - "[Page Mapper] Attempted to unmap page, which has not been mapped previously"); - entry.set_unused(); - allocator.deallocate_frame(frame.value()); - } - 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 diff --git a/arch/x86_64/src/memory/paging/kernel_mapper.cpp b/arch/x86_64/src/memory/paging/kernel_mapper.cpp deleted file mode 100644 index f938cb3..0000000 --- a/arch/x86_64/src/memory/paging/kernel_mapper.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "arch/memory/paging/kernel_mapper.hpp" - -#include "arch/memory/cpu/control_register.hpp" -#include "arch/memory/cpu/tlb.hpp" -#include "arch/memory/paging/temporary_page.hpp" -#include "arch/video/vga/text.hpp" - -namespace teachos::arch::memory::paging -{ - - kernel_mapper::kernel_mapper(allocator::frame_allocator & allocator, multiboot::memory_information const & mem_info) - : allocator(allocator) - , mem_info(mem_info) - { - // Nothing to do - } - - auto kernel_mapper::remap_kernel() -> active_page_table & - { - temporary_page temporary_page{virtual_page{0xCAFEBABE}, allocator}; - auto & active_table = active_page_table::create_or_get(); - auto const frame = allocator.allocate_frame(); - exception_handling::assert(frame.has_value(), - "[Kernel Mapper] Frame could not be allocated and therefore kernel not mapped"); - inactive_page_table new_table{frame.value(), active_table, temporary_page}; - remap_elf_kernel_sections(new_table, temporary_page, active_table); - auto const old_table = switch_active_page_table(new_table); - auto const old_level_4_page = virtual_page::containing_address(old_table.page_table_level_4_frame.start_address()); - active_table.unmap_page(allocator, old_level_4_page); - return active_table; - } - - auto kernel_mapper::remap_elf_kernel_sections(inactive_page_table & inactive_table, temporary_page & temporary_page, - active_page_table & active_table) -> void - { - auto const backup = - allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); - auto page_table_level4 = temporary_page.map_table_frame(backup, active_table); - - active_table[511].set_entry(inactive_table.page_table_level_4_frame, entry::PRESENT | entry::WRITABLE); - cpu::tlb_flush_all(); - map_elf_kernel_sections(active_table); - - page_table_level4[511].set_entry(backup, entry::PRESENT | entry::WRITABLE); - cpu::tlb_flush_all(); - temporary_page.unmap_page(active_table); - } - - auto kernel_mapper::switch_active_page_table(inactive_page_table new_table) -> inactive_page_table - { - auto const backup = - allocator::physical_frame::containing_address(cpu::read_control_register(cpu::control_register::CR3)); - auto const old_table = inactive_page_table{backup}; - - auto const new_address = new_table.page_table_level_4_frame.start_address(); - cpu::write_control_register(cpu::control_register::CR3, new_address); - return old_table; - } - - auto kernel_mapper::map_elf_kernel_sections(active_page_table & active_table) -> void - { - exception_handling::assert(!mem_info.sections.empty(), "[Kernel Mapper] Kernel elf sections empty"); - for (auto const & section : mem_info.sections) - { - if (!section.flags.contains_flags(multiboot::elf_section_flags::OCCUPIES_MEMORY)) - { - continue; - } - exception_handling::assert(section.physical_address % allocator::PAGE_FRAME_SIZE == 0U, - "[Kernel Mapper] Section must be page aligned"); - auto const start_frame = allocator::physical_frame::containing_address(section.physical_address); - // End address is exclusive, so that it is not part of the section anymore (one past the last frame of this - // section). But end frame would now point to the actual last frame and not one past the last frame, therefore - // we increment by one to get one past the last frame of this section. - auto const end_frame = - ++(allocator::physical_frame::containing_address(section.physical_address + section.section_size - 1)); - - allocator::frame_container::iterator const begin{start_frame}; - allocator::frame_container::iterator const end{end_frame}; - allocator::frame_container const frames{begin, end}; - entry const entry{section.flags}; - - for (auto const & frame : frames) - { - active_table.identity_map(allocator, frame, entry.get_flags()); - } - } - - auto const vga_buffer_frame = - allocator::physical_frame::containing_address(video::vga::text::DEFAULT_VGA_TEXT_BUFFER_ADDRESS); - active_table.identity_map(allocator, vga_buffer_frame, entry::WRITABLE); - } - -} // namespace teachos::arch::memory::paging \ No newline at end of file diff --git a/arch/x86_64/src/memory/paging/page_table.cpp b/arch/x86_64/src/memory/paging/page_table.cpp index 48e6d4f..eb11810 100644 --- a/arch/x86_64/src/memory/paging/page_table.cpp +++ b/arch/x86_64/src/memory/paging/page_table.cpp @@ -96,27 +96,6 @@ namespace teachos::arch::memory::paging "[Page Table] Attempted to pass nullptr as table to page table table method"); } - auto page_table_handle::next_table_or_create(allocator::frame_allocator & allocator, - std::size_t table_index) -> page_table_handle - { - auto next_handle = next_table(table_index); - // If the next table method failed then it means that the page level of the frame we want allocate has not yet - // been created itself. So we have to do that before we are able to allocate the wanted frame. This has to be done - // for every level, meaning we potenitally create a level 4, level 3 and level 2 page entry, each pointing to a - // page table one level below. - if (!next_handle.has_value()) - { - auto const allocated_frame = allocator.allocate_frame(); - exception_handling::assert(allocated_frame.has_value(), "[Page mapper] Unable to allocate frame"); - this->operator[](table_index).set_entry(allocated_frame.value(), entry::PRESENT | entry::WRITABLE); - // There should now be an entry at the previously not existent index, therefore we can simply access it again. - next_handle = next_table(table_index); - exception_handling::assert(next_handle.has_value(), "[Page mapper] Unable to create new entry into page table"); - next_handle.value().zero_entries(); - } - return next_handle.value(); - } - auto page_table_handle::zero_entries() -> void { table->zero_entries(); } auto page_table_handle::is_empty() const -> bool { return table->is_empty(); } diff --git a/arch/x86_64/src/memory/paging/temporary_page.cpp b/arch/x86_64/src/memory/paging/temporary_page.cpp index 8439864..152241d 100644 --- a/arch/x86_64/src/memory/paging/temporary_page.cpp +++ b/arch/x86_64/src/memory/paging/temporary_page.cpp @@ -4,13 +4,6 @@ namespace teachos::arch::memory::paging { - temporary_page::temporary_page(virtual_page page, allocator::frame_allocator & allocator) - : page{page} - , allocator{allocator} - { - // Nothing to do - } - auto temporary_page::map_table_frame(allocator::physical_frame frame, active_page_table & active_table) -> page_table_handle { @@ -31,6 +24,6 @@ namespace teachos::arch::memory::paging auto temporary_page::unmap_page(active_page_table & active_table) -> void { - active_table.unmap_page(this->allocator, page); + active_table.unmap_page(allocator, page); } } // namespace teachos::arch::memory::paging -- cgit v1.2.3 From 641f20fd782deb6d9e1e1b9996005ad893028744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 24 Nov 2024 09:22:23 +0000 Subject: Adjust notes on actual unmap implementation --- arch/x86_64/include/arch/memory/paging/active_page_table.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index 88c1c82..4687209 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -121,8 +121,12 @@ namespace teachos::arch::memory::paging /** * @brief Unmaps the virtual page from the previously mapped to physical frame and resets the flags. * - * @note Deallocates and unmaps the entry in every page level if this page was the last one up to level 4 and - * ensures to clear the Translation Lookaside Buffer, so that the unmapped value is removed from cache as well. + * @note For the unmap function to deallocates and unmaps correctly, the entry in every page level if this page was + * the last one up to level 4 should be unmapped and ensured to clear the Translation Lookaside Buffer, so that the + * unmapped value is removed from cache as well. This is currently not done and instead we only dallocate and unmap + * the level 1 page table entry, this is the case because it conflicts with our recursive mapping for the temporary + * page, which requires the other page table entries to walk to the actual level 4 page table. If we remove all page + * table entries beforehand, we therefore can not remap the kernel anymore. * * @tparam T Type constraint of the allocator, being that is follows the given concept and contains an allocate and * deallocate method. -- cgit v1.2.3 From 77146c6e2dbd02661636d9424b7e51562eac30c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 24 Nov 2024 09:44:41 +0000 Subject: Add notes on missing features for kernel remapping --- arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 2 ++ arch/x86_64/src/kernel/main.cpp | 9 ++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index f980451..897ae06 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -48,6 +48,8 @@ namespace teachos::arch::memory::paging inactive_page_table new_table{frame.value(), active_table, temporary_page}; remap_elf_kernel_sections(new_table, temporary_page, active_table); auto const old_table = switch_active_page_table(new_table); + // Turn old level 4 page table, mapped by assembler code into stack guard page. + // Only works if the identity mapped page tables by assembler are right above the stack. auto const old_level_4_page = virtual_page::containing_address(old_table.page_table_level_4_frame.start_address()); active_table.unmap_page(allocator, old_level_4_page); diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 8c68a49..8a73630 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -35,11 +35,10 @@ namespace teachos::arch::kernel video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); } - // TODO: Seems to work correctly, Level 4 Index 0, Level 3 Index 0, Level 2 Index 0, Level 1 Index 184 = 753667 from - // mapping vga is still mapped - // set(CMAKE_POSITION_INDEPENDENT_CODE ON), should enable position independent code, but mapping still does not work - // with same error? - // Can we change the gcc call? gcc -fPIC -c mylibrary.cpp + // TODO: Why is identity mapping multiboot2 information structure with new kernel not required and + // allocator.allocate_frame still works? + // TODO: Fix unmapping old level 4 page table and turn it into guard page, use Stack Probes for stack allocation if + // possible. // TODO: Map heap virtual pages with active table -- cgit v1.2.3 From 55f32173e97fdcf4a45006b66cc4b20329a5c7af Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 24 Nov 2024 13:10:21 +0000 Subject: implement basic heap and remap it --- arch/x86_64/CMakeLists.txt | 2 + arch/x86_64/include/arch/memory/heap/allocator.hpp | 32 ++++++++++ arch/x86_64/include/arch/memory/heap/concept.hpp | 15 +++++ arch/x86_64/include/arch/memory/main.hpp | 13 +++++ .../arch/memory/paging/active_page_table.hpp | 2 +- arch/x86_64/scripts/kernel.ld | 5 +- arch/x86_64/src/kernel/main.cpp | 68 ++++------------------ arch/x86_64/src/memory/heap/allocator.cpp | 27 +++++++++ arch/x86_64/src/memory/main.cpp | 47 +++++++++++++++ 9 files changed, 149 insertions(+), 62 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/heap/allocator.hpp create mode 100644 arch/x86_64/include/arch/memory/heap/concept.hpp create mode 100644 arch/x86_64/include/arch/memory/main.hpp create mode 100644 arch/x86_64/src/memory/heap/allocator.cpp create mode 100644 arch/x86_64/src/memory/main.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 1444054..5b0e3a9 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -41,6 +41,7 @@ target_sources("_video" PRIVATE #]============================================================================] target_sources("_memory" PRIVATE + "src/memory/main.cpp" "src/memory/multiboot/elf_symbols_section.cpp" "src/memory/multiboot/reader.cpp" "src/memory/allocator/area_frame_allocator.cpp" @@ -55,6 +56,7 @@ target_sources("_memory" PRIVATE "src/memory/cpu/tlb.cpp" "src/memory/cpu/control_register.cpp" "src/memory/cpu/msr.cpp" + "src/memory/heap/allocator.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/memory/heap/allocator.hpp b/arch/x86_64/include/arch/memory/heap/allocator.hpp new file mode 100644 index 0000000..c486a4c --- /dev/null +++ b/arch/x86_64/include/arch/memory/heap/allocator.hpp @@ -0,0 +1,32 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_ALLOCATOR_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_ALLOCATOR_HPP + +#include + +namespace teachos::arch::memory::heap +{ + std::size_t constexpr HEAP_START = 0x4000'0000; + std::size_t constexpr HEAP_SIZE = 100 * 1024; + + struct bump_allocator + { + bump_allocator(std::size_t heap_start, std::size_t heap_end) + : heap_start{heap_start} + , heap_end{heap_end} + , next{heap_start} + { + } + + auto allocate(std::size_t size) -> void *; + + auto deallocate(uint8_t * pointer, std::size_t size) -> void; + + private: + std::size_t heap_start; + std::size_t heap_end; + std::size_t next; + }; + +} // namespace teachos::arch::memory::heap + +#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/heap/concept.hpp b/arch/x86_64/include/arch/memory/heap/concept.hpp new file mode 100644 index 0000000..a525b0b --- /dev/null +++ b/arch/x86_64/include/arch/memory/heap/concept.hpp @@ -0,0 +1,15 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_CONCEPT_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_CONCEPT_HPP + +#include + +namespace teachos::arch::memory::heap +{ + template + concept HeapAllocator = requires(T t, uint8_t * pointer, std::size_t size) { + { t.allocate(size) } -> std::same_as; + { t.deallocate(pointer, size) } -> std::same_as; + }; +} // namespace teachos::arch::memory::heap + +#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_CONCEPT_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/main.hpp b/arch/x86_64/include/arch/memory/main.hpp new file mode 100644 index 0000000..e166285 --- /dev/null +++ b/arch/x86_64/include/arch/memory/main.hpp @@ -0,0 +1,13 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_MAIN_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_MAIN_HPP + +namespace teachos::arch::memory +{ + /** + * @brief + * + */ + auto initialize_memory_management() -> void; +} // namespace teachos::arch::memory + +#endif diff --git a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp index 4687209..1b2aaed 100644 --- a/arch/x86_64/include/arch/memory/paging/active_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/active_page_table.hpp @@ -98,7 +98,7 @@ namespace teachos::arch::memory::paging * @see map_page_to_frame */ template - auto map_next_free_page_to_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void + auto map_page_to_next_free_frame(T & allocator, virtual_page page, std::bitset<64U> flags) -> void { auto const frame = allocator.allocate_frame(); exception_handling::assert(frame.has_value(), "[Page mapper] Out of memory exception"); diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index e9d245f..c3eea9c 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -60,9 +60,8 @@ SECTIONS } /*************************************************************************** - * Now it is time to load the 64-bit kernel code. We virtually load it into - * the upper 2GiB, while adjusting the linear load address appropriately. We - * also make sure to align the loaded data onto a page boundary. + * Now it is time to load the 64-bit kernel code. We + * make sure to align the loaded data onto a page boundary. ***************************************************************************/ .init ALIGN(4K) : AT(ADDR (.init)) { diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 8a73630..cbd6e68 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,16 +1,8 @@ #include "arch/kernel/main.hpp" -#include "arch/exception_handling/assert.hpp" -#include "arch/memory/allocator/area_frame_allocator.hpp" -#include "arch/memory/cpu/control_register.hpp" -#include "arch/memory/cpu/msr.hpp" -#include "arch/memory/multiboot/reader.hpp" -#include "arch/memory/paging/kernel_mapper.hpp" -#include "arch/memory/paging/temporary_page.hpp" +#include "arch/memory/main.hpp" #include "arch/video/vga/text.hpp" -#include - namespace teachos::arch::kernel { auto main() -> void @@ -19,61 +11,21 @@ namespace teachos::arch::kernel video::vga::text::cursor(false); video::vga::text::write("TeachOS is starting up...", video::vga::text::common_attributes::green_on_black); - auto const memory_information = memory::multiboot::read_multiboot2(); - memory::allocator::area_frame_allocator allocator(memory_information); + memory::initialize_memory_management(); + + // heap::bump_allocator heap_allocator{memory::heap::HEAP_START, heap::HEAP_START + memory::heap::HEAP_SIZE}; + // auto test = heap_allocator.allocate(1024); - memory::cpu::set_cr2_bit(memory::cpu::cr2_flags::WRITE_PROTECT); - memory::cpu::set_efer_bit(memory::cpu::efer_flags::NXE); + // auto test2 = new (test) multiboot::memory_information{}; - memory::paging::kernel_mapper kernel(allocator, memory_information); - auto & active_table = kernel.remap_kernel(); - auto x = active_table.active_handle.next_table(0); - auto y = x.value().next_table(0); - auto z = y.value().next_table(0); - if (z.has_value()) - { - video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); - } + // if (test || test2) + // { + // video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); + // } // TODO: Why is identity mapping multiboot2 information structure with new kernel not required and // allocator.allocate_frame still works? // TODO: Fix unmapping old level 4 page table and turn it into guard page, use Stack Probes for stack allocation if // possible. - - // TODO: Map heap virtual pages with active table - - /* - size_t address = 42 * memory::paging::PAGE_TABLE_ENTRY_COUNT * memory::paging::PAGE_TABLE_ENTRY_COUNT * - memory::allocator::PAGE_FRAME_SIZE; // 42th P3 entry - auto const page = memory::paging::virtual_page::containing_address(address); - memory::paging::map_next_free_page_to_frame(allocator, page, 0U); - auto optional_frame = memory::paging::translate_page(page); - video::vga::text::newline(); - video::vga::text::write("Mapped physical frame: ", video::vga::text::common_attributes::green_on_black); - video::vga::text::write_number(optional_frame.value().frame_number, - video::vga::text::common_attributes::green_on_black); - video::vga::text::write(" to virtual page: ", video::vga::text::common_attributes::green_on_black); - video::vga::text::write_number(page.page_number, video::vga::text::common_attributes::green_on_black); - - memory::paging::unmap_page(allocator, page); - video::vga::text::newline(); - video::vga::text::write("Unapped virtual page from physical frame: ", - video::vga::text::common_attributes::green_on_black); - optional_frame = memory::paging::translate_page(page); - exception_handling::assert(!optional_frame.has_value(), "[Main] Ummapping failed"); - video::vga::text::write_number(page.page_number, video::vga::text::common_attributes::green_on_black); - - auto last_allocated = allocator.allocate_frame(); - auto allocated = last_allocated; - do - { - last_allocated = allocated; - allocated = allocator.allocate_frame(); - } while (allocated); - video::vga::text::newline(); - video::vga::text::write("Allocated Frames: ", video::vga::text::common_attributes::green_on_black); - video::vga::text::write_number(last_allocated.value().frame_number, - video::vga::text::common_attributes::green_on_black); - */ } } // namespace teachos::arch::kernel diff --git a/arch/x86_64/src/memory/heap/allocator.cpp b/arch/x86_64/src/memory/heap/allocator.cpp new file mode 100644 index 0000000..c9ddd78 --- /dev/null +++ b/arch/x86_64/src/memory/heap/allocator.cpp @@ -0,0 +1,27 @@ +#include "arch/memory/heap/allocator.hpp" + +#include "arch/exception_handling/assert.hpp" + +namespace teachos::arch::memory::heap +{ + auto bump_allocator::allocate(std::size_t size) -> void * + { + // Uses some sort of alignment orignally: + // https://github.com/phil-opp/blog_os/blob/7f6576c9dc34e360b81236c54c25c7827fd6a2df/src/memory/heap_allocator.rs#L24 + auto alloc_start = next; + auto alloc_end = next + size; + + arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory!"); + + next = alloc_end; + return reinterpret_cast(alloc_start); + } + + auto bump_allocator::deallocate(uint8_t * pointer, std::size_t size) -> void + { + // Memory leak + if (pointer || size) + { + } + } +} // namespace teachos::arch::memory::heap \ No newline at end of file diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp new file mode 100644 index 0000000..ce07115 --- /dev/null +++ b/arch/x86_64/src/memory/main.cpp @@ -0,0 +1,47 @@ +#include "arch/memory/main.hpp" + +#include "arch/exception_handling/assert.hpp" +#include "arch/memory/allocator/area_frame_allocator.hpp" +#include "arch/memory/cpu/control_register.hpp" +#include "arch/memory/cpu/msr.hpp" +#include "arch/memory/heap/allocator.hpp" +#include "arch/memory/paging/active_page_table.hpp" +#include "arch/memory/paging/kernel_mapper.hpp" + +namespace teachos::arch::memory +{ + namespace + { + auto remap_heap(allocator::area_frame_allocator allocator, paging::active_page_table & active_table) -> void + { + auto heap_start_page = paging::virtual_page::containing_address(memory::heap::HEAP_START); + auto heap_end_page = + paging::virtual_page::containing_address(memory::heap::HEAP_START + memory::heap::HEAP_SIZE - 1); + + for (auto i = heap_start_page.page_number; i <= heap_end_page.page_number; i++) + { + active_table.map_page_to_next_free_frame(allocator, paging::virtual_page{i}, paging::entry::WRITABLE); + } + } + } // namespace + + 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(); + allocator::area_frame_allocator allocator(memory_information); + + cpu::set_cr2_bit(memory::cpu::cr2_flags::WRITE_PROTECT); + cpu::set_efer_bit(memory::cpu::efer_flags::NXE); + + paging::kernel_mapper kernel(allocator, memory_information); + auto & active_table = kernel.remap_kernel(); + video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); + + remap_heap(allocator, active_table); + } +} // namespace teachos::arch::memory \ No newline at end of file -- cgit v1.2.3 From 24805678884bcfcc3f14e88757955ab574d647cb Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 24 Nov 2024 13:18:31 +0000 Subject: add doxygen comments to remapping --- arch/x86_64/include/arch/memory/heap/allocator.hpp | 16 +++++++++++++++- arch/x86_64/include/arch/memory/main.hpp | 4 +++- arch/x86_64/src/memory/heap/allocator.cpp | 6 +++--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/arch/x86_64/include/arch/memory/heap/allocator.hpp b/arch/x86_64/include/arch/memory/heap/allocator.hpp index c486a4c..6f7535e 100644 --- a/arch/x86_64/include/arch/memory/heap/allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/allocator.hpp @@ -8,6 +8,9 @@ namespace teachos::arch::memory::heap std::size_t constexpr HEAP_START = 0x4000'0000; std::size_t constexpr HEAP_SIZE = 100 * 1024; + /** + * @brief Simple heap allocator + */ struct bump_allocator { bump_allocator(std::size_t heap_start, std::size_t heap_end) @@ -17,9 +20,20 @@ namespace teachos::arch::memory::heap { } + /** + * @brief Allocates the specified amount of memory in the heap + * + * @param size Amount of memory to allocate + * @return Address of the allocated memory + */ auto allocate(std::size_t size) -> void *; - auto deallocate(uint8_t * pointer, std::size_t size) -> void; + /** + * @brief Deallocates heap memory at the specified location + * + * @param pointer Pointer to the location which should be deallocated + */ + auto deallocate(uint8_t * pointer) -> void; private: std::size_t heap_start; diff --git a/arch/x86_64/include/arch/memory/main.hpp b/arch/x86_64/include/arch/memory/main.hpp index e166285..bbf160b 100644 --- a/arch/x86_64/include/arch/memory/main.hpp +++ b/arch/x86_64/include/arch/memory/main.hpp @@ -4,8 +4,10 @@ namespace teachos::arch::memory { /** - * @brief + * @brief Initializes memory management * + * @note Enables the necessary register flags and remaps the kernel, + * elf_sections, vga_text and the heap. */ auto initialize_memory_management() -> void; } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/memory/heap/allocator.cpp b/arch/x86_64/src/memory/heap/allocator.cpp index c9ddd78..bb61be4 100644 --- a/arch/x86_64/src/memory/heap/allocator.cpp +++ b/arch/x86_64/src/memory/heap/allocator.cpp @@ -17,10 +17,10 @@ namespace teachos::arch::memory::heap return reinterpret_cast(alloc_start); } - auto bump_allocator::deallocate(uint8_t * pointer, std::size_t size) -> void + auto bump_allocator::deallocate(uint8_t * pointer) -> void { - // Memory leak - if (pointer || size) + // Not implemented; leaking memory + if (pointer) { } } -- cgit v1.2.3 From 47732f54474a083e9f98e52714c12c0ca1181174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 24 Nov 2024 13:27:15 +0000 Subject: Use container helper classes for heap remapping --- .../arch/memory/allocator/physical_frame.hpp | 4 ++-- .../include/arch/memory/paging/virtual_page.hpp | 23 +++++++++++++++++++++- arch/x86_64/src/memory/main.cpp | 16 +++++++++------ arch/x86_64/src/memory/paging/virtual_page.cpp | 13 ++++++++++++ 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp index a39517a..d5e2f4c 100644 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -54,14 +54,14 @@ namespace teachos::arch::memory::allocator /** * @brief Post increment operator. Returns a copy of the value. * - * @return Copy of the incremented underlying address. + * @return Copy of the incremented underlying frame number. */ auto operator++(int) -> physical_frame; /** * @brief Pre increment operator. Returns a reference to the changed value. * - * @return Reference to the incremented underlying address. + * @return Reference to the incremented underlying frame number. */ auto operator++() -> physical_frame &; diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index c319af2..0ee9cbd 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -17,6 +17,11 @@ namespace teachos::arch::memory::paging */ struct virtual_page { + /** + * @brief Defaulted constructor. + */ + constexpr virtual_page() = default; + /** * @brief Constructor. * @@ -51,6 +56,20 @@ namespace teachos::arch::memory::paging */ auto get_level_index(page_table_handle::level level) const -> size_t; + /** + * @brief Post increment operator. Returns a copy of the value. + * + * @return Copy of the incremented underlying page number. + */ + auto operator++(int) -> virtual_page; + + /** + * @brief Pre increment operator. Returns a reference to the changed value. + * + * @return Reference to the incremented underlying page number. + */ + auto operator++() -> virtual_page &; + /** * @brief Defaulted equals operator. */ @@ -61,9 +80,11 @@ namespace teachos::arch::memory::paging */ auto operator<=>(const virtual_page & other) const -> std::partial_ordering = default; - std::size_t page_number; ///< Index number of the current virtual page, used to distinguish it from other pages. + std::size_t page_number = + {}; ///< Index number of the current virtual page, used to distinguish it from other pages. }; + typedef shared::container> page_container; } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index ce07115..80242cc 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -14,13 +14,16 @@ namespace teachos::arch::memory { auto remap_heap(allocator::area_frame_allocator allocator, paging::active_page_table & active_table) -> void { - auto heap_start_page = paging::virtual_page::containing_address(memory::heap::HEAP_START); - auto heap_end_page = - paging::virtual_page::containing_address(memory::heap::HEAP_START + memory::heap::HEAP_SIZE - 1); - - for (auto i = heap_start_page.page_number; i <= heap_end_page.page_number; i++) + auto const start_page = paging::virtual_page::containing_address(memory::heap::HEAP_START); + auto const end_page = + ++(paging::virtual_page::containing_address(memory::heap::HEAP_START + memory::heap::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}; + + for (auto const & page : pages) { - active_table.map_page_to_next_free_frame(allocator, paging::virtual_page{i}, paging::entry::WRITABLE); + active_table.map_page_to_next_free_frame(allocator, page, paging::entry::WRITABLE); } } } // namespace @@ -43,5 +46,6 @@ namespace teachos::arch::memory video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); remap_heap(allocator, active_table); + video::vga::text::write("Heap remapping successfull", video::vga::text::common_attributes::green_on_black); } } // namespace teachos::arch::memory \ No newline at end of file diff --git a/arch/x86_64/src/memory/paging/virtual_page.cpp b/arch/x86_64/src/memory/paging/virtual_page.cpp index f798709..d374156 100644 --- a/arch/x86_64/src/memory/paging/virtual_page.cpp +++ b/arch/x86_64/src/memory/paging/virtual_page.cpp @@ -17,4 +17,17 @@ namespace teachos::arch::memory::paging { 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 -- cgit v1.2.3 From c291e1ed629489c418049f6c4116433636717636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 24 Nov 2024 13:51:12 +0000 Subject: Add comments and rename file --- arch/x86_64/CMakeLists.txt | 2 +- arch/x86_64/include/arch/memory/heap/allocator.hpp | 46 ------------------- .../include/arch/memory/heap/bump_allocator.hpp | 53 ++++++++++++++++++++++ arch/x86_64/include/arch/memory/heap/concept.hpp | 7 ++- arch/x86_64/src/kernel/main.cpp | 18 +++++--- arch/x86_64/src/memory/heap/allocator.cpp | 27 ----------- arch/x86_64/src/memory/heap/bump_allocator.cpp | 26 +++++++++++ arch/x86_64/src/memory/main.cpp | 2 +- 8 files changed, 97 insertions(+), 84 deletions(-) delete mode 100644 arch/x86_64/include/arch/memory/heap/allocator.hpp create mode 100644 arch/x86_64/include/arch/memory/heap/bump_allocator.hpp delete mode 100644 arch/x86_64/src/memory/heap/allocator.cpp create mode 100644 arch/x86_64/src/memory/heap/bump_allocator.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 5b0e3a9..b758bf0 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -56,7 +56,7 @@ target_sources("_memory" PRIVATE "src/memory/cpu/tlb.cpp" "src/memory/cpu/control_register.cpp" "src/memory/cpu/msr.cpp" - "src/memory/heap/allocator.cpp" + "src/memory/heap/bump_allocator.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/memory/heap/allocator.hpp b/arch/x86_64/include/arch/memory/heap/allocator.hpp deleted file mode 100644 index 6f7535e..0000000 --- a/arch/x86_64/include/arch/memory/heap/allocator.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_ALLOCATOR_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_ALLOCATOR_HPP - -#include - -namespace teachos::arch::memory::heap -{ - std::size_t constexpr HEAP_START = 0x4000'0000; - std::size_t constexpr HEAP_SIZE = 100 * 1024; - - /** - * @brief Simple heap allocator - */ - struct bump_allocator - { - bump_allocator(std::size_t heap_start, std::size_t heap_end) - : heap_start{heap_start} - , heap_end{heap_end} - , next{heap_start} - { - } - - /** - * @brief Allocates the specified amount of memory in the heap - * - * @param size Amount of memory to allocate - * @return Address of the allocated memory - */ - auto allocate(std::size_t size) -> void *; - - /** - * @brief Deallocates heap memory at the specified location - * - * @param pointer Pointer to the location which should be deallocated - */ - auto deallocate(uint8_t * pointer) -> void; - - private: - std::size_t heap_start; - std::size_t heap_end; - std::size_t next; - }; - -} // namespace teachos::arch::memory::heap - -#endif \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp b/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp new file mode 100644 index 0000000..5b581ba --- /dev/null +++ b/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp @@ -0,0 +1,53 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_BUMP_ALLOCATOR_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_BUMP_ALLOCATOR_HPP + +#include + +namespace teachos::arch::memory::heap +{ + /** + * @brief Simple heap allocator, which leaks all allocated memory, because it does not really deallocate anything. + */ + struct bump_allocator + { + /** + * @brief Constructor. + * + * @param heap_start Start of the allocatable heap area + * @param heap_end End of the allocatable heap area (Start + Size) + */ + bump_allocator(std::size_t heap_start, std::size_t heap_end) + : heap_start{heap_start} + , heap_end{heap_end} + , next{heap_start} + { + // Nothing to do + } + + /** + * @brief Allocates the specified amount of memory in the heap. + * + * @param size Amount of memory to allocate. + * @return Address of the first byte to the allocated area + */ + auto allocate(std::size_t size) -> void *; + + /** + * @brief Deallocates heap memory at the specified location. + * + * @note Simply does nothing, because this allocator leaks all memory. + * + * @param pointer Pointer to the location which should be deallocated. + * @param size Size of the underlying memory area we want to deallocate. + */ + auto deallocate(uint8_t * pointer, std::size_t size) -> void; + + private: + std::size_t heap_start; ///< Start of the allocatable heap area + std::size_t heap_end; ///< End of the allocatable heap area + std::size_t next; ///< Current address, which is the start of still unused allocatable heap area + }; + +} // namespace teachos::arch::memory::heap + +#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_BUMP_ALLOCATOR_HPP diff --git a/arch/x86_64/include/arch/memory/heap/concept.hpp b/arch/x86_64/include/arch/memory/heap/concept.hpp index a525b0b..8c8c887 100644 --- a/arch/x86_64/include/arch/memory/heap/concept.hpp +++ b/arch/x86_64/include/arch/memory/heap/concept.hpp @@ -1,10 +1,13 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_CONCEPT_HPP #define TEACHOS_ARCH_X86_64_MEMORY_HEAP_CONCEPT_HPP -#include +#include namespace teachos::arch::memory::heap { + std::size_t constexpr HEAP_START = 0x4000'0000; + std::size_t constexpr HEAP_SIZE = 100 * 1024; + template concept HeapAllocator = requires(T t, uint8_t * pointer, std::size_t size) { { t.allocate(size) } -> std::same_as; @@ -12,4 +15,4 @@ namespace teachos::arch::memory::heap }; } // namespace teachos::arch::memory::heap -#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_CONCEPT_HPP \ No newline at end of file +#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_CONCEPT_HPP diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index cbd6e68..ce13723 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -1,6 +1,9 @@ #include "arch/kernel/main.hpp" +#include "arch/memory/heap/bump_allocator.hpp" +#include "arch/memory/heap/concept.hpp" #include "arch/memory/main.hpp" +#include "arch/memory/multiboot/reader.hpp" #include "arch/video/vga/text.hpp" namespace teachos::arch::kernel @@ -13,15 +16,16 @@ namespace teachos::arch::kernel memory::initialize_memory_management(); - // heap::bump_allocator heap_allocator{memory::heap::HEAP_START, heap::HEAP_START + memory::heap::HEAP_SIZE}; - // auto test = heap_allocator.allocate(1024); + memory::heap::bump_allocator heap_allocator{memory::heap::HEAP_START, + memory::heap::HEAP_START + memory::heap::HEAP_SIZE}; + auto test = heap_allocator.allocate(1024); - // auto test2 = new (test) multiboot::memory_information{}; + auto test2 = new (test) memory::multiboot::memory_information{}; - // if (test || test2) - // { - // video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); - // } + if (test || test2) + { + video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); + } // TODO: Why is identity mapping multiboot2 information structure with new kernel not required and // allocator.allocate_frame still works? diff --git a/arch/x86_64/src/memory/heap/allocator.cpp b/arch/x86_64/src/memory/heap/allocator.cpp deleted file mode 100644 index bb61be4..0000000 --- a/arch/x86_64/src/memory/heap/allocator.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "arch/memory/heap/allocator.hpp" - -#include "arch/exception_handling/assert.hpp" - -namespace teachos::arch::memory::heap -{ - auto bump_allocator::allocate(std::size_t size) -> void * - { - // Uses some sort of alignment orignally: - // https://github.com/phil-opp/blog_os/blob/7f6576c9dc34e360b81236c54c25c7827fd6a2df/src/memory/heap_allocator.rs#L24 - auto alloc_start = next; - auto alloc_end = next + size; - - arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory!"); - - next = alloc_end; - return reinterpret_cast(alloc_start); - } - - auto bump_allocator::deallocate(uint8_t * pointer) -> void - { - // Not implemented; leaking memory - if (pointer) - { - } - } -} // namespace teachos::arch::memory::heap \ No newline at end of file diff --git a/arch/x86_64/src/memory/heap/bump_allocator.cpp b/arch/x86_64/src/memory/heap/bump_allocator.cpp new file mode 100644 index 0000000..486ece8 --- /dev/null +++ b/arch/x86_64/src/memory/heap/bump_allocator.cpp @@ -0,0 +1,26 @@ +#include "arch/memory/heap/bump_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" + +namespace teachos::arch::memory::heap +{ + auto bump_allocator::allocate(std::size_t size) -> void * + { + // Uses some sort of alignment orignally: + // https://github.com/phil-opp/blog_os/blob/7f6576c9dc34e360b81236c54c25c7827fd6a2df/src/memory/heap_allocator.rs#L24 + auto alloc_start = next; + auto alloc_end = next + size; + + arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory!"); + + next = alloc_end; + return reinterpret_cast(alloc_start); + } + + auto bump_allocator::deallocate(uint8_t * pointer, std::size_t size) -> void + { + if (pointer || size) + { + } + } +} // namespace teachos::arch::memory::heap \ No newline at end of file diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 80242cc..34ce113 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -4,7 +4,7 @@ #include "arch/memory/allocator/area_frame_allocator.hpp" #include "arch/memory/cpu/control_register.hpp" #include "arch/memory/cpu/msr.hpp" -#include "arch/memory/heap/allocator.hpp" +#include "arch/memory/heap/concept.hpp" #include "arch/memory/paging/active_page_table.hpp" #include "arch/memory/paging/kernel_mapper.hpp" -- cgit v1.2.3 From 82cfe7fe12626a3bdf1bdf9efcbc7911051ebddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 24 Nov 2024 13:55:00 +0000 Subject: Read and write in allocated memory area --- arch/x86_64/src/kernel/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index ce13723..f4eb033 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -19,10 +19,10 @@ namespace teachos::arch::kernel memory::heap::bump_allocator heap_allocator{memory::heap::HEAP_START, memory::heap::HEAP_START + memory::heap::HEAP_SIZE}; auto test = heap_allocator.allocate(1024); - auto test2 = new (test) memory::multiboot::memory_information{}; - - if (test || test2) + test2->kernel_end = 5000; + auto test3 = test2->kernel_end; + if (test || test2 || test3) { video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); } -- cgit v1.2.3 From eada7bbb150fd81e6fbf71b1df28c8dc19393cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 24 Nov 2024 15:19:29 +0000 Subject: Adjust bump allocator comment --- arch/x86_64/include/arch/memory/heap/bump_allocator.hpp | 3 ++- arch/x86_64/src/kernel/main.cpp | 2 ++ arch/x86_64/src/memory/heap/bump_allocator.cpp | 2 -- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp b/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp index 5b581ba..d31783d 100644 --- a/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp @@ -6,7 +6,8 @@ namespace teachos::arch::memory::heap { /** - * @brief Simple heap allocator, which leaks all allocated memory, because it does not really deallocate anything. + * @brief Simple heap allocator, which allocates linearly and leaks all allocated memory, because it does not really + * deallocate anything. */ struct bump_allocator { diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index f4eb033..13526f4 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -31,5 +31,7 @@ namespace teachos::arch::kernel // allocator.allocate_frame still works? // TODO: Fix unmapping old level 4 page table and turn it into guard page, use Stack Probes for stack allocation if // possible. + + // TODO: Align up and down for the bump allocator. https://os.phil-opp.com/kernel-heap/#a-bump-allocator } } // namespace teachos::arch::kernel diff --git a/arch/x86_64/src/memory/heap/bump_allocator.cpp b/arch/x86_64/src/memory/heap/bump_allocator.cpp index 486ece8..1ab8ea9 100644 --- a/arch/x86_64/src/memory/heap/bump_allocator.cpp +++ b/arch/x86_64/src/memory/heap/bump_allocator.cpp @@ -6,8 +6,6 @@ namespace teachos::arch::memory::heap { auto bump_allocator::allocate(std::size_t size) -> void * { - // Uses some sort of alignment orignally: - // https://github.com/phil-opp/blog_os/blob/7f6576c9dc34e360b81236c54c25c7827fd6a2df/src/memory/heap_allocator.rs#L24 auto alloc_start = next; auto alloc_end = next + size; -- cgit v1.2.3 From d2aa4fbf948a56df5328e0f1b8ec3dfd52b16e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 26 Nov 2024 09:49:06 +0000 Subject: Make bump allocator atomic and therefore thread safe --- .../include/arch/memory/heap/bump_allocator.hpp | 7 ++-- arch/x86_64/src/kernel/main.cpp | 9 ++--- arch/x86_64/src/memory/heap/bump_allocator.cpp | 43 ++++++++++++++++++---- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp b/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp index d31783d..595eeea 100644 --- a/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_BUMP_ALLOCATOR_HPP #define TEACHOS_ARCH_X86_64_MEMORY_HEAP_BUMP_ALLOCATOR_HPP +#include #include namespace teachos::arch::memory::heap @@ -44,9 +45,9 @@ namespace teachos::arch::memory::heap auto deallocate(uint8_t * pointer, std::size_t size) -> void; private: - std::size_t heap_start; ///< Start of the allocatable heap area - std::size_t heap_end; ///< End of the allocatable heap area - std::size_t next; ///< Current address, which is the start of still unused allocatable heap area + std::size_t heap_start; ///< Start of the allocatable heap area + std::size_t heap_end; ///< End of the allocatable heap area + std::atomic_uint64_t next; ///< Current address, which is the start of still unused allocatable heap area }; } // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 13526f4..023327e 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -20,9 +20,10 @@ namespace teachos::arch::kernel memory::heap::HEAP_START + memory::heap::HEAP_SIZE}; auto test = heap_allocator.allocate(1024); auto test2 = new (test) memory::multiboot::memory_information{}; - test2->kernel_end = 5000; - auto test3 = test2->kernel_end; - if (test || test2 || test3) + auto test3 = *test2; + test3.kernel_end = 5000; + auto test4 = test3.kernel_end; + if (test || test2 || test3.kernel_end || test4) { video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); } @@ -31,7 +32,5 @@ namespace teachos::arch::kernel // allocator.allocate_frame still works? // TODO: Fix unmapping old level 4 page table and turn it into guard page, use Stack Probes for stack allocation if // possible. - - // TODO: Align up and down for the bump allocator. https://os.phil-opp.com/kernel-heap/#a-bump-allocator } } // namespace teachos::arch::kernel diff --git a/arch/x86_64/src/memory/heap/bump_allocator.cpp b/arch/x86_64/src/memory/heap/bump_allocator.cpp index 1ab8ea9..19ced47 100644 --- a/arch/x86_64/src/memory/heap/bump_allocator.cpp +++ b/arch/x86_64/src/memory/heap/bump_allocator.cpp @@ -2,17 +2,43 @@ #include "arch/exception_handling/assert.hpp" +#include +#include + namespace teachos::arch::memory::heap { - auto bump_allocator::allocate(std::size_t size) -> void * + namespace { - auto alloc_start = next; - auto alloc_end = next + size; - - arch::exception_handling::assert(alloc_end <= heap_end, "[Heap Allocator] Out of memory!"); + 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 - next = alloc_end; - return reinterpret_cast(alloc_start); + auto bump_allocator::allocate(std::size_t size) -> void * + { + // 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 alloc_start = next.load(std::memory_order::relaxed); + 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. + auto const updated = next.compare_exchange_strong(alloc_start, alloc_end, std::memory_order::relaxed); + if (updated) + { + return reinterpret_cast(alloc_start); + } + } } auto bump_allocator::deallocate(uint8_t * pointer, std::size_t size) -> void @@ -21,4 +47,5 @@ namespace teachos::arch::memory::heap { } } -} // namespace teachos::arch::memory::heap \ No newline at end of file + +} // namespace teachos::arch::memory::heap -- cgit v1.2.3 From a4268440d5c77f39032bb9f003aafd7fef2ca997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 26 Nov 2024 11:09:59 +0000 Subject: Replace strong with weak compare_exchange --- arch/x86_64/src/memory/heap/bump_allocator.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/src/memory/heap/bump_allocator.cpp b/arch/x86_64/src/memory/heap/bump_allocator.cpp index 19ced47..8807645 100644 --- a/arch/x86_64/src/memory/heap/bump_allocator.cpp +++ b/arch/x86_64/src/memory/heap/bump_allocator.cpp @@ -32,8 +32,9 @@ namespace teachos::arch::memory::heap 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. - auto const updated = next.compare_exchange_strong(alloc_start, alloc_end, std::memory_order::relaxed); + // 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); -- cgit v1.2.3 From 31796138b1c85e7b3236055b6d93d568e1fe8a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 28 Nov 2024 12:40:04 +0000 Subject: Create base of linked list allocator --- arch/x86_64/CMakeLists.txt | 2 ++ .../arch/memory/heap/linked_list_allocator.hpp | 37 ++++++++++++++++++++++ .../include/arch/memory/heap/memory_hole.hpp | 28 ++++++++++++++++ .../src/memory/heap/linked_list_allocator.cpp | 16 ++++++++++ arch/x86_64/src/memory/heap/memory_hole.cpp | 11 +++++++ 5 files changed, 94 insertions(+) create mode 100644 arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp create mode 100644 arch/x86_64/include/arch/memory/heap/memory_hole.hpp create mode 100644 arch/x86_64/src/memory/heap/linked_list_allocator.cpp create mode 100644 arch/x86_64/src/memory/heap/memory_hole.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index b758bf0..4ba6590 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -57,6 +57,8 @@ target_sources("_memory" PRIVATE "src/memory/cpu/control_register.cpp" "src/memory/cpu/msr.cpp" "src/memory/heap/bump_allocator.cpp" + "src/memory/heap/memory_hole.cpp" + "src/memory/heap/linked_list_allocator.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp new file mode 100644 index 0000000..a742018 --- /dev/null +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -0,0 +1,37 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_LINKED_LIST_ALLOCATOR_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_LINKED_LIST_ALLOCATOR_HPP + +#include "arch/memory/heap/memory_hole.hpp" + +#include + +namespace teachos::arch::memory::heap +{ + /** + * @brief Sorted by address list of memory holes (free memory). Uses free holes itself to save the information, + * containing the size and pointer to the next hole. Resulting in a single linked list. + */ + struct linked_list_allocator + { + /** + * @brief Constructor. + * + * @param heap_start Start of the allocatable heap area + * @param heap_end End of the allocatable heap area (Start + Size) + */ + linked_list_allocator(std::size_t heap_start, std::size_t heap_end); + + /** + * @brief Returns the smallest allocatable block of heap memory. + * + * @return Smallest allocatable block of heap memory. + */ + auto constexpr min_allocatable_size() -> std::size_t { return sizeof(memory_hole); } + + std::size_t heap_start; ///< Start of the allocatable heap area + std::size_t heap_end; ///< End of the allocatable heap area + memory_hole first; ///< First free entry in our memory + }; +} // namespace teachos::arch::memory::heap + +#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_LINKED_LIST_ALLOCATOR_HPP diff --git a/arch/x86_64/include/arch/memory/heap/memory_hole.hpp b/arch/x86_64/include/arch/memory/heap/memory_hole.hpp new file mode 100644 index 0000000..e017599 --- /dev/null +++ b/arch/x86_64/include/arch/memory/heap/memory_hole.hpp @@ -0,0 +1,28 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_HOLE_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_HOLE_HPP + +#include + +namespace teachos::arch::memory::heap +{ + /** + * @brief Block containing free memory, pointing to the next free hole (nullptr) if there is none. + * Forms a single linked list. + */ + struct memory_hole + { + /** + * @brief Constructor, + * + * @param size Amount of free memory of this specific hole. + * @param next Optional pointer to the next free memory. + */ + memory_hole(std::size_t size, memory_hole * next); + + std::size_t size; ///< Amount of free memory this hole contains, has to always be atleast 16 bytes to hold the size + ///< variable and the pointer to the next hole. + memory_hole * next; ///< Optional pointer to the next free memory, holds nullptr if there is none. + }; +} // namespace teachos::arch::memory::heap + +#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_HOLE_HPP diff --git a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp new file mode 100644 index 0000000..b0f011b --- /dev/null +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -0,0 +1,16 @@ +#include "arch/memory/heap/linked_list_allocator.hpp" + +#include "arch/exception_handling/assert.hpp" + +namespace teachos::arch::memory::heap +{ + linked_list_allocator::linked_list_allocator(std::size_t heap_start, std::size_t heap_end) + : heap_start(heap_start) + , heap_end(heap_end) + , first(heap_end - heap_start, nullptr) + { + exception_handling::assert(heap_end - heap_start < min_allocatable_size(), + "[Memory Hole List] Total heap size can not be smaller than minimum of 16 bytes to hold " + "atleast one memory hole entry"); + } +} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/heap/memory_hole.cpp b/arch/x86_64/src/memory/heap/memory_hole.cpp new file mode 100644 index 0000000..7590610 --- /dev/null +++ b/arch/x86_64/src/memory/heap/memory_hole.cpp @@ -0,0 +1,11 @@ +#include "arch/memory/heap/memory_hole.hpp" + +namespace teachos::arch::memory::heap +{ + memory_hole::memory_hole(std::size_t size, memory_hole * next) + : size(size) + , next(next) + { + // Nothing to do + } +} // namespace teachos::arch::memory::heap -- cgit v1.2.3 From d3e4df4dd4ee117e247f78a86746bf178787bc8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 28 Nov 2024 13:53:01 +0000 Subject: Start with linked list alloc and dealloc --- .../arch/memory/heap/linked_list_allocator.hpp | 30 ++++++++++++++++++++++ .../src/memory/heap/linked_list_allocator.cpp | 27 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index a742018..da7fc37 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -21,6 +21,25 @@ namespace teachos::arch::memory::heap */ linked_list_allocator(std::size_t heap_start, std::size_t heap_end); + /** + * @brief Allocates the specified amount of memory in the heap. + * + * @param size Amount of memory to allocate. + * @return Address of the first byte to the allocated area + */ + auto allocate(std::size_t size) -> void *; + + /** + * @brief Deallocates heap memory at the specified location. + * + * @note Simply does nothing, because this allocator leaks all memory. + * + * @param pointer Pointer to the location which should be deallocated. + * @param size Size of the underlying memory area we want to deallocate. + */ + auto deallocate(uint8_t * pointer, std::size_t size) -> void; + + private: /** * @brief Returns the smallest allocatable block of heap memory. * @@ -28,6 +47,17 @@ namespace teachos::arch::memory::heap */ auto constexpr min_allocatable_size() -> std::size_t { return sizeof(memory_hole); } + /** + * @brief Splits the given hole into two, where the latter block keeps beeing free and the first part will be used + * for the allocation. + * + * @param current_hole Hole we want to split. + * @param new_hole New hole created by the split. + * + * @return Address of the hole we just split. + */ + auto split_hole(memory_hole & current_hole, memory_hole *& new_hole) -> void *; + std::size_t heap_start; ///< Start of the allocatable heap area std::size_t heap_end; ///< End of the allocatable heap area memory_hole first; ///< First free entry in our memory 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 b0f011b..006d9c7 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -2,6 +2,8 @@ #include "arch/exception_handling/assert.hpp" +#include + namespace teachos::arch::memory::heap { linked_list_allocator::linked_list_allocator(std::size_t heap_start, std::size_t heap_end) @@ -13,4 +15,29 @@ namespace teachos::arch::memory::heap "[Memory Hole List] Total heap size can not be smaller than minimum of 16 bytes to hold " "atleast one memory hole entry"); } + + auto linked_list_allocator::allocate(std::size_t size) -> void * + { + if (first.next == nullptr || size) + { + } + return nullptr; + } + + auto linked_list_allocator::deallocate(uint8_t * pointer, std::size_t size) -> void + { + auto const deallocate_size = std::max(size, min_allocatable_size()); + if (pointer || deallocate_size) + { + } + } + + auto split_hole(memory_hole & current_hole, memory_hole *& new_hole) -> void * + { + if (new_hole) + { + } + return static_cast(¤t_hole); + } + } // namespace teachos::arch::memory::heap -- cgit v1.2.3 From 9af867de0050eef28772f7dee799666ae343950e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Thu, 28 Nov 2024 14:33:42 +0000 Subject: Start imlementation on actual algorithm --- .../arch/memory/heap/linked_list_allocator.hpp | 6 +-- .../src/memory/heap/linked_list_allocator.cpp | 44 ++++++++++++++++------ 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index da7fc37..5f9a72b 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -52,15 +52,15 @@ namespace teachos::arch::memory::heap * for the allocation. * * @param current_hole Hole we want to split. - * @param new_hole New hole created by the split. + * @param size Size we want to allocate at the start of the hole. * * @return Address of the hole we just split. */ - auto split_hole(memory_hole & current_hole, memory_hole *& new_hole) -> void *; + auto split_hole(memory_hole *& current_hole, std::size_t size) -> void *; std::size_t heap_start; ///< Start of the allocatable heap area std::size_t heap_end; ///< End of the allocatable heap area - memory_hole first; ///< First free entry in our memory + memory_hole * first; ///< First free entry in our memory }; } // namespace teachos::arch::memory::heap 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 006d9c7..f4ba5e2 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -1,6 +1,7 @@ #include "arch/memory/heap/linked_list_allocator.hpp" #include "arch/exception_handling/assert.hpp" +#include "arch/exception_handling/panic.hpp" #include @@ -9,19 +10,39 @@ namespace teachos::arch::memory::heap linked_list_allocator::linked_list_allocator(std::size_t heap_start, std::size_t heap_end) : heap_start(heap_start) , heap_end(heap_end) - , first(heap_end - heap_start, nullptr) + , first(nullptr) { - exception_handling::assert(heap_end - heap_start < min_allocatable_size(), - "[Memory Hole List] Total heap size can not be smaller than minimum of 16 bytes to hold " - "atleast one memory hole entry"); + 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_hole(heap_size, nullptr); } auto linked_list_allocator::allocate(std::size_t size) -> void * { - if (first.next == nullptr || size) + memory_hole * previous = nullptr; + auto current = first; + while (current != nullptr) { + if (current->size > size) + { + return split_hole(current, size); + } + else if (current->size == size) + { + if (previous != nullptr) + { + previous->next = current->next; + } + delete current; + return static_cast(current); + } + previous = current; + current = current->next; } - return nullptr; + exception_handling::panic("[Linked List Allocator] Out of memory"); } auto linked_list_allocator::deallocate(uint8_t * pointer, std::size_t size) -> void @@ -32,12 +53,13 @@ namespace teachos::arch::memory::heap } } - auto split_hole(memory_hole & current_hole, memory_hole *& new_hole) -> void * + auto split_hole(memory_hole *& current_hole, std::size_t size) -> void * { - if (new_hole) - { - } - return static_cast(¤t_hole); + auto const previous_address = reinterpret_cast(current_hole); + auto const new_address = previous_address + size; + current_hole = + new (reinterpret_cast(new_address)) memory_hole(current_hole->size - size, current_hole->next); + return reinterpret_cast(previous_address); } } // namespace teachos::arch::memory::heap -- cgit v1.2.3 From e8bbb1ad850a362dfa25ba1ea7bdd838a379def8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 1 Dec 2024 07:46:20 +0000 Subject: Move heap virtual location and allocate multiple variables to test heap. --- arch/x86_64/include/arch/memory/heap/concept.hpp | 2 +- arch/x86_64/src/kernel/main.cpp | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/arch/x86_64/include/arch/memory/heap/concept.hpp b/arch/x86_64/include/arch/memory/heap/concept.hpp index 8c8c887..52dba51 100644 --- a/arch/x86_64/include/arch/memory/heap/concept.hpp +++ b/arch/x86_64/include/arch/memory/heap/concept.hpp @@ -5,7 +5,7 @@ namespace teachos::arch::memory::heap { - std::size_t constexpr HEAP_START = 0x4000'0000; + std::size_t constexpr HEAP_START = 0x100000000; std::size_t constexpr HEAP_SIZE = 100 * 1024; template diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 023327e..dd0a1d8 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -20,10 +20,15 @@ namespace teachos::arch::kernel memory::heap::HEAP_START + memory::heap::HEAP_SIZE}; auto test = heap_allocator.allocate(1024); auto test2 = new (test) memory::multiboot::memory_information{}; - auto test3 = *test2; - test3.kernel_end = 5000; - auto test4 = test3.kernel_end; - if (test || test2 || test3.kernel_end || test4) + test = static_cast(static_cast(test) + 1); + auto test3 = new (test) 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; + if (test6 && test7) { video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); } -- cgit v1.2.3 From c1e7edabc1dfbe387546297720fc495837d38d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 1 Dec 2024 09:46:37 +0000 Subject: Fix guard page and ensure it crashes even if guard page is skipped altogether --- arch/x86_64/scripts/kernel.ld | 20 ++++++++++---------- arch/x86_64/src/boot/boot.s | 16 ++++++++++------ arch/x86_64/src/kernel/main.cpp | 35 ++++++++++++++++++++++++----------- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld index c3eea9c..cc07896 100644 --- a/arch/x86_64/scripts/kernel.ld +++ b/arch/x86_64/scripts/kernel.ld @@ -48,17 +48,17 @@ SECTIONS *(.boot_text) } :boot_text - .boot_data ALIGN(4K) : AT(ADDR (.boot_data)) - { - *(.boot_data) - } :boot_data - .boot_bss ALIGN(4K) : AT(ADDR (.boot_bss)) { *(.boot_bss) *(.boot_stack) } + .boot_data ALIGN(4K) : AT(ADDR (.boot_data)) + { + *(.boot_data) + } :boot_data + /*************************************************************************** * Now it is time to load the 64-bit kernel code. We * make sure to align the loaded data onto a page boundary. @@ -112,17 +112,17 @@ SECTIONS KEEP(*crtend.o(.dtors)) } - .data ALIGN(4K) : AT (ADDR (.data)) - { - *(.data*) - } - .bss ALIGN(4K) : AT (ADDR (.bss)) { *(COMMON) *(.bss*) } + .data ALIGN(4K) : AT (ADDR (.data)) + { + *(.data*) + } + /*************************************************************************** * In accordance with the symbol definitions at the start, we generate some * symbols to mark the end of our loaded image. diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index c1b3203..8d27ea1 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -7,6 +7,16 @@ * Uninitialized data for the bootstrapping process. */ .section .boot_bss, "aw", @nobits + +/** + * Reserve some space for the Multiboot 2 information pointer. + */ +.global multiboot_information_pointer +multiboot_information_pointer: .skip 4 + +/** + * Align page maps to 4 KiB or the assembler code, will cause crashes when attempting to enable paging. + */ .align 4096 /** @@ -30,12 +40,6 @@ page_map_level_3: .skip 512 * 8 .global page_map_level_2 page_map_level_2: .skip 512 * 8 -/** - * Reserve some space for the Multiboot 2 information pointer. - */ -.global multiboot_information_pointer -multiboot_information_pointer: .skip 4 - /** * Stack space for the bootstrapping process. * diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index dd0a1d8..7463fc4 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -8,14 +8,19 @@ namespace teachos::arch::kernel { - auto main() -> void + auto stack_overflow_test(int count) -> int { - 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); - - memory::initialize_memory_management(); + int test[5000] = {}; + if (test[0] == 0xFFFF) + { + return count; + } + count = stack_overflow_test(count); + return count++; + } + auto heap_test() -> void + { memory::heap::bump_allocator heap_allocator{memory::heap::HEAP_START, memory::heap::HEAP_START + memory::heap::HEAP_SIZE}; auto test = heap_allocator.allocate(1024); @@ -28,14 +33,22 @@ namespace teachos::arch::kernel test5.kernel_end = 3000; auto test6 = test4.kernel_end; auto test7 = test5.kernel_end; - if (test6 && test7) + auto test8 = memory::multiboot::read_multiboot2(); + if (test6 && test7 && test8.kernel_end) { video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); } + } + + 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); + + memory::initialize_memory_management(); - // TODO: Why is identity mapping multiboot2 information structure with new kernel not required and - // allocator.allocate_frame still works? - // TODO: Fix unmapping old level 4 page table and turn it into guard page, use Stack Probes for stack allocation if - // possible. + // stack_overflow_test(0); + // heap_test(); } } // namespace teachos::arch::kernel -- cgit v1.2.3 From 318fbff1717b291c81db8f9c4d5a84019fe2b4b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 1 Dec 2024 10:21:17 +0000 Subject: Adjust allocate --- arch/x86_64/src/memory/heap/linked_list_allocator.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) 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 f4ba5e2..a2a8c79 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -22,8 +22,8 @@ namespace teachos::arch::memory::heap auto linked_list_allocator::allocate(std::size_t size) -> void * { - memory_hole * previous = nullptr; - auto current = first; + auto & previous = first; + auto & current = first; while (current != nullptr) { if (current->size > size) @@ -32,10 +32,14 @@ namespace teachos::arch::memory::heap } else if (current->size == size) { - if (previous != nullptr) + if (previous != current) { previous->next = current->next; } + else + { + current = current->next; + } delete current; return static_cast(current); } -- cgit v1.2.3 From eba6c94eed15b90ea8a09e4bc16ae1c0f1645dea Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 1 Dec 2024 11:08:00 +0000 Subject: implement first half of linked list dallocation --- arch/x86_64/CMakeLists.txt | 2 +- .../include/arch/memory/heap/bump_allocator.hpp | 2 +- .../arch/memory/heap/linked_list_allocator.hpp | 12 ++--- .../include/arch/memory/heap/memory_block.hpp | 28 +++++++++++ .../include/arch/memory/heap/memory_hole.hpp | 28 ----------- arch/x86_64/src/memory/heap/bump_allocator.cpp | 2 +- .../src/memory/heap/linked_list_allocator.cpp | 55 +++++++++++++++++----- arch/x86_64/src/memory/heap/memory_block.cpp | 11 +++++ arch/x86_64/src/memory/heap/memory_hole.cpp | 11 ----- 9 files changed, 92 insertions(+), 59 deletions(-) create mode 100644 arch/x86_64/include/arch/memory/heap/memory_block.hpp delete mode 100644 arch/x86_64/include/arch/memory/heap/memory_hole.hpp create mode 100644 arch/x86_64/src/memory/heap/memory_block.cpp delete mode 100644 arch/x86_64/src/memory/heap/memory_hole.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 4ba6590..4a02e15 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -57,7 +57,7 @@ target_sources("_memory" PRIVATE "src/memory/cpu/control_register.cpp" "src/memory/cpu/msr.cpp" "src/memory/heap/bump_allocator.cpp" - "src/memory/heap/memory_hole.cpp" + "src/memory/heap/memory_block.cpp" "src/memory/heap/linked_list_allocator.cpp" ) diff --git a/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp b/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp index 595eeea..545b72f 100644 --- a/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/bump_allocator.hpp @@ -42,7 +42,7 @@ namespace teachos::arch::memory::heap * @param pointer Pointer to the location which should be deallocated. * @param size Size of the underlying memory area we want to deallocate. */ - auto deallocate(uint8_t * pointer, std::size_t size) -> void; + auto deallocate(void * pointer, std::size_t size) -> void; private: std::size_t heap_start; ///< Start of the allocatable heap area diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index 5f9a72b..99d0013 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_LINKED_LIST_ALLOCATOR_HPP #define TEACHOS_ARCH_X86_64_MEMORY_HEAP_LINKED_LIST_ALLOCATOR_HPP -#include "arch/memory/heap/memory_hole.hpp" +#include "arch/memory/heap/memory_block.hpp" #include @@ -37,7 +37,7 @@ namespace teachos::arch::memory::heap * @param pointer Pointer to the location which should be deallocated. * @param size Size of the underlying memory area we want to deallocate. */ - auto deallocate(uint8_t * pointer, std::size_t size) -> void; + auto deallocate(void * pointer, std::size_t size) -> void; private: /** @@ -45,22 +45,22 @@ namespace teachos::arch::memory::heap * * @return Smallest allocatable block of heap memory. */ - auto constexpr min_allocatable_size() -> std::size_t { return sizeof(memory_hole); } + auto constexpr min_allocatable_size() -> std::size_t { return sizeof(memory_block); } /** * @brief Splits the given hole into two, where the latter block keeps beeing free and the first part will be used * for the allocation. * - * @param current_hole Hole we want to split. + * @param current_block Hole we want to split. * @param size Size we want to allocate at the start of the hole. * * @return Address of the hole we just split. */ - auto split_hole(memory_hole *& current_hole, std::size_t size) -> void *; + auto split_free_memory_block(memory_block *& current_block, std::size_t size) -> void *; std::size_t heap_start; ///< Start of the allocatable heap area std::size_t heap_end; ///< End of the allocatable heap area - memory_hole * first; ///< First free entry in our memory + memory_block * first; ///< First free entry in our memory }; } // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/include/arch/memory/heap/memory_block.hpp b/arch/x86_64/include/arch/memory/heap/memory_block.hpp new file mode 100644 index 0000000..c48d0cd --- /dev/null +++ b/arch/x86_64/include/arch/memory/heap/memory_block.hpp @@ -0,0 +1,28 @@ +#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_BLOCK_HPP +#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_BLOCK_HPP + +#include + +namespace teachos::arch::memory::heap +{ + /** + * @brief Block containing free memory, pointing to the next free hole (nullptr) if there is none. + * Forms a single linked list. + */ + struct memory_block + { + /** + * @brief Constructor, + * + * @param size Amount of free memory of this specific hole. + * @param next Optional pointer to the next free memory. + */ + memory_block(std::size_t size, memory_block * next); + + std::size_t size; ///< Amount of free memory this hole contains, has to always be atleast 16 bytes to hold the size + ///< variable and the pointer to the next hole. + memory_block * next; ///< Optional pointer to the next free memory, holds nullptr if there is none. + }; +} // namespace teachos::arch::memory::heap + +#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_BLOCK_HPP diff --git a/arch/x86_64/include/arch/memory/heap/memory_hole.hpp b/arch/x86_64/include/arch/memory/heap/memory_hole.hpp deleted file mode 100644 index e017599..0000000 --- a/arch/x86_64/include/arch/memory/heap/memory_hole.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_HOLE_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_HOLE_HPP - -#include - -namespace teachos::arch::memory::heap -{ - /** - * @brief Block containing free memory, pointing to the next free hole (nullptr) if there is none. - * Forms a single linked list. - */ - struct memory_hole - { - /** - * @brief Constructor, - * - * @param size Amount of free memory of this specific hole. - * @param next Optional pointer to the next free memory. - */ - memory_hole(std::size_t size, memory_hole * next); - - std::size_t size; ///< Amount of free memory this hole contains, has to always be atleast 16 bytes to hold the size - ///< variable and the pointer to the next hole. - memory_hole * next; ///< Optional pointer to the next free memory, holds nullptr if there is none. - }; -} // namespace teachos::arch::memory::heap - -#endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_HOLE_HPP diff --git a/arch/x86_64/src/memory/heap/bump_allocator.cpp b/arch/x86_64/src/memory/heap/bump_allocator.cpp index 8807645..bbf2021 100644 --- a/arch/x86_64/src/memory/heap/bump_allocator.cpp +++ b/arch/x86_64/src/memory/heap/bump_allocator.cpp @@ -42,7 +42,7 @@ namespace teachos::arch::memory::heap } } - auto bump_allocator::deallocate(uint8_t * pointer, std::size_t size) -> void + auto bump_allocator::deallocate(void * pointer, std::size_t size) -> void { if (pointer || size) { 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 a2a8c79..9b27f70 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -17,20 +17,24 @@ namespace teachos::arch::memory::heap 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_hole(heap_size, nullptr); + first = new (reinterpret_cast(heap_start)) memory_block(heap_size, nullptr); } auto linked_list_allocator::allocate(std::size_t size) -> void * { + exception_handling::assert(size < min_allocatable_size(), + "[Linked List Allocator] Allocated memory cannot be smaller than 16 bytes"); + auto & previous = first; auto & current = first; + while (current != nullptr) { - if (current->size > size) + if (current->size >= size + min_allocatable_size()) { - return split_hole(current, size); + return split_free_memory_block(current, size); } - else if (current->size == size) + else if (current->size >= size) { if (previous != current) { @@ -40,30 +44,59 @@ namespace teachos::arch::memory::heap { current = current->next; } + delete current; return static_cast(current); } + previous = current; current = current->next; } exception_handling::panic("[Linked List Allocator] Out of memory"); } - auto linked_list_allocator::deallocate(uint8_t * pointer, std::size_t size) -> void + auto linked_list_allocator::deallocate(void * pointer, std::size_t size) -> void { - auto const deallocate_size = std::max(size, min_allocatable_size()); - if (pointer || deallocate_size) + exception_handling::assert(size < min_allocatable_size(), + "[Linked List Allocator] Allocated memory cannot be smaller than 16 bytes"); + + auto & previous = first; + auto & current = first; + + while (current != nullptr) { + // if pointer + size < current + // create memory block + auto const previous_address = reinterpret_cast(pointer); + auto const new_address = previous_address + size; + + if (new_address != reinterpret_cast(current) && + previous_address != (reinterpret_cast(previous) + previous->size)) + { + auto new_block = new (pointer) memory_block(size, current); + previous->next = new_block; + return; + } + + // elseif pointer + size == current + // combine memory block with current + // combine(previous, pointer, current) + + previous = current; + current = current->next; } } - auto split_hole(memory_hole *& current_hole, std::size_t size) -> void * + auto linked_list_allocator::split_free_memory_block(memory_block *& current_block, std::size_t size) -> void * { - auto const previous_address = reinterpret_cast(current_hole); + auto const previous_address = reinterpret_cast(current_block); auto const new_address = previous_address + size; - current_hole = - new (reinterpret_cast(new_address)) memory_hole(current_hole->size - size, current_hole->next); + current_block = + new (reinterpret_cast(new_address)) memory_block(current_block->size - size, current_block->next); return reinterpret_cast(previous_address); } + // auto linked_list_allocator::combine_free_memory_block(memory_block *& previous_block, memory_block *& + // current_block, std::size_t size) -> void * + } // 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 new file mode 100644 index 0000000..b68dd6d --- /dev/null +++ b/arch/x86_64/src/memory/heap/memory_block.cpp @@ -0,0 +1,11 @@ +#include "arch/memory/heap/memory_block.hpp" + +namespace teachos::arch::memory::heap +{ + memory_block::memory_block(std::size_t size, memory_block * next) + : size(size) + , next(next) + { + // Nothing to do + } +} // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/src/memory/heap/memory_hole.cpp b/arch/x86_64/src/memory/heap/memory_hole.cpp deleted file mode 100644 index 7590610..0000000 --- a/arch/x86_64/src/memory/heap/memory_hole.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "arch/memory/heap/memory_hole.hpp" - -namespace teachos::arch::memory::heap -{ - memory_hole::memory_hole(std::size_t size, memory_hole * next) - : size(size) - , next(next) - { - // Nothing to do - } -} // namespace teachos::arch::memory::heap -- cgit v1.2.3 From b8fd52b6b3a7f002cff58ff8da0313a684cb3ab4 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 1 Dec 2024 11:44:30 +0000 Subject: implement heap linked_list deallocate --- .../arch/memory/heap/linked_list_allocator.hpp | 3 + .../src/memory/heap/linked_list_allocator.cpp | 64 +++++++++++++++------- 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index 99d0013..2d76124 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -58,6 +58,9 @@ namespace teachos::arch::memory::heap */ auto split_free_memory_block(memory_block *& current_block, std::size_t size) -> void *; + auto coalesce_free_memory_block(memory_block *& previous_block, memory_block *& current_block, void * pointer, + std::size_t size) -> void *; + std::size_t heap_start; ///< Start of the allocatable heap area std::size_t heap_end; ///< End of the allocatable heap area memory_block * first; ///< First free entry in our memory 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 9b27f70..3330399 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -60,43 +60,65 @@ namespace teachos::arch::memory::heap exception_handling::assert(size < min_allocatable_size(), "[Linked List Allocator] Allocated memory cannot be smaller than 16 bytes"); + auto const start_address = reinterpret_cast(pointer); + auto const end_address = start_address + size; + auto & previous = first; auto & current = first; while (current != nullptr) { - // if pointer + size < current - // create memory block - auto const previous_address = reinterpret_cast(pointer); - auto const new_address = previous_address + size; - - if (new_address != reinterpret_cast(current) && - previous_address != (reinterpret_cast(previous) + previous->size)) + if (reinterpret_cast(current) >= end_address) { - auto new_block = new (pointer) memory_block(size, current); - previous->next = new_block; - return; + break; } - // elseif pointer + size == current - // combine memory block with current - // combine(previous, pointer, current) - - previous = current; + previous->next = current; current = current->next; } + + coalesce_free_memory_block(previous, current, pointer, size); } auto linked_list_allocator::split_free_memory_block(memory_block *& current_block, std::size_t size) -> void * { - auto const previous_address = reinterpret_cast(current_block); - auto const new_address = previous_address + size; + auto const start_address = reinterpret_cast(current_block); + auto const end_address = start_address + size; current_block = - new (reinterpret_cast(new_address)) memory_block(current_block->size - size, current_block->next); - return reinterpret_cast(previous_address); + new (reinterpret_cast(end_address)) memory_block(current_block->size - size, current_block->next); + return reinterpret_cast(start_address); } - // auto linked_list_allocator::combine_free_memory_block(memory_block *& previous_block, memory_block *& - // current_block, std::size_t size) -> void * + 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; + + auto block_size = size; + auto new_block_address = pointer; + auto next_block = current_block; + + // If free memory block after block to deallocate is adjacent + if (end_address == reinterpret_cast(current_block)) + { + block_size += current_block->size; + next_block = current_block->next; + + delete current_block; + } + + // If free memory block before block to deallocate is adjacent + if (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; + } + + new (reinterpret_cast(new_block_address)) memory_block(block_size, next_block); + } } // namespace teachos::arch::memory::heap -- cgit v1.2.3 From 2671b9522db44418536559524a22c95d3575569e Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 1 Dec 2024 12:07:42 +0000 Subject: enable heap test --- arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp | 4 +--- arch/x86_64/src/kernel/main.cpp | 7 ++++--- arch/x86_64/src/memory/heap/linked_list_allocator.cpp | 5 ++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index 2d76124..236d366 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -3,8 +3,6 @@ #include "arch/memory/heap/memory_block.hpp" -#include - namespace teachos::arch::memory::heap { /** @@ -59,7 +57,7 @@ namespace teachos::arch::memory::heap auto split_free_memory_block(memory_block *& current_block, std::size_t size) -> void *; auto coalesce_free_memory_block(memory_block *& previous_block, memory_block *& current_block, void * pointer, - std::size_t size) -> void *; + std::size_t size) -> void; std::size_t heap_start; ///< Start of the allocatable heap area std::size_t heap_end; ///< End of the allocatable heap area diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 7463fc4..ea18232 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -2,6 +2,7 @@ #include "arch/memory/heap/bump_allocator.hpp" #include "arch/memory/heap/concept.hpp" +#include "arch/memory/heap/linked_list_allocator.hpp" #include "arch/memory/main.hpp" #include "arch/memory/multiboot/reader.hpp" #include "arch/video/vga/text.hpp" @@ -21,8 +22,8 @@ namespace teachos::arch::kernel auto heap_test() -> void { - memory::heap::bump_allocator heap_allocator{memory::heap::HEAP_START, - memory::heap::HEAP_START + memory::heap::HEAP_SIZE}; + memory::heap::linked_list_allocator heap_allocator{memory::heap::HEAP_START, + memory::heap::HEAP_START + memory::heap::HEAP_SIZE}; auto test = heap_allocator.allocate(1024); auto test2 = new (test) memory::multiboot::memory_information{}; test = static_cast(static_cast(test) + 1); @@ -49,6 +50,6 @@ namespace teachos::arch::kernel memory::initialize_memory_management(); // stack_overflow_test(0); - // heap_test(); + heap_test(); } } // namespace teachos::arch::kernel 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 3330399..98a936c 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -90,13 +90,12 @@ namespace teachos::arch::memory::heap } auto linked_list_allocator::coalesce_free_memory_block(memory_block *& previous_block, memory_block *& current_block, - void * pointer, std::size_t size) -> void * + void * pointer, std::size_t size) -> void { auto const start_address = reinterpret_cast(pointer); auto const end_address = start_address + size; auto block_size = size; - auto new_block_address = pointer; auto next_block = current_block; // If free memory block after block to deallocate is adjacent @@ -118,7 +117,7 @@ namespace teachos::arch::memory::heap return; } - new (reinterpret_cast(new_block_address)) memory_block(block_size, next_block); + new (reinterpret_cast(pointer)) memory_block(block_size, next_block); } } // namespace teachos::arch::memory::heap -- cgit v1.2.3 From 0cf972394e99dfa69fbaf2ec9f4c718fd36bbc3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 1 Dec 2024 12:38:38 +0000 Subject: Add comments and fix edge case --- .../src/memory/heap/linked_list_allocator.cpp | 23 +++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) 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 98a936c..63a762e 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -68,6 +68,8 @@ namespace teachos::arch::memory::heap 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; @@ -95,10 +97,22 @@ namespace teachos::arch::memory::heap 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 free memory block after block to deallocate is adjacent + // Heap memory has been completly used up and therefore the inital free pointer is null and this deallocation will + // result in the first inital pointer in our linked list of free memory blocks. + if (previous_block == nullptr) + { + previous_block = new (pointer) memory_block(block_size, next_block); + return; + } + + // 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; @@ -107,7 +121,9 @@ namespace teachos::arch::memory::heap delete current_block; } - // If free memory block before block to deallocate is adjacent + // 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 (start_address == (reinterpret_cast(previous_block) + previous_block->size)) { block_size += previous_block->size; @@ -117,7 +133,8 @@ namespace teachos::arch::memory::heap return; } - new (reinterpret_cast(pointer)) memory_block(block_size, next_block); + auto const new_block = new (pointer) memory_block(block_size, next_block); + previous_block->next = new_block; } } // namespace teachos::arch::memory::heap -- cgit v1.2.3 From 9072c2a277c0da298b977cf4fb3dbebb5481abd0 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sun, 1 Dec 2024 13:34:46 +0000 Subject: implement clear_memory_block_header --- .../arch/memory/heap/linked_list_allocator.hpp | 3 +++ arch/x86_64/src/kernel/main.cpp | 8 +++++--- .../src/memory/heap/linked_list_allocator.cpp | 22 +++++++++++++++------- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index 236d366..7432561 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -59,6 +59,9 @@ namespace teachos::arch::memory::heap auto coalesce_free_memory_block(memory_block *& previous_block, memory_block *& current_block, void * pointer, std::size_t size) -> void; + // We cannot call delete, because it causes "undefined reference to `sbrk`". + auto clear_memory_block_header(void * pointer) -> void; + std::size_t heap_start; ///< Start of the allocatable heap area std::size_t heap_end; ///< End of the allocatable heap area memory_block * first; ///< First free entry in our memory diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index ea18232..a4f138c 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -26,8 +26,8 @@ namespace teachos::arch::kernel memory::heap::HEAP_START + memory::heap::HEAP_SIZE}; auto test = heap_allocator.allocate(1024); auto test2 = new (test) memory::multiboot::memory_information{}; - test = static_cast(static_cast(test) + 1); - auto test3 = new (test) memory::multiboot::memory_information{}; + auto test3 = new (static_cast(static_cast(test) + 1)) + memory::multiboot::memory_information{}; auto test4 = *test2; auto test5 = *test3; test4.kernel_end = 5000; @@ -39,6 +39,8 @@ namespace teachos::arch::kernel { video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); } + + heap_allocator.deallocate(test, 1024); } auto main() -> void @@ -50,6 +52,6 @@ namespace teachos::arch::kernel memory::initialize_memory_management(); // stack_overflow_test(0); - heap_test(); + // heap_test(); } } // namespace teachos::arch::kernel 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 63a762e..07d7e5e 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -3,6 +3,8 @@ #include "arch/exception_handling/assert.hpp" #include "arch/exception_handling/panic.hpp" +#include + #include namespace teachos::arch::memory::heap @@ -14,7 +16,7 @@ namespace teachos::arch::memory::heap { auto const heap_size = heap_end - heap_start; exception_handling::assert( - heap_size < min_allocatable_size(), + 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); @@ -22,7 +24,7 @@ namespace teachos::arch::memory::heap auto linked_list_allocator::allocate(std::size_t size) -> void * { - exception_handling::assert(size < min_allocatable_size(), + exception_handling::assert(size > min_allocatable_size(), "[Linked List Allocator] Allocated memory cannot be smaller than 16 bytes"); auto & previous = first; @@ -34,7 +36,8 @@ namespace teachos::arch::memory::heap { return split_free_memory_block(current, size); } - else if (current->size >= size) + + if (current->size >= size) { if (previous != current) { @@ -42,10 +45,10 @@ namespace teachos::arch::memory::heap } else { - current = current->next; + first = current->next; } - delete current; + clear_memory_block_header(current); return static_cast(current); } @@ -57,7 +60,7 @@ namespace teachos::arch::memory::heap auto linked_list_allocator::deallocate(void * pointer, std::size_t size) -> void { - exception_handling::assert(size < min_allocatable_size(), + exception_handling::assert(size > min_allocatable_size(), "[Linked List Allocator] Allocated memory cannot be smaller than 16 bytes"); auto const start_address = reinterpret_cast(pointer); @@ -118,7 +121,7 @@ namespace teachos::arch::memory::heap block_size += current_block->size; next_block = current_block->next; - delete current_block; + clear_memory_block_header(current_block); } // If the block we want to deallocate is behind another free block and we can therefore combine both into one. @@ -137,4 +140,9 @@ namespace teachos::arch::memory::heap previous_block->next = new_block; } + auto linked_list_allocator::clear_memory_block_header(void * pointer) -> void + { + memset(pointer, 0, min_allocatable_size()); + } + } // namespace teachos::arch::memory::heap -- cgit v1.2.3 From f880939eb5f1b5e70b15d6614cc440c09a0d9fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Sun, 1 Dec 2024 13:57:05 +0000 Subject: Add doxygen comments for linked list helper methods. --- .../arch/memory/heap/linked_list_allocator.hpp | 41 ++++++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index 7432561..71e495a 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -7,7 +7,7 @@ namespace teachos::arch::memory::heap { /** * @brief Sorted by address list of memory holes (free memory). Uses free holes itself to save the information, - * containing the size and pointer to the next hole. Resulting in a single linked list. + * containing the size and pointer to the next hole. Resulting in a singly linked list. */ struct linked_list_allocator { @@ -46,20 +46,47 @@ namespace teachos::arch::memory::heap auto constexpr min_allocatable_size() -> std::size_t { return sizeof(memory_block); } /** - * @brief Splits the given hole into two, where the latter block keeps beeing free and the first part will be used - * for the allocation. + * @brief Splits the given free memory block into two, where the latter block keeps being free and the first part + * will be used for the allocation. * - * @param current_block Hole we want to split. - * @param size Size we want to allocate at the start of the hole. + * @param current_block Free memory block we want to split. + * @param size Size we want to allocate at the start of the free memory block. * - * @return Address of the hole we just split. + * @return Previous start address of the memory block we just split. */ auto split_free_memory_block(memory_block *& current_block, std::size_t size) -> void *; + /** + * @brief Combines multiple free memory blocks into one if they are adjacent. + * + * @note The internal algorithm for recombination functions like this: + * 1. Check if there is even any memory left, if not the first entry of our linked list should be a nullptr and we + * can therefore set the first entry to our newly created entry. This entry is created in the now deallocated memory + * area. + * 2. If there are more blocks but neither the previous nor the current block are adjacent, we simply create a new + * free memory block of the given size and set the previous next to our block and the next of our block to the + * current block. + * 3. If the current block is adjacent the start address of the newly created block stays the same, but the size + * increases by the amount in the current memory block header. After reading it we also clear the header. + * 4. If the previous block is adjacent the size of the previous block simply increases to include the given size as + * well. + * + * @param previous_block Free memory block before the block to deallocate in our heap memory. + * @param current_block Free memory block after the block to deallocate in our heap memory. + * @param pointer Block to deallocate. + * @param size Size of the block we want to deallocate. + */ auto coalesce_free_memory_block(memory_block *& previous_block, memory_block *& current_block, void * pointer, std::size_t size) -> void; - // We cannot call delete, because it causes "undefined reference to `sbrk`". + /** + * @brief Clears the memory of the previous memory block header. + * + * @note Done so the given pointer can be reused to construct other classes into, without having the old values. + * Required because we cannot call delete, because it causes "undefined reference to `sbrk`". + * + * @param pointer Address we want to clear the memory block header at (16 bytes) + */ auto clear_memory_block_header(void * pointer) -> void; std::size_t heap_start; ///< Start of the allocatable heap area -- cgit v1.2.3 From a5e5eabd32872f81a7190589aa648dc0e1963888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 2 Dec 2024 10:17:36 +0000 Subject: Fix algorithm issues with linked list allocator --- .../arch/memory/heap/linked_list_allocator.hpp | 10 +++- arch/x86_64/src/kernel/main.cpp | 11 +++- .../src/memory/heap/linked_list_allocator.cpp | 64 +++++++++++----------- 3 files changed, 48 insertions(+), 37 deletions(-) diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index 71e495a..e8ecc30 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -49,12 +49,16 @@ namespace teachos::arch::memory::heap * @brief Splits the given free memory block into two, where the latter block keeps being free and the first part * will be used for the allocation. * - * @param current_block Free memory block we want to split. + * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to allocate + * the required size into. + * @param current_block Free memory block we want to split into a size part for the allocation and the rest for + * future allocations. * @param size Size we want to allocate at the start of the free memory block. * * @return Previous start address of the memory block we just split. */ - auto split_free_memory_block(memory_block *& current_block, std::size_t size) -> void *; + auto split_free_memory_block(memory_block * previous_block, memory_block * current_block, + std::size_t size) -> void *; /** * @brief Combines multiple free memory blocks into one if they are adjacent. @@ -76,7 +80,7 @@ namespace teachos::arch::memory::heap * @param pointer Block to deallocate. * @param size Size of the block we want to deallocate. */ - auto coalesce_free_memory_block(memory_block *& previous_block, memory_block *& current_block, void * pointer, + auto coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, void * pointer, std::size_t size) -> void; /** diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index a4f138c..7992b34 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -41,6 +41,15 @@ namespace teachos::arch::kernel } heap_allocator.deallocate(test, 1024); + + heap_allocator.allocate(1024); // test 9 + auto test10 = heap_allocator.allocate(1024); + auto test11 = heap_allocator.allocate(1024); + auto test12 = heap_allocator.allocate(1024); + heap_allocator.allocate(1024); // test 13 + heap_allocator.deallocate(test11, 1024); + heap_allocator.deallocate(test10, 1024); + heap_allocator.deallocate(test12, 1024); } auto main() -> void @@ -52,6 +61,6 @@ namespace teachos::arch::kernel memory::initialize_memory_management(); // stack_overflow_test(0); - // heap_test(); + heap_test(); } } // namespace teachos::arch::kernel 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 07d7e5e..706f43e 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -27,29 +27,14 @@ namespace teachos::arch::memory::heap exception_handling::assert(size > min_allocatable_size(), "[Linked List Allocator] Allocated memory cannot be smaller than 16 bytes"); - auto & previous = first; - auto & current = first; + memory_block * previous = nullptr; + auto current = first; while (current != nullptr) { if (current->size >= size + min_allocatable_size()) { - return split_free_memory_block(current, size); - } - - if (current->size >= size) - { - if (previous != current) - { - previous->next = current->next; - } - else - { - first = current->next; - } - - clear_memory_block_header(current); - return static_cast(current); + return split_free_memory_block(previous, current, size); } previous = current; @@ -66,8 +51,8 @@ namespace teachos::arch::memory::heap auto const start_address = reinterpret_cast(pointer); auto const end_address = start_address + size; - auto & previous = first; - auto & current = first; + memory_block * previous = nullptr; + auto current = first; while (current != nullptr) { @@ -78,23 +63,35 @@ namespace teachos::arch::memory::heap break; } - previous->next = current; + previous = current; current = current->next; } coalesce_free_memory_block(previous, current, pointer, size); } - auto linked_list_allocator::split_free_memory_block(memory_block *& current_block, std::size_t size) -> void * + auto linked_list_allocator::split_free_memory_block(memory_block * previous_block, memory_block * current_block, + std::size_t size) -> void * { auto const start_address = reinterpret_cast(current_block); auto const end_address = start_address + size; - current_block = + auto const new_block = new (reinterpret_cast(end_address)) memory_block(current_block->size - size, current_block->next); + // 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; + } + clear_memory_block_header(current_block); return reinterpret_cast(start_address); } - auto linked_list_allocator::coalesce_free_memory_block(memory_block *& previous_block, memory_block *& current_block, + 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); @@ -105,14 +102,6 @@ namespace teachos::arch::memory::heap auto block_size = size; auto next_block = current_block; - // Heap memory has been completly used up and therefore the inital free pointer is null and this deallocation will - // result in the first inital pointer in our linked list of free memory blocks. - if (previous_block == nullptr) - { - previous_block = new (pointer) memory_block(block_size, next_block); - return; - } - // 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. @@ -127,7 +116,8 @@ namespace teachos::arch::memory::heap // 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 (start_address == (reinterpret_cast(previous_block) + previous_block->size)) + if (previous_block != nullptr && + start_address == (reinterpret_cast(previous_block) + previous_block->size)) { block_size += previous_block->size; @@ -137,6 +127,14 @@ namespace teachos::arch::memory::heap } 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; } -- cgit v1.2.3 From aa4de534ec7bf0b609aff032c4649484aa49823c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 2 Dec 2024 11:14:43 +0000 Subject: Add check to detect double free in linked list allocator --- arch/x86_64/src/kernel/main.cpp | 3 ++- arch/x86_64/src/memory/heap/linked_list_allocator.cpp | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index 7992b34..e68f0fe 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -42,9 +42,10 @@ namespace teachos::arch::kernel heap_allocator.deallocate(test, 1024); - heap_allocator.allocate(1024); // test 9 + auto test9 = heap_allocator.allocate(1024); auto test10 = heap_allocator.allocate(1024); auto test11 = heap_allocator.allocate(1024); + heap_allocator.deallocate(test9, 1024); auto test12 = heap_allocator.allocate(1024); heap_allocator.allocate(1024); // test 13 heap_allocator.deallocate(test11, 1024); 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 706f43e..f596f27 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -126,6 +126,13 @@ namespace teachos::arch::memory::heap 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 -- cgit v1.2.3 From 37de7b3b395a4b9cdf46a8b20ce6bb6a7d481354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 2 Dec 2024 12:17:51 +0000 Subject: Finish testing (dealloc recombines correctly) --- arch/x86_64/src/kernel/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index e68f0fe..a29c947 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -39,7 +39,6 @@ namespace teachos::arch::kernel { video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); } - heap_allocator.deallocate(test, 1024); auto test9 = heap_allocator.allocate(1024); @@ -47,9 +46,10 @@ namespace teachos::arch::kernel auto test11 = heap_allocator.allocate(1024); heap_allocator.deallocate(test9, 1024); auto test12 = heap_allocator.allocate(1024); - heap_allocator.allocate(1024); // test 13 + auto test13 = heap_allocator.allocate(1024); heap_allocator.deallocate(test11, 1024); heap_allocator.deallocate(test10, 1024); + heap_allocator.deallocate(test13, 1024); heap_allocator.deallocate(test12, 1024); } -- cgit v1.2.3 From f7abde02150deacbc2ad1957e6165769cc2fea0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 2 Dec 2024 12:43:24 +0000 Subject: Add comment on extra double deallocation check --- arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index e8ecc30..6af6298 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -74,6 +74,9 @@ namespace teachos::arch::memory::heap * increases by the amount in the current memory block header. After reading it we also clear the header. * 4. If the previous block is adjacent the size of the previous block simply increases to include the given size as * well. + * 5. If the previous block is directly in our start address, so they overlap then it has to mean some or all of the + * region we are trying to deallocate has been freed before. Which would result in a double free therefore we halt + * the execution of the program. * * @param previous_block Free memory block before the block to deallocate in our heap memory. * @param current_block Free memory block after the block to deallocate in our heap memory. -- cgit v1.2.3 From dcd83b71c833e86c7e00e2b8f75ab6208b5d360d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 2 Dec 2024 13:51:58 +0000 Subject: WIP thread safe linked list --- arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp | 6 +++--- arch/x86_64/include/arch/memory/heap/memory_block.hpp | 3 ++- arch/x86_64/src/memory/heap/linked_list_allocator.cpp | 8 ++++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index 6af6298..e77602c 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -96,9 +96,9 @@ namespace teachos::arch::memory::heap */ auto clear_memory_block_header(void * pointer) -> void; - std::size_t heap_start; ///< Start of the allocatable heap area - std::size_t heap_end; ///< End of the allocatable heap area - memory_block * first; ///< First free entry in our memory + std::size_t heap_start; ///< Start of the allocatable heap area + std::size_t heap_end; ///< End of the allocatable heap area + std::atomic first; ///< First free entry in our memory }; } // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/include/arch/memory/heap/memory_block.hpp b/arch/x86_64/include/arch/memory/heap/memory_block.hpp index c48d0cd..1fbbfd5 100644 --- a/arch/x86_64/include/arch/memory/heap/memory_block.hpp +++ b/arch/x86_64/include/arch/memory/heap/memory_block.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_BLOCK_HPP #define TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_BLOCK_HPP +#include #include namespace teachos::arch::memory::heap @@ -21,7 +22,7 @@ namespace teachos::arch::memory::heap std::size_t size; ///< Amount of free memory this hole contains, has to always be atleast 16 bytes to hold the size ///< variable and the pointer to the next hole. - memory_block * next; ///< Optional pointer to the next free memory, holds nullptr if there is none. + std::atomic next; ///< Optional pointer to the next free memory, holds nullptr if there is none. }; } // namespace teachos::arch::memory::heap 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 f596f27..22b5757 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -28,7 +28,7 @@ namespace teachos::arch::memory::heap "[Linked List Allocator] Allocated memory cannot be smaller than 16 bytes"); memory_block * previous = nullptr; - auto current = first; + auto current = first.load(std::memory_order::relaxed); while (current != nullptr) { @@ -52,7 +52,7 @@ namespace teachos::arch::memory::heap auto const end_address = start_address + size; memory_block * previous = nullptr; - auto current = first; + auto current = first.load(std::memory_order::relaxed); while (current != nullptr) { @@ -81,11 +81,11 @@ namespace teachos::arch::memory::heap // free block (nullptr). Therefore we have to overwrite the first block instead of overwriting its next value. if (previous_block == nullptr) { - first = new_block; + first.compare_exchange_weak(previous_block, new_block, std::memory_order::relaxed); } else { - previous_block->next = new_block; + previous_block->next.compare_exchange_weak(current_block, new_block, std::memory_order::relaxed); } clear_memory_block_header(current_block); return reinterpret_cast(start_address); -- cgit v1.2.3 From b4962c8c7b94fce2e67a00671de87fa96fdbb659 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 3 Dec 2024 08:00:26 +0000 Subject: add mutex to linked_list_allocator --- .../arch/memory/heap/linked_list_allocator.hpp | 8 ++-- .../include/arch/memory/heap/memory_block.hpp | 3 +- arch/x86_64/include/arch/shared/mutex.hpp | 46 ++++++++++++++++++++++ .../src/memory/heap/linked_list_allocator.cpp | 14 +++++-- 4 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 arch/x86_64/include/arch/shared/mutex.hpp diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index e77602c..49217d5 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -2,6 +2,7 @@ #define TEACHOS_ARCH_X86_64_MEMORY_HEAP_LINKED_LIST_ALLOCATOR_HPP #include "arch/memory/heap/memory_block.hpp" +#include "arch/shared/mutex.hpp" namespace teachos::arch::memory::heap { @@ -96,9 +97,10 @@ namespace teachos::arch::memory::heap */ auto clear_memory_block_header(void * pointer) -> void; - std::size_t heap_start; ///< Start of the allocatable heap area - std::size_t heap_end; ///< End of the allocatable heap area - std::atomic first; ///< First free entry in our memory + std::size_t heap_start; ///< Start of the allocatable heap area + std::size_t heap_end; ///< End of the allocatable heap area + memory_block * first; ///< First free entry in our memory + shared::mutex mutex; }; } // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/include/arch/memory/heap/memory_block.hpp b/arch/x86_64/include/arch/memory/heap/memory_block.hpp index 1fbbfd5..c48d0cd 100644 --- a/arch/x86_64/include/arch/memory/heap/memory_block.hpp +++ b/arch/x86_64/include/arch/memory/heap/memory_block.hpp @@ -1,7 +1,6 @@ #ifndef TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_BLOCK_HPP #define TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_BLOCK_HPP -#include #include namespace teachos::arch::memory::heap @@ -22,7 +21,7 @@ namespace teachos::arch::memory::heap std::size_t size; ///< Amount of free memory this hole contains, has to always be atleast 16 bytes to hold the size ///< variable and the pointer to the next hole. - std::atomic next; ///< Optional pointer to the next free memory, holds nullptr if there is none. + memory_block * next; ///< Optional pointer to the next free memory, holds nullptr if there is none. }; } // namespace teachos::arch::memory::heap diff --git a/arch/x86_64/include/arch/shared/mutex.hpp b/arch/x86_64/include/arch/shared/mutex.hpp new file mode 100644 index 0000000..d874dd8 --- /dev/null +++ b/arch/x86_64/include/arch/shared/mutex.hpp @@ -0,0 +1,46 @@ +#ifndef TEACHOS_ARCH_X86_64_MUTEX_HPP +#define TEACHOS_ARCH_X86_64_MUTEX_HPP + +#include + +namespace teachos::arch::shared +{ + struct mutex + { + mutex() = default; + ~mutex() = default; + + mutex(const mutex &) = delete; + mutex & operator=(const mutex &) = delete; + + /** + * @brief Lock the mutex (blocks if not available) + */ + void lock() + { + while (true) + { + if (!locked.exchange(true, std::memory_order_acquire)) + { + return; + } + } + } + + /** + * @brief Try to lock the mutex (non-blocking) + * + * @return true if lock has been acquired and false otherwise + */ + bool try_lock() { return !locked.exchange(true, std::memory_order_acquire); } + + /** + * @brief Unlock the mutex + */ + void unlock() { locked.store(false, std::memory_order_release); } + + private: + std::atomic locked{false}; + }; +} // namespace teachos::arch::shared +#endif // TEACHOS_ARCH_X86_64_MUTEX_HPP \ No newline at end of file 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 22b5757..01838f9 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -13,6 +13,7 @@ namespace teachos::arch::memory::heap : heap_start(heap_start) , heap_end(heap_end) , first(nullptr) + , mutex{shared::mutex{}} { auto const heap_size = heap_end - heap_start; exception_handling::assert( @@ -26,9 +27,10 @@ namespace teachos::arch::memory::heap { exception_handling::assert(size > min_allocatable_size(), "[Linked List Allocator] Allocated memory cannot be smaller than 16 bytes"); + mutex.lock(); memory_block * previous = nullptr; - auto current = first.load(std::memory_order::relaxed); + auto current = first; while (current != nullptr) { @@ -40,6 +42,8 @@ namespace teachos::arch::memory::heap previous = current; current = current->next; } + + mutex.unlock(); exception_handling::panic("[Linked List Allocator] Out of memory"); } @@ -47,12 +51,13 @@ namespace teachos::arch::memory::heap { exception_handling::assert(size > min_allocatable_size(), "[Linked List Allocator] Allocated memory cannot be smaller than 16 bytes"); + mutex.lock(); auto const start_address = reinterpret_cast(pointer); auto const end_address = start_address + size; memory_block * previous = nullptr; - auto current = first.load(std::memory_order::relaxed); + auto current = first; while (current != nullptr) { @@ -68,6 +73,7 @@ namespace teachos::arch::memory::heap } coalesce_free_memory_block(previous, current, pointer, size); + mutex.unlock(); } auto linked_list_allocator::split_free_memory_block(memory_block * previous_block, memory_block * current_block, @@ -81,11 +87,11 @@ namespace teachos::arch::memory::heap // free block (nullptr). Therefore we have to overwrite the first block instead of overwriting its next value. if (previous_block == nullptr) { - first.compare_exchange_weak(previous_block, new_block, std::memory_order::relaxed); + first = new_block; } else { - previous_block->next.compare_exchange_weak(current_block, new_block, std::memory_order::relaxed); + previous_block = new_block; } clear_memory_block_header(current_block); return reinterpret_cast(start_address); -- cgit v1.2.3 From 4f7ea612982a9ee83023e43724ff53f8dce65fe0 Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 3 Dec 2024 08:06:40 +0000 Subject: improve mutex file structure --- arch/x86_64/CMakeLists.txt | 1 + arch/x86_64/include/arch/shared/mutex.hpp | 15 +++------------ arch/x86_64/src/shared/mutex.cpp | 27 +++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 arch/x86_64/src/shared/mutex.cpp diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 4a02e15..c5624d8 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -59,6 +59,7 @@ target_sources("_memory" PRIVATE "src/memory/heap/bump_allocator.cpp" "src/memory/heap/memory_block.cpp" "src/memory/heap/linked_list_allocator.cpp" + "src/shared/mutex.cpp" ) #[============================================================================[ diff --git a/arch/x86_64/include/arch/shared/mutex.hpp b/arch/x86_64/include/arch/shared/mutex.hpp index d874dd8..36a4623 100644 --- a/arch/x86_64/include/arch/shared/mutex.hpp +++ b/arch/x86_64/include/arch/shared/mutex.hpp @@ -16,28 +16,19 @@ namespace teachos::arch::shared /** * @brief Lock the mutex (blocks if not available) */ - void lock() - { - while (true) - { - if (!locked.exchange(true, std::memory_order_acquire)) - { - return; - } - } - } + auto lock() -> void; /** * @brief Try to lock the mutex (non-blocking) * * @return true if lock has been acquired and false otherwise */ - bool try_lock() { return !locked.exchange(true, std::memory_order_acquire); } + auto try_lock() -> bool; /** * @brief Unlock the mutex */ - void unlock() { locked.store(false, std::memory_order_release); } + auto unlock() -> void; private: std::atomic locked{false}; diff --git a/arch/x86_64/src/shared/mutex.cpp b/arch/x86_64/src/shared/mutex.cpp new file mode 100644 index 0000000..65cd095 --- /dev/null +++ b/arch/x86_64/src/shared/mutex.cpp @@ -0,0 +1,27 @@ +#include "arch/shared/mutex.hpp" + +namespace teachos::arch::shared +{ + auto mutex::lock() -> void + { + while (true) + { + if (!locked.exchange(true, std::memory_order_acquire)) + { + return; + } + } + } + + /** + * @brief Try to lock the mutex (non-blocking) + * + * @return true if lock has been acquired and false otherwise + */ + auto mutex::try_lock() -> bool { return !locked.exchange(true, std::memory_order_acquire); } + + /** + * @brief Unlock the mutex + */ + auto mutex::unlock() -> void { locked.store(false, std::memory_order_release); } +} // namespace teachos::arch::shared \ No newline at end of file -- cgit v1.2.3 From 45e36abbd404ba0c4137d0b989f3774af9ac9e3c Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 3 Dec 2024 08:10:33 +0000 Subject: fix linked_list_allocator mutex usage --- arch/x86_64/src/memory/heap/linked_list_allocator.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 01838f9..1c5c443 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -36,14 +36,15 @@ namespace teachos::arch::memory::heap { if (current->size >= size + min_allocatable_size()) { - return split_free_memory_block(previous, current, size); + auto memory_address = split_free_memory_block(previous, current, size); + mutex.unlock(); + return memory_address; } previous = current; current = current->next; } - mutex.unlock(); exception_handling::panic("[Linked List Allocator] Out of memory"); } -- cgit v1.2.3 From e6da0a1b12a3e777bd54e4b22b6a873a4c5fe195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 3 Dec 2024 08:19:24 +0000 Subject: Add allocate case where size fits exactly --- .../arch/memory/heap/linked_list_allocator.hpp | 40 +++++++++++++++++----- .../src/memory/heap/linked_list_allocator.cpp | 26 ++++++++++++-- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index 49217d5..4ccc6a9 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -23,6 +23,15 @@ namespace teachos::arch::memory::heap /** * @brief Allocates the specified amount of memory in the heap. * + * @note The specified size is used to find a free memory block with the exact same size, meaning we can remove that + * free memory block from the free list and simply return its address. Or it has to be big enough to hold the size + * and alteast enough memory for another free memory block entry (16 bytes). If the amount of memory of that free + * memory block is in between we cannot use it for our allocation, because we could only return it to the user, but + * the additional bytes, could not be used to create a free memory block. Additionaly the user couldn't know + * they received more memory than wanted. Therefore the memory would simply be unused and because it is neither + * allocated nor deallocated would never be indexed by the free memory list. We would therefore permanently loose + * that memory, to prevent that allocation into free memory blocks like that are impossible. + * * @param size Amount of memory to allocate. * @return Address of the first byte to the allocated area */ @@ -47,11 +56,24 @@ namespace teachos::arch::memory::heap auto constexpr min_allocatable_size() -> std::size_t { return sizeof(memory_block); } /** - * @brief Splits the given free memory block into two, where the latter block keeps being free and the first part - * will be used for the allocation. + * @brief Removes a free memory block from the free list and returns its address so the caller can allocate into it. + * + * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to + * allocate the required size into. + * @param current_block Free memory block we want to remove from the free list and return for the allocation. + * @param size Size we want to allocate that is exactly the same as the size of the curernt block + * + * @return Previous start address of the memory block we removed, because it has the exact required size. + */ + auto remove_free_memory_block(memory_block * previous_block, memory_block * current_block, + std::size_t size) -> void *; + + /** + * @brief Splits the given free memory block into two, where the latter block keeps being free and the first + * part will be used for the allocation. * - * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to allocate - * the required size into. + * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to + * allocate the required size into. * @param current_block Free memory block we want to split into a size part for the allocation and the rest for * future allocations. * @param size Size we want to allocate at the start of the free memory block. @@ -93,14 +115,14 @@ namespace teachos::arch::memory::heap * @note Done so the given pointer can be reused to construct other classes into, without having the old values. * Required because we cannot call delete, because it causes "undefined reference to `sbrk`". * - * @param pointer Address we want to clear the memory block header at (16 bytes) + * @param pointer Address we want to clear the memory block header at (16 bytes). */ auto clear_memory_block_header(void * pointer) -> void; - std::size_t heap_start; ///< Start of the allocatable heap area - std::size_t heap_end; ///< End of the allocatable heap area - memory_block * first; ///< First free entry in our memory - shared::mutex mutex; + std::size_t heap_start; ///< Start of the allocatable heap area. + std::size_t heap_end; ///< End of the allocatable heap area. + memory_block * first; ///< First free entry in our memory. + shared::mutex mutex; ///< Mutex to ensure only one thread calls allocate or deallocate at once. }; } // namespace teachos::arch::memory::heap 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 1c5c443..d922dc8 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -34,7 +34,11 @@ namespace teachos::arch::memory::heap while (current != nullptr) { - if (current->size >= size + min_allocatable_size()) + if (current->size == size) + { + return remove_free_memory_block(previous, current, size); + } + else if (current->size >= size + min_allocatable_size()) { auto memory_address = split_free_memory_block(previous, current, size); mutex.unlock(); @@ -77,6 +81,24 @@ namespace teachos::arch::memory::heap mutex.unlock(); } + auto linked_list_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block, + std::size_t size) -> 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 = nullptr; + } + else + { + previous_block->next = current_block->next; + } + clear_memory_block_header(current_block); + return reinterpret_cast(start_address); + } + auto linked_list_allocator::split_free_memory_block(memory_block * previous_block, memory_block * current_block, std::size_t size) -> void * { @@ -92,7 +114,7 @@ namespace teachos::arch::memory::heap } else { - previous_block = new_block; + previous_block->next = new_block; } clear_memory_block_header(current_block); return reinterpret_cast(start_address); -- cgit v1.2.3 From 23526b8d10cf41ad5598928bf2bf3264539d497f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 3 Dec 2024 08:41:59 +0000 Subject: Add missing comments --- .../arch/memory/heap/linked_list_allocator.hpp | 44 ++++++++++++++-------- arch/x86_64/include/arch/shared/mutex.hpp | 28 +++++++++++--- .../src/memory/heap/linked_list_allocator.cpp | 30 ++++++--------- 3 files changed, 63 insertions(+), 39 deletions(-) diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index 4ccc6a9..5ff13ca 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -61,12 +61,10 @@ namespace teachos::arch::memory::heap * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to * allocate the required size into. * @param current_block Free memory block we want to remove from the free list and return for the allocation. - * @param size Size we want to allocate that is exactly the same as the size of the curernt block * - * @return Previous start address of the memory block we removed, because it has the exact required size. + * @return Previous start address of the memory block we removed, because it can now be used for the allocation. */ - auto remove_free_memory_block(memory_block * previous_block, memory_block * current_block, - std::size_t size) -> void *; + auto remove_free_memory_block(memory_block * previous_block, memory_block * current_block) -> void *; /** * @brief Splits the given free memory block into two, where the latter block keeps being free and the first @@ -78,28 +76,42 @@ namespace teachos::arch::memory::heap * future allocations. * @param size Size we want to allocate at the start of the free memory block. * - * @return Previous start address of the memory block we just split. + * @return Previous start address of the memory block we just split, because it can now be used for the allocation. */ auto split_free_memory_block(memory_block * previous_block, memory_block * current_block, std::size_t size) -> void *; + /** + * @brief Removes a free memory block from the free list and returns its address so the caller can allocate into it. + * + * @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to + * allocate the required size into. + * @param current_block Free memory block we want to remove from the free list and return for the allocation. + * @param new_block Replaces the current block with the given new block can be nullptr, meaning the free list will + * end here. + * + * @return Previous start address of the memory block we removed, because it can now be used for the allocation. + */ + auto replace_free_memory_block(memory_block * previous_block, memory_block * current_block, + memory_block * new_block) -> void *; + /** * @brief Combines multiple free memory blocks into one if they are adjacent. * * @note The internal algorithm for recombination functions like this: - * 1. Check if there is even any memory left, if not the first entry of our linked list should be a nullptr and we - * can therefore set the first entry to our newly created entry. This entry is created in the now deallocated memory - * area. - * 2. If there are more blocks but neither the previous nor the current block are adjacent, we simply create a new - * free memory block of the given size and set the previous next to our block and the next of our block to the - * current block. + * 1. Check if there is even any memory left, if not the first entry of our linked list should be a nullptr and + * we can therefore set the first entry to our newly created entry. This entry is created in the now deallocated + * memory area. + * 2. If there are more blocks but neither the previous nor the current block are adjacent, we simply create a + * new free memory block of the given size and set the previous next to our block and the next of our block to + * the current block. * 3. If the current block is adjacent the start address of the newly created block stays the same, but the size * increases by the amount in the current memory block header. After reading it we also clear the header. - * 4. If the previous block is adjacent the size of the previous block simply increases to include the given size as - * well. - * 5. If the previous block is directly in our start address, so they overlap then it has to mean some or all of the - * region we are trying to deallocate has been freed before. Which would result in a double free therefore we halt - * the execution of the program. + * 4. If the previous block is adjacent the size of the previous block simply increases to include the given + * size as well. + * 5. If the previous block is directly in our start address, so they overlap then it has to mean some or all of + * the region we are trying to deallocate has been freed before. Which would result in a double free therefore + * we halt the execution of the program. * * @param previous_block Free memory block before the block to deallocate in our heap memory. * @param current_block Free memory block after the block to deallocate in our heap memory. diff --git a/arch/x86_64/include/arch/shared/mutex.hpp b/arch/x86_64/include/arch/shared/mutex.hpp index 36a4623..ecd4490 100644 --- a/arch/x86_64/include/arch/shared/mutex.hpp +++ b/arch/x86_64/include/arch/shared/mutex.hpp @@ -5,33 +5,51 @@ namespace teachos::arch::shared { + /** + * @brief Custom mutex implementation, that simply wraps an atomic boolean to keep track if the mutex is already in + * use by another thread or not. + */ struct mutex { + /** + * @brief Defaulted constructor. + */ mutex() = default; + + /** + * @brief Defaulted destructor. + */ ~mutex() = default; + /** + * @brief Deleted copy constructor. + */ mutex(const mutex &) = delete; + + /** + * @brief Deleted assignment operator. + */ mutex & operator=(const mutex &) = delete; /** - * @brief Lock the mutex (blocks if not available) + * @brief Lock the mutex (blocks for as long as it is not available). */ auto lock() -> void; /** - * @brief Try to lock the mutex (non-blocking) + * @brief Try to lock the mutex (non-blocking). * - * @return true if lock has been acquired and false otherwise + * @return True if lock has been acquired and false otherwise. */ auto try_lock() -> bool; /** - * @brief Unlock the mutex + * @brief Unlock the mutex. */ auto unlock() -> void; private: - std::atomic locked{false}; + std::atomic locked = {false}; // Atomic boolean to track if mutex is locked or not. }; } // namespace teachos::arch::shared #endif // TEACHOS_ARCH_X86_64_MUTEX_HPP \ No newline at end of file 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 d922dc8..6600c6e 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -36,7 +36,7 @@ namespace teachos::arch::memory::heap { if (current->size == size) { - return remove_free_memory_block(previous, current, size); + return remove_free_memory_block(previous, current); } else if (current->size >= size + min_allocatable_size()) { @@ -81,31 +81,25 @@ namespace teachos::arch::memory::heap mutex.unlock(); } - auto linked_list_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block, - std::size_t size) -> void * + auto linked_list_allocator::remove_free_memory_block(memory_block * previous_block, + memory_block * current_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 = nullptr; - } - else - { - previous_block->next = current_block->next; - } - clear_memory_block_header(current_block); - return reinterpret_cast(start_address); + 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 start_address = reinterpret_cast(current_block); - auto const end_address = start_address + size; + 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) -- cgit v1.2.3 From 0a531eaa43cdd6ab15e60da2f4b203505265f5c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 3 Dec 2024 08:47:13 +0000 Subject: Fix missing mutex unlock --- arch/x86_64/src/memory/heap/linked_list_allocator.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 6600c6e..d0bf8e6 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -36,11 +36,13 @@ namespace teachos::arch::memory::heap { if (current->size == size) { - return remove_free_memory_block(previous, current); + auto const memory_address = remove_free_memory_block(previous, current); + mutex.unlock(); + return memory_address; } else if (current->size >= size + min_allocatable_size()) { - auto memory_address = split_free_memory_block(previous, current, size); + auto const memory_address = split_free_memory_block(previous, current, size); mutex.unlock(); return memory_address; } -- cgit v1.2.3 From 6dff0ff5bcdd63de4a68f9c361acd0bace39b5ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 3 Dec 2024 08:52:59 +0000 Subject: Fix minor typos in mutex --- arch/x86_64/include/arch/shared/mutex.hpp | 7 ++++--- arch/x86_64/src/shared/mutex.cpp | 17 +++-------------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/arch/x86_64/include/arch/shared/mutex.hpp b/arch/x86_64/include/arch/shared/mutex.hpp index ecd4490..33e9e17 100644 --- a/arch/x86_64/include/arch/shared/mutex.hpp +++ b/arch/x86_64/include/arch/shared/mutex.hpp @@ -1,5 +1,5 @@ -#ifndef TEACHOS_ARCH_X86_64_MUTEX_HPP -#define TEACHOS_ARCH_X86_64_MUTEX_HPP +#ifndef TEACHOS_ARCH_X86_64_SHARED_MUTEX_HPP +#define TEACHOS_ARCH_X86_64_SHARED_MUTEX_HPP #include @@ -52,4 +52,5 @@ namespace teachos::arch::shared std::atomic locked = {false}; // Atomic boolean to track if mutex is locked or not. }; } // namespace teachos::arch::shared -#endif // TEACHOS_ARCH_X86_64_MUTEX_HPP \ No newline at end of file + +#endif // TEACHOS_ARCH_X86_64_SHARED_MUTEX_HPP diff --git a/arch/x86_64/src/shared/mutex.cpp b/arch/x86_64/src/shared/mutex.cpp index 65cd095..6598255 100644 --- a/arch/x86_64/src/shared/mutex.cpp +++ b/arch/x86_64/src/shared/mutex.cpp @@ -4,24 +4,13 @@ namespace teachos::arch::shared { auto mutex::lock() -> void { - while (true) + while (!try_lock()) { - if (!locked.exchange(true, std::memory_order_acquire)) - { - return; - } + // Nothing to do } } - /** - * @brief Try to lock the mutex (non-blocking) - * - * @return true if lock has been acquired and false otherwise - */ auto mutex::try_lock() -> bool { return !locked.exchange(true, std::memory_order_acquire); } - /** - * @brief Unlock the mutex - */ auto mutex::unlock() -> void { locked.store(false, std::memory_order_release); } -} // namespace teachos::arch::shared \ No newline at end of file +} // namespace teachos::arch::shared -- cgit v1.2.3 From 05fe50cefb12a7333a320a3d101dccdd13b8034a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 3 Dec 2024 09:13:53 +0000 Subject: Clear old memory in contructor --- .../include/arch/memory/heap/linked_list_allocator.hpp | 10 ---------- arch/x86_64/include/arch/memory/heap/memory_block.hpp | 15 ++++++++++++--- arch/x86_64/src/memory/heap/linked_list_allocator.cpp | 14 ++------------ arch/x86_64/src/memory/heap/memory_block.cpp | 10 +++++++--- 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index 5ff13ca..03b8828 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -121,16 +121,6 @@ namespace teachos::arch::memory::heap auto coalesce_free_memory_block(memory_block * previous_block, memory_block * current_block, void * pointer, std::size_t size) -> void; - /** - * @brief Clears the memory of the previous memory block header. - * - * @note Done so the given pointer can be reused to construct other classes into, without having the old values. - * Required because we cannot call delete, because it causes "undefined reference to `sbrk`". - * - * @param pointer Address we want to clear the memory block header at (16 bytes). - */ - auto clear_memory_block_header(void * pointer) -> void; - std::size_t heap_start; ///< Start of the allocatable heap area. std::size_t heap_end; ///< End of the allocatable heap area. memory_block * first; ///< First free entry in our memory. diff --git a/arch/x86_64/include/arch/memory/heap/memory_block.hpp b/arch/x86_64/include/arch/memory/heap/memory_block.hpp index c48d0cd..c62dd57 100644 --- a/arch/x86_64/include/arch/memory/heap/memory_block.hpp +++ b/arch/x86_64/include/arch/memory/heap/memory_block.hpp @@ -12,15 +12,24 @@ namespace teachos::arch::memory::heap struct memory_block { /** - * @brief Constructor, + * @brief Constructor. Clears all memory from the place it was allocated until the end (address + + * size). * * @param size Amount of free memory of this specific hole. * @param next Optional pointer to the next free memory. */ memory_block(std::size_t size, memory_block * next); - std::size_t size; ///< Amount of free memory this hole contains, has to always be atleast 16 bytes to hold the size - ///< variable and the pointer to the next hole. + /** + * @brief Destructor. Clears all internal memory. + * + * @note Used so the memory can be reused to construct other classes into, without having the old values. + * Required because we cannot call delete, because it causes "undefined reference to `sbrk`". + */ + ~memory_block(); + + std::size_t size; ///< Amount of free memory this hole contains, has to always be atleast 16 bytes to hold the + ///< size variable and the pointer to the next hole. memory_block * next; ///< Optional pointer to the next free memory, holds nullptr if there is none. }; } // namespace teachos::arch::memory::heap 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 d0bf8e6..e5bae21 100644 --- a/arch/x86_64/src/memory/heap/linked_list_allocator.cpp +++ b/arch/x86_64/src/memory/heap/linked_list_allocator.cpp @@ -3,10 +3,6 @@ #include "arch/exception_handling/assert.hpp" #include "arch/exception_handling/panic.hpp" -#include - -#include - namespace teachos::arch::memory::heap { linked_list_allocator::linked_list_allocator(std::size_t heap_start, std::size_t heap_end) @@ -112,7 +108,7 @@ namespace teachos::arch::memory::heap { previous_block->next = new_block; } - clear_memory_block_header(current_block); + current_block->~memory_block(); return reinterpret_cast(start_address); } @@ -134,8 +130,7 @@ namespace teachos::arch::memory::heap { block_size += current_block->size; next_block = current_block->next; - - clear_memory_block_header(current_block); + current_block->~memory_block(); } // If the block we want to deallocate is behind another free block and we can therefore combine both into one. @@ -170,9 +165,4 @@ namespace teachos::arch::memory::heap previous_block->next = new_block; } - auto linked_list_allocator::clear_memory_block_header(void * pointer) -> void - { - memset(pointer, 0, min_allocatable_size()); - } - } // 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 index b68dd6d..446cd96 100644 --- a/arch/x86_64/src/memory/heap/memory_block.cpp +++ b/arch/x86_64/src/memory/heap/memory_block.cpp @@ -1,11 +1,15 @@ #include "arch/memory/heap/memory_block.hpp" +#include + namespace teachos::arch::memory::heap { memory_block::memory_block(std::size_t size, memory_block * next) - : size(size) - , next(next) { - // Nothing to do + memset(static_cast(this), 0, size); + this->size = size; + this->next = next; } + + memory_block::~memory_block() { memset(static_cast(this), 0, sizeof(memory_block)); } } // namespace teachos::arch::memory::heap -- cgit v1.2.3 From 888ae9e053973125551729ff787b8f3c4cf4e1be Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Tue, 3 Dec 2024 09:15:46 +0000 Subject: add additional tests to heap_test --- arch/x86_64/src/kernel/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index a29c947..c0fcc27 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -39,6 +39,9 @@ namespace teachos::arch::kernel { video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); } + test2->kernel_end = 2000; + test2->kernel_start = 1000; + test2->multiboot_start = 2000; heap_allocator.deallocate(test, 1024); auto test9 = heap_allocator.allocate(1024); -- cgit v1.2.3 From 82bd19117313e6d61ab2ac03583e22b8a627f14a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 4 Dec 2024 15:32:19 +0000 Subject: Add doxygen docs file --- arch/x86_64/include/arch/boot/pointers.hpp | 3 +++ docs/arch/x86_64/boot.rst | 9 +++++++++ docs/arch/x86_64/boot/pointers.rst | 5 +++++ docs/arch/x86_64/exception_handling.rst | 9 +++++++++ docs/arch/x86_64/exception_handling/assert.rst | 5 +++++ docs/arch/x86_64/exception_handling/panic.rst | 5 +++++ docs/arch/x86_64/kernel.rst | 9 +++++++++ docs/arch/x86_64/kernel/halt.rst | 5 +++++ docs/arch/x86_64/kernel/main.rst | 5 +++++ docs/arch/x86_64/memory.rst | 9 +++++++++ docs/arch/x86_64/memory/allocator.rst | 9 +++++++++ docs/arch/x86_64/memory/allocator/area_frame_allocator.rst | 5 +++++ docs/arch/x86_64/memory/allocator/concept.rst | 5 +++++ docs/arch/x86_64/memory/allocator/physical_frame.rst | 5 +++++ docs/arch/x86_64/memory/allocator/tiny_frame_allocator.rst | 5 +++++ docs/arch/x86_64/memory/cpu.rst | 9 +++++++++ docs/arch/x86_64/memory/cpu/control_register.rst | 5 +++++ docs/arch/x86_64/memory/cpu/msr.rst | 5 +++++ docs/arch/x86_64/memory/cpu/tlb.rst | 5 +++++ docs/arch/x86_64/memory/heap.rst | 9 +++++++++ docs/arch/x86_64/memory/heap/bump_allocator.rst | 5 +++++ docs/arch/x86_64/memory/heap/concept.rst | 5 +++++ docs/arch/x86_64/memory/heap/linked_list_allocator.rst | 5 +++++ docs/arch/x86_64/memory/heap/memory_block.rst | 5 +++++ docs/arch/x86_64/memory/main.rst | 5 +++++ docs/arch/x86_64/memory/multiboot.rst | 9 +++++++++ docs/arch/x86_64/memory/multiboot/elf_symbols_section.rst | 5 +++++ docs/arch/x86_64/memory/multiboot/info.rst | 5 +++++ docs/arch/x86_64/memory/multiboot/memory_map.rst | 5 +++++ docs/arch/x86_64/memory/multiboot/reader.rst | 5 +++++ docs/arch/x86_64/memory/paging.rst | 9 +++++++++ docs/arch/x86_64/memory/paging/active_page_table.rst | 5 +++++ docs/arch/x86_64/memory/paging/inactive_page_table.rst | 5 +++++ docs/arch/x86_64/memory/paging/kernel_mapper.rst | 5 +++++ docs/arch/x86_64/memory/paging/page_entry.rst | 5 +++++ docs/arch/x86_64/memory/paging/page_table.rst | 5 +++++ docs/arch/x86_64/memory/paging/temporary_page.rst | 5 +++++ docs/arch/x86_64/memory/paging/virtual_page.rst | 5 +++++ docs/arch/x86_64/shared.rst | 9 +++++++++ docs/arch/x86_64/shared/container.rst | 5 +++++ docs/arch/x86_64/shared/contiguous_pointer_iterator.rst | 5 +++++ docs/arch/x86_64/shared/forward_value_iterator.rst | 5 +++++ docs/arch/x86_64/shared/mutex.rst | 5 +++++ 43 files changed, 253 insertions(+) create mode 100644 docs/arch/x86_64/boot.rst create mode 100644 docs/arch/x86_64/boot/pointers.rst create mode 100644 docs/arch/x86_64/exception_handling.rst create mode 100644 docs/arch/x86_64/exception_handling/assert.rst create mode 100644 docs/arch/x86_64/exception_handling/panic.rst create mode 100644 docs/arch/x86_64/kernel.rst create mode 100644 docs/arch/x86_64/kernel/halt.rst create mode 100644 docs/arch/x86_64/kernel/main.rst create mode 100644 docs/arch/x86_64/memory.rst create mode 100644 docs/arch/x86_64/memory/allocator.rst create mode 100644 docs/arch/x86_64/memory/allocator/area_frame_allocator.rst create mode 100644 docs/arch/x86_64/memory/allocator/concept.rst create mode 100644 docs/arch/x86_64/memory/allocator/physical_frame.rst create mode 100644 docs/arch/x86_64/memory/allocator/tiny_frame_allocator.rst create mode 100644 docs/arch/x86_64/memory/cpu.rst create mode 100644 docs/arch/x86_64/memory/cpu/control_register.rst create mode 100644 docs/arch/x86_64/memory/cpu/msr.rst create mode 100644 docs/arch/x86_64/memory/cpu/tlb.rst create mode 100644 docs/arch/x86_64/memory/heap.rst create mode 100644 docs/arch/x86_64/memory/heap/bump_allocator.rst create mode 100644 docs/arch/x86_64/memory/heap/concept.rst create mode 100644 docs/arch/x86_64/memory/heap/linked_list_allocator.rst create mode 100644 docs/arch/x86_64/memory/heap/memory_block.rst create mode 100644 docs/arch/x86_64/memory/main.rst create mode 100644 docs/arch/x86_64/memory/multiboot.rst create mode 100644 docs/arch/x86_64/memory/multiboot/elf_symbols_section.rst create mode 100644 docs/arch/x86_64/memory/multiboot/info.rst create mode 100644 docs/arch/x86_64/memory/multiboot/memory_map.rst create mode 100644 docs/arch/x86_64/memory/multiboot/reader.rst create mode 100644 docs/arch/x86_64/memory/paging.rst create mode 100644 docs/arch/x86_64/memory/paging/active_page_table.rst create mode 100644 docs/arch/x86_64/memory/paging/inactive_page_table.rst create mode 100644 docs/arch/x86_64/memory/paging/kernel_mapper.rst create mode 100644 docs/arch/x86_64/memory/paging/page_entry.rst create mode 100644 docs/arch/x86_64/memory/paging/page_table.rst create mode 100644 docs/arch/x86_64/memory/paging/temporary_page.rst create mode 100644 docs/arch/x86_64/memory/paging/virtual_page.rst create mode 100644 docs/arch/x86_64/shared.rst create mode 100644 docs/arch/x86_64/shared/container.rst create mode 100644 docs/arch/x86_64/shared/contiguous_pointer_iterator.rst create mode 100644 docs/arch/x86_64/shared/forward_value_iterator.rst create mode 100644 docs/arch/x86_64/shared/mutex.rst diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index 1172443..29cc3cf 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -5,6 +5,9 @@ namespace teachos::arch::boot { + /** + * @brief Address pointing to the start of the multiboot information structure. + */ extern "C" size_t const multiboot_information_pointer; } // namespace teachos::arch::boot diff --git a/docs/arch/x86_64/boot.rst b/docs/arch/x86_64/boot.rst new file mode 100644 index 0000000..8be2a57 --- /dev/null +++ b/docs/arch/x86_64/boot.rst @@ -0,0 +1,9 @@ +Boot Information Subsystem +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + boot/* \ No newline at end of file diff --git a/docs/arch/x86_64/boot/pointers.rst b/docs/arch/x86_64/boot/pointers.rst new file mode 100644 index 0000000..3ec626a --- /dev/null +++ b/docs/arch/x86_64/boot/pointers.rst @@ -0,0 +1,5 @@ +Boot Information Structure +======================= + +.. doxygenfile:: arch/x86_64/include/arch/boot/pointers.hpp + diff --git a/docs/arch/x86_64/exception_handling.rst b/docs/arch/x86_64/exception_handling.rst new file mode 100644 index 0000000..3bf2770 --- /dev/null +++ b/docs/arch/x86_64/exception_handling.rst @@ -0,0 +1,9 @@ +Exception Handling Subsystem +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + exception_handling/* \ No newline at end of file diff --git a/docs/arch/x86_64/exception_handling/assert.rst b/docs/arch/x86_64/exception_handling/assert.rst new file mode 100644 index 0000000..053cf66 --- /dev/null +++ b/docs/arch/x86_64/exception_handling/assert.rst @@ -0,0 +1,5 @@ +Exception Handling Assertion +======================= + +.. doxygenfile:: arch/x86_64/include/arch/exception_handling/assert.hpp + diff --git a/docs/arch/x86_64/exception_handling/panic.rst b/docs/arch/x86_64/exception_handling/panic.rst new file mode 100644 index 0000000..50b6284 --- /dev/null +++ b/docs/arch/x86_64/exception_handling/panic.rst @@ -0,0 +1,5 @@ +Exception Handling Panic +======================= + +.. doxygenfile:: arch/x86_64/include/arch/exception_handling/panic.hpp + diff --git a/docs/arch/x86_64/kernel.rst b/docs/arch/x86_64/kernel.rst new file mode 100644 index 0000000..650e3a6 --- /dev/null +++ b/docs/arch/x86_64/kernel.rst @@ -0,0 +1,9 @@ +Kernel Main Subsystem +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + kernel/* \ No newline at end of file diff --git a/docs/arch/x86_64/kernel/halt.rst b/docs/arch/x86_64/kernel/halt.rst new file mode 100644 index 0000000..c425e81 --- /dev/null +++ b/docs/arch/x86_64/kernel/halt.rst @@ -0,0 +1,5 @@ +Kernel Halt +======================= + +.. doxygenfile:: arch/x86_64/include/arch/kernel/halt.hpp + diff --git a/docs/arch/x86_64/kernel/main.rst b/docs/arch/x86_64/kernel/main.rst new file mode 100644 index 0000000..194bd85 --- /dev/null +++ b/docs/arch/x86_64/kernel/main.rst @@ -0,0 +1,5 @@ +Kernel Main +======================= + +.. doxygenfile:: arch/x86_64/include/arch/kernel/main.hpp + diff --git a/docs/arch/x86_64/memory.rst b/docs/arch/x86_64/memory.rst new file mode 100644 index 0000000..58d12e9 --- /dev/null +++ b/docs/arch/x86_64/memory.rst @@ -0,0 +1,9 @@ +Kernel Memory Subsystem +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + memory/* \ No newline at end of file diff --git a/docs/arch/x86_64/memory/allocator.rst b/docs/arch/x86_64/memory/allocator.rst new file mode 100644 index 0000000..6ce0a74 --- /dev/null +++ b/docs/arch/x86_64/memory/allocator.rst @@ -0,0 +1,9 @@ +Physical Frame Allocator Subsystem +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + allocator/* diff --git a/docs/arch/x86_64/memory/allocator/area_frame_allocator.rst b/docs/arch/x86_64/memory/allocator/area_frame_allocator.rst new file mode 100644 index 0000000..422f33c --- /dev/null +++ b/docs/arch/x86_64/memory/allocator/area_frame_allocator.rst @@ -0,0 +1,5 @@ +Area Physical Frame Allocator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp + diff --git a/docs/arch/x86_64/memory/allocator/concept.rst b/docs/arch/x86_64/memory/allocator/concept.rst new file mode 100644 index 0000000..734a2ce --- /dev/null +++ b/docs/arch/x86_64/memory/allocator/concept.rst @@ -0,0 +1,5 @@ +Physical Frame Allocator Concept +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/allocator/concept.hpp + diff --git a/docs/arch/x86_64/memory/allocator/physical_frame.rst b/docs/arch/x86_64/memory/allocator/physical_frame.rst new file mode 100644 index 0000000..c5d0fd2 --- /dev/null +++ b/docs/arch/x86_64/memory/allocator/physical_frame.rst @@ -0,0 +1,5 @@ +Physical Frame +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/allocator/physical_frame.hpp + diff --git a/docs/arch/x86_64/memory/allocator/tiny_frame_allocator.rst b/docs/arch/x86_64/memory/allocator/tiny_frame_allocator.rst new file mode 100644 index 0000000..27401b2 --- /dev/null +++ b/docs/arch/x86_64/memory/allocator/tiny_frame_allocator.rst @@ -0,0 +1,5 @@ +Tiny Physical Frame Allocator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp + diff --git a/docs/arch/x86_64/memory/cpu.rst b/docs/arch/x86_64/memory/cpu.rst new file mode 100644 index 0000000..4cb5af0 --- /dev/null +++ b/docs/arch/x86_64/memory/cpu.rst @@ -0,0 +1,9 @@ +CPU Registers Subsystem +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + cpu/* diff --git a/docs/arch/x86_64/memory/cpu/control_register.rst b/docs/arch/x86_64/memory/cpu/control_register.rst new file mode 100644 index 0000000..f087112 --- /dev/null +++ b/docs/arch/x86_64/memory/cpu/control_register.rst @@ -0,0 +1,5 @@ +CPU Control Registers +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/cpu/control_register.hpp + diff --git a/docs/arch/x86_64/memory/cpu/msr.rst b/docs/arch/x86_64/memory/cpu/msr.rst new file mode 100644 index 0000000..c67d51c --- /dev/null +++ b/docs/arch/x86_64/memory/cpu/msr.rst @@ -0,0 +1,5 @@ +CPU Model-Specific Register +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/cpu/msr.hpp + diff --git a/docs/arch/x86_64/memory/cpu/tlb.rst b/docs/arch/x86_64/memory/cpu/tlb.rst new file mode 100644 index 0000000..0d482dc --- /dev/null +++ b/docs/arch/x86_64/memory/cpu/tlb.rst @@ -0,0 +1,5 @@ +CPU Translation Lookaside Buffer +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/cpu/tlb.hpp + diff --git a/docs/arch/x86_64/memory/heap.rst b/docs/arch/x86_64/memory/heap.rst new file mode 100644 index 0000000..409d93a --- /dev/null +++ b/docs/arch/x86_64/memory/heap.rst @@ -0,0 +1,9 @@ +Heap Memory Subsystem +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + heap/* diff --git a/docs/arch/x86_64/memory/heap/bump_allocator.rst b/docs/arch/x86_64/memory/heap/bump_allocator.rst new file mode 100644 index 0000000..185f00b --- /dev/null +++ b/docs/arch/x86_64/memory/heap/bump_allocator.rst @@ -0,0 +1,5 @@ +Heap Bump Allocator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/heap/bump_allocator.hpp + diff --git a/docs/arch/x86_64/memory/heap/concept.rst b/docs/arch/x86_64/memory/heap/concept.rst new file mode 100644 index 0000000..c0c3123 --- /dev/null +++ b/docs/arch/x86_64/memory/heap/concept.rst @@ -0,0 +1,5 @@ +Heap Allocator Concept +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/heap/concept.hpp + diff --git a/docs/arch/x86_64/memory/heap/linked_list_allocator.rst b/docs/arch/x86_64/memory/heap/linked_list_allocator.rst new file mode 100644 index 0000000..26b25ab --- /dev/null +++ b/docs/arch/x86_64/memory/heap/linked_list_allocator.rst @@ -0,0 +1,5 @@ +Heap Linked List Allocator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp + diff --git a/docs/arch/x86_64/memory/heap/memory_block.rst b/docs/arch/x86_64/memory/heap/memory_block.rst new file mode 100644 index 0000000..8ed6566 --- /dev/null +++ b/docs/arch/x86_64/memory/heap/memory_block.rst @@ -0,0 +1,5 @@ +Heap Linked List Free Memory Block +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/heap/memory_block.hpp + diff --git a/docs/arch/x86_64/memory/main.rst b/docs/arch/x86_64/memory/main.rst new file mode 100644 index 0000000..d9a9f39 --- /dev/null +++ b/docs/arch/x86_64/memory/main.rst @@ -0,0 +1,5 @@ +Memory Main +=========== + +.. doxygenfile:: arch/x86_64/include/arch/memory/main.hpp + diff --git a/docs/arch/x86_64/memory/multiboot.rst b/docs/arch/x86_64/memory/multiboot.rst new file mode 100644 index 0000000..22ec3f2 --- /dev/null +++ b/docs/arch/x86_64/memory/multiboot.rst @@ -0,0 +1,9 @@ +Kernel Multiboot Subsystem +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + multiboot/* diff --git a/docs/arch/x86_64/memory/multiboot/elf_symbols_section.rst b/docs/arch/x86_64/memory/multiboot/elf_symbols_section.rst new file mode 100644 index 0000000..bbd6dfb --- /dev/null +++ b/docs/arch/x86_64/memory/multiboot/elf_symbols_section.rst @@ -0,0 +1,5 @@ +Multiboot ELF Header Symbols Section Structure +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp + diff --git a/docs/arch/x86_64/memory/multiboot/info.rst b/docs/arch/x86_64/memory/multiboot/info.rst new file mode 100644 index 0000000..847870d --- /dev/null +++ b/docs/arch/x86_64/memory/multiboot/info.rst @@ -0,0 +1,5 @@ +Multiboot Header Information Structure +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/multiboot/info.hpp + diff --git a/docs/arch/x86_64/memory/multiboot/memory_map.rst b/docs/arch/x86_64/memory/multiboot/memory_map.rst new file mode 100644 index 0000000..9c77331 --- /dev/null +++ b/docs/arch/x86_64/memory/multiboot/memory_map.rst @@ -0,0 +1,5 @@ +Multiboot Memory Map Header Structure +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/multiboot/memory_map.hpp + diff --git a/docs/arch/x86_64/memory/multiboot/reader.rst b/docs/arch/x86_64/memory/multiboot/reader.rst new file mode 100644 index 0000000..fac98e2 --- /dev/null +++ b/docs/arch/x86_64/memory/multiboot/reader.rst @@ -0,0 +1,5 @@ +Multiboot Reader +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/multiboot/reader.hpp + diff --git a/docs/arch/x86_64/memory/paging.rst b/docs/arch/x86_64/memory/paging.rst new file mode 100644 index 0000000..10cd976 --- /dev/null +++ b/docs/arch/x86_64/memory/paging.rst @@ -0,0 +1,9 @@ +Virtual Page Table Paging Subsystem +=========== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + paging/* diff --git a/docs/arch/x86_64/memory/paging/active_page_table.rst b/docs/arch/x86_64/memory/paging/active_page_table.rst new file mode 100644 index 0000000..5710131 --- /dev/null +++ b/docs/arch/x86_64/memory/paging/active_page_table.rst @@ -0,0 +1,5 @@ +Active Page Table +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/paging/active_page_table.hpp + diff --git a/docs/arch/x86_64/memory/paging/inactive_page_table.rst b/docs/arch/x86_64/memory/paging/inactive_page_table.rst new file mode 100644 index 0000000..5732e64 --- /dev/null +++ b/docs/arch/x86_64/memory/paging/inactive_page_table.rst @@ -0,0 +1,5 @@ +Inactive Page Table +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp + diff --git a/docs/arch/x86_64/memory/paging/kernel_mapper.rst b/docs/arch/x86_64/memory/paging/kernel_mapper.rst new file mode 100644 index 0000000..9948e4e --- /dev/null +++ b/docs/arch/x86_64/memory/paging/kernel_mapper.rst @@ -0,0 +1,5 @@ +Kernel Mapper +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp + diff --git a/docs/arch/x86_64/memory/paging/page_entry.rst b/docs/arch/x86_64/memory/paging/page_entry.rst new file mode 100644 index 0000000..8900b0e --- /dev/null +++ b/docs/arch/x86_64/memory/paging/page_entry.rst @@ -0,0 +1,5 @@ +Virtual Page Table Entry +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/paging/page_entry.hpp + diff --git a/docs/arch/x86_64/memory/paging/page_table.rst b/docs/arch/x86_64/memory/paging/page_table.rst new file mode 100644 index 0000000..c5ab8c7 --- /dev/null +++ b/docs/arch/x86_64/memory/paging/page_table.rst @@ -0,0 +1,5 @@ +Virtual Page Table +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/paging/page_table.hpp + diff --git a/docs/arch/x86_64/memory/paging/temporary_page.rst b/docs/arch/x86_64/memory/paging/temporary_page.rst new file mode 100644 index 0000000..0c63899 --- /dev/null +++ b/docs/arch/x86_64/memory/paging/temporary_page.rst @@ -0,0 +1,5 @@ +Temporary Virtual Page Table +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/paging/temporary_page.hpp + diff --git a/docs/arch/x86_64/memory/paging/virtual_page.rst b/docs/arch/x86_64/memory/paging/virtual_page.rst new file mode 100644 index 0000000..dd42f47 --- /dev/null +++ b/docs/arch/x86_64/memory/paging/virtual_page.rst @@ -0,0 +1,5 @@ +Virtual Page +======================= + +.. doxygenfile:: arch/x86_64/include/arch/memory/paging/virtual_page.hpp + diff --git a/docs/arch/x86_64/shared.rst b/docs/arch/x86_64/shared.rst new file mode 100644 index 0000000..c9b754f --- /dev/null +++ b/docs/arch/x86_64/shared.rst @@ -0,0 +1,9 @@ +Shared Code Subsystem +====================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :glob: + + shared/* \ No newline at end of file diff --git a/docs/arch/x86_64/shared/container.rst b/docs/arch/x86_64/shared/container.rst new file mode 100644 index 0000000..c4b6aef --- /dev/null +++ b/docs/arch/x86_64/shared/container.rst @@ -0,0 +1,5 @@ +Shared Container Structure +======================= + +.. doxygenfile:: arch/x86_64/include/arch/shared/container.hpp + diff --git a/docs/arch/x86_64/shared/contiguous_pointer_iterator.rst b/docs/arch/x86_64/shared/contiguous_pointer_iterator.rst new file mode 100644 index 0000000..a5f921d --- /dev/null +++ b/docs/arch/x86_64/shared/contiguous_pointer_iterator.rst @@ -0,0 +1,5 @@ +Shared Contiguous Pointer Iterator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/shared/contiguous_pointer_iterator.hpp + diff --git a/docs/arch/x86_64/shared/forward_value_iterator.rst b/docs/arch/x86_64/shared/forward_value_iterator.rst new file mode 100644 index 0000000..cdff5af --- /dev/null +++ b/docs/arch/x86_64/shared/forward_value_iterator.rst @@ -0,0 +1,5 @@ +Shared Forward Value Iterator +======================= + +.. doxygenfile:: arch/x86_64/include/arch/shared/forward_value_iterator.hpp + diff --git a/docs/arch/x86_64/shared/mutex.rst b/docs/arch/x86_64/shared/mutex.rst new file mode 100644 index 0000000..bc23636 --- /dev/null +++ b/docs/arch/x86_64/shared/mutex.rst @@ -0,0 +1,5 @@ +Shared Mutex +======================= + +.. doxygenfile:: arch/x86_64/include/arch/shared/mutex.hpp + -- cgit v1.2.3 From a5c6d172b2a134f63387b0ed9055b48147f0b663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Wed, 4 Dec 2024 16:07:09 +0000 Subject: Add namespace spacing and add comment to endif --- arch/x86_64/include/arch/boot/pointers.hpp | 1 + arch/x86_64/include/arch/exception_handling/assert.hpp | 3 ++- arch/x86_64/include/arch/exception_handling/panic.hpp | 14 ++++++++++++-- arch/x86_64/include/arch/io/port_io.hpp | 2 +- arch/x86_64/include/arch/kernel/halt.hpp | 8 ++++++-- arch/x86_64/include/arch/kernel/main.hpp | 8 ++++++-- .../include/arch/memory/allocator/area_frame_allocator.hpp | 1 + arch/x86_64/include/arch/memory/allocator/concept.hpp | 1 + .../include/arch/memory/allocator/physical_frame.hpp | 1 + .../include/arch/memory/allocator/tiny_frame_allocator.hpp | 1 + arch/x86_64/include/arch/memory/cpu/control_register.hpp | 1 + arch/x86_64/include/arch/memory/cpu/msr.hpp | 1 + arch/x86_64/include/arch/memory/heap/concept.hpp | 1 + .../include/arch/memory/heap/linked_list_allocator.hpp | 1 + arch/x86_64/include/arch/memory/heap/memory_block.hpp | 1 + arch/x86_64/include/arch/memory/main.hpp | 5 +++-- .../include/arch/memory/multiboot/elf_symbols_section.hpp | 1 + arch/x86_64/include/arch/memory/multiboot/info.hpp | 1 + arch/x86_64/include/arch/memory/multiboot/memory_map.hpp | 1 + arch/x86_64/include/arch/memory/multiboot/reader.hpp | 1 + .../include/arch/memory/paging/inactive_page_table.hpp | 1 + arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp | 1 + arch/x86_64/include/arch/memory/paging/page_entry.hpp | 1 + arch/x86_64/include/arch/memory/paging/page_table.hpp | 1 + arch/x86_64/include/arch/memory/paging/temporary_page.hpp | 1 + arch/x86_64/include/arch/memory/paging/virtual_page.hpp | 1 + arch/x86_64/include/arch/shared/container.hpp | 1 + .../include/arch/shared/contiguous_pointer_iterator.hpp | 1 + arch/x86_64/include/arch/shared/forward_value_iterator.hpp | 1 + arch/x86_64/include/arch/shared/mutex.hpp | 1 + arch/x86_64/include/arch/video/vga/io.hpp | 2 +- arch/x86_64/include/arch/video/vga/text.hpp | 3 ++- 32 files changed, 57 insertions(+), 12 deletions(-) diff --git a/arch/x86_64/include/arch/boot/pointers.hpp b/arch/x86_64/include/arch/boot/pointers.hpp index 29cc3cf..fe9c657 100644 --- a/arch/x86_64/include/arch/boot/pointers.hpp +++ b/arch/x86_64/include/arch/boot/pointers.hpp @@ -9,6 +9,7 @@ namespace teachos::arch::boot * @brief Address pointing to the start of the multiboot information structure. */ extern "C" size_t const multiboot_information_pointer; + } // namespace teachos::arch::boot #endif // TEACHOS_ARCH_X86_64_BOOT_POINTERS_HPP diff --git a/arch/x86_64/include/arch/exception_handling/assert.hpp b/arch/x86_64/include/arch/exception_handling/assert.hpp index 58c1f33..7dc4381 100644 --- a/arch/x86_64/include/arch/exception_handling/assert.hpp +++ b/arch/x86_64/include/arch/exception_handling/assert.hpp @@ -11,6 +11,7 @@ namespace teachos::arch::exception_handling * @param message Message that should be printed before halting the execution if the condition is not met. */ auto assert(bool condition, char const * message) -> void; + } // namespace teachos::arch::exception_handling -#endif +#endif // TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_ASSERT_HPP diff --git a/arch/x86_64/include/arch/exception_handling/panic.hpp b/arch/x86_64/include/arch/exception_handling/panic.hpp index 9566159..6a2404c 100644 --- a/arch/x86_64/include/arch/exception_handling/panic.hpp +++ b/arch/x86_64/include/arch/exception_handling/panic.hpp @@ -4,10 +4,20 @@ namespace teachos::arch::exception_handling { /** - * @brief Print a kernel panic message and then halt the system. + * @brief Print the given kernel panic message and then halt the system. + * + * @param reason Reason to print before halting the system. */ [[noreturn]] auto panic(char const * reason) -> void; + + /** + * @brief Print the given kernel panic message started by a given prefix and then halt the system. + * + * @param prefix Prefix to print before printing the reason. + * @param reason Reason to print before halting the system. + */ [[noreturn]] auto panic(char const * prefix, char const * reason) -> void; + } // namespace teachos::arch::exception_handling -#endif \ No newline at end of file +#endif // TEACHOS_ARCH_X86_64_EXCEPTION_HANDLING_PANIC_HPP diff --git a/arch/x86_64/include/arch/io/port_io.hpp b/arch/x86_64/include/arch/io/port_io.hpp index 1945261..ba41660 100644 --- a/arch/x86_64/include/arch/io/port_io.hpp +++ b/arch/x86_64/include/arch/io/port_io.hpp @@ -130,4 +130,4 @@ namespace teachos::arch::io } // namespace teachos::arch::io -#endif +#endif // TEACHOS_ARCH_X86_64_IO_PORT_IO_HPP diff --git a/arch/x86_64/include/arch/kernel/halt.hpp b/arch/x86_64/include/arch/kernel/halt.hpp index 6c58938..377acc0 100644 --- a/arch/x86_64/include/arch/kernel/halt.hpp +++ b/arch/x86_64/include/arch/kernel/halt.hpp @@ -3,7 +3,11 @@ namespace teachos::arch::kernel { + /** + * @brief Halts the kernel execution, meaning any code after a call to this will not run anymore. + */ extern "C" [[noreturn]] auto halt() -> void; -} -#endif \ No newline at end of file +} // namespace teachos::arch::kernel + +#endif // TEACHOS_ARCH_X86_64_KERNEL_HALT_HPP diff --git a/arch/x86_64/include/arch/kernel/main.hpp b/arch/x86_64/include/arch/kernel/main.hpp index 8813b46..a13e5f4 100644 --- a/arch/x86_64/include/arch/kernel/main.hpp +++ b/arch/x86_64/include/arch/kernel/main.hpp @@ -3,7 +3,11 @@ namespace teachos::arch::kernel { + /** + * @brief Initalizes the kernel system. + */ auto main() -> void; -} -#endif +} // namespace teachos::arch::kernel + +#endif // TEACHOS_ARCH_X86_64_KERNEL_MAIN_HPP diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp index adba4f1..685babd 100644 --- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -60,6 +60,7 @@ namespace teachos::arch::memory::allocator physical_frame const multiboot_start; ///< The start address of the multiboot code in memory. physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. }; + } // namespace teachos::arch::memory::allocator #endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP diff --git a/arch/x86_64/include/arch/memory/allocator/concept.hpp b/arch/x86_64/include/arch/memory/allocator/concept.hpp index 9d58fad..18bb6bd 100644 --- a/arch/x86_64/include/arch/memory/allocator/concept.hpp +++ b/arch/x86_64/include/arch/memory/allocator/concept.hpp @@ -17,6 +17,7 @@ namespace teachos::arch::memory::allocator { t.allocate_frame() } -> std::same_as>; { t.deallocate_frame(a) } -> std::same_as; }; + } // namespace teachos::arch::memory::allocator #endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_CONCEPT_HPP diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp index d5e2f4c..c323c10 100644 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -80,6 +80,7 @@ namespace teachos::arch::memory::allocator }; typedef shared::container> frame_container; + } // namespace teachos::arch::memory::allocator #endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP diff --git a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp index 8124442..5a9b772 100644 --- a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -66,6 +66,7 @@ namespace teachos::arch::memory::allocator std::array, TINY_ALLOCATOR_FRAMES_COUNT> frames = {}; ///< Container that holds the frames allocated by another allocator. }; + } // namespace teachos::arch::memory::allocator #endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_TINY_FRAME_ALLOCATOR_HPP diff --git a/arch/x86_64/include/arch/memory/cpu/control_register.hpp b/arch/x86_64/include/arch/memory/cpu/control_register.hpp index 4988036..9b0a4d5 100644 --- a/arch/x86_64/include/arch/memory/cpu/control_register.hpp +++ b/arch/x86_64/include/arch/memory/cpu/control_register.hpp @@ -65,6 +65,7 @@ namespace teachos::arch::memory::cpu * @param flag he flag to set in the CR2. */ auto set_cr2_bit(cr2_flags flag) -> void; + } // namespace teachos::arch::memory::cpu #endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_CR3_HPP diff --git a/arch/x86_64/include/arch/memory/cpu/msr.hpp b/arch/x86_64/include/arch/memory/cpu/msr.hpp index 49e9bcf..5cce816 100644 --- a/arch/x86_64/include/arch/memory/cpu/msr.hpp +++ b/arch/x86_64/include/arch/memory/cpu/msr.hpp @@ -58,6 +58,7 @@ namespace teachos::arch::memory::cpu * @param flag The flag to set in the EFER register. */ auto set_efer_bit(efer_flags flag) -> void; + } // namespace teachos::arch::memory::cpu #endif // TEACHOS_ARCH_X86_64_MEMORY_CPU_NXE_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/heap/concept.hpp b/arch/x86_64/include/arch/memory/heap/concept.hpp index 52dba51..1cd24f4 100644 --- a/arch/x86_64/include/arch/memory/heap/concept.hpp +++ b/arch/x86_64/include/arch/memory/heap/concept.hpp @@ -13,6 +13,7 @@ namespace teachos::arch::memory::heap { t.allocate(size) } -> std::same_as; { t.deallocate(pointer, size) } -> std::same_as; }; + } // namespace teachos::arch::memory::heap #endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_CONCEPT_HPP diff --git a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp index 03b8828..06b21bb 100644 --- a/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp +++ b/arch/x86_64/include/arch/memory/heap/linked_list_allocator.hpp @@ -126,6 +126,7 @@ namespace teachos::arch::memory::heap memory_block * first; ///< First free entry in our memory. shared::mutex mutex; ///< Mutex to ensure only one thread calls allocate or deallocate at once. }; + } // namespace teachos::arch::memory::heap #endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_LINKED_LIST_ALLOCATOR_HPP diff --git a/arch/x86_64/include/arch/memory/heap/memory_block.hpp b/arch/x86_64/include/arch/memory/heap/memory_block.hpp index c62dd57..502d64e 100644 --- a/arch/x86_64/include/arch/memory/heap/memory_block.hpp +++ b/arch/x86_64/include/arch/memory/heap/memory_block.hpp @@ -32,6 +32,7 @@ namespace teachos::arch::memory::heap ///< size variable and the pointer to the next hole. memory_block * next; ///< Optional pointer to the next free memory, holds nullptr if there is none. }; + } // namespace teachos::arch::memory::heap #endif // TEACHOS_ARCH_X86_64_MEMORY_HEAP_MEMORY_BLOCK_HPP diff --git a/arch/x86_64/include/arch/memory/main.hpp b/arch/x86_64/include/arch/memory/main.hpp index bbf160b..164abbc 100644 --- a/arch/x86_64/include/arch/memory/main.hpp +++ b/arch/x86_64/include/arch/memory/main.hpp @@ -4,12 +4,13 @@ namespace teachos::arch::memory { /** - * @brief Initializes memory management + * @brief Initializes memory management. * * @note Enables the necessary register flags and remaps the kernel, * elf_sections, vga_text and the heap. */ auto initialize_memory_management() -> void; + } // namespace teachos::arch::memory -#endif +#endif // TEACHOS_ARCH_X86_64_MEMORY_MAIN_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp index 549839a..e8f6b0a 100644 --- a/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/elf_symbols_section.hpp @@ -163,6 +163,7 @@ namespace teachos::arch::memory::multiboot }; typedef shared::container> elf_section_header_container; + } // namespace teachos::arch::memory::multiboot #endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_ELF_SYBOLS_SECTION_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/info.hpp b/arch/x86_64/include/arch/memory/multiboot/info.hpp index 7924993..a9abf12 100644 --- a/arch/x86_64/include/arch/memory/multiboot/info.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/info.hpp @@ -58,6 +58,7 @@ namespace teachos::arch::memory::multiboot uint32_t total_size; ///< Total size of all multiboot::tags and their data. alignas(8) struct tag tags; ///< Specific tags. }; + } // namespace teachos::arch::memory::multiboot #endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_INFO_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp index 413f5a1..c28c986 100644 --- a/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/memory_map.hpp @@ -47,6 +47,7 @@ namespace teachos::arch::memory::multiboot }; typedef shared::container> memory_area_container; + } // namespace teachos::arch::memory::multiboot #endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_MEMORY_MAP_HPP diff --git a/arch/x86_64/include/arch/memory/multiboot/reader.hpp b/arch/x86_64/include/arch/memory/multiboot/reader.hpp index 9707757..bda0c43 100644 --- a/arch/x86_64/include/arch/memory/multiboot/reader.hpp +++ b/arch/x86_64/include/arch/memory/multiboot/reader.hpp @@ -47,6 +47,7 @@ namespace teachos::arch::memory::multiboot * @return Relevant data read from multiboot2. */ auto read_multiboot2() -> memory_information; + } // namespace teachos::arch::memory::multiboot #endif // TEACHOS_ARCH_X86_64_MEMORY_MULTIBOOT_READER_HPP diff --git a/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp index a9ab258..8d96740 100644 --- a/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/inactive_page_table.hpp @@ -33,6 +33,7 @@ namespace teachos::arch::memory::paging allocator::physical_frame page_table_level_4_frame; ///< Temporary level 4 page table }; + } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_INACTIVE_PAGE_TABLE_HPP diff --git a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp index 897ae06..74f1c14 100644 --- a/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp +++ b/arch/x86_64/include/arch/memory/paging/kernel_mapper.hpp @@ -153,6 +153,7 @@ namespace teachos::arch::memory::paging multiboot::memory_information const & mem_info; ///< Information about elf kernel sections required for remapping process. }; + } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_KERNEL_MAPPER_HPP diff --git a/arch/x86_64/include/arch/memory/paging/page_entry.hpp b/arch/x86_64/include/arch/memory/paging/page_entry.hpp index a7ba262..876ea3c 100644 --- a/arch/x86_64/include/arch/memory/paging/page_entry.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_entry.hpp @@ -110,6 +110,7 @@ namespace teachos::arch::memory::paging std::bitset<64U> flags; ///< Underlying bitset used to read the flags from. Bits 9 - 11 and 52 - 62 can be ///< freely used for additional flags by the operating system. }; + } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_ENTRY_HPP diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 7a15875..51ddcd4 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -142,6 +142,7 @@ namespace teachos::arch::memory::paging level table_level; ///< Level page table is currently on, depends on how often next_level was ///< called successfully. }; + } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_PAGE_TABLE_HPP diff --git a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp index 02cb545..d0d7781 100644 --- a/arch/x86_64/include/arch/memory/paging/temporary_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/temporary_page.hpp @@ -58,6 +58,7 @@ namespace teachos::arch::memory::paging virtual_page page; ///< Underlying virtual page we want to temporarily map. allocator::tiny_frame_allocator allocator; ///< Allocator that should be used to map the temporary page. }; + } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_TEMPORARY_PAGE_HPP \ No newline at end of file diff --git a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp index 0ee9cbd..d820e82 100644 --- a/arch/x86_64/include/arch/memory/paging/virtual_page.hpp +++ b/arch/x86_64/include/arch/memory/paging/virtual_page.hpp @@ -85,6 +85,7 @@ namespace teachos::arch::memory::paging }; typedef shared::container> page_container; + } // namespace teachos::arch::memory::paging #endif // TEACHOS_ARCH_X86_64_MEMORY_PAGING_VIRTUAL_PAGE_HPP diff --git a/arch/x86_64/include/arch/shared/container.hpp b/arch/x86_64/include/arch/shared/container.hpp index b335e72..f2fd1dc 100644 --- a/arch/x86_64/include/arch/shared/container.hpp +++ b/arch/x86_64/include/arch/shared/container.hpp @@ -77,6 +77,7 @@ namespace teachos::arch::shared iterator begin_itr = {}; ///< Pointer to the first element of the given template type. iterator end_itr = {}; ///< Pointer to one pas the last element of the given template type. }; + } // namespace teachos::arch::shared #endif // TEACHOS_ARCH_X86_64_SHARED_CONTAINER_HPP diff --git a/arch/x86_64/include/arch/shared/contiguous_pointer_iterator.hpp b/arch/x86_64/include/arch/shared/contiguous_pointer_iterator.hpp index 7d5019a..e2520dc 100644 --- a/arch/x86_64/include/arch/shared/contiguous_pointer_iterator.hpp +++ b/arch/x86_64/include/arch/shared/contiguous_pointer_iterator.hpp @@ -184,6 +184,7 @@ namespace teachos::arch::shared pointer_type ptr = {}; ///< Underlying value the iterator is currently pointing too and should increment or decrement. }; + } // namespace teachos::arch::shared #endif // TEACHOS_ARCH_X86_64_SHARED_CONTIGUOUS_POINTER_ITERATOR_HPP diff --git a/arch/x86_64/include/arch/shared/forward_value_iterator.hpp b/arch/x86_64/include/arch/shared/forward_value_iterator.hpp index a84d291..c5dfc06 100644 --- a/arch/x86_64/include/arch/shared/forward_value_iterator.hpp +++ b/arch/x86_64/include/arch/shared/forward_value_iterator.hpp @@ -104,6 +104,7 @@ namespace teachos::arch::shared value_type value = {}; ///< Underlying value the iterator is currently pointing too and should increment or decrement. }; + } // namespace teachos::arch::shared #endif // TEACHOS_ARCH_X86_64_SHARED_FORWARD_VALUE_ITERATOR_HPP diff --git a/arch/x86_64/include/arch/shared/mutex.hpp b/arch/x86_64/include/arch/shared/mutex.hpp index 33e9e17..b18a8b3 100644 --- a/arch/x86_64/include/arch/shared/mutex.hpp +++ b/arch/x86_64/include/arch/shared/mutex.hpp @@ -51,6 +51,7 @@ namespace teachos::arch::shared private: std::atomic locked = {false}; // Atomic boolean to track if mutex is locked or not. }; + } // namespace teachos::arch::shared #endif // TEACHOS_ARCH_X86_64_SHARED_MUTEX_HPP diff --git a/arch/x86_64/include/arch/video/vga/io.hpp b/arch/x86_64/include/arch/video/vga/io.hpp index 3d2e90c..c399fad 100644 --- a/arch/x86_64/include/arch/video/vga/io.hpp +++ b/arch/x86_64/include/arch/video/vga/io.hpp @@ -36,4 +36,4 @@ namespace teachos::arch::video::vga } // namespace teachos::arch::video::vga -#endif +#endif // TEACHOS_ARCH_X86_64_VIDEO_VGA_IO_HPP diff --git a/arch/x86_64/include/arch/video/vga/text.hpp b/arch/x86_64/include/arch/video/vga/text.hpp index 665dc1c..cfbf98f 100644 --- a/arch/x86_64/include/arch/video/vga/text.hpp +++ b/arch/x86_64/include/arch/video/vga/text.hpp @@ -163,6 +163,7 @@ namespace teachos::arch::video::vga::text divisor /= 10; } } + } // namespace teachos::arch::video::vga::text -#endif \ No newline at end of file +#endif // TEACHOS_ARCH_X86_64_VIDEO_VGA_TEXT_HPP \ No newline at end of file -- cgit v1.2.3 From 50e2bda01928bfbad90a91439ac6326473a698b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 9 Dec 2024 12:03:39 +0000 Subject: Generate doyxgen files with build taks --- CMakeLists.txt | 2 +- arch/x86_64/include/arch/memory/allocator/concept.hpp | 4 +--- arch/x86_64/include/arch/memory/heap/concept.hpp | 3 +++ 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3586669..12ac210 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ set(CMAKE_CXX_EXTENSIONS NO) find_package("Doxygen") -set(DOXYGEN_GENERATE_HTML NO) +set(DOXYGEN_GENERATE_HTML YES) set(DOXYGEN_GENERATE_XML YES) set(DOXYGEN_EXCLUDE_PATTERNS "*.cpp") set(DOXYGEN_OUTPUT_DIRECTORY "doxygen") diff --git a/arch/x86_64/include/arch/memory/allocator/concept.hpp b/arch/x86_64/include/arch/memory/allocator/concept.hpp index 18bb6bd..2d3f4ae 100644 --- a/arch/x86_64/include/arch/memory/allocator/concept.hpp +++ b/arch/x86_64/include/arch/memory/allocator/concept.hpp @@ -8,9 +8,7 @@ namespace teachos::arch::memory::allocator { /** - * @brief Frame allocator concept - * - * @tparam T + * @brief Frame allocator concept required for allocating and deallocating physical frames in memory. */ template concept FrameAllocator = requires(T t, physical_frame const & a) { diff --git a/arch/x86_64/include/arch/memory/heap/concept.hpp b/arch/x86_64/include/arch/memory/heap/concept.hpp index 1cd24f4..e22e35f 100644 --- a/arch/x86_64/include/arch/memory/heap/concept.hpp +++ b/arch/x86_64/include/arch/memory/heap/concept.hpp @@ -8,6 +8,9 @@ namespace teachos::arch::memory::heap std::size_t constexpr HEAP_START = 0x100000000; std::size_t constexpr HEAP_SIZE = 100 * 1024; + /** + * @brief Heap allocator concept required for allocating and managing free space on the heap. + */ template concept HeapAllocator = requires(T t, uint8_t * pointer, std::size_t size) { { t.allocate(size) } -> std::same_as; -- cgit v1.2.3 From 4ff0477e844fe13620b02c197a8db4c01809399f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Mon, 9 Dec 2024 15:16:50 +0000 Subject: Fix method writing to wrong CR register and improve doxygen comments. --- .../include/arch/exception_handling/assert.hpp | 2 +- .../arch/memory/allocator/area_frame_allocator.hpp | 5 ++-- .../arch/memory/allocator/physical_frame.hpp | 2 +- .../arch/memory/allocator/tiny_frame_allocator.hpp | 4 +++- .../include/arch/memory/cpu/control_register.hpp | 16 ++++++------- arch/x86_64/include/arch/memory/cpu/msr.hpp | 28 +++++++++++----------- arch/x86_64/include/arch/memory/cpu/tlb.hpp | 5 +++- .../include/arch/memory/heap/memory_block.hpp | 2 +- arch/x86_64/src/memory/cpu/control_register.cpp | 6 ++--- arch/x86_64/src/memory/main.cpp | 2 +- 10 files changed, 39 insertions(+), 33 deletions(-) diff --git a/arch/x86_64/include/arch/exception_handling/assert.hpp b/arch/x86_64/include/arch/exception_handling/assert.hpp index 7dc4381..1286768 100644 --- a/arch/x86_64/include/arch/exception_handling/assert.hpp +++ b/arch/x86_64/include/arch/exception_handling/assert.hpp @@ -5,7 +5,7 @@ namespace teachos::arch::exception_handling { /** * @brief Assert a condition to be true, if not do not continue - * execution of the code and print the formatted message to screen. + * execution of the code and print the given message to screen. * * @param condition Condition we want to be true or else halt execution. * @param message Message that should be printed before halting the execution if the condition is not met. diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp index 685babd..b8370db 100644 --- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp @@ -9,7 +9,8 @@ namespace teachos::arch::memory::allocator { /** - * @brief Allocates memory using memory areas read from the multiboot2 information pointer. + * @brief Allocates memory linearly using memory areas read from the multiboot2 information pointer and leaks any + * deallocated frames. */ struct area_frame_allocator { @@ -39,7 +40,7 @@ namespace teachos::arch::memory::allocator * * @note Simply does nothing, because the simply area frame * allocator implementation does not keep track of free or used frames and can therefore not deallocate, because it - * does not know which frames have ben alocated in the first place. + * does not know which frames have been alocated in the first place. * * @param physical_frame Previously allocated physical_frame that should be deallocated. */ diff --git a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp index c323c10..7f04042 100644 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ b/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp @@ -45,7 +45,7 @@ namespace teachos::arch::memory::allocator auto static containing_address(physical_address address) -> physical_frame; /** - * @brief Evaluates the start address of the physical frame. + * @brief Get the start address of this physical frame. * * @return Start address of the physical frame. */ diff --git a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp index 5a9b772..1ceb74d 100644 --- a/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp +++ b/arch/x86_64/include/arch/memory/allocator/tiny_frame_allocator.hpp @@ -14,7 +14,9 @@ namespace teachos::arch::memory::allocator } /** - * @brief Allocates memory using memory areas read from the multiboot2 information pointer. + * @brief Allocates memory using memory areas read from the multiboot2 information pointer. Does not allocate its own + * frames, but uses the necessary three frames provided by another allocator to map one virtual level 1 page entry and + * the necessary upper layers. */ struct tiny_frame_allocator { diff --git a/arch/x86_64/include/arch/memory/cpu/control_register.hpp b/arch/x86_64/include/arch/memory/cpu/control_register.hpp index 9b0a4d5..e11813d 100644 --- a/arch/x86_64/include/arch/memory/cpu/control_register.hpp +++ b/arch/x86_64/include/arch/memory/cpu/control_register.hpp @@ -27,14 +27,14 @@ namespace teachos::arch::memory::cpu }; /** - * @brief Control register 2 flags that can be set. + * @brief Control register 0 flags that can be set. * * @note Modifies the basic operation of the processor. Only the most important extensions are listed below, the rest * are excluded for brevity. See https://en.wikipedia.org/wiki/Control_register#CR0 for more information. */ - enum struct cr2_flags : uint64_t + enum struct cr0_flags : uint64_t { - PROTECTED_MODE_ENABLED = 1U << 0U, ///< System is in protected moe else system is in real mode. + PROTECTED_MODE_ENABLED = 1U << 0U, ///< System is in protected or system is in real mode. TASK_SWITCHED = 1U << 3U, ///< Allows saving x87 task context upon a task switch only after x87 instruction used. WRITE_PROTECT = 1U << 16U, ///< When set, the CPU cannot write to read-only pages when privilege level is 0. PAGING = 1U << 31U, // Enable paging using the CR3 register. @@ -57,14 +57,14 @@ namespace teachos::arch::memory::cpu auto write_control_register(control_register cr, uint64_t new_value) -> void; /** - * @brief Sets a specific bit in the CR2. + * @brief Sets a specific bit in the CR0. * - * @note This function reads the current value of the CR2 register, ORs the specified - * bit with the current value, and writes the updated value back to the CR2. + * @note This function reads the current value of the CR0 register, ORs the specified + * bit with the current value, and writes the updated value back to the CR0. * - * @param flag he flag to set in the CR2. + * @param flag he flag to set in the CR0. */ - auto set_cr2_bit(cr2_flags flag) -> void; + auto set_cr0_bit(cr0_flags flag) -> void; } // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/include/arch/memory/cpu/msr.hpp b/arch/x86_64/include/arch/memory/cpu/msr.hpp index 5cce816..cda70e2 100644 --- a/arch/x86_64/include/arch/memory/cpu/msr.hpp +++ b/arch/x86_64/include/arch/memory/cpu/msr.hpp @@ -7,7 +7,7 @@ namespace teachos::arch::memory::cpu { /** - * @brief Important Flags that can be writen into the Extended Feature Enable Register (EFER). + * @brief Important flags that can be writen into the Extended Feature Enable Register (EFER). * * @note EFER is a model-specific register allowing to configure CPU extensions. Only the most important extensions * are listed below, the rest are excluded for brevity. See https://en.wikipedia.org/wiki/Control_register#EFER for @@ -15,22 +15,21 @@ namespace teachos::arch::memory::cpu */ enum class efer_flags : uint64_t { - SCE = 1UL << 0UL, ///< System Call Extensions - LME = 1UL << 8UL, ///< Long Mode Enabled - LMA = 1UL << 10UL, ///< Long Mode Active - NXE = 1UL << 11UL, ///< No-Execute Enable - SVME = 1UL << 12UL, ///< Secure Virtual Machine Enable - LMSLE = 1UL << 13UL, ///< Long Mode Segment Limit Enable - FFXSR = 1UL << 14UL, ///< Fast FXSAVE/FXSTOR - TCE = 1UL << 15UL, ///< Translation Cache Extension + SCE = 1UL << 0UL, ///< System Call Extensions. + LME = 1UL << 8UL, ///< Long Mode Enabled. + LMA = 1UL << 10UL, ///< Long Mode Active. + NXE = 1UL << 11UL, ///< No-Execute Enable. + SVME = 1UL << 12UL, ///< Secure Virtual Machine Enable. + LMSLE = 1UL << 13UL, ///< Long Mode Segment Limit Enable. + FFXSR = 1UL << 14UL, ///< Fast FXSAVE/FXSTOR. + TCE = 1UL << 15UL, ///< Translation Cache Extension. }; /** - * @brief Reads a 64-bit Model-Specific Register (MSR). + * @brief Reads a 64-bit from the Model-Specific Register (MSR). * - * @note This function reads the value of an MSR specified by the given address. It - * combines the lower and upper 32-bits of the MSR value and returns it as a - * 64-bit unsigned integer. + * @note This function reads the value of an MSR specified by the given address. It combines the lower and upper + * 32-bits of the MSR value read using the 'rdmsr' instruction and returns it as a 64-bit unsigned integer. * * @param msr The address of the MSR to read. * @return The 64-bit value read from the MSR. @@ -50,7 +49,8 @@ namespace teachos::arch::memory::cpu auto write_msr(uint32_t msr, uint64_t new_value) -> void; /** - * @brief Sets a specific bit in the Extended Feature Enable Register (EFER) Model-Specific Register (MSR) register. + * @brief Sets a specific bit in the Extended Feature Enable Register (EFER), which is a Model-Specific Register + * (MSR). * * @note This function reads the current value of the EFER register, ORs the specified * bit with the current value, and writes the updated value back to the EFER register. diff --git a/arch/x86_64/include/arch/memory/cpu/tlb.hpp b/arch/x86_64/include/arch/memory/cpu/tlb.hpp index 21f09e5..075d7bb 100644 --- a/arch/x86_64/include/arch/memory/cpu/tlb.hpp +++ b/arch/x86_64/include/arch/memory/cpu/tlb.hpp @@ -15,7 +15,10 @@ namespace teachos::arch::memory::cpu auto tlb_flush(paging::virtual_address address) -> void; /** - * @brief Invalidates the translation lookaside buffer (TLB) entry for all page tables + * @brief Invalidates the translation lookaside buffer (TLB) entry for all page tables. + * + * @note Simply reassigns the CR3 register the value of the CR3 register, causing a flush of the TLB buffer, because + * the system has to assume that the location of the level 4 page table moved. */ auto tlb_flush_all() -> void; diff --git a/arch/x86_64/include/arch/memory/heap/memory_block.hpp b/arch/x86_64/include/arch/memory/heap/memory_block.hpp index 502d64e..b9a2254 100644 --- a/arch/x86_64/include/arch/memory/heap/memory_block.hpp +++ b/arch/x86_64/include/arch/memory/heap/memory_block.hpp @@ -7,7 +7,7 @@ namespace teachos::arch::memory::heap { /** * @brief Block containing free memory, pointing to the next free hole (nullptr) if there is none. - * Forms a single linked list. + * Forms a singly linked list of free memory blocks that we can callocate memory into. */ struct memory_block { diff --git a/arch/x86_64/src/memory/cpu/control_register.cpp b/arch/x86_64/src/memory/cpu/control_register.cpp index 7624244..298874f 100644 --- a/arch/x86_64/src/memory/cpu/control_register.cpp +++ b/arch/x86_64/src/memory/cpu/control_register.cpp @@ -66,9 +66,9 @@ namespace teachos::arch::memory::cpu } } - auto set_cr2_bit(cr2_flags flag) -> void + auto set_cr0_bit(cr0_flags flag) -> void { - auto const cr2 = read_control_register(control_register::CR2); - write_control_register(control_register::CR2, static_cast::type>(flag) | cr2); + auto const cr0 = read_control_register(control_register::CR0); + write_control_register(control_register::CR0, static_cast::type>(flag) | cr0); } } // namespace teachos::arch::memory::cpu diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 34ce113..2f01c5e 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -38,7 +38,7 @@ namespace teachos::arch::memory auto const memory_information = multiboot::read_multiboot2(); allocator::area_frame_allocator allocator(memory_information); - cpu::set_cr2_bit(memory::cpu::cr2_flags::WRITE_PROTECT); + cpu::set_cr0_bit(memory::cpu::cr0_flags::WRITE_PROTECT); cpu::set_efer_bit(memory::cpu::efer_flags::NXE); paging::kernel_mapper kernel(allocator, memory_information); -- cgit v1.2.3 From 568d0fd25f4ab12b183e230210d68252031bfa18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 17 Dec 2024 08:24:15 +0000 Subject: Improve log messages --- arch/x86_64/src/kernel/main.cpp | 3 ++- arch/x86_64/src/memory/main.cpp | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index c0fcc27..a8cdc3a 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -37,7 +37,7 @@ namespace teachos::arch::kernel auto test8 = memory::multiboot::read_multiboot2(); if (test6 && test7 && test8.kernel_end) { - video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); + video::vga::text::write("Heap test successfull", video::vga::text::common_attributes::green_on_black); } test2->kernel_end = 2000; test2->kernel_start = 1000; @@ -61,6 +61,7 @@ namespace teachos::arch::kernel 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(); diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 2f01c5e..5290061 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -44,8 +44,10 @@ namespace teachos::arch::memory paging::kernel_mapper kernel(allocator, memory_information); auto & active_table = kernel.remap_kernel(); video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); + video::vga::text::newline(); remap_heap(allocator, active_table); video::vga::text::write("Heap remapping successfull", video::vga::text::common_attributes::green_on_black); + video::vga::text::newline(); } -} // namespace teachos::arch::memory \ No newline at end of file +} // namespace teachos::arch::memory -- cgit v1.2.3 From 3d488e53a1d15fcc01a7b1d23b9585ca7a724864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20Gm=C3=BCr?= Date: Tue, 17 Dec 2024 09:36:31 +0000 Subject: Fix typo --- arch/x86_64/include/arch/memory/paging/page_table.hpp | 2 +- arch/x86_64/src/kernel/main.cpp | 2 +- arch/x86_64/src/memory/main.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86_64/include/arch/memory/paging/page_table.hpp b/arch/x86_64/include/arch/memory/paging/page_table.hpp index 51ddcd4..60a0a2f 100644 --- a/arch/x86_64/include/arch/memory/paging/page_table.hpp +++ b/arch/x86_64/include/arch/memory/paging/page_table.hpp @@ -140,7 +140,7 @@ namespace teachos::arch::memory::paging page_table * table; ///< Handle to underlying page table, can never be null (invariant ensured by ///< constructor) level table_level; ///< Level page table is currently on, depends on how often next_level was - ///< called successfully. + ///< called successfuly. }; } // namespace teachos::arch::memory::paging diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp index a8cdc3a..681f960 100644 --- a/arch/x86_64/src/kernel/main.cpp +++ b/arch/x86_64/src/kernel/main.cpp @@ -37,7 +37,7 @@ namespace teachos::arch::kernel auto test8 = memory::multiboot::read_multiboot2(); if (test6 && test7 && test8.kernel_end) { - video::vga::text::write("Heap test successfull", video::vga::text::common_attributes::green_on_black); + video::vga::text::write("Heap test successful", video::vga::text::common_attributes::green_on_black); } test2->kernel_end = 2000; test2->kernel_start = 1000; diff --git a/arch/x86_64/src/memory/main.cpp b/arch/x86_64/src/memory/main.cpp index 5290061..b978319 100644 --- a/arch/x86_64/src/memory/main.cpp +++ b/arch/x86_64/src/memory/main.cpp @@ -43,11 +43,11 @@ namespace teachos::arch::memory paging::kernel_mapper kernel(allocator, memory_information); auto & active_table = kernel.remap_kernel(); - video::vga::text::write("Kernel remapping successfull", video::vga::text::common_attributes::green_on_black); + video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); remap_heap(allocator, active_table); - video::vga::text::write("Heap remapping successfull", video::vga::text::common_attributes::green_on_black); + video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); video::vga::text::newline(); } } // namespace teachos::arch::memory -- cgit v1.2.3