| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- using System;
- namespace ChocolArm64.Memory
- {
- public class AMemoryMgr
- {
- public const long RamSize = 4L * 1024 * 1024 * 1024;
- public const long AddrSize = RamSize;
- private const int PTLvl0Bits = 10;
- private const int PTLvl1Bits = 10;
- 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 + PTLvl1Bits;
- private const int PTLvl1Bit = PTPageBits;
- 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;
- public AMemoryMgr()
- {
- PageTable = new PTEntry[PTLvl0Size][];
- }
- public void Map(long Position, long Size, int Type, AMemoryPerm Perm)
- {
- SetPTEntry(Position, Size, new PTEntry(PTMap.Mapped, Perm, Type, 0));
- }
- public void Unmap(long Position, long Size)
- {
- SetPTEntry(Position, Size, new PTEntry(PTMap.Unmapped, 0, 0, 0));
- }
- public void Unmap(long Position, long Size, int Type)
- {
- SetPTEntry(Position, Size, Type, new PTEntry(PTMap.Unmapped, 0, 0, 0));
- }
- 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)
- {
- 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 &&
- 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 void ClearAttrBit(long Position, long Size, int Bit)
- {
- while (Size > 0)
- {
- PTEntry Entry = GetPTEntry(Position);
- Entry.Attr &= ~(1 << Bit);
- SetPTEntry(Position, Entry);
- Position += PageSize;
- Size -= PageSize;
- }
- }
- public void SetAttrBit(long Position, long Size, int Bit)
- {
- while (Size > 0)
- {
- PTEntry Entry = GetPTEntry(Position);
- Entry.Attr |= (1 << Bit);
- SetPTEntry(Position, Entry);
- Position += PageSize;
- Size -= PageSize;
- }
- }
- public bool HasPermission(long Position, AMemoryPerm 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)
- {
- 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, 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;
- if (PageTable[L0] == null)
- {
- PageTable[L0] = new PTEntry[PTLvl1Size];
- }
- PageTable[L0][L1] = Entry;
- }
- }
- }
|