memory_manager: Add protections for invalid GPU addresses.
- Avoid a crash in Xenoblade Chronicles 2.
This commit is contained in:
parent
21eb4cfa7f
commit
197dcf0b5e
2 changed files with 45 additions and 24 deletions
|
@ -90,32 +90,44 @@ GPUVAddr MemoryManager::FindFreeRegion(GPUVAddr region_start, u64 size, u64 alig
|
||||||
return std::max(base, vma_handle->second.base);
|
return std::max(base, vma_handle->second.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) {
|
bool MemoryManager::IsAddressValid(GPUVAddr addr) const {
|
||||||
VAddr cpu_addr = page_table.backing_addr[gpu_addr >> page_bits];
|
return (addr >> page_bits) < page_table.pointers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr addr) {
|
||||||
|
if (!IsAddressValid(addr)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
VAddr cpu_addr = page_table.backing_addr[addr >> page_bits];
|
||||||
if (cpu_addr) {
|
if (cpu_addr) {
|
||||||
return cpu_addr + (gpu_addr & page_mask);
|
return cpu_addr + (addr & page_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T MemoryManager::Read(GPUVAddr vaddr) {
|
T MemoryManager::Read(GPUVAddr addr) {
|
||||||
const u8* page_pointer = page_table.pointers[vaddr >> page_bits];
|
if (!IsAddressValid(addr)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const u8* page_pointer = page_table.pointers[addr >> page_bits];
|
||||||
if (page_pointer) {
|
if (page_pointer) {
|
||||||
// NOTE: Avoid adding any extra logic to this fast-path block
|
// NOTE: Avoid adding any extra logic to this fast-path block
|
||||||
T value;
|
T value;
|
||||||
std::memcpy(&value, &page_pointer[vaddr & page_mask], sizeof(T));
|
std::memcpy(&value, &page_pointer[addr & page_mask], sizeof(T));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::PageType type = page_table.attributes[vaddr >> page_bits];
|
Common::PageType type = page_table.attributes[addr >> page_bits];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Common::PageType::Unmapped:
|
case Common::PageType::Unmapped:
|
||||||
LOG_ERROR(HW_GPU, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
|
LOG_ERROR(HW_GPU, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, addr);
|
||||||
return 0;
|
return 0;
|
||||||
case Common::PageType::Memory:
|
case Common::PageType::Memory:
|
||||||
ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
|
ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", addr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -124,22 +136,26 @@ T MemoryManager::Read(GPUVAddr vaddr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void MemoryManager::Write(GPUVAddr vaddr, T data) {
|
void MemoryManager::Write(GPUVAddr addr, T data) {
|
||||||
u8* page_pointer = page_table.pointers[vaddr >> page_bits];
|
if (!IsAddressValid(addr)) {
|
||||||
if (page_pointer) {
|
|
||||||
// NOTE: Avoid adding any extra logic to this fast-path block
|
|
||||||
std::memcpy(&page_pointer[vaddr & page_mask], &data, sizeof(T));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::PageType type = page_table.attributes[vaddr >> page_bits];
|
u8* page_pointer = page_table.pointers[addr >> page_bits];
|
||||||
|
if (page_pointer) {
|
||||||
|
// NOTE: Avoid adding any extra logic to this fast-path block
|
||||||
|
std::memcpy(&page_pointer[addr & page_mask], &data, sizeof(T));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::PageType type = page_table.attributes[addr >> page_bits];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Common::PageType::Unmapped:
|
case Common::PageType::Unmapped:
|
||||||
LOG_ERROR(HW_GPU, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
|
LOG_ERROR(HW_GPU, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
|
||||||
static_cast<u32>(data), vaddr);
|
static_cast<u32>(data), addr);
|
||||||
return;
|
return;
|
||||||
case Common::PageType::Memory:
|
case Common::PageType::Memory:
|
||||||
ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr);
|
ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", addr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -156,6 +172,10 @@ template void MemoryManager::Write<u32>(GPUVAddr addr, u32 data);
|
||||||
template void MemoryManager::Write<u64>(GPUVAddr addr, u64 data);
|
template void MemoryManager::Write<u64>(GPUVAddr addr, u64 data);
|
||||||
|
|
||||||
u8* MemoryManager::GetPointer(GPUVAddr addr) {
|
u8* MemoryManager::GetPointer(GPUVAddr addr) {
|
||||||
|
if (!IsAddressValid(addr)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
u8* page_pointer = page_table.pointers[addr >> page_bits];
|
u8* page_pointer = page_table.pointers[addr >> page_bits];
|
||||||
if (page_pointer) {
|
if (page_pointer) {
|
||||||
return page_pointer + (addr & page_mask);
|
return page_pointer + (addr & page_mask);
|
||||||
|
|
|
@ -46,19 +46,19 @@ public:
|
||||||
MemoryManager();
|
MemoryManager();
|
||||||
|
|
||||||
GPUVAddr AllocateSpace(u64 size, u64 align);
|
GPUVAddr AllocateSpace(u64 size, u64 align);
|
||||||
GPUVAddr AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align);
|
GPUVAddr AllocateSpace(GPUVAddr addr, u64 size, u64 align);
|
||||||
GPUVAddr MapBufferEx(GPUVAddr cpu_addr, u64 size);
|
GPUVAddr MapBufferEx(GPUVAddr cpu_addr, u64 size);
|
||||||
GPUVAddr MapBufferEx(GPUVAddr cpu_addr, GPUVAddr gpu_addr, u64 size);
|
GPUVAddr MapBufferEx(GPUVAddr cpu_addr, GPUVAddr addr, u64 size);
|
||||||
GPUVAddr UnmapBuffer(GPUVAddr gpu_addr, u64 size);
|
GPUVAddr UnmapBuffer(GPUVAddr addr, u64 size);
|
||||||
std::optional<VAddr> GpuToCpuAddress(GPUVAddr gpu_addr);
|
std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T Read(GPUVAddr vaddr);
|
T Read(GPUVAddr addr);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Write(GPUVAddr vaddr, T data);
|
void Write(GPUVAddr addr, T data);
|
||||||
|
|
||||||
u8* GetPointer(GPUVAddr vaddr);
|
u8* GetPointer(GPUVAddr addr);
|
||||||
|
|
||||||
void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size);
|
void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size);
|
||||||
void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size);
|
void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size);
|
||||||
|
@ -69,6 +69,7 @@ private:
|
||||||
using VMAHandle = VMAMap::const_iterator;
|
using VMAHandle = VMAMap::const_iterator;
|
||||||
using VMAIter = VMAMap::iterator;
|
using VMAIter = VMAMap::iterator;
|
||||||
|
|
||||||
|
bool IsAddressValid(GPUVAddr addr) const;
|
||||||
void MapPages(GPUVAddr base, u64 size, u8* memory, Common::PageType type,
|
void MapPages(GPUVAddr base, u64 size, u8* memory, Common::PageType type,
|
||||||
VAddr backing_addr = 0);
|
VAddr backing_addr = 0);
|
||||||
void MapMemoryRegion(GPUVAddr base, u64 size, u8* target, VAddr backing_addr);
|
void MapMemoryRegion(GPUVAddr base, u64 size, u8* target, VAddr backing_addr);
|
||||||
|
|
Loading…
Reference in a new issue