Change SvcGetInfo 5 to return actual heap size, remove AMemoryAlloc since it is no longer needed with direct memory access, move some memory management logic out of AMemoryMgr, change default virtual filesystem path to AppData

This commit is contained in:
gdkchan 2018-02-27 20:45:07 -03:00
parent 1cb0bbe585
commit 22fa2f77c6
4 changed files with 73 additions and 166 deletions

View file

@ -41,9 +41,9 @@ namespace ChocolArm64.Memory
private byte* RamPtr; private byte* RamPtr;
public AMemory(IntPtr Ram, AMemoryAlloc Allocator) public AMemory(IntPtr Ram)
{ {
Manager = new AMemoryMgr(Allocator); Manager = new AMemoryMgr();
Monitors = new Dictionary<int, ExMonitor>(); Monitors = new Dictionary<int, ExMonitor>();

View file

@ -1,35 +0,0 @@
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

@ -1,6 +1,6 @@
namespace ChocolArm64.Memory namespace ChocolArm64.Memory
{ {
public struct AMemoryMapInfo public class AMemoryMapInfo
{ {
public long Position { get; private set; } public long Position { get; private set; }
public long Size { get; private set; } public long Size { get; private set; }

View file

@ -1,3 +1,5 @@
using System;
namespace ChocolArm64.Memory namespace ChocolArm64.Memory
{ {
public class AMemoryMgr public class AMemoryMgr
@ -5,22 +7,20 @@ namespace ChocolArm64.Memory
public const long AddrSize = RamSize; public const long AddrSize = RamSize;
public const long RamSize = 4L * 1024 * 1024 * 1024; public const long RamSize = 4L * 1024 * 1024 * 1024;
private const int PTLvl0Bits = 11; private const int PTLvl0Bits = 10;
private const int PTLvl1Bits = 13; private const int PTLvl1Bits = 10;
private const int PTPageBits = 12; private const int PTPageBits = 12;
private const int PTLvl0Size = 1 << PTLvl0Bits; private const int PTLvl0Size = 1 << PTLvl0Bits;
private const int PTLvl1Size = 1 << PTLvl1Bits; private const int PTLvl1Size = 1 << PTLvl1Bits;
public const int PageSize = 1 << PTPageBits; public const int PageSize = 1 << PTPageBits;
private const int PTLvl0Mask = PTLvl0Size - 1; private const int PTLvl0Mask = PTLvl0Size - 1;
private const int PTLvl1Mask = PTLvl1Size - 1; private const int PTLvl1Mask = PTLvl1Size - 1;
public const int PageMask = PageSize - 1; public const int PageMask = PageSize - 1;
private const int PTLvl0Bit = PTPageBits + PTLvl0Bits; private const int PTLvl0Bit = PTPageBits + PTLvl1Bits;
private const int PTLvl1Bit = PTPageBits; private const int PTLvl1Bit = PTPageBits;
private AMemoryAlloc Allocator;
private enum PTMap private enum PTMap
{ {
@ -47,132 +47,24 @@ namespace ChocolArm64.Memory
private PTEntry[][] PageTable; private PTEntry[][] PageTable;
private bool IsHeapInitialized; public AMemoryMgr()
public long HeapAddr { get; private set; }
public long HeapSize { get; private set; }
public AMemoryMgr(AMemoryAlloc Allocator)
{ {
this.Allocator = Allocator;
PageTable = new PTEntry[PTLvl0Size][]; PageTable = new PTEntry[PTLvl0Size][];
} }
public long GetTotalMemorySize() public void Map(long Position, long Size, int Type, AMemoryPerm Perm)
{ {
return Allocator.GetFreeMem() + GetUsedMemorySize(); SetPTEntry(Position, Size, new PTEntry(PTMap.Mapped, Perm, Type, 0));
} }
public long GetUsedMemorySize() public void Unmap(long Position, long Size)
{ {
long Size = 0; SetPTEntry(Position, Size, new PTEntry(PTMap.Unmapped, 0, 0, 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) public void Unmap(long Position, long Size, int Type)
{ {
if (!IsHeapInitialized) SetPTEntry(Position, Size, Type, new PTEntry(PTMap.Unmapped, 0, 0, 0));
{
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) public void Reprotect(long Position, long Size, AMemoryPerm Perm)
@ -197,12 +89,22 @@ namespace ChocolArm64.Memory
public AMemoryMapInfo GetMapInfo(long Position) public AMemoryMapInfo GetMapInfo(long Position)
{ {
if (!IsValidPosition(Position))
{
return null;
}
Position = AMemoryHelper.PageRoundDown(Position); Position = AMemoryHelper.PageRoundDown(Position);
PTEntry BaseEntry = GetPTEntry(Position); PTEntry BaseEntry = GetPTEntry(Position);
bool IsSameSegment(long Pos) bool IsSameSegment(long Pos)
{ {
if (!IsValidPosition(Pos))
{
return false;
}
PTEntry Entry = GetPTEntry(Pos); PTEntry Entry = GetPTEntry(Pos);
return Entry.Map == BaseEntry.Map && return Entry.Map == BaseEntry.Map &&
@ -269,6 +171,16 @@ namespace ChocolArm64.Memory
return GetPTEntry(Position).Perm.HasFlag(Perm); return GetPTEntry(Position).Perm.HasFlag(Perm);
} }
public bool IsValidPosition(long Position)
{
if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0)
{
return false;
}
return true;
}
public bool IsMapped(long Position) public bool IsMapped(long Position)
{ {
if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0) if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0)
@ -300,8 +212,38 @@ namespace ChocolArm64.Memory
return PageTable[L0][L1]; return PageTable[L0][L1];
} }
private void SetPTEntry(long Position, long Size, PTEntry Entry)
{
while (Size > 0)
{
SetPTEntry(Position, Entry);
Position += PageSize;
Size -= PageSize;
}
}
private void SetPTEntry(long Position, long Size, int Type, PTEntry Entry)
{
while (Size > 0)
{
if (GetPTEntry(Position).Type == Type)
{
SetPTEntry(Position, Entry);
}
Position += PageSize;
Size -= PageSize;
}
}
private void SetPTEntry(long Position, PTEntry Entry) private void SetPTEntry(long Position, PTEntry Entry)
{ {
if (!IsValidPosition(Position))
{
throw new ArgumentOutOfRangeException(nameof(Position));
}
long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;