From 3bc103446552648c0205f93b0c2005dc39f52cf9 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Wed, 21 Jun 2017 21:55:24 -0700 Subject: [PATCH] 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. --- src/core/memory.cpp | 25 ++++++++++++++++++++----- 1 file 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;