summaryrefslogtreecommitdiff
path: root/src/core/memory.cpp
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2017-06-21 21:55:24 -0700
committerGravatar Yuri Kunde Schlesner2017-06-21 22:56:31 -0700
commitf2a5a77e278dbca3ce717ecae44b1aa44554c413 (patch)
treef2237690e6f3072ac81dee383f72869a44ade8a3 /src/core/memory.cpp
parentMerge pull request #2792 from wwylele/lutlutlut (diff)
downloadyuzu-f2a5a77e278dbca3ce717ecae44b1aa44554c413.tar.gz
yuzu-f2a5a77e278dbca3ce717ecae44b1aa44554c413.tar.xz
yuzu-f2a5a77e278dbca3ce717ecae44b1aa44554c413.zip
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 b8438e490..9024f4922 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -139,7 +139,12 @@ void UnmapRegion(VAddr base, u32 size) {
139static u8* GetPointerFromVMA(VAddr vaddr) { 139static u8* GetPointerFromVMA(VAddr vaddr) {
140 u8* direct_pointer = nullptr; 140 u8* direct_pointer = nullptr;
141 141
142 auto& vma = Kernel::g_current_process->vm_manager.FindVMA(vaddr)->second; 142 auto& vm_manager = Kernel::g_current_process->vm_manager;
143
144 auto it = vm_manager.FindVMA(vaddr);
145 ASSERT(it != vm_manager.vma_map.end());
146
147 auto& vma = it->second;
143 switch (vma.type) { 148 switch (vma.type) {
144 case Kernel::VMAType::AllocatedMemoryBlock: 149 case Kernel::VMAType::AllocatedMemoryBlock:
145 direct_pointer = vma.backing_block->data() + vma.offset; 150 direct_pointer = vma.backing_block->data() + vma.offset;
@@ -147,6 +152,8 @@ static u8* GetPointerFromVMA(VAddr vaddr) {
147 case Kernel::VMAType::BackingMemory: 152 case Kernel::VMAType::BackingMemory:
148 direct_pointer = vma.backing_memory; 153 direct_pointer = vma.backing_memory;
149 break; 154 break;
155 case Kernel::VMAType::Free:
156 return nullptr;
150 default: 157 default:
151 UNREACHABLE(); 158 UNREACHABLE();
152 } 159 }
@@ -341,11 +348,19 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) {
341 if (res_count == 0) { 348 if (res_count == 0) {
342 PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS]; 349 PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
343 switch (page_type) { 350 switch (page_type) {
344 case PageType::RasterizerCachedMemory: 351 case PageType::RasterizerCachedMemory: {
345 page_type = PageType::Memory; 352 u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK);
346 current_page_table->pointers[vaddr >> PAGE_BITS] = 353 if (pointer == nullptr) {
347 GetPointerFromVMA(vaddr & ~PAGE_MASK); 354 // It's possible that this function has called been while updating the pagetable
355 // after unmapping a VMA. In that case the underlying VMA will no longer exist,
356 // and we should just leave the pagetable entry blank.
357 page_type = PageType::Unmapped;
358 } else {
359 page_type = PageType::Memory;
360 current_page_table->pointers[vaddr >> PAGE_BITS] = pointer;
361 }
348 break; 362 break;
363 }
349 case PageType::RasterizerCachedSpecial: 364 case PageType::RasterizerCachedSpecial:
350 page_type = PageType::Special; 365 page_type = PageType::Special;
351 break; 366 break;