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