Split main project into core,graphics and chocolarm4 subproject (#29)
This commit is contained in:
parent
cb665bb715
commit
62b827f474
257 changed files with 415 additions and 285 deletions
286
ChocolArm64/Memory/AMemoryMgr.cs
Normal file
286
ChocolArm64/Memory/AMemoryMgr.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue