aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp28
-rw-r--r--arch/x86_64/include/arch/memory/multiboot/memory_map.hpp146
-rw-r--r--arch/x86_64/include/arch/memory/paging/page_mapper.hpp2
-rw-r--r--arch/x86_64/src/kernel/main.cpp5
-rw-r--r--arch/x86_64/src/memory/allocator/area_frame_allocator.cpp95
-rw-r--r--arch/x86_64/src/memory/multiboot/memory_map.cpp59
6 files changed, 242 insertions, 93 deletions
diff --git a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp
index a1b771e..8e971f0 100644
--- a/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp
+++ b/arch/x86_64/include/arch/memory/allocator/area_frame_allocator.hpp
@@ -45,22 +45,6 @@ namespace teachos::arch::memory::allocator
*/
auto deallocate_frame(physical_frame physical_frame) -> void;
- /**
- * @brief Returns the iterator pointing to the first element of the memory area.
- * Allows using this class in the for each loop, because it follows the InputIterator template scheme.
- *
- * @return Iterator pointing to first element of the memory area.
- */
- auto begin() -> multiboot::memory_area_iterator;
-
- /**
- * @brief Returns the iterator pointing to one past the last element of the memory area.
- * Allows using this class in the for each loop, because it follows the InputIterator template scheme.
- *
- * @return Iterator pointing to one past the last element of the memory area.
- */
- auto end() -> multiboot::memory_area_iterator;
-
private:
/**
* @brief Find the next memory area and write it into current_area.
@@ -69,12 +53,12 @@ namespace teachos::arch::memory::allocator
physical_frame next_free_frame; ///< The physical_frame after the last allocated one.
std::optional<multiboot::memory_area> 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..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 <cstdint>
+#include <iterator>
namespace teachos::arch::memory::multiboot
{
@@ -44,48 +45,175 @@ 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.
+ */
+ 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
+ * 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.
*
* @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.
+ */
+ 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
*/
- bool operator==(memory_area_iterator const & other) const = default;
+ auto empty() const -> bool;
private:
- memory_area * ptr; ///< Underlying address the iterator is currently pointing too.
+ 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/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);
}
diff --git a/arch/x86_64/src/kernel/main.cpp b/arch/x86_64/src/kernel/main.cpp
index ad1eb39..5186c21 100644
--- a/arch/x86_64/src/kernel/main.cpp
+++ b/arch/x86_64/src/kernel/main.cpp
@@ -22,11 +22,8 @@ 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 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 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