diff options
| author | LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> | 2019-10-31 19:09:03 +0100 |
|---|---|---|
| committer | Ac_K <Acoustik666@gmail.com> | 2019-10-31 19:09:03 +0100 |
| commit | eee639d6ba544fa5dd9352426d55e91bc54e157d (patch) | |
| tree | 1df440ca57d8c1725e84f403fbeecddb8e508a3a /ChocolArm64/Memory | |
| parent | 35443bac5a16ced668d84e0a22c21ca9076b3924 (diff) | |
.NET Core 3.0 is here! (#784)
* .NET Core 3.0 is here!
* Remove IMemoryManager.cs and its references.
* Add T Math/F.FusedMultiplyAdd(T, T, T). Nits.
* Nit.
* Update appveyor.yml
* Revert "Resolve Visual Studio build issues"
This reverts commit 1772128ce0fc058e6280001aace3a77a7a96897b.
* Update SvcTable.cs
Diffstat (limited to 'ChocolArm64/Memory')
| -rw-r--r-- | ChocolArm64/Memory/CompareExchange128.cs | 151 | ||||
| -rw-r--r-- | ChocolArm64/Memory/IMemory.cs | 37 | ||||
| -rw-r--r-- | ChocolArm64/Memory/MemoryHelper.cs | 71 | ||||
| -rw-r--r-- | ChocolArm64/Memory/MemoryManagement.cs | 114 | ||||
| -rw-r--r-- | ChocolArm64/Memory/MemoryManagementUnix.cs | 70 | ||||
| -rw-r--r-- | ChocolArm64/Memory/MemoryManagementWindows.cs | 155 | ||||
| -rw-r--r-- | ChocolArm64/Memory/MemoryManager.cs | 1017 | ||||
| -rw-r--r-- | ChocolArm64/Memory/MemoryProtection.cs | 16 | ||||
| -rw-r--r-- | ChocolArm64/Memory/MemoryProtectionException.cs | 10 |
9 files changed, 0 insertions, 1641 deletions
diff --git a/ChocolArm64/Memory/CompareExchange128.cs b/ChocolArm64/Memory/CompareExchange128.cs deleted file mode 100644 index 1618ff0f..00000000 --- a/ChocolArm64/Memory/CompareExchange128.cs +++ /dev/null @@ -1,151 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace ChocolArm64.Memory -{ - static class CompareExchange128 - { - private struct Int128 - { - public ulong Low { get; } - public ulong High { get; } - - public Int128(ulong low, ulong high) - { - Low = low; - High = high; - } - } - - private delegate Int128 InterlockedCompareExchange(IntPtr address, Int128 expected, Int128 desired); - - private delegate int GetCpuId(); - - private static InterlockedCompareExchange _interlockedCompareExchange; - - static CompareExchange128() - { - if (RuntimeInformation.OSArchitecture != Architecture.X64 || !IsCmpxchg16bSupported()) - { - throw new PlatformNotSupportedException(); - } - - byte[] interlockedCompareExchange128Code; - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - interlockedCompareExchange128Code = new byte[] - { - 0x53, // push rbx - 0x49, 0x8b, 0x00, // mov rax, [r8] - 0x49, 0x8b, 0x19, // mov rbx, [r9] - 0x49, 0x89, 0xca, // mov r10, rcx - 0x49, 0x89, 0xd3, // mov r11, rdx - 0x49, 0x8b, 0x49, 0x08, // mov rcx, [r9+8] - 0x49, 0x8b, 0x50, 0x08, // mov rdx, [r8+8] - 0xf0, 0x49, 0x0f, 0xc7, 0x0b, // lock cmpxchg16b [r11] - 0x49, 0x89, 0x02, // mov [r10], rax - 0x4c, 0x89, 0xd0, // mov rax, r10 - 0x49, 0x89, 0x52, 0x08, // mov [r10+8], rdx - 0x5b, // pop rbx - 0xc3 // ret - }; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || - RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - interlockedCompareExchange128Code = new byte[] - { - 0x53, // push rbx - 0x49, 0x89, 0xd1, // mov r9, rdx - 0x48, 0x89, 0xcb, // mov rbx, rcx - 0x48, 0x89, 0xf0, // mov rax, rsi - 0x4c, 0x89, 0xca, // mov rdx, r9 - 0x4c, 0x89, 0xc1, // mov rcx, r8 - 0xf0, 0x48, 0x0f, 0xc7, 0x0f, // lock cmpxchg16b [rdi] - 0x5b, // pop rbx - 0xc3 // ret - }; - } - else - { - throw new PlatformNotSupportedException(); - } - - IntPtr funcPtr = MapCodeAsExecutable(interlockedCompareExchange128Code); - - _interlockedCompareExchange = Marshal.GetDelegateForFunctionPointer<InterlockedCompareExchange>(funcPtr); - } - - private static bool IsCmpxchg16bSupported() - { - byte[] getCpuIdCode = new byte[] - { - 0x53, // push rbx - 0xb8, 0x01, 0x00, 0x00, 0x00, // mov eax, 0x1 - 0x0f, 0xa2, // cpuid - 0x89, 0xc8, // mov eax, ecx - 0x5b, // pop rbx - 0xc3 // ret - }; - - IntPtr funcPtr = MapCodeAsExecutable(getCpuIdCode); - - GetCpuId getCpuId = Marshal.GetDelegateForFunctionPointer<GetCpuId>(funcPtr); - - int cpuId = getCpuId(); - - MemoryManagement.Free(funcPtr); - - return (cpuId & (1 << 13)) != 0; - } - - private static IntPtr MapCodeAsExecutable(byte[] code) - { - ulong codeLength = (ulong)code.Length; - - IntPtr funcPtr = MemoryManagement.Allocate(codeLength); - - unsafe - { - fixed (byte* codePtr = code) - { - byte* dest = (byte*)funcPtr; - - long size = (long)codeLength; - - Buffer.MemoryCopy(codePtr, dest, size, size); - } - } - - MemoryManagement.Reprotect(funcPtr, codeLength, MemoryProtection.Execute); - - return funcPtr; - } - - public static bool InterlockedCompareExchange128( - IntPtr address, - ulong expectedLow, - ulong expectedHigh, - ulong desiredLow, - ulong desiredHigh) - { - Int128 expected = new Int128(expectedLow, expectedHigh); - Int128 desired = new Int128(desiredLow, desiredHigh); - - Int128 old = _interlockedCompareExchange(address, expected, desired); - - return old.Low == expected.Low && old.High == expected.High; - } - - public static void InterlockedRead128(IntPtr address, out ulong low, out ulong high) - { - Int128 zero = new Int128(0, 0); - - Int128 old = _interlockedCompareExchange(address, zero, zero); - - low = old.Low; - high = old.High; - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Memory/IMemory.cs b/ChocolArm64/Memory/IMemory.cs deleted file mode 100644 index dc582155..00000000 --- a/ChocolArm64/Memory/IMemory.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace ChocolArm64.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); - } -}
\ No newline at end of file diff --git a/ChocolArm64/Memory/MemoryHelper.cs b/ChocolArm64/Memory/MemoryHelper.cs deleted file mode 100644 index 1c436dd8..00000000 --- a/ChocolArm64/Memory/MemoryHelper.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; -using System.Text; - -namespace ChocolArm64.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/ChocolArm64/Memory/MemoryManagement.cs b/ChocolArm64/Memory/MemoryManagement.cs deleted file mode 100644 index 80585791..00000000 --- a/ChocolArm64/Memory/MemoryManagement.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace ChocolArm64.Memory -{ - public static class MemoryManagement - { - public static bool HasWriteWatchSupport => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - - 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 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 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(); - } - } - - [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; - } - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Memory/MemoryManagementUnix.cs b/ChocolArm64/Memory/MemoryManagementUnix.cs deleted file mode 100644 index fe3cfb7e..00000000 --- a/ChocolArm64/Memory/MemoryManagementUnix.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Mono.Unix.Native; -using System; - -namespace ChocolArm64.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 Reprotect(IntPtr address, ulong size, MemoryProtection protection) - { - MmapProts prot = GetProtection(protection); - - return Syscall.mprotect(address, size, prot) == 0; - } - - private static MmapProts GetProtection(MemoryProtection protection) - { - switch (protection) - { - case MemoryProtection.None: return MmapProts.PROT_NONE; - case MemoryProtection.Read: return MmapProts.PROT_READ; - case MemoryProtection.ReadAndWrite: return MmapProts.PROT_READ | MmapProts.PROT_WRITE; - case MemoryProtection.ReadAndExecute: return MmapProts.PROT_READ | MmapProts.PROT_EXEC; - case 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/ChocolArm64/Memory/MemoryManagementWindows.cs b/ChocolArm64/Memory/MemoryManagementWindows.cs deleted file mode 100644 index 6cee1342..00000000 --- a/ChocolArm64/Memory/MemoryManagementWindows.cs +++ /dev/null @@ -1,155 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace ChocolArm64.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 - } - - private enum WriteWatchFlags : uint - { - None = 0, - Reset = 1 - } - - [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); - - [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 = - 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 Reprotect(IntPtr address, IntPtr size, Memory.MemoryProtection protection) - { - MemoryProtection prot = GetProtection(protection); - - return VirtualProtect(address, size, prot, out _); - } - - 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.Execute: return MemoryProtection.Execute; - - default: throw new ArgumentException($"Invalid permission \"{protection}\"."); - } - } - - public static bool Free(IntPtr address) - { - 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; - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Memory/MemoryManager.cs b/ChocolArm64/Memory/MemoryManager.cs deleted file mode 100644 index 2347f1eb..00000000 --- a/ChocolArm64/Memory/MemoryManager.cs +++ /dev/null @@ -1,1017 +0,0 @@ -using ChocolArm64.Instructions; -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; -using System.Threading; - -using static ChocolArm64.Memory.CompareExchange128; -using static ChocolArm64.Memory.MemoryManagement; - -namespace ChocolArm64.Memory -{ - public unsafe class MemoryManager : ARMeilleure.Memory.IMemoryManager - { - public const int PageBits = 12; - public const int PageSize = 1 << PageBits; - public const int PageMask = PageSize - 1; - - private const long PteFlagNotModified = 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 bool HasWriteWatchSupport => MemoryManagement.HasWriteWatchSupport; - - 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; - } - - 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) - { - if ((ptrUlong & PteFlagNotModified) != 0) - { - ClearPtEntryFlag(position, PteFlagNotModified); - } - - 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.Exchange(ref *ptePtr, newPtr); - - // 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 bool IsRegionModified(long position, long size) - { - if (!HasWriteWatchSupport) - { - 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) - { - 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]; - - ulong ptrUlong = (ulong)ptr; - - if ((ptrUlong & PteFlagNotModified) == 0) - { - modified = true; - - SetPtEntryFlag(position, PteFlagNotModified); - } - } - else - { - modified = true; - } - - position += PageSize; - } - - return modified; - } - - public bool TryGetHostAddress(long position, long size, out IntPtr ptr) - { - if (IsContiguous(position, size)) - { - ptr = (IntPtr)Translate(position); - - return true; - } - - ptr = IntPtr.Zero; - - return false; - } - - 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 bool AtomicCompareExchange2xInt32( - long position, - int expectedLow, - int expectedHigh, - int desiredLow, - int desiredHigh) - { - long expected = (uint)expectedLow; - long desired = (uint)desiredLow; - - expected |= (long)expectedHigh << 32; - desired |= (long)desiredHigh << 32; - - return AtomicCompareExchangeInt64(position, expected, desired); - } - - internal bool AtomicCompareExchangeInt128( - long position, - ulong expectedLow, - ulong expectedHigh, - ulong desiredLow, - ulong desiredHigh) - { - if ((position & 0xf) != 0) - { - AbortWithAlignmentFault(position); - } - - IntPtr ptr = TranslateWrite(position); - - return InterlockedCompareExchange128(ptr, expectedLow, expectedHigh, desiredLow, desiredHigh); - } - - internal Vector128<float> AtomicReadInt128(long position) - { - if ((position & 0xf) != 0) - { - AbortWithAlignmentFault(position); - } - - IntPtr ptr = Translate(position); - - InterlockedRead128(ptr, out ulong low, out ulong high); - - Vector128<float> vector = default(Vector128<float>); - - vector = VectorHelper.VectorInsertInt(low, vector, 0, 3); - vector = VectorHelper.VectorInsertInt(high, vector, 1, 3); - - return vector; - } - - public 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; - } - - public 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; - } - - public 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; - } - - 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 Vector128<float> ReadVector8(long position) - { - if (Sse2.IsSupported) - { - return Sse.StaticCast<byte, float>(Sse2.SetVector128(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ReadByte(position))); - } - else - { - Vector128<float> value = VectorHelper.VectorSingleZero(); - - value = VectorHelper.VectorInsertInt(ReadByte(position), value, 0, 0); - - return value; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector128<float> ReadVector16(long position) - { - if (Sse2.IsSupported && (position & 1) == 0) - { - return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse2.SetZeroVector128<ushort>(), ReadUInt16(position), 0)); - } - else - { - Vector128<float> value = VectorHelper.VectorSingleZero(); - - value = VectorHelper.VectorInsertInt(ReadUInt16(position), value, 0, 1); - - return value; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector128<float> ReadVector32(long position) - { - if (Sse.IsSupported && (position & 3) == 0) - { - return Sse.LoadScalarVector128((float*)Translate(position)); - } - else - { - Vector128<float> value = VectorHelper.VectorSingleZero(); - - value = VectorHelper.VectorInsertInt(ReadUInt32(position), value, 0, 2); - - return value; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector128<float> ReadVector64(long position) - { - if (Sse2.IsSupported && (position & 7) == 0) - { - return Sse.StaticCast<double, float>(Sse2.LoadScalarVector128((double*)Translate(position))); - } - else - { - Vector128<float> value = VectorHelper.VectorSingleZero(); - - value = VectorHelper.VectorInsertInt(ReadUInt64(position), value, 0, 3); - - return value; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector128<float> ReadVector128(long position) - { - if (Sse.IsSupported && (position & 15) == 0) - { - return Sse.LoadVector128((float*)Translate(position)); - } - else - { - Vector128<float> value = VectorHelper.VectorSingleZero(); - - value = VectorHelper.VectorInsertInt(ReadUInt64(position + 0), value, 0, 3); - value = VectorHelper.VectorInsertInt(ReadUInt64(position + 8), value, 1, 3); - - return value; - } - } - - 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 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); - } - - 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)); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector8(long position, Vector128<float> value) - { - if (Sse41.IsSupported) - { - WriteByte(position, Sse41.Extract(Sse.StaticCast<float, byte>(value), 0)); - } - else if (Sse2.IsSupported) - { - WriteByte(position, (byte)Sse2.Extract(Sse.StaticCast<float, ushort>(value), 0)); - } - else - { - WriteByte(position, (byte)VectorHelper.VectorExtractIntZx(value, 0, 0)); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector16(long position, Vector128<float> value) - { - if (Sse2.IsSupported) - { - WriteUInt16(position, Sse2.Extract(Sse.StaticCast<float, ushort>(value), 0)); - } - else - { - WriteUInt16(position, (ushort)VectorHelper.VectorExtractIntZx(value, 0, 1)); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector32(long position, Vector128<float> value) - { - if (Sse.IsSupported && (position & 3) == 0) - { - Sse.StoreScalar((float*)TranslateWrite(position), value); - } - else - { - WriteUInt32(position, (uint)VectorHelper.VectorExtractIntZx(value, 0, 2)); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector64(long position, Vector128<float> value) - { - if (Sse2.IsSupported && (position & 7) == 0) - { - Sse2.StoreScalar((double*)TranslateWrite(position), Sse.StaticCast<float, double>(value)); - } - else - { - WriteUInt64(position, VectorHelper.VectorExtractIntZx(value, 0, 3)); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector128Internal(long position, Vector128<float> value) - { - if (Sse.IsSupported && (position & 15) == 0) - { - Sse.Store((float*)TranslateWrite(position), value); - } - else - { - WriteUInt64(position + 0, VectorHelper.VectorExtractIntZx(value, 0, 3)); - WriteUInt64(position + 8, VectorHelper.VectorExtractIntZx(value, 1, 3)); - } - } - - public void WriteVector128(long position, ARMeilleure.State.V128 value) - { - WriteUInt64(position + 0, value.GetUInt64(0)); - WriteUInt64(position + 8, value.GetUInt64(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 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); - } - - 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/ChocolArm64/Memory/MemoryProtection.cs b/ChocolArm64/Memory/MemoryProtection.cs deleted file mode 100644 index d0874bfc..00000000 --- a/ChocolArm64/Memory/MemoryProtection.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace ChocolArm64.Memory -{ - [Flags] - public enum MemoryProtection - { - None = 0, - Read = 1 << 0, - Write = 1 << 1, - Execute = 1 << 2, - - ReadAndWrite = Read | Write, - ReadAndExecute = Read | Execute - } -}
\ No newline at end of file diff --git a/ChocolArm64/Memory/MemoryProtectionException.cs b/ChocolArm64/Memory/MemoryProtectionException.cs deleted file mode 100644 index 3d2cebad..00000000 --- a/ChocolArm64/Memory/MemoryProtectionException.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace ChocolArm64.Memory -{ - class MemoryProtectionException : Exception - { - public MemoryProtectionException(MemoryProtection protection) : - base($"Failed to set memory protection to \"{protection}\".") { } - } -}
\ No newline at end of file |
