Initial work

This commit is contained in:
gdk 2019-10-13 03:02:07 -03:00 committed by Thog
parent f617fb542a
commit 1876b346fe
518 changed files with 15170 additions and 12486 deletions

View file

@ -355,12 +355,9 @@ namespace ARMeilleure.Instructions
}
while (bit < context.Memory.AddressSpaceBits);
if (!context.Memory.HasWriteWatchSupport)
{
Operand hasFlagSet = context.BitwiseAnd(pte, Const((long)MemoryManager.PteFlagsMask));
Operand hasFlagSet = context.BitwiseAnd(pte, Const((long)MemoryManager.PteFlagsMask));
context.BranchIfTrue(lblFallbackPath, hasFlagSet);
}
context.BranchIfTrue(lblFallbackPath, hasFlagSet);
Operand pageOffset = context.BitwiseAnd(address, Const(address.Type, MemoryManager.PageMask));

View file

@ -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);
}
}

View file

@ -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;
}
}
}
}

View file

@ -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;
}
}
}

View file

@ -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);