aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--arch/x86_64/src/kapi/memory.cpp27
-rw-r--r--kapi/include/kapi/memory.hpp59
-rw-r--r--src/kapi/memory.cpp91
4 files changed, 136 insertions, 42 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d973268..f0c5a20 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -76,6 +76,7 @@ add_executable("kernel"
# Platform Independent KAPI implementation
"src/kapi/cio.cpp"
+ "src/kapi/memory.cpp"
"src/kapi/system.cpp"
)
diff --git a/arch/x86_64/src/kapi/memory.cpp b/arch/x86_64/src/kapi/memory.cpp
index 748893a..abfb32e 100644
--- a/arch/x86_64/src/kapi/memory.cpp
+++ b/arch/x86_64/src/kapi/memory.cpp
@@ -21,19 +21,17 @@
#include <atomic>
#include <bit>
+#include <cstddef>
+#include <cstdint>
#include <memory>
#include <span>
+#include <utility>
namespace teachos::memory
{
namespace
{
- // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
- auto constinit allocator = static_cast<frame_allocator *>(nullptr);
- // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
- auto constinit mapper = static_cast<page_mapper *>(nullptr);
-
constexpr auto static unused_page_address = linear_address{0x0000'7fff'cafe'faceuz};
constexpr auto static recursive_page_map_index = x86_64::page_table::entry_count - 2;
@@ -152,25 +150,6 @@ namespace teachos::memory
} // namespace
- auto active_frame_allocator() -> frame_allocator &
- {
- if (!allocator)
- {
- system::panic("[x86_64] The frame allocator has not been set yet.");
- }
-
- return *allocator;
- }
-
- auto active_page_mapper() -> page_mapper &
- {
- if (!mapper)
- {
- system::panic("[x86_64] The page mapper has not been set you.");
- }
- return *mapper;
- }
-
auto init() -> void
{
auto static constinit is_initialized = std::atomic_flag{};
diff --git a/kapi/include/kapi/memory.hpp b/kapi/include/kapi/memory.hpp
index bed8dbc..b51a8a5 100644
--- a/kapi/include/kapi/memory.hpp
+++ b/kapi/include/kapi/memory.hpp
@@ -8,39 +8,62 @@
#include "kapi/memory/page.hpp" // IWYU pragma: export
#include "kapi/memory/page_mapper.hpp" // IWYU pragma: export
+#include <cstddef>
+#include <optional>
+
namespace teachos::memory
{
//! @qualifier platform-defined
- //! Get the currently active frame allocator.
+ //! Initialize the memory subsystem.
//!
//! @note This function must be implemented by the target platform.
//!
- //! @warning If no allocator has been initialized yet, the behavior of this function is platform implementation
- //! defined. Implementations are encouraged to terminate execution via a kernel panic.
+ //! This function initializes the memory subsystem and activates the platform-specific frame allocator and page
+ //! mapper. When this function returns, a valid frame allocator and page mapper are expected to have been registered.
+ auto init() -> void;
+
+ //! @qualifier kernel-defined
+ //! Set the currently active frame allocator.
//!
- //! @return A reference to the currently active frame allocator.
- auto active_frame_allocator() -> frame_allocator &;
+ //! @param allocator A new frame allocator.
+ //! @return The previously active frame allocator.
+ auto set_frame_allocator(frame_allocator & allocator) -> std::optional<frame_allocator *>;
- //! @qualifier platform-defined
- //! Get the currently active page mapper.
+ //! @qualifier kernel-defined
+ //! Set the currently active page mapper.
//!
- //! @note This function must be implemented by the target platform.
+ //! @param mapper A new page mapper.
+ //! @return The previously active page mapper.
+ auto set_page_mapper(page_mapper & mapper) -> std::optional<page_mapper *>;
+
+ //! @qualifier kernel-defined
+ //! Allocate a new frame of physical memory
//!
- //! @warning If no mapper has been initialized yet, the behavior of this function is platform implementation
- //! defined. Implementations are encouraged to terminate execution via a kernel panic.
+ //! @warning This function will panic if no frame allocator has been registered.
//!
- //! @return A reference to the currently active page mapper.
- auto active_page_mapper() -> page_mapper &;
+ //! @return An engaged std::optional iff. a frame could be allocated, std::nullopt otherwise.
+ auto allocate_frame() -> std::optional<frame>;
- //! @qualifier platform-defined
- //! Initialize the memory subsystem.
+ //! @qualifier kernel-defined
+ //! Map a page onto a frame.
//!
- //! @note This function must be implemented by the target platform.
+ //! @warning This function will panic if no page mapper has been registered, or the page has already been mapped.
+ //! This function will not ensure that the frame is not already in use.
//!
- //! This function initializes the memory subsystem and activates the platform-specific frame allocator and page
- //! mapper. When this function returns, a valid frame allocator and page mapper are expected to have been registered.
- auto init() -> void;
+ //! @param page The page to map.
+ //! @param frame The frame to map the page into.
+ //! @return A pointer to the first byte of the mapped page.
+ auto map(page page, frame frame) -> std::byte *;
+
+ //! @qualifier kernel-defined
+ //! Unmap a page.
+ //!
+ //! @warning This function will panic if no page mapper has been registered, or the page has already been mapped.
+ //! This function will not ensure that the frame is not already in use.
+ //!
+ //! @param page The page to unmap
+ auto unmap(page page) -> void;
} // namespace teachos::memory
diff --git a/src/kapi/memory.cpp b/src/kapi/memory.cpp
new file mode 100644
index 0000000..d6c84e1
--- /dev/null
+++ b/src/kapi/memory.cpp
@@ -0,0 +1,91 @@
+#include "kapi/memory.hpp"
+
+#include "kapi/system.hpp"
+
+#include <cstddef>
+#include <optional>
+#include <utility>
+
+namespace teachos::memory
+{
+
+ namespace
+ {
+ struct bad_frame_allocator final : public frame_allocator
+ {
+ bad_frame_allocator static instance;
+
+ auto allocate() noexcept -> std::optional<frame> override
+ {
+ system::panic("Tried to allocate a frame without an active allocator.");
+ }
+
+ auto release(frame) -> void override
+ {
+ system::panic("Tried to release a frame without an active allocator.");
+ }
+ };
+
+ struct bad_page_mapper final : public page_mapper
+ {
+ bad_page_mapper static instance;
+
+ auto map(page, frame, flags) -> std::byte * override
+ {
+ system::panic("Tried to map a page without an active mapper.");
+ }
+
+ auto unmap(page) -> void override
+ {
+ system::panic("Tried to unmap a page without an active mapper.");
+ }
+
+ auto try_unmap(page) noexcept -> bool override
+ {
+ return false;
+ }
+ };
+
+ constinit bad_frame_allocator bad_frame_allocator::instance{};
+ constinit bad_page_mapper bad_page_mapper::instance{};
+ } // namespace
+
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+ constinit auto active_frame_allocator = static_cast<frame_allocator *>(&bad_frame_allocator::instance);
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+ constinit auto active_page_mapper = static_cast<page_mapper *>(&bad_page_mapper::instance);
+
+ auto set_frame_allocator(frame_allocator & allocator) -> std::optional<frame_allocator *>
+ {
+ if (&allocator == active_frame_allocator)
+ {
+ return {};
+ }
+ return std::exchange(active_frame_allocator, &allocator);
+ }
+
+ auto set_page_mapper(page_mapper & mapper) -> std::optional<page_mapper *>
+ {
+ if (&mapper == active_page_mapper)
+ {
+ return {};
+ }
+ return std::exchange(active_page_mapper, &mapper);
+ }
+
+ auto allocate_frame() -> std::optional<frame>
+ {
+ return active_frame_allocator->allocate();
+ }
+
+ auto map(page page, frame frame) -> std::byte *
+ {
+ return active_page_mapper->map(page, frame, page_mapper::flags::empty);
+ }
+
+ auto unmap(page page) -> void
+ {
+ return active_page_mapper->unmap(page);
+ }
+
+} // namespace teachos::memory \ No newline at end of file