|
|
@@ -3,6 +3,8 @@
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
+#include <vector>
|
|
|
+
|
|
|
#include "common/alignment.h"
|
|
|
#include "common/common_types.h"
|
|
|
#include "core/hle/kernel/k_page_bitmap.h"
|
|
|
@@ -33,28 +35,36 @@ public:
|
|
|
return reinterpret_cast<T*>(m_backing_memory.data() + (addr - m_address));
|
|
|
}
|
|
|
|
|
|
- Result Initialize(VAddr addr, size_t sz) {
|
|
|
+ Result Initialize(VAddr memory, size_t size, size_t align) {
|
|
|
// We need to have positive size.
|
|
|
- R_UNLESS(sz > 0, ResultOutOfMemory);
|
|
|
- m_backing_memory.resize(sz);
|
|
|
+ R_UNLESS(size > 0, ResultOutOfMemory);
|
|
|
+ m_backing_memory.resize(size);
|
|
|
+
|
|
|
+ // Set addresses.
|
|
|
+ m_address = memory;
|
|
|
+ m_aligned_address = Common::AlignDown(memory, align);
|
|
|
|
|
|
- // Calculate management overhead.
|
|
|
- const size_t management_size =
|
|
|
- KPageBitmap::CalculateManagementOverheadSize(sz / sizeof(PageBuffer));
|
|
|
- const size_t allocatable_size = sz - management_size;
|
|
|
+ // Calculate extents.
|
|
|
+ const size_t managed_size = m_address + size - m_aligned_address;
|
|
|
+ const size_t overhead_size = Common::AlignUp(
|
|
|
+ KPageBitmap::CalculateManagementOverheadSize(managed_size / sizeof(PageBuffer)),
|
|
|
+ sizeof(PageBuffer));
|
|
|
+ R_UNLESS(overhead_size < size, ResultOutOfMemory);
|
|
|
|
|
|
// 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);
|
|
|
+ m_size = Common::AlignDown(size - overhead_size, sizeof(PageBuffer));
|
|
|
+ m_count = m_size / sizeof(PageBuffer);
|
|
|
|
|
|
// Clear the management region.
|
|
|
- u64* management_ptr = GetPointer<u64>(m_address + allocatable_size);
|
|
|
- std::memset(management_ptr, 0, management_size);
|
|
|
+ u64* management_ptr = GetPointer<u64>(m_address + size - overhead_size);
|
|
|
+ std::memset(management_ptr, 0, overhead_size);
|
|
|
|
|
|
// Initialize the bitmap.
|
|
|
- m_page_bitmap.Initialize(management_ptr, m_count);
|
|
|
+ const size_t allocatable_region_size =
|
|
|
+ (m_address + size - overhead_size) - m_aligned_address;
|
|
|
+ ASSERT(allocatable_region_size >= sizeof(PageBuffer));
|
|
|
+
|
|
|
+ m_page_bitmap.Initialize(management_ptr, allocatable_region_size / sizeof(PageBuffer));
|
|
|
|
|
|
// Free the pages to the bitmap.
|
|
|
for (size_t i = 0; i < m_count; i++) {
|
|
|
@@ -62,7 +72,8 @@ public:
|
|
|
std::memset(GetPointer<PageBuffer>(m_address) + i, 0, PageSize);
|
|
|
|
|
|
// Set the bit for the free page.
|
|
|
- m_page_bitmap.SetBit(i);
|
|
|
+ m_page_bitmap.SetBit((m_address + (i * sizeof(PageBuffer)) - m_aligned_address) /
|
|
|
+ sizeof(PageBuffer));
|
|
|
}
|
|
|
|
|
|
R_SUCCEED();
|
|
|
@@ -101,7 +112,28 @@ public:
|
|
|
m_page_bitmap.ClearBit(offset);
|
|
|
m_peak = std::max(m_peak, (++m_used));
|
|
|
|
|
|
- return GetPointer<PageBuffer>(m_address) + offset;
|
|
|
+ return GetPointer<PageBuffer>(m_aligned_address) + offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ PageBuffer* Allocate(size_t count) {
|
|
|
+ // 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.FindFreeRange(count);
|
|
|
+ if (soffset < 0) [[likely]] {
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ const size_t offset = static_cast<size_t>(soffset);
|
|
|
+
|
|
|
+ // Update our tracking.
|
|
|
+ m_page_bitmap.ClearRange(offset, count);
|
|
|
+ m_used += count;
|
|
|
+ m_peak = std::max(m_peak, m_used);
|
|
|
+
|
|
|
+ return GetPointer<PageBuffer>(m_aligned_address) + offset;
|
|
|
}
|
|
|
|
|
|
void Free(PageBuffer* pb) {
|
|
|
@@ -113,7 +145,7 @@ public:
|
|
|
KScopedSpinLock lk(m_lock);
|
|
|
|
|
|
// Set the bit for the free page.
|
|
|
- size_t offset = (reinterpret_cast<uintptr_t>(pb) - m_address) / sizeof(PageBuffer);
|
|
|
+ size_t offset = (reinterpret_cast<uintptr_t>(pb) - m_aligned_address) / sizeof(PageBuffer);
|
|
|
m_page_bitmap.SetBit(offset);
|
|
|
|
|
|
// Decrement our used count.
|
|
|
@@ -127,6 +159,7 @@ private:
|
|
|
size_t m_peak{};
|
|
|
size_t m_count{};
|
|
|
VAddr m_address{};
|
|
|
+ VAddr m_aligned_address{};
|
|
|
size_t m_size{};
|
|
|
|
|
|
// TODO(bunnei): Back by host memory until we emulate kernel virtual address space.
|