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
This commit is contained in:
Alex Barney 2018-10-30 19:43:02 -06:00 committed by gdkchan
parent 5a87e58183
commit 9cb57fb4bb
314 changed files with 19456 additions and 19456 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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