xref: /onnv-gate/usr/src/cmd/mdb/i86pc/modules/unix/i86mmu.c (revision 11459:976cd2e02041)
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*11459SJonathan.Adams@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * This part of the file contains the mdb support for dcmds:
280Sstevel@tonic-gate  *	::memseg_list
290Sstevel@tonic-gate  * and walkers for:
300Sstevel@tonic-gate  *	memseg - a memseg list walker for ::memseg_list
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include <sys/types.h>
350Sstevel@tonic-gate #include <sys/machparam.h>
360Sstevel@tonic-gate #include <sys/controlregs.h>
373446Smrj #include <sys/mach_mmu.h>
385084Sjohnlev #ifdef __xpv
395084Sjohnlev #include <sys/hypervisor.h>
405084Sjohnlev #endif
410Sstevel@tonic-gate #include <vm/as.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
440Sstevel@tonic-gate #include <mdb/mdb_target.h>
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #include <vm/page.h>
470Sstevel@tonic-gate #include <vm/hat_i86.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate struct pfn2pp {
500Sstevel@tonic-gate 	pfn_t pfn;
510Sstevel@tonic-gate 	page_t *pp;
520Sstevel@tonic-gate };
530Sstevel@tonic-gate 
543446Smrj static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *);
555084Sjohnlev static void init_mmu(void);
560Sstevel@tonic-gate 
570Sstevel@tonic-gate int
platform_vtop(uintptr_t addr,struct as * asp,physaddr_t * pap)580Sstevel@tonic-gate platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
590Sstevel@tonic-gate {
600Sstevel@tonic-gate 	if (asp == NULL)
610Sstevel@tonic-gate 		return (DCMD_ERR);
620Sstevel@tonic-gate 
635084Sjohnlev 	init_mmu();
645084Sjohnlev 
650Sstevel@tonic-gate 	if (mmu.num_level == 0)
660Sstevel@tonic-gate 		return (DCMD_ERR);
670Sstevel@tonic-gate 
683446Smrj 	return (do_va2pa(addr, asp, 0, pap, NULL));
690Sstevel@tonic-gate }
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /*
720Sstevel@tonic-gate  * ::memseg_list dcmd and walker to implement it.
730Sstevel@tonic-gate  */
740Sstevel@tonic-gate /*ARGSUSED*/
750Sstevel@tonic-gate int
memseg_list(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)760Sstevel@tonic-gate memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
770Sstevel@tonic-gate {
780Sstevel@tonic-gate 	struct memseg ms;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
810Sstevel@tonic-gate 		if (mdb_pwalk_dcmd("memseg", "memseg_list",
820Sstevel@tonic-gate 		    0, NULL, 0) == -1) {
830Sstevel@tonic-gate 			mdb_warn("can't walk memseg");
840Sstevel@tonic-gate 			return (DCMD_ERR);
850Sstevel@tonic-gate 		}
860Sstevel@tonic-gate 		return (DCMD_OK);
870Sstevel@tonic-gate 	}
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
900Sstevel@tonic-gate 		mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
915084Sjohnlev 		    "PAGES", "EPAGES", "BASE", "END");
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
940Sstevel@tonic-gate 		mdb_warn("can't read memseg at %#lx", addr);
950Sstevel@tonic-gate 		return (DCMD_ERR);
960Sstevel@tonic-gate 	}
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr,
995084Sjohnlev 	    ms.pages, ms.epages, ms.pages_base, ms.pages_end);
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	return (DCMD_OK);
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /*
1050Sstevel@tonic-gate  * walk the memseg structures
1060Sstevel@tonic-gate  */
1070Sstevel@tonic-gate int
memseg_walk_init(mdb_walk_state_t * wsp)1080Sstevel@tonic-gate memseg_walk_init(mdb_walk_state_t *wsp)
1090Sstevel@tonic-gate {
1100Sstevel@tonic-gate 	if (wsp->walk_addr != NULL) {
1110Sstevel@tonic-gate 		mdb_warn("memseg only supports global walks\n");
1120Sstevel@tonic-gate 		return (WALK_ERR);
1130Sstevel@tonic-gate 	}
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
1160Sstevel@tonic-gate 		mdb_warn("symbol 'memsegs' not found");
1170Sstevel@tonic-gate 		return (WALK_ERR);
1180Sstevel@tonic-gate 	}
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
1210Sstevel@tonic-gate 	return (WALK_NEXT);
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate int
memseg_walk_step(mdb_walk_state_t * wsp)1260Sstevel@tonic-gate memseg_walk_step(mdb_walk_state_t *wsp)
1270Sstevel@tonic-gate {
1280Sstevel@tonic-gate 	int status;
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	if (wsp->walk_addr == 0) {
1310Sstevel@tonic-gate 		return (WALK_DONE);
1320Sstevel@tonic-gate 	}
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (struct memseg),
1350Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
1360Sstevel@tonic-gate 		mdb_warn("failed to read struct memseg at %p", wsp->walk_addr);
1370Sstevel@tonic-gate 		return (WALK_DONE);
1380Sstevel@tonic-gate 	}
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1410Sstevel@tonic-gate 	    wsp->walk_cbdata);
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	return (status);
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate void
memseg_walk_fini(mdb_walk_state_t * wsp)1490Sstevel@tonic-gate memseg_walk_fini(mdb_walk_state_t *wsp)
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct memseg));
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate /*
1553446Smrj  * Now HAT related dcmds.
1560Sstevel@tonic-gate  */
1570Sstevel@tonic-gate 
1585084Sjohnlev static struct hat *khat;		/* value of kas.a_hat */
1590Sstevel@tonic-gate struct hat_mmu_info mmu;
1600Sstevel@tonic-gate uintptr_t kernelbase;
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate /*
1635084Sjohnlev  * stuff for i86xpv images
1645084Sjohnlev  */
1655084Sjohnlev static int is_xpv;
1665084Sjohnlev static uintptr_t mfn_list_addr; /* kernel MFN list address */
1675084Sjohnlev uintptr_t xen_virt_start; /* address of mfn_to_pfn[] table */
1685084Sjohnlev ulong_t mfn_count;	/* number of pfn's in the MFN list */
1695084Sjohnlev pfn_t *mfn_list;	/* local MFN list copy */
1705084Sjohnlev 
1715084Sjohnlev /*
1720Sstevel@tonic-gate  * read mmu parameters from kernel
1730Sstevel@tonic-gate  */
1740Sstevel@tonic-gate static void
init_mmu(void)1755084Sjohnlev init_mmu(void)
1760Sstevel@tonic-gate {
1770Sstevel@tonic-gate 	struct as kas;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	if (mmu.num_level != 0)
1800Sstevel@tonic-gate 		return;
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1)
1830Sstevel@tonic-gate 		mdb_warn("Can't use HAT information before mmu_init()\n");
1840Sstevel@tonic-gate 	if (mdb_readsym(&kas, sizeof (kas), "kas") == -1)
1850Sstevel@tonic-gate 		mdb_warn("Couldn't find kas - kernel's struct as\n");
1860Sstevel@tonic-gate 	if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1)
1870Sstevel@tonic-gate 		mdb_warn("Couldn't find kernelbase\n");
1880Sstevel@tonic-gate 	khat = kas.a_hat;
1895084Sjohnlev 
1905084Sjohnlev 	/*
1915084Sjohnlev 	 * Is this a paravirtualized domain image?
1925084Sjohnlev 	 */
1935084Sjohnlev 	if (mdb_readsym(&mfn_list_addr, sizeof (mfn_list_addr),
1945084Sjohnlev 	    "mfn_list") == -1 ||
1955084Sjohnlev 	    mdb_readsym(&xen_virt_start, sizeof (xen_virt_start),
1965084Sjohnlev 	    "xen_virt_start") == -1 ||
1975084Sjohnlev 	    mdb_readsym(&mfn_count, sizeof (mfn_count), "mfn_count") == -1) {
1985084Sjohnlev 		mfn_list_addr = NULL;
1995084Sjohnlev 	}
2005084Sjohnlev 
2015084Sjohnlev 	is_xpv = mfn_list_addr != NULL;
2025084Sjohnlev 
2035084Sjohnlev #ifndef _KMDB
2045084Sjohnlev 	/*
2055084Sjohnlev 	 * recreate the local mfn_list
2065084Sjohnlev 	 */
2075084Sjohnlev 	if (is_xpv) {
2085084Sjohnlev 		size_t sz = mfn_count * sizeof (pfn_t);
2095084Sjohnlev 		mfn_list = mdb_zalloc(sz, UM_SLEEP);
2105084Sjohnlev 
2115084Sjohnlev 		if (mdb_vread(mfn_list, sz, (uintptr_t)mfn_list_addr) == -1) {
2125084Sjohnlev 			mdb_warn("Failed to read MFN list\n");
2135084Sjohnlev 			mdb_free(mfn_list, sz);
2145084Sjohnlev 			mfn_list = NULL;
2155084Sjohnlev 		}
2165084Sjohnlev 	}
2175084Sjohnlev #endif
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate 
2205084Sjohnlev void
free_mmu(void)2215084Sjohnlev free_mmu(void)
2225084Sjohnlev {
2235084Sjohnlev #ifdef __xpv
2245084Sjohnlev 	if (mfn_list != NULL)
2255084Sjohnlev 		mdb_free(mfn_list, mfn_count * sizeof (mfn_t));
2265084Sjohnlev #endif
2275084Sjohnlev }
2285084Sjohnlev 
2295084Sjohnlev #ifdef __xpv
2305084Sjohnlev 
2315084Sjohnlev #ifdef _KMDB
2325084Sjohnlev 
2335084Sjohnlev /*
2345084Sjohnlev  * Convert between MFNs and PFNs.  Since we're in kmdb we can go directly
2355084Sjohnlev  * through the machine to phys mapping and the MFN list.
2365084Sjohnlev  */
2375084Sjohnlev 
2385084Sjohnlev pfn_t
mdb_mfn_to_pfn(mfn_t mfn)2395084Sjohnlev mdb_mfn_to_pfn(mfn_t mfn)
2405084Sjohnlev {
2415084Sjohnlev 	pfn_t pfn;
2425084Sjohnlev 	mfn_t tmp;
2435084Sjohnlev 	pfn_t *pfn_list;
2445084Sjohnlev 
2455084Sjohnlev 	if (mfn_list_addr == NULL)
2465084Sjohnlev 		return (-(pfn_t)1);
2475084Sjohnlev 
2485084Sjohnlev 	pfn_list = (pfn_t *)xen_virt_start;
2495084Sjohnlev 	if (mdb_vread(&pfn, sizeof (pfn), (uintptr_t)(pfn_list + mfn)) == -1)
2505084Sjohnlev 		return (-(pfn_t)1);
2515084Sjohnlev 
2525084Sjohnlev 	if (mdb_vread(&tmp, sizeof (tmp),
2535084Sjohnlev 	    (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
2545084Sjohnlev 		return (-(pfn_t)1);
2555084Sjohnlev 
2565084Sjohnlev 	if (pfn >= mfn_count || tmp != mfn)
2575084Sjohnlev 		return (-(pfn_t)1);
2585084Sjohnlev 
2595084Sjohnlev 	return (pfn);
2605084Sjohnlev }
2615084Sjohnlev 
2625084Sjohnlev mfn_t
mdb_pfn_to_mfn(pfn_t pfn)2635084Sjohnlev mdb_pfn_to_mfn(pfn_t pfn)
2645084Sjohnlev {
2655084Sjohnlev 	mfn_t mfn;
2665084Sjohnlev 
2675084Sjohnlev 	init_mmu();
2685084Sjohnlev 
2695084Sjohnlev 	if (mfn_list_addr == NULL || pfn >= mfn_count)
2705084Sjohnlev 		return (-(mfn_t)1);
2715084Sjohnlev 
2725084Sjohnlev 	if (mdb_vread(&mfn, sizeof (mfn),
2735084Sjohnlev 	    (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
2745084Sjohnlev 		return (-(mfn_t)1);
2755084Sjohnlev 
2765084Sjohnlev 	return (mfn);
2775084Sjohnlev }
2785084Sjohnlev 
2795084Sjohnlev #else /* _KMDB */
2805084Sjohnlev 
2815084Sjohnlev /*
2825084Sjohnlev  * Convert between MFNs and PFNs.  Since a crash dump doesn't include the
2835084Sjohnlev  * MFN->PFN translation table (it's part of the hypervisor, not our image)
2845084Sjohnlev  * we do the MFN->PFN translation by searching the PFN->MFN (mfn_list)
2855084Sjohnlev  * table, if it's there.
2865084Sjohnlev  */
2875084Sjohnlev 
2885084Sjohnlev pfn_t
mdb_mfn_to_pfn(mfn_t mfn)2895084Sjohnlev mdb_mfn_to_pfn(mfn_t mfn)
2905084Sjohnlev {
2915084Sjohnlev 	pfn_t pfn;
2925084Sjohnlev 
2935084Sjohnlev 	init_mmu();
2945084Sjohnlev 
2955084Sjohnlev 	if (mfn_list == NULL)
2965084Sjohnlev 		return (-(pfn_t)1);
2975084Sjohnlev 
2985084Sjohnlev 	for (pfn = 0; pfn < mfn_count; ++pfn) {
2995084Sjohnlev 		if (mfn_list[pfn] != mfn)
3005084Sjohnlev 			continue;
3015084Sjohnlev 		return (pfn);
3025084Sjohnlev 	}
3035084Sjohnlev 
3045084Sjohnlev 	return (-(pfn_t)1);
3055084Sjohnlev }
3065084Sjohnlev 
3075084Sjohnlev mfn_t
mdb_pfn_to_mfn(pfn_t pfn)3085084Sjohnlev mdb_pfn_to_mfn(pfn_t pfn)
3095084Sjohnlev {
3105084Sjohnlev 	init_mmu();
3115084Sjohnlev 
3125084Sjohnlev 	if (mfn_list == NULL || pfn >= mfn_count)
3135084Sjohnlev 		return (-(mfn_t)1);
3145084Sjohnlev 
3155084Sjohnlev 	return (mfn_list[pfn]);
3165084Sjohnlev }
3175084Sjohnlev 
3185084Sjohnlev #endif /* _KMDB */
3195084Sjohnlev 
3205084Sjohnlev static paddr_t
mdb_ma_to_pa(uint64_t ma)3215084Sjohnlev mdb_ma_to_pa(uint64_t ma)
3225084Sjohnlev {
3235084Sjohnlev 	pfn_t pfn = mdb_mfn_to_pfn(mmu_btop(ma));
3245084Sjohnlev 	if (pfn == -(pfn_t)1)
3255084Sjohnlev 		return (-(paddr_t)1);
3265084Sjohnlev 
3275084Sjohnlev 	return (mmu_ptob((paddr_t)pfn) | (ma & (MMU_PAGESIZE - 1)));
3285084Sjohnlev }
3295084Sjohnlev 
3305084Sjohnlev #else /* __xpv */
3315084Sjohnlev 
3323446Smrj #define	mdb_ma_to_pa(ma) (ma)
3333446Smrj #define	mdb_mfn_to_pfn(mfn) (mfn)
3343446Smrj #define	mdb_pfn_to_mfn(pfn) (pfn)
3353446Smrj 
3365084Sjohnlev #endif /* __xpv */
3375084Sjohnlev 
3385084Sjohnlev /*
3395084Sjohnlev  * ::mfntopfn dcmd translates hypervisor machine page number
3405084Sjohnlev  * to physical page number
3415084Sjohnlev  */
3425084Sjohnlev /*ARGSUSED*/
3435084Sjohnlev int
mfntopfn_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3445084Sjohnlev mfntopfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3455084Sjohnlev {
3465084Sjohnlev 	pfn_t pfn;
3475084Sjohnlev 
3485084Sjohnlev 	if ((flags & DCMD_ADDRSPEC) == 0) {
3495084Sjohnlev 		mdb_warn("MFN missing\n");
3505084Sjohnlev 		return (DCMD_USAGE);
3515084Sjohnlev 	}
3525084Sjohnlev 
3535084Sjohnlev 	if ((pfn = mdb_mfn_to_pfn((pfn_t)addr)) == -(pfn_t)1) {
3545084Sjohnlev 		mdb_warn("Invalid mfn %lr\n", (pfn_t)addr);
3555084Sjohnlev 		return (DCMD_ERR);
3565084Sjohnlev 	}
3575084Sjohnlev 
3585084Sjohnlev 	mdb_printf("%lr\n", pfn);
3595084Sjohnlev 
3605084Sjohnlev 	return (DCMD_OK);
3615084Sjohnlev }
3625084Sjohnlev 
3635084Sjohnlev /*
3645084Sjohnlev  * ::pfntomfn dcmd translates physical page number to
3655084Sjohnlev  * hypervisor machine page number
3665084Sjohnlev  */
3675084Sjohnlev /*ARGSUSED*/
3685084Sjohnlev int
pfntomfn_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3695084Sjohnlev pfntomfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3705084Sjohnlev {
3715084Sjohnlev 	pfn_t mfn;
3725084Sjohnlev 
3735084Sjohnlev 	if ((flags & DCMD_ADDRSPEC) == 0) {
3745084Sjohnlev 		mdb_warn("PFN missing\n");
3755084Sjohnlev 		return (DCMD_USAGE);
3765084Sjohnlev 	}
3775084Sjohnlev 
3785084Sjohnlev 	if ((mfn = mdb_pfn_to_mfn((pfn_t)addr)) == -(pfn_t)1) {
3795084Sjohnlev 		mdb_warn("Invalid pfn %lr\n", (pfn_t)addr);
3805084Sjohnlev 		return (DCMD_ABORT);
3815084Sjohnlev 	}
3825084Sjohnlev 
3835084Sjohnlev 	mdb_printf("%lr\n", mfn);
3845084Sjohnlev 
3855084Sjohnlev 	if (flags & DCMD_LOOP)
3865084Sjohnlev 		mdb_set_dot(addr + 1);
3875084Sjohnlev 	return (DCMD_OK);
3885084Sjohnlev }
3895084Sjohnlev 
3903446Smrj static pfn_t
pte2mfn(x86pte_t pte,uint_t level)3913446Smrj pte2mfn(x86pte_t pte, uint_t level)
3923446Smrj {
3933446Smrj 	pfn_t mfn;
3943446Smrj 	if (level > 0 && (pte & PT_PAGESIZE))
3953446Smrj 		mfn = mmu_btop(pte & PT_PADDR_LGPG);
3963446Smrj 	else
3973446Smrj 		mfn = mmu_btop(pte & PT_PADDR);
3983446Smrj 	return (mfn);
3993446Smrj }
4003446Smrj 
4010Sstevel@tonic-gate /*
4020Sstevel@tonic-gate  * Print a PTE in more human friendly way. The PTE is assumed to be in
4030Sstevel@tonic-gate  * a level 0 page table, unless -l specifies another level.
4040Sstevel@tonic-gate  *
4050Sstevel@tonic-gate  * The PTE value can be specified as the -p option, since on a 32 bit kernel
4060Sstevel@tonic-gate  * with PAE running it's larger than a uintptr_t.
4070Sstevel@tonic-gate  */
4080Sstevel@tonic-gate static int
do_pte_dcmd(int level,uint64_t pte)4090Sstevel@tonic-gate do_pte_dcmd(int level, uint64_t pte)
4100Sstevel@tonic-gate {
4110Sstevel@tonic-gate 	static char *attr[] = {
4120Sstevel@tonic-gate 	    "wrback", "wrthru", "uncached", "uncached",
4130Sstevel@tonic-gate 	    "wrback", "wrthru", "wrcombine", "uncached"};
4140Sstevel@tonic-gate 	int pat_index = 0;
4153446Smrj 	pfn_t mfn;
4160Sstevel@tonic-gate 
4173446Smrj 	mdb_printf("pte=%llr: ", pte);
4180Sstevel@tonic-gate 	if (PTE_GET(pte, mmu.pt_nx))
4190Sstevel@tonic-gate 		mdb_printf("noexec ");
4200Sstevel@tonic-gate 
4213446Smrj 	mfn = pte2mfn(pte, level);
4225084Sjohnlev 	mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn);
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOCONSIST))
4250Sstevel@tonic-gate 		mdb_printf("noconsist ");
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOSYNC))
4280Sstevel@tonic-gate 		mdb_printf("nosync ");
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	if (PTE_GET(pte, mmu.pt_global))
4310Sstevel@tonic-gate 		mdb_printf("global ");
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
4340Sstevel@tonic-gate 		mdb_printf("largepage ");
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_MOD))
4370Sstevel@tonic-gate 		mdb_printf("mod ");
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_REF))
4400Sstevel@tonic-gate 		mdb_printf("ref ");
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	if (PTE_GET(pte, PT_USER))
4430Sstevel@tonic-gate 		mdb_printf("user ");
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	if (PTE_GET(pte, PT_WRITABLE))
4460Sstevel@tonic-gate 		mdb_printf("write ");
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	/*
4490Sstevel@tonic-gate 	 * Report non-standard cacheability
4500Sstevel@tonic-gate 	 */
4510Sstevel@tonic-gate 	pat_index = 0;
4520Sstevel@tonic-gate 	if (level > 0) {
4530Sstevel@tonic-gate 		if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE))
4540Sstevel@tonic-gate 			pat_index += 4;
4550Sstevel@tonic-gate 	} else {
4560Sstevel@tonic-gate 		if (PTE_GET(pte, PT_PAT_4K))
4570Sstevel@tonic-gate 			pat_index += 4;
4580Sstevel@tonic-gate 	}
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOCACHE))
4610Sstevel@tonic-gate 		pat_index += 2;
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	if (PTE_GET(pte, PT_WRITETHRU))
4640Sstevel@tonic-gate 		pat_index += 1;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	if (pat_index != 0)
4670Sstevel@tonic-gate 		mdb_printf("%s", attr[pat_index]);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	if (PTE_GET(pte, PT_VALID) == 0)
4700Sstevel@tonic-gate 		mdb_printf(" !VALID ");
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	mdb_printf("\n");
4730Sstevel@tonic-gate 	return (DCMD_OK);
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate /*
4770Sstevel@tonic-gate  * Print a PTE in more human friendly way. The PTE is assumed to be in
4780Sstevel@tonic-gate  * a level 0 page table, unless -l specifies another level.
4790Sstevel@tonic-gate  *
4800Sstevel@tonic-gate  * The PTE value can be specified as the -p option, since on a 32 bit kernel
4810Sstevel@tonic-gate  * with PAE running it's larger than a uintptr_t.
4820Sstevel@tonic-gate  */
4830Sstevel@tonic-gate /*ARGSUSED*/
4840Sstevel@tonic-gate int
pte_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4850Sstevel@tonic-gate pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4860Sstevel@tonic-gate {
4870Sstevel@tonic-gate 	int level = 0;
4880Sstevel@tonic-gate 	uint64_t pte = 0;
4890Sstevel@tonic-gate 	char *level_str = NULL;
4900Sstevel@tonic-gate 	char *pte_str = NULL;
4910Sstevel@tonic-gate 
4925084Sjohnlev 	init_mmu();
4935084Sjohnlev 
4940Sstevel@tonic-gate 	if (mmu.num_level == 0)
4950Sstevel@tonic-gate 		return (DCMD_ERR);
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
4980Sstevel@tonic-gate 	    'p', MDB_OPT_STR, &pte_str,
4990Sstevel@tonic-gate 	    'l', MDB_OPT_STR, &level_str) != argc)
5000Sstevel@tonic-gate 		return (DCMD_USAGE);
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	/*
5030Sstevel@tonic-gate 	 * parse the PTE to decode, if it's 0, we don't do anything
5040Sstevel@tonic-gate 	 */
5050Sstevel@tonic-gate 	if (pte_str != NULL) {
5060Sstevel@tonic-gate 		pte = mdb_strtoull(pte_str);
5070Sstevel@tonic-gate 	} else {
5080Sstevel@tonic-gate 		if ((flags & DCMD_ADDRSPEC) == 0)
5090Sstevel@tonic-gate 			return (DCMD_USAGE);
5100Sstevel@tonic-gate 		pte = addr;
5110Sstevel@tonic-gate 	}
5120Sstevel@tonic-gate 	if (pte == 0)
5130Sstevel@tonic-gate 		return (DCMD_OK);
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	/*
5160Sstevel@tonic-gate 	 * parse the level if supplied
5170Sstevel@tonic-gate 	 */
5180Sstevel@tonic-gate 	if (level_str != NULL) {
5190Sstevel@tonic-gate 		level = mdb_strtoull(level_str);
5200Sstevel@tonic-gate 		if (level < 0 || level > mmu.max_level)
5210Sstevel@tonic-gate 			return (DCMD_ERR);
5220Sstevel@tonic-gate 	}
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	return (do_pte_dcmd(level, pte));
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate 
5273446Smrj static size_t
va2entry(htable_t * htable,uintptr_t addr)5283446Smrj va2entry(htable_t *htable, uintptr_t addr)
5293446Smrj {
5303446Smrj 	size_t entry = (addr - htable->ht_vaddr);
5313446Smrj 
5323446Smrj 	entry >>= mmu.level_shift[htable->ht_level];
5333446Smrj 	return (entry & HTABLE_NUM_PTES(htable) - 1);
5343446Smrj }
5353446Smrj 
5363446Smrj static x86pte_t
get_pte(hat_t * hat,htable_t * htable,uintptr_t addr)5373446Smrj get_pte(hat_t *hat, htable_t *htable, uintptr_t addr)
5383446Smrj {
5393446Smrj 	x86pte_t buf;
5403446Smrj 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
5413446Smrj 	size_t len;
5423446Smrj 
5433446Smrj 	if (htable->ht_flags & HTABLE_VLP) {
5443446Smrj 		uintptr_t ptr = (uintptr_t)hat->hat_vlp_ptes;
5453446Smrj 		ptr += va2entry(htable, addr) << mmu.pte_size_shift;
5463446Smrj 		len = mdb_vread(&buf, mmu.pte_size, ptr);
5473446Smrj 	} else {
5483446Smrj 		paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn);
5493446Smrj 		paddr += va2entry(htable, addr) << mmu.pte_size_shift;
5503446Smrj 		len = mdb_pread(&buf, mmu.pte_size, paddr);
5513446Smrj 	}
5523446Smrj 
5533446Smrj 	if (len != mmu.pte_size)
5543446Smrj 		return (0);
5553446Smrj 
5563446Smrj 	if (mmu.pte_size == sizeof (x86pte_t))
5573446Smrj 		return (buf);
5583446Smrj 	return (*pte32);
5593446Smrj }
5603446Smrj 
5610Sstevel@tonic-gate static int
do_va2pa(uintptr_t addr,struct as * asp,int print_level,physaddr_t * pap,pfn_t * mfnp)5623446Smrj do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap,
5633446Smrj     pfn_t *mfnp)
5640Sstevel@tonic-gate {
5650Sstevel@tonic-gate 	struct as as;
5660Sstevel@tonic-gate 	struct hat *hatp;
5670Sstevel@tonic-gate 	struct hat hat;
5680Sstevel@tonic-gate 	htable_t *ht;
5690Sstevel@tonic-gate 	htable_t htable;
5700Sstevel@tonic-gate 	uintptr_t base;
5710Sstevel@tonic-gate 	int h;
5720Sstevel@tonic-gate 	int level;
5730Sstevel@tonic-gate 	int found = 0;
5740Sstevel@tonic-gate 	x86pte_t pte;
5750Sstevel@tonic-gate 	physaddr_t paddr;
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	if (asp != NULL) {
5780Sstevel@tonic-gate 		if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
5790Sstevel@tonic-gate 			mdb_warn("Couldn't read struct as\n");
5800Sstevel@tonic-gate 			return (DCMD_ERR);
5810Sstevel@tonic-gate 		}
5820Sstevel@tonic-gate 		hatp = as.a_hat;
5830Sstevel@tonic-gate 	} else {
5840Sstevel@tonic-gate 		hatp = khat;
5850Sstevel@tonic-gate 	}
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	/*
5880Sstevel@tonic-gate 	 * read the hat and its hash table
5890Sstevel@tonic-gate 	 */
5900Sstevel@tonic-gate 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
5910Sstevel@tonic-gate 		mdb_warn("Couldn't read struct hat\n");
5920Sstevel@tonic-gate 		return (DCMD_ERR);
5930Sstevel@tonic-gate 	}
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	/*
5960Sstevel@tonic-gate 	 * read the htable hashtable
5970Sstevel@tonic-gate 	 */
5980Sstevel@tonic-gate 	for (level = 0; level <= mmu.max_level; ++level) {
5993446Smrj 		if (level == TOP_LEVEL(&hat))
6000Sstevel@tonic-gate 			base = 0;
6010Sstevel@tonic-gate 		else
6020Sstevel@tonic-gate 			base = addr & mmu.level_mask[level + 1];
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
6050Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
6060Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
6070Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
6080Sstevel@tonic-gate 				return (DCMD_ERR);
6090Sstevel@tonic-gate 			}
6100Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
6110Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
6120Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
6130Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
6140Sstevel@tonic-gate 					return (DCMD_ERR);
6150Sstevel@tonic-gate 				}
6163446Smrj 
6170Sstevel@tonic-gate 				if (htable.ht_vaddr != base ||
6180Sstevel@tonic-gate 				    htable.ht_level != level)
6190Sstevel@tonic-gate 					continue;
6200Sstevel@tonic-gate 
6213446Smrj 				pte = get_pte(&hat, &htable, addr);
6223446Smrj 
6233446Smrj 				if (print_level) {
6243446Smrj 					mdb_printf("\tlevel=%d htable=%p "
6253446Smrj 					    "pte=%llr\n", level, ht, pte);
6263446Smrj 				}
6273446Smrj 
6283446Smrj 				if (!PTE_ISVALID(pte)) {
6293446Smrj 					mdb_printf("Address %p is unmapped.\n",
6303446Smrj 					    addr);
6310Sstevel@tonic-gate 					return (DCMD_ERR);
6323446Smrj 				}
6333446Smrj 
6343446Smrj 				if (found)
6353446Smrj 					continue;
6363446Smrj 
6373446Smrj 				if (PTE_IS_LGPG(pte, level))
6383446Smrj 					paddr = mdb_ma_to_pa(pte &
6393446Smrj 					    PT_PADDR_LGPG);
6400Sstevel@tonic-gate 				else
6413446Smrj 					paddr = mdb_ma_to_pa(pte & PT_PADDR);
6423446Smrj 				paddr += addr & mmu.level_offset[level];
6433446Smrj 				if (pap != NULL)
6440Sstevel@tonic-gate 					*pap = paddr;
6453446Smrj 				if (mfnp != NULL)
6463446Smrj 					*mfnp = pte2mfn(pte, level);
6473446Smrj 				found = 1;
6480Sstevel@tonic-gate 			}
6490Sstevel@tonic-gate 		}
6500Sstevel@tonic-gate 	}
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate done:
6530Sstevel@tonic-gate 	if (!found)
6540Sstevel@tonic-gate 		return (DCMD_ERR);
6550Sstevel@tonic-gate 	return (DCMD_OK);
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate int
va2pfn_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)6590Sstevel@tonic-gate va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6600Sstevel@tonic-gate {
6610Sstevel@tonic-gate 	uintptr_t addrspace;
6620Sstevel@tonic-gate 	char *addrspace_str = NULL;
6633446Smrj 	int piped = flags & DCMD_PIPE_OUT;
6643446Smrj 	pfn_t pfn;
6653446Smrj 	pfn_t mfn;
6660Sstevel@tonic-gate 	int rc;
6670Sstevel@tonic-gate 
6685084Sjohnlev 	init_mmu();
6695084Sjohnlev 
6700Sstevel@tonic-gate 	if (mmu.num_level == 0)
6710Sstevel@tonic-gate 		return (DCMD_ERR);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
6740Sstevel@tonic-gate 	    'a', MDB_OPT_STR, &addrspace_str) != argc)
6750Sstevel@tonic-gate 		return (DCMD_USAGE);
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
6780Sstevel@tonic-gate 		return (DCMD_USAGE);
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	/*
6810Sstevel@tonic-gate 	 * parse the address space
6820Sstevel@tonic-gate 	 */
6830Sstevel@tonic-gate 	if (addrspace_str != NULL)
6840Sstevel@tonic-gate 		addrspace = mdb_strtoull(addrspace_str);
6850Sstevel@tonic-gate 	else
6860Sstevel@tonic-gate 		addrspace = 0;
6870Sstevel@tonic-gate 
6883446Smrj 	rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn);
6893446Smrj 
6903446Smrj 	if (rc != DCMD_OK)
6913446Smrj 		return (rc);
6923446Smrj 
6933446Smrj 	if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) {
6943446Smrj 		mdb_warn("Invalid mfn %lr\n", mfn);
6953446Smrj 		return (DCMD_ERR);
6963446Smrj 	}
6970Sstevel@tonic-gate 
6983446Smrj 	if (piped) {
6993446Smrj 		mdb_printf("0x%lr\n", pfn);
7003446Smrj 		return (DCMD_OK);
7013446Smrj 	}
7020Sstevel@tonic-gate 
7033446Smrj 	mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn);
7043446Smrj 
7055084Sjohnlev 	if (is_xpv)
7065084Sjohnlev 		mdb_printf(" (mfn 0x%lr)", mfn);
7075084Sjohnlev 
7083446Smrj 	mdb_printf("\n");
7093446Smrj 
7103446Smrj 	return (DCMD_OK);
7110Sstevel@tonic-gate }
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate /*
7140Sstevel@tonic-gate  * Report all hat's that either use PFN as a page table or that map the page.
7150Sstevel@tonic-gate  */
7160Sstevel@tonic-gate static int
do_report_maps(pfn_t pfn)7170Sstevel@tonic-gate do_report_maps(pfn_t pfn)
7180Sstevel@tonic-gate {
7191747Sjosephb 	struct hat *hatp;
7200Sstevel@tonic-gate 	struct hat hat;
7210Sstevel@tonic-gate 	htable_t *ht;
7220Sstevel@tonic-gate 	htable_t htable;
7230Sstevel@tonic-gate 	uintptr_t base;
7240Sstevel@tonic-gate 	int h;
7250Sstevel@tonic-gate 	int level;
7260Sstevel@tonic-gate 	int entry;
7270Sstevel@tonic-gate 	x86pte_t pte;
7280Sstevel@tonic-gate 	x86pte_t buf;
7290Sstevel@tonic-gate 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
7300Sstevel@tonic-gate 	physaddr_t paddr;
7310Sstevel@tonic-gate 	size_t len;
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	/*
7341747Sjosephb 	 * The hats are kept in a list with khat at the head.
7350Sstevel@tonic-gate 	 */
7361747Sjosephb 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
7370Sstevel@tonic-gate 		/*
7380Sstevel@tonic-gate 		 * read the hat and its hash table
7390Sstevel@tonic-gate 		 */
7400Sstevel@tonic-gate 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
7410Sstevel@tonic-gate 			mdb_warn("Couldn't read struct hat\n");
7420Sstevel@tonic-gate 			return (DCMD_ERR);
7430Sstevel@tonic-gate 		}
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 		/*
7460Sstevel@tonic-gate 		 * read the htable hashtable
7470Sstevel@tonic-gate 		 */
7480Sstevel@tonic-gate 		paddr = 0;
7490Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
7500Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
7510Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
7520Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
7530Sstevel@tonic-gate 				return (DCMD_ERR);
7540Sstevel@tonic-gate 			}
7550Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
7560Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
7570Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
7580Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
7590Sstevel@tonic-gate 					return (DCMD_ERR);
7600Sstevel@tonic-gate 				}
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 				/*
7630Sstevel@tonic-gate 				 * only report kernel addresses once
7640Sstevel@tonic-gate 				 */
7650Sstevel@tonic-gate 				if (hatp != khat &&
7660Sstevel@tonic-gate 				    htable.ht_vaddr >= kernelbase)
7670Sstevel@tonic-gate 					continue;
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 				/*
7700Sstevel@tonic-gate 				 * Is the PFN a pagetable itself?
7710Sstevel@tonic-gate 				 */
7720Sstevel@tonic-gate 				if (htable.ht_pfn == pfn) {
7730Sstevel@tonic-gate 					mdb_printf("Pagetable for "
7740Sstevel@tonic-gate 					    "hat=%p htable=%p\n", hatp, ht);
7750Sstevel@tonic-gate 					continue;
7760Sstevel@tonic-gate 				}
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 				/*
7790Sstevel@tonic-gate 				 * otherwise, examine page mappings
7800Sstevel@tonic-gate 				 */
7810Sstevel@tonic-gate 				level = htable.ht_level;
7820Sstevel@tonic-gate 				if (level > mmu.max_page_level)
7830Sstevel@tonic-gate 					continue;
7843446Smrj 				paddr = mmu_ptob((physaddr_t)htable.ht_pfn);
7853446Smrj 				for (entry = 0;
7863446Smrj 				    entry < HTABLE_NUM_PTES(&htable);
7870Sstevel@tonic-gate 				    ++entry) {
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 					base = htable.ht_vaddr + entry *
7900Sstevel@tonic-gate 					    mmu.level_size[level];
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 					/*
7930Sstevel@tonic-gate 					 * only report kernel addresses once
7940Sstevel@tonic-gate 					 */
7950Sstevel@tonic-gate 					if (hatp != khat &&
7960Sstevel@tonic-gate 					    base >= kernelbase)
7970Sstevel@tonic-gate 						continue;
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 					len = mdb_pread(&buf, mmu.pte_size,
8000Sstevel@tonic-gate 					    paddr + entry * mmu.pte_size);
8010Sstevel@tonic-gate 					if (len != mmu.pte_size)
8020Sstevel@tonic-gate 						return (DCMD_ERR);
8030Sstevel@tonic-gate 					if (mmu.pte_size == sizeof (x86pte_t))
8040Sstevel@tonic-gate 						pte = buf;
8050Sstevel@tonic-gate 					else
8060Sstevel@tonic-gate 						pte = *pte32;
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 					if ((pte & PT_VALID) == 0)
8090Sstevel@tonic-gate 						continue;
8100Sstevel@tonic-gate 					if (level == 0 || !(pte & PT_PAGESIZE))
8110Sstevel@tonic-gate 						pte &= PT_PADDR;
8120Sstevel@tonic-gate 					else
8130Sstevel@tonic-gate 						pte &= PT_PADDR_LGPG;
8143446Smrj 					if (mmu_btop(mdb_ma_to_pa(pte)) != pfn)
8150Sstevel@tonic-gate 						continue;
8160Sstevel@tonic-gate 					mdb_printf("hat=%p maps addr=%p\n",
8175084Sjohnlev 					    hatp, (caddr_t)base);
8180Sstevel@tonic-gate 				}
8190Sstevel@tonic-gate 			}
8200Sstevel@tonic-gate 		}
8210Sstevel@tonic-gate 	}
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate done:
8240Sstevel@tonic-gate 	return (DCMD_OK);
8250Sstevel@tonic-gate }
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate /*
8280Sstevel@tonic-gate  * given a PFN as its address argument, prints out the uses of it
8290Sstevel@tonic-gate  */
8300Sstevel@tonic-gate /*ARGSUSED*/
8310Sstevel@tonic-gate int
report_maps_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)8320Sstevel@tonic-gate report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
8330Sstevel@tonic-gate {
8343446Smrj 	pfn_t pfn;
8353446Smrj 	uint_t mflag = 0;
8363446Smrj 
8375084Sjohnlev 	init_mmu();
8385084Sjohnlev 
8390Sstevel@tonic-gate 	if (mmu.num_level == 0)
8400Sstevel@tonic-gate 		return (DCMD_ERR);
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
8430Sstevel@tonic-gate 		return (DCMD_USAGE);
8440Sstevel@tonic-gate 
8453446Smrj 	if (mdb_getopts(argc, argv,
8463446Smrj 	    'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
8473446Smrj 		return (DCMD_USAGE);
8483446Smrj 
8493446Smrj 	pfn = (pfn_t)addr;
8503446Smrj 	if (mflag)
8513446Smrj 		pfn = mdb_mfn_to_pfn(pfn);
8523446Smrj 
8533446Smrj 	return (do_report_maps(pfn));
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate static int
do_ptable_dcmd(pfn_t pfn)8570Sstevel@tonic-gate do_ptable_dcmd(pfn_t pfn)
8580Sstevel@tonic-gate {
8591747Sjosephb 	struct hat *hatp;
8600Sstevel@tonic-gate 	struct hat hat;
8610Sstevel@tonic-gate 	htable_t *ht;
8620Sstevel@tonic-gate 	htable_t htable;
8630Sstevel@tonic-gate 	uintptr_t base;
8640Sstevel@tonic-gate 	int h;
8650Sstevel@tonic-gate 	int level;
8660Sstevel@tonic-gate 	int entry;
8670Sstevel@tonic-gate 	uintptr_t pagesize;
8680Sstevel@tonic-gate 	x86pte_t pte;
8690Sstevel@tonic-gate 	x86pte_t buf;
8700Sstevel@tonic-gate 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
8710Sstevel@tonic-gate 	physaddr_t paddr;
8720Sstevel@tonic-gate 	size_t len;
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	/*
8751747Sjosephb 	 * The hats are kept in a list with khat at the head.
8760Sstevel@tonic-gate 	 */
8771747Sjosephb 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
8780Sstevel@tonic-gate 		/*
8790Sstevel@tonic-gate 		 * read the hat and its hash table
8800Sstevel@tonic-gate 		 */
8810Sstevel@tonic-gate 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
8820Sstevel@tonic-gate 			mdb_warn("Couldn't read struct hat\n");
8830Sstevel@tonic-gate 			return (DCMD_ERR);
8840Sstevel@tonic-gate 		}
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 		/*
8870Sstevel@tonic-gate 		 * read the htable hashtable
8880Sstevel@tonic-gate 		 */
8890Sstevel@tonic-gate 		paddr = 0;
8900Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
8910Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
8920Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
8930Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
8940Sstevel@tonic-gate 				return (DCMD_ERR);
8950Sstevel@tonic-gate 			}
8960Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
8970Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
8980Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
8990Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
9000Sstevel@tonic-gate 					return (DCMD_ERR);
9010Sstevel@tonic-gate 				}
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 				/*
9040Sstevel@tonic-gate 				 * Is this the PFN for this htable
9050Sstevel@tonic-gate 				 */
9060Sstevel@tonic-gate 				if (htable.ht_pfn == pfn)
9070Sstevel@tonic-gate 					goto found_it;
9080Sstevel@tonic-gate 			}
9090Sstevel@tonic-gate 		}
9100Sstevel@tonic-gate 	}
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate found_it:
9130Sstevel@tonic-gate 	if (htable.ht_pfn == pfn) {
9140Sstevel@tonic-gate 		mdb_printf("htable=%p\n", ht);
9150Sstevel@tonic-gate 		level = htable.ht_level;
9160Sstevel@tonic-gate 		base = htable.ht_vaddr;
9170Sstevel@tonic-gate 		pagesize = mmu.level_size[level];
9180Sstevel@tonic-gate 	} else {
9190Sstevel@tonic-gate 		mdb_printf("Unknown pagetable - assuming level/addr 0");
9200Sstevel@tonic-gate 		level = 0;	/* assume level == 0 for PFN */
9210Sstevel@tonic-gate 		base = 0;
9220Sstevel@tonic-gate 		pagesize = MMU_PAGESIZE;
9230Sstevel@tonic-gate 	}
9240Sstevel@tonic-gate 
9253446Smrj 	paddr = mmu_ptob((physaddr_t)pfn);
9260Sstevel@tonic-gate 	for (entry = 0; entry < mmu.ptes_per_table; ++entry) {
9270Sstevel@tonic-gate 		len = mdb_pread(&buf, mmu.pte_size,
9280Sstevel@tonic-gate 		    paddr + entry * mmu.pte_size);
9290Sstevel@tonic-gate 		if (len != mmu.pte_size)
9300Sstevel@tonic-gate 			return (DCMD_ERR);
9310Sstevel@tonic-gate 		if (mmu.pte_size == sizeof (x86pte_t))
9320Sstevel@tonic-gate 			pte = buf;
9330Sstevel@tonic-gate 		else
9340Sstevel@tonic-gate 			pte = *pte32;
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 		if (pte == 0)
9370Sstevel@tonic-gate 			continue;
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 		mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize);
9400Sstevel@tonic-gate 		do_pte_dcmd(level, pte);
9410Sstevel@tonic-gate 	}
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate done:
9440Sstevel@tonic-gate 	return (DCMD_OK);
9450Sstevel@tonic-gate }
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate /*
9483446Smrj  * Dump the page table at the given PFN
9490Sstevel@tonic-gate  */
9500Sstevel@tonic-gate /*ARGSUSED*/
9510Sstevel@tonic-gate int
ptable_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)9520Sstevel@tonic-gate ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
9530Sstevel@tonic-gate {
9543446Smrj 	pfn_t pfn;
9553446Smrj 	uint_t mflag = 0;
9563446Smrj 
9575084Sjohnlev 	init_mmu();
9585084Sjohnlev 
9590Sstevel@tonic-gate 	if (mmu.num_level == 0)
9600Sstevel@tonic-gate 		return (DCMD_ERR);
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
9630Sstevel@tonic-gate 		return (DCMD_USAGE);
9640Sstevel@tonic-gate 
9653446Smrj 	if (mdb_getopts(argc, argv,
9663446Smrj 	    'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
9673446Smrj 		return (DCMD_USAGE);
9683446Smrj 
9693446Smrj 	pfn = (pfn_t)addr;
9703446Smrj 	if (mflag)
9713446Smrj 		pfn = mdb_mfn_to_pfn(pfn);
9723446Smrj 
9733446Smrj 	return (do_ptable_dcmd(pfn));
9740Sstevel@tonic-gate }
9753446Smrj 
9763446Smrj static int
do_htables_dcmd(hat_t * hatp)9773446Smrj do_htables_dcmd(hat_t *hatp)
9783446Smrj {
9793446Smrj 	struct hat hat;
9803446Smrj 	htable_t *ht;
9813446Smrj 	htable_t htable;
9823446Smrj 	int h;
9833446Smrj 
9843446Smrj 	/*
9853446Smrj 	 * read the hat and its hash table
9863446Smrj 	 */
9873446Smrj 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
9883446Smrj 		mdb_warn("Couldn't read struct hat\n");
9893446Smrj 		return (DCMD_ERR);
9903446Smrj 	}
9913446Smrj 
9923446Smrj 	/*
9933446Smrj 	 * read the htable hashtable
9943446Smrj 	 */
9953446Smrj 	for (h = 0; h < hat.hat_num_hash; ++h) {
9963446Smrj 		if (mdb_vread(&ht, sizeof (htable_t *),
9973446Smrj 		    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
9983446Smrj 			mdb_warn("Couldn't read htable ptr\\n");
9993446Smrj 			return (DCMD_ERR);
10003446Smrj 		}
10013446Smrj 		for (; ht != NULL; ht = htable.ht_next) {
10023446Smrj 			mdb_printf("%p\n", ht);
10033446Smrj 			if (mdb_vread(&htable, sizeof (htable_t),
10043446Smrj 			    (uintptr_t)ht) == -1) {
10053446Smrj 				mdb_warn("Couldn't read htable\n");
10063446Smrj 				return (DCMD_ERR);
10073446Smrj 			}
10083446Smrj 		}
10093446Smrj 	}
10103446Smrj 	return (DCMD_OK);
10113446Smrj }
10123446Smrj 
10133446Smrj /*
10143446Smrj  * Dump the htables for the given hat
10153446Smrj  */
10163446Smrj /*ARGSUSED*/
10173446Smrj int
htables_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)10183446Smrj htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
10193446Smrj {
10203446Smrj 	hat_t *hat;
10213446Smrj 
10225084Sjohnlev 	init_mmu();
10235084Sjohnlev 
10243446Smrj 	if (mmu.num_level == 0)
10253446Smrj 		return (DCMD_ERR);
10263446Smrj 
10273446Smrj 	if ((flags & DCMD_ADDRSPEC) == 0)
10283446Smrj 		return (DCMD_USAGE);
10293446Smrj 
10303446Smrj 	hat = (hat_t *)addr;
10313446Smrj 
10323446Smrj 	return (do_htables_dcmd(hat));
10333446Smrj }
1034