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 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'arch/x86_64') 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 -- 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(-) (limited to 'arch/x86_64') 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 +++++++++++----- 5 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 arch/x86_64/include/arch/boot/multiboot.hpp (limited to 'arch/x86_64') 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 -- 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(+) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 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 --- 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 +- 7 files changed, 62 insertions(+), 52 deletions(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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 --- 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 +++----- 8 files changed, 104 insertions(+), 135 deletions(-) create mode 100644 arch/x86_64/include/arch/exception_handling/assert.hpp create mode 100644 arch/x86_64/src/exception_handling/assert.cpp (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(+) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 +++++++++++++++++++++ 11 files changed, 112 insertions(+), 18 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 (limited to 'arch/x86_64') 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; -- 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(+) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 +-- 12 files changed, 171 insertions(+), 150 deletions(-) (limited to 'arch/x86_64') 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. -- 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(+) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(+) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 --- 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 ++--- 4 files changed, 5 insertions(+), 9 deletions(-) (limited to 'arch/x86_64') 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 47ec911e3b3624d875da5b9cc0102e3d17a6d54a Mon Sep 17 00:00:00 2001 From: Fabian Imhof Date: Sat, 26 Oct 2024 10:09:46 +0000 Subject: use linker variable --- arch/x86_64/src/memory/paging/page_table.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(+) (limited to 'arch/x86_64') 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(+) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 +- 12 files changed, 71 insertions(+), 70 deletions(-) (limited to 'arch/x86_64') 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}; } -- 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(+) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(+) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(+) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 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 (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(+) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(+) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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 (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(+) (limited to 'arch/x86_64') 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 +++ 1 file changed, 3 insertions(+) (limited to 'arch/x86_64') 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 -- 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(-) (limited to 'arch/x86_64') 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 --- arch/x86_64/include/arch/memory/allocator/concept.hpp | 4 +--- arch/x86_64/include/arch/memory/heap/concept.hpp | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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(-) (limited to 'arch/x86_64') 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