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