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 }