forked from Bananymous/banan-os
104 lines
2.5 KiB
C++
104 lines
2.5 KiB
C++
#include <kernel/Lock/LockGuard.h>
|
|
#include <kernel/Memory/MemoryRegion.h>
|
|
|
|
namespace Kernel
|
|
{
|
|
|
|
MemoryRegion::MemoryRegion(PageTable& page_table, size_t size, Type type, PageTable::flags_t flags, int status_flags)
|
|
: m_page_table(page_table)
|
|
, m_size(size)
|
|
, m_type(type)
|
|
, m_flags(flags)
|
|
, m_status_flags(status_flags)
|
|
{
|
|
}
|
|
|
|
MemoryRegion::~MemoryRegion()
|
|
{
|
|
ASSERT(m_pinned_count == 0);
|
|
if (m_vaddr)
|
|
m_page_table.unmap_range(m_vaddr, m_size);
|
|
}
|
|
|
|
BAN::ErrorOr<void> MemoryRegion::initialize(AddressRange address_range)
|
|
{
|
|
size_t needed_pages = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
|
|
m_vaddr = m_page_table.reserve_free_contiguous_pages(needed_pages, address_range.start);
|
|
if (m_vaddr == 0)
|
|
return BAN::Error::from_errno(ENOMEM);
|
|
if (m_vaddr + m_size > address_range.end)
|
|
return BAN::Error::from_errno(ENOMEM);
|
|
return {};
|
|
}
|
|
|
|
bool MemoryRegion::contains(vaddr_t address) const
|
|
{
|
|
return m_vaddr <= address && address < m_vaddr + m_size;
|
|
}
|
|
|
|
bool MemoryRegion::contains_fully(vaddr_t address, size_t size) const
|
|
{
|
|
return m_vaddr <= address && address + size <= m_vaddr + m_size;
|
|
}
|
|
|
|
bool MemoryRegion::overlaps(vaddr_t address, size_t size) const
|
|
{
|
|
if (address + size <= m_vaddr)
|
|
return false;
|
|
if (address >= m_vaddr + m_size)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
BAN::ErrorOr<void> MemoryRegion::mprotect(PageTable::flags_t new_page_flags)
|
|
{
|
|
if (m_flags == new_page_flags)
|
|
return {};
|
|
|
|
const size_t page_count = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
|
|
for (size_t i = 0; i < page_count; i++)
|
|
{
|
|
const vaddr_t vaddr = m_vaddr + i * PAGE_SIZE;
|
|
const paddr_t paddr = m_page_table.physical_address_of(vaddr);
|
|
if (paddr == 0)
|
|
continue;
|
|
m_page_table.map_page_at(paddr, vaddr, new_page_flags);
|
|
}
|
|
|
|
m_flags = new_page_flags;
|
|
return {};
|
|
}
|
|
|
|
BAN::ErrorOr<bool> MemoryRegion::allocate_page_containing(vaddr_t address, bool wants_write)
|
|
{
|
|
ASSERT(contains(address));
|
|
if (wants_write && !writable())
|
|
return false;
|
|
auto ret = allocate_page_containing_impl(address, wants_write);
|
|
if (!ret.is_error() && ret.value())
|
|
m_physical_page_count++;
|
|
return ret;
|
|
}
|
|
|
|
void MemoryRegion::pin()
|
|
{
|
|
LockGuard _(m_pinned_mutex);
|
|
m_pinned_count++;
|
|
}
|
|
|
|
void MemoryRegion::unpin()
|
|
{
|
|
LockGuard _(m_pinned_mutex);
|
|
if (--m_pinned_count == 0)
|
|
m_pinned_blocker.unblock();
|
|
}
|
|
|
|
void MemoryRegion::wait_not_pinned()
|
|
{
|
|
LockGuard _(m_pinned_mutex);
|
|
while (m_pinned_count)
|
|
m_pinned_blocker.block_with_timeout_ms(100, &m_pinned_mutex);
|
|
}
|
|
|
|
}
|