diff options
Diffstat (limited to 'Ryujinx.Memory/Tracking')
-rw-r--r-- | Ryujinx.Memory/Tracking/AbstractRegion.cs | 8 | ||||
-rw-r--r-- | Ryujinx.Memory/Tracking/IRegionHandle.cs | 1 | ||||
-rw-r--r-- | Ryujinx.Memory/Tracking/MemoryTracking.cs | 17 | ||||
-rw-r--r-- | Ryujinx.Memory/Tracking/MultiRegionHandle.cs | 11 | ||||
-rw-r--r-- | Ryujinx.Memory/Tracking/PreciseRegionSignal.cs | 4 | ||||
-rw-r--r-- | Ryujinx.Memory/Tracking/RegionHandle.cs | 35 | ||||
-rw-r--r-- | Ryujinx.Memory/Tracking/SmartMultiRegionHandle.cs | 11 | ||||
-rw-r--r-- | Ryujinx.Memory/Tracking/VirtualRegion.cs | 19 |
8 files changed, 103 insertions, 3 deletions
diff --git a/Ryujinx.Memory/Tracking/AbstractRegion.cs b/Ryujinx.Memory/Tracking/AbstractRegion.cs index ffac439f..a3c3990e 100644 --- a/Ryujinx.Memory/Tracking/AbstractRegion.cs +++ b/Ryujinx.Memory/Tracking/AbstractRegion.cs @@ -53,6 +53,14 @@ namespace Ryujinx.Memory.Tracking public abstract void Signal(ulong address, ulong size, bool write); /// <summary> + /// Signals to the handles that a precise memory event has occurred. Assumes that the tracking lock has been obtained. + /// </summary> + /// <param name="address">Address accessed</param> + /// <param name="size">Size of the region affected in bytes</param> + /// <param name="write">Whether the region was written to or read</param> + public abstract void SignalPrecise(ulong address, ulong size, bool write); + + /// <summary> /// Split this region into two, around the specified address. /// This region is updated to end at the split address, and a new region is created to represent past that point. /// </summary> diff --git a/Ryujinx.Memory/Tracking/IRegionHandle.cs b/Ryujinx.Memory/Tracking/IRegionHandle.cs index ec802cb3..9d99d90e 100644 --- a/Ryujinx.Memory/Tracking/IRegionHandle.cs +++ b/Ryujinx.Memory/Tracking/IRegionHandle.cs @@ -13,5 +13,6 @@ namespace Ryujinx.Memory.Tracking void ForceDirty(); void Reprotect(bool asDirty = false); void RegisterAction(RegionSignal action); + void RegisterPreciseAction(PreciseRegionSignal action); } } diff --git a/Ryujinx.Memory/Tracking/MemoryTracking.cs b/Ryujinx.Memory/Tracking/MemoryTracking.cs index ed3d7e38..aa7f9a6c 100644 --- a/Ryujinx.Memory/Tracking/MemoryTracking.cs +++ b/Ryujinx.Memory/Tracking/MemoryTracking.cs @@ -190,12 +190,15 @@ namespace Ryujinx.Memory.Tracking /// <summary> /// Signal that a virtual memory event happened at the given location. + /// This can be flagged as a precise event, which will avoid reprotection and call special handlers if possible. + /// A precise event has an exact address and size, rather than triggering on page granularity. /// </summary> /// <param name="address">Virtual address accessed</param> /// <param name="size">Size of the region affected in bytes</param> /// <param name="write">Whether the region was written to or read</param> + /// <param name="precise">True if the access is precise, false otherwise</param> /// <returns>True if the event triggered any tracking regions, false otherwise</returns> - public bool VirtualMemoryEvent(ulong address, ulong size, bool write) + public bool VirtualMemoryEvent(ulong address, ulong size, bool write, bool precise = false) { // Look up the virtual region using the region list. // Signal up the chain to relevant handles. @@ -206,7 +209,7 @@ namespace Ryujinx.Memory.Tracking int count = _virtualRegions.FindOverlapsNonOverlapping(address, size, ref overlaps); - if (count == 0) + if (count == 0 && !precise) { if (!_memoryManager.IsMapped(address)) { @@ -224,7 +227,15 @@ namespace Ryujinx.Memory.Tracking for (int i = 0; i < count; i++) { VirtualRegion region = overlaps[i]; - region.Signal(address, size, write); + + if (precise) + { + region.SignalPrecise(address, size, write); + } + else + { + region.Signal(address, size, write); + } } } diff --git a/Ryujinx.Memory/Tracking/MultiRegionHandle.cs b/Ryujinx.Memory/Tracking/MultiRegionHandle.cs index 638e7290..cce7ccb4 100644 --- a/Ryujinx.Memory/Tracking/MultiRegionHandle.cs +++ b/Ryujinx.Memory/Tracking/MultiRegionHandle.cs @@ -206,6 +206,17 @@ namespace Ryujinx.Memory.Tracking } } + public void RegisterPreciseAction(ulong address, ulong size, PreciseRegionSignal action) + { + int startHandle = (int)((address - Address) / Granularity); + int lastHandle = (int)((address + (size - 1) - Address) / Granularity); + + for (int i = startHandle; i <= lastHandle; i++) + { + _handles[i].RegisterPreciseAction(action); + } + } + public void Dispose() { foreach (var handle in _handles) diff --git a/Ryujinx.Memory/Tracking/PreciseRegionSignal.cs b/Ryujinx.Memory/Tracking/PreciseRegionSignal.cs new file mode 100644 index 00000000..038f9595 --- /dev/null +++ b/Ryujinx.Memory/Tracking/PreciseRegionSignal.cs @@ -0,0 +1,4 @@ +namespace Ryujinx.Memory.Tracking +{ + public delegate bool PreciseRegionSignal(ulong address, ulong size, bool write); +} diff --git a/Ryujinx.Memory/Tracking/RegionHandle.cs b/Ryujinx.Memory/Tracking/RegionHandle.cs index 40deba98..5ecd53a2 100644 --- a/Ryujinx.Memory/Tracking/RegionHandle.cs +++ b/Ryujinx.Memory/Tracking/RegionHandle.cs @@ -37,6 +37,7 @@ namespace Ryujinx.Memory.Tracking private object _preActionLock = new object(); private RegionSignal _preAction; // Action to perform before a read or write. This will block the memory access. + private PreciseRegionSignal _preciseAction; // Action to perform on a precise read or write. private readonly List<VirtualRegion> _regions; private readonly MemoryTracking _tracking; private bool _disposed; @@ -113,7 +114,10 @@ namespace Ryujinx.Memory.Tracking /// <summary> /// Signal that a memory action occurred within this handle's virtual regions. /// </summary> + /// <param name="address">Address accessed</param> + /// <param name="size">Size of the region affected in bytes</param> /// <param name="write">Whether the region was written to or read</param> + /// <param name="handleIterable">Reference to the handles being iterated, in case the list needs to be copied</param> internal void Signal(ulong address, ulong size, bool write, ref IList<RegionHandle> handleIterable) { // If this handle was already unmapped (even if just partially), @@ -164,6 +168,27 @@ namespace Ryujinx.Memory.Tracking } /// <summary> + /// Signal that a precise memory action occurred within this handle's virtual regions. + /// If there is no precise action, or the action returns false, the normal signal handler will be called. + /// </summary> + /// <param name="address">Address accessed</param> + /// <param name="size">Size of the region affected in bytes</param> + /// <param name="write">Whether the region was written to or read</param> + /// <param name="handleIterable">Reference to the handles being iterated, in case the list needs to be copied</param> + /// <returns>True if a precise action was performed and returned true, false otherwise</returns> + internal bool SignalPrecise(ulong address, ulong size, bool write, ref IList<RegionHandle> handleIterable) + { + if (!Unmapped && _preciseAction != null && _preciseAction(address, size, write)) + { + return true; + } + + Signal(address, size, write, ref handleIterable); + + return false; + } + + /// <summary> /// Force this handle to be dirty, without reprotecting. /// </summary> public void ForceDirty() @@ -244,6 +269,16 @@ namespace Ryujinx.Memory.Tracking } /// <summary> + /// Register an action to perform when a precise access occurs (one with exact address and size). + /// If the action returns true, read/write tracking are skipped. + /// </summary> + /// <param name="action">Action to call on read or write</param> + public void RegisterPreciseAction(PreciseRegionSignal action) + { + _preciseAction = action; + } + + /// <summary> /// Register an action to perform when the region is written to. /// This action will not be removed when it is called - it is called each time the dirty flag is set. /// </summary> diff --git a/Ryujinx.Memory/Tracking/SmartMultiRegionHandle.cs b/Ryujinx.Memory/Tracking/SmartMultiRegionHandle.cs index eabbd723..47fe72e5 100644 --- a/Ryujinx.Memory/Tracking/SmartMultiRegionHandle.cs +++ b/Ryujinx.Memory/Tracking/SmartMultiRegionHandle.cs @@ -63,6 +63,17 @@ namespace Ryujinx.Memory.Tracking } } + public void RegisterPreciseAction(PreciseRegionSignal action) + { + foreach (var handle in _handles) + { + if (handle != null) + { + handle?.RegisterPreciseAction((address, size, write) => action(handle.Address, handle.Size, write)); + } + } + } + public void QueryModified(Action<ulong, ulong> modifiedAction) { if (!Dirty) diff --git a/Ryujinx.Memory/Tracking/VirtualRegion.cs b/Ryujinx.Memory/Tracking/VirtualRegion.cs index 40f56351..57a0344a 100644 --- a/Ryujinx.Memory/Tracking/VirtualRegion.cs +++ b/Ryujinx.Memory/Tracking/VirtualRegion.cs @@ -31,6 +31,25 @@ namespace Ryujinx.Memory.Tracking UpdateProtection(); } + public override void SignalPrecise(ulong address, ulong size, bool write) + { + IList<RegionHandle> handles = Handles; + + bool allPrecise = true; + + for (int i = 0; i < handles.Count; i++) + { + allPrecise &= handles[i].SignalPrecise(address, size, write, ref handles); + } + + // Only update protection if a regular signal handler was called. + // This allows precise actions to skip reprotection costs if they want (they can still do it manually). + if (!allPrecise) + { + UpdateProtection(); + } + } + /// <summary> /// Signal that this region has been mapped or unmapped. /// </summary> |