| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- namespace Ryujinx.Memory
- {
- public class PageTable<T> where T : unmanaged
- {
- public const int PageBits = 12;
- public const int PageSize = 1 << PageBits;
- public const int PageMask = PageSize - 1;
- private const int PtLevelBits = 9; // 9 * 4 + 12 = 48 (max address space size)
- private const int PtLevelSize = 1 << PtLevelBits;
- private const int PtLevelMask = PtLevelSize - 1;
- private readonly T[][][][] _pageTable;
- public PageTable()
- {
- _pageTable = new T[PtLevelSize][][][];
- }
- public T Read(ulong va)
- {
- int l3 = (int)(va >> PageBits) & PtLevelMask;
- int l2 = (int)(va >> (PageBits + PtLevelBits)) & PtLevelMask;
- int l1 = (int)(va >> (PageBits + PtLevelBits * 2)) & PtLevelMask;
- int l0 = (int)(va >> (PageBits + PtLevelBits * 3)) & PtLevelMask;
- if (_pageTable[l0] == null)
- {
- return default;
- }
- if (_pageTable[l0][l1] == null)
- {
- return default;
- }
- if (_pageTable[l0][l1][l2] == null)
- {
- return default;
- }
- return _pageTable[l0][l1][l2][l3];
- }
- public void Map(ulong va, T value)
- {
- int l3 = (int)(va >> PageBits) & PtLevelMask;
- int l2 = (int)(va >> (PageBits + PtLevelBits)) & PtLevelMask;
- int l1 = (int)(va >> (PageBits + PtLevelBits * 2)) & PtLevelMask;
- int l0 = (int)(va >> (PageBits + PtLevelBits * 3)) & PtLevelMask;
- if (_pageTable[l0] == null)
- {
- _pageTable[l0] = new T[PtLevelSize][][];
- }
- if (_pageTable[l0][l1] == null)
- {
- _pageTable[l0][l1] = new T[PtLevelSize][];
- }
- if (_pageTable[l0][l1][l2] == null)
- {
- _pageTable[l0][l1][l2] = new T[PtLevelSize];
- }
- _pageTable[l0][l1][l2][l3] = value;
- }
- public void Unmap(ulong va)
- {
- int l3 = (int)(va >> PageBits) & PtLevelMask;
- int l2 = (int)(va >> (PageBits + PtLevelBits)) & PtLevelMask;
- int l1 = (int)(va >> (PageBits + PtLevelBits * 2)) & PtLevelMask;
- int l0 = (int)(va >> (PageBits + PtLevelBits * 3)) & PtLevelMask;
- if (_pageTable[l0] == null)
- {
- return;
- }
- if (_pageTable[l0][l1] == null)
- {
- return;
- }
- if (_pageTable[l0][l1][l2] == null)
- {
- return;
- }
- _pageTable[l0][l1][l2][l3] = default;
- bool empty = true;
- for (int i = 0; i < _pageTable[l0][l1][l2].Length; i++)
- {
- empty &= _pageTable[l0][l1][l2][i].Equals(default);
- }
- if (empty)
- {
- _pageTable[l0][l1][l2] = null;
- RemoveIfAllNull(l0, l1);
- }
- }
- private void RemoveIfAllNull(int l0, int l1)
- {
- bool empty = true;
- for (int i = 0; i < _pageTable[l0][l1].Length; i++)
- {
- empty &= (_pageTable[l0][l1][i] == null);
- }
- if (empty)
- {
- _pageTable[l0][l1] = null;
- RemoveIfAllNull(l0);
- }
- }
- private void RemoveIfAllNull(int l0)
- {
- bool empty = true;
- for (int i = 0; i < _pageTable[l0].Length; i++)
- {
- empty &= (_pageTable[l0][i] == null);
- }
- if (empty)
- {
- _pageTable[l0] = null;
- }
- }
- }
- }
|