aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format18
-rw-r--r--arch/x86_64/CMakeLists.txt8
-rw-r--r--arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp12
-rw-r--r--arch/x86_64/include/arch/memory/allocator/physical_frame.hpp86
-rw-r--r--arch/x86_64/include/x86_64/memory/address.hpp47
-rw-r--r--arch/x86_64/include/x86_64/memory/frame.hpp95
-rw-r--r--arch/x86_64/include/x86_64/memory/region_allocator.hpp76
-rw-r--r--arch/x86_64/scripts/x86-64-linker-script.txt150
-rw-r--r--arch/x86_64/src/boot/boot.s2
-rw-r--r--arch/x86_64/src/memory.cpp90
-rw-r--r--arch/x86_64/src/memory/allocator/physical_frame.cpp24
-rw-r--r--arch/x86_64/src/memory/region_allocator.cpp95
-rw-r--r--libs/multiboot2/include/multiboot2/impl/data.hpp6
-rw-r--r--libs/multiboot2/include/multiboot2/impl/iterator.hpp5
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;
}