AMemoryMgr.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. using System;
  2. namespace ChocolArm64.Memory
  3. {
  4. public class AMemoryMgr
  5. {
  6. public const long RamSize = 4L * 1024 * 1024 * 1024;
  7. public const long AddrSize = RamSize;
  8. private const int PTLvl0Bits = 10;
  9. private const int PTLvl1Bits = 10;
  10. private const int PTPageBits = 12;
  11. private const int PTLvl0Size = 1 << PTLvl0Bits;
  12. private const int PTLvl1Size = 1 << PTLvl1Bits;
  13. public const int PageSize = 1 << PTPageBits;
  14. private const int PTLvl0Mask = PTLvl0Size - 1;
  15. private const int PTLvl1Mask = PTLvl1Size - 1;
  16. public const int PageMask = PageSize - 1;
  17. private const int PTLvl0Bit = PTPageBits + PTLvl1Bits;
  18. private const int PTLvl1Bit = PTPageBits;
  19. private enum PTMap
  20. {
  21. Unmapped,
  22. Mapped
  23. }
  24. private struct PTEntry
  25. {
  26. public PTMap Map;
  27. public AMemoryPerm Perm;
  28. public int Type;
  29. public int Attr;
  30. public PTEntry(PTMap Map, AMemoryPerm Perm, int Type, int Attr)
  31. {
  32. this.Map = Map;
  33. this.Perm = Perm;
  34. this.Type = Type;
  35. this.Attr = Attr;
  36. }
  37. }
  38. private PTEntry[][] PageTable;
  39. public AMemoryMgr()
  40. {
  41. PageTable = new PTEntry[PTLvl0Size][];
  42. }
  43. public void Map(long Position, long Size, int Type, AMemoryPerm Perm)
  44. {
  45. SetPTEntry(Position, Size, new PTEntry(PTMap.Mapped, Perm, Type, 0));
  46. }
  47. public void Unmap(long Position, long Size)
  48. {
  49. SetPTEntry(Position, Size, new PTEntry(PTMap.Unmapped, 0, 0, 0));
  50. }
  51. public void Unmap(long Position, long Size, int Type)
  52. {
  53. SetPTEntry(Position, Size, Type, new PTEntry(PTMap.Unmapped, 0, 0, 0));
  54. }
  55. public void Reprotect(long Position, long Size, AMemoryPerm Perm)
  56. {
  57. Position = AMemoryHelper.PageRoundDown(Position);
  58. Size = AMemoryHelper.PageRoundUp(Size);
  59. long PagesCount = Size / PageSize;
  60. while (PagesCount-- > 0)
  61. {
  62. PTEntry Entry = GetPTEntry(Position);
  63. Entry.Perm = Perm;
  64. SetPTEntry(Position, Entry);
  65. Position += PageSize;
  66. }
  67. }
  68. public AMemoryMapInfo GetMapInfo(long Position)
  69. {
  70. if (!IsValidPosition(Position))
  71. {
  72. return null;
  73. }
  74. Position = AMemoryHelper.PageRoundDown(Position);
  75. PTEntry BaseEntry = GetPTEntry(Position);
  76. bool IsSameSegment(long Pos)
  77. {
  78. if (!IsValidPosition(Pos))
  79. {
  80. return false;
  81. }
  82. PTEntry Entry = GetPTEntry(Pos);
  83. return Entry.Map == BaseEntry.Map &&
  84. Entry.Perm == BaseEntry.Perm &&
  85. Entry.Type == BaseEntry.Type &&
  86. Entry.Attr == BaseEntry.Attr;
  87. }
  88. long Start = Position;
  89. long End = Position + PageSize;
  90. while (Start > 0 && IsSameSegment(Start - PageSize))
  91. {
  92. Start -= PageSize;
  93. }
  94. while (End < AddrSize && IsSameSegment(End))
  95. {
  96. End += PageSize;
  97. }
  98. long Size = End - Start;
  99. return new AMemoryMapInfo(
  100. Start,
  101. Size,
  102. BaseEntry.Type,
  103. BaseEntry.Attr,
  104. BaseEntry.Perm);
  105. }
  106. public void ClearAttrBit(long Position, long Size, int Bit)
  107. {
  108. while (Size > 0)
  109. {
  110. PTEntry Entry = GetPTEntry(Position);
  111. Entry.Attr &= ~(1 << Bit);
  112. SetPTEntry(Position, Entry);
  113. Position += PageSize;
  114. Size -= PageSize;
  115. }
  116. }
  117. public void SetAttrBit(long Position, long Size, int Bit)
  118. {
  119. while (Size > 0)
  120. {
  121. PTEntry Entry = GetPTEntry(Position);
  122. Entry.Attr |= (1 << Bit);
  123. SetPTEntry(Position, Entry);
  124. Position += PageSize;
  125. Size -= PageSize;
  126. }
  127. }
  128. public bool HasPermission(long Position, AMemoryPerm Perm)
  129. {
  130. return GetPTEntry(Position).Perm.HasFlag(Perm);
  131. }
  132. public bool IsValidPosition(long Position)
  133. {
  134. if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0)
  135. {
  136. return false;
  137. }
  138. return true;
  139. }
  140. public bool IsMapped(long Position)
  141. {
  142. if (Position >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0)
  143. {
  144. return false;
  145. }
  146. long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
  147. long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
  148. if (PageTable[L0] == null)
  149. {
  150. return false;
  151. }
  152. return PageTable[L0][L1].Map != PTMap.Unmapped;
  153. }
  154. private PTEntry GetPTEntry(long Position)
  155. {
  156. long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
  157. long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
  158. if (PageTable[L0] == null)
  159. {
  160. return default(PTEntry);
  161. }
  162. return PageTable[L0][L1];
  163. }
  164. private void SetPTEntry(long Position, long Size, PTEntry Entry)
  165. {
  166. while (Size > 0)
  167. {
  168. SetPTEntry(Position, Entry);
  169. Position += PageSize;
  170. Size -= PageSize;
  171. }
  172. }
  173. private void SetPTEntry(long Position, long Size, int Type, PTEntry Entry)
  174. {
  175. while (Size > 0)
  176. {
  177. if (GetPTEntry(Position).Type == Type)
  178. {
  179. SetPTEntry(Position, Entry);
  180. }
  181. Position += PageSize;
  182. Size -= PageSize;
  183. }
  184. }
  185. private void SetPTEntry(long Position, PTEntry Entry)
  186. {
  187. if (!IsValidPosition(Position))
  188. {
  189. throw new ArgumentOutOfRangeException(nameof(Position));
  190. }
  191. long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask;
  192. long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask;
  193. if (PageTable[L0] == null)
  194. {
  195. PageTable[L0] = new PTEntry[PTLvl1Size];
  196. }
  197. PageTable[L0][L1] = Entry;
  198. }
  199. }
  200. }