VirtualRegion.cs
1 using Ryujinx.Memory.Range; 2 using System.Collections.Generic; 3 4 namespace Ryujinx.Memory.Tracking 5 { 6 /// <summary> 7 /// A region of virtual memory. 8 /// </summary> 9 class VirtualRegion : AbstractRegion 10 { 11 public List<RegionHandle> Handles = new(); 12 13 private readonly MemoryTracking _tracking; 14 private MemoryPermission _lastPermission; 15 16 public bool Guest { get; } 17 18 public VirtualRegion(MemoryTracking tracking, ulong address, ulong size, bool guest, MemoryPermission lastPermission = MemoryPermission.Invalid) : base(address, size) 19 { 20 _lastPermission = lastPermission; 21 _tracking = tracking; 22 23 Guest = guest; 24 } 25 26 /// <inheritdoc/> 27 public override void Signal(ulong address, ulong size, bool write, int? exemptId) 28 { 29 IList<RegionHandle> handles = Handles; 30 31 for (int i = 0; i < handles.Count; i++) 32 { 33 if (exemptId == null || handles[i].Id != exemptId.Value) 34 { 35 handles[i].Signal(address, size, write, ref handles); 36 } 37 } 38 39 UpdateProtection(); 40 } 41 42 /// <inheritdoc/> 43 public override void SignalPrecise(ulong address, ulong size, bool write, int? exemptId) 44 { 45 IList<RegionHandle> handles = Handles; 46 47 bool allPrecise = true; 48 49 for (int i = 0; i < handles.Count; i++) 50 { 51 if (exemptId == null || handles[i].Id != exemptId.Value) 52 { 53 allPrecise &= handles[i].SignalPrecise(address, size, write, ref handles); 54 } 55 } 56 57 // Only update protection if a regular signal handler was called. 58 // This allows precise actions to skip reprotection costs if they want (they can still do it manually). 59 if (!allPrecise) 60 { 61 UpdateProtection(); 62 } 63 } 64 65 /// <summary> 66 /// Signal that this region has been mapped or unmapped. 67 /// </summary> 68 /// <param name="mapped">True if the region has been mapped, false if unmapped</param> 69 public void SignalMappingChanged(bool mapped) 70 { 71 _lastPermission = MemoryPermission.Invalid; 72 73 if (!Guest) 74 { 75 foreach (RegionHandle handle in Handles) 76 { 77 handle.SignalMappingChanged(mapped); 78 } 79 } 80 } 81 82 /// <summary> 83 /// Gets the strictest permission that the child handles demand. Assumes that the tracking lock has been obtained. 84 /// </summary> 85 /// <returns>Protection level that this region demands</returns> 86 public MemoryPermission GetRequiredPermission() 87 { 88 // Start with Read/Write, each handle can strip off permissions as necessary. 89 // Assumes the tracking lock has already been obtained. 90 91 MemoryPermission result = MemoryPermission.ReadAndWrite; 92 93 foreach (var handle in Handles) 94 { 95 result &= handle.RequiredPermission; 96 if (result == 0) 97 { 98 return result; 99 } 100 } 101 return result; 102 } 103 104 /// <summary> 105 /// Updates the protection for this virtual region. 106 /// </summary> 107 public bool UpdateProtection() 108 { 109 MemoryPermission permission = GetRequiredPermission(); 110 111 if (_lastPermission != permission) 112 { 113 _tracking.ProtectVirtualRegion(this, permission, Guest); 114 _lastPermission = permission; 115 116 return true; 117 } 118 119 return false; 120 } 121 122 /// <summary> 123 /// Removes a handle from this virtual region. If there are no handles left, this virtual region is removed. 124 /// </summary> 125 /// <param name="handle">Handle to remove</param> 126 public void RemoveHandle(RegionHandle handle) 127 { 128 lock (_tracking.TrackingLock) 129 { 130 Handles.Remove(handle); 131 UpdateProtection(); 132 if (Handles.Count == 0) 133 { 134 _tracking.RemoveVirtual(this); 135 } 136 } 137 } 138 139 public override INonOverlappingRange Split(ulong splitAddress) 140 { 141 VirtualRegion newRegion = new(_tracking, splitAddress, EndAddress - splitAddress, Guest, _lastPermission); 142 Size = splitAddress - Address; 143 144 // The new region inherits all of our parents. 145 newRegion.Handles = new List<RegionHandle>(Handles); 146 foreach (var parent in Handles) 147 { 148 parent.AddChild(newRegion); 149 } 150 151 return newRegion; 152 } 153 } 154 }