diff options
Diffstat (limited to 'ARMeilleure/Memory')
| -rw-r--r-- | ARMeilleure/Memory/IJitMemoryAllocator.cs | 8 | ||||
| -rw-r--r-- | ARMeilleure/Memory/IJitMemoryBlock.cs | 14 | ||||
| -rw-r--r-- | ARMeilleure/Memory/IMemoryManager.cs | 19 | ||||
| -rw-r--r-- | ARMeilleure/Memory/MemoryHelper.cs | 71 | ||||
| -rw-r--r-- | ARMeilleure/Memory/MemoryManagement.cs | 128 | ||||
| -rw-r--r-- | ARMeilleure/Memory/MemoryManagementUnix.cs | 94 | ||||
| -rw-r--r-- | ARMeilleure/Memory/MemoryManagementWindows.cs | 142 | ||||
| -rw-r--r-- | ARMeilleure/Memory/MemoryManager.cs | 738 | ||||
| -rw-r--r-- | ARMeilleure/Memory/MemoryManagerPal.cs | 11 | ||||
| -rw-r--r-- | ARMeilleure/Memory/MemoryProtection.cs | 17 | ||||
| -rw-r--r-- | ARMeilleure/Memory/MemoryProtectionException.cs | 9 | ||||
| -rw-r--r-- | ARMeilleure/Memory/ReservedRegion.cs | 16 |
12 files changed, 54 insertions, 1213 deletions
diff --git a/ARMeilleure/Memory/IJitMemoryAllocator.cs b/ARMeilleure/Memory/IJitMemoryAllocator.cs new file mode 100644 index 00000000..5745a4bf --- /dev/null +++ b/ARMeilleure/Memory/IJitMemoryAllocator.cs @@ -0,0 +1,8 @@ +namespace ARMeilleure.Memory +{ + public interface IJitMemoryAllocator + { + IJitMemoryBlock Allocate(ulong size); + IJitMemoryBlock Reserve(ulong size); + } +} diff --git a/ARMeilleure/Memory/IJitMemoryBlock.cs b/ARMeilleure/Memory/IJitMemoryBlock.cs new file mode 100644 index 00000000..670f2862 --- /dev/null +++ b/ARMeilleure/Memory/IJitMemoryBlock.cs @@ -0,0 +1,14 @@ +using System; + +namespace ARMeilleure.Memory +{ + public interface IJitMemoryBlock : IDisposable + { + IntPtr Pointer { get; } + + bool Commit(ulong offset, ulong size); + + void MapAsRx(ulong offset, ulong size); + void MapAsRwx(ulong offset, ulong size); + } +} diff --git a/ARMeilleure/Memory/IMemoryManager.cs b/ARMeilleure/Memory/IMemoryManager.cs new file mode 100644 index 00000000..ce1f5848 --- /dev/null +++ b/ARMeilleure/Memory/IMemoryManager.cs @@ -0,0 +1,19 @@ +using System; + +namespace ARMeilleure.Memory +{ + public interface IMemoryManager + { + int AddressSpaceBits { get; } + + IntPtr PageTablePointer { get; } + + T Read<T>(ulong va) where T : unmanaged; + void Write<T>(ulong va, T value) where T : unmanaged; + + ref T GetRef<T>(ulong va) where T : unmanaged; + ref T GetRefNoChecks<T>(ulong va) where T : unmanaged; + + bool IsMapped(ulong va); + } +}
\ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryHelper.cs b/ARMeilleure/Memory/MemoryHelper.cs deleted file mode 100644 index 8e310d4d..00000000 --- a/ARMeilleure/Memory/MemoryHelper.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; -using System.Text; - -namespace ARMeilleure.Memory -{ - public static class MemoryHelper - { - public static void FillWithZeros(MemoryManager memory, long position, int size) - { - int size8 = size & ~(8 - 1); - - for (int offs = 0; offs < size8; offs += 8) - { - memory.WriteInt64(position + offs, 0); - } - - for (int offs = size8; offs < (size - size8); offs++) - { - memory.WriteByte(position + offs, 0); - } - } - - public unsafe static T Read<T>(MemoryManager memory, long position) where T : struct - { - long size = Marshal.SizeOf<T>(); - - byte[] data = memory.ReadBytes(position, size); - - fixed (byte* ptr = data) - { - return Marshal.PtrToStructure<T>((IntPtr)ptr); - } - } - - public unsafe static void Write<T>(MemoryManager memory, long position, T value) where T : struct - { - long size = Marshal.SizeOf<T>(); - - byte[] data = new byte[size]; - - fixed (byte* ptr = data) - { - Marshal.StructureToPtr<T>(value, (IntPtr)ptr, false); - } - - memory.WriteBytes(position, data); - } - - public static string ReadAsciiString(MemoryManager memory, long position, long maxSize = -1) - { - using (MemoryStream ms = new MemoryStream()) - { - for (long offs = 0; offs < maxSize || maxSize == -1; offs++) - { - byte value = (byte)memory.ReadByte(position + offs); - - if (value == 0) - { - break; - } - - ms.WriteByte(value); - } - - return Encoding.ASCII.GetString(ms.ToArray()); - } - } - } -}
\ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryManagement.cs b/ARMeilleure/Memory/MemoryManagement.cs deleted file mode 100644 index ba62f8e7..00000000 --- a/ARMeilleure/Memory/MemoryManagement.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace ARMeilleure.Memory -{ - public static class MemoryManagement - { - public static IntPtr Allocate(ulong size) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - IntPtr sizeNint = new IntPtr((long)size); - - return MemoryManagementWindows.Allocate(sizeNint); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || - RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return MemoryManagementUnix.Allocate(size); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - public static IntPtr AllocateWriteTracked(ulong size) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - IntPtr sizeNint = new IntPtr((long)size); - - return MemoryManagementWindows.AllocateWriteTracked(sizeNint); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || - RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return MemoryManagementUnix.Allocate(size); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - public static bool Commit(IntPtr address, ulong size) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - IntPtr sizeNint = new IntPtr((long)size); - - return MemoryManagementWindows.Commit(address, sizeNint); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || - RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return MemoryManagementUnix.Commit(address, size); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - public static void Reprotect(IntPtr address, ulong size, MemoryProtection permission) - { - bool result; - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - IntPtr sizeNint = new IntPtr((long)size); - - result = MemoryManagementWindows.Reprotect(address, sizeNint, permission); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || - RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - result = MemoryManagementUnix.Reprotect(address, size, permission); - } - else - { - throw new PlatformNotSupportedException(); - } - - if (!result) - { - throw new MemoryProtectionException(permission); - } - } - - public static IntPtr Reserve(ulong size) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - IntPtr sizeNint = new IntPtr((long)size); - - return MemoryManagementWindows.Reserve(sizeNint); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || - RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return MemoryManagementUnix.Reserve(size); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - public static bool Free(IntPtr address) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return MemoryManagementWindows.Free(address); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || - RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return MemoryManagementUnix.Free(address); - } - else - { - throw new PlatformNotSupportedException(); - } - } - } -}
\ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryManagementUnix.cs b/ARMeilleure/Memory/MemoryManagementUnix.cs deleted file mode 100644 index e9b29608..00000000 --- a/ARMeilleure/Memory/MemoryManagementUnix.cs +++ /dev/null @@ -1,94 +0,0 @@ -using Mono.Unix.Native; -using System; - -namespace ARMeilleure.Memory -{ - static class MemoryManagementUnix - { - public static IntPtr Allocate(ulong size) - { - ulong pageSize = (ulong)Syscall.sysconf(SysconfName._SC_PAGESIZE); - - const MmapProts prot = MmapProts.PROT_READ | MmapProts.PROT_WRITE; - - const MmapFlags flags = MmapFlags.MAP_PRIVATE | MmapFlags.MAP_ANONYMOUS; - - IntPtr ptr = Syscall.mmap(IntPtr.Zero, size + pageSize, prot, flags, -1, 0); - - if (ptr == IntPtr.Zero) - { - throw new OutOfMemoryException(); - } - - unsafe - { - ptr = new IntPtr(ptr.ToInt64() + (long)pageSize); - - *((ulong*)ptr - 1) = size; - } - - return ptr; - } - - public static bool Commit(IntPtr address, ulong size) - { - return Syscall.mprotect(address, size, MmapProts.PROT_READ | MmapProts.PROT_WRITE) == 0; - } - - public static bool Reprotect(IntPtr address, ulong size, Memory.MemoryProtection protection) - { - MmapProts prot = GetProtection(protection); - - return Syscall.mprotect(address, size, prot) == 0; - } - - public static IntPtr Reserve(ulong size) - { - ulong pageSize = (ulong)Syscall.sysconf(SysconfName._SC_PAGESIZE); - - const MmapProts prot = MmapProts.PROT_NONE; - - const MmapFlags flags = MmapFlags.MAP_PRIVATE | MmapFlags.MAP_ANONYMOUS; - - IntPtr ptr = Syscall.mmap(IntPtr.Zero, size + pageSize, prot, flags, -1, 0); - - if (ptr == IntPtr.Zero) - { - throw new OutOfMemoryException(); - } - - return ptr; - } - - private static MmapProts GetProtection(Memory.MemoryProtection protection) - { - switch (protection) - { - case Memory.MemoryProtection.None: return MmapProts.PROT_NONE; - case Memory.MemoryProtection.Read: return MmapProts.PROT_READ; - case Memory.MemoryProtection.ReadAndWrite: return MmapProts.PROT_READ | MmapProts.PROT_WRITE; - case Memory.MemoryProtection.ReadAndExecute: return MmapProts.PROT_READ | MmapProts.PROT_EXEC; - case Memory.MemoryProtection.ReadWriteExecute: return MmapProts.PROT_READ | MmapProts.PROT_WRITE | MmapProts.PROT_EXEC; - case Memory.MemoryProtection.Execute: return MmapProts.PROT_EXEC; - - default: throw new ArgumentException($"Invalid permission \"{protection}\"."); - } - } - - public static bool Free(IntPtr address) - { - ulong pageSize = (ulong)Syscall.sysconf(SysconfName._SC_PAGESIZE); - - ulong size; - - unsafe - { - size = *((ulong*)address - 1); - - address = new IntPtr(address.ToInt64() - (long)pageSize); - } - - return Syscall.munmap(address, size + pageSize) == 0; - } - } -}
\ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryManagementWindows.cs b/ARMeilleure/Memory/MemoryManagementWindows.cs deleted file mode 100644 index a9455063..00000000 --- a/ARMeilleure/Memory/MemoryManagementWindows.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace ARMeilleure.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) - { - const AllocationType flags = - AllocationType.Reserve | - AllocationType.Commit; - - IntPtr ptr = VirtualAlloc(IntPtr.Zero, size, flags, MemoryProtection.ReadWrite); - - if (ptr == IntPtr.Zero) - { - throw new OutOfMemoryException(); - } - - return ptr; - } - - public static IntPtr AllocateWriteTracked(IntPtr size) - { - const AllocationType flags = - AllocationType.Reserve | - AllocationType.Commit | - AllocationType.WriteWatch; - - 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) - { - const AllocationType flags = AllocationType.Commit; - - IntPtr ptr = VirtualAlloc(location, size, flags, MemoryProtection.ReadWrite); - - return ptr != IntPtr.Zero; - } - - public static bool Reprotect(IntPtr address, IntPtr size, Memory.MemoryProtection protection) - { - MemoryProtection prot = GetProtection(protection); - - return VirtualProtect(address, size, prot, out _); - } - - public static IntPtr Reserve(IntPtr size) - { - const AllocationType flags = AllocationType.Reserve; - - IntPtr ptr = VirtualAlloc(IntPtr.Zero, size, flags, MemoryProtection.ReadWrite); - - if (ptr == IntPtr.Zero) - { - throw new OutOfMemoryException(); - } - - return ptr; - } - - private static MemoryProtection GetProtection(Memory.MemoryProtection protection) - { - switch (protection) - { - case Memory.MemoryProtection.None: return MemoryProtection.NoAccess; - case Memory.MemoryProtection.Read: return MemoryProtection.ReadOnly; - case Memory.MemoryProtection.ReadAndWrite: return MemoryProtection.ReadWrite; - case Memory.MemoryProtection.ReadAndExecute: return MemoryProtection.ExecuteRead; - case Memory.MemoryProtection.ReadWriteExecute: return MemoryProtection.ExecuteReadWrite; - case Memory.MemoryProtection.Execute: return MemoryProtection.Execute; - - default: throw new ArgumentException($"Invalid permission \"{protection}\"."); - } - } - - public static bool Free(IntPtr address) - { - return VirtualFree(address, IntPtr.Zero, AllocationType.Release); - } - } -}
\ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryManager.cs b/ARMeilleure/Memory/MemoryManager.cs deleted file mode 100644 index c5a0323b..00000000 --- a/ARMeilleure/Memory/MemoryManager.cs +++ /dev/null @@ -1,738 +0,0 @@ -using ARMeilleure.State; -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Threading; - -using static ARMeilleure.Memory.MemoryManagement; - -namespace ARMeilleure.Memory -{ - public unsafe class MemoryManager - { - public const int PageBits = 12; - public const int PageSize = 1 << PageBits; - public const int PageMask = PageSize - 1; - - internal const long PteFlagsMask = 7; - - public IntPtr Ram { get; private set; } - - private byte* _ramPtr; - - private IntPtr _pageTable; - - internal IntPtr PageTable => _pageTable; - - internal int PtLevelBits { get; } - internal int PtLevelSize { get; } - internal int PtLevelMask { get; } - - public int AddressSpaceBits { get; } - public long AddressSpaceSize { get; } - - public MemoryManager( - IntPtr ram, - int addressSpaceBits = 48, - bool useFlatPageTable = false) - { - Ram = ram; - - _ramPtr = (byte*)ram; - - AddressSpaceBits = addressSpaceBits; - AddressSpaceSize = 1L << addressSpaceBits; - - // When flat page table is requested, we use a single - // array for the mappings of the entire address space. - // This has better performance, but also high memory usage. - // The multi level page table uses 9 bits per level, so - // the memory usage is lower, but the performance is also - // lower, since each address translation requires multiple reads. - if (useFlatPageTable) - { - PtLevelBits = addressSpaceBits - PageBits; - } - else - { - PtLevelBits = 9; - } - - PtLevelSize = 1 << PtLevelBits; - PtLevelMask = PtLevelSize - 1; - - _pageTable = Allocate((ulong)(PtLevelSize * IntPtr.Size)); - } - - public void Map(long va, long pa, long size) - { - SetPtEntries(va, _ramPtr + pa, size); - } - - public void Unmap(long position, long size) - { - SetPtEntries(position, null, size); - } - - public bool IsMapped(long position) - { - return Translate(position) != IntPtr.Zero; - } - - public long GetPhysicalAddress(long virtualAddress) - { - byte* ptr = (byte*)Translate(virtualAddress); - - return (long)(ptr - _ramPtr); - } - - private IntPtr Translate(long position) - { - if (!IsValidPosition(position)) - { - return IntPtr.Zero; - } - - byte* ptr = GetPtEntry(position); - - ulong ptrUlong = (ulong)ptr; - - if ((ptrUlong & PteFlagsMask) != 0) - { - ptrUlong &= ~(ulong)PteFlagsMask; - - ptr = (byte*)ptrUlong; - } - - if (ptr == null) - { - return IntPtr.Zero; - } - - return new IntPtr(ptr + (position & PageMask)); - } - - private IntPtr TranslateWrite(long position) - { - if (!IsValidPosition(position)) - { - return IntPtr.Zero; - } - - byte* ptr = GetPtEntry(position); - - ulong ptrUlong = (ulong)ptr; - - if ((ptrUlong & PteFlagsMask) != 0) - { - ClearPtEntryFlag(position, PteFlagsMask); - - ptrUlong &= ~(ulong)PteFlagsMask; - - ptr = (byte*)ptrUlong; - } - - return new IntPtr(ptr + (position & PageMask)); - } - - private byte* GetPtEntry(long position) - { - return *(byte**)GetPtPtr(position); - } - - private void SetPtEntries(long va, byte* ptr, long size) - { - long endPosition = (va + size + PageMask) & ~PageMask; - - while ((ulong)va < (ulong)endPosition) - { - SetPtEntry(va, ptr); - - va += PageSize; - - if (ptr != null) - { - ptr += PageSize; - } - } - } - - private void SetPtEntry(long position, byte* ptr) - { - *(byte**)GetPtPtr(position) = ptr; - } - - private void SetPtEntryFlag(long position, long flag) - { - ModifyPtEntryFlag(position, flag, setFlag: true); - } - - private void ClearPtEntryFlag(long position, long flag) - { - ModifyPtEntryFlag(position, flag, setFlag: false); - } - - private void ModifyPtEntryFlag(long position, long flag, bool setFlag) - { - IntPtr* pt = (IntPtr*)_pageTable; - - while (true) - { - IntPtr* ptPtr = GetPtPtr(position); - - IntPtr old = *ptPtr; - - long modified = old.ToInt64(); - - if (setFlag) - { - modified |= flag; - } - else - { - modified &= ~flag; - } - - IntPtr origValue = Interlocked.CompareExchange(ref *ptPtr, new IntPtr(modified), old); - - if (origValue == old) - { - break; - } - } - } - - private IntPtr* GetPtPtr(long position) - { - if (!IsValidPosition(position)) - { - throw new ArgumentOutOfRangeException(nameof(position)); - } - - IntPtr nextPtr = _pageTable; - - IntPtr* ptePtr = null; - - int bit = PageBits; - - while (true) - { - long index = (position >> bit) & PtLevelMask; - - ptePtr = &((IntPtr*)nextPtr)[index]; - - bit += PtLevelBits; - - if (bit >= AddressSpaceBits) - { - break; - } - - nextPtr = *ptePtr; - - if (nextPtr == IntPtr.Zero) - { - // Entry does not yet exist, allocate a new one. - IntPtr newPtr = Allocate((ulong)(PtLevelSize * IntPtr.Size)); - - // Try to swap the current pointer (should be zero), with the allocated one. - nextPtr = Interlocked.CompareExchange(ref *ptePtr, newPtr, IntPtr.Zero); - - // If the old pointer is not null, then another thread already has set it. - if (nextPtr != IntPtr.Zero) - { - Free(newPtr); - } - else - { - nextPtr = newPtr; - } - } - } - - return ptePtr; - } - - public unsafe (ulong, ulong)[] GetModifiedRanges(ulong address, ulong size, int id) - { - ulong idMask = 1UL << id; - - 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) - { - // If the address is invalid, we stop and consider all the remaining memory - // as not modified (since the address is invalid, we can't check, and technically - // the memory doesn't exist). - if (!IsValidPosition((long)address)) - { - break; - } - - byte* ptr = ((byte**)_pageTable)[address >> PageBits]; - - ulong ptrUlong = (ulong)ptr; - - if ((ptrUlong & idMask) == 0) - { - // Modified. - currSize += PageSize; - - SetPtEntryFlag((long)address, (long)idMask); - } - else - { - if (currSize != 0) - { - ranges.Add((currAddr, currSize)); - } - - currAddr = address + PageSize; - currSize = 0; - } - - address += PageSize; - } - - if (currSize != 0) - { - ranges.Add((currAddr, currSize)); - } - - return ranges.ToArray(); - } - - private bool IsContiguous(long position, long size) - { - long endPos = position + size; - - position &= ~PageMask; - - long expectedPa = GetPhysicalAddress(position); - - while ((ulong)position < (ulong)endPos) - { - long pa = GetPhysicalAddress(position); - - if (pa != expectedPa) - { - return false; - } - - position += PageSize; - expectedPa += PageSize; - } - - return true; - } - - public bool IsValidPosition(long position) - { - return (ulong)position < (ulong)AddressSpaceSize; - } - - internal V128 AtomicLoadInt128(long position) - { - if ((position & 0xf) != 0) - { - AbortWithAlignmentFault(position); - } - - IntPtr ptr = TranslateWrite(position); - - return MemoryManagerPal.AtomicLoad128(ptr); - } - - internal bool AtomicCompareExchangeByte(long position, byte expected, byte desired) - { - int* ptr = (int*)Translate(position); - - int currentValue = *ptr; - - int expected32 = (currentValue & ~byte.MaxValue) | expected; - int desired32 = (currentValue & ~byte.MaxValue) | desired; - - return Interlocked.CompareExchange(ref *ptr, desired32, expected32) == expected32; - } - - internal bool AtomicCompareExchangeInt16(long position, short expected, short desired) - { - if ((position & 1) != 0) - { - AbortWithAlignmentFault(position); - } - - int* ptr = (int*)Translate(position); - - int currentValue = *ptr; - - int expected32 = (currentValue & ~ushort.MaxValue) | (ushort)expected; - int desired32 = (currentValue & ~ushort.MaxValue) | (ushort)desired; - - return Interlocked.CompareExchange(ref *ptr, desired32, expected32) == expected32; - } - - public bool AtomicCompareExchangeInt32(long position, int expected, int desired) - { - if ((position & 3) != 0) - { - AbortWithAlignmentFault(position); - } - - int* ptr = (int*)TranslateWrite(position); - - return Interlocked.CompareExchange(ref *ptr, desired, expected) == expected; - } - - internal bool AtomicCompareExchangeInt64(long position, long expected, long desired) - { - if ((position & 7) != 0) - { - AbortWithAlignmentFault(position); - } - - long* ptr = (long*)TranslateWrite(position); - - return Interlocked.CompareExchange(ref *ptr, desired, expected) == expected; - } - - internal bool AtomicCompareExchangeInt128(long position, V128 expected, V128 desired) - { - if ((position & 0xf) != 0) - { - AbortWithAlignmentFault(position); - } - - IntPtr ptr = TranslateWrite(position); - - return MemoryManagerPal.CompareAndSwap128(ptr, expected, desired) == expected; - } - - public int AtomicIncrementInt32(long position) - { - if ((position & 3) != 0) - { - AbortWithAlignmentFault(position); - } - - int* ptr = (int*)TranslateWrite(position); - - return Interlocked.Increment(ref *ptr); - } - - public int AtomicDecrementInt32(long position) - { - if ((position & 3) != 0) - { - AbortWithAlignmentFault(position); - } - - int* ptr = (int*)TranslateWrite(position); - - return Interlocked.Decrement(ref *ptr); - } - - private void AbortWithAlignmentFault(long position) - { - // TODO: Abort mode and exception support on the CPU. - throw new InvalidOperationException($"Tried to compare exchange a misaligned address 0x{position:X16}."); - } - - public sbyte ReadSByte(long position) - { - return (sbyte)ReadByte(position); - } - - public short ReadInt16(long position) - { - return (short)ReadUInt16(position); - } - - public int ReadInt32(long position) - { - return (int)ReadUInt32(position); - } - - public long ReadInt64(long position) - { - return (long)ReadUInt64(position); - } - - public byte ReadByte(long position) - { - return *((byte*)Translate(position)); - } - - public ushort ReadUInt16(long position) - { - if ((position & 1) == 0) - { - return *((ushort*)Translate(position)); - } - else - { - return (ushort)(ReadByte(position + 0) << 0 | - ReadByte(position + 1) << 8); - } - } - - public uint ReadUInt32(long position) - { - if ((position & 3) == 0) - { - return *((uint*)Translate(position)); - } - else - { - return (uint)(ReadUInt16(position + 0) << 0 | - ReadUInt16(position + 2) << 16); - } - } - - public ulong ReadUInt64(long position) - { - if ((position & 7) == 0) - { - return *((ulong*)Translate(position)); - } - else - { - return (ulong)ReadUInt32(position + 0) << 0 | - (ulong)ReadUInt32(position + 4) << 32; - } - } - - public V128 ReadVector128(long position) - { - return new V128(ReadUInt64(position), ReadUInt64(position + 8)); - } - - public byte[] ReadBytes(long position, long size) - { - long endAddr = position + size; - - if ((ulong)size > int.MaxValue) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - - if ((ulong)endAddr < (ulong)position) - { - throw new ArgumentOutOfRangeException(nameof(position)); - } - - byte[] data = new byte[size]; - - int offset = 0; - - 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; - } - - return data; - } - - public ReadOnlySpan<byte> GetSpan(ulong address, ulong size) - { - if (IsContiguous(address, size)) - { - return new ReadOnlySpan<byte>((void*)Translate((long)address), (int)size); - } - else - { - return ReadBytes((long)address, (long)size); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsContiguous(ulong address, ulong size) - { - if (!IsValidPosition((long)address)) - { - return false; - } - - ulong endVa = (address + size + PageMask) & ~(ulong)PageMask; - - address &= ~(ulong)PageMask; - - int pages = (int)((endVa - address) / PageSize); - - for (int page = 0; page < pages - 1; page++) - { - if (!IsValidPosition((long)address + PageSize)) - { - return false; - } - - if (GetPtEntry((long)address) + PageSize != GetPtEntry((long)address + PageSize)) - { - return false; - } - - address += PageSize; - } - - return true; - } - - public void WriteSByte(long position, sbyte value) - { - WriteByte(position, (byte)value); - } - - public void WriteInt16(long position, short value) - { - WriteUInt16(position, (ushort)value); - } - - public void WriteInt32(long position, int value) - { - WriteUInt32(position, (uint)value); - } - - public void WriteInt64(long position, long value) - { - WriteUInt64(position, (ulong)value); - } - - public void WriteByte(long position, byte value) - { - *((byte*)TranslateWrite(position)) = value; - } - - public void WriteUInt16(long position, ushort value) - { - if ((position & 1) == 0) - { - *((ushort*)TranslateWrite(position)) = value; - } - else - { - WriteByte(position + 0, (byte)(value >> 0)); - WriteByte(position + 1, (byte)(value >> 8)); - } - } - - public void WriteUInt32(long position, uint value) - { - if ((position & 3) == 0) - { - *((uint*)TranslateWrite(position)) = value; - } - else - { - WriteUInt16(position + 0, (ushort)(value >> 0)); - WriteUInt16(position + 2, (ushort)(value >> 16)); - } - } - - public void WriteUInt64(long position, ulong value) - { - if ((position & 7) == 0) - { - *((ulong*)TranslateWrite(position)) = value; - } - else - { - WriteUInt32(position + 0, (uint)(value >> 0)); - WriteUInt32(position + 4, (uint)(value >> 32)); - } - } - - public void WriteVector128(long position, V128 value) - { - WriteUInt64(position + 0, value.Extract<ulong>(0)); - WriteUInt64(position + 8, value.Extract<ulong>(1)); - } - - public void WriteBytes(long position, byte[] data) - { - long endAddr = position + data.Length; - - if ((ulong)endAddr < (ulong)position) - { - throw new ArgumentOutOfRangeException(nameof(position)); - } - - int offset = 0; - - 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, TranslateWrite(position), copySize); - - position += copySize; - offset += copySize; - } - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - IntPtr ptr = Interlocked.Exchange(ref _pageTable, IntPtr.Zero); - - if (ptr != IntPtr.Zero) - { - FreePageTableEntry(ptr, PageBits); - } - } - - private void FreePageTableEntry(IntPtr ptr, int levelBitEnd) - { - levelBitEnd += PtLevelBits; - - if (levelBitEnd >= AddressSpaceBits) - { - Free(ptr); - - return; - } - - for (int index = 0; index < PtLevelSize; index++) - { - IntPtr ptePtr = ((IntPtr*)ptr)[index]; - - if (ptePtr != IntPtr.Zero) - { - FreePageTableEntry(ptePtr, levelBitEnd); - } - } - - Free(ptr); - } - } -}
\ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryManagerPal.cs b/ARMeilleure/Memory/MemoryManagerPal.cs index 66c43642..0dc83959 100644 --- a/ARMeilleure/Memory/MemoryManagerPal.cs +++ b/ARMeilleure/Memory/MemoryManagerPal.cs @@ -1,13 +1,12 @@ using ARMeilleure.IntermediateRepresentation; using ARMeilleure.State; using ARMeilleure.Translation; -using System; namespace ARMeilleure.Memory { static class MemoryManagerPal { - private delegate V128 CompareExchange128(IntPtr address, V128 expected, V128 desired); + private delegate V128 CompareExchange128(ref V128 location, V128 expected, V128 desired); private static CompareExchange128 _compareExchange128; @@ -18,14 +17,14 @@ namespace ARMeilleure.Memory _lock = new object(); } - public static V128 AtomicLoad128(IntPtr address) + public static V128 AtomicLoad128(ref V128 location) { - return GetCompareAndSwap128()(address, V128.Zero, V128.Zero); + return GetCompareAndSwap128()(ref location, V128.Zero, V128.Zero); } - public static V128 CompareAndSwap128(IntPtr address, V128 expected, V128 desired) + public static V128 CompareAndSwap128(ref V128 location, V128 expected, V128 desired) { - return GetCompareAndSwap128()(address, expected, desired); + return GetCompareAndSwap128()(ref location, expected, desired); } private static CompareExchange128 GetCompareAndSwap128() diff --git a/ARMeilleure/Memory/MemoryProtection.cs b/ARMeilleure/Memory/MemoryProtection.cs deleted file mode 100644 index 6bc16f8e..00000000 --- a/ARMeilleure/Memory/MemoryProtection.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace ARMeilleure.Memory -{ - [Flags] - public enum MemoryProtection - { - None = 0, - Read = 1 << 0, - Write = 1 << 1, - Execute = 1 << 2, - - ReadAndWrite = Read | Write, - ReadAndExecute = Read | Execute, - ReadWriteExecute = Read | Write | Execute - } -}
\ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryProtectionException.cs b/ARMeilleure/Memory/MemoryProtectionException.cs deleted file mode 100644 index 6313ce6a..00000000 --- a/ARMeilleure/Memory/MemoryProtectionException.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace ARMeilleure.Memory -{ - class MemoryProtectionException : Exception - { - public MemoryProtectionException(MemoryProtection protection) : base($"Failed to set memory protection to \"{protection}\".") { } - } -}
\ No newline at end of file diff --git a/ARMeilleure/Memory/ReservedRegion.cs b/ARMeilleure/Memory/ReservedRegion.cs index 521019ad..dc6eb9da 100644 --- a/ARMeilleure/Memory/ReservedRegion.cs +++ b/ARMeilleure/Memory/ReservedRegion.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace ARMeilleure.Memory { @@ -8,20 +6,22 @@ namespace ARMeilleure.Memory { private const int DefaultGranularity = 65536; // Mapping granularity in Windows. - public IntPtr Pointer { get; } + public IJitMemoryBlock Block { get; } - private ulong _maxSize; - private ulong _sizeGranularity; + public IntPtr Pointer => Block.Pointer; + + private readonly ulong _maxSize; + private readonly ulong _sizeGranularity; private ulong _currentSize; - public ReservedRegion(ulong maxSize, ulong granularity = 0) + public ReservedRegion(IJitMemoryAllocator allocator, ulong maxSize, ulong granularity = 0) { if (granularity == 0) { granularity = DefaultGranularity; } - Pointer = MemoryManagement.Reserve(maxSize); + Block = allocator.Reserve(maxSize); _maxSize = maxSize; _sizeGranularity = granularity; _currentSize = 0; @@ -43,7 +43,7 @@ namespace ARMeilleure.Memory { ulong overflowBytes = desiredSize - _currentSize; ulong moreToCommit = (((_sizeGranularity - 1) + overflowBytes) / _sizeGranularity) * _sizeGranularity; // Round up. - MemoryManagement.Commit(new IntPtr((long)Pointer + (long)_currentSize), moreToCommit); + Block.Commit(_currentSize, moreToCommit); _currentSize += moreToCommit; } } |
