diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index c8bf72ad..c5a2c033 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 00000000..bd0585e1 --- /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 00000000..645356e2 --- /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)); + } + +}