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.cpp172
1 files changed, 95 insertions, 77 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 805963178..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.
@@ -31,10 +41,10 @@ struct Memory::Impl {
explicit Impl(Core::System& system_) : system{system_} {}
void SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) {
- current_page_table = &process.PageTable().PageTableImpl();
+ current_page_table = &process.GetPageTable().PageTableImpl();
current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer();
- const std::size_t address_space_width = process.PageTable().GetAddressSpaceWidth();
+ const std::size_t address_space_width = process.GetPageTable().GetAddressSpaceWidth();
system.ArmInterface(core_id).PageTableChanged(*current_page_table, address_space_width);
}
@@ -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) {
@@ -183,13 +193,18 @@ struct Memory::Impl {
return string;
}
- void WalkBlock(const Kernel::KProcess& process, const Common::ProcessAddress addr,
- const std::size_t size, auto on_unmapped, auto on_memory, auto on_rasterizer,
- auto increment) {
- const auto& page_table = process.PageTable().PageTableImpl();
+ bool WalkBlock(const Common::ProcessAddress addr, const std::size_t size, auto on_unmapped,
+ auto on_memory, auto on_rasterizer, auto increment) {
+ const auto& page_table = system.ApplicationProcess()->GetPageTable().PageTableImpl();
std::size_t remaining_size = size;
std::size_t page_index = addr >> YUZU_PAGEBITS;
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 =
@@ -200,11 +215,13 @@ struct Memory::Impl {
const auto [pointer, type] = page_table.pointers[page_index].PointerType();
switch (type) {
case Common::PageType::Unmapped: {
+ user_accessible = false;
on_unmapped(copy_amount, current_vaddr);
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;
}
@@ -227,13 +244,15 @@ struct Memory::Impl {
increment(copy_amount);
remaining_size -= copy_amount;
}
+
+ return user_accessible;
}
template <bool UNSAFE>
- void ReadBlockImpl(const Kernel::KProcess& process, const Common::ProcessAddress src_addr,
- void* dest_buffer, const std::size_t size) {
- WalkBlock(
- process, src_addr, size,
+ bool ReadBlockImpl(const Common::ProcessAddress src_addr, void* dest_buffer,
+ const std::size_t size) {
+ return WalkBlock(
+ src_addr, size,
[src_addr, size, &dest_buffer](const std::size_t copy_amount,
const Common::ProcessAddress current_vaddr) {
LOG_ERROR(HW_Memory,
@@ -256,14 +275,14 @@ struct Memory::Impl {
});
}
- void ReadBlock(const Common::ProcessAddress src_addr, void* dest_buffer,
+ bool ReadBlock(const Common::ProcessAddress src_addr, void* dest_buffer,
const std::size_t size) {
- ReadBlockImpl<false>(*system.ApplicationProcess(), src_addr, dest_buffer, size);
+ return ReadBlockImpl<false>(src_addr, dest_buffer, size);
}
- void ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_buffer,
+ bool ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_buffer,
const std::size_t size) {
- ReadBlockImpl<true>(*system.ApplicationProcess(), src_addr, dest_buffer, size);
+ return ReadBlockImpl<true>(src_addr, dest_buffer, size);
}
const u8* GetSpan(const VAddr src_addr, const std::size_t size) const {
@@ -283,10 +302,10 @@ struct Memory::Impl {
}
template <bool UNSAFE>
- void WriteBlockImpl(const Kernel::KProcess& process, const Common::ProcessAddress dest_addr,
- const void* src_buffer, const std::size_t size) {
- WalkBlock(
- process, dest_addr, size,
+ bool WriteBlockImpl(const Common::ProcessAddress dest_addr, const void* src_buffer,
+ const std::size_t size) {
+ return WalkBlock(
+ dest_addr, size,
[dest_addr, size](const std::size_t copy_amount,
const Common::ProcessAddress current_vaddr) {
LOG_ERROR(HW_Memory,
@@ -308,20 +327,19 @@ struct Memory::Impl {
});
}
- void WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer,
+ bool WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer,
const std::size_t size) {
- WriteBlockImpl<false>(*system.ApplicationProcess(), dest_addr, src_buffer, size);
+ return WriteBlockImpl<false>(dest_addr, src_buffer, size);
}
- void WriteBlockUnsafe(const Common::ProcessAddress dest_addr, const void* src_buffer,
+ bool WriteBlockUnsafe(const Common::ProcessAddress dest_addr, const void* src_buffer,
const std::size_t size) {
- WriteBlockImpl<true>(*system.ApplicationProcess(), dest_addr, src_buffer, size);
+ return WriteBlockImpl<true>(dest_addr, src_buffer, size);
}
- void ZeroBlock(const Kernel::KProcess& process, const Common::ProcessAddress dest_addr,
- const std::size_t size) {
- WalkBlock(
- process, dest_addr, size,
+ bool ZeroBlock(const Common::ProcessAddress dest_addr, const std::size_t size) {
+ return WalkBlock(
+ dest_addr, size,
[dest_addr, size](const std::size_t copy_amount,
const Common::ProcessAddress current_vaddr) {
LOG_ERROR(HW_Memory,
@@ -339,23 +357,23 @@ struct Memory::Impl {
[](const std::size_t copy_amount) {});
}
- void CopyBlock(const Kernel::KProcess& process, Common::ProcessAddress dest_addr,
- Common::ProcessAddress src_addr, const std::size_t size) {
- WalkBlock(
- process, dest_addr, size,
+ bool CopyBlock(Common::ProcessAddress dest_addr, Common::ProcessAddress src_addr,
+ const std::size_t size) {
+ return WalkBlock(
+ dest_addr, size,
[&](const std::size_t copy_amount, const Common::ProcessAddress current_vaddr) {
LOG_ERROR(HW_Memory,
"Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
GetInteger(current_vaddr), GetInteger(src_addr), size);
- ZeroBlock(process, dest_addr, copy_amount);
+ ZeroBlock(dest_addr, copy_amount);
},
[&](const std::size_t copy_amount, const u8* const src_ptr) {
- WriteBlockImpl<false>(process, dest_addr, src_ptr, copy_amount);
+ WriteBlockImpl<false>(dest_addr, src_ptr, copy_amount);
},
[&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
u8* const host_ptr) {
HandleRasterizerDownload(GetInteger(current_vaddr), copy_amount);
- WriteBlockImpl<false>(process, dest_addr, host_ptr, copy_amount);
+ WriteBlockImpl<false>(dest_addr, host_ptr, copy_amount);
},
[&](const std::size_t copy_amount) {
dest_addr += copy_amount;
@@ -364,13 +382,13 @@ struct Memory::Impl {
}
template <typename Callback>
- Result PerformCacheOperation(const Kernel::KProcess& process, Common::ProcessAddress dest_addr,
- std::size_t size, Callback&& cb) {
+ Result PerformCacheOperation(Common::ProcessAddress dest_addr, std::size_t size,
+ Callback&& cb) {
class InvalidMemoryException : public std::exception {};
try {
WalkBlock(
- process, dest_addr, size,
+ dest_addr, size,
[&](const std::size_t block_size, const Common::ProcessAddress current_vaddr) {
LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}",
GetInteger(current_vaddr));
@@ -387,41 +405,38 @@ struct Memory::Impl {
return ResultSuccess;
}
- Result InvalidateDataCache(const Kernel::KProcess& process, Common::ProcessAddress dest_addr,
- std::size_t size) {
+ Result InvalidateDataCache(Common::ProcessAddress dest_addr, std::size_t size) {
auto on_rasterizer = [&](const Common::ProcessAddress current_vaddr,
const std::size_t block_size) {
// dc ivac: Invalidate to point of coherency
// GPU flush -> CPU invalidate
HandleRasterizerDownload(GetInteger(current_vaddr), block_size);
};
- return PerformCacheOperation(process, dest_addr, size, on_rasterizer);
+ return PerformCacheOperation(dest_addr, size, on_rasterizer);
}
- Result StoreDataCache(const Kernel::KProcess& process, Common::ProcessAddress dest_addr,
- std::size_t size) {
+ Result StoreDataCache(Common::ProcessAddress dest_addr, std::size_t size) {
auto on_rasterizer = [&](const Common::ProcessAddress current_vaddr,
const std::size_t block_size) {
// dc cvac: Store to point of coherency
// CPU flush -> GPU invalidate
system.GPU().InvalidateRegion(GetInteger(current_vaddr), block_size);
};
- return PerformCacheOperation(process, dest_addr, size, on_rasterizer);
+ return PerformCacheOperation(dest_addr, size, on_rasterizer);
}
- Result FlushDataCache(const Kernel::KProcess& process, Common::ProcessAddress dest_addr,
- std::size_t size) {
+ Result FlushDataCache(Common::ProcessAddress dest_addr, std::size_t size) {
auto on_rasterizer = [&](const Common::ProcessAddress current_vaddr,
const std::size_t block_size) {
// dc civac: Store to point of coherency, and invalidate from cache
// CPU flush -> GPU invalidate
system.GPU().InvalidateRegion(GetInteger(current_vaddr), block_size);
};
- return PerformCacheOperation(process, dest_addr, size, on_rasterizer);
+ return PerformCacheOperation(dest_addr, size, on_rasterizer);
}
void MarkRegionDebug(u64 vaddr, u64 size, bool debug) {
- if (vaddr == 0) {
+ if (vaddr == 0 || !AddressSpaceContains(*current_page_table, vaddr, size)) {
return;
}
@@ -448,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();
@@ -466,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:
@@ -477,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;
}
@@ -506,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
@@ -534,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;
}
@@ -584,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;
@@ -593,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;
@@ -612,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:
@@ -808,13 +826,13 @@ void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress b
bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const {
const Kernel::KProcess& process = *system.ApplicationProcess();
- const auto& page_table = process.PageTable().PageTableImpl();
+ const auto& page_table = process.GetPageTable().PageTableImpl();
const size_t page = vaddr >> YUZU_PAGEBITS;
if (page >= page_table.pointers.size()) {
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;
}
@@ -899,14 +917,14 @@ std::string Memory::ReadCString(Common::ProcessAddress vaddr, std::size_t max_le
return impl->ReadCString(vaddr, max_length);
}
-void Memory::ReadBlock(const Common::ProcessAddress src_addr, void* dest_buffer,
+bool Memory::ReadBlock(const Common::ProcessAddress src_addr, void* dest_buffer,
const std::size_t size) {
- impl->ReadBlock(src_addr, dest_buffer, size);
+ return impl->ReadBlock(src_addr, dest_buffer, size);
}
-void Memory::ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_buffer,
+bool Memory::ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_buffer,
const std::size_t size) {
- impl->ReadBlockUnsafe(src_addr, dest_buffer, size);
+ return impl->ReadBlockUnsafe(src_addr, dest_buffer, size);
}
const u8* Memory::GetSpan(const VAddr src_addr, const std::size_t size) const {
@@ -917,23 +935,23 @@ u8* Memory::GetSpan(const VAddr src_addr, const std::size_t size) {
return impl->GetSpan(src_addr, size);
}
-void Memory::WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer,
+bool Memory::WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer,
const std::size_t size) {
- impl->WriteBlock(dest_addr, src_buffer, size);
+ return impl->WriteBlock(dest_addr, src_buffer, size);
}
-void Memory::WriteBlockUnsafe(const Common::ProcessAddress dest_addr, const void* src_buffer,
+bool Memory::WriteBlockUnsafe(const Common::ProcessAddress dest_addr, const void* src_buffer,
const std::size_t size) {
- impl->WriteBlockUnsafe(dest_addr, src_buffer, size);
+ return impl->WriteBlockUnsafe(dest_addr, src_buffer, size);
}
-void Memory::CopyBlock(Common::ProcessAddress dest_addr, Common::ProcessAddress src_addr,
+bool Memory::CopyBlock(Common::ProcessAddress dest_addr, Common::ProcessAddress src_addr,
const std::size_t size) {
- impl->CopyBlock(*system.ApplicationProcess(), dest_addr, src_addr, size);
+ return impl->CopyBlock(dest_addr, src_addr, size);
}
-void Memory::ZeroBlock(Common::ProcessAddress dest_addr, const std::size_t size) {
- impl->ZeroBlock(*system.ApplicationProcess(), dest_addr, size);
+bool Memory::ZeroBlock(Common::ProcessAddress dest_addr, const std::size_t size) {
+ return impl->ZeroBlock(dest_addr, size);
}
void Memory::SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers) {
@@ -941,15 +959,15 @@ void Memory::SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers
}
Result Memory::InvalidateDataCache(Common::ProcessAddress dest_addr, const std::size_t size) {
- return impl->InvalidateDataCache(*system.ApplicationProcess(), dest_addr, size);
+ return impl->InvalidateDataCache(dest_addr, size);
}
Result Memory::StoreDataCache(Common::ProcessAddress dest_addr, const std::size_t size) {
- return impl->StoreDataCache(*system.ApplicationProcess(), dest_addr, size);
+ return impl->StoreDataCache(dest_addr, size);
}
Result Memory::FlushDataCache(Common::ProcessAddress dest_addr, const std::size_t size) {
- return impl->FlushDataCache(*system.ApplicationProcess(), dest_addr, size);
+ return impl->FlushDataCache(dest_addr, size);
}
void Memory::RasterizerMarkRegionCached(Common::ProcessAddress vaddr, u64 size, bool cached) {