PageTable.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. namespace Ryujinx.Memory
  2. {
  3. public class PageTable<T> where T : unmanaged
  4. {
  5. public const int PageBits = 12;
  6. public const int PageSize = 1 << PageBits;
  7. public const int PageMask = PageSize - 1;
  8. private const int PtLevelBits = 9; // 9 * 4 + 12 = 48 (max address space size)
  9. private const int PtLevelSize = 1 << PtLevelBits;
  10. private const int PtLevelMask = PtLevelSize - 1;
  11. private readonly T[][][][] _pageTable;
  12. public PageTable()
  13. {
  14. _pageTable = new T[PtLevelSize][][][];
  15. }
  16. public T Read(ulong va)
  17. {
  18. int l3 = (int)(va >> PageBits) & PtLevelMask;
  19. int l2 = (int)(va >> (PageBits + PtLevelBits)) & PtLevelMask;
  20. int l1 = (int)(va >> (PageBits + PtLevelBits * 2)) & PtLevelMask;
  21. int l0 = (int)(va >> (PageBits + PtLevelBits * 3)) & PtLevelMask;
  22. if (_pageTable[l0] == null)
  23. {
  24. return default;
  25. }
  26. if (_pageTable[l0][l1] == null)
  27. {
  28. return default;
  29. }
  30. if (_pageTable[l0][l1][l2] == null)
  31. {
  32. return default;
  33. }
  34. return _pageTable[l0][l1][l2][l3];
  35. }
  36. public void Map(ulong va, T value)
  37. {
  38. int l3 = (int)(va >> PageBits) & PtLevelMask;
  39. int l2 = (int)(va >> (PageBits + PtLevelBits)) & PtLevelMask;
  40. int l1 = (int)(va >> (PageBits + PtLevelBits * 2)) & PtLevelMask;
  41. int l0 = (int)(va >> (PageBits + PtLevelBits * 3)) & PtLevelMask;
  42. if (_pageTable[l0] == null)
  43. {
  44. _pageTable[l0] = new T[PtLevelSize][][];
  45. }
  46. if (_pageTable[l0][l1] == null)
  47. {
  48. _pageTable[l0][l1] = new T[PtLevelSize][];
  49. }
  50. if (_pageTable[l0][l1][l2] == null)
  51. {
  52. _pageTable[l0][l1][l2] = new T[PtLevelSize];
  53. }
  54. _pageTable[l0][l1][l2][l3] = value;
  55. }
  56. public void Unmap(ulong va)
  57. {
  58. int l3 = (int)(va >> PageBits) & PtLevelMask;
  59. int l2 = (int)(va >> (PageBits + PtLevelBits)) & PtLevelMask;
  60. int l1 = (int)(va >> (PageBits + PtLevelBits * 2)) & PtLevelMask;
  61. int l0 = (int)(va >> (PageBits + PtLevelBits * 3)) & PtLevelMask;
  62. if (_pageTable[l0] == null)
  63. {
  64. return;
  65. }
  66. if (_pageTable[l0][l1] == null)
  67. {
  68. return;
  69. }
  70. if (_pageTable[l0][l1][l2] == null)
  71. {
  72. return;
  73. }
  74. _pageTable[l0][l1][l2][l3] = default;
  75. bool empty = true;
  76. for (int i = 0; i < _pageTable[l0][l1][l2].Length; i++)
  77. {
  78. empty &= _pageTable[l0][l1][l2][i].Equals(default);
  79. }
  80. if (empty)
  81. {
  82. _pageTable[l0][l1][l2] = null;
  83. RemoveIfAllNull(l0, l1);
  84. }
  85. }
  86. private void RemoveIfAllNull(int l0, int l1)
  87. {
  88. bool empty = true;
  89. for (int i = 0; i < _pageTable[l0][l1].Length; i++)
  90. {
  91. empty &= (_pageTable[l0][l1][i] == null);
  92. }
  93. if (empty)
  94. {
  95. _pageTable[l0][l1] = null;
  96. RemoveIfAllNull(l0);
  97. }
  98. }
  99. private void RemoveIfAllNull(int l0)
  100. {
  101. bool empty = true;
  102. for (int i = 0; i < _pageTable[l0].Length; i++)
  103. {
  104. empty &= (_pageTable[l0][i] == null);
  105. }
  106. if (empty)
  107. {
  108. _pageTable[l0] = null;
  109. }
  110. }
  111. }
  112. }