xref: /onnv-gate/usr/src/cmd/mdb/i86pc/modules/unix/i86mmu.c (revision 5084:7d838c5c0eed)
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 /*
223446Smrj  * 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>
393446Smrj #include <sys/mach_mmu.h>
40*5084Sjohnlev #ifdef __xpv
41*5084Sjohnlev #include <sys/hypervisor.h>
42*5084Sjohnlev #endif
430Sstevel@tonic-gate #include <vm/as.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
460Sstevel@tonic-gate #include <mdb/mdb_target.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #include <vm/page.h>
490Sstevel@tonic-gate #include <vm/hat_i86.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate struct pfn2pp {
520Sstevel@tonic-gate 	pfn_t pfn;
530Sstevel@tonic-gate 	page_t *pp;
540Sstevel@tonic-gate };
550Sstevel@tonic-gate 
563446Smrj static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *);
57*5084Sjohnlev static void init_mmu(void);
580Sstevel@tonic-gate 
590Sstevel@tonic-gate int
600Sstevel@tonic-gate platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
610Sstevel@tonic-gate {
620Sstevel@tonic-gate 	if (asp == NULL)
630Sstevel@tonic-gate 		return (DCMD_ERR);
640Sstevel@tonic-gate 
65*5084Sjohnlev 	init_mmu();
66*5084Sjohnlev 
670Sstevel@tonic-gate 	if (mmu.num_level == 0)
680Sstevel@tonic-gate 		return (DCMD_ERR);
690Sstevel@tonic-gate 
703446Smrj 	return (do_va2pa(addr, asp, 0, pap, NULL));
710Sstevel@tonic-gate }
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 
740Sstevel@tonic-gate /*ARGSUSED*/
750Sstevel@tonic-gate int
760Sstevel@tonic-gate page_num2pp_cb(uintptr_t addr, void *ignored, uintptr_t *data)
770Sstevel@tonic-gate {
780Sstevel@tonic-gate 	struct memseg ms, *msp = &ms;
790Sstevel@tonic-gate 	struct pfn2pp *p = (struct pfn2pp *)data;
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	if (mdb_vread(msp, sizeof (struct memseg), addr) == -1) {
820Sstevel@tonic-gate 		mdb_warn("can't read memseg at %#lx", addr);
830Sstevel@tonic-gate 		return (DCMD_ERR);
840Sstevel@tonic-gate 	}
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	if (p->pfn >= msp->pages_base && p->pfn < msp->pages_end) {
870Sstevel@tonic-gate 		p->pp = msp->pages + (p->pfn - msp->pages_base);
880Sstevel@tonic-gate 		return (WALK_DONE);
890Sstevel@tonic-gate 	}
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	return (WALK_NEXT);
920Sstevel@tonic-gate }
930Sstevel@tonic-gate 
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate  * ::page_num2pp dcmd
960Sstevel@tonic-gate  */
970Sstevel@tonic-gate /*ARGSUSED*/
980Sstevel@tonic-gate int
990Sstevel@tonic-gate page_num2pp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1000Sstevel@tonic-gate {
1010Sstevel@tonic-gate 	struct pfn2pp pfn2pp;
1020Sstevel@tonic-gate 	page_t page;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0) {
1050Sstevel@tonic-gate 		mdb_warn("page frame number missing\n");
1060Sstevel@tonic-gate 			return (DCMD_USAGE);
1070Sstevel@tonic-gate 	}
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	pfn2pp.pfn = (pfn_t)addr;
1100Sstevel@tonic-gate 	pfn2pp.pp = NULL;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	if (mdb_walk("memseg", (mdb_walk_cb_t)page_num2pp_cb,
1130Sstevel@tonic-gate 	    (void *)&pfn2pp) == -1) {
1140Sstevel@tonic-gate 		mdb_warn("can't walk memseg");
1150Sstevel@tonic-gate 		return (DCMD_ERR);
1160Sstevel@tonic-gate 	}
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	if (pfn2pp.pp == NULL)
1190Sstevel@tonic-gate 		return (DCMD_ERR);
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	mdb_printf("%x has page at %p\n", pfn2pp.pfn, pfn2pp.pp);
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	if (mdb_vread(&page, sizeof (page_t),
1240Sstevel@tonic-gate 	    (uintptr_t)pfn2pp.pp) == -1) {
1250Sstevel@tonic-gate 		mdb_warn("can't read page at %p", &page);
1260Sstevel@tonic-gate 		return (DCMD_ERR);
1270Sstevel@tonic-gate 	}
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	if (page.p_pagenum != pfn2pp.pfn) {
1300Sstevel@tonic-gate 		mdb_warn("WARNING! Found page structure contains "
131*5084Sjohnlev 		    "different pagenumber %x\n", page.p_pagenum);
1320Sstevel@tonic-gate 	}
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	return (DCMD_OK);
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate  * ::memseg_list dcmd and walker to implement it.
1400Sstevel@tonic-gate  */
1410Sstevel@tonic-gate /*ARGSUSED*/
1420Sstevel@tonic-gate int
1430Sstevel@tonic-gate memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1440Sstevel@tonic-gate {
1450Sstevel@tonic-gate 	struct memseg ms;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
1480Sstevel@tonic-gate 		if (mdb_pwalk_dcmd("memseg", "memseg_list",
1490Sstevel@tonic-gate 		    0, NULL, 0) == -1) {
1500Sstevel@tonic-gate 			mdb_warn("can't walk memseg");
1510Sstevel@tonic-gate 			return (DCMD_ERR);
1520Sstevel@tonic-gate 		}
1530Sstevel@tonic-gate 		return (DCMD_OK);
1540Sstevel@tonic-gate 	}
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
1570Sstevel@tonic-gate 		mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
158*5084Sjohnlev 		    "PAGES", "EPAGES", "BASE", "END");
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
1610Sstevel@tonic-gate 		mdb_warn("can't read memseg at %#lx", addr);
1620Sstevel@tonic-gate 		return (DCMD_ERR);
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr,
166*5084Sjohnlev 	    ms.pages, ms.epages, ms.pages_base, ms.pages_end);
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	return (DCMD_OK);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate  * walk the memseg structures
1730Sstevel@tonic-gate  */
1740Sstevel@tonic-gate int
1750Sstevel@tonic-gate memseg_walk_init(mdb_walk_state_t *wsp)
1760Sstevel@tonic-gate {
1770Sstevel@tonic-gate 	if (wsp->walk_addr != NULL) {
1780Sstevel@tonic-gate 		mdb_warn("memseg only supports global walks\n");
1790Sstevel@tonic-gate 		return (WALK_ERR);
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
1830Sstevel@tonic-gate 		mdb_warn("symbol 'memsegs' not found");
1840Sstevel@tonic-gate 		return (WALK_ERR);
1850Sstevel@tonic-gate 	}
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
1880Sstevel@tonic-gate 	return (WALK_NEXT);
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate int
1930Sstevel@tonic-gate memseg_walk_step(mdb_walk_state_t *wsp)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate 	int status;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	if (wsp->walk_addr == 0) {
1980Sstevel@tonic-gate 		return (WALK_DONE);
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (struct memseg),
2020Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
2030Sstevel@tonic-gate 		mdb_warn("failed to read struct memseg at %p", wsp->walk_addr);
2040Sstevel@tonic-gate 		return (WALK_DONE);
2050Sstevel@tonic-gate 	}
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
2080Sstevel@tonic-gate 	    wsp->walk_cbdata);
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	return (status);
2130Sstevel@tonic-gate }
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate void
2160Sstevel@tonic-gate memseg_walk_fini(mdb_walk_state_t *wsp)
2170Sstevel@tonic-gate {
2180Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct memseg));
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate /*
2223446Smrj  * Now HAT related dcmds.
2230Sstevel@tonic-gate  */
2240Sstevel@tonic-gate 
225*5084Sjohnlev static struct hat *khat;		/* value of kas.a_hat */
2260Sstevel@tonic-gate struct hat_mmu_info mmu;
2270Sstevel@tonic-gate uintptr_t kernelbase;
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate /*
230*5084Sjohnlev  * stuff for i86xpv images
231*5084Sjohnlev  */
232*5084Sjohnlev static int is_xpv;
233*5084Sjohnlev static uintptr_t mfn_list_addr; /* kernel MFN list address */
234*5084Sjohnlev uintptr_t xen_virt_start; /* address of mfn_to_pfn[] table */
235*5084Sjohnlev ulong_t mfn_count;	/* number of pfn's in the MFN list */
236*5084Sjohnlev pfn_t *mfn_list;	/* local MFN list copy */
237*5084Sjohnlev 
238*5084Sjohnlev /*
2390Sstevel@tonic-gate  * read mmu parameters from kernel
2400Sstevel@tonic-gate  */
2410Sstevel@tonic-gate static void
242*5084Sjohnlev init_mmu(void)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	struct as kas;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	if (mmu.num_level != 0)
2470Sstevel@tonic-gate 		return;
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1)
2500Sstevel@tonic-gate 		mdb_warn("Can't use HAT information before mmu_init()\n");
2510Sstevel@tonic-gate 	if (mdb_readsym(&kas, sizeof (kas), "kas") == -1)
2520Sstevel@tonic-gate 		mdb_warn("Couldn't find kas - kernel's struct as\n");
2530Sstevel@tonic-gate 	if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1)
2540Sstevel@tonic-gate 		mdb_warn("Couldn't find kernelbase\n");
2550Sstevel@tonic-gate 	khat = kas.a_hat;
256*5084Sjohnlev 
257*5084Sjohnlev 	/*
258*5084Sjohnlev 	 * Is this a paravirtualized domain image?
259*5084Sjohnlev 	 */
260*5084Sjohnlev 	if (mdb_readsym(&mfn_list_addr, sizeof (mfn_list_addr),
261*5084Sjohnlev 	    "mfn_list") == -1 ||
262*5084Sjohnlev 	    mdb_readsym(&xen_virt_start, sizeof (xen_virt_start),
263*5084Sjohnlev 	    "xen_virt_start") == -1 ||
264*5084Sjohnlev 	    mdb_readsym(&mfn_count, sizeof (mfn_count), "mfn_count") == -1) {
265*5084Sjohnlev 		mfn_list_addr = NULL;
266*5084Sjohnlev 	}
267*5084Sjohnlev 
268*5084Sjohnlev 	is_xpv = mfn_list_addr != NULL;
269*5084Sjohnlev 
270*5084Sjohnlev #ifndef _KMDB
271*5084Sjohnlev 	/*
272*5084Sjohnlev 	 * recreate the local mfn_list
273*5084Sjohnlev 	 */
274*5084Sjohnlev 	if (is_xpv) {
275*5084Sjohnlev 		size_t sz = mfn_count * sizeof (pfn_t);
276*5084Sjohnlev 		mfn_list = mdb_zalloc(sz, UM_SLEEP);
277*5084Sjohnlev 
278*5084Sjohnlev 		if (mdb_vread(mfn_list, sz, (uintptr_t)mfn_list_addr) == -1) {
279*5084Sjohnlev 			mdb_warn("Failed to read MFN list\n");
280*5084Sjohnlev 			mdb_free(mfn_list, sz);
281*5084Sjohnlev 			mfn_list = NULL;
282*5084Sjohnlev 		}
283*5084Sjohnlev 	}
284*5084Sjohnlev #endif
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate 
287*5084Sjohnlev void
288*5084Sjohnlev free_mmu(void)
289*5084Sjohnlev {
290*5084Sjohnlev #ifdef __xpv
291*5084Sjohnlev 	if (mfn_list != NULL)
292*5084Sjohnlev 		mdb_free(mfn_list, mfn_count * sizeof (mfn_t));
293*5084Sjohnlev #endif
294*5084Sjohnlev }
295*5084Sjohnlev 
296*5084Sjohnlev #ifdef __xpv
297*5084Sjohnlev 
298*5084Sjohnlev #ifdef _KMDB
299*5084Sjohnlev 
300*5084Sjohnlev /*
301*5084Sjohnlev  * Convert between MFNs and PFNs.  Since we're in kmdb we can go directly
302*5084Sjohnlev  * through the machine to phys mapping and the MFN list.
303*5084Sjohnlev  */
304*5084Sjohnlev 
305*5084Sjohnlev pfn_t
306*5084Sjohnlev mdb_mfn_to_pfn(mfn_t mfn)
307*5084Sjohnlev {
308*5084Sjohnlev 	pfn_t pfn;
309*5084Sjohnlev 	mfn_t tmp;
310*5084Sjohnlev 	pfn_t *pfn_list;
311*5084Sjohnlev 
312*5084Sjohnlev 	if (mfn_list_addr == NULL)
313*5084Sjohnlev 		return (-(pfn_t)1);
314*5084Sjohnlev 
315*5084Sjohnlev 	pfn_list = (pfn_t *)xen_virt_start;
316*5084Sjohnlev 	if (mdb_vread(&pfn, sizeof (pfn), (uintptr_t)(pfn_list + mfn)) == -1)
317*5084Sjohnlev 		return (-(pfn_t)1);
318*5084Sjohnlev 
319*5084Sjohnlev 	if (mdb_vread(&tmp, sizeof (tmp),
320*5084Sjohnlev 	    (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
321*5084Sjohnlev 		return (-(pfn_t)1);
322*5084Sjohnlev 
323*5084Sjohnlev 	if (pfn >= mfn_count || tmp != mfn)
324*5084Sjohnlev 		return (-(pfn_t)1);
325*5084Sjohnlev 
326*5084Sjohnlev 	return (pfn);
327*5084Sjohnlev }
328*5084Sjohnlev 
329*5084Sjohnlev mfn_t
330*5084Sjohnlev mdb_pfn_to_mfn(pfn_t pfn)
331*5084Sjohnlev {
332*5084Sjohnlev 	mfn_t mfn;
333*5084Sjohnlev 
334*5084Sjohnlev 	init_mmu();
335*5084Sjohnlev 
336*5084Sjohnlev 	if (mfn_list_addr == NULL || pfn >= mfn_count)
337*5084Sjohnlev 		return (-(mfn_t)1);
338*5084Sjohnlev 
339*5084Sjohnlev 	if (mdb_vread(&mfn, sizeof (mfn),
340*5084Sjohnlev 	    (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
341*5084Sjohnlev 		return (-(mfn_t)1);
342*5084Sjohnlev 
343*5084Sjohnlev 	return (mfn);
344*5084Sjohnlev }
345*5084Sjohnlev 
346*5084Sjohnlev #else /* _KMDB */
347*5084Sjohnlev 
348*5084Sjohnlev /*
349*5084Sjohnlev  * Convert between MFNs and PFNs.  Since a crash dump doesn't include the
350*5084Sjohnlev  * MFN->PFN translation table (it's part of the hypervisor, not our image)
351*5084Sjohnlev  * we do the MFN->PFN translation by searching the PFN->MFN (mfn_list)
352*5084Sjohnlev  * table, if it's there.
353*5084Sjohnlev  */
354*5084Sjohnlev 
355*5084Sjohnlev pfn_t
356*5084Sjohnlev mdb_mfn_to_pfn(mfn_t mfn)
357*5084Sjohnlev {
358*5084Sjohnlev 	pfn_t pfn;
359*5084Sjohnlev 
360*5084Sjohnlev 	init_mmu();
361*5084Sjohnlev 
362*5084Sjohnlev 	if (mfn_list == NULL)
363*5084Sjohnlev 		return (-(pfn_t)1);
364*5084Sjohnlev 
365*5084Sjohnlev 	for (pfn = 0; pfn < mfn_count; ++pfn) {
366*5084Sjohnlev 		if (mfn_list[pfn] != mfn)
367*5084Sjohnlev 			continue;
368*5084Sjohnlev 		return (pfn);
369*5084Sjohnlev 	}
370*5084Sjohnlev 
371*5084Sjohnlev 	return (-(pfn_t)1);
372*5084Sjohnlev }
373*5084Sjohnlev 
374*5084Sjohnlev mfn_t
375*5084Sjohnlev mdb_pfn_to_mfn(pfn_t pfn)
376*5084Sjohnlev {
377*5084Sjohnlev 	init_mmu();
378*5084Sjohnlev 
379*5084Sjohnlev 	if (mfn_list == NULL || pfn >= mfn_count)
380*5084Sjohnlev 		return (-(mfn_t)1);
381*5084Sjohnlev 
382*5084Sjohnlev 	return (mfn_list[pfn]);
383*5084Sjohnlev }
384*5084Sjohnlev 
385*5084Sjohnlev #endif /* _KMDB */
386*5084Sjohnlev 
387*5084Sjohnlev static paddr_t
388*5084Sjohnlev mdb_ma_to_pa(uint64_t ma)
389*5084Sjohnlev {
390*5084Sjohnlev 	pfn_t pfn = mdb_mfn_to_pfn(mmu_btop(ma));
391*5084Sjohnlev 	if (pfn == -(pfn_t)1)
392*5084Sjohnlev 		return (-(paddr_t)1);
393*5084Sjohnlev 
394*5084Sjohnlev 	return (mmu_ptob((paddr_t)pfn) | (ma & (MMU_PAGESIZE - 1)));
395*5084Sjohnlev }
396*5084Sjohnlev 
397*5084Sjohnlev #else /* __xpv */
398*5084Sjohnlev 
3993446Smrj #define	mdb_ma_to_pa(ma) (ma)
4003446Smrj #define	mdb_mfn_to_pfn(mfn) (mfn)
4013446Smrj #define	mdb_pfn_to_mfn(pfn) (pfn)
4023446Smrj 
403*5084Sjohnlev #endif /* __xpv */
404*5084Sjohnlev 
405*5084Sjohnlev /*
406*5084Sjohnlev  * ::mfntopfn dcmd translates hypervisor machine page number
407*5084Sjohnlev  * to physical page number
408*5084Sjohnlev  */
409*5084Sjohnlev /*ARGSUSED*/
410*5084Sjohnlev int
411*5084Sjohnlev mfntopfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
412*5084Sjohnlev {
413*5084Sjohnlev 	pfn_t pfn;
414*5084Sjohnlev 
415*5084Sjohnlev 	if ((flags & DCMD_ADDRSPEC) == 0) {
416*5084Sjohnlev 		mdb_warn("MFN missing\n");
417*5084Sjohnlev 		return (DCMD_USAGE);
418*5084Sjohnlev 	}
419*5084Sjohnlev 
420*5084Sjohnlev 	if ((pfn = mdb_mfn_to_pfn((pfn_t)addr)) == -(pfn_t)1) {
421*5084Sjohnlev 		mdb_warn("Invalid mfn %lr\n", (pfn_t)addr);
422*5084Sjohnlev 		return (DCMD_ERR);
423*5084Sjohnlev 	}
424*5084Sjohnlev 
425*5084Sjohnlev 	mdb_printf("%lr\n", pfn);
426*5084Sjohnlev 
427*5084Sjohnlev 	return (DCMD_OK);
428*5084Sjohnlev }
429*5084Sjohnlev 
430*5084Sjohnlev /*
431*5084Sjohnlev  * ::pfntomfn dcmd translates physical page number to
432*5084Sjohnlev  * hypervisor machine page number
433*5084Sjohnlev  */
434*5084Sjohnlev /*ARGSUSED*/
435*5084Sjohnlev int
436*5084Sjohnlev pfntomfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
437*5084Sjohnlev {
438*5084Sjohnlev 	pfn_t mfn;
439*5084Sjohnlev 
440*5084Sjohnlev 	if ((flags & DCMD_ADDRSPEC) == 0) {
441*5084Sjohnlev 		mdb_warn("PFN missing\n");
442*5084Sjohnlev 		return (DCMD_USAGE);
443*5084Sjohnlev 	}
444*5084Sjohnlev 
445*5084Sjohnlev 	if ((mfn = mdb_pfn_to_mfn((pfn_t)addr)) == -(pfn_t)1) {
446*5084Sjohnlev 		mdb_warn("Invalid pfn %lr\n", (pfn_t)addr);
447*5084Sjohnlev 		return (DCMD_ABORT);
448*5084Sjohnlev 	}
449*5084Sjohnlev 
450*5084Sjohnlev 	mdb_printf("%lr\n", mfn);
451*5084Sjohnlev 
452*5084Sjohnlev 	if (flags & DCMD_LOOP)
453*5084Sjohnlev 		mdb_set_dot(addr + 1);
454*5084Sjohnlev 	return (DCMD_OK);
455*5084Sjohnlev }
456*5084Sjohnlev 
4573446Smrj static pfn_t
4583446Smrj pte2mfn(x86pte_t pte, uint_t level)
4593446Smrj {
4603446Smrj 	pfn_t mfn;
4613446Smrj 	if (level > 0 && (pte & PT_PAGESIZE))
4623446Smrj 		mfn = mmu_btop(pte & PT_PADDR_LGPG);
4633446Smrj 	else
4643446Smrj 		mfn = mmu_btop(pte & PT_PADDR);
4653446Smrj 	return (mfn);
4663446Smrj }
4673446Smrj 
4680Sstevel@tonic-gate /*
4690Sstevel@tonic-gate  * Print a PTE in more human friendly way. The PTE is assumed to be in
4700Sstevel@tonic-gate  * a level 0 page table, unless -l specifies another level.
4710Sstevel@tonic-gate  *
4720Sstevel@tonic-gate  * The PTE value can be specified as the -p option, since on a 32 bit kernel
4730Sstevel@tonic-gate  * with PAE running it's larger than a uintptr_t.
4740Sstevel@tonic-gate  */
4750Sstevel@tonic-gate static int
4760Sstevel@tonic-gate do_pte_dcmd(int level, uint64_t pte)
4770Sstevel@tonic-gate {
4780Sstevel@tonic-gate 	static char *attr[] = {
4790Sstevel@tonic-gate 	    "wrback", "wrthru", "uncached", "uncached",
4800Sstevel@tonic-gate 	    "wrback", "wrthru", "wrcombine", "uncached"};
4810Sstevel@tonic-gate 	int pat_index = 0;
4823446Smrj 	pfn_t mfn;
4830Sstevel@tonic-gate 
4843446Smrj 	mdb_printf("pte=%llr: ", pte);
4850Sstevel@tonic-gate 	if (PTE_GET(pte, mmu.pt_nx))
4860Sstevel@tonic-gate 		mdb_printf("noexec ");
4870Sstevel@tonic-gate 
4883446Smrj 	mfn = pte2mfn(pte, level);
489*5084Sjohnlev 	mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn);
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOCONSIST))
4920Sstevel@tonic-gate 		mdb_printf("noconsist ");
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOSYNC))
4950Sstevel@tonic-gate 		mdb_printf("nosync ");
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	if (PTE_GET(pte, mmu.pt_global))
4980Sstevel@tonic-gate 		mdb_printf("global ");
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
5010Sstevel@tonic-gate 		mdb_printf("largepage ");
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_MOD))
5040Sstevel@tonic-gate 		mdb_printf("mod ");
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_REF))
5070Sstevel@tonic-gate 		mdb_printf("ref ");
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	if (PTE_GET(pte, PT_USER))
5100Sstevel@tonic-gate 		mdb_printf("user ");
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	if (PTE_GET(pte, PT_WRITABLE))
5130Sstevel@tonic-gate 		mdb_printf("write ");
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	/*
5160Sstevel@tonic-gate 	 * Report non-standard cacheability
5170Sstevel@tonic-gate 	 */
5180Sstevel@tonic-gate 	pat_index = 0;
5190Sstevel@tonic-gate 	if (level > 0) {
5200Sstevel@tonic-gate 		if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE))
5210Sstevel@tonic-gate 			pat_index += 4;
5220Sstevel@tonic-gate 	} else {
5230Sstevel@tonic-gate 		if (PTE_GET(pte, PT_PAT_4K))
5240Sstevel@tonic-gate 			pat_index += 4;
5250Sstevel@tonic-gate 	}
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOCACHE))
5280Sstevel@tonic-gate 		pat_index += 2;
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	if (PTE_GET(pte, PT_WRITETHRU))
5310Sstevel@tonic-gate 		pat_index += 1;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	if (pat_index != 0)
5340Sstevel@tonic-gate 		mdb_printf("%s", attr[pat_index]);
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	if (PTE_GET(pte, PT_VALID) == 0)
5370Sstevel@tonic-gate 		mdb_printf(" !VALID ");
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	mdb_printf("\n");
5400Sstevel@tonic-gate 	return (DCMD_OK);
5410Sstevel@tonic-gate }
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate /*
5440Sstevel@tonic-gate  * Print a PTE in more human friendly way. The PTE is assumed to be in
5450Sstevel@tonic-gate  * a level 0 page table, unless -l specifies another level.
5460Sstevel@tonic-gate  *
5470Sstevel@tonic-gate  * The PTE value can be specified as the -p option, since on a 32 bit kernel
5480Sstevel@tonic-gate  * with PAE running it's larger than a uintptr_t.
5490Sstevel@tonic-gate  */
5500Sstevel@tonic-gate /*ARGSUSED*/
5510Sstevel@tonic-gate int
5520Sstevel@tonic-gate pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5530Sstevel@tonic-gate {
5540Sstevel@tonic-gate 	int level = 0;
5550Sstevel@tonic-gate 	uint64_t pte = 0;
5560Sstevel@tonic-gate 	char *level_str = NULL;
5570Sstevel@tonic-gate 	char *pte_str = NULL;
5580Sstevel@tonic-gate 
559*5084Sjohnlev 	init_mmu();
560*5084Sjohnlev 
5610Sstevel@tonic-gate 	if (mmu.num_level == 0)
5620Sstevel@tonic-gate 		return (DCMD_ERR);
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
5650Sstevel@tonic-gate 	    'p', MDB_OPT_STR, &pte_str,
5660Sstevel@tonic-gate 	    'l', MDB_OPT_STR, &level_str) != argc)
5670Sstevel@tonic-gate 		return (DCMD_USAGE);
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	/*
5700Sstevel@tonic-gate 	 * parse the PTE to decode, if it's 0, we don't do anything
5710Sstevel@tonic-gate 	 */
5720Sstevel@tonic-gate 	if (pte_str != NULL) {
5730Sstevel@tonic-gate 		pte = mdb_strtoull(pte_str);
5740Sstevel@tonic-gate 	} else {
5750Sstevel@tonic-gate 		if ((flags & DCMD_ADDRSPEC) == 0)
5760Sstevel@tonic-gate 			return (DCMD_USAGE);
5770Sstevel@tonic-gate 		pte = addr;
5780Sstevel@tonic-gate 	}
5790Sstevel@tonic-gate 	if (pte == 0)
5800Sstevel@tonic-gate 		return (DCMD_OK);
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	/*
5830Sstevel@tonic-gate 	 * parse the level if supplied
5840Sstevel@tonic-gate 	 */
5850Sstevel@tonic-gate 	if (level_str != NULL) {
5860Sstevel@tonic-gate 		level = mdb_strtoull(level_str);
5870Sstevel@tonic-gate 		if (level < 0 || level > mmu.max_level)
5880Sstevel@tonic-gate 			return (DCMD_ERR);
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	return (do_pte_dcmd(level, pte));
5920Sstevel@tonic-gate }
5930Sstevel@tonic-gate 
5943446Smrj static size_t
5953446Smrj va2entry(htable_t *htable, uintptr_t addr)
5963446Smrj {
5973446Smrj 	size_t entry = (addr - htable->ht_vaddr);
5983446Smrj 
5993446Smrj 	entry >>= mmu.level_shift[htable->ht_level];
6003446Smrj 	return (entry & HTABLE_NUM_PTES(htable) - 1);
6013446Smrj }
6023446Smrj 
6033446Smrj static x86pte_t
6043446Smrj get_pte(hat_t *hat, htable_t *htable, uintptr_t addr)
6053446Smrj {
6063446Smrj 	x86pte_t buf;
6073446Smrj 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
6083446Smrj 	size_t len;
6093446Smrj 
6103446Smrj 	if (htable->ht_flags & HTABLE_VLP) {
6113446Smrj 		uintptr_t ptr = (uintptr_t)hat->hat_vlp_ptes;
6123446Smrj 		ptr += va2entry(htable, addr) << mmu.pte_size_shift;
6133446Smrj 		len = mdb_vread(&buf, mmu.pte_size, ptr);
6143446Smrj 	} else {
6153446Smrj 		paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn);
6163446Smrj 		paddr += va2entry(htable, addr) << mmu.pte_size_shift;
6173446Smrj 		len = mdb_pread(&buf, mmu.pte_size, paddr);
6183446Smrj 	}
6193446Smrj 
6203446Smrj 	if (len != mmu.pte_size)
6213446Smrj 		return (0);
6223446Smrj 
6233446Smrj 	if (mmu.pte_size == sizeof (x86pte_t))
6243446Smrj 		return (buf);
6253446Smrj 	return (*pte32);
6263446Smrj }
6273446Smrj 
6280Sstevel@tonic-gate static int
6293446Smrj do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap,
6303446Smrj     pfn_t *mfnp)
6310Sstevel@tonic-gate {
6320Sstevel@tonic-gate 	struct as as;
6330Sstevel@tonic-gate 	struct hat *hatp;
6340Sstevel@tonic-gate 	struct hat hat;
6350Sstevel@tonic-gate 	htable_t *ht;
6360Sstevel@tonic-gate 	htable_t htable;
6370Sstevel@tonic-gate 	uintptr_t base;
6380Sstevel@tonic-gate 	int h;
6390Sstevel@tonic-gate 	int level;
6400Sstevel@tonic-gate 	int found = 0;
6410Sstevel@tonic-gate 	x86pte_t pte;
6420Sstevel@tonic-gate 	physaddr_t paddr;
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	if (asp != NULL) {
6450Sstevel@tonic-gate 		if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
6460Sstevel@tonic-gate 			mdb_warn("Couldn't read struct as\n");
6470Sstevel@tonic-gate 			return (DCMD_ERR);
6480Sstevel@tonic-gate 		}
6490Sstevel@tonic-gate 		hatp = as.a_hat;
6500Sstevel@tonic-gate 	} else {
6510Sstevel@tonic-gate 		hatp = khat;
6520Sstevel@tonic-gate 	}
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	/*
6550Sstevel@tonic-gate 	 * read the hat and its hash table
6560Sstevel@tonic-gate 	 */
6570Sstevel@tonic-gate 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
6580Sstevel@tonic-gate 		mdb_warn("Couldn't read struct hat\n");
6590Sstevel@tonic-gate 		return (DCMD_ERR);
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	/*
6630Sstevel@tonic-gate 	 * read the htable hashtable
6640Sstevel@tonic-gate 	 */
6650Sstevel@tonic-gate 	for (level = 0; level <= mmu.max_level; ++level) {
6663446Smrj 		if (level == TOP_LEVEL(&hat))
6670Sstevel@tonic-gate 			base = 0;
6680Sstevel@tonic-gate 		else
6690Sstevel@tonic-gate 			base = addr & mmu.level_mask[level + 1];
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
6720Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
6730Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
6740Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
6750Sstevel@tonic-gate 				return (DCMD_ERR);
6760Sstevel@tonic-gate 			}
6770Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
6780Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
6790Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
6800Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
6810Sstevel@tonic-gate 					return (DCMD_ERR);
6820Sstevel@tonic-gate 				}
6833446Smrj 
6840Sstevel@tonic-gate 				if (htable.ht_vaddr != base ||
6850Sstevel@tonic-gate 				    htable.ht_level != level)
6860Sstevel@tonic-gate 					continue;
6870Sstevel@tonic-gate 
6883446Smrj 				pte = get_pte(&hat, &htable, addr);
6893446Smrj 
6903446Smrj 				if (print_level) {
6913446Smrj 					mdb_printf("\tlevel=%d htable=%p "
6923446Smrj 					    "pte=%llr\n", level, ht, pte);
6933446Smrj 				}
6943446Smrj 
6953446Smrj 				if (!PTE_ISVALID(pte)) {
6963446Smrj 					mdb_printf("Address %p is unmapped.\n",
6973446Smrj 					    addr);
6980Sstevel@tonic-gate 					return (DCMD_ERR);
6993446Smrj 				}
7003446Smrj 
7013446Smrj 				if (found)
7023446Smrj 					continue;
7033446Smrj 
7043446Smrj 				if (PTE_IS_LGPG(pte, level))
7053446Smrj 					paddr = mdb_ma_to_pa(pte &
7063446Smrj 					    PT_PADDR_LGPG);
7070Sstevel@tonic-gate 				else
7083446Smrj 					paddr = mdb_ma_to_pa(pte & PT_PADDR);
7093446Smrj 				paddr += addr & mmu.level_offset[level];
7103446Smrj 				if (pap != NULL)
7110Sstevel@tonic-gate 					*pap = paddr;
7123446Smrj 				if (mfnp != NULL)
7133446Smrj 					*mfnp = pte2mfn(pte, level);
7143446Smrj 				found = 1;
7150Sstevel@tonic-gate 			}
7160Sstevel@tonic-gate 		}
7170Sstevel@tonic-gate 	}
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate done:
7200Sstevel@tonic-gate 	if (!found)
7210Sstevel@tonic-gate 		return (DCMD_ERR);
7220Sstevel@tonic-gate 	return (DCMD_OK);
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate int
7260Sstevel@tonic-gate va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
7270Sstevel@tonic-gate {
7280Sstevel@tonic-gate 	uintptr_t addrspace;
7290Sstevel@tonic-gate 	char *addrspace_str = NULL;
7303446Smrj 	int piped = flags & DCMD_PIPE_OUT;
7313446Smrj 	pfn_t pfn;
7323446Smrj 	pfn_t mfn;
7330Sstevel@tonic-gate 	int rc;
7340Sstevel@tonic-gate 
735*5084Sjohnlev 	init_mmu();
736*5084Sjohnlev 
7370Sstevel@tonic-gate 	if (mmu.num_level == 0)
7380Sstevel@tonic-gate 		return (DCMD_ERR);
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
7410Sstevel@tonic-gate 	    'a', MDB_OPT_STR, &addrspace_str) != argc)
7420Sstevel@tonic-gate 		return (DCMD_USAGE);
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
7450Sstevel@tonic-gate 		return (DCMD_USAGE);
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	/*
7480Sstevel@tonic-gate 	 * parse the address space
7490Sstevel@tonic-gate 	 */
7500Sstevel@tonic-gate 	if (addrspace_str != NULL)
7510Sstevel@tonic-gate 		addrspace = mdb_strtoull(addrspace_str);
7520Sstevel@tonic-gate 	else
7530Sstevel@tonic-gate 		addrspace = 0;
7540Sstevel@tonic-gate 
7553446Smrj 	rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn);
7563446Smrj 
7573446Smrj 	if (rc != DCMD_OK)
7583446Smrj 		return (rc);
7593446Smrj 
7603446Smrj 	if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) {
7613446Smrj 		mdb_warn("Invalid mfn %lr\n", mfn);
7623446Smrj 		return (DCMD_ERR);
7633446Smrj 	}
7640Sstevel@tonic-gate 
7653446Smrj 	if (piped) {
7663446Smrj 		mdb_printf("0x%lr\n", pfn);
7673446Smrj 		return (DCMD_OK);
7683446Smrj 	}
7690Sstevel@tonic-gate 
7703446Smrj 	mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn);
7713446Smrj 
772*5084Sjohnlev 	if (is_xpv)
773*5084Sjohnlev 		mdb_printf(" (mfn 0x%lr)", mfn);
774*5084Sjohnlev 
7753446Smrj 	mdb_printf("\n");
7763446Smrj 
7773446Smrj 	return (DCMD_OK);
7780Sstevel@tonic-gate }
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate /*
7810Sstevel@tonic-gate  * Report all hat's that either use PFN as a page table or that map the page.
7820Sstevel@tonic-gate  */
7830Sstevel@tonic-gate static int
7840Sstevel@tonic-gate do_report_maps(pfn_t pfn)
7850Sstevel@tonic-gate {
7861747Sjosephb 	struct hat *hatp;
7870Sstevel@tonic-gate 	struct hat hat;
7880Sstevel@tonic-gate 	htable_t *ht;
7890Sstevel@tonic-gate 	htable_t htable;
7900Sstevel@tonic-gate 	uintptr_t base;
7910Sstevel@tonic-gate 	int h;
7920Sstevel@tonic-gate 	int level;
7930Sstevel@tonic-gate 	int entry;
7940Sstevel@tonic-gate 	x86pte_t pte;
7950Sstevel@tonic-gate 	x86pte_t buf;
7960Sstevel@tonic-gate 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
7970Sstevel@tonic-gate 	physaddr_t paddr;
7980Sstevel@tonic-gate 	size_t len;
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	/*
8011747Sjosephb 	 * The hats are kept in a list with khat at the head.
8020Sstevel@tonic-gate 	 */
8031747Sjosephb 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
8040Sstevel@tonic-gate 		/*
8050Sstevel@tonic-gate 		 * read the hat and its hash table
8060Sstevel@tonic-gate 		 */
8070Sstevel@tonic-gate 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
8080Sstevel@tonic-gate 			mdb_warn("Couldn't read struct hat\n");
8090Sstevel@tonic-gate 			return (DCMD_ERR);
8100Sstevel@tonic-gate 		}
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 		/*
8130Sstevel@tonic-gate 		 * read the htable hashtable
8140Sstevel@tonic-gate 		 */
8150Sstevel@tonic-gate 		paddr = 0;
8160Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
8170Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
8180Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
8190Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
8200Sstevel@tonic-gate 				return (DCMD_ERR);
8210Sstevel@tonic-gate 			}
8220Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
8230Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
8240Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
8250Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
8260Sstevel@tonic-gate 					return (DCMD_ERR);
8270Sstevel@tonic-gate 				}
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 				/*
8300Sstevel@tonic-gate 				 * only report kernel addresses once
8310Sstevel@tonic-gate 				 */
8320Sstevel@tonic-gate 				if (hatp != khat &&
8330Sstevel@tonic-gate 				    htable.ht_vaddr >= kernelbase)
8340Sstevel@tonic-gate 					continue;
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 				/*
8370Sstevel@tonic-gate 				 * Is the PFN a pagetable itself?
8380Sstevel@tonic-gate 				 */
8390Sstevel@tonic-gate 				if (htable.ht_pfn == pfn) {
8400Sstevel@tonic-gate 					mdb_printf("Pagetable for "
8410Sstevel@tonic-gate 					    "hat=%p htable=%p\n", hatp, ht);
8420Sstevel@tonic-gate 					continue;
8430Sstevel@tonic-gate 				}
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 				/*
8460Sstevel@tonic-gate 				 * otherwise, examine page mappings
8470Sstevel@tonic-gate 				 */
8480Sstevel@tonic-gate 				level = htable.ht_level;
8490Sstevel@tonic-gate 				if (level > mmu.max_page_level)
8500Sstevel@tonic-gate 					continue;
8513446Smrj 				paddr = mmu_ptob((physaddr_t)htable.ht_pfn);
8523446Smrj 				for (entry = 0;
8533446Smrj 				    entry < HTABLE_NUM_PTES(&htable);
8540Sstevel@tonic-gate 				    ++entry) {
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 					base = htable.ht_vaddr + entry *
8570Sstevel@tonic-gate 					    mmu.level_size[level];
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 					/*
8600Sstevel@tonic-gate 					 * only report kernel addresses once
8610Sstevel@tonic-gate 					 */
8620Sstevel@tonic-gate 					if (hatp != khat &&
8630Sstevel@tonic-gate 					    base >= kernelbase)
8640Sstevel@tonic-gate 						continue;
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 					len = mdb_pread(&buf, mmu.pte_size,
8670Sstevel@tonic-gate 					    paddr + entry * mmu.pte_size);
8680Sstevel@tonic-gate 					if (len != mmu.pte_size)
8690Sstevel@tonic-gate 						return (DCMD_ERR);
8700Sstevel@tonic-gate 					if (mmu.pte_size == sizeof (x86pte_t))
8710Sstevel@tonic-gate 						pte = buf;
8720Sstevel@tonic-gate 					else
8730Sstevel@tonic-gate 						pte = *pte32;
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 					if ((pte & PT_VALID) == 0)
8760Sstevel@tonic-gate 						continue;
8770Sstevel@tonic-gate 					if (level == 0 || !(pte & PT_PAGESIZE))
8780Sstevel@tonic-gate 						pte &= PT_PADDR;
8790Sstevel@tonic-gate 					else
8800Sstevel@tonic-gate 						pte &= PT_PADDR_LGPG;
8813446Smrj 					if (mmu_btop(mdb_ma_to_pa(pte)) != pfn)
8820Sstevel@tonic-gate 						continue;
8830Sstevel@tonic-gate 					mdb_printf("hat=%p maps addr=%p\n",
884*5084Sjohnlev 					    hatp, (caddr_t)base);
8850Sstevel@tonic-gate 				}
8860Sstevel@tonic-gate 			}
8870Sstevel@tonic-gate 		}
8880Sstevel@tonic-gate 	}
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate done:
8910Sstevel@tonic-gate 	return (DCMD_OK);
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate /*
8950Sstevel@tonic-gate  * given a PFN as its address argument, prints out the uses of it
8960Sstevel@tonic-gate  */
8970Sstevel@tonic-gate /*ARGSUSED*/
8980Sstevel@tonic-gate int
8990Sstevel@tonic-gate report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
9000Sstevel@tonic-gate {
9013446Smrj 	pfn_t pfn;
9023446Smrj 	uint_t mflag = 0;
9033446Smrj 
904*5084Sjohnlev 	init_mmu();
905*5084Sjohnlev 
9060Sstevel@tonic-gate 	if (mmu.num_level == 0)
9070Sstevel@tonic-gate 		return (DCMD_ERR);
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
9100Sstevel@tonic-gate 		return (DCMD_USAGE);
9110Sstevel@tonic-gate 
9123446Smrj 	if (mdb_getopts(argc, argv,
9133446Smrj 	    'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
9143446Smrj 		return (DCMD_USAGE);
9153446Smrj 
9163446Smrj 	pfn = (pfn_t)addr;
9173446Smrj 	if (mflag)
9183446Smrj 		pfn = mdb_mfn_to_pfn(pfn);
9193446Smrj 
9203446Smrj 	return (do_report_maps(pfn));
9210Sstevel@tonic-gate }
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate static int
9240Sstevel@tonic-gate do_ptable_dcmd(pfn_t pfn)
9250Sstevel@tonic-gate {
9261747Sjosephb 	struct hat *hatp;
9270Sstevel@tonic-gate 	struct hat hat;
9280Sstevel@tonic-gate 	htable_t *ht;
9290Sstevel@tonic-gate 	htable_t htable;
9300Sstevel@tonic-gate 	uintptr_t base;
9310Sstevel@tonic-gate 	int h;
9320Sstevel@tonic-gate 	int level;
9330Sstevel@tonic-gate 	int entry;
9340Sstevel@tonic-gate 	uintptr_t pagesize;
9350Sstevel@tonic-gate 	x86pte_t pte;
9360Sstevel@tonic-gate 	x86pte_t buf;
9370Sstevel@tonic-gate 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
9380Sstevel@tonic-gate 	physaddr_t paddr;
9390Sstevel@tonic-gate 	size_t len;
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	/*
9421747Sjosephb 	 * The hats are kept in a list with khat at the head.
9430Sstevel@tonic-gate 	 */
9441747Sjosephb 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
9450Sstevel@tonic-gate 		/*
9460Sstevel@tonic-gate 		 * read the hat and its hash table
9470Sstevel@tonic-gate 		 */
9480Sstevel@tonic-gate 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
9490Sstevel@tonic-gate 			mdb_warn("Couldn't read struct hat\n");
9500Sstevel@tonic-gate 			return (DCMD_ERR);
9510Sstevel@tonic-gate 		}
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 		/*
9540Sstevel@tonic-gate 		 * read the htable hashtable
9550Sstevel@tonic-gate 		 */
9560Sstevel@tonic-gate 		paddr = 0;
9570Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
9580Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
9590Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
9600Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
9610Sstevel@tonic-gate 				return (DCMD_ERR);
9620Sstevel@tonic-gate 			}
9630Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
9640Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
9650Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
9660Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
9670Sstevel@tonic-gate 					return (DCMD_ERR);
9680Sstevel@tonic-gate 				}
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 				/*
9710Sstevel@tonic-gate 				 * Is this the PFN for this htable
9720Sstevel@tonic-gate 				 */
9730Sstevel@tonic-gate 				if (htable.ht_pfn == pfn)
9740Sstevel@tonic-gate 					goto found_it;
9750Sstevel@tonic-gate 			}
9760Sstevel@tonic-gate 		}
9770Sstevel@tonic-gate 	}
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate found_it:
9800Sstevel@tonic-gate 	if (htable.ht_pfn == pfn) {
9810Sstevel@tonic-gate 		mdb_printf("htable=%p\n", ht);
9820Sstevel@tonic-gate 		level = htable.ht_level;
9830Sstevel@tonic-gate 		base = htable.ht_vaddr;
9840Sstevel@tonic-gate 		pagesize = mmu.level_size[level];
9850Sstevel@tonic-gate 	} else {
9860Sstevel@tonic-gate 		mdb_printf("Unknown pagetable - assuming level/addr 0");
9870Sstevel@tonic-gate 		level = 0;	/* assume level == 0 for PFN */
9880Sstevel@tonic-gate 		base = 0;
9890Sstevel@tonic-gate 		pagesize = MMU_PAGESIZE;
9900Sstevel@tonic-gate 	}
9910Sstevel@tonic-gate 
9923446Smrj 	paddr = mmu_ptob((physaddr_t)pfn);
9930Sstevel@tonic-gate 	for (entry = 0; entry < mmu.ptes_per_table; ++entry) {
9940Sstevel@tonic-gate 		len = mdb_pread(&buf, mmu.pte_size,
9950Sstevel@tonic-gate 		    paddr + entry * mmu.pte_size);
9960Sstevel@tonic-gate 		if (len != mmu.pte_size)
9970Sstevel@tonic-gate 			return (DCMD_ERR);
9980Sstevel@tonic-gate 		if (mmu.pte_size == sizeof (x86pte_t))
9990Sstevel@tonic-gate 			pte = buf;
10000Sstevel@tonic-gate 		else
10010Sstevel@tonic-gate 			pte = *pte32;
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 		if (pte == 0)
10040Sstevel@tonic-gate 			continue;
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 		mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize);
10070Sstevel@tonic-gate 		do_pte_dcmd(level, pte);
10080Sstevel@tonic-gate 	}
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate done:
10110Sstevel@tonic-gate 	return (DCMD_OK);
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate /*
10153446Smrj  * Dump the page table at the given PFN
10160Sstevel@tonic-gate  */
10170Sstevel@tonic-gate /*ARGSUSED*/
10180Sstevel@tonic-gate int
10190Sstevel@tonic-gate ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
10200Sstevel@tonic-gate {
10213446Smrj 	pfn_t pfn;
10223446Smrj 	uint_t mflag = 0;
10233446Smrj 
1024*5084Sjohnlev 	init_mmu();
1025*5084Sjohnlev 
10260Sstevel@tonic-gate 	if (mmu.num_level == 0)
10270Sstevel@tonic-gate 		return (DCMD_ERR);
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
10300Sstevel@tonic-gate 		return (DCMD_USAGE);
10310Sstevel@tonic-gate 
10323446Smrj 	if (mdb_getopts(argc, argv,
10333446Smrj 	    'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
10343446Smrj 		return (DCMD_USAGE);
10353446Smrj 
10363446Smrj 	pfn = (pfn_t)addr;
10373446Smrj 	if (mflag)
10383446Smrj 		pfn = mdb_mfn_to_pfn(pfn);
10393446Smrj 
10403446Smrj 	return (do_ptable_dcmd(pfn));
10410Sstevel@tonic-gate }
10423446Smrj 
10433446Smrj static int
10443446Smrj do_htables_dcmd(hat_t *hatp)
10453446Smrj {
10463446Smrj 	struct hat hat;
10473446Smrj 	htable_t *ht;
10483446Smrj 	htable_t htable;
10493446Smrj 	int h;
10503446Smrj 
10513446Smrj 	/*
10523446Smrj 	 * read the hat and its hash table
10533446Smrj 	 */
10543446Smrj 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
10553446Smrj 		mdb_warn("Couldn't read struct hat\n");
10563446Smrj 		return (DCMD_ERR);
10573446Smrj 	}
10583446Smrj 
10593446Smrj 	/*
10603446Smrj 	 * read the htable hashtable
10613446Smrj 	 */
10623446Smrj 	for (h = 0; h < hat.hat_num_hash; ++h) {
10633446Smrj 		if (mdb_vread(&ht, sizeof (htable_t *),
10643446Smrj 		    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
10653446Smrj 			mdb_warn("Couldn't read htable ptr\\n");
10663446Smrj 			return (DCMD_ERR);
10673446Smrj 		}
10683446Smrj 		for (; ht != NULL; ht = htable.ht_next) {
10693446Smrj 			mdb_printf("%p\n", ht);
10703446Smrj 			if (mdb_vread(&htable, sizeof (htable_t),
10713446Smrj 			    (uintptr_t)ht) == -1) {
10723446Smrj 				mdb_warn("Couldn't read htable\n");
10733446Smrj 				return (DCMD_ERR);
10743446Smrj 			}
10753446Smrj 		}
10763446Smrj 	}
10773446Smrj 	return (DCMD_OK);
10783446Smrj }
10793446Smrj 
10803446Smrj /*
10813446Smrj  * Dump the htables for the given hat
10823446Smrj  */
10833446Smrj /*ARGSUSED*/
10843446Smrj int
10853446Smrj htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
10863446Smrj {
10873446Smrj 	hat_t *hat;
10883446Smrj 
1089*5084Sjohnlev 	init_mmu();
1090*5084Sjohnlev 
10913446Smrj 	if (mmu.num_level == 0)
10923446Smrj 		return (DCMD_ERR);
10933446Smrj 
10943446Smrj 	if ((flags & DCMD_ADDRSPEC) == 0)
10953446Smrj 		return (DCMD_USAGE);
10963446Smrj 
10973446Smrj 	hat = (hat_t *)addr;
10983446Smrj 
10993446Smrj 	return (do_htables_dcmd(hat));
11003446Smrj }
1101