MemoryManagementWindows.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. using Ryujinx.Memory.WindowsShared;
  2. using System;
  3. using System.Runtime.Versioning;
  4. namespace Ryujinx.Memory
  5. {
  6. [SupportedOSPlatform("windows")]
  7. static class MemoryManagementWindows
  8. {
  9. public const int PageSize = 0x1000;
  10. private static readonly PlaceholderManager _placeholders = new PlaceholderManager();
  11. private static readonly PlaceholderManager4KB _placeholders4KB = new PlaceholderManager4KB();
  12. public static IntPtr Allocate(IntPtr size)
  13. {
  14. return AllocateInternal(size, AllocationType.Reserve | AllocationType.Commit);
  15. }
  16. public static IntPtr Reserve(IntPtr size, bool viewCompatible, bool force4KBMap)
  17. {
  18. if (viewCompatible)
  19. {
  20. IntPtr baseAddress = AllocateInternal2(size, AllocationType.Reserve | AllocationType.ReservePlaceholder);
  21. if (!force4KBMap)
  22. {
  23. _placeholders.ReserveRange((ulong)baseAddress, (ulong)size);
  24. }
  25. return baseAddress;
  26. }
  27. return AllocateInternal(size, AllocationType.Reserve);
  28. }
  29. private static IntPtr AllocateInternal(IntPtr size, AllocationType flags = 0)
  30. {
  31. IntPtr ptr = WindowsApi.VirtualAlloc(IntPtr.Zero, size, flags, MemoryProtection.ReadWrite);
  32. if (ptr == IntPtr.Zero)
  33. {
  34. throw new OutOfMemoryException();
  35. }
  36. return ptr;
  37. }
  38. private static IntPtr AllocateInternal2(IntPtr size, AllocationType flags = 0)
  39. {
  40. IntPtr ptr = WindowsApi.VirtualAlloc2(WindowsApi.CurrentProcessHandle, IntPtr.Zero, size, flags, MemoryProtection.NoAccess, IntPtr.Zero, 0);
  41. if (ptr == IntPtr.Zero)
  42. {
  43. throw new OutOfMemoryException();
  44. }
  45. return ptr;
  46. }
  47. public static bool Commit(IntPtr location, IntPtr size)
  48. {
  49. return WindowsApi.VirtualAlloc(location, size, AllocationType.Commit, MemoryProtection.ReadWrite) != IntPtr.Zero;
  50. }
  51. public static bool Decommit(IntPtr location, IntPtr size)
  52. {
  53. return WindowsApi.VirtualFree(location, size, AllocationType.Decommit);
  54. }
  55. public static void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size, MemoryBlock owner)
  56. {
  57. _placeholders.MapView(sharedMemory, srcOffset, location, size, owner);
  58. }
  59. public static void MapView4KB(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size)
  60. {
  61. _placeholders4KB.UnmapAndMarkRangeAsMapped(location, size);
  62. ulong uaddress = (ulong)location;
  63. ulong usize = (ulong)size;
  64. IntPtr endLocation = (IntPtr)(uaddress + usize);
  65. while (location != endLocation)
  66. {
  67. WindowsApi.VirtualFree(location, (IntPtr)PageSize, AllocationType.Release | AllocationType.PreservePlaceholder);
  68. var ptr = WindowsApi.MapViewOfFile3(
  69. sharedMemory,
  70. WindowsApi.CurrentProcessHandle,
  71. location,
  72. srcOffset,
  73. (IntPtr)PageSize,
  74. 0x4000,
  75. MemoryProtection.ReadWrite,
  76. IntPtr.Zero,
  77. 0);
  78. if (ptr == IntPtr.Zero)
  79. {
  80. throw new WindowsApiException("MapViewOfFile3");
  81. }
  82. location += PageSize;
  83. srcOffset += PageSize;
  84. }
  85. }
  86. public static void UnmapView(IntPtr sharedMemory, IntPtr location, IntPtr size, MemoryBlock owner)
  87. {
  88. _placeholders.UnmapView(sharedMemory, location, size, owner);
  89. }
  90. public static void UnmapView4KB(IntPtr location, IntPtr size)
  91. {
  92. _placeholders4KB.UnmapView(location, size);
  93. }
  94. public static bool Reprotect(IntPtr address, IntPtr size, MemoryPermission permission, bool forView)
  95. {
  96. if (forView)
  97. {
  98. return _placeholders.ReprotectView(address, size, permission);
  99. }
  100. else
  101. {
  102. return WindowsApi.VirtualProtect(address, size, WindowsApi.GetProtection(permission), out _);
  103. }
  104. }
  105. public static bool Reprotect4KB(IntPtr address, IntPtr size, MemoryPermission permission, bool forView)
  106. {
  107. ulong uaddress = (ulong)address;
  108. ulong usize = (ulong)size;
  109. while (usize > 0)
  110. {
  111. if (!WindowsApi.VirtualProtect((IntPtr)uaddress, (IntPtr)PageSize, WindowsApi.GetProtection(permission), out _))
  112. {
  113. return false;
  114. }
  115. uaddress += PageSize;
  116. usize -= PageSize;
  117. }
  118. return true;
  119. }
  120. public static bool Free(IntPtr address, IntPtr size, bool force4KBMap)
  121. {
  122. if (force4KBMap)
  123. {
  124. _placeholders4KB.UnmapRange(address, size);
  125. }
  126. else
  127. {
  128. _placeholders.UnreserveRange((ulong)address, (ulong)size);
  129. }
  130. return WindowsApi.VirtualFree(address, IntPtr.Zero, AllocationType.Release);
  131. }
  132. public static IntPtr CreateSharedMemory(IntPtr size, bool reserve)
  133. {
  134. var prot = reserve ? FileMapProtection.SectionReserve : FileMapProtection.SectionCommit;
  135. IntPtr handle = WindowsApi.CreateFileMapping(
  136. WindowsApi.InvalidHandleValue,
  137. IntPtr.Zero,
  138. FileMapProtection.PageReadWrite | prot,
  139. (uint)(size.ToInt64() >> 32),
  140. (uint)size.ToInt64(),
  141. null);
  142. if (handle == IntPtr.Zero)
  143. {
  144. throw new OutOfMemoryException();
  145. }
  146. return handle;
  147. }
  148. public static void DestroySharedMemory(IntPtr handle)
  149. {
  150. if (!WindowsApi.CloseHandle(handle))
  151. {
  152. throw new ArgumentException("Invalid handle.", nameof(handle));
  153. }
  154. }
  155. public static IntPtr MapSharedMemory(IntPtr handle)
  156. {
  157. IntPtr ptr = WindowsApi.MapViewOfFile(handle, 4 | 2, 0, 0, IntPtr.Zero);
  158. if (ptr == IntPtr.Zero)
  159. {
  160. throw new OutOfMemoryException();
  161. }
  162. return ptr;
  163. }
  164. public static void UnmapSharedMemory(IntPtr address)
  165. {
  166. if (!WindowsApi.UnmapViewOfFile(address))
  167. {
  168. throw new ArgumentException("Invalid address.", nameof(address));
  169. }
  170. }
  171. public static bool RetryFromAccessViolation()
  172. {
  173. return _placeholders.RetryFromAccessViolation();
  174. }
  175. }
  176. }