File shadPS4-PR1822.patch of Package shadPS4

diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index f90d4e6a..343946ca 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -389,12 +389,8 @@ s32 MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) {
     return UnmapMemoryImpl(virtual_addr, size);
 }
 
-s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, size_t size) {
-    const auto it = FindVMA(virtual_addr);
-    const auto& vma_base = it->second;
-    ASSERT_MSG(vma_base.Contains(virtual_addr, size),
-               "Existing mapping does not contain requested unmap range");
-
+size_t MemoryManager::UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma_base,
+                                          size_t size) {
     const auto type = vma_base.type;
     if (type == VMAType::Free) {
         return ORBIS_OK;
@@ -405,16 +401,17 @@ s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, size_t size) {
     const auto phys_base = vma_base.phys_base;
     const bool is_exec = vma_base.is_exec;
     const auto start_in_vma = virtual_addr - vma_base_addr;
+    const auto adjusted_size =
+        vma_base_size - start_in_vma < size ? vma_base_size - start_in_vma : size;
     const bool has_backing = type == VMAType::Direct || type == VMAType::File;
     if (type == VMAType::Direct || type == VMAType::Pooled) {
-        rasterizer->UnmapMemory(virtual_addr, size);
-    }
+        rasterizer->UnmapMemory(virtual_addr, adjusted_size);
     if (type == VMAType::Flexible) {
-        flexible_usage -= size;
+        flexible_usage -= adjusted_size;
     }
 
     // Mark region as free and attempt to coalesce it with neighbours.
-    const auto new_it = CarveVMA(virtual_addr, size);
+    const auto new_it = CarveVMA(virtual_addr, adjusted_size);
     auto& vma = new_it->second;
     vma.type = VMAType::Free;
     vma.prot = MemoryProt::NoAccess;
@@ -426,11 +423,25 @@ s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, size_t size) {
 
     if (type != VMAType::Reserved && type != VMAType::PoolReserved) {
         // Unmap the memory region.
-        impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + size, phys_base,
-                   is_exec, has_backing, readonly_file);
+    impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + adjusted_size, phys_base,
+               is_exec, has_backing, readonly_file);
         TRACK_FREE(virtual_addr, "VMEM");
     }
 
+    return adjusted_size;
+}
+
+s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, size_t size) {
+    auto unmapped_bytes = 0;
+    do {
+        auto it = FindVMA(virtual_addr + unmapped_bytes);
+        auto& vma_base = it->second;
+        auto unmapped =
+            UnmapBytesFromEntry(virtual_addr + unmapped_bytes, vma_base, size - unmapped_bytes);
+        ASSERT_MSG(unmapped > 0, "Failed to unmap memory, progress is impossible");
+        unmapped_bytes += unmapped;
+    } while (unmapped_bytes < size);
+
     return ORBIS_OK;
 }
 
@@ -651,6 +662,12 @@ MemoryManager::VMAHandle MemoryManager::CarveVMA(VAddr virtual_addr, size_t size
 
     const VAddr start_in_vma = virtual_addr - vma.base;
     const VAddr end_in_vma = start_in_vma + size;
+
+    if (start_in_vma == 0 && size == vma.size) {
+        // if requsting the whole VMA, return it
+        return vma_handle;
+    }
+
     ASSERT_MSG(end_in_vma <= vma.size, "Mapping cannot fit inside free region");
 
     if (end_in_vma != vma.size) {
diff --git a/src/core/memory.h b/src/core/memory.h
index 615ecc3e..b8f7e7db 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -252,6 +252,8 @@ private:
 
     DMemHandle Split(DMemHandle dmem_handle, size_t offset_in_area);
 
+    size_t UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma_base, size_t size);
+
     s32 UnmapMemoryImpl(VAddr virtual_addr, size_t size);
 
 private:
openSUSE Build Service is sponsored by