Home | History | Annotate | Download | only in unix
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     26 
     27 /*
     28  * This part of the file contains the mdb support for dcmds:
     29  *	::memseg_list
     30  *	::page_num2pp
     31  * and walkers for:
     32  *	memseg - a memseg list walker for ::memseg_list
     33  *
     34  */
     35 
     36 #include <sys/types.h>
     37 #include <sys/machparam.h>
     38 #include <sys/controlregs.h>
     39 #include <sys/mach_mmu.h>
     40 #ifdef __xpv
     41 #include <sys/hypervisor.h>
     42 #endif
     43 #include <vm/as.h>
     44 
     45 #include <mdb/mdb_modapi.h>
     46 #include <mdb/mdb_target.h>
     47 
     48 #include <vm/page.h>
     49 #include <vm/hat_i86.h>
     50 
     51 struct pfn2pp {
     52 	pfn_t pfn;
     53 	page_t *pp;
     54 };
     55 
     56 static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *);
     57 static void init_mmu(void);
     58 
     59 int
     60 platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
     61 {
     62 	if (asp == NULL)
     63 		return (DCMD_ERR);
     64 
     65 	init_mmu();
     66 
     67 	if (mmu.num_level == 0)
     68 		return (DCMD_ERR);
     69 
     70 	return (do_va2pa(addr, asp, 0, pap, NULL));
     71 }
     72 
     73 
     74 /*ARGSUSED*/
     75 int
     76 page_num2pp_cb(uintptr_t addr, void *ignored, uintptr_t *data)
     77 {
     78 	struct memseg ms, *msp = &ms;
     79 	struct pfn2pp *p = (struct pfn2pp *)data;
     80 
     81 	if (mdb_vread(msp, sizeof (struct memseg), addr) == -1) {
     82 		mdb_warn("can't read memseg at %#lx", addr);
     83 		return (DCMD_ERR);
     84 	}
     85 
     86 	if (p->pfn >= msp->pages_base && p->pfn < msp->pages_end) {
     87 		p->pp = msp->pages + (p->pfn - msp->pages_base);
     88 		return (WALK_DONE);
     89 	}
     90 
     91 	return (WALK_NEXT);
     92 }
     93 
     94 /*
     95  * ::page_num2pp dcmd
     96  */
     97 /*ARGSUSED*/
     98 int
     99 page_num2pp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    100 {
    101 	struct pfn2pp pfn2pp;
    102 	page_t page;
    103 
    104 	if ((flags & DCMD_ADDRSPEC) == 0) {
    105 		mdb_warn("page frame number missing\n");
    106 			return (DCMD_USAGE);
    107 	}
    108 
    109 	pfn2pp.pfn = (pfn_t)addr;
    110 	pfn2pp.pp = NULL;
    111 
    112 	if (mdb_walk("memseg", (mdb_walk_cb_t)page_num2pp_cb,
    113 	    (void *)&pfn2pp) == -1) {
    114 		mdb_warn("can't walk memseg");
    115 		return (DCMD_ERR);
    116 	}
    117 
    118 	if (pfn2pp.pp == NULL)
    119 		return (DCMD_ERR);
    120 
    121 	mdb_printf("%x has page at %p\n", pfn2pp.pfn, pfn2pp.pp);
    122 
    123 	if (mdb_vread(&page, sizeof (page_t),
    124 	    (uintptr_t)pfn2pp.pp) == -1) {
    125 		mdb_warn("can't read page at %p", &page);
    126 		return (DCMD_ERR);
    127 	}
    128 
    129 	if (page.p_pagenum != pfn2pp.pfn) {
    130 		mdb_warn("WARNING! Found page structure contains "
    131 		    "different pagenumber %x\n", page.p_pagenum);
    132 	}
    133 
    134 	return (DCMD_OK);
    135 }
    136 
    137 
    138 /*
    139  * ::memseg_list dcmd and walker to implement it.
    140  */
    141 /*ARGSUSED*/
    142 int
    143 memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    144 {
    145 	struct memseg ms;
    146 
    147 	if (!(flags & DCMD_ADDRSPEC)) {
    148 		if (mdb_pwalk_dcmd("memseg", "memseg_list",
    149 		    0, NULL, 0) == -1) {
    150 			mdb_warn("can't walk memseg");
    151 			return (DCMD_ERR);
    152 		}
    153 		return (DCMD_OK);
    154 	}
    155 
    156 	if (DCMD_HDRSPEC(flags))
    157 		mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
    158 		    "PAGES", "EPAGES", "BASE", "END");
    159 
    160 	if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
    161 		mdb_warn("can't read memseg at %#lx", addr);
    162 		return (DCMD_ERR);
    163 	}
    164 
    165 	mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr,
    166 	    ms.pages, ms.epages, ms.pages_base, ms.pages_end);
    167 
    168 	return (DCMD_OK);
    169 }
    170 
    171 /*
    172  * walk the memseg structures
    173  */
    174 int
    175 memseg_walk_init(mdb_walk_state_t *wsp)
    176 {
    177 	if (wsp->walk_addr != NULL) {
    178 		mdb_warn("memseg only supports global walks\n");
    179 		return (WALK_ERR);
    180 	}
    181 
    182 	if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
    183 		mdb_warn("symbol 'memsegs' not found");
    184 		return (WALK_ERR);
    185 	}
    186 
    187 	wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
    188 	return (WALK_NEXT);
    189 
    190 }
    191 
    192 int
    193 memseg_walk_step(mdb_walk_state_t *wsp)
    194 {
    195 	int status;
    196 
    197 	if (wsp->walk_addr == 0) {
    198 		return (WALK_DONE);
    199 	}
    200 
    201 	if (mdb_vread(wsp->walk_data, sizeof (struct memseg),
    202 	    wsp->walk_addr) == -1) {
    203 		mdb_warn("failed to read struct memseg at %p", wsp->walk_addr);
    204 		return (WALK_DONE);
    205 	}
    206 
    207 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
    208 	    wsp->walk_cbdata);
    209 
    210 	wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
    211 
    212 	return (status);
    213 }
    214 
    215 void
    216 memseg_walk_fini(mdb_walk_state_t *wsp)
    217 {
    218 	mdb_free(wsp->walk_data, sizeof (struct memseg));
    219 }
    220 
    221 /*
    222  * Now HAT related dcmds.
    223  */
    224 
    225 static struct hat *khat;		/* value of kas.a_hat */
    226 struct hat_mmu_info mmu;
    227 uintptr_t kernelbase;
    228 
    229 /*
    230  * stuff for i86xpv images
    231  */
    232 static int is_xpv;
    233 static uintptr_t mfn_list_addr; /* kernel MFN list address */
    234 uintptr_t xen_virt_start; /* address of mfn_to_pfn[] table */
    235 ulong_t mfn_count;	/* number of pfn's in the MFN list */
    236 pfn_t *mfn_list;	/* local MFN list copy */
    237 
    238 /*
    239  * read mmu parameters from kernel
    240  */
    241 static void
    242 init_mmu(void)
    243 {
    244 	struct as kas;
    245 
    246 	if (mmu.num_level != 0)
    247 		return;
    248 
    249 	if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1)
    250 		mdb_warn("Can't use HAT information before mmu_init()\n");
    251 	if (mdb_readsym(&kas, sizeof (kas), "kas") == -1)
    252 		mdb_warn("Couldn't find kas - kernel's struct as\n");
    253 	if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1)
    254 		mdb_warn("Couldn't find kernelbase\n");
    255 	khat = kas.a_hat;
    256 
    257 	/*
    258 	 * Is this a paravirtualized domain image?
    259 	 */
    260 	if (mdb_readsym(&mfn_list_addr, sizeof (mfn_list_addr),
    261 	    "mfn_list") == -1 ||
    262 	    mdb_readsym(&xen_virt_start, sizeof (xen_virt_start),
    263 	    "xen_virt_start") == -1 ||
    264 	    mdb_readsym(&mfn_count, sizeof (mfn_count), "mfn_count") == -1) {
    265 		mfn_list_addr = NULL;
    266 	}
    267 
    268 	is_xpv = mfn_list_addr != NULL;
    269 
    270 #ifndef _KMDB
    271 	/*
    272 	 * recreate the local mfn_list
    273 	 */
    274 	if (is_xpv) {
    275 		size_t sz = mfn_count * sizeof (pfn_t);
    276 		mfn_list = mdb_zalloc(sz, UM_SLEEP);
    277 
    278 		if (mdb_vread(mfn_list, sz, (uintptr_t)mfn_list_addr) == -1) {
    279 			mdb_warn("Failed to read MFN list\n");
    280 			mdb_free(mfn_list, sz);
    281 			mfn_list = NULL;
    282 		}
    283 	}
    284 #endif
    285 }
    286 
    287 void
    288 free_mmu(void)
    289 {
    290 #ifdef __xpv
    291 	if (mfn_list != NULL)
    292 		mdb_free(mfn_list, mfn_count * sizeof (mfn_t));
    293 #endif
    294 }
    295 
    296 #ifdef __xpv
    297 
    298 #ifdef _KMDB
    299 
    300 /*
    301  * Convert between MFNs and PFNs.  Since we're in kmdb we can go directly
    302  * through the machine to phys mapping and the MFN list.
    303  */
    304 
    305 pfn_t
    306 mdb_mfn_to_pfn(mfn_t mfn)
    307 {
    308 	pfn_t pfn;
    309 	mfn_t tmp;
    310 	pfn_t *pfn_list;
    311 
    312 	if (mfn_list_addr == NULL)
    313 		return (-(pfn_t)1);
    314 
    315 	pfn_list = (pfn_t *)xen_virt_start;
    316 	if (mdb_vread(&pfn, sizeof (pfn), (uintptr_t)(pfn_list + mfn)) == -1)
    317 		return (-(pfn_t)1);
    318 
    319 	if (mdb_vread(&tmp, sizeof (tmp),
    320 	    (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
    321 		return (-(pfn_t)1);
    322 
    323 	if (pfn >= mfn_count || tmp != mfn)
    324 		return (-(pfn_t)1);
    325 
    326 	return (pfn);
    327 }
    328 
    329 mfn_t
    330 mdb_pfn_to_mfn(pfn_t pfn)
    331 {
    332 	mfn_t mfn;
    333 
    334 	init_mmu();
    335 
    336 	if (mfn_list_addr == NULL || pfn >= mfn_count)
    337 		return (-(mfn_t)1);
    338 
    339 	if (mdb_vread(&mfn, sizeof (mfn),
    340 	    (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
    341 		return (-(mfn_t)1);
    342 
    343 	return (mfn);
    344 }
    345 
    346 #else /* _KMDB */
    347 
    348 /*
    349  * Convert between MFNs and PFNs.  Since a crash dump doesn't include the
    350  * MFN->PFN translation table (it's part of the hypervisor, not our image)
    351  * we do the MFN->PFN translation by searching the PFN->MFN (mfn_list)
    352  * table, if it's there.
    353  */
    354 
    355 pfn_t
    356 mdb_mfn_to_pfn(mfn_t mfn)
    357 {
    358 	pfn_t pfn;
    359 
    360 	init_mmu();
    361 
    362 	if (mfn_list == NULL)
    363 		return (-(pfn_t)1);
    364 
    365 	for (pfn = 0; pfn < mfn_count; ++pfn) {
    366 		if (mfn_list[pfn] != mfn)
    367 			continue;
    368 		return (pfn);
    369 	}
    370 
    371 	return (-(pfn_t)1);
    372 }
    373 
    374 mfn_t
    375 mdb_pfn_to_mfn(pfn_t pfn)
    376 {
    377 	init_mmu();
    378 
    379 	if (mfn_list == NULL || pfn >= mfn_count)
    380 		return (-(mfn_t)1);
    381 
    382 	return (mfn_list[pfn]);
    383 }
    384 
    385 #endif /* _KMDB */
    386 
    387 static paddr_t
    388 mdb_ma_to_pa(uint64_t ma)
    389 {
    390 	pfn_t pfn = mdb_mfn_to_pfn(mmu_btop(ma));
    391 	if (pfn == -(pfn_t)1)
    392 		return (-(paddr_t)1);
    393 
    394 	return (mmu_ptob((paddr_t)pfn) | (ma & (MMU_PAGESIZE - 1)));
    395 }
    396 
    397 #else /* __xpv */
    398 
    399 #define	mdb_ma_to_pa(ma) (ma)
    400 #define	mdb_mfn_to_pfn(mfn) (mfn)
    401 #define	mdb_pfn_to_mfn(pfn) (pfn)
    402 
    403 #endif /* __xpv */
    404 
    405 /*
    406  * ::mfntopfn dcmd translates hypervisor machine page number
    407  * to physical page number
    408  */
    409 /*ARGSUSED*/
    410 int
    411 mfntopfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    412 {
    413 	pfn_t pfn;
    414 
    415 	if ((flags & DCMD_ADDRSPEC) == 0) {
    416 		mdb_warn("MFN missing\n");
    417 		return (DCMD_USAGE);
    418 	}
    419 
    420 	if ((pfn = mdb_mfn_to_pfn((pfn_t)addr)) == -(pfn_t)1) {
    421 		mdb_warn("Invalid mfn %lr\n", (pfn_t)addr);
    422 		return (DCMD_ERR);
    423 	}
    424 
    425 	mdb_printf("%lr\n", pfn);
    426 
    427 	return (DCMD_OK);
    428 }
    429 
    430 /*
    431  * ::pfntomfn dcmd translates physical page number to
    432  * hypervisor machine page number
    433  */
    434 /*ARGSUSED*/
    435 int
    436 pfntomfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    437 {
    438 	pfn_t mfn;
    439 
    440 	if ((flags & DCMD_ADDRSPEC) == 0) {
    441 		mdb_warn("PFN missing\n");
    442 		return (DCMD_USAGE);
    443 	}
    444 
    445 	if ((mfn = mdb_pfn_to_mfn((pfn_t)addr)) == -(pfn_t)1) {
    446 		mdb_warn("Invalid pfn %lr\n", (pfn_t)addr);
    447 		return (DCMD_ABORT);
    448 	}
    449 
    450 	mdb_printf("%lr\n", mfn);
    451 
    452 	if (flags & DCMD_LOOP)
    453 		mdb_set_dot(addr + 1);
    454 	return (DCMD_OK);
    455 }
    456 
    457 static pfn_t
    458 pte2mfn(x86pte_t pte, uint_t level)
    459 {
    460 	pfn_t mfn;
    461 	if (level > 0 && (pte & PT_PAGESIZE))
    462 		mfn = mmu_btop(pte & PT_PADDR_LGPG);
    463 	else
    464 		mfn = mmu_btop(pte & PT_PADDR);
    465 	return (mfn);
    466 }
    467 
    468 /*
    469  * Print a PTE in more human friendly way. The PTE is assumed to be in
    470  * a level 0 page table, unless -l specifies another level.
    471  *
    472  * The PTE value can be specified as the -p option, since on a 32 bit kernel
    473  * with PAE running it's larger than a uintptr_t.
    474  */
    475 static int
    476 do_pte_dcmd(int level, uint64_t pte)
    477 {
    478 	static char *attr[] = {
    479 	    "wrback", "wrthru", "uncached", "uncached",
    480 	    "wrback", "wrthru", "wrcombine", "uncached"};
    481 	int pat_index = 0;
    482 	pfn_t mfn;
    483 
    484 	mdb_printf("pte=%llr: ", pte);
    485 	if (PTE_GET(pte, mmu.pt_nx))
    486 		mdb_printf("noexec ");
    487 
    488 	mfn = pte2mfn(pte, level);
    489 	mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn);
    490 
    491 	if (PTE_GET(pte, PT_NOCONSIST))
    492 		mdb_printf("noconsist ");
    493 
    494 	if (PTE_GET(pte, PT_NOSYNC))
    495 		mdb_printf("nosync ");
    496 
    497 	if (PTE_GET(pte, mmu.pt_global))
    498 		mdb_printf("global ");
    499 
    500 	if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
    501 		mdb_printf("largepage ");
    502 
    503 	if (level > 0 && PTE_GET(pte, PT_MOD))
    504 		mdb_printf("mod ");
    505 
    506 	if (level > 0 && PTE_GET(pte, PT_REF))
    507 		mdb_printf("ref ");
    508 
    509 	if (PTE_GET(pte, PT_USER))
    510 		mdb_printf("user ");
    511 
    512 	if (PTE_GET(pte, PT_WRITABLE))
    513 		mdb_printf("write ");
    514 
    515 	/*
    516 	 * Report non-standard cacheability
    517 	 */
    518 	pat_index = 0;
    519 	if (level > 0) {
    520 		if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE))
    521 			pat_index += 4;
    522 	} else {
    523 		if (PTE_GET(pte, PT_PAT_4K))
    524 			pat_index += 4;
    525 	}
    526 
    527 	if (PTE_GET(pte, PT_NOCACHE))
    528 		pat_index += 2;
    529 
    530 	if (PTE_GET(pte, PT_WRITETHRU))
    531 		pat_index += 1;
    532 
    533 	if (pat_index != 0)
    534 		mdb_printf("%s", attr[pat_index]);
    535 
    536 	if (PTE_GET(pte, PT_VALID) == 0)
    537 		mdb_printf(" !VALID ");
    538 
    539 	mdb_printf("\n");
    540 	return (DCMD_OK);
    541 }
    542 
    543 /*
    544  * Print a PTE in more human friendly way. The PTE is assumed to be in
    545  * a level 0 page table, unless -l specifies another level.
    546  *
    547  * The PTE value can be specified as the -p option, since on a 32 bit kernel
    548  * with PAE running it's larger than a uintptr_t.
    549  */
    550 /*ARGSUSED*/
    551 int
    552 pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    553 {
    554 	int level = 0;
    555 	uint64_t pte = 0;
    556 	char *level_str = NULL;
    557 	char *pte_str = NULL;
    558 
    559 	init_mmu();
    560 
    561 	if (mmu.num_level == 0)
    562 		return (DCMD_ERR);
    563 
    564 	if (mdb_getopts(argc, argv,
    565 	    'p', MDB_OPT_STR, &pte_str,
    566 	    'l', MDB_OPT_STR, &level_str) != argc)
    567 		return (DCMD_USAGE);
    568 
    569 	/*
    570 	 * parse the PTE to decode, if it's 0, we don't do anything
    571 	 */
    572 	if (pte_str != NULL) {
    573 		pte = mdb_strtoull(pte_str);
    574 	} else {
    575 		if ((flags & DCMD_ADDRSPEC) == 0)
    576 			return (DCMD_USAGE);
    577 		pte = addr;
    578 	}
    579 	if (pte == 0)
    580 		return (DCMD_OK);
    581 
    582 	/*
    583 	 * parse the level if supplied
    584 	 */
    585 	if (level_str != NULL) {
    586 		level = mdb_strtoull(level_str);
    587 		if (level < 0 || level > mmu.max_level)
    588 			return (DCMD_ERR);
    589 	}
    590 
    591 	return (do_pte_dcmd(level, pte));
    592 }
    593 
    594 static size_t
    595 va2entry(htable_t *htable, uintptr_t addr)
    596 {
    597 	size_t entry = (addr - htable->ht_vaddr);
    598 
    599 	entry >>= mmu.level_shift[htable->ht_level];
    600 	return (entry & HTABLE_NUM_PTES(htable) - 1);
    601 }
    602 
    603 static x86pte_t
    604 get_pte(hat_t *hat, htable_t *htable, uintptr_t addr)
    605 {
    606 	x86pte_t buf;
    607 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
    608 	size_t len;
    609 
    610 	if (htable->ht_flags & HTABLE_VLP) {
    611 		uintptr_t ptr = (uintptr_t)hat->hat_vlp_ptes;
    612 		ptr += va2entry(htable, addr) << mmu.pte_size_shift;
    613 		len = mdb_vread(&buf, mmu.pte_size, ptr);
    614 	} else {
    615 		paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn);
    616 		paddr += va2entry(htable, addr) << mmu.pte_size_shift;
    617 		len = mdb_pread(&buf, mmu.pte_size, paddr);
    618 	}
    619 
    620 	if (len != mmu.pte_size)
    621 		return (0);
    622 
    623 	if (mmu.pte_size == sizeof (x86pte_t))
    624 		return (buf);
    625 	return (*pte32);
    626 }
    627 
    628 static int
    629 do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap,
    630     pfn_t *mfnp)
    631 {
    632 	struct as as;
    633 	struct hat *hatp;
    634 	struct hat hat;
    635 	htable_t *ht;
    636 	htable_t htable;
    637 	uintptr_t base;
    638 	int h;
    639 	int level;
    640 	int found = 0;
    641 	x86pte_t pte;
    642 	physaddr_t paddr;
    643 
    644 	if (asp != NULL) {
    645 		if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
    646 			mdb_warn("Couldn't read struct as\n");
    647 			return (DCMD_ERR);
    648 		}
    649 		hatp = as.a_hat;
    650 	} else {
    651 		hatp = khat;
    652 	}
    653 
    654 	/*
    655 	 * read the hat and its hash table
    656 	 */
    657 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
    658 		mdb_warn("Couldn't read struct hat\n");
    659 		return (DCMD_ERR);
    660 	}
    661 
    662 	/*
    663 	 * read the htable hashtable
    664 	 */
    665 	for (level = 0; level <= mmu.max_level; ++level) {
    666 		if (level == TOP_LEVEL(&hat))
    667 			base = 0;
    668 		else
    669 			base = addr & mmu.level_mask[level + 1];
    670 
    671 		for (h = 0; h < hat.hat_num_hash; ++h) {
    672 			if (mdb_vread(&ht, sizeof (htable_t *),
    673 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
    674 				mdb_warn("Couldn't read htable\n");
    675 				return (DCMD_ERR);
    676 			}
    677 			for (; ht != NULL; ht = htable.ht_next) {
    678 				if (mdb_vread(&htable, sizeof (htable_t),
    679 				    (uintptr_t)ht) == -1) {
    680 					mdb_warn("Couldn't read htable\n");
    681 					return (DCMD_ERR);
    682 				}
    683 
    684 				if (htable.ht_vaddr != base ||
    685 				    htable.ht_level != level)
    686 					continue;
    687 
    688 				pte = get_pte(&hat, &htable, addr);
    689 
    690 				if (print_level) {
    691 					mdb_printf("\tlevel=%d htable=%p "
    692 					    "pte=%llr\n", level, ht, pte);
    693 				}
    694 
    695 				if (!PTE_ISVALID(pte)) {
    696 					mdb_printf("Address %p is unmapped.\n",
    697 					    addr);
    698 					return (DCMD_ERR);
    699 				}
    700 
    701 				if (found)
    702 					continue;
    703 
    704 				if (PTE_IS_LGPG(pte, level))
    705 					paddr = mdb_ma_to_pa(pte &
    706 					    PT_PADDR_LGPG);
    707 				else
    708 					paddr = mdb_ma_to_pa(pte & PT_PADDR);
    709 				paddr += addr & mmu.level_offset[level];
    710 				if (pap != NULL)
    711 					*pap = paddr;
    712 				if (mfnp != NULL)
    713 					*mfnp = pte2mfn(pte, level);
    714 				found = 1;
    715 			}
    716 		}
    717 	}
    718 
    719 done:
    720 	if (!found)
    721 		return (DCMD_ERR);
    722 	return (DCMD_OK);
    723 }
    724 
    725 int
    726 va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    727 {
    728 	uintptr_t addrspace;
    729 	char *addrspace_str = NULL;
    730 	int piped = flags & DCMD_PIPE_OUT;
    731 	pfn_t pfn;
    732 	pfn_t mfn;
    733 	int rc;
    734 
    735 	init_mmu();
    736 
    737 	if (mmu.num_level == 0)
    738 		return (DCMD_ERR);
    739 
    740 	if (mdb_getopts(argc, argv,
    741 	    'a', MDB_OPT_STR, &addrspace_str) != argc)
    742 		return (DCMD_USAGE);
    743 
    744 	if ((flags & DCMD_ADDRSPEC) == 0)
    745 		return (DCMD_USAGE);
    746 
    747 	/*
    748 	 * parse the address space
    749 	 */
    750 	if (addrspace_str != NULL)
    751 		addrspace = mdb_strtoull(addrspace_str);
    752 	else
    753 		addrspace = 0;
    754 
    755 	rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn);
    756 
    757 	if (rc != DCMD_OK)
    758 		return (rc);
    759 
    760 	if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) {
    761 		mdb_warn("Invalid mfn %lr\n", mfn);
    762 		return (DCMD_ERR);
    763 	}
    764 
    765 	if (piped) {
    766 		mdb_printf("0x%lr\n", pfn);
    767 		return (DCMD_OK);
    768 	}
    769 
    770 	mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn);
    771 
    772 	if (is_xpv)
    773 		mdb_printf(" (mfn 0x%lr)", mfn);
    774 
    775 	mdb_printf("\n");
    776 
    777 	return (DCMD_OK);
    778 }
    779 
    780 /*
    781  * Report all hat's that either use PFN as a page table or that map the page.
    782  */
    783 static int
    784 do_report_maps(pfn_t pfn)
    785 {
    786 	struct hat *hatp;
    787 	struct hat hat;
    788 	htable_t *ht;
    789 	htable_t htable;
    790 	uintptr_t base;
    791 	int h;
    792 	int level;
    793 	int entry;
    794 	x86pte_t pte;
    795 	x86pte_t buf;
    796 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
    797 	physaddr_t paddr;
    798 	size_t len;
    799 
    800 	/*
    801 	 * The hats are kept in a list with khat at the head.
    802 	 */
    803 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
    804 		/*
    805 		 * read the hat and its hash table
    806 		 */
    807 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
    808 			mdb_warn("Couldn't read struct hat\n");
    809 			return (DCMD_ERR);
    810 		}
    811 
    812 		/*
    813 		 * read the htable hashtable
    814 		 */
    815 		paddr = 0;
    816 		for (h = 0; h < hat.hat_num_hash; ++h) {
    817 			if (mdb_vread(&ht, sizeof (htable_t *),
    818 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
    819 				mdb_warn("Couldn't read htable\n");
    820 				return (DCMD_ERR);
    821 			}
    822 			for (; ht != NULL; ht = htable.ht_next) {
    823 				if (mdb_vread(&htable, sizeof (htable_t),
    824 				    (uintptr_t)ht) == -1) {
    825 					mdb_warn("Couldn't read htable\n");
    826 					return (DCMD_ERR);
    827 				}
    828 
    829 				/*
    830 				 * only report kernel addresses once
    831 				 */
    832 				if (hatp != khat &&
    833 				    htable.ht_vaddr >= kernelbase)
    834 					continue;
    835 
    836 				/*
    837 				 * Is the PFN a pagetable itself?
    838 				 */
    839 				if (htable.ht_pfn == pfn) {
    840 					mdb_printf("Pagetable for "
    841 					    "hat=%p htable=%p\n", hatp, ht);
    842 					continue;
    843 				}
    844 
    845 				/*
    846 				 * otherwise, examine page mappings
    847 				 */
    848 				level = htable.ht_level;
    849 				if (level > mmu.max_page_level)
    850 					continue;
    851 				paddr = mmu_ptob((physaddr_t)htable.ht_pfn);
    852 				for (entry = 0;
    853 				    entry < HTABLE_NUM_PTES(&htable);
    854 				    ++entry) {
    855 
    856 					base = htable.ht_vaddr + entry *
    857 					    mmu.level_size[level];
    858 
    859 					/*
    860 					 * only report kernel addresses once
    861 					 */
    862 					if (hatp != khat &&
    863 					    base >= kernelbase)
    864 						continue;
    865 
    866 					len = mdb_pread(&buf, mmu.pte_size,
    867 					    paddr + entry * mmu.pte_size);
    868 					if (len != mmu.pte_size)
    869 						return (DCMD_ERR);
    870 					if (mmu.pte_size == sizeof (x86pte_t))
    871 						pte = buf;
    872 					else
    873 						pte = *pte32;
    874 
    875 					if ((pte & PT_VALID) == 0)
    876 						continue;
    877 					if (level == 0 || !(pte & PT_PAGESIZE))
    878 						pte &= PT_PADDR;
    879 					else
    880 						pte &= PT_PADDR_LGPG;
    881 					if (mmu_btop(mdb_ma_to_pa(pte)) != pfn)
    882 						continue;
    883 					mdb_printf("hat=%p maps addr=%p\n",
    884 					    hatp, (caddr_t)base);
    885 				}
    886 			}
    887 		}
    888 	}
    889 
    890 done:
    891 	return (DCMD_OK);
    892 }
    893 
    894 /*
    895  * given a PFN as its address argument, prints out the uses of it
    896  */
    897 /*ARGSUSED*/
    898 int
    899 report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    900 {
    901 	pfn_t pfn;
    902 	uint_t mflag = 0;
    903 
    904 	init_mmu();
    905 
    906 	if (mmu.num_level == 0)
    907 		return (DCMD_ERR);
    908 
    909 	if ((flags & DCMD_ADDRSPEC) == 0)
    910 		return (DCMD_USAGE);
    911 
    912 	if (mdb_getopts(argc, argv,
    913 	    'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
    914 		return (DCMD_USAGE);
    915 
    916 	pfn = (pfn_t)addr;
    917 	if (mflag)
    918 		pfn = mdb_mfn_to_pfn(pfn);
    919 
    920 	return (do_report_maps(pfn));
    921 }
    922 
    923 static int
    924 do_ptable_dcmd(pfn_t pfn)
    925 {
    926 	struct hat *hatp;
    927 	struct hat hat;
    928 	htable_t *ht;
    929 	htable_t htable;
    930 	uintptr_t base;
    931 	int h;
    932 	int level;
    933 	int entry;
    934 	uintptr_t pagesize;
    935 	x86pte_t pte;
    936 	x86pte_t buf;
    937 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
    938 	physaddr_t paddr;
    939 	size_t len;
    940 
    941 	/*
    942 	 * The hats are kept in a list with khat at the head.
    943 	 */
    944 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
    945 		/*
    946 		 * read the hat and its hash table
    947 		 */
    948 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
    949 			mdb_warn("Couldn't read struct hat\n");
    950 			return (DCMD_ERR);
    951 		}
    952 
    953 		/*
    954 		 * read the htable hashtable
    955 		 */
    956 		paddr = 0;
    957 		for (h = 0; h < hat.hat_num_hash; ++h) {
    958 			if (mdb_vread(&ht, sizeof (htable_t *),
    959 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
    960 				mdb_warn("Couldn't read htable\n");
    961 				return (DCMD_ERR);
    962 			}
    963 			for (; ht != NULL; ht = htable.ht_next) {
    964 				if (mdb_vread(&htable, sizeof (htable_t),
    965 				    (uintptr_t)ht) == -1) {
    966 					mdb_warn("Couldn't read htable\n");
    967 					return (DCMD_ERR);
    968 				}
    969 
    970 				/*
    971 				 * Is this the PFN for this htable
    972 				 */
    973 				if (htable.ht_pfn == pfn)
    974 					goto found_it;
    975 			}
    976 		}
    977 	}
    978 
    979 found_it:
    980 	if (htable.ht_pfn == pfn) {
    981 		mdb_printf("htable=%p\n", ht);
    982 		level = htable.ht_level;
    983 		base = htable.ht_vaddr;
    984 		pagesize = mmu.level_size[level];
    985 	} else {
    986 		mdb_printf("Unknown pagetable - assuming level/addr 0");
    987 		level = 0;	/* assume level == 0 for PFN */
    988 		base = 0;
    989 		pagesize = MMU_PAGESIZE;
    990 	}
    991 
    992 	paddr = mmu_ptob((physaddr_t)pfn);
    993 	for (entry = 0; entry < mmu.ptes_per_table; ++entry) {
    994 		len = mdb_pread(&buf, mmu.pte_size,
    995 		    paddr + entry * mmu.pte_size);
    996 		if (len != mmu.pte_size)
    997 			return (DCMD_ERR);
    998 		if (mmu.pte_size == sizeof (x86pte_t))
    999 			pte = buf;
   1000 		else
   1001 			pte = *pte32;
   1002 
   1003 		if (pte == 0)
   1004 			continue;
   1005 
   1006 		mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize);
   1007 		do_pte_dcmd(level, pte);
   1008 	}
   1009 
   1010 done:
   1011 	return (DCMD_OK);
   1012 }
   1013 
   1014 /*
   1015  * Dump the page table at the given PFN
   1016  */
   1017 /*ARGSUSED*/
   1018 int
   1019 ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1020 {
   1021 	pfn_t pfn;
   1022 	uint_t mflag = 0;
   1023 
   1024 	init_mmu();
   1025 
   1026 	if (mmu.num_level == 0)
   1027 		return (DCMD_ERR);
   1028 
   1029 	if ((flags & DCMD_ADDRSPEC) == 0)
   1030 		return (DCMD_USAGE);
   1031 
   1032 	if (mdb_getopts(argc, argv,
   1033 	    'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
   1034 		return (DCMD_USAGE);
   1035 
   1036 	pfn = (pfn_t)addr;
   1037 	if (mflag)
   1038 		pfn = mdb_mfn_to_pfn(pfn);
   1039 
   1040 	return (do_ptable_dcmd(pfn));
   1041 }
   1042 
   1043 static int
   1044 do_htables_dcmd(hat_t *hatp)
   1045 {
   1046 	struct hat hat;
   1047 	htable_t *ht;
   1048 	htable_t htable;
   1049 	int h;
   1050 
   1051 	/*
   1052 	 * read the hat and its hash table
   1053 	 */
   1054 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
   1055 		mdb_warn("Couldn't read struct hat\n");
   1056 		return (DCMD_ERR);
   1057 	}
   1058 
   1059 	/*
   1060 	 * read the htable hashtable
   1061 	 */
   1062 	for (h = 0; h < hat.hat_num_hash; ++h) {
   1063 		if (mdb_vread(&ht, sizeof (htable_t *),
   1064 		    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
   1065 			mdb_warn("Couldn't read htable ptr\\n");
   1066 			return (DCMD_ERR);
   1067 		}
   1068 		for (; ht != NULL; ht = htable.ht_next) {
   1069 			mdb_printf("%p\n", ht);
   1070 			if (mdb_vread(&htable, sizeof (htable_t),
   1071 			    (uintptr_t)ht) == -1) {
   1072 				mdb_warn("Couldn't read htable\n");
   1073 				return (DCMD_ERR);
   1074 			}
   1075 		}
   1076 	}
   1077 	return (DCMD_OK);
   1078 }
   1079 
   1080 /*
   1081  * Dump the htables for the given hat
   1082  */
   1083 /*ARGSUSED*/
   1084 int
   1085 htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1086 {
   1087 	hat_t *hat;
   1088 
   1089 	init_mmu();
   1090 
   1091 	if (mmu.num_level == 0)
   1092 		return (DCMD_ERR);
   1093 
   1094 	if ((flags & DCMD_ADDRSPEC) == 0)
   1095 		return (DCMD_USAGE);
   1096 
   1097 	hat = (hat_t *)addr;
   1098 
   1099 	return (do_htables_dcmd(hat));
   1100 }
   1101