diff options
| -rw-r--r-- | CMakeLists.txt | 1 | ||||
| -rw-r--r-- | arch/x86_64/src/kapi/memory.cpp | 27 | ||||
| -rw-r--r-- | kapi/include/kapi/memory.hpp | 59 | ||||
| -rw-r--r-- | src/kapi/memory.cpp | 91 |
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 |
