aboutsummaryrefslogtreecommitdiff
path: root/src/core/memory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/memory.cpp')
-rw-r--r--src/core/memory.cpp79
1 files changed, 41 insertions, 38 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index a5e6b8592c..837016de1d 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -101,8 +101,10 @@ struct Memory::Impl {
}
u64 protect_bytes = 0, protect_begin = 0;
+
+ current_page_table->entries.CommitRegion(vaddr >> YUZU_PAGEBITS, (vaddr + size) >> YUZU_PAGEBITS);
for (u64 addr = vaddr; addr < vaddr + size; addr += YUZU_PAGESIZE) {
- const Common::PageType page_type = current_page_table->entries[addr >> YUZU_PAGEBITS].ptr.Type();
+ const Common::PageType page_type = current_page_table->entries.GetUnchecked(addr >> YUZU_PAGEBITS).Type();
switch (page_type) {
case Common::PageType::RasterizerCachedMemory:
if (protect_bytes > 0) {
@@ -123,16 +125,14 @@ struct Memory::Impl {
}
[[nodiscard]] u8* GetPointerFromRasterizerCachedMemory(u64 vaddr) const {
- Common::PhysicalAddress const paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr;
- if (paddr)
- return system.DeviceMemory().GetPointer<u8>(paddr + vaddr);
+ if (u64 paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].Pointer(true); paddr)
+ return reinterpret_cast<u8*>(paddr) + vaddr;
return {};
}
[[nodiscard]] u8* GetPointerFromDebugMemory(u64 vaddr) const {
- const Common::PhysicalAddress paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr;
- if (paddr != 0)
- return system.DeviceMemory().GetPointer<u8>(paddr + vaddr);
+ if (u64 paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].Pointer(true); paddr)
+ return reinterpret_cast<u8*>(paddr) + vaddr;
return {};
}
@@ -243,10 +243,12 @@ struct Memory::Impl {
std::size_t page_index = addr >> YUZU_PAGEBITS;
std::size_t page_offset = addr & YUZU_PAGEMASK;
bool user_accessible = true;
+
+ current_page_table->entries.CommitRegion(page_index, page_index + (size >> YUZU_PAGEBITS) + 1);
while (remaining_size != 0) {
const std::size_t copy_amount = (std::min)(std::size_t(YUZU_PAGESIZE) - page_offset, remaining_size);
const auto current_vaddr = u64((page_index << YUZU_PAGEBITS) + page_offset);
- const auto [pointer, type] = current_page_table->entries[page_index].ptr.PointerType();
+ const auto [pointer, type, _] = current_page_table->entries.GetUnchecked(page_index).PointerTypeBlock();
switch (type) {
case Common::PageType::Unmapped: {
user_accessible = false;
@@ -297,10 +299,10 @@ struct Memory::Impl {
}
[[nodiscard]] inline const u8* GetSpan(const VAddr addr, const std::size_t size) const noexcept {
- return (current_page_table->entries[addr >> YUZU_PAGEBITS].block == current_page_table->entries[(addr + size) >> YUZU_PAGEBITS].block) ? GetPointerSilent(addr) : nullptr;
+ return (current_page_table->entries[addr >> YUZU_PAGEBITS].Block() == current_page_table->entries[(addr + size) >> YUZU_PAGEBITS].Block()) ? GetPointerSilent(addr) : nullptr;
}
[[nodiscard]] inline u8* GetSpan(const VAddr addr, const std::size_t size) noexcept {
- return (current_page_table->entries[addr >> YUZU_PAGEBITS].block == current_page_table->entries[(addr + size) >> YUZU_PAGEBITS].block) ? GetPointerSilent(addr) : nullptr;
+ return (current_page_table->entries[addr >> YUZU_PAGEBITS].Block() == current_page_table->entries[(addr + size) >> YUZU_PAGEBITS].Block()) ? GetPointerSilent(addr) : nullptr;
}
bool WriteBlockImpl(const Common::ProcessAddress addr, const void* buffer, const std::size_t size, bool unsafe) {
@@ -404,11 +406,14 @@ struct Memory::Impl {
// The region is at a granularity of CPU pages.
const u64 num_pages = ((vaddr + size - 1) >> YUZU_PAGEBITS) - (vaddr >> YUZU_PAGEBITS) + 1;
+
+ current_page_table->entries.CommitRegion(vaddr >> YUZU_PAGEBITS, (vaddr >> YUZU_PAGEBITS) + num_pages);
for (u64 i = 0; i < num_pages; ++i, vaddr += YUZU_PAGESIZE) {
- const Common::PageType page_type = current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Type();
+ auto& entry = current_page_table->entries.GetUnchecked(vaddr >> YUZU_PAGEBITS);
+ const auto [pointer, type, block] = entry.PointerTypeBlock(true);
if (debug) {
// Switch page type to debug if now debug
- switch (page_type) {
+ switch (type) {
case Common::PageType::Unmapped:
ASSERT(false && "Attempted to mark unmapped pages as debug");
break;
@@ -417,14 +422,14 @@ struct Memory::Impl {
// Page is already marked.
break;
case Common::PageType::Memory:
- current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Store(0, Common::PageType::DebugMemory);
+ entry.MarkDebug(pointer, block);
break;
default:
UNREACHABLE();
}
} else {
// Switch page type to non-debug if now non-debug
- switch (page_type) {
+ switch (type) {
case Common::PageType::Unmapped:
ASSERT(false && "Attempted to mark unmapped pages as non-debug");
break;
@@ -433,8 +438,7 @@ struct Memory::Impl {
// Don't mess with already non-debug or rasterizer memory.
break;
case Common::PageType::DebugMemory: {
- u8* const pointer = GetPointerFromDebugMemory(vaddr & ~YUZU_PAGEMASK);
- current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Store(uintptr_t(pointer) - (vaddr & ~YUZU_PAGEMASK), Common::PageType::Memory);
+ entry.Store(false, Common::PageType::Memory, block, pointer);
break;
}
default:
@@ -466,8 +470,10 @@ struct Memory::Impl {
// is different). This assumes the specified GPU address region is contiguous as well.
const u64 num_pages = ((vaddr + size - 1) >> YUZU_PAGEBITS) - (vaddr >> YUZU_PAGEBITS) + 1;
+ current_page_table->entries.CommitRegion(vaddr >> YUZU_PAGEBITS, (vaddr >> YUZU_PAGEBITS) + num_pages);
for (u64 i = 0; i < num_pages; ++i, vaddr += YUZU_PAGESIZE) {
- const Common::PageType page_type= current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Type();
+ auto& entry = current_page_table->entries.GetUnchecked(vaddr >> YUZU_PAGEBITS);
+ const Common::PageType page_type = entry.Type();
if (cached) {
// Switch page type to cached if now cached
switch (page_type) {
@@ -477,7 +483,7 @@ struct Memory::Impl {
break;
case Common::PageType::DebugMemory:
case Common::PageType::Memory:
- current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Store(0, Common::PageType::RasterizerCachedMemory);
+ entry.MarkRasterizerCached();
break;
case Common::PageType::RasterizerCachedMemory:
// There can be more than one GPU region mapped per CPU region, so it's common
@@ -499,13 +505,13 @@ struct Memory::Impl {
// that this area is already unmarked as cached.
break;
case Common::PageType::RasterizerCachedMemory: {
- if (u8* const pointer = GetPointerFromRasterizerCachedMemory(vaddr & ~YUZU_PAGEMASK); pointer == nullptr) {
+ if (auto [ptr, _, block] = entry.PointerTypeBlock(true); ptr == 0) {
// It's possible that this function has been called while updating the
// pagetable after unmapping a VMA. In that case the underlying VMA will no
// longer exist, and we should just leave the pagetable entry blank.
- current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Store(0, Common::PageType::Unmapped);
+ entry.Store(false, Common::PageType::Unmapped, block, 0);
} else {
- current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Store(uintptr_t(pointer) - (vaddr & ~YUZU_PAGEMASK), Common::PageType::Memory);
+ entry.Store(false, Common::PageType::Memory, block, ptr);
}
break;
}
@@ -539,22 +545,18 @@ struct Memory::Impl {
ASSERT_MSG(type != Common::PageType::Memory,
"Mapping memory page without a pointer @ {:016x}", base * YUZU_PAGESIZE);
- while (base != end) {
- page_table.entries[base].ptr.Store(0, type);
- page_table.entries[base].addr = 0;
- page_table.entries[base].block = 0;
- base += 1;
- }
+ page_table.entries.ZeroRegion(base, end);
} else {
- auto orig_base = base;
+ auto current_block = block_count.fetch_add(1, std::memory_order_relaxed);
+ ASSERT(current_block != 65535);
+
+ page_table.entries.CommitRegion(base, end);
while (base != end) {
- auto host_ptr = uintptr_t(system.DeviceMemory().GetPointer<u8>(target)) - (base << YUZU_PAGEBITS);
- auto backing = GetInteger(target) - (base << YUZU_PAGEBITS);
- page_table.entries[base].ptr.Store(host_ptr, type);
- page_table.entries[base].addr = backing;
- page_table.entries[base].block = orig_base << YUZU_PAGEBITS;
+ auto host_ptr = reinterpret_cast<u64>(system.DeviceMemory().GetPointer<u8>(target)) - (base << YUZU_PAGEBITS);;
+ auto& entry = page_table.entries.GetUnchecked(base);
- ASSERT_MSG(page_table.entries[base].ptr.Pointer(),
+ entry.Store(false, type, current_block, host_ptr);
+ ASSERT_MSG(page_table.entries[base].Pointer(),
"memory mapping base yield a nullptr within the table");
base += 1;
@@ -569,11 +571,11 @@ struct Memory::Impl {
vaddr &= 0xffffffffffffULL;
if (AddressSpaceContains(*current_page_table, vaddr, 1)) [[likely]] {
// Avoid adding any extra logic to this fast-path block
- const uintptr_t raw_pointer = current_page_table->entries[vaddr >> YUZU_PAGEBITS].ptr.Raw();
- if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) [[likely]] {
+ const auto raw = current_page_table->entries[vaddr >> YUZU_PAGEBITS].Raw();
+ if (auto pointer = Common::PageTable::PageEntryData::ExtractPointer(raw); pointer) [[likely]] {
return reinterpret_cast<u8*>(pointer + vaddr);
} else {
- switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
+ switch (static_cast<Common::PageType>(raw.type)) {
case Common::PageType::Memory:
ASSERT_MSG(false, "Mapped memory page without a pointer @ {:#016x}", vaddr);
return nullptr;
@@ -773,6 +775,7 @@ struct Memory::Impl {
#else
Common::HostMemory* host_buffer{};
#endif
+ std::atomic<u16> block_count = 0;
};
Memory::Memory(Core::System& system_) : system{system_} {
@@ -811,7 +814,7 @@ bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const {
if (page >= page_table.entries.size()) {
return false;
}
- const auto [pointer, type] = page_table.entries[page].ptr.PointerType();
+ const auto [pointer, type, _] = page_table.entries[page].PointerTypeBlock();
return pointer != 0 || type == Common::PageType::RasterizerCachedMemory ||
type == Common::PageType::DebugMemory;
}