diff options
| author | Alex Barney <thealexbarney@gmail.com> | 2018-10-30 19:43:02 -0600 |
|---|---|---|
| committer | gdkchan <gab.dark.100@gmail.com> | 2018-10-30 22:43:02 -0300 |
| commit | 9cb57fb4bb3bbae0ae052a5af4a96a49fc5d864d (patch) | |
| tree | 0c97425aeb311c142bc92a6fcc503cb2c07d4376 /ChocolArm64/Memory | |
| parent | 5a87e58183578f5b84ca8d01cbb76aed11820f78 (diff) | |
Adjust naming conventions for Ryujinx and ChocolArm64 projects (#484)
* Change naming convention for Ryujinx project
* Change naming convention for ChocolArm64 project
* Fix NaN
* Remove unneeded this. from Ryujinx project
* Adjust naming from new PRs
* Name changes based on feedback
* How did this get removed?
* Rebasing fix
* Change FP enum case
* Remove prefix from ChocolArm64 classes - Part 1
* Remove prefix from ChocolArm64 classes - Part 2
* Fix alignment from last commit's renaming
* Rename namespaces
* Rename stragglers
* Fix alignment
* Rename OpCode class
* Missed a few
* Adjust alignment
Diffstat (limited to 'ChocolArm64/Memory')
| -rw-r--r-- | ChocolArm64/Memory/AMemory.cs | 745 | ||||
| -rw-r--r-- | ChocolArm64/Memory/AMemoryHelper.cs | 67 | ||||
| -rw-r--r-- | ChocolArm64/Memory/IAMemory.cs | 37 | ||||
| -rw-r--r-- | ChocolArm64/Memory/IMemory.cs | 37 | ||||
| -rw-r--r-- | ChocolArm64/Memory/MemoryHelper.cs | 67 | ||||
| -rw-r--r-- | ChocolArm64/Memory/MemoryManager.cs | 745 |
6 files changed, 849 insertions, 849 deletions
diff --git a/ChocolArm64/Memory/AMemory.cs b/ChocolArm64/Memory/AMemory.cs deleted file mode 100644 index 2854871e..00000000 --- a/ChocolArm64/Memory/AMemory.cs +++ /dev/null @@ -1,745 +0,0 @@ -using ChocolArm64.Events; -using ChocolArm64.Exceptions; -using ChocolArm64.State; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; -using System.Threading; - -namespace ChocolArm64.Memory -{ - public unsafe class AMemory : IAMemory, IDisposable - { - private const int PTLvl0Bits = 13; - private const int PTLvl1Bits = 14; - private const int PTPageBits = 12; - - private const int PTLvl0Size = 1 << PTLvl0Bits; - private const int PTLvl1Size = 1 << PTLvl1Bits; - public const int PageSize = 1 << PTPageBits; - - private const int PTLvl0Mask = PTLvl0Size - 1; - private const int PTLvl1Mask = PTLvl1Size - 1; - public const int PageMask = PageSize - 1; - - private const int PTLvl0Bit = PTPageBits + PTLvl1Bits; - private const int PTLvl1Bit = PTPageBits; - - private const long ErgMask = (4 << AThreadState.ErgSizeLog2) - 1; - - private class ArmMonitor - { - public long Position; - public bool ExState; - - public bool HasExclusiveAccess(long Position) - { - return this.Position == Position && ExState; - } - } - - private Dictionary<int, ArmMonitor> Monitors; - - private ConcurrentDictionary<long, IntPtr> ObservedPages; - - public IntPtr Ram { get; private set; } - - private byte* RamPtr; - - private byte*** PageTable; - - public event EventHandler<AInvalidAccessEventArgs> InvalidAccess; - - public AMemory(IntPtr Ram) - { - Monitors = new Dictionary<int, ArmMonitor>(); - - ObservedPages = new ConcurrentDictionary<long, IntPtr>(); - - this.Ram = Ram; - - RamPtr = (byte*)Ram; - - PageTable = (byte***)Marshal.AllocHGlobal(PTLvl0Size * IntPtr.Size); - - for (int L0 = 0; L0 < PTLvl0Size; L0++) - { - PageTable[L0] = null; - } - } - - public void RemoveMonitor(int Core) - { - lock (Monitors) - { - ClearExclusive(Core); - - Monitors.Remove(Core); - } - } - - public void SetExclusive(int Core, long Position) - { - Position &= ~ErgMask; - - lock (Monitors) - { - foreach (ArmMonitor Mon in Monitors.Values) - { - if (Mon.Position == Position && Mon.ExState) - { - Mon.ExState = false; - } - } - - if (!Monitors.TryGetValue(Core, out ArmMonitor ThreadMon)) - { - ThreadMon = new ArmMonitor(); - - Monitors.Add(Core, ThreadMon); - } - - ThreadMon.Position = Position; - ThreadMon.ExState = true; - } - } - - public bool TestExclusive(int Core, long Position) - { - //Note: Any call to this method also should be followed by a - //call to ClearExclusiveForStore if this method returns true. - Position &= ~ErgMask; - - Monitor.Enter(Monitors); - - if (!Monitors.TryGetValue(Core, out ArmMonitor ThreadMon)) - { - return false; - } - - bool ExState = ThreadMon.HasExclusiveAccess(Position); - - if (!ExState) - { - Monitor.Exit(Monitors); - } - - return ExState; - } - - public void ClearExclusiveForStore(int Core) - { - if (Monitors.TryGetValue(Core, out ArmMonitor ThreadMon)) - { - ThreadMon.ExState = false; - } - - Monitor.Exit(Monitors); - } - - public void ClearExclusive(int Core) - { - lock (Monitors) - { - if (Monitors.TryGetValue(Core, out ArmMonitor ThreadMon)) - { - ThreadMon.ExState = false; - } - } - } - - public void WriteInt32ToSharedAddr(long Position, int Value) - { - long MaskedPosition = Position & ~ErgMask; - - lock (Monitors) - { - foreach (ArmMonitor Mon in Monitors.Values) - { - if (Mon.Position == MaskedPosition && Mon.ExState) - { - Mon.ExState = false; - } - } - - WriteInt32(Position, Value); - } - } - - 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) - { - return *((ushort*)Translate(Position)); - } - - public uint ReadUInt32(long Position) - { - return *((uint*)Translate(Position)); - } - - public ulong ReadUInt64(long Position) - { - return *((ulong*)Translate(Position)); - } - - 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 - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector128<float> ReadVector16(long Position) - { - if (Sse2.IsSupported) - { - return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse2.SetZeroVector128<ushort>(), ReadUInt16(Position), 0)); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector128<float> ReadVector32(long Position) - { - if (Sse.IsSupported) - { - return Sse.LoadScalarVector128((float*)Translate(Position)); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector128<float> ReadVector64(long Position) - { - if (Sse2.IsSupported) - { - return Sse.StaticCast<double, float>(Sse2.LoadScalarVector128((double*)Translate(Position))); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector128<float> ReadVector128(long Position) - { - if (Sse.IsSupported) - { - return Sse.LoadVector128((float*)Translate(Position)); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - public byte[] ReadBytes(long Position, long Size) - { - if ((uint)Size > int.MaxValue) - { - throw new ArgumentOutOfRangeException(nameof(Size)); - } - - EnsureRangeIsValid(Position, Size); - - byte[] Data = new byte[Size]; - - Marshal.Copy((IntPtr)Translate(Position), Data, 0, (int)Size); - - return Data; - } - - public void ReadBytes(long Position, byte[] Data, int StartIndex, int Size) - { - //Note: This will be moved later. - EnsureRangeIsValid(Position, (uint)Size); - - Marshal.Copy((IntPtr)Translate(Position), Data, StartIndex, Size); - } - - 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) - { - *((ushort*)TranslateWrite(Position)) = Value; - } - - public void WriteUInt32(long Position, uint Value) - { - *((uint*)TranslateWrite(Position)) = Value; - } - - public void WriteUInt64(long Position, ulong Value) - { - *((ulong*)TranslateWrite(Position)) = Value; - } - - [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 - { - throw new PlatformNotSupportedException(); - } - } - - [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 - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector32(long Position, Vector128<float> Value) - { - if (Sse.IsSupported) - { - Sse.StoreScalar((float*)TranslateWrite(Position), Value); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector64(long Position, Vector128<float> Value) - { - if (Sse2.IsSupported) - { - Sse2.StoreScalar((double*)TranslateWrite(Position), Sse.StaticCast<float, double>(Value)); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteVector128(long Position, Vector128<float> Value) - { - if (Sse.IsSupported) - { - Sse.Store((float*)TranslateWrite(Position), Value); - } - else - { - throw new PlatformNotSupportedException(); - } - } - - public void WriteBytes(long Position, byte[] Data) - { - EnsureRangeIsValid(Position, (uint)Data.Length); - - Marshal.Copy(Data, 0, (IntPtr)TranslateWrite(Position), Data.Length); - } - - public void WriteBytes(long Position, byte[] Data, int StartIndex, int Size) - { - //Note: This will be moved later. - //Using Translate instead of TranslateWrite is on purpose. - EnsureRangeIsValid(Position, (uint)Size); - - Marshal.Copy(Data, StartIndex, (IntPtr)Translate(Position), Size); - } - - public void CopyBytes(long Src, long Dst, long Size) - { - //Note: This will be moved later. - EnsureRangeIsValid(Src, Size); - EnsureRangeIsValid(Dst, Size); - - byte* SrcPtr = Translate(Src); - byte* DstPtr = TranslateWrite(Dst); - - Buffer.MemoryCopy(SrcPtr, DstPtr, Size, 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); - - StopObservingRegion(Position, Size); - } - - public bool IsMapped(long Position) - { - if (!(IsValidPosition(Position))) - { - return false; - } - - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - return false; - } - - return PageTable[L0][L1] != null || ObservedPages.ContainsKey(Position >> PTPageBits); - } - - public long GetPhysicalAddress(long VirtualAddress) - { - byte* Ptr = Translate(VirtualAddress); - - return (long)(Ptr - RamPtr); - } - - internal byte* Translate(long Position) - { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - long Old = Position; - - byte** Lvl1 = PageTable[L0]; - - if ((Position >> (PTLvl0Bit + PTLvl0Bits)) != 0) - { - goto Unmapped; - } - - if (Lvl1 == null) - { - goto Unmapped; - } - - Position &= PageMask; - - byte* Ptr = Lvl1[L1]; - - if (Ptr == null) - { - goto Unmapped; - } - - return Ptr + Position; - -Unmapped: - return HandleNullPte(Old); - } - - private byte* HandleNullPte(long Position) - { - long Key = Position >> PTPageBits; - - if (ObservedPages.TryGetValue(Key, out IntPtr Ptr)) - { - return (byte*)Ptr + (Position & PageMask); - } - - InvalidAccess?.Invoke(this, new AInvalidAccessEventArgs(Position)); - - throw new VmmPageFaultException(Position); - } - - internal byte* TranslateWrite(long Position) - { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - long Old = Position; - - byte** Lvl1 = PageTable[L0]; - - if ((Position >> (PTLvl0Bit + PTLvl0Bits)) != 0) - { - goto Unmapped; - } - - if (Lvl1 == null) - { - goto Unmapped; - } - - Position &= PageMask; - - byte* Ptr = Lvl1[L1]; - - if (Ptr == null) - { - goto Unmapped; - } - - return Ptr + Position; - -Unmapped: - return HandleNullPteWrite(Old); - } - - private byte* HandleNullPteWrite(long Position) - { - long Key = Position >> PTPageBits; - - if (ObservedPages.TryGetValue(Key, out IntPtr Ptr)) - { - SetPTEntry(Position, (byte*)Ptr); - - return (byte*)Ptr + (Position & PageMask); - } - - InvalidAccess?.Invoke(this, new AInvalidAccessEventArgs(Position)); - - throw new VmmPageFaultException(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) - { - if (!IsValidPosition(Position)) - { - throw new ArgumentOutOfRangeException(nameof(Position)); - } - - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - if (PageTable[L0] == null) - { - byte** Lvl1 = (byte**)Marshal.AllocHGlobal(PTLvl1Size * IntPtr.Size); - - for (int ZL1 = 0; ZL1 < PTLvl1Size; ZL1++) - { - Lvl1[ZL1] = null; - } - - Thread.MemoryBarrier(); - - PageTable[L0] = Lvl1; - } - - PageTable[L0][L1] = Ptr; - } - - public (bool[], int) IsRegionModified(long Position, long Size) - { - long EndPosition = (Position + Size + PageMask) & ~PageMask; - - Position &= ~PageMask; - - Size = EndPosition - Position; - - bool[] Modified = new bool[Size >> PTPageBits]; - - int Count = 0; - - lock (ObservedPages) - { - for (int Page = 0; Page < Modified.Length; Page++) - { - byte* Ptr = Translate(Position); - - if (ObservedPages.TryAdd(Position >> PTPageBits, (IntPtr)Ptr)) - { - Modified[Page] = true; - - Count++; - } - else - { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; - - byte** Lvl1 = PageTable[L0]; - - if (Lvl1 != null) - { - if (Modified[Page] = Lvl1[L1] != null) - { - Count++; - } - } - } - - SetPTEntry(Position, null); - - Position += PageSize; - } - } - - return (Modified, Count); - } - - public void StopObservingRegion(long Position, long Size) - { - long EndPosition = (Position + Size + PageMask) & ~PageMask; - - while (Position < EndPosition) - { - lock (ObservedPages) - { - if (ObservedPages.TryRemove(Position >> PTPageBits, out IntPtr Ptr)) - { - SetPTEntry(Position, (byte*)Ptr); - } - } - - Position += PageSize; - } - } - - public IntPtr GetHostAddress(long Position, long Size) - { - EnsureRangeIsValid(Position, Size); - - return (IntPtr)Translate(Position); - } - - internal void EnsureRangeIsValid(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) - { - throw new VmmAccessException(Position, Size); - } - - Position += PageSize; - ExpectedPA += PageSize; - } - } - - public bool IsValidPosition(long Position) - { - return Position >> (PTLvl0Bits + PTLvl1Bits + PTPageBits) == 0; - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (PageTable == null) - { - return; - } - - for (int L0 = 0; L0 < PTLvl0Size; L0++) - { - if (PageTable[L0] != null) - { - Marshal.FreeHGlobal((IntPtr)PageTable[L0]); - } - - PageTable[L0] = null; - } - - Marshal.FreeHGlobal((IntPtr)PageTable); - - PageTable = null; - } - } -}
\ No newline at end of file diff --git a/ChocolArm64/Memory/AMemoryHelper.cs b/ChocolArm64/Memory/AMemoryHelper.cs deleted file mode 100644 index ea877834..00000000 --- a/ChocolArm64/Memory/AMemoryHelper.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; -using System.Text; - -namespace ChocolArm64.Memory -{ - public static class AMemoryHelper - { - public static void FillWithZeros(AMemory 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>(AMemory Memory, long Position) where T : struct - { - long Size = Marshal.SizeOf<T>(); - - Memory.EnsureRangeIsValid(Position, Size); - - IntPtr Ptr = (IntPtr)Memory.Translate(Position); - - return Marshal.PtrToStructure<T>(Ptr); - } - - public unsafe static void Write<T>(AMemory Memory, long Position, T Value) where T : struct - { - long Size = Marshal.SizeOf<T>(); - - Memory.EnsureRangeIsValid(Position, Size); - - IntPtr Ptr = (IntPtr)Memory.TranslateWrite(Position); - - Marshal.StructureToPtr<T>(Value, Ptr, false); - } - - public static string ReadAsciiString(AMemory 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/IAMemory.cs b/ChocolArm64/Memory/IAMemory.cs deleted file mode 100644 index 5b7d17bb..00000000 --- a/ChocolArm64/Memory/IAMemory.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace ChocolArm64.Memory -{ - public interface IAMemory - { - 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/IMemory.cs b/ChocolArm64/Memory/IMemory.cs new file mode 100644 index 00000000..dc582155 --- /dev/null +++ b/ChocolArm64/Memory/IMemory.cs @@ -0,0 +1,37 @@ +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 new file mode 100644 index 00000000..2e721afa --- /dev/null +++ b/ChocolArm64/Memory/MemoryHelper.cs @@ -0,0 +1,67 @@ +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>(); + + memory.EnsureRangeIsValid(position, size); + + IntPtr ptr = (IntPtr)memory.Translate(position); + + return Marshal.PtrToStructure<T>(ptr); + } + + public unsafe static void Write<T>(MemoryManager memory, long position, T value) where T : struct + { + long size = Marshal.SizeOf<T>(); + + memory.EnsureRangeIsValid(position, size); + + IntPtr ptr = (IntPtr)memory.TranslateWrite(position); + + Marshal.StructureToPtr<T>(value, ptr, false); + } + + 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/MemoryManager.cs b/ChocolArm64/Memory/MemoryManager.cs new file mode 100644 index 00000000..308dd17e --- /dev/null +++ b/ChocolArm64/Memory/MemoryManager.cs @@ -0,0 +1,745 @@ +using ChocolArm64.Events; +using ChocolArm64.Exceptions; +using ChocolArm64.State; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +using System.Threading; + +namespace ChocolArm64.Memory +{ + public unsafe class MemoryManager : IMemory, IDisposable + { + private const int PtLvl0Bits = 13; + private const int PtLvl1Bits = 14; + private const int PtPageBits = 12; + + private const int PtLvl0Size = 1 << PtLvl0Bits; + private const int PtLvl1Size = 1 << PtLvl1Bits; + public const int PageSize = 1 << PtPageBits; + + private const int PtLvl0Mask = PtLvl0Size - 1; + private const int PtLvl1Mask = PtLvl1Size - 1; + public const int PageMask = PageSize - 1; + + private const int PtLvl0Bit = PtPageBits + PtLvl1Bits; + private const int PtLvl1Bit = PtPageBits; + + private const long ErgMask = (4 << CpuThreadState.ErgSizeLog2) - 1; + + private class ArmMonitor + { + public long Position; + public bool ExState; + + public bool HasExclusiveAccess(long position) + { + return Position == position && ExState; + } + } + + private Dictionary<int, ArmMonitor> _monitors; + + private ConcurrentDictionary<long, IntPtr> _observedPages; + + public IntPtr Ram { get; private set; } + + private byte* _ramPtr; + + private byte*** _pageTable; + + public event EventHandler<InvalidAccessEventArgs> InvalidAccess; + + public MemoryManager(IntPtr ram) + { + _monitors = new Dictionary<int, ArmMonitor>(); + + _observedPages = new ConcurrentDictionary<long, IntPtr>(); + + Ram = ram; + + _ramPtr = (byte*)ram; + + _pageTable = (byte***)Marshal.AllocHGlobal(PtLvl0Size * IntPtr.Size); + + for (int l0 = 0; l0 < PtLvl0Size; l0++) + { + _pageTable[l0] = null; + } + } + + public void RemoveMonitor(int core) + { + lock (_monitors) + { + ClearExclusive(core); + + _monitors.Remove(core); + } + } + + public void SetExclusive(int core, long position) + { + position &= ~ErgMask; + + lock (_monitors) + { + foreach (ArmMonitor mon in _monitors.Values) + { + if (mon.Position == position && mon.ExState) + { + mon.ExState = false; + } + } + + if (!_monitors.TryGetValue(core, out ArmMonitor threadMon)) + { + threadMon = new ArmMonitor(); + + _monitors.Add(core, threadMon); + } + + threadMon.Position = position; + threadMon.ExState = true; + } + } + + public bool TestExclusive(int core, long position) + { + //Note: Any call to this method also should be followed by a + //call to ClearExclusiveForStore if this method returns true. + position &= ~ErgMask; + + Monitor.Enter(_monitors); + + if (!_monitors.TryGetValue(core, out ArmMonitor threadMon)) + { + return false; + } + + bool exState = threadMon.HasExclusiveAccess(position); + + if (!exState) + { + Monitor.Exit(_monitors); + } + + return exState; + } + + public void ClearExclusiveForStore(int core) + { + if (_monitors.TryGetValue(core, out ArmMonitor threadMon)) + { + threadMon.ExState = false; + } + + Monitor.Exit(_monitors); + } + + public void ClearExclusive(int core) + { + lock (_monitors) + { + if (_monitors.TryGetValue(core, out ArmMonitor threadMon)) + { + threadMon.ExState = false; + } + } + } + + public void WriteInt32ToSharedAddr(long position, int value) + { + long maskedPosition = position & ~ErgMask; + + lock (_monitors) + { + foreach (ArmMonitor mon in _monitors.Values) + { + if (mon.Position == maskedPosition && mon.ExState) + { + mon.ExState = false; + } + } + + WriteInt32(position, value); + } + } + + 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) + { + return *((ushort*)Translate(position)); + } + + public uint ReadUInt32(long position) + { + return *((uint*)Translate(position)); + } + + public ulong ReadUInt64(long position) + { + return *((ulong*)Translate(position)); + } + + 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 + { + throw new PlatformNotSupportedException(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector128<float> ReadVector16(long position) + { + if (Sse2.IsSupported) + { + return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse2.SetZeroVector128<ushort>(), ReadUInt16(position), 0)); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector128<float> ReadVector32(long position) + { + if (Sse.IsSupported) + { + return Sse.LoadScalarVector128((float*)Translate(position)); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector128<float> ReadVector64(long position) + { + if (Sse2.IsSupported) + { + return Sse.StaticCast<double, float>(Sse2.LoadScalarVector128((double*)Translate(position))); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector128<float> ReadVector128(long position) + { + if (Sse.IsSupported) + { + return Sse.LoadVector128((float*)Translate(position)); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + public byte[] ReadBytes(long position, long size) + { + if ((uint)size > int.MaxValue) + { + throw new ArgumentOutOfRangeException(nameof(size)); + } + + EnsureRangeIsValid(position, size); + + byte[] data = new byte[size]; + + Marshal.Copy((IntPtr)Translate(position), data, 0, (int)size); + + return data; + } + + public void ReadBytes(long position, byte[] data, int startIndex, int size) + { + //Note: This will be moved later. + EnsureRangeIsValid(position, (uint)size); + + Marshal.Copy((IntPtr)Translate(position), data, startIndex, size); + } + + 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) + { + *((ushort*)TranslateWrite(position)) = value; + } + + public void WriteUInt32(long position, uint value) + { + *((uint*)TranslateWrite(position)) = value; + } + + public void WriteUInt64(long position, ulong value) + { + *((ulong*)TranslateWrite(position)) = value; + } + + [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 + { + throw new PlatformNotSupportedException(); + } + } + + [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 + { + throw new PlatformNotSupportedException(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector32(long position, Vector128<float> value) + { + if (Sse.IsSupported) + { + Sse.StoreScalar((float*)TranslateWrite(position), value); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector64(long position, Vector128<float> value) + { + if (Sse2.IsSupported) + { + Sse2.StoreScalar((double*)TranslateWrite(position), Sse.StaticCast<float, double>(value)); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector128(long position, Vector128<float> value) + { + if (Sse.IsSupported) + { + Sse.Store((float*)TranslateWrite(position), value); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + public void WriteBytes(long position, byte[] data) + { + EnsureRangeIsValid(position, (uint)data.Length); + + Marshal.Copy(data, 0, (IntPtr)TranslateWrite(position), data.Length); + } + + public void WriteBytes(long position, byte[] data, int startIndex, int size) + { + //Note: This will be moved later. + //Using Translate instead of TranslateWrite is on purpose. + EnsureRangeIsValid(position, (uint)size); + + Marshal.Copy(data, startIndex, (IntPtr)Translate(position), size); + } + + public void CopyBytes(long src, long dst, long size) + { + //Note: This will be moved later. + EnsureRangeIsValid(src, size); + EnsureRangeIsValid(dst, size); + + byte* srcPtr = Translate(src); + byte* dstPtr = TranslateWrite(dst); + + Buffer.MemoryCopy(srcPtr, dstPtr, size, 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); + + StopObservingRegion(position, size); + } + + public bool IsMapped(long position) + { + if (!(IsValidPosition(position))) + { + return false; + } + + long l0 = (position >> PtLvl0Bit) & PtLvl0Mask; + long l1 = (position >> PtLvl1Bit) & PtLvl1Mask; + + if (_pageTable[l0] == null) + { + return false; + } + + return _pageTable[l0][l1] != null || _observedPages.ContainsKey(position >> PtPageBits); + } + + public long GetPhysicalAddress(long virtualAddress) + { + byte* ptr = Translate(virtualAddress); + + return (long)(ptr - _ramPtr); + } + + internal byte* Translate(long position) + { + long l0 = (position >> PtLvl0Bit) & PtLvl0Mask; + long l1 = (position >> PtLvl1Bit) & PtLvl1Mask; + + long old = position; + + byte** lvl1 = _pageTable[l0]; + + if ((position >> (PtLvl0Bit + PtLvl0Bits)) != 0) + { + goto Unmapped; + } + + if (lvl1 == null) + { + goto Unmapped; + } + + position &= PageMask; + + byte* ptr = lvl1[l1]; + + if (ptr == null) + { + goto Unmapped; + } + + return ptr + position; + +Unmapped: + return HandleNullPte(old); + } + + private byte* HandleNullPte(long position) + { + long key = position >> PtPageBits; + + if (_observedPages.TryGetValue(key, out IntPtr ptr)) + { + return (byte*)ptr + (position & PageMask); + } + + InvalidAccess?.Invoke(this, new InvalidAccessEventArgs(position)); + + throw new VmmPageFaultException(position); + } + + internal byte* TranslateWrite(long position) + { + long l0 = (position >> PtLvl0Bit) & PtLvl0Mask; + long l1 = (position >> PtLvl1Bit) & PtLvl1Mask; + + long old = position; + + byte** lvl1 = _pageTable[l0]; + + if ((position >> (PtLvl0Bit + PtLvl0Bits)) != 0) + { + goto Unmapped; + } + + if (lvl1 == null) + { + goto Unmapped; + } + + position &= PageMask; + + byte* ptr = lvl1[l1]; + + if (ptr == null) + { + goto Unmapped; + } + + return ptr + position; + +Unmapped: + return HandleNullPteWrite(old); + } + + private byte* HandleNullPteWrite(long position) + { + long key = position >> PtPageBits; + + if (_observedPages.TryGetValue(key, out IntPtr ptr)) + { + SetPtEntry(position, (byte*)ptr); + + return (byte*)ptr + (position & PageMask); + } + + InvalidAccess?.Invoke(this, new InvalidAccessEventArgs(position)); + + throw new VmmPageFaultException(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) + { + if (!IsValidPosition(position)) + { + throw new ArgumentOutOfRangeException(nameof(position)); + } + + long l0 = (position >> PtLvl0Bit) & PtLvl0Mask; + long l1 = (position >> PtLvl1Bit) & PtLvl1Mask; + + if (_pageTable[l0] == null) + { + byte** lvl1 = (byte**)Marshal.AllocHGlobal(PtLvl1Size * IntPtr.Size); + + for (int zl1 = 0; zl1 < PtLvl1Size; zl1++) + { + lvl1[zl1] = null; + } + + Thread.MemoryBarrier(); + + _pageTable[l0] = lvl1; + } + + _pageTable[l0][l1] = ptr; + } + + public (bool[], int) IsRegionModified(long position, long size) + { + long endPosition = (position + size + PageMask) & ~PageMask; + + position &= ~PageMask; + + size = endPosition - position; + + bool[] modified = new bool[size >> PtPageBits]; + + int count = 0; + + lock (_observedPages) + { + for (int page = 0; page < modified.Length; page++) + { + byte* ptr = Translate(position); + + if (_observedPages.TryAdd(position >> PtPageBits, (IntPtr)ptr)) + { + modified[page] = true; + + count++; + } + else + { + long l0 = (position >> PtLvl0Bit) & PtLvl0Mask; + long l1 = (position >> PtLvl1Bit) & PtLvl1Mask; + + byte** lvl1 = _pageTable[l0]; + + if (lvl1 != null) + { + if (modified[page] = lvl1[l1] != null) + { + count++; + } + } + } + + SetPtEntry(position, null); + + position += PageSize; + } + } + + return (modified, count); + } + + public void StopObservingRegion(long position, long size) + { + long endPosition = (position + size + PageMask) & ~PageMask; + + while (position < endPosition) + { + lock (_observedPages) + { + if (_observedPages.TryRemove(position >> PtPageBits, out IntPtr ptr)) + { + SetPtEntry(position, (byte*)ptr); + } + } + + position += PageSize; + } + } + + public IntPtr GetHostAddress(long position, long size) + { + EnsureRangeIsValid(position, size); + + return (IntPtr)Translate(position); + } + + internal void EnsureRangeIsValid(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) + { + throw new VmmAccessException(position, size); + } + + position += PageSize; + expectedPa += PageSize; + } + } + + public bool IsValidPosition(long position) + { + return position >> (PtLvl0Bits + PtLvl1Bits + PtPageBits) == 0; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (_pageTable == null) + { + return; + } + + for (int l0 = 0; l0 < PtLvl0Size; l0++) + { + if (_pageTable[l0] != null) + { + Marshal.FreeHGlobal((IntPtr)_pageTable[l0]); + } + + _pageTable[l0] = null; + } + + Marshal.FreeHGlobal((IntPtr)_pageTable); + + _pageTable = null; + } + } +}
\ No newline at end of file |
