Split main project into core,graphics and chocolarm4 subproject (#29)

This commit is contained in:
emmauss 2018-02-20 22:09:23 +02:00 committed by gdkchan
parent cb665bb715
commit 62b827f474
257 changed files with 415 additions and 285 deletions

View file

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

View file

@ -0,0 +1,35 @@
using ChocolArm64.Exceptions;
namespace ChocolArm64.Memory
{
public class AMemoryAlloc
{
private long PhysPos;
public long Alloc(long Size)
{
long Position = PhysPos;
Size = AMemoryHelper.PageRoundUp(Size);
PhysPos += Size;
if (PhysPos > AMemoryMgr.RamSize || PhysPos < 0)
{
throw new VmmOutOfMemoryException(Size);
}
return Position;
}
public void Free(long Position)
{
//TODO
}
public long GetFreeMem()
{
return AMemoryMgr.RamSize - PhysPos;
}
}
}

View file

@ -0,0 +1,73 @@
using System.IO;
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 static byte[] ReadBytes(AMemory Memory, long Position, int Size)
{
byte[] Data = new byte[Size];
for (int Offs = 0; Offs < Size; Offs++)
{
Data[Offs] = (byte)Memory.ReadByte(Position + Offs);
}
return Data;
}
public static void WriteBytes(AMemory Memory, long Position, byte[] Data)
{
for (int Offs = 0; Offs < Data.Length; Offs++)
{
Memory.WriteByte(Position + Offs, Data[Offs]);
}
}
public static string ReadAsciiString(AMemory Memory, long Position, int MaxSize = -1)
{
using (MemoryStream MS = new MemoryStream())
{
for (int 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());
}
}
public static long PageRoundUp(long Value)
{
return (Value + AMemoryMgr.PageMask) & ~AMemoryMgr.PageMask;
}
public static long PageRoundDown(long Value)
{
return Value & ~AMemoryMgr.PageMask;
}
}
}

View file

@ -0,0 +1,21 @@
namespace ChocolArm64.Memory
{
public struct AMemoryMapInfo
{
public long Position { get; private set; }
public long Size { get; private set; }
public int Type { get; private set; }
public int Attr { get; private set; }
public AMemoryPerm Perm { get; private set; }
public AMemoryMapInfo(long Position, long Size, int Type, int Attr, AMemoryPerm Perm)
{
this.Position = Position;
this.Size = Size;
this.Type = Type;
this.Attr = Attr;
this.Perm = Perm;
}
}
}

View file

@ -0,0 +1,286 @@
namespace ChocolArm64.Memory
{
public class AMemoryMgr
{
public const long AddrSize = RamSize;
public const long RamSize = 4L * 1024 * 1024 * 1024;
private const int PTLvl0Bits = 11;
private const int PTLvl1Bits = 13;
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 + PTLvl0Bits;
private const int PTLvl1Bit = PTPageBits;
private AMemoryAlloc Allocator;
private enum PTMap
{
Unmapped,
Mapped
}
private struct PTEntry
{
public PTMap Map;
public AMemoryPerm Perm;
public int Type;
public int Attr;
public PTEntry(PTMap Map, AMemoryPerm Perm, int Type, int Attr)
{
this.Map = Map;
this.Perm = Perm;
this.Type = Type;
this.Attr = Attr;
}
}
private PTEntry[][] PageTable;
private bool IsHeapInitialized;
public long HeapAddr { get; private set; }
public long HeapSize { get; private set; }
public AMemoryMgr(AMemoryAlloc Allocator)
{
this.Allocator = Allocator;
PageTable = new PTEntry[PTLvl0Size][];
}
public long GetTotalMemorySize()
{
return Allocator.GetFreeMem() + GetUsedMemorySize();
}
public long GetUsedMemorySize()
{
long Size = 0;
for (int L0 = 0; L0 < PageTable.Length; L0++)
{
if (PageTable[L0] == null)
{
continue;
}
for (int L1 = 0; L1 < PageTable[L0].Length; L1++)
{
Size += PageTable[L0][L1].Map != PTMap.Unmapped ? PageSize : 0;
}
}
return Size;
}
public bool SetHeapAddr(long Position)
{
if (!IsHeapInitialized)
{
HeapAddr = Position;
IsHeapInitialized = true;
return true;
}
return false;
}
public void SetHeapSize(long Size, int Type)
{
//TODO: Return error when theres no enough space to allocate heap.
Size = AMemoryHelper.PageRoundUp(Size);
long Position = HeapAddr;
if ((ulong)Size < (ulong)HeapSize)
{
//Try to free now free area if size is smaller than old size.
Position += Size;
while ((ulong)Size < (ulong)HeapSize)
{
Allocator.Free(Position);
Position += PageSize;
}
}
else
{
//Allocate extra needed size.
Position += HeapSize;
Size -= HeapSize;
MapPhys(Position, Size, Type, AMemoryPerm.RW);
}
HeapSize = Size;
}
public void MapPhys(long Position, long Size, int Type, AMemoryPerm Perm)
{
while (Size > 0)
{
if (!IsMapped(Position))
{
SetPTEntry(Position, new PTEntry(PTMap.Mapped, Perm, Type, 0));
}
long CPgSize = PageSize - (Position & PageMask);
Position += CPgSize;
Size -= CPgSize;
}
}
public void MapMirror(long Src, long Dst, long Size, int Type)
{
Src = AMemoryHelper.PageRoundDown(Src);
Dst = AMemoryHelper.PageRoundDown(Dst);
Size = AMemoryHelper.PageRoundUp(Size);
long PagesCount = Size / PageSize;
while (PagesCount-- > 0)
{
PTEntry SrcEntry = GetPTEntry(Src);
PTEntry DstEntry = GetPTEntry(Dst);
DstEntry.Map = PTMap.Mapped;
DstEntry.Type = Type;
DstEntry.Perm = SrcEntry.Perm;
SrcEntry.Perm = AMemoryPerm.None;
SrcEntry.Attr |= 1;
SetPTEntry(Src, SrcEntry);
SetPTEntry(Dst, DstEntry);
Src += PageSize;
Dst += PageSize;
}
}
public void Reprotect(long Position, long Size, AMemoryPerm Perm)
{
Position = AMemoryHelper.PageRoundDown(Position);
Size = AMemoryHelper.PageRoundUp(Size);
long PagesCount = Size / PageSize;
while (PagesCount-- > 0)
{
PTEntry Entry = GetPTEntry(Position);
Entry.Perm = Perm;
SetPTEntry(Position, Entry);
Position += PageSize;
}
}
public AMemoryMapInfo GetMapInfo(long Position)
{
Position = AMemoryHelper.PageRoundDown(Position);
PTEntry BaseEntry = GetPTEntry(Position);
bool IsSameSegment(long Pos)
{
PTEntry Entry = GetPTEntry(Pos);
return Entry.Map == BaseEntry.Map &&
Entry.Perm == BaseEntry.Perm &&
Entry.Type == BaseEntry.Type &&
Entry.Attr == BaseEntry.Attr;
}
long Start = Position;
long End = Position + PageSize;
while (Start > 0 && IsSameSegment(Start - PageSize))
{
Start -= PageSize;
}
while (End < AddrSize && IsSameSegment(End))
{
End += PageSize;
}
long Size = End - Start;
return new AMemoryMapInfo(
Start,
Size,
BaseEntry.Type,
BaseEntry.Attr,
BaseEntry.Perm);
}
public bool HasPermission(long Position, AMemoryPerm Perm)
{
return GetPTEntry(Position).Perm.HasFlag(Perm);
}
public bool IsMapped(long Position)
{
if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0)
{
return false;
}
long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
if (PageTable[L0] == null)
{
return false;
}
return PageTable[L0][L1].Map != PTMap.Unmapped;
}
private PTEntry GetPTEntry(long Position)
{
long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
if (PageTable[L0] == null)
{
return default(PTEntry);
}
return PageTable[L0][L1];
}
private void SetPTEntry(long Position, PTEntry Entry)
{
long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
if (PageTable[L0] == null)
{
PageTable[L0] = new PTEntry[PTLvl1Size];
}
PageTable[L0][L1] = Entry;
}
}
}

View file

@ -0,0 +1,15 @@
using System;
namespace ChocolArm64.Memory
{
[Flags]
public enum AMemoryPerm
{
None = 0,
Read = 1 << 0,
Write = 1 << 1,
Execute = 1 << 2,
RW = Read | Write,
RX = Read | Execute
}
}