diff options
| -rw-r--r-- | .clang-format | 18 | ||||
| -rw-r--r-- | arch/x86_64/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp | 12 | ||||
| -rw-r--r-- | arch/x86_64/include/arch/memory/allocator/physical_frame.hpp | 86 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/address.hpp | 47 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/frame.hpp | 95 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/memory/region_allocator.hpp | 76 | ||||
| -rw-r--r-- | arch/x86_64/scripts/x86-64-linker-script.txt | 150 | ||||
| -rw-r--r-- | arch/x86_64/src/boot/boot.s | 2 | ||||
| -rw-r--r-- | arch/x86_64/src/memory.cpp | 90 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/allocator/physical_frame.cpp | 24 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/region_allocator.cpp | 95 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/impl/data.hpp | 6 | ||||
| -rw-r--r-- | libs/multiboot2/include/multiboot2/impl/iterator.hpp | 5 |
14 files changed, 538 insertions, 176 deletions
diff --git a/.clang-format b/.clang-format index d4da962..b32e8c9 100644 --- a/.clang-format +++ b/.clang-format @@ -40,15 +40,21 @@ DerivePointerAlignment: 'false' FixNamespaceComments: 'true' IncludeBlocks: Regroup IncludeCategories: - # Local Headers - - Regex: '"(.*/?)+/.+\.hpp"' + # Kernel Headers + - Regex: 'kern/[[:alnum:]._\/]+\.hpp' Priority: 100 + # Architecture Interface Headers + - Regex: 'arch/[[:alnum:]._\/]+\.hpp' + Priority: 110 + # Architecture Implementation Headers + - Regex: 'x86_64/[[:alnum:]._\/]+\.hpp' + Priority: 110 + # Library Headers + - Regex: '[[:alnum:]._\/]+\.hpp' + Priority: 300 # STL Headers - Regex: '<[[:alnum:]._]+(?!\.(h|hpp))>' - Priority: 400 - # C Library Headers - - Regex: '<([[:alnum:]._]/*)+\.h>' - Priority: 300 + Priority: 900 IndentCaseLabels: 'true' IndentPPDirectives: None IndentWidth: '2' diff --git a/arch/x86_64/CMakeLists.txt b/arch/x86_64/CMakeLists.txt index 86c9559..d1af777 100644 --- a/arch/x86_64/CMakeLists.txt +++ b/arch/x86_64/CMakeLists.txt @@ -41,6 +41,14 @@ target_sources("arch-x86_64" PRIVATE ) #[============================================================================[ +# Memory Code +#]============================================================================] + +target_sources("arch-x86_64" PRIVATE + "src/memory/region_allocator.cpp" +) + +#[============================================================================[ # VGA Code #]============================================================================] 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 6cb5f56..a86c9b7 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,12 +1,12 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP +#ifndef TEACHOS_X86_64_MEMORY_AREA_ALLOCATOR_HPP +#define TEACHOS_X86_64_MEMORY_AREA_ALLOCATOR_HPP -#include "arch/memory/allocator/physical_frame.hpp" -#include "arch/memory/multiboot/reader.hpp" +// #include "arch/memory/allocator/physical_frame.hpp" +// #include "arch/memory/multiboot/reader.hpp" #include <optional> -namespace teachos::arch::memory::allocator +namespace x86_64::memory { /** * @brief Allocates memory linearly using memory areas read from the multiboot2 information pointer and leaks any @@ -62,6 +62,6 @@ namespace teachos::arch::memory::allocator physical_frame const multiboot_end; ///< The end address of the multiboot code in memory. }; -} // namespace teachos::arch::memory::allocator +} // namespace x86_64::memory #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 deleted file mode 100644 index cb6c5b3..0000000 --- a/arch/x86_64/include/arch/memory/allocator/physical_frame.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP -#define TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP - -#include "arch/stl/container.hpp" -#include "arch/stl/forward_value_iterator.hpp" - -#include <compare> -#include <cstdint> -#include <iterator> - -namespace teachos::arch::memory::allocator -{ - using physical_address = std::size_t; - - 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 - * physical frame or not. - */ - struct physical_frame - { - /** - * @brief Defaulted constructor. - */ - constexpr physical_frame() = default; - - /** - * @brief Constructor. - * - * @param frame_number Index number that should be assigned to this physical frame. - */ - 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. - * - * @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(physical_address address) -> physical_frame; - - /** - * @brief Get the start address of this physical frame. - * - * @return Start address of the physical frame. - */ - auto start_address() const -> physical_address; - - /** - * @brief Post increment operator. Returns a copy of the value. - * - * @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 frame number. - */ - auto operator++() -> physical_frame &; - - /** - * @brief Defaulted equals operator. - */ - auto operator==(physical_frame const & other) const -> bool = default; - - /** - * @brief Defaulted three-way comparsion operator. - */ - auto operator<=>(physical_frame const & 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. - }; - - using frame_container = stl::container<stl::forward_value_iterator<physical_frame>>; - -} // namespace teachos::arch::memory::allocator - -#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_PHYSICAL_FRAME_HPP diff --git a/arch/x86_64/include/x86_64/memory/address.hpp b/arch/x86_64/include/x86_64/memory/address.hpp new file mode 100644 index 0000000..20e9655 --- /dev/null +++ b/arch/x86_64/include/x86_64/memory/address.hpp @@ -0,0 +1,47 @@ +#ifndef TEACHOS_X86_64_MEMORY_ADDRESS_HPP +#define TEACHOS_X86_64_MEMORY_ADDRESS_HPP + +#include <bit> +#include <compare> +#include <cstddef> +#include <cstdint> + +namespace teachos::x86_64::memory +{ + + enum struct address_type : bool + { + linear, + physical, + }; + + template<address_type Type> + struct address + { + constexpr explicit address(std::uintptr_t value) noexcept + : m_value{value} + { + } + + explicit address(std::byte * pointer) noexcept + : m_value{std::bit_cast<std::uintptr_t>(pointer)} + { + } + + explicit operator std::byte *() const noexcept { return std::bit_cast<std::byte *>(m_value); } + + auto constexpr operator<=>(address const &) const noexcept -> std::strong_ordering = default; + auto constexpr operator==(address const &) const noexcept -> bool = default; + + auto constexpr raw() const noexcept -> std::uintptr_t { return m_value; } + + private: + std::uintptr_t m_value{}; + }; + + using linear_address = address<address_type::linear>; + using physical_address = address<address_type::physical>; + +} // namespace teachos::x86_64::memory + +#endif
\ No newline at end of file diff --git a/arch/x86_64/include/x86_64/memory/frame.hpp b/arch/x86_64/include/x86_64/memory/frame.hpp new file mode 100644 index 0000000..21565fd --- /dev/null +++ b/arch/x86_64/include/x86_64/memory/frame.hpp @@ -0,0 +1,95 @@ +#ifndef TEACHOS_X86_64_MEMORY_FRAME_HPP +#define TEACHOS_X86_64_MEMORY_FRAME_HPP + +#include "x86_64/memory/address.hpp" + +#include <compare> +#include <cstddef> + +namespace teachos::x86_64::memory +{ + /** + * @brief Specific physical frame containing helper functions to determine if a specific address is in that + * physical frame or not. + */ + struct frame + { + auto static inline constexpr DEFAULT_SIZE = std::size_t{4096}; ///< Default page size of x86_84 is always 4KiB. + + /** + * @brief Defaulted constructor. + */ + constexpr frame() = default; + + /** + * @brief Constructor. + * + * @param frame_number Index number that should be assigned to this physical frame. + */ + explicit constexpr frame(std::size_t number) + : m_number(number) + { + } + + /** + * @brief Returns the physical frame the given address is contained in. + * + * @param address Physical address we want to get the corresponding physical frame for. + * @return Frame the given address is contained in. + */ + auto constexpr static containing(physical_address address) noexcept -> frame + { + return frame{address.raw() / DEFAULT_SIZE}; + } + + /** + * @brief Get the start address of this physical frame. + * + * @return Start address of the physical frame. + */ + auto constexpr start_address() const noexcept -> physical_address + { + return physical_address{m_number * DEFAULT_SIZE}; + } + + auto constexpr operator+(std::size_t offset) const noexcept -> frame { return frame{m_number + offset}; } + + /** + * @brief Post increment operator. Returns a copy of the value. + * + * @return Copy of the incremented underlying frame number. + */ + auto constexpr operator++(int) noexcept -> frame + { + auto copy = *this; + return ++copy; + } + + /** + * @brief Pre increment operator. Returns a reference to the changed value. + * + * @return Reference to the incremented underlying frame number. + */ + auto constexpr operator++() noexcept -> frame & + { + ++m_number; + return *this; + } + + /** + * @brief Defaulted equals operator. + */ + auto constexpr operator==(frame const & other) const noexcept -> bool = default; + + /** + * @brief Defaulted three-way comparison operator. + */ + auto constexpr operator<=>(frame const & other) const noexcept -> std::strong_ordering = default; + + private: + std::size_t m_number{}; ///< Index number of the current physical frame, used to distinguish it from other frames. + }; + +} // namespace teachos::x86_64::memory + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_frame_HPP diff --git a/arch/x86_64/include/x86_64/memory/region_allocator.hpp b/arch/x86_64/include/x86_64/memory/region_allocator.hpp new file mode 100644 index 0000000..23bea10 --- /dev/null +++ b/arch/x86_64/include/x86_64/memory/region_allocator.hpp @@ -0,0 +1,76 @@ +#ifndef TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP +#define TEACHOS_X86_64_MEMORY_REGION_ALLOCATOR_HPP + +#include "x86_64/memory/address.hpp" +#include "x86_64/memory/frame.hpp" + +#include <multiboot2/information.hpp> + +#include <optional> +#include <utility> + +namespace teachos::x86_64::memory +{ + /** + * @brief Allocates memory linearly using memory areas read from the multiboot2 information pointer and leaks any + * deallocated frames. + */ + struct region_allocator + { + struct memory_information + { + std::pair<physical_address, physical_address> image_range; + std::pair<physical_address, physical_address> mbi_range; + multiboot2::memory_map memory_map; + }; + + /** + * @brief Constructor. + * + * @param mem_info Structure containing all relevant information to map and allocate memory. + */ + explicit region_allocator(memory_information const & mem_info); + + /** + * @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 + * 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 + * + * @return next free physical frame or nullopt if none was found. + */ + auto allocate_frame() -> std::optional<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 been allocated in the first place. + * + * @param physical_frame Previously allocated physical_frame that should be deallocated. + */ + auto deallocate_frame(frame const & physical_frame) -> void; + + private: + /** + * @brief Find the next memory area and write it into current_area. + */ + auto choose_next_area() -> void; + + frame m_next_frame; ///< The physical_frame after the last allocated one. + std::optional<multiboot2::memory_map::region> m_current_region; ///< The memory region currently allocated from + multiboot2::memory_map m_memory_map; ///< The boot loader supplied memory map. + frame const m_kernel_start; ///< The start address of the kernel code in memory. + frame const m_kernel_end; ///< The end address of the kernel code in memory. + frame const m_multiboot_start; ///< The start address of the multiboot code in memory. + frame const m_multiboot_end; ///< The end address of the multiboot code in memory. + }; + +} // namespace teachos::x86_64::memory + +#endif // TEACHOS_ARCH_X86_64_MEMORY_ALLOCATOR_AREA_FRAME_ALLOCATOR_HPP diff --git a/arch/x86_64/scripts/x86-64-linker-script.txt b/arch/x86_64/scripts/x86-64-linker-script.txt new file mode 100644 index 0000000..3d9a7ae --- /dev/null +++ b/arch/x86_64/scripts/x86-64-linker-script.txt @@ -0,0 +1,150 @@ +ENTRY(_start) + +/***************************************************************************** + * Virtual and linear start addresses of the TeachOS kernel + *****************************************************************************/ +TEACHOS_LOW = 1M; + +PHDRS { + boot_rodata PT_LOAD FLAGS(4); + boot_text PT_LOAD FLAGS(5); + boot_data PT_LOAD FLAGS(6); + + text PT_LOAD FLAGS(5); + data PT_LOAD FLAGS(6); + rodata PT_LOAD FLAGS(4); +} + +SECTIONS +{ + /*************************************************************************** + * Load the bootstrap code into low memory. We need to be accessible in + * 32-Bit mode, so we want to live down low, but we need to leave the 1MiB + * hole open since some BIOS functionality resides below it. + ***************************************************************************/ + . = TEACHOS_LOW; + + /*************************************************************************** + * We want to be able to be able to access all memory (linear and virtual) + * during bootstrapping and operation. To achieve this, we define some + * symbols at the beginning. + ***************************************************************************/ + _start_linear = .; + _start_virtual = .; + + /*************************************************************************** + * The bootstrapping infratructure goes first. We first place the read-only + * data, followed by our code, initialized mutable data, and finally our + * uninitialized mutable data. + ***************************************************************************/ + .boot_rodata ALIGN(4K) : AT(ADDR (.boot_rodata)) + { + KEEP(*(.boot_mbh)) + *(.boot_rodata) + } :boot_rodata + + .boot_text ALIGN(4K) : AT(ADDR (.boot_text)) + { + *(.boot_text) + } :boot_text + + .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. + ***************************************************************************/ + .init ALIGN(4K) : AT(ADDR (.init)) + { + /* + * Make sure that the crt code is wrapped around the compiler generated + * initialization code. + */ + KEEP(*crti.s.o*(.init)) + KEEP(*(EXCLUDE_FILE (*crti.s.o* *crtn.s.o*) .init)) + KEEP(*crtn.s.o*(.init)) + } :text + + .fini ALIGN(4K) : AT(ADDR (.fini)) + { + /* + * Make sure that the crt code is wrapped around the compiler generated + * finalizer code. + */ + KEEP(*crti.s.o*(.fini)) + KEEP(*(EXCLUDE_FILE (*crti.s.o* *crtn.s.o*) .fini)) + KEEP(*crtn.s.o*(.fini)) + } + + .stl_text ALIGN(4K) : AT(ADDR (.stl_text)) + { + *(.stl_text .stl_text*) + KEEP(*libstdc++.a:*(.text .text.*)) + } + + .text ALIGN(4K) : AT(ADDR (.text)) + { + *(.text .text.*) + } + + .user_text ALIGN(4K) : AT(ADDR (.user_text)) + { + *(.user_text .user_text.*) + } + + .rodata ALIGN(4K) : AT (ADDR (.rodata)) + { + *(.rodata) + *(.rodata.*) + } :rodata + + .ctors ALIGN(4K) : AT (ADDR (.ctors)) + { + KEEP(*crtbegin.o(.ctors)) + KEEP(*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP(*(SORT(.ctors.*))) + KEEP(*crtend.o(.ctors)) + } :data + + .dtors ALIGN(4K) : AT (ADDR (.dtors)) + { + KEEP(*crtbegin.o(.dtors)) + KEEP(*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP(*(SORT(.dtors.*))) + KEEP(*crtend.o(.dtors)) + } + + .bss ALIGN(4K) : AT (ADDR (.bss)) + { + *(COMMON) + *(.bss*) + } + + .data ALIGN(4K) : AT (ADDR (.data)) + { + *(.data*) + } + + .user_data ALIGN(4K) : AT (ADDR (.user_data)) + { + *(.user_data .user_data.*) + } + + /*************************************************************************** + * In accordance with the symbol definitions at the start, we generate some + * symbols to mark the end of our loaded image. + ***************************************************************************/ + _end_virtual = ADDR(.bss) + SIZEOF(.bss); + _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 ada6426..e0cff7c 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -12,7 +12,7 @@ * Reserve some space for the Multiboot 2 information pointer. */ .global multiboot_information_pointer -multiboot_information_pointer: .skip 4 +multiboot_information_pointer: .skip 8 /** * Align page maps to 4 KiB or the assembler code, will cause crashes when attempting to enable paging. diff --git a/arch/x86_64/src/memory.cpp b/arch/x86_64/src/memory.cpp index 245d7bd..2b16beb 100644 --- a/arch/x86_64/src/memory.cpp +++ b/arch/x86_64/src/memory.cpp @@ -1,62 +1,54 @@ #include "arch/memory.hpp" -// #include "noarch/error.hpp" -// #include "noarch/print.hpp" -// #include "x86_64/bootstrap/mutiboot.hpp" -// #include "x86_64/memory/frame_allocator.hpp" -// #include "x86_64/memory/mbi_frame_allocator.hpp" +#include "kern/error.hpp" -// #include <elf/constants.hpp> -// #include <elf/section_header.hpp> -// #include <elf/section_header_table.hpp> -// #include <multiboot2/information.hpp> +#include "arch/asm_pointer.hpp" +#include "x86_64/memory/region_allocator.hpp" -namespace teachos::arch::memory -{ +#include <multiboot2/information.hpp> - // namespace - // { - // /** - // * @brief Remap the kernel according to the ELF information. - // * - // * After initial bootup, a basic identity mapping of the lower 1GiB is set up. This mapping allows execution - // from, - // * as well as read and write access to, the mapped memory. In order to protect the kernel, remap it according to - // the - // * information supplied by the ELF file. This means remapping code sections as read-only and data sections as - // * no-execute (and read only for .rodata). - // * - // * @param sections Information about the sections in the loaded kernel binary. - // * @param allocator The frame allocator used to create new page mappings. - // */ - // auto remap_kernel(elf::section_header_table const & sections, x86_64::memory::frame_allocator & allocator) -> - // void - // { - // static_cast<void>(sections); - // static_cast<void>(allocator); - // } - // } // namespace +#include <atomic> - auto init() -> void - { - // kernel::println("Initializing memory"); +extern "C" teachos::arch::asm_pointer<multiboot2::information_view> multiboot_information_pointer; - // if (!x86_64::bootstrap::multiboot_information_pointer->has<multiboot2::memory_map>()) - // { - // kernel::panic("Received no memory map from the boot loader!"); - // } +namespace teachos::arch::memory +{ + namespace + { + auto constinit is_initialized = std::atomic_flag{}; - // if (!x86_64::bootstrap::multiboot_information_pointer->has<multiboot2::elf_symbols>()) - // { - // kernel::panic("Received no ELF symbol information from the boot loader!"); - // } + // auto create_memory_information() -> x86_64::memory::region_allocator::memory_information { - // auto memory_map = x86_64::bootstrap::multiboot_information_pointer->memory_map(); - // auto elf_symbols = x86_64::bootstrap::multiboot_information_pointer->elf_symbols(); - // auto section_header_table = elf::section_header_table{elf_symbols.data(), elf::file_class::bits_64}; - // auto allocator = x86_64::memory::mbi_frame_allocator{memory_map, section_header_table}; + // }; + } // namespace - // remap_kernel(section_header_table, allocator); + auto init() -> void + { + if (is_initialized.test_and_set()) + { + teachos::panic("[x86_64] Memory management has already been initialized."); + } + + auto memory_map = multiboot_information_pointer->maybe_memory_map(); + if (!memory_map) + { + teachos::panic("[x86_64] No memory map available."); + } + + // auto mem_info = x86_64::memory::region_allocator::memory_information{}; + // auto allocator = x86_64::memory::region_allocator{mem_info}; + + // kernel::cpu::set_cr0_bit(kernel::cpu::cr0_flags::WRITE_PROTECT); + // kernel::cpu::set_efer_bit(kernel::cpu::efer_flags::NXE); + + // paging::kernel_mapper kernel(allocator, memory_information); + // kernel.remap_kernel(); + // video::vga::text::write("Kernel remapping successful", video::vga::text::common_attributes::green_on_black); + // video::vga::text::newline(); + + // remap_heap(heap::KERNEL_HEAP_START, heap::KERNEL_HEAP_SIZE); + // video::vga::text::write("Heap remapping successful", video::vga::text::common_attributes::green_on_black); + // video::vga::text::newline(); } } // namespace teachos::arch::memory diff --git a/arch/x86_64/src/memory/allocator/physical_frame.cpp b/arch/x86_64/src/memory/allocator/physical_frame.cpp deleted file mode 100644 index ec387a1..0000000 --- a/arch/x86_64/src/memory/allocator/physical_frame.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "arch/memory/allocator/physical_frame.hpp" - -namespace teachos::arch::memory::allocator -{ - auto physical_frame::containing_address(physical_address address) -> physical_frame - { - return physical_frame{address / PAGE_FRAME_SIZE}; - } - - auto physical_frame::start_address() const -> physical_address { return frame_number * PAGE_FRAME_SIZE; } - - auto physical_frame::operator++(int) -> physical_frame - { - physical_frame const old_value = *this; - ++frame_number; - return old_value; - } - - auto physical_frame::operator++() -> physical_frame & - { - ++frame_number; - return *this; - } -} // namespace teachos::arch::memory::allocator diff --git a/arch/x86_64/src/memory/region_allocator.cpp b/arch/x86_64/src/memory/region_allocator.cpp new file mode 100644 index 0000000..c9a98b4 --- /dev/null +++ b/arch/x86_64/src/memory/region_allocator.cpp @@ -0,0 +1,95 @@ +// #include "arch/memory/allocator/region_allocator.hpp" + +// #include "arch/exception_handling/assert.hpp" + +// #include <algorithm> +// #include <array> +// #include <ranges> + +#include "x86_64/memory/region_allocator.hpp" + +#include "x86_64/memory/address.hpp" +#include "x86_64/memory/frame.hpp" + +#include <multiboot2/information.hpp> + +#include <algorithm> +#include <ranges> + +namespace teachos::x86_64::memory +{ + namespace + { + auto constexpr last_frame(multiboot2::memory_map::region const & region) + { + return frame::containing(physical_address{region.base + region.size_in_B - 1}); + } + } // namespace + + region_allocator::region_allocator(memory_information const & mem_info) + : m_next_frame{} + , m_current_region{} + , m_memory_map{} + , m_kernel_start(frame::containing(mem_info.image_range.first)) + , m_kernel_end(frame::containing(mem_info.image_range.second)) + , m_multiboot_start(frame::containing(mem_info.mbi_range.first)) + , m_multiboot_end(frame::containing(mem_info.mbi_range.second)) + { + choose_next_area(); + } + + auto region_allocator::choose_next_area() -> void + { + m_current_region.reset(); + auto next_area_with_free_frames = + m_memory_map | std::views::filter(&multiboot2::memory_map::region::available) | + std::views::filter([next = m_next_frame](auto const & region) { return last_frame(region) >= next; }); + + auto lowest_region_with_free_frames = + std::ranges::min_element(next_area_with_free_frames, [](auto lhs, auto rhs) { return lhs.base < rhs.base; }); + + if (lowest_region_with_free_frames != next_area_with_free_frames.end()) + { + m_current_region = *lowest_region_with_free_frames; + auto start_frame = frame::containing(physical_address{m_current_region->base}); + if (m_next_frame < start_frame) + { + m_next_frame = start_frame; + } + } + } + + auto region_allocator::allocate_frame() -> std::optional<frame> + { + if (!m_current_region) + { + return {}; + } + + auto const end_address = physical_address{m_current_region->base + m_current_region->size_in_B - 1}; + auto end_frame = frame::containing(end_address); + + if (m_next_frame > end_frame) + { + choose_next_area(); + } + else if (m_next_frame >= m_kernel_start && m_next_frame <= m_kernel_end) + { + m_next_frame = m_kernel_end + 1; + } + else if (m_next_frame >= m_multiboot_start && m_next_frame <= m_multiboot_end) + { + m_next_frame = m_multiboot_end + 1; + } + else + { + auto allocated = m_next_frame; + ++m_next_frame; + return allocated; + } + + return allocate_frame(); + } + + auto region_allocator::deallocate_frame(frame const &) -> void {} +} // namespace teachos::x86_64::memory diff --git a/libs/multiboot2/include/multiboot2/impl/data.hpp b/libs/multiboot2/include/multiboot2/impl/data.hpp index 367e8cb..a5f2e14 100644 --- a/libs/multiboot2/include/multiboot2/impl/data.hpp +++ b/libs/multiboot2/include/multiboot2/impl/data.hpp @@ -99,17 +99,17 @@ namespace multiboot2::impl /** * @brief Start address of this region */ - std::uint64_t const base; + std::uint64_t base; /** * @brief Size of this region in bytes. */ - std::uint64_t const size_in_B; + std::uint64_t size_in_B; /** * @brief Type of this region. */ - memory_type const type; + memory_type type; std::uint32_t : 0; }; diff --git a/libs/multiboot2/include/multiboot2/impl/iterator.hpp b/libs/multiboot2/include/multiboot2/impl/iterator.hpp index b84ef2c..e82326d 100644 --- a/libs/multiboot2/include/multiboot2/impl/iterator.hpp +++ b/libs/multiboot2/include/multiboot2/impl/iterator.hpp @@ -40,7 +40,10 @@ namespace multiboot2::impl { m_current = next; } - m_current.reset(); + else + { + m_current.reset(); + } } return *this; } |
