Initial work
This commit is contained in:
parent
f617fb542a
commit
1876b346fe
518 changed files with 15170 additions and 12486 deletions
|
@ -1,37 +0,0 @@
|
|||
namespace ARMeilleure.Memory
|
||||
{
|
||||
public interface IMemory
|
||||
{
|
||||
sbyte ReadSByte(long position);
|
||||
|
||||
short ReadInt16(long position);
|
||||
|
||||
int ReadInt32(long position);
|
||||
|
||||
long ReadInt64(long position);
|
||||
|
||||
byte ReadByte(long position);
|
||||
|
||||
ushort ReadUInt16(long position);
|
||||
|
||||
uint ReadUInt32(long position);
|
||||
|
||||
ulong ReadUInt64(long position);
|
||||
|
||||
void WriteSByte(long position, sbyte value);
|
||||
|
||||
void WriteInt16(long position, short value);
|
||||
|
||||
void WriteInt32(long position, int value);
|
||||
|
||||
void WriteInt64(long position, long value);
|
||||
|
||||
void WriteByte(long position, byte value);
|
||||
|
||||
void WriteUInt16(long position, ushort value);
|
||||
|
||||
void WriteUInt32(long position, uint value);
|
||||
|
||||
void WriteUInt64(long position, ulong value);
|
||||
}
|
||||
}
|
|
@ -6,8 +6,6 @@ namespace ARMeilleure.Memory
|
|||
{
|
||||
public static class MemoryManagement
|
||||
{
|
||||
public static bool HasWriteWatchSupport => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
|
||||
public static IntPtr Allocate(ulong size)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
|
@ -88,27 +86,5 @@ namespace ARMeilleure.Memory
|
|||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool GetModifiedPages(
|
||||
IntPtr address,
|
||||
IntPtr size,
|
||||
IntPtr[] addresses,
|
||||
out ulong count)
|
||||
{
|
||||
// This is only supported on windows, but returning
|
||||
// false (failed) is also valid for platforms without
|
||||
// write tracking support on the OS.
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return MemoryManagementWindows.GetModifiedPages(address, size, addresses, out count);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,12 +36,6 @@ namespace ARMeilleure.Memory
|
|||
WriteCombineModifierflag = 0x400
|
||||
}
|
||||
|
||||
private enum WriteWatchFlags : uint
|
||||
{
|
||||
None = 0,
|
||||
Reset = 1
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr VirtualAlloc(
|
||||
IntPtr lpAddress,
|
||||
|
@ -62,15 +56,6 @@ namespace ARMeilleure.Memory
|
|||
IntPtr dwSize,
|
||||
AllocationType dwFreeType);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern int GetWriteWatch(
|
||||
WriteWatchFlags dwFlags,
|
||||
IntPtr lpBaseAddress,
|
||||
IntPtr dwRegionSize,
|
||||
IntPtr[] lpAddresses,
|
||||
ref ulong lpdwCount,
|
||||
out uint lpdwGranularity);
|
||||
|
||||
public static IntPtr Allocate(IntPtr size)
|
||||
{
|
||||
const AllocationType flags =
|
||||
|
@ -130,27 +115,5 @@ namespace ARMeilleure.Memory
|
|||
{
|
||||
return VirtualFree(address, IntPtr.Zero, AllocationType.Release);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool GetModifiedPages(
|
||||
IntPtr address,
|
||||
IntPtr size,
|
||||
IntPtr[] addresses,
|
||||
out ulong count)
|
||||
{
|
||||
ulong pagesCount = (ulong)addresses.Length;
|
||||
|
||||
int result = GetWriteWatch(
|
||||
WriteWatchFlags.Reset,
|
||||
address,
|
||||
size,
|
||||
addresses,
|
||||
ref pagesCount,
|
||||
out uint granularity);
|
||||
|
||||
count = pagesCount;
|
||||
|
||||
return result == 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
|
@ -29,8 +30,6 @@ namespace ARMeilleure.Memory
|
|||
internal int PtLevelSize { get; }
|
||||
internal int PtLevelMask { get; }
|
||||
|
||||
public bool HasWriteWatchSupport => MemoryManagement.HasWriteWatchSupport;
|
||||
|
||||
public int AddressSpaceBits { get; }
|
||||
public long AddressSpaceSize { get; }
|
||||
|
||||
|
@ -254,119 +253,57 @@ namespace ARMeilleure.Memory
|
|||
return ptePtr;
|
||||
}
|
||||
|
||||
public bool IsRegionModified(long position, long size)
|
||||
public unsafe (ulong, ulong)[] GetModifiedRanges(ulong address, ulong size)
|
||||
{
|
||||
if (!HasWriteWatchSupport)
|
||||
List<(ulong, ulong)> ranges = new List<(ulong, ulong)>();
|
||||
|
||||
ulong endAddress = (address + size + PageMask) & ~(ulong)PageMask;
|
||||
|
||||
address &= ~(ulong)PageMask;
|
||||
|
||||
ulong currAddr = address;
|
||||
ulong currSize = 0;
|
||||
|
||||
while (address < endAddress)
|
||||
{
|
||||
return IsRegionModifiedFallback(position, size);
|
||||
}
|
||||
|
||||
IntPtr address = Translate(position);
|
||||
|
||||
IntPtr baseAddr = address;
|
||||
IntPtr expectedAddr = address;
|
||||
|
||||
long pendingPages = 0;
|
||||
|
||||
long pages = size / PageSize;
|
||||
|
||||
bool modified = false;
|
||||
|
||||
bool IsAnyPageModified()
|
||||
{
|
||||
IntPtr pendingSize = new IntPtr(pendingPages * PageSize);
|
||||
|
||||
IntPtr[] addresses = new IntPtr[pendingPages];
|
||||
|
||||
bool result = GetModifiedPages(baseAddr, pendingSize, addresses, out ulong count);
|
||||
|
||||
if (result)
|
||||
if (IsValidPosition((long)address))
|
||||
{
|
||||
return count != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
while (pages-- > 0)
|
||||
{
|
||||
if (address != expectedAddr)
|
||||
{
|
||||
modified |= IsAnyPageModified();
|
||||
|
||||
baseAddr = address;
|
||||
|
||||
pendingPages = 0;
|
||||
}
|
||||
|
||||
expectedAddr = address + PageSize;
|
||||
|
||||
pendingPages++;
|
||||
|
||||
if (pages == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
position += PageSize;
|
||||
|
||||
address = Translate(position);
|
||||
}
|
||||
|
||||
if (pendingPages != 0)
|
||||
{
|
||||
modified |= IsAnyPageModified();
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
private unsafe bool IsRegionModifiedFallback(long position, long size)
|
||||
{
|
||||
long endAddr = (position + size + PageMask) & ~PageMask;
|
||||
|
||||
bool modified = false;
|
||||
|
||||
while ((ulong)position < (ulong)endAddr)
|
||||
{
|
||||
if (IsValidPosition(position))
|
||||
{
|
||||
byte* ptr = ((byte**)_pageTable)[position >> PageBits];
|
||||
byte* ptr = ((byte**)_pageTable)[address >> PageBits];
|
||||
|
||||
ulong ptrUlong = (ulong)ptr;
|
||||
|
||||
if ((ptrUlong & PteFlagNotModified) == 0)
|
||||
{
|
||||
modified = true;
|
||||
// Modified.
|
||||
currSize += PageSize;
|
||||
|
||||
SetPtEntryFlag(position, PteFlagNotModified);
|
||||
SetPtEntryFlag((long)address, PteFlagNotModified);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currSize != 0)
|
||||
{
|
||||
ranges.Add((currAddr, currSize));
|
||||
}
|
||||
|
||||
currAddr = address + PageSize;
|
||||
currSize = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
modified = true;
|
||||
currSize += PageSize;
|
||||
}
|
||||
|
||||
position += PageSize;
|
||||
address += PageSize;
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
public bool TryGetHostAddress(long position, long size, out IntPtr ptr)
|
||||
{
|
||||
if (IsContiguous(position, size))
|
||||
if (currSize != 0)
|
||||
{
|
||||
ptr = (IntPtr)Translate(position);
|
||||
|
||||
return true;
|
||||
ranges.Add((currAddr, currSize));
|
||||
}
|
||||
|
||||
ptr = IntPtr.Zero;
|
||||
|
||||
return false;
|
||||
return ranges.ToArray();
|
||||
}
|
||||
|
||||
private bool IsContiguous(long position, long size)
|
||||
|
@ -612,41 +549,6 @@ namespace ARMeilleure.Memory
|
|||
return data;
|
||||
}
|
||||
|
||||
public void ReadBytes(long position, byte[] data, int startIndex, int size)
|
||||
{
|
||||
// Note: This will be moved later.
|
||||
long endAddr = position + size;
|
||||
|
||||
if ((ulong)size > int.MaxValue)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
if ((ulong)endAddr < (ulong)position)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(position));
|
||||
}
|
||||
|
||||
int offset = startIndex;
|
||||
|
||||
while ((ulong)position < (ulong)endAddr)
|
||||
{
|
||||
long pageLimit = (position + PageSize) & ~(long)PageMask;
|
||||
|
||||
if ((ulong)pageLimit > (ulong)endAddr)
|
||||
{
|
||||
pageLimit = endAddr;
|
||||
}
|
||||
|
||||
int copySize = (int)(pageLimit - position);
|
||||
|
||||
Marshal.Copy(Translate(position), data, offset, copySize);
|
||||
|
||||
position += copySize;
|
||||
offset += copySize;
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteSByte(long position, sbyte value)
|
||||
{
|
||||
WriteByte(position, (byte)value);
|
||||
|
@ -746,53 +648,6 @@ namespace ARMeilleure.Memory
|
|||
}
|
||||
}
|
||||
|
||||
public void WriteBytes(long position, byte[] data, int startIndex, int size)
|
||||
{
|
||||
// Note: This will be moved later.
|
||||
long endAddr = position + size;
|
||||
|
||||
if ((ulong)endAddr < (ulong)position)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(position));
|
||||
}
|
||||
|
||||
int offset = startIndex;
|
||||
|
||||
while ((ulong)position < (ulong)endAddr)
|
||||
{
|
||||
long pageLimit = (position + PageSize) & ~(long)PageMask;
|
||||
|
||||
if ((ulong)pageLimit > (ulong)endAddr)
|
||||
{
|
||||
pageLimit = endAddr;
|
||||
}
|
||||
|
||||
int copySize = (int)(pageLimit - position);
|
||||
|
||||
Marshal.Copy(data, offset, Translate(position), copySize);
|
||||
|
||||
position += copySize;
|
||||
offset += copySize;
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyBytes(long src, long dst, long size)
|
||||
{
|
||||
// Note: This will be moved later.
|
||||
if (IsContiguous(src, size) &&
|
||||
IsContiguous(dst, size))
|
||||
{
|
||||
byte* srcPtr = (byte*)Translate(src);
|
||||
byte* dstPtr = (byte*)Translate(dst);
|
||||
|
||||
Buffer.MemoryCopy(srcPtr, dstPtr, size, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteBytes(dst, ReadBytes(src, size));
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue