aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Memory.Tests
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Memory.Tests')
-rw-r--r--Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs3
-rw-r--r--Ryujinx.Memory.Tests/TrackingTests.cs63
2 files changed, 66 insertions, 0 deletions
diff --git a/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs b/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs
index 62b3ee4a..0dd2ce46 100644
--- a/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs
+++ b/Ryujinx.Memory.Tests/MockVirtualMemoryManager.cs
@@ -6,6 +6,8 @@ namespace Ryujinx.Memory.Tests
{
public bool NoMappings;
+ public event Action<ulong, ulong, MemoryPermission> OnProtect;
+
public MockVirtualMemoryManager(ulong size, int pageSize)
{
}
@@ -82,6 +84,7 @@ namespace Ryujinx.Memory.Tests
public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection)
{
+ OnProtect?.Invoke(va, size, protection);
}
}
}
diff --git a/Ryujinx.Memory.Tests/TrackingTests.cs b/Ryujinx.Memory.Tests/TrackingTests.cs
index 25c23092..a9cc6df3 100644
--- a/Ryujinx.Memory.Tests/TrackingTests.cs
+++ b/Ryujinx.Memory.Tests/TrackingTests.cs
@@ -421,5 +421,68 @@ namespace Ryujinx.Memory.Tests
Assert.AreEqual((0, 0), _tracking.GetRegionCounts());
}
+
+ [Test]
+ public void ReadAndWriteProtection()
+ {
+ MemoryPermission protection = MemoryPermission.ReadAndWrite;
+
+ _memoryManager.OnProtect += (va, size, newProtection) =>
+ {
+ Assert.AreEqual((0, PageSize), (va, size)); // Should protect the exact region all the operations use.
+ protection = newProtection;
+ };
+
+ RegionHandle handle = _tracking.BeginTracking(0, PageSize);
+
+ // After creating the handle, there is no protection yet.
+ Assert.AreEqual(MemoryPermission.ReadAndWrite, protection);
+
+ bool dirtyInitial = handle.Dirty;
+ Assert.True(dirtyInitial); // Handle starts dirty.
+
+ handle.Reprotect();
+
+ // After a reprotect, there is write protection, which will set a dirty flag when any write happens.
+ Assert.AreEqual(MemoryPermission.Read, protection);
+
+ (ulong address, ulong size)? readTrackingTriggered = null;
+ handle.RegisterAction((address, size) =>
+ {
+ readTrackingTriggered = (address, size);
+ });
+
+ // Registering an action adds read/write protection.
+ Assert.AreEqual(MemoryPermission.None, protection);
+
+ bool dirtyAfterReprotect = handle.Dirty;
+ Assert.False(dirtyAfterReprotect); // Handle is no longer dirty.
+
+ // First we should read, which will trigger the action. This _should not_ remove write protection on the memory.
+
+ _tracking.VirtualMemoryEvent(0, 4, false);
+
+ bool dirtyAfterRead = handle.Dirty;
+ Assert.False(dirtyAfterRead); // Not dirtied, as this was a read.
+
+ Assert.AreEqual(readTrackingTriggered, (0UL, 4UL)); // Read action was triggered.
+
+ Assert.AreEqual(MemoryPermission.Read, protection); // Write protection is still present.
+
+ readTrackingTriggered = null;
+
+ // Now, perform a write.
+
+ _tracking.VirtualMemoryEvent(0, 4, true);
+
+ bool dirtyAfterWriteAfterRead = handle.Dirty;
+ Assert.True(dirtyAfterWriteAfterRead); // Should be dirty.
+
+ Assert.AreEqual(MemoryPermission.ReadAndWrite, protection); // All protection is now be removed from the memory.
+
+ Assert.IsNull(readTrackingTriggered); // Read tracking was removed when the action fired, as it can only fire once.
+
+ handle.Dispose();
+ }
}
}