From 3c60d4b0eaa54983cf8e347fb156742c925f0594 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Tue, 10 Nov 2020 22:07:52 -0300
Subject: [PATCH] Do not report unmapped pages as dirty (#1672)

* Do not report unmapped pages as dirty

* Make tests pass again

* PR feedback
---
 Ryujinx.Cpu/MemoryManager.cs                  | 29 +++++++++++++++++--
 .../MockVirtualMemoryManager.cs               |  5 ++++
 .../Tracking/IVirtualMemoryManager.cs         |  1 +
 Ryujinx.Memory/Tracking/MemoryTracking.cs     |  3 +-
 Ryujinx.Memory/Tracking/RegionHandle.cs       |  6 ++--
 5 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/Ryujinx.Cpu/MemoryManager.cs b/Ryujinx.Cpu/MemoryManager.cs
index 26cc01c9..3fa08fe7 100644
--- a/Ryujinx.Cpu/MemoryManager.cs
+++ b/Ryujinx.Cpu/MemoryManager.cs
@@ -1,4 +1,4 @@
-using ARMeilleure.Memory;
+using ARMeilleure.Memory;
 using Ryujinx.Cpu.Tracking;
 using Ryujinx.Memory;
 using Ryujinx.Memory.Tracking;
@@ -461,7 +461,32 @@ namespace Ryujinx.Cpu
         }
 
         /// <summary>
-        /// Checks if the page at a given CPU virtual address.
+        /// Checks if a memory range is mapped.
+        /// </summary>
+        /// <param name="va">Virtual address of the range</param>
+        /// <param name="size">Size of the range in bytes</param>
+        /// <returns>True if the entire range is mapped, false otherwise</returns>
+        public bool IsRangeMapped(ulong va, ulong size)
+        {
+            ulong endVa = (va + size + PageMask) & ~(ulong)PageMask;
+
+            va &= ~(ulong)PageMask;
+
+            while (va < endVa)
+            {
+                if (!IsMapped(va))
+                {
+                    return false;
+                }
+
+                va += PageSize;
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// Checks if the page at a given CPU virtual address is mapped.
         /// </summary>
         /// <param name="va">Virtual address to check</param>
         /// <returns>True if the address is mapped, false otherwise</returns>
diff --git a/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs b/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs
index f9692cfc..037bedc8 100644
--- a/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs
+++ b/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs
@@ -15,6 +15,11 @@ namespace Ryujinx.Memory.Tests
             return NoMappings ? new (ulong address, ulong size)[0] : new (ulong address, ulong size)[] { (va, size) };
         }
 
+        public bool IsRangeMapped(ulong va, ulong size)
+        {
+            return true;
+        }
+
         public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection)
         {
             
diff --git a/Ryujinx.Memory/Tracking/IVirtualMemoryManager.cs b/Ryujinx.Memory/Tracking/IVirtualMemoryManager.cs
index 6b5474e1..e6d8e8c9 100644
--- a/Ryujinx.Memory/Tracking/IVirtualMemoryManager.cs
+++ b/Ryujinx.Memory/Tracking/IVirtualMemoryManager.cs
@@ -4,6 +4,7 @@
     {
         (ulong address, ulong size)[] GetPhysicalRegions(ulong va, ulong size);
 
+        bool IsRangeMapped(ulong va, ulong size);
         void TrackingReprotect(ulong va, ulong size, MemoryPermission protection);
     }
 }
diff --git a/Ryujinx.Memory/Tracking/MemoryTracking.cs b/Ryujinx.Memory/Tracking/MemoryTracking.cs
index 779166c4..aff223e8 100644
--- a/Ryujinx.Memory/Tracking/MemoryTracking.cs
+++ b/Ryujinx.Memory/Tracking/MemoryTracking.cs
@@ -75,6 +75,7 @@ namespace Ryujinx.Memory.Tracking
                 {
                     VirtualRegion region = results[i];
                     region.RecalculatePhysicalChildren();
+                    region.UpdateProtection();
                 }
             }
         }
@@ -200,7 +201,7 @@ namespace Ryujinx.Memory.Tracking
 
             lock (TrackingLock)
             {
-                RegionHandle handle = new RegionHandle(this, address, size);
+                RegionHandle handle = new RegionHandle(this, address, size, _memoryManager.IsRangeMapped(address, size));
 
                 return handle;
             }
diff --git a/Ryujinx.Memory/Tracking/RegionHandle.cs b/Ryujinx.Memory/Tracking/RegionHandle.cs
index c00d039b..96898c21 100644
--- a/Ryujinx.Memory/Tracking/RegionHandle.cs
+++ b/Ryujinx.Memory/Tracking/RegionHandle.cs
@@ -10,7 +10,7 @@ namespace Ryujinx.Memory.Tracking
     /// </summary>
     public class RegionHandle : IRegionHandle, IRange
     {
-        public bool Dirty { get; private set; } = true;
+        public bool Dirty { get; private set; }
 
         public ulong Address { get; }
         public ulong Size { get; }
@@ -32,8 +32,10 @@ namespace Ryujinx.Memory.Tracking
         /// <param name="tracking">Tracking object for the target memory block</param>
         /// <param name="address">Virtual address of the region to track</param>
         /// <param name="size">Size of the region to track</param>
-        internal RegionHandle(MemoryTracking tracking, ulong address, ulong size)
+        /// <param name="dirty">Initial value of the dirty flag</param>
+        internal RegionHandle(MemoryTracking tracking, ulong address, ulong size, bool dirty = true)
         {
+            Dirty = dirty;
             Address = address;
             Size = size;
             EndAddress = address + size;