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