VirtualRegion.cs 4.3 KB

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