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.cpp51
1 files changed, 35 insertions, 16 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 179685b72..fa5273402 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -24,6 +24,16 @@
namespace Core::Memory {
+namespace {
+
+bool AddressSpaceContains(const Common::PageTable& table, const Common::ProcessAddress addr,
+ const std::size_t size) {
+ const Common::ProcessAddress max_addr = 1ULL << table.GetAddressSpaceBits();
+ return addr + size >= addr && addr + size <= max_addr;
+}
+
+} // namespace
+
// Implementation class used to keep the specifics of the memory subsystem hidden
// from outside classes. This also allows modification to the internals of the memory
// subsystem without needing to rebuild all files that make use of the memory interface.
@@ -73,7 +83,7 @@ struct Memory::Impl {
return {};
}
- return system.DeviceMemory().GetPointer<u8>(paddr) + vaddr;
+ return system.DeviceMemory().GetPointer<u8>(paddr + vaddr);
}
[[nodiscard]] u8* GetPointerFromDebugMemory(u64 vaddr) const {
@@ -84,7 +94,7 @@ struct Memory::Impl {
return {};
}
- return system.DeviceMemory().GetPointer<u8>(paddr) + vaddr;
+ return system.DeviceMemory().GetPointer<u8>(paddr + vaddr);
}
u8 Read8(const Common::ProcessAddress addr) {
@@ -191,6 +201,11 @@ struct Memory::Impl {
std::size_t page_offset = addr & YUZU_PAGEMASK;
bool user_accessible = true;
+ if (!AddressSpaceContains(page_table, addr, size)) [[unlikely]] {
+ on_unmapped(size, addr);
+ return false;
+ }
+
while (remaining_size) {
const std::size_t copy_amount =
std::min(static_cast<std::size_t>(YUZU_PAGESIZE) - page_offset, remaining_size);
@@ -205,7 +220,8 @@ struct Memory::Impl {
break;
}
case Common::PageType::Memory: {
- u8* mem_ptr = pointer + page_offset + (page_index << YUZU_PAGEBITS);
+ u8* mem_ptr =
+ reinterpret_cast<u8*>(pointer + page_offset + (page_index << YUZU_PAGEBITS));
on_memory(copy_amount, mem_ptr);
break;
}
@@ -420,7 +436,7 @@ struct Memory::Impl {
}
void MarkRegionDebug(u64 vaddr, u64 size, bool debug) {
- if (vaddr == 0) {
+ if (vaddr == 0 || !AddressSpaceContains(*current_page_table, vaddr, size)) {
return;
}
@@ -447,7 +463,7 @@ struct Memory::Impl {
break;
case Common::PageType::Memory:
current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store(
- nullptr, Common::PageType::DebugMemory);
+ 0, Common::PageType::DebugMemory);
break;
default:
UNREACHABLE();
@@ -465,7 +481,8 @@ struct Memory::Impl {
case Common::PageType::DebugMemory: {
u8* const pointer{GetPointerFromDebugMemory(vaddr & ~YUZU_PAGEMASK)};
current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store(
- pointer - (vaddr & ~YUZU_PAGEMASK), Common::PageType::Memory);
+ reinterpret_cast<uintptr_t>(pointer) - (vaddr & ~YUZU_PAGEMASK),
+ Common::PageType::Memory);
break;
}
default:
@@ -476,7 +493,7 @@ struct Memory::Impl {
}
void RasterizerMarkRegionCached(u64 vaddr, u64 size, bool cached) {
- if (vaddr == 0) {
+ if (vaddr == 0 || !AddressSpaceContains(*current_page_table, vaddr, size)) {
return;
}
@@ -505,7 +522,7 @@ struct Memory::Impl {
case Common::PageType::DebugMemory:
case Common::PageType::Memory:
current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store(
- nullptr, Common::PageType::RasterizerCachedMemory);
+ 0, Common::PageType::RasterizerCachedMemory);
break;
case Common::PageType::RasterizerCachedMemory:
// There can be more than one GPU region mapped per CPU region, so it's common
@@ -533,10 +550,11 @@ struct Memory::Impl {
// 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->pointers[vaddr >> YUZU_PAGEBITS].Store(
- nullptr, Common::PageType::Unmapped);
+ 0, Common::PageType::Unmapped);
} else {
current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store(
- pointer - (vaddr & ~YUZU_PAGEMASK), Common::PageType::Memory);
+ reinterpret_cast<uintptr_t>(pointer) - (vaddr & ~YUZU_PAGEMASK),
+ Common::PageType::Memory);
}
break;
}
@@ -583,7 +601,7 @@ struct Memory::Impl {
"Mapping memory page without a pointer @ {:016x}", base * YUZU_PAGESIZE);
while (base != end) {
- page_table.pointers[base].Store(nullptr, type);
+ page_table.pointers[base].Store(0, type);
page_table.backing_addr[base] = 0;
page_table.blocks[base] = 0;
base += 1;
@@ -592,7 +610,8 @@ struct Memory::Impl {
auto orig_base = base;
while (base != end) {
auto host_ptr =
- system.DeviceMemory().GetPointer<u8>(target) - (base << YUZU_PAGEBITS);
+ reinterpret_cast<uintptr_t>(system.DeviceMemory().GetPointer<u8>(target)) -
+ (base << YUZU_PAGEBITS);
auto backing = GetInteger(target) - (base << YUZU_PAGEBITS);
page_table.pointers[base].Store(host_ptr, type);
page_table.backing_addr[base] = backing;
@@ -611,15 +630,15 @@ struct Memory::Impl {
// AARCH64 masks the upper 16 bit of all memory accesses
vaddr = vaddr & 0xffffffffffffULL;
- if (vaddr >= 1uLL << current_page_table->GetAddressSpaceBits()) {
+ if (!AddressSpaceContains(*current_page_table, vaddr, 1)) [[unlikely]] {
on_unmapped();
return nullptr;
}
// Avoid adding any extra logic to this fast-path block
const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Raw();
- if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
- return &pointer[vaddr];
+ if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
+ return reinterpret_cast<u8*>(pointer + vaddr);
}
switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
case Common::PageType::Unmapped:
@@ -813,7 +832,7 @@ bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const {
return false;
}
const auto [pointer, type] = page_table.pointers[page].PointerType();
- return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory ||
+ return pointer != 0 || type == Common::PageType::RasterizerCachedMemory ||
type == Common::PageType::DebugMemory;
}