aboutsummaryrefslogtreecommitdiff
path: root/src/core/memory.cpp
diff options
context:
space:
mode:
authorYuri Kunde Schlesner <yuriks@yuriks.net>2017-06-21 21:55:24 -0700
committerYuri Kunde Schlesner <yuriks@yuriks.net>2017-06-21 22:56:31 -0700
commit3bc103446552648c0205f93b0c2005dc39f52cf9 (patch)
treef2237690e6f3072ac81dee383f72869a44ade8a3 /src/core/memory.cpp
parent294e6b6306c48995e0277dc58cbba12a6f25573e (diff)
Memory: Fix crash when unmapping a VMA covering cached surfaces
Unmapping pages tries to flush any cached GPU surfaces touching that region. When a cached page is invalidated, GetPointerFromVMA() is used to restore the original pagetable pointer. However, since that VMA has already been deleted, this hits an UNREACHABLE case in that function. Now when this happens, just set the page type to Unmapped and continue, which arrives at the correct end result.
Diffstat (limited to 'src/core/memory.cpp')
-rw-r--r--src/core/memory.cpp25
1 files changed, 20 insertions, 5 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index b8438e490e..9024f49225 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -139,7 +139,12 @@ void UnmapRegion(VAddr base, u32 size) {
static u8* GetPointerFromVMA(VAddr vaddr) {
u8* direct_pointer = nullptr;
- auto& vma = Kernel::g_current_process->vm_manager.FindVMA(vaddr)->second;
+ auto& vm_manager = Kernel::g_current_process->vm_manager;
+
+ auto it = vm_manager.FindVMA(vaddr);
+ ASSERT(it != vm_manager.vma_map.end());
+
+ auto& vma = it->second;
switch (vma.type) {
case Kernel::VMAType::AllocatedMemoryBlock:
direct_pointer = vma.backing_block->data() + vma.offset;
@@ -147,6 +152,8 @@ static u8* GetPointerFromVMA(VAddr vaddr) {
case Kernel::VMAType::BackingMemory:
direct_pointer = vma.backing_memory;
break;
+ case Kernel::VMAType::Free:
+ return nullptr;
default:
UNREACHABLE();
}
@@ -341,11 +348,19 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) {
if (res_count == 0) {
PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
switch (page_type) {
- case PageType::RasterizerCachedMemory:
- page_type = PageType::Memory;
- current_page_table->pointers[vaddr >> PAGE_BITS] =
- GetPointerFromVMA(vaddr & ~PAGE_MASK);
+ case PageType::RasterizerCachedMemory: {
+ u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK);
+ if (pointer == nullptr) {
+ // It's possible that this function has called been 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.
+ page_type = PageType::Unmapped;
+ } else {
+ page_type = PageType::Memory;
+ current_page_table->pointers[vaddr >> PAGE_BITS] = pointer;
+ }
break;
+ }
case PageType::RasterizerCachedSpecial:
page_type = PageType::Special;
break;