diff options
Diffstat (limited to 'Ryujinx.Memory/Tracking/VirtualRegion.cs')
| -rw-r--r-- | Ryujinx.Memory/Tracking/VirtualRegion.cs | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/Ryujinx.Memory/Tracking/VirtualRegion.cs b/Ryujinx.Memory/Tracking/VirtualRegion.cs new file mode 100644 index 00000000..90fb55d6 --- /dev/null +++ b/Ryujinx.Memory/Tracking/VirtualRegion.cs @@ -0,0 +1,165 @@ +using Ryujinx.Memory.Range; +using System.Collections.Generic; + +namespace Ryujinx.Memory.Tracking +{ + /// <summary> + /// A region of virtual memory. + /// </summary> + class VirtualRegion : AbstractRegion + { + public List<RegionHandle> Handles = new List<RegionHandle>(); + private List<PhysicalRegion> _physicalChildren; + + private readonly MemoryTracking _tracking; + + public VirtualRegion(MemoryTracking tracking, ulong address, ulong size) : base(address, size) + { + _tracking = tracking; + + UpdatePhysicalChildren(); + } + + public override void Signal(ulong address, ulong size, bool write) + { + _tracking.ProtectVirtualRegion(this, MemoryPermission.ReadAndWrite); // Remove our protection immedately. + + foreach (var handle in Handles) + { + handle.Signal(address, size, write); + } + } + + /// <summary> + /// Clears all physical children of this region. Assumes that the tracking lock has been obtained. + /// </summary> + private void ClearPhysicalChildren() + { + if (_physicalChildren != null) + { + foreach (PhysicalRegion child in _physicalChildren) + { + child.RemoveParent(this); + } + } + } + + /// <summary> + /// Updates the physical children of this region, assuming that they are clear and that the tracking lock has been obtained. + /// </summary> + private void UpdatePhysicalChildren() + { + _physicalChildren = _tracking.GetPhysicalRegionsForVirtual(Address, Size); + + foreach (PhysicalRegion child in _physicalChildren) + { + child.VirtualParents.Add(this); + } + } + + /// <summary> + /// Recalculates the physical children for this virtual region. Assumes that the tracking lock has been obtained. + /// </summary> + public void RecalculatePhysicalChildren() + { + ClearPhysicalChildren(); + UpdatePhysicalChildren(); + } + + /// <summary> + /// Gets the strictest permission that the child handles demand. Assumes that the tracking lock has been obtained. + /// </summary> + /// <returns>Protection level that this region demands</returns> + public MemoryPermission GetRequiredPermission() + { + // Start with Read/Write, each handle can strip off permissions as necessary. + // Assumes the tracking lock has already been obtained. + + MemoryPermission result = MemoryPermission.ReadAndWrite; + + foreach (var handle in Handles) + { + result &= handle.RequiredPermission; + if (result == 0) return result; + } + return result; + } + + /// <summary> + /// Updates the protection for this virtual region, and all child physical regions. + /// </summary> + public void UpdateProtection() + { + // Re-evaluate protection for all physical children. + + _tracking.ProtectVirtualRegion(this, GetRequiredPermission()); + lock (_tracking.TrackingLock) + { + foreach (var child in _physicalChildren) + { + child.UpdateProtection(); + } + } + } + + /// <summary> + /// Removes a handle from this virtual region. If there are no handles left, this virtual region is removed. + /// </summary> + /// <param name="handle">Handle to remove</param> + public void RemoveHandle(RegionHandle handle) + { + bool removedRegions = false; + lock (_tracking.TrackingLock) + { + Handles.Remove(handle); + UpdateProtection(); + if (Handles.Count == 0) + { + _tracking.RemoveVirtual(this); + foreach (var child in _physicalChildren) + { + removedRegions |= child.RemoveParent(this); + } + } + } + + if (removedRegions) + { + // The first lock will unprotect any regions that have been removed. This second lock will remove them. + lock (_tracking.TrackingLock) + { + foreach (var child in _physicalChildren) + { + child.TryDelete(); + } + } + } + } + + /// <summary> + /// Add a child physical region to this virtual region. Assumes that the tracking lock has been obtained. + /// </summary> + /// <param name="region">Physical region to add as a child</param> + public void AddChild(PhysicalRegion region) + { + _physicalChildren.Add(region); + } + + public override INonOverlappingRange Split(ulong splitAddress) + { + ClearPhysicalChildren(); + VirtualRegion newRegion = new VirtualRegion(_tracking, splitAddress, EndAddress - splitAddress); + Size = splitAddress - Address; + UpdatePhysicalChildren(); + + // The new region inherits all of our parents. + newRegion.Handles = new List<RegionHandle>(Handles); + foreach (var parent in Handles) + { + parent.AddChild(newRegion); + } + + return newRegion; + } + } +} |
