| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- 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;
- }
- }
- }
|