diff options
| -rw-r--r-- | arch/x86_64/include/arch/memory/page_table.hpp | 6 | ||||
| -rw-r--r-- | arch/x86_64/kapi/memory.cpp | 1 | ||||
| -rw-r--r-- | kapi/include/kapi/memory.hpp | 30 | ||||
| -rw-r--r-- | kernel/CMakeLists.txt | 41 | ||||
| -rw-r--r-- | kernel/include/kernel/memory/mmio_allocator.hpp | 41 | ||||
| -rw-r--r-- | kernel/kapi/memory.cpp | 25 | ||||
| -rw-r--r-- | kernel/src/memory/mmio_allocator.cpp | 107 |
7 files changed, 228 insertions, 23 deletions
diff --git a/arch/x86_64/include/arch/memory/page_table.hpp b/arch/x86_64/include/arch/memory/page_table.hpp index 3cbb0af..c75ccaf 100644 --- a/arch/x86_64/include/arch/memory/page_table.hpp +++ b/arch/x86_64/include/arch/memory/page_table.hpp @@ -174,7 +174,7 @@ namespace arch::memory result |= mapper_flags::writable; } - if ((flags & table_flags::disable_cache) != table_flags::empty) + if ((flags & (table_flags::disable_cache | table_flags::write_through)) != table_flags::empty) { result |= mapper_flags::uncached; } @@ -211,7 +211,7 @@ namespace arch::memory if ((flags & mapper_flags::uncached) != mapper_flags::empty) { - result |= table_flags::disable_cache; + result |= (table_flags::disable_cache | table_flags::write_through); } if ((flags & mapper_flags::supervisor_only) == mapper_flags::empty) @@ -229,4 +229,4 @@ namespace arch::memory } // namespace arch::memory -#endif
\ No newline at end of file +#endif diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index 5f12e5c..853639c 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -245,6 +245,7 @@ namespace kapi::memory [](auto const & region) { return region.base + region.size_in_B; })); init_pmm(frame::containing(physical_address{highest_byte}).number() + 1, handoff_to_kernel_pmm); + init_mmio(mmio_base, 1_GiB / page::size); kstd::println("[x86_64:MEM] Releasing bootstrap memory allocators."); region_based_allocator.reset(); diff --git a/kapi/include/kapi/memory.hpp b/kapi/include/kapi/memory.hpp index 914ca61..ae33904 100644 --- a/kapi/include/kapi/memory.hpp +++ b/kapi/include/kapi/memory.hpp @@ -79,6 +79,36 @@ namespace kapi::memory //! @param page The page to unmap auto unmap(page page) -> void; + //! Initialize the Memory-mapped I/O region system. + //! + //! @param base The base address for the MMIO region. + //! @param page_count The number of pages the MMIO region is spans. + auto init_mmio(linear_address base, std::size_t page_count) -> void; + + //! Allocate a Memory-mapped I/O region of the given size. + //! + //! @warning This function will panic if the MMIO system has not been initialized! + //! @param page_count The number of pages to allocate. + auto allocate_mmio_region(std::size_t page_count) -> linear_address; + + //! Map a region of Memory-mapped I/O address space to a given hardware address using the given flags. + //! + //! @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 will always set the @p uncached flag. + //! + //! @param base The base of the virtual region. + //! @param hw_base The base of the hardware region. + //! @param flags The flags to apply. + auto map_mmio_region(linear_address base, physical_address hw_base, page_mapper::flags flags = {}) -> std::byte *; + + //! Release a Memory-mapped I/O region. + //! + //! @warning This function will panic if the MMIO system has not been initialized! + //! @param base The start address of the region to release. + auto release_mmio_region(linear_address base) -> void; + //! @} //! @addtogroup kapi-memory-platform-defined diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index ef73586..67db0a8 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -20,6 +20,7 @@ add_library("kernel_objs" OBJECT "src/acpi/manager.cpp" "src/memory/bitmap_allocator.cpp" "src/memory/block_list_allocator.cpp" + "src/memory/mmio_allocator.cpp" "src/memory.cpp" "src/devices/block_device.cpp" "src/devices/block_device_utils.cpp" @@ -66,37 +67,37 @@ target_sources("kernel_objs" PUBLIC add_library("os::kernel" ALIAS "kernel_objs") if(CMAKE_CROSSCOMPILING) - add_executable("kernel" + add_executable("kernel" "src/main.cpp" "src/memory/operators.cpp" ) - target_link_libraries("kernel" PRIVATE + target_link_libraries("kernel" PRIVATE "os::arch" "os::kernel" ) - target_link_options("kernel" PRIVATE + target_link_options("kernel" PRIVATE "-T${KERNEL_LINKER_SCRIPT}" "-no-pie" "-nostdlib" ) - set_property(TARGET "kernel" + set_property(TARGET "kernel" APPEND PROPERTY LINK_DEPENDS "${KERNEL_LINKER_SCRIPT}" ) - target_disassemble("kernel") - target_extract_debug_symbols("kernel") - target_strip("kernel") + target_disassemble("kernel") + target_extract_debug_symbols("kernel") + target_strip("kernel") - target_generate_bootable_iso("kernel") + target_generate_bootable_iso("kernel") else() - enable_coverage("kernel_objs") + enable_coverage("kernel_objs") - add_library("kernel_test_support" OBJECT + add_library("kernel_test_support" OBJECT "src/test_support/kapi/cpu.cpp" "src/test_support/kapi/cio.cpp" "src/test_support/kapi/interrupts.cpp" @@ -108,21 +109,21 @@ else() "src/test_support/simulated_memory.cpp" "src/test_support/state_reset_listener.cpp" ) - add_library("os::kernel_test_support" ALIAS "kernel_test_support") + add_library("os::kernel_test_support" ALIAS "kernel_test_support") - target_link_libraries("kernel_test_support" PUBLIC + target_link_libraries("kernel_test_support" PUBLIC "os::kernel" "Catch2::Catch2WithMain" ) - add_executable("kernel_tests" + add_executable("kernel_tests" # KAPI Shim Tests "kapi/cpu.tests.cpp" "kapi/system.tests.cpp" - + # KSTD Shim Tests "kstd/print.tests.cpp" - + # Memory Subsystem Tests "src/memory/bitmap_allocator.tests.cpp" "src/memory/block_list_allocator.tests.cpp" @@ -130,19 +131,19 @@ else() # Storage Subsystem Tests "src/devices/storage/ram_disk/device.tests.cpp" ) - add_executable("os::kernel_tests" ALIAS "kernel_tests") + add_executable("os::kernel_tests" ALIAS "kernel_tests") - target_link_libraries("kernel_tests" PRIVATE + target_link_libraries("kernel_tests" PRIVATE "os::kernel" "os::kernel_test_support" ) - set_target_properties("kernel_tests" PROPERTIES + set_target_properties("kernel_tests" PROPERTIES C_CLANG_TIDY "" CXX_CLANG_TIDY "" ) - enable_coverage("kernel_tests") - catch_discover_tests("os::kernel_tests") + enable_coverage("kernel_tests") + catch_discover_tests("os::kernel_tests") endif() diff --git a/kernel/include/kernel/memory/mmio_allocator.hpp b/kernel/include/kernel/memory/mmio_allocator.hpp new file mode 100644 index 0000000..4ec6bec --- /dev/null +++ b/kernel/include/kernel/memory/mmio_allocator.hpp @@ -0,0 +1,41 @@ +#ifndef TEACHOS_KERNEL_MEMORY_MMIO_ALLOCATOR_HPP +#define TEACHOS_KERNEL_MEMORY_MMIO_ALLOCATOR_HPP + +#include "kapi/memory.hpp" + +#include <kstd/allocator> +#include <kstd/memory> + +#include <cstddef> + +namespace kernel::memory +{ + + struct mmio_allocator + { + mmio_allocator(kapi::memory::linear_address base, std::size_t pages); + + [[nodiscard]] auto allocate(std::size_t page_count) -> kapi::memory::linear_address; + auto release(kapi::memory::linear_address base) -> void; + + private: + struct node + { + kapi::memory::linear_address base{}; + std::size_t page_count{}; + node * next{}; + node * previous{}; + bool is_free{}; + }; + + auto make_node(kapi::memory::linear_address base, std::size_t page_count, node * next, node * previous, + bool is_free) -> node *; + auto destroy_node(node *) -> void; + + [[no_unique_address]] kstd::allocator<node> m_allocator{}; + node * m_head{}; + }; + +} // namespace kernel::memory + +#endif diff --git a/kernel/kapi/memory.cpp b/kernel/kapi/memory.cpp index 06a3165..b224c50 100644 --- a/kernel/kapi/memory.cpp +++ b/kernel/kapi/memory.cpp @@ -3,6 +3,7 @@ #include "kapi/system.hpp" #include "kernel/memory/bitmap_allocator.hpp" +#include "kernel/memory/mmio_allocator.hpp" #include <kstd/print> #include <kstd/units> @@ -63,6 +64,7 @@ namespace kapi::memory constinit bad_frame_allocator bad_frame_allocator::instance{}; constinit bad_page_mapper bad_page_mapper::instance{}; auto constinit allocator = std::optional<kernel::memory::bitmap_frame_allocator>{}; + auto constinit mmio_allocator = std::optional<kernel::memory::mmio_allocator>{}; } // namespace constinit auto static active_frame_allocator = static_cast<frame_allocator *>(&bad_frame_allocator::instance); @@ -147,4 +149,27 @@ namespace kapi::memory kstd::println("[OS:MEM] Physical memory manager initialized."); } + auto init_mmio(linear_address base, std::size_t page_count) -> void + { + mmio_allocator.emplace(base, page_count); + } + + auto allocate_mmio_region(std::size_t page_count) -> linear_address + { + auto region = mmio_allocator->allocate(page_count); + return region; + } + + auto map_mmio_region(linear_address base, physical_address hw_base, page_mapper::flags flags) -> std::byte * + { + auto start_page = page::containing(base); + auto start_frame = frame::containing(hw_base); + return map(start_page, start_frame, flags | page_mapper::flags::uncached); + } + + auto release_mmio_region(linear_address base) -> void + { + mmio_allocator->release(base); + } + } // namespace kapi::memory diff --git a/kernel/src/memory/mmio_allocator.cpp b/kernel/src/memory/mmio_allocator.cpp new file mode 100644 index 0000000..f77f14f --- /dev/null +++ b/kernel/src/memory/mmio_allocator.cpp @@ -0,0 +1,107 @@ +#include "kernel/memory/mmio_allocator.hpp" + +#include "kapi/memory.hpp" +#include "kapi/system.hpp" + +#include <kstd/allocator> + +#include <cstddef> +#include <memory> +#include <utility> + +namespace kernel::memory +{ + + mmio_allocator::mmio_allocator(kapi::memory::linear_address base, std::size_t pages) + : m_head{make_node(base, pages, nullptr, nullptr, true)} + {} + + auto mmio_allocator::allocate(std::size_t count) -> kapi::memory::linear_address + { + if (count == 0 || !m_head) + { + return {}; + } + + auto current = m_head; + while (current) + { + if (current->page_count > count) + { + auto new_base = current->base + (count * kapi::memory::page::size); + auto split_node = make_node(new_base, current->page_count - count, std::move(current->next), current, true); + + if (current->next) + { + current->next->previous = split_node; + } + current->next = split_node; + current->page_count = count; + } + + current->is_free = false; + return current->base; + } + + kapi::system::panic("[OS:MEM] MMIO alloctor out of memory!"); + return {}; + } + + auto mmio_allocator::release(kapi::memory::linear_address base) -> void + { + auto current = m_head; + + while (current) + { + if (current->base == base && !current->is_free) + { + current->is_free = true; + + if (current->next && current->next->is_free) + { + auto removed = current->next; + current->page_count += removed->page_count; + current->next = removed->next; + if (current->next) + { + current->next->previous = current; + } + destroy_node(removed); + } + + if (current->previous && current->previous->is_free) + { + auto removed = current; + removed->previous->page_count += removed->page_count; + removed->previous->next = removed->next; + if (removed->next) + { + removed->next->previous = removed->previous; + } + destroy_node(removed); + } + return; + } + current = current->next; + } + } + + auto mmio_allocator::make_node(kapi::memory::linear_address base, std::size_t page_count, node * next, + node * previous, bool is_free) -> node * + { + using traits = std::allocator_traits<kstd::allocator<node>>; + + auto new_node = traits::allocate(m_allocator, 1); + traits::construct(m_allocator, new_node, base, page_count, next, previous, is_free); + return new_node; + } + + auto mmio_allocator::destroy_node(node * instance) -> void + { + using traits = std::allocator_traits<kstd::allocator<node>>; + + traits::destroy(m_allocator, instance); + traits::deallocate(m_allocator, instance, 1); + } + +} // namespace kernel::memory |
