Ryujinx/ChocolArm64/Memory/AMemory.cs

320 lines
9.3 KiB
C#
Raw Normal View History

using ChocolArm64.Exceptions;
2018-02-05 00:08:20 +01:00
using ChocolArm64.State;
using System;
using System.Collections.Generic;
2018-02-18 05:57:33 +01:00
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
2018-02-05 00:08:20 +01:00
namespace ChocolArm64.Memory
{
public unsafe class AMemory : IDisposable
2018-02-05 00:08:20 +01:00
{
2018-02-18 20:28:07 +01:00
private const long ErgMask = (4 << AThreadState.ErgSizeLog2) - 1;
2018-02-05 00:08:20 +01:00
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;
public IntPtr Ram { get; private set; }
2018-02-05 00:08:20 +01:00
private byte* RamPtr;
public AMemory()
2018-02-05 00:08:20 +01:00
{
Manager = new AMemoryMgr();
2018-02-05 00:08:20 +01:00
Monitors = new Dictionary<int, ExMonitor>();
ExAddrs = new HashSet<long>();
Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize + AMemoryMgr.PageSize);
2018-02-05 00:08:20 +01:00
RamPtr = (byte*)Ram;
}
public void RemoveMonitor(int ThreadId)
{
lock (Monitors)
{
if (Monitors.TryGetValue(ThreadId, out ExMonitor Monitor))
{
ExAddrs.Remove(Monitor.Position);
}
2018-02-05 00:08:20 +01:00
Monitors.Remove(ThreadId);
}
}
2018-02-18 20:28:07 +01:00
public void SetExclusive(AThreadState ThreadState, long Position)
2018-02-05 00:08:20 +01:00
{
Position &= ~ErgMask;
2018-02-05 00:08:20 +01:00
lock (Monitors)
{
2018-02-18 20:28:07 +01:00
if (Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor))
2018-02-05 00:08:20 +01:00
{
ExAddrs.Remove(Monitor.Position);
2018-02-05 00:08:20 +01:00
}
bool ExState = ExAddrs.Add(Position);
Monitor = new ExMonitor(Position, ExState);
2018-02-05 00:08:20 +01:00
2018-02-18 20:28:07 +01:00
if (!Monitors.TryAdd(ThreadState.ThreadId, Monitor))
2018-02-05 00:08:20 +01:00
{
2018-02-18 20:28:07 +01:00
Monitors[ThreadState.ThreadId] = Monitor;
2018-02-05 00:08:20 +01:00
}
}
}
2018-02-18 20:28:07 +01:00
public bool TestExclusive(AThreadState ThreadState, long Position)
2018-02-05 00:08:20 +01:00
{
Position &= ~ErgMask;
2018-02-05 00:08:20 +01:00
lock (Monitors)
{
2018-02-18 20:28:07 +01:00
if (!Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor))
2018-02-05 00:08:20 +01:00
{
return false;
}
return Monitor.HasExclusiveAccess(Position);
}
}
2018-02-18 20:28:07 +01:00
public void ClearExclusive(AThreadState ThreadState)
2018-02-05 00:08:20 +01:00
{
lock (Monitors)
{
2018-02-18 20:28:07 +01:00
if (Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor))
2018-02-05 00:08:20 +01:00
{
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);
}
}
2018-02-05 00:08:20 +01:00
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);
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2018-02-05 00:08:20 +01:00
public byte ReadByte(long Position)
{
EnsureAccessIsValid(Position, AMemoryPerm.Read);
return *((byte*)(RamPtr + (uint)Position));
2018-02-05 00:08:20 +01:00
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2018-02-05 00:08:20 +01:00
public ushort ReadUInt16(long Position)
{
EnsureAccessIsValid(Position + 0, AMemoryPerm.Read);
EnsureAccessIsValid(Position + 1, AMemoryPerm.Read);
return *((ushort*)(RamPtr + (uint)Position));
2018-02-05 00:08:20 +01:00
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2018-02-05 00:08:20 +01:00
public uint ReadUInt32(long Position)
{
EnsureAccessIsValid(Position + 0, AMemoryPerm.Read);
EnsureAccessIsValid(Position + 3, AMemoryPerm.Read);
return *((uint*)(RamPtr + (uint)Position));
2018-02-05 00:08:20 +01:00
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2018-02-05 00:08:20 +01:00
public ulong ReadUInt64(long Position)
{
EnsureAccessIsValid(Position + 0, AMemoryPerm.Read);
EnsureAccessIsValid(Position + 7, AMemoryPerm.Read);
return *((ulong*)(RamPtr + (uint)Position));
2018-02-05 00:08:20 +01:00
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AVec ReadVector8(long Position)
{
return new AVec() { B0 = ReadByte(Position) };
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AVec ReadVector16(long Position)
{
return new AVec() { H0 = ReadUInt16(Position) };
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AVec ReadVector32(long Position)
{
return new AVec() { W0 = ReadUInt32(Position) };
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AVec ReadVector64(long Position)
{
return new AVec() { X0 = ReadUInt64(Position) };
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2018-02-05 00:08:20 +01:00
public AVec ReadVector128(long Position)
{
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);
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2018-02-05 00:08:20 +01:00
public void WriteByte(long Position, byte Value)
{
EnsureAccessIsValid(Position, AMemoryPerm.Write);
*((byte*)(RamPtr + (uint)Position)) = Value;
2018-02-05 00:08:20 +01:00
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2018-02-05 00:08:20 +01:00
public void WriteUInt16(long Position, ushort Value)
{
EnsureAccessIsValid(Position + 0, AMemoryPerm.Write);
EnsureAccessIsValid(Position + 1, AMemoryPerm.Write);
*((ushort*)(RamPtr + (uint)Position)) = Value;
2018-02-05 00:08:20 +01:00
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2018-02-05 00:08:20 +01:00
public void WriteUInt32(long Position, uint Value)
{
EnsureAccessIsValid(Position + 0, AMemoryPerm.Write);
EnsureAccessIsValid(Position + 3, AMemoryPerm.Write);
*((uint*)(RamPtr + (uint)Position)) = Value;
2018-02-05 00:08:20 +01:00
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2018-02-05 00:08:20 +01:00
public void WriteUInt64(long Position, ulong Value)
{
EnsureAccessIsValid(Position + 0, AMemoryPerm.Write);
EnsureAccessIsValid(Position + 7, AMemoryPerm.Write);
*((ulong*)(RamPtr + (uint)Position)) = Value;
2018-02-05 00:08:20 +01:00
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteVector8(long Position, AVec Value)
{
WriteByte(Position, Value.B0);
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteVector16(long Position, AVec Value)
{
WriteUInt16(Position, Value.H0);
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteVector32(long Position, AVec Value)
{
WriteUInt32(Position, Value.W0);
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteVector64(long Position, AVec Value)
{
WriteUInt64(Position, Value.X0);
}
2018-02-18 05:57:33 +01:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2018-02-05 00:08:20 +01:00
public void WriteVector128(long Position, AVec Value)
{
WriteUInt64(Position + 0, Value.X0);
WriteUInt64(Position + 8, Value.X1);
}
private void EnsureAccessIsValid(long Position, AMemoryPerm Perm)
2018-02-05 00:08:20 +01:00
{
#if DEBUG
if (AOptimizations.EnableMemoryChecks)
{
if (!Manager.IsMapped(Position))
{
throw new VmmPageFaultException(Position);
}
if (!Manager.HasPermission(Position, Perm))
{
throw new VmmAccessViolationException(Position, Perm);
}
}
#endif
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (Ram != IntPtr.Zero)
{
Marshal.FreeHGlobal(Ram);
Ram = IntPtr.Zero;
}
2018-02-05 00:08:20 +01:00
}
}
}