aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86_64/include/arch/memory/page_table.hpp6
-rw-r--r--arch/x86_64/kapi/memory.cpp1
-rw-r--r--kapi/include/kapi/memory.hpp30
-rw-r--r--kernel/CMakeLists.txt41
-rw-r--r--kernel/include/kernel/memory/mmio_allocator.hpp41
-rw-r--r--kernel/kapi/memory.cpp25
-rw-r--r--kernel/src/memory/mmio_allocator.cpp107
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