From a6ca9fd453d8b4db478673548ae58974370a32bd Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sun, 8 Oct 2023 02:56:01 +0300 Subject: [PATCH] Kernel: Implement bare boness DMA Region This does nothing but allocate contiguous physical and virtual memory and map it as CacheDisable. Also memory is automatically freed RAII style. --- kernel/CMakeLists.txt | 1 + kernel/include/kernel/Memory/DMARegion.h | 27 ++++++++++++++ kernel/kernel/Memory/DMARegion.cpp | 46 ++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 kernel/include/kernel/Memory/DMARegion.h create mode 100644 kernel/kernel/Memory/DMARegion.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index c8bf72adf0..c5a2c033d5 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -34,6 +34,7 @@ set(KERNEL_SOURCES kernel/Input/PS2Keymap.cpp kernel/InterruptController.cpp kernel/kernel.cpp + kernel/Memory/DMARegion.cpp kernel/Memory/FileBackedRegion.cpp kernel/Memory/GeneralAllocator.cpp kernel/Memory/Heap.cpp diff --git a/kernel/include/kernel/Memory/DMARegion.h b/kernel/include/kernel/Memory/DMARegion.h new file mode 100644 index 0000000000..bd0585e189 --- /dev/null +++ b/kernel/include/kernel/Memory/DMARegion.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace Kernel +{ + + class DMARegion + { + public: + BAN::ErrorOr> create(size_t size); + ~DMARegion(); + + size_t size() const { return m_size; } + vaddr_t vaddr() const { return m_vaddr; } + paddr_t paddr() const { return m_paddr; } + + private: + DMARegion(size_t size, vaddr_t vaddr, paddr_t paddr); + + private: + const size_t m_size; + const vaddr_t m_vaddr; + const paddr_t m_paddr; + }; + +} \ No newline at end of file diff --git a/kernel/kernel/Memory/DMARegion.cpp b/kernel/kernel/Memory/DMARegion.cpp new file mode 100644 index 0000000000..645356e254 --- /dev/null +++ b/kernel/kernel/Memory/DMARegion.cpp @@ -0,0 +1,46 @@ +#include +#include +#include + +namespace Kernel +{ + + BAN::ErrorOr> DMARegion::create(size_t size) + { + size_t needed_pages = BAN::Math::div_round_up(size, PAGE_SIZE); + + vaddr_t vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET); + if (vaddr == 0) + return BAN::Error::from_errno(ENOMEM); + BAN::ScopeGuard vaddr_guard([vaddr, size] { PageTable::kernel().unmap_range(vaddr, size); }); + + paddr_t paddr = Heap::get().take_free_contiguous_pages(needed_pages); + if (paddr == 0) + return BAN::Error::from_errno(ENOMEM); + BAN::ScopeGuard paddr_guard([paddr, needed_pages] { Heap::get().release_contiguous_pages(paddr, needed_pages); }); + + auto* region_ptr = new DMARegion(size, vaddr, paddr); + if (region_ptr == nullptr) + return BAN::Error::from_errno(ENOMEM); + + vaddr_guard.disable(); + paddr_guard.disable(); + + PageTable::kernel().map_range_at(paddr, vaddr, size, PageTable::Flags::CacheDisable | PageTable::Flags::ReadWrite | PageTable::Flags::Reserved); + + return BAN::UniqPtr::adopt(region_ptr); + } + + DMARegion::DMARegion(size_t size, vaddr_t vaddr, paddr_t paddr) + : m_size(size) + , m_vaddr(vaddr) + , m_paddr(paddr) + { } + + DMARegion::~DMARegion() + { + PageTable::kernel().unmap_range(m_vaddr, m_size); + Heap::get().release_contiguous_pages(m_vaddr, BAN::Math::div_round_up(m_size, PAGE_SIZE)); + } + +}