xref: /onnv-gate/usr/src/cmd/mdb/i86pc/modules/unix/i86mmu.c (revision 3446:5903aece022d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51747Sjosephb  * Common Development and Distribution License (the "License").
61747Sjosephb  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*3446Smrj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * This part of the file contains the mdb support for dcmds:
290Sstevel@tonic-gate  *	::memseg_list
300Sstevel@tonic-gate  *	::page_num2pp
310Sstevel@tonic-gate  * and walkers for:
320Sstevel@tonic-gate  *	memseg - a memseg list walker for ::memseg_list
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  */
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #include <sys/types.h>
370Sstevel@tonic-gate #include <sys/machparam.h>
380Sstevel@tonic-gate #include <sys/controlregs.h>
39*3446Smrj #include <sys/mach_mmu.h>
400Sstevel@tonic-gate #include <vm/as.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
430Sstevel@tonic-gate #include <mdb/mdb_target.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include <vm/page.h>
460Sstevel@tonic-gate #include <vm/hat_i86.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate struct pfn2pp {
490Sstevel@tonic-gate 	pfn_t pfn;
500Sstevel@tonic-gate 	page_t *pp;
510Sstevel@tonic-gate };
520Sstevel@tonic-gate 
53*3446Smrj static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *);
540Sstevel@tonic-gate static void get_mmu(void);
550Sstevel@tonic-gate 
560Sstevel@tonic-gate int
570Sstevel@tonic-gate platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
580Sstevel@tonic-gate {
590Sstevel@tonic-gate 	if (asp == NULL)
600Sstevel@tonic-gate 		return (DCMD_ERR);
610Sstevel@tonic-gate 
620Sstevel@tonic-gate 	/*
630Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
640Sstevel@tonic-gate 	 */
650Sstevel@tonic-gate 	get_mmu();
660Sstevel@tonic-gate 	if (mmu.num_level == 0)
670Sstevel@tonic-gate 		return (DCMD_ERR);
680Sstevel@tonic-gate 
69*3446Smrj 	return (do_va2pa(addr, asp, 0, pap, NULL));
700Sstevel@tonic-gate }
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*ARGSUSED*/
740Sstevel@tonic-gate int
750Sstevel@tonic-gate page_num2pp_cb(uintptr_t addr, void *ignored, uintptr_t *data)
760Sstevel@tonic-gate {
770Sstevel@tonic-gate 	struct memseg ms, *msp = &ms;
780Sstevel@tonic-gate 	struct pfn2pp *p = (struct pfn2pp *)data;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	if (mdb_vread(msp, sizeof (struct memseg), addr) == -1) {
810Sstevel@tonic-gate 		mdb_warn("can't read memseg at %#lx", addr);
820Sstevel@tonic-gate 		return (DCMD_ERR);
830Sstevel@tonic-gate 	}
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 	if (p->pfn >= msp->pages_base && p->pfn < msp->pages_end) {
860Sstevel@tonic-gate 		p->pp = msp->pages + (p->pfn - msp->pages_base);
870Sstevel@tonic-gate 		return (WALK_DONE);
880Sstevel@tonic-gate 	}
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	return (WALK_NEXT);
910Sstevel@tonic-gate }
920Sstevel@tonic-gate 
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate  * ::page_num2pp dcmd
950Sstevel@tonic-gate  */
960Sstevel@tonic-gate /*ARGSUSED*/
970Sstevel@tonic-gate int
980Sstevel@tonic-gate page_num2pp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate 	struct pfn2pp pfn2pp;
1010Sstevel@tonic-gate 	page_t page;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0) {
1040Sstevel@tonic-gate 		mdb_warn("page frame number missing\n");
1050Sstevel@tonic-gate 			return (DCMD_USAGE);
1060Sstevel@tonic-gate 	}
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	pfn2pp.pfn = (pfn_t)addr;
1090Sstevel@tonic-gate 	pfn2pp.pp = NULL;
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 	if (mdb_walk("memseg", (mdb_walk_cb_t)page_num2pp_cb,
1120Sstevel@tonic-gate 	    (void *)&pfn2pp) == -1) {
1130Sstevel@tonic-gate 		mdb_warn("can't walk memseg");
1140Sstevel@tonic-gate 		return (DCMD_ERR);
1150Sstevel@tonic-gate 	}
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	if (pfn2pp.pp == NULL)
1180Sstevel@tonic-gate 		return (DCMD_ERR);
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	mdb_printf("%x has page at %p\n", pfn2pp.pfn, pfn2pp.pp);
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	if (mdb_vread(&page, sizeof (page_t),
1230Sstevel@tonic-gate 	    (uintptr_t)pfn2pp.pp) == -1) {
1240Sstevel@tonic-gate 		mdb_warn("can't read page at %p", &page);
1250Sstevel@tonic-gate 		return (DCMD_ERR);
1260Sstevel@tonic-gate 	}
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	if (page.p_pagenum != pfn2pp.pfn) {
1290Sstevel@tonic-gate 		mdb_warn("WARNING! Found page structure contains "
1300Sstevel@tonic-gate 			"different pagenumber %x\n", page.p_pagenum);
1310Sstevel@tonic-gate 	}
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	return (DCMD_OK);
1340Sstevel@tonic-gate }
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate /*
1380Sstevel@tonic-gate  * ::memseg_list dcmd and walker to implement it.
1390Sstevel@tonic-gate  */
1400Sstevel@tonic-gate /*ARGSUSED*/
1410Sstevel@tonic-gate int
1420Sstevel@tonic-gate memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate 	struct memseg ms;
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
1470Sstevel@tonic-gate 		if (mdb_pwalk_dcmd("memseg", "memseg_list",
1480Sstevel@tonic-gate 		    0, NULL, 0) == -1) {
1490Sstevel@tonic-gate 			mdb_warn("can't walk memseg");
1500Sstevel@tonic-gate 			return (DCMD_ERR);
1510Sstevel@tonic-gate 		}
1520Sstevel@tonic-gate 		return (DCMD_OK);
1530Sstevel@tonic-gate 	}
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
1560Sstevel@tonic-gate 		mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
1570Sstevel@tonic-gate 			"PAGES", "EPAGES", "BASE", "END");
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
1600Sstevel@tonic-gate 		mdb_warn("can't read memseg at %#lx", addr);
1610Sstevel@tonic-gate 		return (DCMD_ERR);
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr,
1650Sstevel@tonic-gate 		ms.pages, ms.epages, ms.pages_base, ms.pages_end);
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	return (DCMD_OK);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate  * walk the memseg structures
1720Sstevel@tonic-gate  */
1730Sstevel@tonic-gate int
1740Sstevel@tonic-gate memseg_walk_init(mdb_walk_state_t *wsp)
1750Sstevel@tonic-gate {
1760Sstevel@tonic-gate 	if (wsp->walk_addr != NULL) {
1770Sstevel@tonic-gate 		mdb_warn("memseg only supports global walks\n");
1780Sstevel@tonic-gate 		return (WALK_ERR);
1790Sstevel@tonic-gate 	}
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
1820Sstevel@tonic-gate 		mdb_warn("symbol 'memsegs' not found");
1830Sstevel@tonic-gate 		return (WALK_ERR);
1840Sstevel@tonic-gate 	}
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
1870Sstevel@tonic-gate 	return (WALK_NEXT);
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate int
1920Sstevel@tonic-gate memseg_walk_step(mdb_walk_state_t *wsp)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate 	int status;
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	if (wsp->walk_addr == 0) {
1970Sstevel@tonic-gate 		return (WALK_DONE);
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (struct memseg),
2010Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
2020Sstevel@tonic-gate 		mdb_warn("failed to read struct memseg at %p", wsp->walk_addr);
2030Sstevel@tonic-gate 		return (WALK_DONE);
2040Sstevel@tonic-gate 	}
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
2070Sstevel@tonic-gate 	    wsp->walk_cbdata);
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	return (status);
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate void
2150Sstevel@tonic-gate memseg_walk_fini(mdb_walk_state_t *wsp)
2160Sstevel@tonic-gate {
2170Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct memseg));
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate /*
221*3446Smrj  * Now HAT related dcmds.
2220Sstevel@tonic-gate  */
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate struct hat *khat;		/* value of kas.a_hat */
2250Sstevel@tonic-gate struct hat_mmu_info mmu;
2260Sstevel@tonic-gate uintptr_t kernelbase;
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate /*
2290Sstevel@tonic-gate  * read mmu parameters from kernel
2300Sstevel@tonic-gate  */
2310Sstevel@tonic-gate static void
2320Sstevel@tonic-gate get_mmu(void)
2330Sstevel@tonic-gate {
2340Sstevel@tonic-gate 	struct as kas;
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	if (mmu.num_level != 0)
2370Sstevel@tonic-gate 		return;
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1)
2400Sstevel@tonic-gate 		mdb_warn("Can't use HAT information before mmu_init()\n");
2410Sstevel@tonic-gate 	if (mdb_readsym(&kas, sizeof (kas), "kas") == -1)
2420Sstevel@tonic-gate 		mdb_warn("Couldn't find kas - kernel's struct as\n");
2430Sstevel@tonic-gate 	if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1)
2440Sstevel@tonic-gate 		mdb_warn("Couldn't find kernelbase\n");
2450Sstevel@tonic-gate 	khat = kas.a_hat;
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate 
248*3446Smrj #define	mdb_ma_to_pa(ma) (ma)
249*3446Smrj #define	mdb_mfn_to_pfn(mfn) (mfn)
250*3446Smrj #define	mdb_pfn_to_mfn(pfn) (pfn)
251*3446Smrj 
252*3446Smrj static pfn_t
253*3446Smrj pte2mfn(x86pte_t pte, uint_t level)
254*3446Smrj {
255*3446Smrj 	pfn_t mfn;
256*3446Smrj 	if (level > 0 && (pte & PT_PAGESIZE))
257*3446Smrj 		mfn = mmu_btop(pte & PT_PADDR_LGPG);
258*3446Smrj 	else
259*3446Smrj 		mfn = mmu_btop(pte & PT_PADDR);
260*3446Smrj 	return (mfn);
261*3446Smrj }
262*3446Smrj 
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate  * Print a PTE in more human friendly way. The PTE is assumed to be in
2650Sstevel@tonic-gate  * a level 0 page table, unless -l specifies another level.
2660Sstevel@tonic-gate  *
2670Sstevel@tonic-gate  * The PTE value can be specified as the -p option, since on a 32 bit kernel
2680Sstevel@tonic-gate  * with PAE running it's larger than a uintptr_t.
2690Sstevel@tonic-gate  */
2700Sstevel@tonic-gate static int
2710Sstevel@tonic-gate do_pte_dcmd(int level, uint64_t pte)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate 	static char *attr[] = {
2740Sstevel@tonic-gate 	    "wrback", "wrthru", "uncached", "uncached",
2750Sstevel@tonic-gate 	    "wrback", "wrthru", "wrcombine", "uncached"};
2760Sstevel@tonic-gate 	int pat_index = 0;
277*3446Smrj 	pfn_t mfn;
2780Sstevel@tonic-gate 
279*3446Smrj 	mdb_printf("pte=%llr: ", pte);
2800Sstevel@tonic-gate 	if (PTE_GET(pte, mmu.pt_nx))
2810Sstevel@tonic-gate 		mdb_printf("noexec ");
2820Sstevel@tonic-gate 
283*3446Smrj 	mfn = pte2mfn(pte, level);
284*3446Smrj 	mdb_printf("%s=0x%lr ", "pfn", mfn);
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOCONSIST))
2870Sstevel@tonic-gate 		mdb_printf("noconsist ");
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOSYNC))
2900Sstevel@tonic-gate 		mdb_printf("nosync ");
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	if (PTE_GET(pte, mmu.pt_global))
2930Sstevel@tonic-gate 		mdb_printf("global ");
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
2960Sstevel@tonic-gate 		mdb_printf("largepage ");
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_MOD))
2990Sstevel@tonic-gate 		mdb_printf("mod ");
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_REF))
3020Sstevel@tonic-gate 		mdb_printf("ref ");
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	if (PTE_GET(pte, PT_USER))
3050Sstevel@tonic-gate 		mdb_printf("user ");
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	if (PTE_GET(pte, PT_WRITABLE))
3080Sstevel@tonic-gate 		mdb_printf("write ");
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	/*
3110Sstevel@tonic-gate 	 * Report non-standard cacheability
3120Sstevel@tonic-gate 	 */
3130Sstevel@tonic-gate 	pat_index = 0;
3140Sstevel@tonic-gate 	if (level > 0) {
3150Sstevel@tonic-gate 		if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE))
3160Sstevel@tonic-gate 			pat_index += 4;
3170Sstevel@tonic-gate 	} else {
3180Sstevel@tonic-gate 		if (PTE_GET(pte, PT_PAT_4K))
3190Sstevel@tonic-gate 			pat_index += 4;
3200Sstevel@tonic-gate 	}
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOCACHE))
3230Sstevel@tonic-gate 		pat_index += 2;
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	if (PTE_GET(pte, PT_WRITETHRU))
3260Sstevel@tonic-gate 		pat_index += 1;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	if (pat_index != 0)
3290Sstevel@tonic-gate 		mdb_printf("%s", attr[pat_index]);
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	if (PTE_GET(pte, PT_VALID) == 0)
3320Sstevel@tonic-gate 		mdb_printf(" !VALID ");
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	mdb_printf("\n");
3350Sstevel@tonic-gate 	return (DCMD_OK);
3360Sstevel@tonic-gate }
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate /*
3390Sstevel@tonic-gate  * Print a PTE in more human friendly way. The PTE is assumed to be in
3400Sstevel@tonic-gate  * a level 0 page table, unless -l specifies another level.
3410Sstevel@tonic-gate  *
3420Sstevel@tonic-gate  * The PTE value can be specified as the -p option, since on a 32 bit kernel
3430Sstevel@tonic-gate  * with PAE running it's larger than a uintptr_t.
3440Sstevel@tonic-gate  */
3450Sstevel@tonic-gate /*ARGSUSED*/
3460Sstevel@tonic-gate int
3470Sstevel@tonic-gate pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3480Sstevel@tonic-gate {
3490Sstevel@tonic-gate 	int level = 0;
3500Sstevel@tonic-gate 	uint64_t pte = 0;
3510Sstevel@tonic-gate 	char *level_str = NULL;
3520Sstevel@tonic-gate 	char *pte_str = NULL;
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	/*
3550Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
3560Sstevel@tonic-gate 	 */
3570Sstevel@tonic-gate 	get_mmu();
3580Sstevel@tonic-gate 	if (mmu.num_level == 0)
3590Sstevel@tonic-gate 		return (DCMD_ERR);
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
3620Sstevel@tonic-gate 	    'p', MDB_OPT_STR, &pte_str,
3630Sstevel@tonic-gate 	    'l', MDB_OPT_STR, &level_str) != argc)
3640Sstevel@tonic-gate 		return (DCMD_USAGE);
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	/*
3670Sstevel@tonic-gate 	 * parse the PTE to decode, if it's 0, we don't do anything
3680Sstevel@tonic-gate 	 */
3690Sstevel@tonic-gate 	if (pte_str != NULL) {
3700Sstevel@tonic-gate 		pte = mdb_strtoull(pte_str);
3710Sstevel@tonic-gate 	} else {
3720Sstevel@tonic-gate 		if ((flags & DCMD_ADDRSPEC) == 0)
3730Sstevel@tonic-gate 			return (DCMD_USAGE);
3740Sstevel@tonic-gate 		pte = addr;
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate 	if (pte == 0)
3770Sstevel@tonic-gate 		return (DCMD_OK);
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	/*
3800Sstevel@tonic-gate 	 * parse the level if supplied
3810Sstevel@tonic-gate 	 */
3820Sstevel@tonic-gate 	if (level_str != NULL) {
3830Sstevel@tonic-gate 		level = mdb_strtoull(level_str);
3840Sstevel@tonic-gate 		if (level < 0 || level > mmu.max_level)
3850Sstevel@tonic-gate 			return (DCMD_ERR);
3860Sstevel@tonic-gate 	}
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	return (do_pte_dcmd(level, pte));
3890Sstevel@tonic-gate }
3900Sstevel@tonic-gate 
391*3446Smrj static size_t
392*3446Smrj va2entry(htable_t *htable, uintptr_t addr)
393*3446Smrj {
394*3446Smrj 	size_t entry = (addr - htable->ht_vaddr);
395*3446Smrj 
396*3446Smrj 	entry >>= mmu.level_shift[htable->ht_level];
397*3446Smrj 	return (entry & HTABLE_NUM_PTES(htable) - 1);
398*3446Smrj }
399*3446Smrj 
400*3446Smrj static x86pte_t
401*3446Smrj get_pte(hat_t *hat, htable_t *htable, uintptr_t addr)
402*3446Smrj {
403*3446Smrj 	x86pte_t buf;
404*3446Smrj 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
405*3446Smrj 	size_t len;
406*3446Smrj 
407*3446Smrj 	if (htable->ht_flags & HTABLE_VLP) {
408*3446Smrj 		uintptr_t ptr = (uintptr_t)hat->hat_vlp_ptes;
409*3446Smrj 		ptr += va2entry(htable, addr) << mmu.pte_size_shift;
410*3446Smrj 		len = mdb_vread(&buf, mmu.pte_size, ptr);
411*3446Smrj 	} else {
412*3446Smrj 		paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn);
413*3446Smrj 		paddr += va2entry(htable, addr) << mmu.pte_size_shift;
414*3446Smrj 		len = mdb_pread(&buf, mmu.pte_size, paddr);
415*3446Smrj 	}
416*3446Smrj 
417*3446Smrj 	if (len != mmu.pte_size)
418*3446Smrj 		return (0);
419*3446Smrj 
420*3446Smrj 	if (mmu.pte_size == sizeof (x86pte_t))
421*3446Smrj 		return (buf);
422*3446Smrj 	return (*pte32);
423*3446Smrj }
424*3446Smrj 
4250Sstevel@tonic-gate static int
426*3446Smrj do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap,
427*3446Smrj     pfn_t *mfnp)
4280Sstevel@tonic-gate {
4290Sstevel@tonic-gate 	struct as as;
4300Sstevel@tonic-gate 	struct hat *hatp;
4310Sstevel@tonic-gate 	struct hat hat;
4320Sstevel@tonic-gate 	htable_t *ht;
4330Sstevel@tonic-gate 	htable_t htable;
4340Sstevel@tonic-gate 	uintptr_t base;
4350Sstevel@tonic-gate 	int h;
4360Sstevel@tonic-gate 	int level;
4370Sstevel@tonic-gate 	int found = 0;
4380Sstevel@tonic-gate 	x86pte_t pte;
4390Sstevel@tonic-gate 	physaddr_t paddr;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	if (asp != NULL) {
4420Sstevel@tonic-gate 		if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
4430Sstevel@tonic-gate 			mdb_warn("Couldn't read struct as\n");
4440Sstevel@tonic-gate 			return (DCMD_ERR);
4450Sstevel@tonic-gate 		}
4460Sstevel@tonic-gate 		hatp = as.a_hat;
4470Sstevel@tonic-gate 	} else {
4480Sstevel@tonic-gate 		hatp = khat;
4490Sstevel@tonic-gate 	}
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	/*
4520Sstevel@tonic-gate 	 * read the hat and its hash table
4530Sstevel@tonic-gate 	 */
4540Sstevel@tonic-gate 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
4550Sstevel@tonic-gate 		mdb_warn("Couldn't read struct hat\n");
4560Sstevel@tonic-gate 		return (DCMD_ERR);
4570Sstevel@tonic-gate 	}
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	/*
4600Sstevel@tonic-gate 	 * read the htable hashtable
4610Sstevel@tonic-gate 	 */
4620Sstevel@tonic-gate 	for (level = 0; level <= mmu.max_level; ++level) {
463*3446Smrj 		if (level == TOP_LEVEL(&hat))
4640Sstevel@tonic-gate 			base = 0;
4650Sstevel@tonic-gate 		else
4660Sstevel@tonic-gate 			base = addr & mmu.level_mask[level + 1];
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
4690Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
4700Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
4710Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
4720Sstevel@tonic-gate 				return (DCMD_ERR);
4730Sstevel@tonic-gate 			}
4740Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
4750Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
4760Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
4770Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
4780Sstevel@tonic-gate 					return (DCMD_ERR);
4790Sstevel@tonic-gate 				}
480*3446Smrj 
4810Sstevel@tonic-gate 				if (htable.ht_vaddr != base ||
4820Sstevel@tonic-gate 				    htable.ht_level != level)
4830Sstevel@tonic-gate 					continue;
4840Sstevel@tonic-gate 
485*3446Smrj 				pte = get_pte(&hat, &htable, addr);
486*3446Smrj 
487*3446Smrj 				if (print_level) {
488*3446Smrj 					mdb_printf("\tlevel=%d htable=%p "
489*3446Smrj 					    "pte=%llr\n", level, ht, pte);
490*3446Smrj 				}
491*3446Smrj 
492*3446Smrj 				if (!PTE_ISVALID(pte)) {
493*3446Smrj 					mdb_printf("Address %p is unmapped.\n",
494*3446Smrj 					    addr);
4950Sstevel@tonic-gate 					return (DCMD_ERR);
496*3446Smrj 				}
497*3446Smrj 
498*3446Smrj 				if (found)
499*3446Smrj 					continue;
500*3446Smrj 
501*3446Smrj 				if (PTE_IS_LGPG(pte, level))
502*3446Smrj 					paddr = mdb_ma_to_pa(pte &
503*3446Smrj 					    PT_PADDR_LGPG);
5040Sstevel@tonic-gate 				else
505*3446Smrj 					paddr = mdb_ma_to_pa(pte & PT_PADDR);
506*3446Smrj 				paddr += addr & mmu.level_offset[level];
507*3446Smrj 				if (pap != NULL)
5080Sstevel@tonic-gate 					*pap = paddr;
509*3446Smrj 				if (mfnp != NULL)
510*3446Smrj 					*mfnp = pte2mfn(pte, level);
511*3446Smrj 				found = 1;
5120Sstevel@tonic-gate 			}
5130Sstevel@tonic-gate 		}
5140Sstevel@tonic-gate 	}
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate done:
5170Sstevel@tonic-gate 	if (!found)
5180Sstevel@tonic-gate 		return (DCMD_ERR);
5190Sstevel@tonic-gate 	return (DCMD_OK);
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate int
5230Sstevel@tonic-gate va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5240Sstevel@tonic-gate {
5250Sstevel@tonic-gate 	uintptr_t addrspace;
5260Sstevel@tonic-gate 	char *addrspace_str = NULL;
527*3446Smrj 	int piped = flags & DCMD_PIPE_OUT;
528*3446Smrj 	pfn_t pfn;
529*3446Smrj 	pfn_t mfn;
5300Sstevel@tonic-gate 	int rc;
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	/*
5330Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
5340Sstevel@tonic-gate 	 */
5350Sstevel@tonic-gate 	get_mmu();
5360Sstevel@tonic-gate 	if (mmu.num_level == 0)
5370Sstevel@tonic-gate 		return (DCMD_ERR);
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
5400Sstevel@tonic-gate 	    'a', MDB_OPT_STR, &addrspace_str) != argc)
5410Sstevel@tonic-gate 		return (DCMD_USAGE);
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
5440Sstevel@tonic-gate 		return (DCMD_USAGE);
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	/*
5470Sstevel@tonic-gate 	 * parse the address space
5480Sstevel@tonic-gate 	 */
5490Sstevel@tonic-gate 	if (addrspace_str != NULL)
5500Sstevel@tonic-gate 		addrspace = mdb_strtoull(addrspace_str);
5510Sstevel@tonic-gate 	else
5520Sstevel@tonic-gate 		addrspace = 0;
5530Sstevel@tonic-gate 
554*3446Smrj 	rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn);
555*3446Smrj 
556*3446Smrj 	if (rc != DCMD_OK)
557*3446Smrj 		return (rc);
558*3446Smrj 
559*3446Smrj 	if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) {
560*3446Smrj 		mdb_warn("Invalid mfn %lr\n", mfn);
561*3446Smrj 		return (DCMD_ERR);
562*3446Smrj 	}
5630Sstevel@tonic-gate 
564*3446Smrj 	if (piped) {
565*3446Smrj 		mdb_printf("0x%lr\n", pfn);
566*3446Smrj 		return (DCMD_OK);
567*3446Smrj 	}
5680Sstevel@tonic-gate 
569*3446Smrj 	mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn);
570*3446Smrj 
571*3446Smrj 	mdb_printf("\n");
572*3446Smrj 
573*3446Smrj 	return (DCMD_OK);
5740Sstevel@tonic-gate }
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate /*
5770Sstevel@tonic-gate  * Report all hat's that either use PFN as a page table or that map the page.
5780Sstevel@tonic-gate  */
5790Sstevel@tonic-gate static int
5800Sstevel@tonic-gate do_report_maps(pfn_t pfn)
5810Sstevel@tonic-gate {
5821747Sjosephb 	struct hat *hatp;
5830Sstevel@tonic-gate 	struct hat hat;
5840Sstevel@tonic-gate 	htable_t *ht;
5850Sstevel@tonic-gate 	htable_t htable;
5860Sstevel@tonic-gate 	uintptr_t base;
5870Sstevel@tonic-gate 	int h;
5880Sstevel@tonic-gate 	int level;
5890Sstevel@tonic-gate 	int entry;
5900Sstevel@tonic-gate 	x86pte_t pte;
5910Sstevel@tonic-gate 	x86pte_t buf;
5920Sstevel@tonic-gate 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
5930Sstevel@tonic-gate 	physaddr_t paddr;
5940Sstevel@tonic-gate 	size_t len;
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	/*
5971747Sjosephb 	 * The hats are kept in a list with khat at the head.
5980Sstevel@tonic-gate 	 */
5991747Sjosephb 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
6000Sstevel@tonic-gate 		/*
6010Sstevel@tonic-gate 		 * read the hat and its hash table
6020Sstevel@tonic-gate 		 */
6030Sstevel@tonic-gate 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
6040Sstevel@tonic-gate 			mdb_warn("Couldn't read struct hat\n");
6050Sstevel@tonic-gate 			return (DCMD_ERR);
6060Sstevel@tonic-gate 		}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 		/*
6090Sstevel@tonic-gate 		 * read the htable hashtable
6100Sstevel@tonic-gate 		 */
6110Sstevel@tonic-gate 		paddr = 0;
6120Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
6130Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
6140Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
6150Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
6160Sstevel@tonic-gate 				return (DCMD_ERR);
6170Sstevel@tonic-gate 			}
6180Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
6190Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
6200Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
6210Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
6220Sstevel@tonic-gate 					return (DCMD_ERR);
6230Sstevel@tonic-gate 				}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 				/*
6260Sstevel@tonic-gate 				 * only report kernel addresses once
6270Sstevel@tonic-gate 				 */
6280Sstevel@tonic-gate 				if (hatp != khat &&
6290Sstevel@tonic-gate 				    htable.ht_vaddr >= kernelbase)
6300Sstevel@tonic-gate 					continue;
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 				/*
6330Sstevel@tonic-gate 				 * Is the PFN a pagetable itself?
6340Sstevel@tonic-gate 				 */
6350Sstevel@tonic-gate 				if (htable.ht_pfn == pfn) {
6360Sstevel@tonic-gate 					mdb_printf("Pagetable for "
6370Sstevel@tonic-gate 					    "hat=%p htable=%p\n", hatp, ht);
6380Sstevel@tonic-gate 					continue;
6390Sstevel@tonic-gate 				}
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 				/*
6420Sstevel@tonic-gate 				 * otherwise, examine page mappings
6430Sstevel@tonic-gate 				 */
6440Sstevel@tonic-gate 				level = htable.ht_level;
6450Sstevel@tonic-gate 				if (level > mmu.max_page_level)
6460Sstevel@tonic-gate 					continue;
647*3446Smrj 				paddr = mmu_ptob((physaddr_t)htable.ht_pfn);
648*3446Smrj 				for (entry = 0;
649*3446Smrj 				    entry < HTABLE_NUM_PTES(&htable);
6500Sstevel@tonic-gate 				    ++entry) {
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 					base = htable.ht_vaddr + entry *
6530Sstevel@tonic-gate 					    mmu.level_size[level];
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 					/*
6560Sstevel@tonic-gate 					 * only report kernel addresses once
6570Sstevel@tonic-gate 					 */
6580Sstevel@tonic-gate 					if (hatp != khat &&
6590Sstevel@tonic-gate 					    base >= kernelbase)
6600Sstevel@tonic-gate 						continue;
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 					len = mdb_pread(&buf, mmu.pte_size,
6630Sstevel@tonic-gate 					    paddr + entry * mmu.pte_size);
6640Sstevel@tonic-gate 					if (len != mmu.pte_size)
6650Sstevel@tonic-gate 						return (DCMD_ERR);
6660Sstevel@tonic-gate 					if (mmu.pte_size == sizeof (x86pte_t))
6670Sstevel@tonic-gate 						pte = buf;
6680Sstevel@tonic-gate 					else
6690Sstevel@tonic-gate 						pte = *pte32;
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 					if ((pte & PT_VALID) == 0)
6720Sstevel@tonic-gate 						continue;
6730Sstevel@tonic-gate 					if (level == 0 || !(pte & PT_PAGESIZE))
6740Sstevel@tonic-gate 						pte &= PT_PADDR;
6750Sstevel@tonic-gate 					else
6760Sstevel@tonic-gate 						pte &= PT_PADDR_LGPG;
677*3446Smrj 					if (mmu_btop(mdb_ma_to_pa(pte)) != pfn)
6780Sstevel@tonic-gate 						continue;
6790Sstevel@tonic-gate 					mdb_printf("hat=%p maps addr=%p\n",
6800Sstevel@tonic-gate 						hatp, (caddr_t)base);
6810Sstevel@tonic-gate 				}
6820Sstevel@tonic-gate 			}
6830Sstevel@tonic-gate 		}
6840Sstevel@tonic-gate 	}
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate done:
6870Sstevel@tonic-gate 	return (DCMD_OK);
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate /*
6910Sstevel@tonic-gate  * given a PFN as its address argument, prints out the uses of it
6920Sstevel@tonic-gate  */
6930Sstevel@tonic-gate /*ARGSUSED*/
6940Sstevel@tonic-gate int
6950Sstevel@tonic-gate report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6960Sstevel@tonic-gate {
697*3446Smrj 	pfn_t pfn;
698*3446Smrj 	uint_t mflag = 0;
699*3446Smrj 
7000Sstevel@tonic-gate 	/*
7010Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
7020Sstevel@tonic-gate 	 */
7030Sstevel@tonic-gate 	get_mmu();
7040Sstevel@tonic-gate 	if (mmu.num_level == 0)
7050Sstevel@tonic-gate 		return (DCMD_ERR);
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
7080Sstevel@tonic-gate 		return (DCMD_USAGE);
7090Sstevel@tonic-gate 
710*3446Smrj 	if (mdb_getopts(argc, argv,
711*3446Smrj 	    'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
712*3446Smrj 		return (DCMD_USAGE);
713*3446Smrj 
714*3446Smrj 	pfn = (pfn_t)addr;
715*3446Smrj 	if (mflag)
716*3446Smrj 		pfn = mdb_mfn_to_pfn(pfn);
717*3446Smrj 
718*3446Smrj 	return (do_report_maps(pfn));
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate static int
7220Sstevel@tonic-gate do_ptable_dcmd(pfn_t pfn)
7230Sstevel@tonic-gate {
7241747Sjosephb 	struct hat *hatp;
7250Sstevel@tonic-gate 	struct hat hat;
7260Sstevel@tonic-gate 	htable_t *ht;
7270Sstevel@tonic-gate 	htable_t htable;
7280Sstevel@tonic-gate 	uintptr_t base;
7290Sstevel@tonic-gate 	int h;
7300Sstevel@tonic-gate 	int level;
7310Sstevel@tonic-gate 	int entry;
7320Sstevel@tonic-gate 	uintptr_t pagesize;
7330Sstevel@tonic-gate 	x86pte_t pte;
7340Sstevel@tonic-gate 	x86pte_t buf;
7350Sstevel@tonic-gate 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
7360Sstevel@tonic-gate 	physaddr_t paddr;
7370Sstevel@tonic-gate 	size_t len;
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	/*
7401747Sjosephb 	 * The hats are kept in a list with khat at the head.
7410Sstevel@tonic-gate 	 */
7421747Sjosephb 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
7430Sstevel@tonic-gate 		/*
7440Sstevel@tonic-gate 		 * read the hat and its hash table
7450Sstevel@tonic-gate 		 */
7460Sstevel@tonic-gate 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
7470Sstevel@tonic-gate 			mdb_warn("Couldn't read struct hat\n");
7480Sstevel@tonic-gate 			return (DCMD_ERR);
7490Sstevel@tonic-gate 		}
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 		/*
7520Sstevel@tonic-gate 		 * read the htable hashtable
7530Sstevel@tonic-gate 		 */
7540Sstevel@tonic-gate 		paddr = 0;
7550Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
7560Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
7570Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
7580Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
7590Sstevel@tonic-gate 				return (DCMD_ERR);
7600Sstevel@tonic-gate 			}
7610Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
7620Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
7630Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
7640Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
7650Sstevel@tonic-gate 					return (DCMD_ERR);
7660Sstevel@tonic-gate 				}
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 				/*
7690Sstevel@tonic-gate 				 * Is this the PFN for this htable
7700Sstevel@tonic-gate 				 */
7710Sstevel@tonic-gate 				if (htable.ht_pfn == pfn)
7720Sstevel@tonic-gate 					goto found_it;
7730Sstevel@tonic-gate 			}
7740Sstevel@tonic-gate 		}
7750Sstevel@tonic-gate 	}
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate found_it:
7780Sstevel@tonic-gate 	if (htable.ht_pfn == pfn) {
7790Sstevel@tonic-gate 		mdb_printf("htable=%p\n", ht);
7800Sstevel@tonic-gate 		level = htable.ht_level;
7810Sstevel@tonic-gate 		base = htable.ht_vaddr;
7820Sstevel@tonic-gate 		pagesize = mmu.level_size[level];
7830Sstevel@tonic-gate 	} else {
7840Sstevel@tonic-gate 		mdb_printf("Unknown pagetable - assuming level/addr 0");
7850Sstevel@tonic-gate 		level = 0;	/* assume level == 0 for PFN */
7860Sstevel@tonic-gate 		base = 0;
7870Sstevel@tonic-gate 		pagesize = MMU_PAGESIZE;
7880Sstevel@tonic-gate 	}
7890Sstevel@tonic-gate 
790*3446Smrj 	paddr = mmu_ptob((physaddr_t)pfn);
7910Sstevel@tonic-gate 	for (entry = 0; entry < mmu.ptes_per_table; ++entry) {
7920Sstevel@tonic-gate 		len = mdb_pread(&buf, mmu.pte_size,
7930Sstevel@tonic-gate 		    paddr + entry * mmu.pte_size);
7940Sstevel@tonic-gate 		if (len != mmu.pte_size)
7950Sstevel@tonic-gate 			return (DCMD_ERR);
7960Sstevel@tonic-gate 		if (mmu.pte_size == sizeof (x86pte_t))
7970Sstevel@tonic-gate 			pte = buf;
7980Sstevel@tonic-gate 		else
7990Sstevel@tonic-gate 			pte = *pte32;
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 		if (pte == 0)
8020Sstevel@tonic-gate 			continue;
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 		mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize);
8050Sstevel@tonic-gate 		do_pte_dcmd(level, pte);
8060Sstevel@tonic-gate 	}
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate done:
8090Sstevel@tonic-gate 	return (DCMD_OK);
8100Sstevel@tonic-gate }
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate /*
813*3446Smrj  * Dump the page table at the given PFN
8140Sstevel@tonic-gate  */
8150Sstevel@tonic-gate /*ARGSUSED*/
8160Sstevel@tonic-gate int
8170Sstevel@tonic-gate ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
8180Sstevel@tonic-gate {
819*3446Smrj 	pfn_t pfn;
820*3446Smrj 	uint_t mflag = 0;
821*3446Smrj 
8220Sstevel@tonic-gate 	/*
8230Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
8240Sstevel@tonic-gate 	 */
8250Sstevel@tonic-gate 	get_mmu();
8260Sstevel@tonic-gate 	if (mmu.num_level == 0)
8270Sstevel@tonic-gate 		return (DCMD_ERR);
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
8300Sstevel@tonic-gate 		return (DCMD_USAGE);
8310Sstevel@tonic-gate 
832*3446Smrj 	if (mdb_getopts(argc, argv,
833*3446Smrj 	    'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
834*3446Smrj 		return (DCMD_USAGE);
835*3446Smrj 
836*3446Smrj 	pfn = (pfn_t)addr;
837*3446Smrj 	if (mflag)
838*3446Smrj 		pfn = mdb_mfn_to_pfn(pfn);
839*3446Smrj 
840*3446Smrj 	return (do_ptable_dcmd(pfn));
8410Sstevel@tonic-gate }
842*3446Smrj 
843*3446Smrj static int
844*3446Smrj do_htables_dcmd(hat_t *hatp)
845*3446Smrj {
846*3446Smrj 	struct hat hat;
847*3446Smrj 	htable_t *ht;
848*3446Smrj 	htable_t htable;
849*3446Smrj 	int h;
850*3446Smrj 
851*3446Smrj 	/*
852*3446Smrj 	 * read the hat and its hash table
853*3446Smrj 	 */
854*3446Smrj 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
855*3446Smrj 		mdb_warn("Couldn't read struct hat\n");
856*3446Smrj 		return (DCMD_ERR);
857*3446Smrj 	}
858*3446Smrj 
859*3446Smrj 	/*
860*3446Smrj 	 * read the htable hashtable
861*3446Smrj 	 */
862*3446Smrj 	for (h = 0; h < hat.hat_num_hash; ++h) {
863*3446Smrj 		if (mdb_vread(&ht, sizeof (htable_t *),
864*3446Smrj 		    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
865*3446Smrj 			mdb_warn("Couldn't read htable ptr\\n");
866*3446Smrj 			return (DCMD_ERR);
867*3446Smrj 		}
868*3446Smrj 		for (; ht != NULL; ht = htable.ht_next) {
869*3446Smrj 			mdb_printf("%p\n", ht);
870*3446Smrj 			if (mdb_vread(&htable, sizeof (htable_t),
871*3446Smrj 			    (uintptr_t)ht) == -1) {
872*3446Smrj 				mdb_warn("Couldn't read htable\n");
873*3446Smrj 				return (DCMD_ERR);
874*3446Smrj 			}
875*3446Smrj 		}
876*3446Smrj 	}
877*3446Smrj 	return (DCMD_OK);
878*3446Smrj }
879*3446Smrj 
880*3446Smrj /*
881*3446Smrj  * Dump the htables for the given hat
882*3446Smrj  */
883*3446Smrj /*ARGSUSED*/
884*3446Smrj int
885*3446Smrj htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
886*3446Smrj {
887*3446Smrj 	hat_t *hat;
888*3446Smrj 
889*3446Smrj 	/*
890*3446Smrj 	 * The kernel has to at least have made it thru mmu_init()
891*3446Smrj 	 */
892*3446Smrj 	get_mmu();
893*3446Smrj 	if (mmu.num_level == 0)
894*3446Smrj 		return (DCMD_ERR);
895*3446Smrj 
896*3446Smrj 	if ((flags & DCMD_ADDRSPEC) == 0)
897*3446Smrj 		return (DCMD_USAGE);
898*3446Smrj 
899*3446Smrj 	hat = (hat_t *)addr;
900*3446Smrj 
901*3446Smrj 	return (do_htables_dcmd(hat));
902*3446Smrj }
903