/ src / Ryujinx.Memory / PageTable.cs
PageTable.cs
  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  
  9          private const int PtLevelBits = 9; // 9 * 4 + 12 = 48 (max address space size)
 10          private const int PtLevelSize = 1 << PtLevelBits;
 11          private const int PtLevelMask = PtLevelSize - 1;
 12  
 13          private readonly T[][][][] _pageTable;
 14  
 15          public PageTable()
 16          {
 17              _pageTable = new T[PtLevelSize][][][];
 18          }
 19  
 20          public T Read(ulong va)
 21          {
 22              int l3 = (int)(va >> PageBits) & PtLevelMask;
 23              int l2 = (int)(va >> (PageBits + PtLevelBits)) & PtLevelMask;
 24              int l1 = (int)(va >> (PageBits + PtLevelBits * 2)) & PtLevelMask;
 25              int l0 = (int)(va >> (PageBits + PtLevelBits * 3)) & PtLevelMask;
 26  
 27              if (_pageTable[l0] == null)
 28              {
 29                  return default;
 30              }
 31  
 32              if (_pageTable[l0][l1] == null)
 33              {
 34                  return default;
 35              }
 36  
 37              if (_pageTable[l0][l1][l2] == null)
 38              {
 39                  return default;
 40              }
 41  
 42              return _pageTable[l0][l1][l2][l3];
 43          }
 44  
 45          public void Map(ulong va, T value)
 46          {
 47              int l3 = (int)(va >> PageBits) & PtLevelMask;
 48              int l2 = (int)(va >> (PageBits + PtLevelBits)) & PtLevelMask;
 49              int l1 = (int)(va >> (PageBits + PtLevelBits * 2)) & PtLevelMask;
 50              int l0 = (int)(va >> (PageBits + PtLevelBits * 3)) & PtLevelMask;
 51  
 52              if (_pageTable[l0] == null)
 53              {
 54                  _pageTable[l0] = new T[PtLevelSize][][];
 55              }
 56  
 57              if (_pageTable[l0][l1] == null)
 58              {
 59                  _pageTable[l0][l1] = new T[PtLevelSize][];
 60              }
 61  
 62              if (_pageTable[l0][l1][l2] == null)
 63              {
 64                  _pageTable[l0][l1][l2] = new T[PtLevelSize];
 65              }
 66  
 67              _pageTable[l0][l1][l2][l3] = value;
 68          }
 69  
 70          public void Unmap(ulong va)
 71          {
 72              int l3 = (int)(va >> PageBits) & PtLevelMask;
 73              int l2 = (int)(va >> (PageBits + PtLevelBits)) & PtLevelMask;
 74              int l1 = (int)(va >> (PageBits + PtLevelBits * 2)) & PtLevelMask;
 75              int l0 = (int)(va >> (PageBits + PtLevelBits * 3)) & PtLevelMask;
 76  
 77              if (_pageTable[l0] == null)
 78              {
 79                  return;
 80              }
 81  
 82              if (_pageTable[l0][l1] == null)
 83              {
 84                  return;
 85              }
 86  
 87              if (_pageTable[l0][l1][l2] == null)
 88              {
 89                  return;
 90              }
 91  
 92              _pageTable[l0][l1][l2][l3] = default;
 93  
 94              bool empty = true;
 95  
 96              for (int i = 0; i < _pageTable[l0][l1][l2].Length; i++)
 97              {
 98                  empty &= _pageTable[l0][l1][l2][i].Equals(default);
 99              }
100  
101              if (empty)
102              {
103                  _pageTable[l0][l1][l2] = null;
104  
105                  RemoveIfAllNull(l0, l1);
106              }
107          }
108  
109          private void RemoveIfAllNull(int l0, int l1)
110          {
111              bool empty = true;
112  
113              for (int i = 0; i < _pageTable[l0][l1].Length; i++)
114              {
115                  empty &= (_pageTable[l0][l1][i] == null);
116              }
117  
118              if (empty)
119              {
120                  _pageTable[l0][l1] = null;
121  
122                  RemoveIfAllNull(l0);
123              }
124          }
125  
126          private void RemoveIfAllNull(int l0)
127          {
128              bool empty = true;
129  
130              for (int i = 0; i < _pageTable[l0].Length; i++)
131              {
132                  empty &= (_pageTable[l0][i] == null);
133              }
134  
135              if (empty)
136              {
137                  _pageTable[l0] = null;
138              }
139          }
140      }
141  }