static x86pte_t get_pte(hat_t *hat, htable_t *htable, uintptr_t addr) { x86pte_t buf; if (htable->ht_flags & HTABLE_COPIED) { uintptr_t ptr = (uintptr_t)hat->hat_copied_ptes; ptr += va2entry(htable, addr) << mmu.pte_size_shift; return (*(x86pte_t *)ptr); } paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn); paddr += va2entry(htable, addr) << mmu.pte_size_shift; if ((mdb_pread(&buf, mmu.pte_size, paddr)) == mmu.pte_size) return (buf); return (0); }
static x86pte_t get_pte(hat_t *hat, htable_t *htable, uintptr_t addr) { x86pte_t buf; x86pte32_t *pte32 = (x86pte32_t *)&buf; size_t len; if (htable->ht_flags & HTABLE_VLP) { uintptr_t ptr = (uintptr_t)hat->hat_vlp_ptes; ptr += va2entry(htable, addr) << mmu.pte_size_shift; len = mdb_vread(&buf, mmu.pte_size, ptr); } else { paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn); paddr += va2entry(htable, addr) << mmu.pte_size_shift; len = mdb_pread(&buf, mmu.pte_size, paddr); } if (len != mmu.pte_size) return (0); if (mmu.pte_size == sizeof (x86pte_t)) return (buf); return (*pte32); }
static int do_ptable_dcmd(pfn_t pfn) { struct hat *hatp; struct hat hat; htable_t *ht; htable_t htable; uintptr_t base; int h; int level; int entry; uintptr_t pagesize; x86pte_t pte; x86pte_t buf; x86pte32_t *pte32 = (x86pte32_t *)&buf; physaddr_t paddr; size_t len; /* * The hats are kept in a list with khat at the head. */ for (hatp = khat; hatp != NULL; hatp = hat.hat_next) { /* * read the hat and its hash table */ if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) { mdb_warn("Couldn't read struct hat\n"); return (DCMD_ERR); } /* * read the htable hashtable */ paddr = 0; for (h = 0; h < hat.hat_num_hash; ++h) { if (mdb_vread(&ht, sizeof (htable_t *), (uintptr_t)(hat.hat_ht_hash + h)) == -1) { mdb_warn("Couldn't read htable\n"); return (DCMD_ERR); } for (; ht != NULL; ht = htable.ht_next) { if (mdb_vread(&htable, sizeof (htable_t), (uintptr_t)ht) == -1) { mdb_warn("Couldn't read htable\n"); return (DCMD_ERR); } /* * Is this the PFN for this htable */ if (htable.ht_pfn == pfn) goto found_it; } } } found_it: if (htable.ht_pfn == pfn) { mdb_printf("htable=%p\n", ht); level = htable.ht_level; base = htable.ht_vaddr; pagesize = mmu.level_size[level]; } else { mdb_printf("Unknown pagetable - assuming level/addr 0"); level = 0; /* assume level == 0 for PFN */ base = 0; pagesize = MMU_PAGESIZE; } paddr = mmu_ptob((physaddr_t)pfn); for (entry = 0; entry < mmu.ptes_per_table; ++entry) { len = mdb_pread(&buf, mmu.pte_size, paddr + entry * mmu.pte_size); if (len != mmu.pte_size) return (DCMD_ERR); if (mmu.pte_size == sizeof (x86pte_t)) pte = buf; else pte = *pte32; if (pte == 0) continue; mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize); do_pte_dcmd(level, pte); } done: return (DCMD_OK); }
/* * Report all hat's that either use PFN as a page table or that map the page. */ static int do_report_maps(pfn_t pfn) { struct hat *hatp; struct hat hat; htable_t *ht; htable_t htable; uintptr_t base; int h; int level; int entry; x86pte_t pte; x86pte_t buf; x86pte32_t *pte32 = (x86pte32_t *)&buf; physaddr_t paddr; size_t len; /* * The hats are kept in a list with khat at the head. */ for (hatp = khat; hatp != NULL; hatp = hat.hat_next) { /* * read the hat and its hash table */ if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) { mdb_warn("Couldn't read struct hat\n"); return (DCMD_ERR); } /* * read the htable hashtable */ paddr = 0; for (h = 0; h < hat.hat_num_hash; ++h) { if (mdb_vread(&ht, sizeof (htable_t *), (uintptr_t)(hat.hat_ht_hash + h)) == -1) { mdb_warn("Couldn't read htable\n"); return (DCMD_ERR); } for (; ht != NULL; ht = htable.ht_next) { if (mdb_vread(&htable, sizeof (htable_t), (uintptr_t)ht) == -1) { mdb_warn("Couldn't read htable\n"); return (DCMD_ERR); } /* * only report kernel addresses once */ if (hatp != khat && htable.ht_vaddr >= kernelbase) continue; /* * Is the PFN a pagetable itself? */ if (htable.ht_pfn == pfn) { mdb_printf("Pagetable for " "hat=%p htable=%p\n", hatp, ht); continue; } /* * otherwise, examine page mappings */ level = htable.ht_level; if (level > mmu.max_page_level) continue; paddr = mmu_ptob((physaddr_t)htable.ht_pfn); for (entry = 0; entry < HTABLE_NUM_PTES(&htable); ++entry) { base = htable.ht_vaddr + entry * mmu.level_size[level]; /* * only report kernel addresses once */ if (hatp != khat && base >= kernelbase) continue; len = mdb_pread(&buf, mmu.pte_size, paddr + entry * mmu.pte_size); if (len != mmu.pte_size) return (DCMD_ERR); if (mmu.pte_size == sizeof (x86pte_t)) pte = buf; else pte = *pte32; if ((pte & PT_VALID) == 0) continue; if (level == 0 || !(pte & PT_PAGESIZE)) pte &= PT_PADDR; else pte &= PT_PADDR_LGPG; if (mmu_btop(mdb_ma_to_pa(pte)) != pfn) continue; mdb_printf("hat=%p maps addr=%p\n", hatp, (caddr_t)base); } } } } done: return (DCMD_OK); }
static int do_ptable_dcmd(pfn_t pfn, uint64_t level) { struct hat *hatp; struct hat hat; htable_t *ht; htable_t htable; uintptr_t base; int h; int entry; uintptr_t pagesize; x86pte_t pte; physaddr_t paddr; size_t len; /* * The hats are kept in a list with khat at the head. */ for (hatp = khat; hatp != NULL; hatp = hat.hat_next) { /* * read the hat and its hash table */ if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) { mdb_warn("Couldn't read struct hat\n"); return (DCMD_ERR); } /* * read the htable hashtable */ paddr = 0; for (h = 0; h < hat.hat_num_hash; ++h) { if (mdb_vread(&ht, sizeof (htable_t *), (uintptr_t)(hat.hat_ht_hash + h)) == -1) { mdb_warn("Couldn't read htable\n"); return (DCMD_ERR); } for (; ht != NULL; ht = htable.ht_next) { if (mdb_vread(&htable, sizeof (htable_t), (uintptr_t)ht) == -1) { mdb_warn("Couldn't read htable\n"); return (DCMD_ERR); } /* * Is this the PFN for this htable */ if (htable.ht_pfn == pfn) goto found_it; } } } found_it: if (htable.ht_pfn == pfn) { mdb_printf("htable=%p\n", ht); if (level == (uint64_t)-1) { level = htable.ht_level; } else if (htable.ht_level != level) { mdb_warn("htable has level %d but forcing level %lu\n", htable.ht_level, level); } base = htable.ht_vaddr; pagesize = mmu.level_size[level]; } else { if (level == (uint64_t)-1) level = 0; mdb_warn("couldn't find matching htable, using level=%lu, " "base address=0x0\n", level); base = 0; pagesize = mmu.level_size[level]; } paddr = mmu_ptob((physaddr_t)pfn); for (entry = 0; entry < mmu.ptes_per_table; ++entry) { len = mdb_pread(&pte, mmu.pte_size, paddr + entry * mmu.pte_size); if (len != mmu.pte_size) return (DCMD_ERR); if (pte == 0) continue; mdb_printf("[%3d] va=0x%p ", entry, VA_SIGN_EXTEND(base + entry * pagesize)); do_pte_dcmd(level, pte); } done: return (DCMD_OK); }
int ptmap_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { physaddr_t paddrs[MAX_NUM_LEVEL] = { 0, }; size_t entry[MAX_NUM_LEVEL] = { 0, }; uintptr_t start = (uintptr_t)-1; boolean_t writable = B_FALSE; boolean_t user = B_FALSE; boolean_t wflag = B_FALSE; level_t curlevel; if ((flags & DCMD_ADDRSPEC) == 0) return (DCMD_USAGE); if (mdb_getopts(argc, argv, 'w', MDB_OPT_SETBITS, TRUE, &wflag, NULL) != argc) return (DCMD_USAGE); init_mmu(); if (mmu.num_level == 0) return (DCMD_ERR); curlevel = mmu.max_level; paddrs[curlevel] = addr & MMU_PAGEMASK; for (;;) { physaddr_t pte_addr; x86pte_t pte; pte_addr = paddrs[curlevel] + (entry[curlevel] << mmu.pte_size_shift); if (mdb_pread(&pte, sizeof (pte), pte_addr) != sizeof (pte)) { mdb_warn("couldn't read pte at %p", pte_addr); return (DCMD_ERR); } if (PTE_GET(pte, PT_VALID) == 0) { if (start != (uintptr_t)-1) { ptmap_report(entry, start, user, writable, wflag); start = (uintptr_t)-1; } } else if (curlevel == 0 || PTE_GET(pte, PT_PAGESIZE)) { if (start == (uintptr_t)-1) { start = entry2va(entry); user = PTE_GET(pte, PT_USER); writable = PTE_GET(pte, PT_WRITABLE); } else if (user != PTE_GET(pte, PT_USER) || writable != PTE_GET(pte, PT_WRITABLE)) { ptmap_report(entry, start, user, writable, wflag); start = entry2va(entry); user = PTE_GET(pte, PT_USER); writable = PTE_GET(pte, PT_WRITABLE); } } else { /* Descend a level. */ physaddr_t pa = mmu_ptob(pte2mfn(pte, curlevel)); paddrs[--curlevel] = pa; entry[curlevel] = 0; continue; } while (++entry[curlevel] == mmu.ptes_per_table) { /* Ascend back up. */ entry[curlevel] = 0; if (curlevel == mmu.max_level) { if (start != (uintptr_t)-1) { ptmap_report(entry, start, user, writable, wflag); } goto out; } curlevel++; } } out: return (DCMD_OK); }