Ryujinx/Ryujinx.Memory/MemoryManagementWindows.cs
gdkchan f77694e4f7
Implement a new physical memory manager and replace DeviceMemory (#856)
* Implement a new physical memory manager and replace DeviceMemory

* Proper generic constraints

* Fix debug build

* Add memory tests

* New CPU memory manager and general code cleanup

* Remove host memory management from CPU project, use Ryujinx.Memory instead

* Fix tests

* Document exceptions on MemoryBlock

* Fix leak on unix memory allocation

* Proper disposal of some objects on tests

* Fix JitCache not being set as initialized

* GetRef without checks for 8-bits and 16-bits CAS

* Add MemoryBlock destructor

* Throw in separate method to improve codegen

* Address PR feedback

* QueryModified improvements

* Fix memory write tracking not marking all pages as modified in some cases

* Simplify MarkRegionAsModified

* Remove XML doc for ghost param

* Add back optimization to avoid useless buffer updates

* Add Ryujinx.Cpu project, move MemoryManager there and remove MemoryBlockWrapper

* Some nits

* Do not perform address translation when size is 0

* Address PR feedback and format NativeInterface class

* Remove ghost parameter description

* Update Ryujinx.Cpu to .NET Core 3.1

* Address PR feedback

* Fix build

* Return a well defined value for GetPhysicalAddress with invalid VA, and do not return unmapped ranges as modified

* Typo
2020-05-04 08:54:50 +10:00

106 lines
3.4 KiB
C#

using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Memory
{
static class MemoryManagementWindows
{
[Flags]
private enum AllocationType : uint
{
Commit = 0x1000,
Reserve = 0x2000,
Decommit = 0x4000,
Release = 0x8000,
Reset = 0x80000,
Physical = 0x400000,
TopDown = 0x100000,
WriteWatch = 0x200000,
LargePages = 0x20000000
}
[Flags]
private enum MemoryProtection : uint
{
NoAccess = 0x01,
ReadOnly = 0x02,
ReadWrite = 0x04,
WriteCopy = 0x08,
Execute = 0x10,
ExecuteRead = 0x20,
ExecuteReadWrite = 0x40,
ExecuteWriteCopy = 0x80,
GuardModifierflag = 0x100,
NoCacheModifierflag = 0x200,
WriteCombineModifierflag = 0x400
}
[DllImport("kernel32.dll")]
private static extern IntPtr VirtualAlloc(
IntPtr lpAddress,
IntPtr dwSize,
AllocationType flAllocationType,
MemoryProtection flProtect);
[DllImport("kernel32.dll")]
private static extern bool VirtualProtect(
IntPtr lpAddress,
IntPtr dwSize,
MemoryProtection flNewProtect,
out MemoryProtection lpflOldProtect);
[DllImport("kernel32.dll")]
private static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, AllocationType dwFreeType);
public static IntPtr Allocate(IntPtr size)
{
return AllocateInternal(size, AllocationType.Reserve | AllocationType.Commit);
}
public static IntPtr Reserve(IntPtr size)
{
return AllocateInternal(size, AllocationType.Reserve);
}
private static IntPtr AllocateInternal(IntPtr size, AllocationType flags = 0)
{
IntPtr ptr = VirtualAlloc(IntPtr.Zero, size, flags, MemoryProtection.ReadWrite);
if (ptr == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
return ptr;
}
public static bool Commit(IntPtr location, IntPtr size)
{
return VirtualAlloc(location, size, AllocationType.Commit, MemoryProtection.ReadWrite) != IntPtr.Zero;
}
public static bool Reprotect(IntPtr address, IntPtr size, MemoryPermission permission)
{
return VirtualProtect(address, size, GetProtection(permission), out _);
}
private static MemoryProtection GetProtection(MemoryPermission permission)
{
return permission switch
{
MemoryPermission.None => MemoryProtection.NoAccess,
MemoryPermission.Read => MemoryProtection.ReadOnly,
MemoryPermission.ReadAndWrite => MemoryProtection.ReadWrite,
MemoryPermission.ReadAndExecute => MemoryProtection.ExecuteRead,
MemoryPermission.ReadWriteExecute => MemoryProtection.ExecuteReadWrite,
MemoryPermission.Execute => MemoryProtection.Execute,
_ => throw new MemoryProtectionException(permission)
};
}
public static bool Free(IntPtr address)
{
return VirtualFree(address, IntPtr.Zero, AllocationType.Release);
}
}
}