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.
This commit is contained in:
parent
799aab02f5
commit
a6ca9fd453
|
@ -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
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <kernel/Memory/MemoryRegion.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class DMARegion
|
||||
{
|
||||
public:
|
||||
BAN::ErrorOr<BAN::UniqPtr<DMARegion>> 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;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
#include <BAN/ScopeGuard.h>
|
||||
#include <kernel/Memory/DMARegion.h>
|
||||
#include <kernel/Memory/Heap.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<DMARegion>> DMARegion::create(size_t size)
|
||||
{
|
||||
size_t needed_pages = BAN::Math::div_round_up<size_t>(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<DMARegion>::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<size_t>(m_size, PAGE_SIZE));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue