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