diff options
Diffstat (limited to 'arch/x86_64/src/memory')
| -rw-r--r-- | arch/x86_64/src/memory/allocator/area_frame_allocator.cpp | 95 | ||||
| -rw-r--r-- | arch/x86_64/src/memory/multiboot/memory_map.cpp | 59 |
2 files changed, 97 insertions, 57 deletions
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 05b828c..6ed4f28 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 <algorithm> +#include <array> +#include <ranges> + 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)) @@ -20,26 +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; + }); - for (multiboot::memory_area_iterator it = begin(); it != end(); ++it) - { - multiboot::memory_area & area = *it; + 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::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.has_value() || area.base_address < current_area.value().base_address) - { - current_area.emplace(area); - } - } - } - - if (current_area.has_value()) + 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; @@ -53,41 +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.has_value()) + if (!current_area.has_value()) { - 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 >= kernel_start && physical_frame <= kernel_end) - { - // `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 - 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 @@ -95,8 +90,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..b5e2759 100644 --- a/arch/x86_64/src/memory/multiboot/memory_map.cpp +++ b/arch/x86_64/src/memory/multiboot/memory_map.cpp @@ -1,19 +1,24 @@ #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) + memory_area_iterator::memory_area_iterator(value_type * 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; } + 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 & @@ -21,4 +26,48 @@ namespace teachos::arch::memory::multiboot ++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 |
