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.
master
Yuri Kunde Schlesner 2017-06-21 21:55:24 +07:00
parent 72b69cea4b
commit f2a5a77e27
1 changed files with 20 additions and 5 deletions

@ -139,7 +139,12 @@ void UnmapRegion(VAddr base, u32 size) {
static u8* GetPointerFromVMA(VAddr vaddr) { static u8* GetPointerFromVMA(VAddr vaddr) {
u8* direct_pointer = nullptr; 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) { switch (vma.type) {
case Kernel::VMAType::AllocatedMemoryBlock: case Kernel::VMAType::AllocatedMemoryBlock:
direct_pointer = vma.backing_block->data() + vma.offset; direct_pointer = vma.backing_block->data() + vma.offset;
@ -147,6 +152,8 @@ static u8* GetPointerFromVMA(VAddr vaddr) {
case Kernel::VMAType::BackingMemory: case Kernel::VMAType::BackingMemory:
direct_pointer = vma.backing_memory; direct_pointer = vma.backing_memory;
break; break;
case Kernel::VMAType::Free:
return nullptr;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
@ -341,11 +348,19 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) {
if (res_count == 0) { if (res_count == 0) {
PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS]; PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
switch (page_type) { switch (page_type) {
case PageType::RasterizerCachedMemory: case PageType::RasterizerCachedMemory: {
page_type = PageType::Memory; u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK);
current_page_table->pointers[vaddr >> PAGE_BITS] = if (pointer == nullptr) {
GetPointerFromVMA(vaddr & ~PAGE_MASK); // 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; break;
}
case PageType::RasterizerCachedSpecial: case PageType::RasterizerCachedSpecial:
page_type = PageType::Special; page_type = PageType::Special;
break; break;