1 from gdb import Type, Value, lookup_type
2 from . import KernelStruct
3 from ..arch import PageTableHelper as TLB
5 class PageTableEntry(KernelStruct):
6 def __init__(self, ptep, level, pte=None) -> None:
8 self.base_page_order = TLB.translation_shift_bits(-1)
11 super().__init__(Value(ptep), PageTableEntry)
17 self.va = PageTable.va_at(ptep, level)
19 self.pte = int(self._kstruct['val'])
23 self.pa = TLB.physical_pfn(self.pte) << self.base_page_order
25 self.page_order = TLB.translation_shift_bits(self.level)
26 self.page_size = 1 << self.page_order
27 self.page_order -= self.base_page_order
30 def from_pteval(pte_val, level):
31 return PageTableEntry(0, level, pte=pte_val)
33 def print_abstract(self, pp, *args):
34 self.print_detailed(pp, *args)
36 def print_simple(self, pp, *args):
37 self.print_detailed(pp, *args)
39 def print_detailed(self, pp, *args):
41 pp.print("<Mapping not exists>")
44 pp.printf("Level %d Translation", TLB.translation_level(self.level))
47 pp2.printf("PTE raw value: 0x%016x", self.pte)
50 pp2.printf("Virtual address: <n/a> (ptep=<n/a>)")
52 pp2.printf("Virtual address: 0x%016x (ptep=0x%016x)", self.va, int(self._kstruct))
54 pp2.printf("Mapped physical: 0x%016x (order %d page)", self.pa, self.page_order)
55 pp2.printf("Page Protection: %s", self.get_page_prot())
56 pp2.printf("Present: %s", self.present())
57 pp2.printf("Huge: %s", TLB.huge_page(self.pte, self.page_order))
58 pp2.print("Attributes:")
59 pp2.next_level().print(self.get_attributes())
62 return TLB.huge_page(self.pte, self.page_order) or not self.page_order
65 def get_type() -> Type:
66 return lookup_type("pte_t").pointer()
68 def get_page_mask(self):
69 return PageTableEntry.get_level_shift(self.level) - 1
72 return TLB.mapping_present(self.pte)
74 def get_page_prot(self):
75 return ''.join(TLB.protections(self.pte))
77 def get_attributes(self):
78 attrs = [ self.get_page_prot(),
79 *TLB.other_attributes(self.level, self.pte),
80 "leaf" if self.leaf() else "root" ]
81 return ', '.join(attrs)
84 return TLB.null_mapping(self.pte)
86 def same_kind_to(self, pte2):
87 return TLB.same_kind(self.pte, pte2.pte)
90 def get_level_shift(level):
91 return 1 << TLB.translation_shift_bits(level)
95 return 1 << (TLB.vaddr_width() - TLB.translation_shift_bits(-1))
98 return (self.ptep & (((1 << TLB.translation_shift_bits(0)) - 1))) // TLB.pte_size()
101 return (self.ptep & (((1 << TLB.translation_shift_bits(-1)) - 1))) // TLB.pte_size()
104 def __init__(self) -> None:
109 pfn_mask = ((1 << TLB.translation_shift_bits(0)) - 1)
110 return ((ptep & pfn_mask) // TLB.pte_size())
114 vfn_mask = ((1 << TLB.translation_shift_bits(-1)) - 1)
115 return ((ptep & vfn_mask) // TLB.pte_size())
118 def mkptep_for(mnt, va):
119 mnt_mask = ~((1 << TLB.translation_shift_bits(0)) - 1)
120 offset = (TLB.physical_pfn(va) * TLB.pte_size()) & ~mnt_mask
122 return (mnt & mnt_mask) | offset
125 def ptep_infer_level(ptep):
127 pfn = PageTable.get_pfn(ptep)
128 pfn = pfn << TLB.translation_shift_bits(-1)
129 vfn = (TLB.pgtable_len() - 1)
130 msk = vfn << TLB.translation_shift_bits(l)
131 max_l = TLB.translation_level()
135 while (pfn & msk) == msk:
137 msk = vfn << TLB.translation_shift_bits(l)
141 return (max_l - l, mnt)
144 def va_at(ptep, level):
145 vms_mask = ((1 << TLB.vaddr_width()) - 1)
147 ptep = PageTable.get_pfn(ptep) << TLB.translation_shift_bits(level)
148 return ptep & vms_mask
152 return PageTable.get_lntep(ptep, 0)
155 def get_lntep(ptep, level):
156 lnmask = (1 << TLB.translation_shift_bits(level)) - 1
157 size = (1 << TLB.translation_shift_bits(-1))
158 vpfn = (lnmask * size) & lnmask
159 offset = ((ptep // TLB.pte_size()) * size // (lnmask + 1)) & (size - 1)
161 return (ptep & ~lnmask) | vpfn | (offset * TLB.pte_size())
164 def mkptep_at(mnt, va, level):
165 lfmask = (1 << TLB.translation_shift_bits(-1)) - 1
166 lsize = (1 << TLB.translation_shift_bits(level))
167 offset = (va // lsize) * TLB.pte_size()
169 return mnt | ((lsize - 1) & ~lfmask) | offset
172 def shift_ptep_nextlevel(ptep):
173 mnt_mask = ~((1 << TLB.translation_shift_bits(0)) - 1)
174 size = (1 << TLB.translation_shift_bits(-1))
175 mnt = ptep & mnt_mask
176 vpfn = ((ptep // TLB.pte_size()) * size) & ~mnt_mask
181 def shift_ptep_prevlevel(ptep):
182 mnt_mask = ~((1 << TLB.translation_shift_bits(0)) - 1)
183 self_mnt = (TLB.pgtable_len() - 1) * (~mnt_mask + 1)
184 unshifted = PageTable.get_pfn(ptep) << TLB.translation_shift_bits(-1)
185 unshifted = PageTable.mkptep_for(self_mnt, unshifted)
186 return PageTable.mkptep_for(ptep & mnt_mask, unshifted)
188 def __print_pte_ranged(self, pp, pte_head, pte_tail):
189 start_va = pte_head.va
191 if pte_head == pte_tail:
192 end_va = pte_head.va + pte_head.page_size
196 sz = end_va - start_va
197 if not pte_head.null():
198 pp.printf("0x%016x...0x%016x, 0x%016x [0x%08x] %s",
199 start_va, end_va - 1, pte_head.pa, sz,
200 pte_head.get_attributes())
202 pp.printfa("0x{:016x}...0x{:016x}, {:^18s} [0x{:08x}] <no mapping>",
203 start_va, end_va - 1, "n/a", sz)
205 def __scan_pagetable(self, pp, start_ptep, end_ptep, max_level = -1):
206 ptep = PageTable.get_l0tep(start_ptep)
208 max_level = TLB.translation_level(max_level)
209 va_end = PageTable.va_at(end_ptep, -1) + 1
213 pp.printfa("{:^18s} {:^18s} {:^18s} {:^10s} {:^20s}",
214 "va-start", "va-end", "physical", "size", "attributes")
215 while PageTable.va_at(ptep, level) <= va_end:
216 pte = PageTableEntry(ptep, level)
222 if not head_pte.null():
223 self.__print_pte_ranged(pp, head_pte, prev_pte)
225 elif not pte.leaf() and level < max_level:
226 ptep = PageTable.shift_ptep_nextlevel(ptep)
231 self.__print_pte_ranged(pp, head_pte, prev_pte)
234 n = pte.pfn() - head_pte.pfn()
235 pa = head_pte.pa + (n << pte.base_page_order)
236 if pa != pte.pa or not pte.same_kind_to(head_pte):
237 self.__print_pte_ranged(pp, head_pte, prev_pte)
241 if pte.vfn() == TLB.pgtable_len() - 1:
243 ptep = PageTable.shift_ptep_prevlevel(ptep + TLB.pte_size())
248 ptep += TLB.pte_size()
251 self.__print_pte_ranged(pp, head_pte, prev_pte)
253 def print_ptes_between(self, pp, va, va_end, level=-1, mnt=0xFFC00000):
254 ptep_start = PageTable.mkptep_for(mnt, va)
255 ptep_end = PageTable.mkptep_for(mnt, va_end)
256 self.__scan_pagetable(pp, ptep_start, ptep_end, level)
258 def get_pte(self, va, level=-1, mnt=0xFFC00000) -> PageTableEntry:
259 ptep = PageTable.mkptep_at(mnt, va, level)
260 return PageTableEntry(ptep, level)
262 def print_ptes(self, pp, va, pte_num, level=-1, mnt=0xFFC00000):
263 ptep_start = PageTable.mkptep_for(mnt, va)
264 ptep_end = ptep_start + pte_num * TLB.pte_size()
265 self.__scan_pagetable(pp, ptep_start, ptep_end, level)