2 changed files with 137 additions and 0 deletions
@ -0,0 +1,136 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/alignment.h" |
|||
#include "common/common_types.h" |
|||
#include "core/hle/kernel/k_page_bitmap.h" |
|||
#include "core/hle/kernel/k_spin_lock.h" |
|||
#include "core/hle/kernel/memory_types.h" |
|||
#include "core/hle/kernel/svc_results.h" |
|||
|
|||
namespace Kernel { |
|||
|
|||
class KDynamicPageManager { |
|||
public: |
|||
class PageBuffer { |
|||
private: |
|||
u8 m_buffer[PageSize]; |
|||
}; |
|||
static_assert(sizeof(PageBuffer) == PageSize); |
|||
|
|||
public: |
|||
KDynamicPageManager() = default; |
|||
|
|||
template <typename T> |
|||
T* GetPointer(VAddr addr) { |
|||
return reinterpret_cast<T*>(m_backing_memory.data() + (addr - m_address)); |
|||
} |
|||
|
|||
template <typename T> |
|||
const T* GetPointer(VAddr addr) const { |
|||
return reinterpret_cast<T*>(m_backing_memory.data() + (addr - m_address)); |
|||
} |
|||
|
|||
Result Initialize(VAddr addr, size_t sz) { |
|||
// We need to have positive size. |
|||
R_UNLESS(sz > 0, ResultOutOfMemory); |
|||
m_backing_memory.resize(sz); |
|||
|
|||
// Calculate management overhead. |
|||
const size_t management_size = |
|||
KPageBitmap::CalculateManagementOverheadSize(sz / sizeof(PageBuffer)); |
|||
const size_t allocatable_size = sz - management_size; |
|||
|
|||
// Set tracking fields. |
|||
m_address = addr; |
|||
m_size = Common::AlignDown(allocatable_size, sizeof(PageBuffer)); |
|||
m_count = allocatable_size / sizeof(PageBuffer); |
|||
R_UNLESS(m_count > 0, ResultOutOfMemory); |
|||
|
|||
// Clear the management region. |
|||
u64* management_ptr = GetPointer<u64>(m_address + allocatable_size); |
|||
std::memset(management_ptr, 0, management_size); |
|||
|
|||
// Initialize the bitmap. |
|||
m_page_bitmap.Initialize(management_ptr, m_count); |
|||
|
|||
// Free the pages to the bitmap. |
|||
for (size_t i = 0; i < m_count; i++) { |
|||
// Ensure the freed page is all-zero. |
|||
std::memset(GetPointer<PageBuffer>(m_address) + i, 0, PageSize); |
|||
|
|||
// Set the bit for the free page. |
|||
m_page_bitmap.SetBit(i); |
|||
} |
|||
|
|||
return ResultSuccess; |
|||
} |
|||
|
|||
VAddr GetAddress() const { |
|||
return m_address; |
|||
} |
|||
size_t GetSize() const { |
|||
return m_size; |
|||
} |
|||
size_t GetUsed() const { |
|||
return m_used; |
|||
} |
|||
size_t GetPeak() const { |
|||
return m_peak; |
|||
} |
|||
size_t GetCount() const { |
|||
return m_count; |
|||
} |
|||
|
|||
PageBuffer* Allocate() { |
|||
// Take the lock. |
|||
// TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. |
|||
KScopedSpinLock lk(m_lock); |
|||
|
|||
// Find a random free block. |
|||
s64 soffset = m_page_bitmap.FindFreeBlock(true); |
|||
if (soffset < 0) [[unlikely]] { |
|||
return nullptr; |
|||
} |
|||
|
|||
const size_t offset = static_cast<size_t>(soffset); |
|||
|
|||
// Update our tracking. |
|||
m_page_bitmap.ClearBit(offset); |
|||
m_peak = std::max(m_peak, (++m_used)); |
|||
|
|||
return GetPointer<PageBuffer>(m_address) + offset; |
|||
} |
|||
|
|||
void Free(PageBuffer* pb) { |
|||
// Ensure all pages in the heap are zero. |
|||
std::memset(pb, 0, PageSize); |
|||
|
|||
// Take the lock. |
|||
// TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. |
|||
KScopedSpinLock lk(m_lock); |
|||
|
|||
// Set the bit for the free page. |
|||
size_t offset = (reinterpret_cast<uintptr_t>(pb) - m_address) / sizeof(PageBuffer); |
|||
m_page_bitmap.SetBit(offset); |
|||
|
|||
// Decrement our used count. |
|||
--m_used; |
|||
} |
|||
|
|||
private: |
|||
KSpinLock m_lock; |
|||
KPageBitmap m_page_bitmap; |
|||
size_t m_used{}; |
|||
size_t m_peak{}; |
|||
size_t m_count{}; |
|||
VAddr m_address{}; |
|||
size_t m_size{}; |
|||
|
|||
// TODO(bunnei): Back by host memory until we emulate kernel virtual address space. |
|||
std::vector<u8> m_backing_memory; |
|||
}; |
|||
|
|||
} // namespace Kernel |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue