From 41f6c9f87f3cd231954cd401be39653c4f78740a Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Sun, 24 Sep 2017 20:52:46 -0500
Subject: [PATCH] Memory/RasterizerCache: Ignore unmapped memory regions when
 caching physical regions.

Not all physical regions need to be mapped into the address space of every process, for example, system modules do not have a VRAM mapping.

This fixes a crash when loading applets and system modules.
---
 src/core/memory.cpp | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 68a6b1ac26..2f5cdcefe4 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -316,8 +316,15 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, int count_delta) {
 
     for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) {
         boost::optional<VAddr> maybe_vaddr = PhysicalToVirtualAddress(paddr);
-        if (!maybe_vaddr)
+        // While the physical <-> virtual mapping is 1:1 for the regions supported by the cache,
+        // some games (like Pokemon Super Mystery Dungeon) will try to use textures that go beyond
+        // the end address of VRAM, causing the Virtual->Physical translation to fail when flushing
+        // parts of the texture.
+        if (!maybe_vaddr) {
+            LOG_ERROR(HW_Memory,
+                      "Trying to flush a cached region to an invalid physical address %08X", paddr);
             continue;
+        }
         VAddr vaddr = *maybe_vaddr;
 
         u8& res_count = current_page_table->cached_res_count[vaddr >> PAGE_BITS];
@@ -329,6 +336,10 @@ 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::Unmapped:
+                // It is not necessary for a process to have this region mapped into its address
+                // space, for example, a system module need not have a VRAM mapping.
+                break;
             case PageType::Memory:
                 page_type = PageType::RasterizerCachedMemory;
                 current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
@@ -347,6 +358,10 @@ 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::Unmapped:
+                // It is not necessary for a process to have this region mapped into its address
+                // space, for example, a system module need not have a VRAM mapping.
+                break;
             case PageType::RasterizerCachedMemory: {
                 u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK);
                 if (pointer == nullptr) {