diff options
Diffstat (limited to 'ChocolArm64/Memory/AMemory.cs')
| -rw-r--r-- | ChocolArm64/Memory/AMemory.cs | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/ChocolArm64/Memory/AMemory.cs b/ChocolArm64/Memory/AMemory.cs new file mode 100644 index 00000000..f2abffbf --- /dev/null +++ b/ChocolArm64/Memory/AMemory.cs @@ -0,0 +1,345 @@ +using ChocolArm64.Exceptions; +using ChocolArm64.State; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace ChocolArm64.Memory +{ + public unsafe class AMemory + { + private const long ErgMask = (4 << AThreadState.ErgSizeLog2) - 1; + + public AMemoryMgr Manager { get; private set; } + + private struct ExMonitor + { + public long Position { get; private set; } + + private bool ExState; + + public ExMonitor(long Position, bool ExState) + { + this.Position = Position; + this.ExState = ExState; + } + + public bool HasExclusiveAccess(long Position) + { + return this.Position == Position && ExState; + } + + public void Reset() + { + ExState = false; + } + } + + private Dictionary<int, ExMonitor> Monitors; + + private HashSet<long> ExAddrs; + + private byte* RamPtr; + + public AMemory(IntPtr Ram, AMemoryAlloc Allocator) + { + Manager = new AMemoryMgr(Allocator); + + Monitors = new Dictionary<int, ExMonitor>(); + + ExAddrs = new HashSet<long>(); + + RamPtr = (byte*)Ram; + } + + public void RemoveMonitor(int ThreadId) + { + lock (Monitors) + { + if (Monitors.TryGetValue(ThreadId, out ExMonitor Monitor)) + { + ExAddrs.Remove(Monitor.Position); + } + + Monitors.Remove(ThreadId); + } + } + + public void SetExclusive(AThreadState ThreadState, long Position) + { + Position &= ~ErgMask; + + lock (Monitors) + { + if (Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor)) + { + ExAddrs.Remove(Monitor.Position); + } + + bool ExState = ExAddrs.Add(Position); + + Monitor = new ExMonitor(Position, ExState); + + if (!Monitors.TryAdd(ThreadState.ThreadId, Monitor)) + { + Monitors[ThreadState.ThreadId] = Monitor; + } + } + } + + public bool TestExclusive(AThreadState ThreadState, long Position) + { + Position &= ~ErgMask; + + lock (Monitors) + { + if (!Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor)) + { + return false; + } + + return Monitor.HasExclusiveAccess(Position); + } + } + + public void ClearExclusive(AThreadState ThreadState) + { + lock (Monitors) + { + if (Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor)) + { + Monitor.Reset(); + ExAddrs.Remove(Monitor.Position); + } + } + } + + public bool AcquireAddress(long Position) + { + Position &= ~ErgMask; + + lock (Monitors) + { + return ExAddrs.Add(Position); + } + } + + public void ReleaseAddress(long Position) + { + Position &= ~ErgMask; + + lock (Monitors) + { + ExAddrs.Remove(Position); + } + } + + public sbyte ReadSByte(long Position) => (sbyte)ReadByte (Position); + public short ReadInt16(long Position) => (short)ReadUInt16(Position); + public int ReadInt32(long Position) => (int)ReadUInt32(Position); + public long ReadInt64(long Position) => (long)ReadUInt64(Position); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte ReadByte(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return *((byte*)(RamPtr + (uint)Position)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ushort ReadUInt16(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return *((ushort*)(RamPtr + (uint)Position)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint ReadUInt32(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return *((uint*)(RamPtr + (uint)Position)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ulong ReadUInt64(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return *((ulong*)(RamPtr + (uint)Position)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public AVec ReadVector8(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return new AVec() { B0 = ReadByte(Position) }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public AVec ReadVector16(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return new AVec() { H0 = ReadUInt16(Position) }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public AVec ReadVector32(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return new AVec() { W0 = ReadUInt32(Position) }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public AVec ReadVector64(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return new AVec() { X0 = ReadUInt64(Position) }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public AVec ReadVector128(long Position) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Read); +#endif + + return new AVec() + { + X0 = ReadUInt64(Position + 0), + X1 = ReadUInt64(Position + 8) + }; + } + + 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); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteByte(long Position, byte Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + *((byte*)(RamPtr + (uint)Position)) = Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteUInt16(long Position, ushort Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + *((ushort*)(RamPtr + (uint)Position)) = Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteUInt32(long Position, uint Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + *((uint*)(RamPtr + (uint)Position)) = Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteUInt64(long Position, ulong Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + *((ulong*)(RamPtr + (uint)Position)) = Value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector8(long Position, AVec Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + WriteByte(Position, Value.B0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector16(long Position, AVec Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + WriteUInt16(Position, Value.H0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector32(long Position, AVec Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + WriteUInt32(Position, Value.W0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector64(long Position, AVec Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + WriteUInt64(Position, Value.X0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteVector128(long Position, AVec Value) + { +#if DEBUG + EnsureAccessIsValid(Position, AMemoryPerm.Write); +#endif + + WriteUInt64(Position + 0, Value.X0); + WriteUInt64(Position + 8, Value.X1); + } + + private void EnsureAccessIsValid(long Position, AMemoryPerm Perm) + { + if (!Manager.IsMapped(Position)) + { + throw new VmmPageFaultException(Position); + } + + if (!Manager.HasPermission(Position, Perm)) + { + throw new VmmAccessViolationException(Position, Perm); + } + } + } +}
\ No newline at end of file |
