mirror of
https://github.com/citra-emu/citra-nightly.git
synced 2024-12-24 01:15:37 +00:00
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.
This commit is contained in:
parent
72b69cea4b
commit
f2a5a77e27
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue