X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/b60166b327a9108b07e3069fa6568a451529ffd9..270869139db617e29a35bb9ded41087bb702f9ac:/lunaix-os/scripts/gdb/lunadbg/structs/pagetable.py diff --git a/lunaix-os/scripts/gdb/lunadbg/structs/pagetable.py b/lunaix-os/scripts/gdb/lunadbg/structs/pagetable.py index 1ffc062..58ed0c8 100644 --- a/lunaix-os/scripts/gdb/lunadbg/structs/pagetable.py +++ b/lunaix-os/scripts/gdb/lunadbg/structs/pagetable.py @@ -3,22 +3,33 @@ from . import KernelStruct from ..arch import PageTableHelper as TLB class PageTableEntry(KernelStruct): - def __init__(self, gdb_inferior: Value, level, va) -> None: + def __init__(self, ptep, level, pte=None) -> None: self.level = level - self.pg_mask = self.get_page_mask() - self.va = va & ~self.pg_mask self.base_page_order = TLB.translation_shift_bits(-1) + self.ptep = ptep - ptep = gdb_inferior[va // (self.pg_mask + 1)].address - super().__init__(ptep, PageTableEntry) - - try: - self.pte = int(self._kstruct.dereference()) - except: - self.pte = 0 + super().__init__(Value(ptep), PageTableEntry) + + if pte: + self.pte = pte + self.va = None + else: + self.va = PageTable.va_at(ptep, level) + try: + self.pte = int(self._kstruct['val']) + except: + self.pte = 0 self.pa = TLB.physical_pfn(self.pte) << self.base_page_order + self.page_order = TLB.translation_shift_bits(self.level) + self.page_size = 1 << self.page_order + self.page_order -= self.base_page_order + + @staticmethod + def from_pteval(pte_val, level): + return PageTableEntry(0, level, pte=pte_val) + def print_abstract(self, pp, *args): self.print_detailed(pp, *args) @@ -30,24 +41,29 @@ class PageTableEntry(KernelStruct): pp.print("") return - page_order = TLB.translation_shift_bits(self.level) - page_order -= self.base_page_order - pp.printf("Level %d Translation", TLB.translation_level(self.level)) pp2 = pp.next_level() - pp2.printf("Entry value: 0x%x", self.pte) - pp2.printf("Virtual address: 0x%x (ptep=0x%x)", self.va, int(self._kstruct)) - pp2.printf("Mapped physical: 0x%x (order %d page)", self.pa, page_order) + pp2.printf("PTE raw value: 0x%016x", self.pte) + + if not self.va: + pp2.printf("Virtual address: (ptep=)") + else: + pp2.printf("Virtual address: 0x%016x (ptep=0x%016x)", self.va, int(self._kstruct)) + + pp2.printf("Mapped physical: 0x%016x (order %d page)", self.pa, self.page_order) pp2.printf("Page Protection: %s", self.get_page_prot()) pp2.printf("Present: %s", self.present()) - pp2.printf("Huge: %s", TLB.huge_page(self.pte)) + pp2.printf("Huge: %s", TLB.huge_page(self.pte, self.page_order)) pp2.print("Attributes:") pp2.next_level().print(self.get_attributes()) + + def leaf(self): + return TLB.huge_page(self.pte, self.page_order) or not self.page_order @staticmethod def get_type() -> Type: - return lookup_type("unsigned int").pointer() + return lookup_type("pte_t").pointer() def get_page_mask(self): return PageTableEntry.get_level_shift(self.level) - 1 @@ -60,7 +76,8 @@ class PageTableEntry(KernelStruct): def get_attributes(self): attrs = [ self.get_page_prot(), - *TLB.other_attributes(self.level, self.pte) ] + *TLB.other_attributes(self.level, self.pte), + "leaf" if self.leaf() else "root" ] return ', '.join(attrs) def null(self): @@ -76,22 +93,108 @@ class PageTableEntry(KernelStruct): @staticmethod def max_page_count(): return 1 << (TLB.vaddr_width() - TLB.translation_shift_bits(-1)) + + def pfn(self): + return (self.ptep & (((1 << TLB.translation_shift_bits(0)) - 1))) // TLB.pte_size() + + def vfn(self): + return (self.ptep & (((1 << TLB.translation_shift_bits(-1)) - 1))) // TLB.pte_size() class PageTable(): def __init__(self) -> None: - self.levels = [ - Value(0xFFFFF000).cast(PageTableEntry.get_type()), - Value(0xFFC00000).cast(PageTableEntry.get_type()) - ] + pass - def get_pte(self, va, level=-1) -> PageTableEntry: - return PageTableEntry(self.levels[level], level, va) + @staticmethod + def get_pfn(ptep): + pfn_mask = ((1 << TLB.translation_shift_bits(0)) - 1) + return ((ptep & pfn_mask) // TLB.pte_size()) + + @staticmethod + def get_vfn(ptep): + vfn_mask = ((1 << TLB.translation_shift_bits(-1)) - 1) + return ((ptep & vfn_mask) // TLB.pte_size()) + + @staticmethod + def mkptep_for(mnt, va): + mnt_mask = ~((1 << TLB.translation_shift_bits(0)) - 1) + offset = (TLB.physical_pfn(va) * TLB.pte_size()) & ~mnt_mask + + return (mnt & mnt_mask) | offset + + @staticmethod + def ptep_infer_level(ptep): + l = 0 + pfn = PageTable.get_pfn(ptep) + pfn = pfn << TLB.translation_shift_bits(-1) + vfn = (TLB.pgtable_len() - 1) + msk = vfn << TLB.translation_shift_bits(l) + max_l = TLB.translation_level() + + mnt = ptep & msk + + while (pfn & msk) == msk: + l+=1 + msk = vfn << TLB.translation_shift_bits(l) + if l == max_l: + break + + return (max_l - l, mnt) + + @staticmethod + def va_at(ptep, level): + vms_mask = ((1 << TLB.vaddr_width()) - 1) + + ptep = PageTable.get_pfn(ptep) << TLB.translation_shift_bits(level) + return ptep & vms_mask + + @staticmethod + def get_l0tep(ptep): + return PageTable.get_lntep(ptep, 0) + + @staticmethod + def get_lntep(ptep, level): + lnmask = (1 << TLB.translation_shift_bits(level)) - 1 + size = (1 << TLB.translation_shift_bits(-1)) + vpfn = (lnmask * size) & lnmask + offset = ((ptep // TLB.pte_size()) * size // (lnmask + 1)) & (size - 1) + + return (ptep & ~lnmask) | vpfn | (offset * TLB.pte_size()) + + @staticmethod + def mkptep_at(mnt, va, level): + lfmask = (1 << TLB.translation_shift_bits(-1)) - 1 + lsize = (1 << TLB.translation_shift_bits(level)) + offset = (va // lsize) * TLB.pte_size() + + return mnt | ((lsize - 1) & ~lfmask) | offset + + @staticmethod + def shift_ptep_nextlevel(ptep): + mnt_mask = ~((1 << TLB.translation_shift_bits(0)) - 1) + size = (1 << TLB.translation_shift_bits(-1)) + mnt = ptep & mnt_mask + vpfn = ((ptep // TLB.pte_size()) * size) & ~mnt_mask + + return mnt | vpfn + + @staticmethod + def shift_ptep_prevlevel(ptep): + mnt_mask = ~((1 << TLB.translation_shift_bits(0)) - 1) + self_mnt = (TLB.pgtable_len() - 1) * (~mnt_mask + 1) + unshifted = PageTable.get_pfn(ptep) << TLB.translation_shift_bits(-1) + unshifted = PageTable.mkptep_for(self_mnt, unshifted) + return PageTable.mkptep_for(ptep & mnt_mask, unshifted) def __print_pte_ranged(self, pp, pte_head, pte_tail): start_va = pte_head.va - end_va = pte_tail.va + + if pte_head == pte_tail: + end_va = pte_head.va + pte_head.page_size + else: + end_va = pte_tail.va + sz = end_va - start_va - if not (pte_head.null() and pte_tail.null()): + if not pte_head.null(): pp.printf("0x%016x...0x%016x, 0x%016x [0x%08x] %s", start_va, end_va - 1, pte_head.pa, sz, pte_head.get_attributes()) @@ -99,25 +202,64 @@ class PageTable(): pp.printfa("0x{:016x}...0x{:016x}, {:^18s} [0x{:08x}] ", start_va, end_va - 1, "n/a", sz) - def print_ptes_between(self, pp, va, va_end, level=-1): - shift = PageTableEntry.get_level_shift(level) - n = (va_end - va) // shift - self.print_ptes(pp, va, n, level) - - def print_ptes(self, pp, va, pte_num, level=-1): - head_pte = PageTableEntry(self.levels[level], level, va) - curr_pte = head_pte - va = head_pte.va + def __scan_pagetable(self, pp, start_ptep, end_ptep, max_level = -1): + ptep = PageTable.get_l0tep(start_ptep) + level = 0 + max_level = TLB.translation_level(max_level) + va_end = PageTable.va_at(end_ptep, -1) + 1 + head_pte = None + prev_pte = None pp.printfa("{:^18s} {:^18s} {:^18s} {:^10s} {:^20s}", "va-start", "va-end", "physical", "size", "attributes") - for i in range(1, pte_num): - va_ = va + i * PageTableEntry.get_level_shift(level) - curr_pte = PageTableEntry(self.levels[level], level, va_) + while PageTable.va_at(ptep, level) <= va_end: + pte = PageTableEntry(ptep, level) + if head_pte == None: + head_pte = pte + prev_pte = pte + + if pte.null(): + if not head_pte.null(): + self.__print_pte_ranged(pp, head_pte, prev_pte) + head_pte = pte + elif not pte.leaf() and level < max_level: + ptep = PageTable.shift_ptep_nextlevel(ptep) + level+=1 + continue + else: + if head_pte.null(): + self.__print_pte_ranged(pp, head_pte, prev_pte) + head_pte = pte + else: + n = pte.pfn() - head_pte.pfn() + pa = head_pte.pa + (n << pte.base_page_order) + if pa != pte.pa or not pte.same_kind_to(head_pte): + self.__print_pte_ranged(pp, head_pte, prev_pte) + head_pte = pte + + prev_pte = pte + if pte.vfn() == TLB.pgtable_len() - 1: + if level != 0: + ptep = PageTable.shift_ptep_prevlevel(ptep + TLB.pte_size()) + level-=1 + continue + break - if not curr_pte.same_kind_to(head_pte): - self.__print_pte_ranged(pp, head_pte, curr_pte) - head_pte = curr_pte + ptep += TLB.pte_size() + - if curr_pte != head_pte: - self.__print_pte_ranged(pp, head_pte, curr_pte) \ No newline at end of file + self.__print_pte_ranged(pp, head_pte, prev_pte) + + def print_ptes_between(self, pp, va, va_end, level=-1, mnt=0xFFC00000): + ptep_start = PageTable.mkptep_for(mnt, va) + ptep_end = PageTable.mkptep_for(mnt, va_end) + self.__scan_pagetable(pp, ptep_start, ptep_end, level) + + def get_pte(self, va, level=-1, mnt=0xFFC00000) -> PageTableEntry: + ptep = PageTable.mkptep_at(mnt, va, level) + return PageTableEntry(ptep, level) + + def print_ptes(self, pp, va, pte_num, level=-1, mnt=0xFFC00000): + ptep_start = PageTable.mkptep_for(mnt, va) + ptep_end = ptep_start + pte_num * TLB.pte_size() + self.__scan_pagetable(pp, ptep_start, ptep_end, level) \ No newline at end of file