xref: /onnv-gate/usr/src/cmd/mdb/i86pc/modules/unix/i86mmu.c (revision 1747:09f7348b6555)
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
5*1747Sjosephb  * Common Development and Distribution License (the "License").
6*1747Sjosephb  * 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*1747Sjosephb  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * This part of the file contains the mdb support for dcmds:
300Sstevel@tonic-gate  *	::memseg_list
310Sstevel@tonic-gate  *	::page_num2pp
320Sstevel@tonic-gate  * and walkers for:
330Sstevel@tonic-gate  *	memseg - a memseg list walker for ::memseg_list
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  */
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #include <sys/types.h>
380Sstevel@tonic-gate #include <sys/machparam.h>
390Sstevel@tonic-gate #include <sys/controlregs.h>
400Sstevel@tonic-gate #include <vm/as.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
430Sstevel@tonic-gate #include <mdb/mdb_target.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include <vm/page.h>
460Sstevel@tonic-gate #include <vm/hat_i86.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate struct pfn2pp {
490Sstevel@tonic-gate 	pfn_t pfn;
500Sstevel@tonic-gate 	page_t *pp;
510Sstevel@tonic-gate };
520Sstevel@tonic-gate 
530Sstevel@tonic-gate static int do_va2pfn(uintptr_t, struct as *, int, physaddr_t *);
540Sstevel@tonic-gate static void get_mmu(void);
550Sstevel@tonic-gate 
560Sstevel@tonic-gate int
570Sstevel@tonic-gate platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
580Sstevel@tonic-gate {
590Sstevel@tonic-gate 	if (asp == NULL)
600Sstevel@tonic-gate 		return (DCMD_ERR);
610Sstevel@tonic-gate 
620Sstevel@tonic-gate 	/*
630Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
640Sstevel@tonic-gate 	 */
650Sstevel@tonic-gate 	get_mmu();
660Sstevel@tonic-gate 	if (mmu.num_level == 0)
670Sstevel@tonic-gate 		return (DCMD_ERR);
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	return (do_va2pfn(addr, asp, 0, pap));
700Sstevel@tonic-gate }
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*ARGSUSED*/
740Sstevel@tonic-gate int
750Sstevel@tonic-gate page_num2pp_cb(uintptr_t addr, void *ignored, uintptr_t *data)
760Sstevel@tonic-gate {
770Sstevel@tonic-gate 	struct memseg ms, *msp = &ms;
780Sstevel@tonic-gate 	struct pfn2pp *p = (struct pfn2pp *)data;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	if (mdb_vread(msp, sizeof (struct memseg), addr) == -1) {
810Sstevel@tonic-gate 		mdb_warn("can't read memseg at %#lx", addr);
820Sstevel@tonic-gate 		return (DCMD_ERR);
830Sstevel@tonic-gate 	}
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 	if (p->pfn >= msp->pages_base && p->pfn < msp->pages_end) {
860Sstevel@tonic-gate 		p->pp = msp->pages + (p->pfn - msp->pages_base);
870Sstevel@tonic-gate 		return (WALK_DONE);
880Sstevel@tonic-gate 	}
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	return (WALK_NEXT);
910Sstevel@tonic-gate }
920Sstevel@tonic-gate 
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate  * ::page_num2pp dcmd
950Sstevel@tonic-gate  */
960Sstevel@tonic-gate /*ARGSUSED*/
970Sstevel@tonic-gate int
980Sstevel@tonic-gate page_num2pp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate 	struct pfn2pp pfn2pp;
1010Sstevel@tonic-gate 	page_t page;
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0) {
1040Sstevel@tonic-gate 		mdb_warn("page frame number missing\n");
1050Sstevel@tonic-gate 			return (DCMD_USAGE);
1060Sstevel@tonic-gate 	}
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	pfn2pp.pfn = (pfn_t)addr;
1090Sstevel@tonic-gate 	pfn2pp.pp = NULL;
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 	if (mdb_walk("memseg", (mdb_walk_cb_t)page_num2pp_cb,
1120Sstevel@tonic-gate 	    (void *)&pfn2pp) == -1) {
1130Sstevel@tonic-gate 		mdb_warn("can't walk memseg");
1140Sstevel@tonic-gate 		return (DCMD_ERR);
1150Sstevel@tonic-gate 	}
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	if (pfn2pp.pp == NULL)
1180Sstevel@tonic-gate 		return (DCMD_ERR);
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	mdb_printf("%x has page at %p\n", pfn2pp.pfn, pfn2pp.pp);
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	if (mdb_vread(&page, sizeof (page_t),
1230Sstevel@tonic-gate 	    (uintptr_t)pfn2pp.pp) == -1) {
1240Sstevel@tonic-gate 		mdb_warn("can't read page at %p", &page);
1250Sstevel@tonic-gate 		return (DCMD_ERR);
1260Sstevel@tonic-gate 	}
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	if (page.p_pagenum != pfn2pp.pfn) {
1290Sstevel@tonic-gate 		mdb_warn("WARNING! Found page structure contains "
1300Sstevel@tonic-gate 			"different pagenumber %x\n", page.p_pagenum);
1310Sstevel@tonic-gate 	}
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	return (DCMD_OK);
1340Sstevel@tonic-gate }
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate /*
1410Sstevel@tonic-gate  * ::memseg_list dcmd and walker to implement it.
1420Sstevel@tonic-gate  */
1430Sstevel@tonic-gate /*ARGSUSED*/
1440Sstevel@tonic-gate int
1450Sstevel@tonic-gate memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1460Sstevel@tonic-gate {
1470Sstevel@tonic-gate 	struct memseg ms;
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
1500Sstevel@tonic-gate 		if (mdb_pwalk_dcmd("memseg", "memseg_list",
1510Sstevel@tonic-gate 		    0, NULL, 0) == -1) {
1520Sstevel@tonic-gate 			mdb_warn("can't walk memseg");
1530Sstevel@tonic-gate 			return (DCMD_ERR);
1540Sstevel@tonic-gate 		}
1550Sstevel@tonic-gate 		return (DCMD_OK);
1560Sstevel@tonic-gate 	}
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
1590Sstevel@tonic-gate 		mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
1600Sstevel@tonic-gate 			"PAGES", "EPAGES", "BASE", "END");
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
1630Sstevel@tonic-gate 		mdb_warn("can't read memseg at %#lx", addr);
1640Sstevel@tonic-gate 		return (DCMD_ERR);
1650Sstevel@tonic-gate 	}
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr,
1680Sstevel@tonic-gate 		ms.pages, ms.epages, ms.pages_base, ms.pages_end);
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	return (DCMD_OK);
1710Sstevel@tonic-gate }
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate /*
1740Sstevel@tonic-gate  * walk the memseg structures
1750Sstevel@tonic-gate  */
1760Sstevel@tonic-gate int
1770Sstevel@tonic-gate memseg_walk_init(mdb_walk_state_t *wsp)
1780Sstevel@tonic-gate {
1790Sstevel@tonic-gate 	if (wsp->walk_addr != NULL) {
1800Sstevel@tonic-gate 		mdb_warn("memseg only supports global walks\n");
1810Sstevel@tonic-gate 		return (WALK_ERR);
1820Sstevel@tonic-gate 	}
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
1850Sstevel@tonic-gate 		mdb_warn("symbol 'memsegs' not found");
1860Sstevel@tonic-gate 		return (WALK_ERR);
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
1900Sstevel@tonic-gate 	return (WALK_NEXT);
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate int
1950Sstevel@tonic-gate memseg_walk_step(mdb_walk_state_t *wsp)
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate 	int status;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	if (wsp->walk_addr == 0) {
2000Sstevel@tonic-gate 		return (WALK_DONE);
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (struct memseg),
2040Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
2050Sstevel@tonic-gate 		mdb_warn("failed to read struct memseg at %p", wsp->walk_addr);
2060Sstevel@tonic-gate 		return (WALK_DONE);
2070Sstevel@tonic-gate 	}
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
2100Sstevel@tonic-gate 	    wsp->walk_cbdata);
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	return (status);
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate void
2180Sstevel@tonic-gate memseg_walk_fini(mdb_walk_state_t *wsp)
2190Sstevel@tonic-gate {
2200Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct memseg));
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate /*
2240Sstevel@tonic-gate  * HAT related dcmds:
2250Sstevel@tonic-gate  *
2260Sstevel@tonic-gate  * ::pte [-p XXXXXXXX] [-l 0/1/2/3]
2270Sstevel@tonic-gate  *
2280Sstevel@tonic-gate  * dcmd that interprets the -p argument as a page table entry and
2290Sstevel@tonic-gate  * prints it in more human readable form. The PTE is assumed to be in
2300Sstevel@tonic-gate  * a level 0 page table, unless -l specifies another level.
2310Sstevel@tonic-gate  *
2320Sstevel@tonic-gate  * ::vatopfn [-v] [-a as]
2330Sstevel@tonic-gate  *
2340Sstevel@tonic-gate  * Given a virtual address, returns the PFN, if any, mapped at the address.
2350Sstevel@tonic-gate  * -v shows the intermediate htable/page table entries used to resolve the
2360Sstevel@tonic-gate  * mapping. By default the virtual address is assumed to be in the kernel's
2370Sstevel@tonic-gate  * address space.  -a is used to specify a different address space.
2380Sstevel@tonic-gate  */
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate struct hat *khat;		/* value of kas.a_hat */
2410Sstevel@tonic-gate struct hat_mmu_info mmu;
2420Sstevel@tonic-gate uintptr_t kernelbase;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate /*
2450Sstevel@tonic-gate  * read mmu parameters from kernel
2460Sstevel@tonic-gate  */
2470Sstevel@tonic-gate static void
2480Sstevel@tonic-gate get_mmu(void)
2490Sstevel@tonic-gate {
2500Sstevel@tonic-gate 	struct as kas;
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	if (mmu.num_level != 0)
2530Sstevel@tonic-gate 		return;
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1)
2560Sstevel@tonic-gate 		mdb_warn("Can't use HAT information before mmu_init()\n");
2570Sstevel@tonic-gate 	if (mdb_readsym(&kas, sizeof (kas), "kas") == -1)
2580Sstevel@tonic-gate 		mdb_warn("Couldn't find kas - kernel's struct as\n");
2590Sstevel@tonic-gate 	if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1)
2600Sstevel@tonic-gate 		mdb_warn("Couldn't find kernelbase\n");
2610Sstevel@tonic-gate 	khat = kas.a_hat;
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate /*
2650Sstevel@tonic-gate  * Print a PTE in more human friendly way. The PTE is assumed to be in
2660Sstevel@tonic-gate  * a level 0 page table, unless -l specifies another level.
2670Sstevel@tonic-gate  *
2680Sstevel@tonic-gate  * The PTE value can be specified as the -p option, since on a 32 bit kernel
2690Sstevel@tonic-gate  * with PAE running it's larger than a uintptr_t.
2700Sstevel@tonic-gate  */
2710Sstevel@tonic-gate static int
2720Sstevel@tonic-gate do_pte_dcmd(int level, uint64_t pte)
2730Sstevel@tonic-gate {
2740Sstevel@tonic-gate 	static char *attr[] = {
2750Sstevel@tonic-gate 	    "wrback", "wrthru", "uncached", "uncached",
2760Sstevel@tonic-gate 	    "wrback", "wrthru", "wrcombine", "uncached"};
2770Sstevel@tonic-gate 	int pat_index = 0;
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	mdb_printf("PTE=%llx: ", pte);
2800Sstevel@tonic-gate 	if (PTE_GET(pte, mmu.pt_nx))
2810Sstevel@tonic-gate 		mdb_printf("noexec ");
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	mdb_printf("page=0x%llx ", PTE2PFN(pte, level));
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOCONSIST))
2860Sstevel@tonic-gate 		mdb_printf("noconsist ");
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOSYNC))
2890Sstevel@tonic-gate 		mdb_printf("nosync ");
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	if (PTE_GET(pte, mmu.pt_global))
2920Sstevel@tonic-gate 		mdb_printf("global ");
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
2950Sstevel@tonic-gate 		mdb_printf("largepage ");
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_MOD))
2980Sstevel@tonic-gate 		mdb_printf("mod ");
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_REF))
3010Sstevel@tonic-gate 		mdb_printf("ref ");
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	if (PTE_GET(pte, PT_USER))
3040Sstevel@tonic-gate 		mdb_printf("user ");
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	if (PTE_GET(pte, PT_WRITABLE))
3070Sstevel@tonic-gate 		mdb_printf("write ");
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	/*
3100Sstevel@tonic-gate 	 * Report non-standard cacheability
3110Sstevel@tonic-gate 	 */
3120Sstevel@tonic-gate 	pat_index = 0;
3130Sstevel@tonic-gate 	if (level > 0) {
3140Sstevel@tonic-gate 		if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE))
3150Sstevel@tonic-gate 			pat_index += 4;
3160Sstevel@tonic-gate 	} else {
3170Sstevel@tonic-gate 		if (PTE_GET(pte, PT_PAT_4K))
3180Sstevel@tonic-gate 			pat_index += 4;
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOCACHE))
3220Sstevel@tonic-gate 		pat_index += 2;
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	if (PTE_GET(pte, PT_WRITETHRU))
3250Sstevel@tonic-gate 		pat_index += 1;
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	if (pat_index != 0)
3280Sstevel@tonic-gate 		mdb_printf("%s", attr[pat_index]);
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	if (PTE_GET(pte, PT_VALID) == 0)
3310Sstevel@tonic-gate 		mdb_printf(" !VALID ");
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	mdb_printf("\n");
3340Sstevel@tonic-gate 	return (DCMD_OK);
3350Sstevel@tonic-gate }
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate /*
3380Sstevel@tonic-gate  * Print a PTE in more human friendly way. The PTE is assumed to be in
3390Sstevel@tonic-gate  * a level 0 page table, unless -l specifies another level.
3400Sstevel@tonic-gate  *
3410Sstevel@tonic-gate  * The PTE value can be specified as the -p option, since on a 32 bit kernel
3420Sstevel@tonic-gate  * with PAE running it's larger than a uintptr_t.
3430Sstevel@tonic-gate  */
3440Sstevel@tonic-gate /*ARGSUSED*/
3450Sstevel@tonic-gate int
3460Sstevel@tonic-gate pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3470Sstevel@tonic-gate {
3480Sstevel@tonic-gate 	int level = 0;
3490Sstevel@tonic-gate 	uint64_t pte = 0;
3500Sstevel@tonic-gate 	char *level_str = NULL;
3510Sstevel@tonic-gate 	char *pte_str = NULL;
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	/*
3540Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
3550Sstevel@tonic-gate 	 */
3560Sstevel@tonic-gate 	get_mmu();
3570Sstevel@tonic-gate 	if (mmu.num_level == 0)
3580Sstevel@tonic-gate 		return (DCMD_ERR);
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
3610Sstevel@tonic-gate 	    'p', MDB_OPT_STR, &pte_str,
3620Sstevel@tonic-gate 	    'l', MDB_OPT_STR, &level_str) != argc)
3630Sstevel@tonic-gate 		return (DCMD_USAGE);
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	/*
3660Sstevel@tonic-gate 	 * parse the PTE to decode, if it's 0, we don't do anything
3670Sstevel@tonic-gate 	 */
3680Sstevel@tonic-gate 	if (pte_str != NULL) {
3690Sstevel@tonic-gate 		pte = mdb_strtoull(pte_str);
3700Sstevel@tonic-gate 	} else {
3710Sstevel@tonic-gate 		if ((flags & DCMD_ADDRSPEC) == 0)
3720Sstevel@tonic-gate 			return (DCMD_USAGE);
3730Sstevel@tonic-gate 		pte = addr;
3740Sstevel@tonic-gate 	}
3750Sstevel@tonic-gate 	if (pte == 0)
3760Sstevel@tonic-gate 		return (DCMD_OK);
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	/*
3790Sstevel@tonic-gate 	 * parse the level if supplied
3800Sstevel@tonic-gate 	 */
3810Sstevel@tonic-gate 	if (level_str != NULL) {
3820Sstevel@tonic-gate 		level = mdb_strtoull(level_str);
3830Sstevel@tonic-gate 		if (level < 0 || level > mmu.max_level)
3840Sstevel@tonic-gate 			return (DCMD_ERR);
3850Sstevel@tonic-gate 	}
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	return (do_pte_dcmd(level, pte));
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate static int
3910Sstevel@tonic-gate do_va2pfn(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap)
3920Sstevel@tonic-gate {
3930Sstevel@tonic-gate 	struct as as;
3940Sstevel@tonic-gate 	struct hat *hatp;
3950Sstevel@tonic-gate 	struct hat hat;
3960Sstevel@tonic-gate 	htable_t *ht;
3970Sstevel@tonic-gate 	htable_t htable;
3980Sstevel@tonic-gate 	uintptr_t base;
3990Sstevel@tonic-gate 	int h;
4000Sstevel@tonic-gate 	int level;
4010Sstevel@tonic-gate 	int found = 0;
4020Sstevel@tonic-gate 	x86pte_t pte;
4030Sstevel@tonic-gate 	x86pte_t buf;
4040Sstevel@tonic-gate 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
4050Sstevel@tonic-gate 	physaddr_t paddr;
4060Sstevel@tonic-gate 	size_t len;
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	if (asp != NULL) {
4090Sstevel@tonic-gate 		if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
4100Sstevel@tonic-gate 			mdb_warn("Couldn't read struct as\n");
4110Sstevel@tonic-gate 			return (DCMD_ERR);
4120Sstevel@tonic-gate 		}
4130Sstevel@tonic-gate 		hatp = as.a_hat;
4140Sstevel@tonic-gate 	} else {
4150Sstevel@tonic-gate 		hatp = khat;
4160Sstevel@tonic-gate 	}
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	/*
4190Sstevel@tonic-gate 	 * read the hat and its hash table
4200Sstevel@tonic-gate 	 */
4210Sstevel@tonic-gate 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
4220Sstevel@tonic-gate 		mdb_warn("Couldn't read struct hat\n");
4230Sstevel@tonic-gate 		return (DCMD_ERR);
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	/*
4270Sstevel@tonic-gate 	 * read the htable hashtable
4280Sstevel@tonic-gate 	 */
4290Sstevel@tonic-gate 	*pap = 0;
4300Sstevel@tonic-gate 	for (level = 0; level <= mmu.max_level; ++level) {
4310Sstevel@tonic-gate 		if (level == mmu.max_level)
4320Sstevel@tonic-gate 			base = 0;
4330Sstevel@tonic-gate 		else
4340Sstevel@tonic-gate 			base = addr & mmu.level_mask[level + 1];
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
4370Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
4380Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
4390Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
4400Sstevel@tonic-gate 				return (DCMD_ERR);
4410Sstevel@tonic-gate 			}
4420Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
4430Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
4440Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
4450Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
4460Sstevel@tonic-gate 					return (DCMD_ERR);
4470Sstevel@tonic-gate 				}
4480Sstevel@tonic-gate 				if (htable.ht_vaddr != base ||
4490Sstevel@tonic-gate 				    htable.ht_level != level)
4500Sstevel@tonic-gate 					continue;
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 				/*
4530Sstevel@tonic-gate 				 * found - read the page table entry
4540Sstevel@tonic-gate 				 */
4550Sstevel@tonic-gate 				paddr = htable.ht_pfn << MMU_PAGESHIFT;
4560Sstevel@tonic-gate 				paddr += ((addr - base) >>
4570Sstevel@tonic-gate 				    mmu.level_shift[level]) <<
4580Sstevel@tonic-gate 				    mmu.pte_size_shift;
4590Sstevel@tonic-gate 				len = mdb_pread(&buf, mmu.pte_size, paddr);
4600Sstevel@tonic-gate 				if (len != mmu.pte_size)
4610Sstevel@tonic-gate 					return (DCMD_ERR);
4620Sstevel@tonic-gate 				if (mmu.pte_size == sizeof (x86pte_t))
4630Sstevel@tonic-gate 					pte = buf;
4640Sstevel@tonic-gate 				else
4650Sstevel@tonic-gate 					pte = *pte32;
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 				if (!found) {
4680Sstevel@tonic-gate 					if (PTE_IS_LGPG(pte, level))
4690Sstevel@tonic-gate 						paddr = pte & PT_PADDR_LGPG;
4700Sstevel@tonic-gate 					else
4710Sstevel@tonic-gate 						paddr = pte & PT_PADDR;
4720Sstevel@tonic-gate 					paddr += addr & mmu.level_offset[level];
4730Sstevel@tonic-gate 					*pap = paddr;
4740Sstevel@tonic-gate 					found = 1;
4750Sstevel@tonic-gate 				}
4760Sstevel@tonic-gate 				if (print_level == 0)
4770Sstevel@tonic-gate 					continue;
4780Sstevel@tonic-gate 				mdb_printf("\tlevel=%d htable=%p pte=%llx\n",
4790Sstevel@tonic-gate 				    level, ht, pte);
4800Sstevel@tonic-gate 			}
4810Sstevel@tonic-gate 		}
4820Sstevel@tonic-gate 	}
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate done:
4850Sstevel@tonic-gate 	if (!found)
4860Sstevel@tonic-gate 		return (DCMD_ERR);
4870Sstevel@tonic-gate 	return (DCMD_OK);
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate int
4910Sstevel@tonic-gate va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4920Sstevel@tonic-gate {
4930Sstevel@tonic-gate 	uintptr_t addrspace;
4940Sstevel@tonic-gate 	char *addrspace_str = NULL;
4950Sstevel@tonic-gate 	uint64_t physaddr;
4960Sstevel@tonic-gate 	int rc;
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	/*
4990Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
5000Sstevel@tonic-gate 	 */
5010Sstevel@tonic-gate 	get_mmu();
5020Sstevel@tonic-gate 	if (mmu.num_level == 0)
5030Sstevel@tonic-gate 		return (DCMD_ERR);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
5060Sstevel@tonic-gate 	    'a', MDB_OPT_STR, &addrspace_str) != argc)
5070Sstevel@tonic-gate 		return (DCMD_USAGE);
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
5100Sstevel@tonic-gate 		return (DCMD_USAGE);
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	/*
5130Sstevel@tonic-gate 	 * parse the address space
5140Sstevel@tonic-gate 	 */
5150Sstevel@tonic-gate 	if (addrspace_str != NULL)
5160Sstevel@tonic-gate 		addrspace = mdb_strtoull(addrspace_str);
5170Sstevel@tonic-gate 	else
5180Sstevel@tonic-gate 		addrspace = 0;
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	rc = do_va2pfn(addr, (struct as *)addrspace, 1, &physaddr);
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	if (rc == DCMD_OK)
5230Sstevel@tonic-gate 		mdb_printf("Virtual %p maps Physical %llx\n", addr, physaddr);
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	return (rc);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate /*
5290Sstevel@tonic-gate  * Report all hat's that either use PFN as a page table or that map the page.
5300Sstevel@tonic-gate  */
5310Sstevel@tonic-gate static int
5320Sstevel@tonic-gate do_report_maps(pfn_t pfn)
5330Sstevel@tonic-gate {
534*1747Sjosephb 	struct hat *hatp;
5350Sstevel@tonic-gate 	struct hat hat;
5360Sstevel@tonic-gate 	htable_t *ht;
5370Sstevel@tonic-gate 	htable_t htable;
5380Sstevel@tonic-gate 	uintptr_t base;
5390Sstevel@tonic-gate 	int h;
5400Sstevel@tonic-gate 	int level;
5410Sstevel@tonic-gate 	int entry;
5420Sstevel@tonic-gate 	x86pte_t pte;
5430Sstevel@tonic-gate 	x86pte_t buf;
5440Sstevel@tonic-gate 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
5450Sstevel@tonic-gate 	physaddr_t paddr;
5460Sstevel@tonic-gate 	size_t len;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	/*
549*1747Sjosephb 	 * The hats are kept in a list with khat at the head.
5500Sstevel@tonic-gate 	 */
551*1747Sjosephb 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
5520Sstevel@tonic-gate 		/*
5530Sstevel@tonic-gate 		 * read the hat and its hash table
5540Sstevel@tonic-gate 		 */
5550Sstevel@tonic-gate 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
5560Sstevel@tonic-gate 			mdb_warn("Couldn't read struct hat\n");
5570Sstevel@tonic-gate 			return (DCMD_ERR);
5580Sstevel@tonic-gate 		}
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 		/*
5610Sstevel@tonic-gate 		 * read the htable hashtable
5620Sstevel@tonic-gate 		 */
5630Sstevel@tonic-gate 		paddr = 0;
5640Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
5650Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
5660Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
5670Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
5680Sstevel@tonic-gate 				return (DCMD_ERR);
5690Sstevel@tonic-gate 			}
5700Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
5710Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
5720Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
5730Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
5740Sstevel@tonic-gate 					return (DCMD_ERR);
5750Sstevel@tonic-gate 				}
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 				/*
5780Sstevel@tonic-gate 				 * only report kernel addresses once
5790Sstevel@tonic-gate 				 */
5800Sstevel@tonic-gate 				if (hatp != khat &&
5810Sstevel@tonic-gate 				    htable.ht_vaddr >= kernelbase)
5820Sstevel@tonic-gate 					continue;
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 				/*
5850Sstevel@tonic-gate 				 * Is the PFN a pagetable itself?
5860Sstevel@tonic-gate 				 */
5870Sstevel@tonic-gate 				if (htable.ht_pfn == pfn) {
5880Sstevel@tonic-gate 					mdb_printf("Pagetable for "
5890Sstevel@tonic-gate 					    "hat=%p htable=%p\n", hatp, ht);
5900Sstevel@tonic-gate 					continue;
5910Sstevel@tonic-gate 				}
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 				/*
5940Sstevel@tonic-gate 				 * otherwise, examine page mappings
5950Sstevel@tonic-gate 				 */
5960Sstevel@tonic-gate 				level = htable.ht_level;
5970Sstevel@tonic-gate 				if (level > mmu.max_page_level)
5980Sstevel@tonic-gate 					continue;
5990Sstevel@tonic-gate 				paddr = htable.ht_pfn << MMU_PAGESHIFT;
6000Sstevel@tonic-gate 				for (entry = 0; entry < htable.ht_num_ptes;
6010Sstevel@tonic-gate 				    ++entry) {
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 					base = htable.ht_vaddr + entry *
6040Sstevel@tonic-gate 					    mmu.level_size[level];
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 					/*
6070Sstevel@tonic-gate 					 * only report kernel addresses once
6080Sstevel@tonic-gate 					 */
6090Sstevel@tonic-gate 					if (hatp != khat &&
6100Sstevel@tonic-gate 					    base >= kernelbase)
6110Sstevel@tonic-gate 						continue;
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 					len = mdb_pread(&buf, mmu.pte_size,
6140Sstevel@tonic-gate 					    paddr + entry * mmu.pte_size);
6150Sstevel@tonic-gate 					if (len != mmu.pte_size)
6160Sstevel@tonic-gate 						return (DCMD_ERR);
6170Sstevel@tonic-gate 					if (mmu.pte_size == sizeof (x86pte_t))
6180Sstevel@tonic-gate 						pte = buf;
6190Sstevel@tonic-gate 					else
6200Sstevel@tonic-gate 						pte = *pte32;
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 					if ((pte & PT_VALID) == 0)
6230Sstevel@tonic-gate 						continue;
6240Sstevel@tonic-gate 					if (level == 0 || !(pte & PT_PAGESIZE))
6250Sstevel@tonic-gate 						pte &= PT_PADDR;
6260Sstevel@tonic-gate 					else
6270Sstevel@tonic-gate 						pte &= PT_PADDR_LGPG;
6280Sstevel@tonic-gate 					if ((pte >> MMU_PAGESHIFT) != pfn)
6290Sstevel@tonic-gate 						continue;
6300Sstevel@tonic-gate 					mdb_printf("hat=%p maps addr=%p\n",
6310Sstevel@tonic-gate 						hatp, (caddr_t)base);
6320Sstevel@tonic-gate 				}
6330Sstevel@tonic-gate 			}
6340Sstevel@tonic-gate 		}
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate done:
6380Sstevel@tonic-gate 	return (DCMD_OK);
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate /*
6420Sstevel@tonic-gate  * given a PFN as its address argument, prints out the uses of it
6430Sstevel@tonic-gate  */
6440Sstevel@tonic-gate /*ARGSUSED*/
6450Sstevel@tonic-gate int
6460Sstevel@tonic-gate report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6470Sstevel@tonic-gate {
6480Sstevel@tonic-gate 	/*
6490Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
6500Sstevel@tonic-gate 	 */
6510Sstevel@tonic-gate 	get_mmu();
6520Sstevel@tonic-gate 	if (mmu.num_level == 0)
6530Sstevel@tonic-gate 		return (DCMD_ERR);
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
6560Sstevel@tonic-gate 		return (DCMD_USAGE);
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 	return (do_report_maps((pfn_t)addr));
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate /*
6620Sstevel@tonic-gate  * Dump the page table at the given PFN
6630Sstevel@tonic-gate  */
6640Sstevel@tonic-gate static int
6650Sstevel@tonic-gate do_ptable_dcmd(pfn_t pfn)
6660Sstevel@tonic-gate {
667*1747Sjosephb 	struct hat *hatp;
6680Sstevel@tonic-gate 	struct hat hat;
6690Sstevel@tonic-gate 	htable_t *ht;
6700Sstevel@tonic-gate 	htable_t htable;
6710Sstevel@tonic-gate 	uintptr_t base;
6720Sstevel@tonic-gate 	int h;
6730Sstevel@tonic-gate 	int level;
6740Sstevel@tonic-gate 	int entry;
6750Sstevel@tonic-gate 	uintptr_t pagesize;
6760Sstevel@tonic-gate 	x86pte_t pte;
6770Sstevel@tonic-gate 	x86pte_t buf;
6780Sstevel@tonic-gate 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
6790Sstevel@tonic-gate 	physaddr_t paddr;
6800Sstevel@tonic-gate 	size_t len;
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	/*
683*1747Sjosephb 	 * The hats are kept in a list with khat at the head.
6840Sstevel@tonic-gate 	 */
685*1747Sjosephb 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
6860Sstevel@tonic-gate 		/*
6870Sstevel@tonic-gate 		 * read the hat and its hash table
6880Sstevel@tonic-gate 		 */
6890Sstevel@tonic-gate 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
6900Sstevel@tonic-gate 			mdb_warn("Couldn't read struct hat\n");
6910Sstevel@tonic-gate 			return (DCMD_ERR);
6920Sstevel@tonic-gate 		}
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 		/*
6950Sstevel@tonic-gate 		 * read the htable hashtable
6960Sstevel@tonic-gate 		 */
6970Sstevel@tonic-gate 		paddr = 0;
6980Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
6990Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
7000Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
7010Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
7020Sstevel@tonic-gate 				return (DCMD_ERR);
7030Sstevel@tonic-gate 			}
7040Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
7050Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
7060Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
7070Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
7080Sstevel@tonic-gate 					return (DCMD_ERR);
7090Sstevel@tonic-gate 				}
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 				/*
7120Sstevel@tonic-gate 				 * Is this the PFN for this htable
7130Sstevel@tonic-gate 				 */
7140Sstevel@tonic-gate 				if (htable.ht_pfn == pfn)
7150Sstevel@tonic-gate 					goto found_it;
7160Sstevel@tonic-gate 			}
7170Sstevel@tonic-gate 		}
7180Sstevel@tonic-gate 	}
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate found_it:
7210Sstevel@tonic-gate 	if (htable.ht_pfn == pfn) {
7220Sstevel@tonic-gate 		mdb_printf("htable=%p\n", ht);
7230Sstevel@tonic-gate 		level = htable.ht_level;
7240Sstevel@tonic-gate 		base = htable.ht_vaddr;
7250Sstevel@tonic-gate 		pagesize = mmu.level_size[level];
7260Sstevel@tonic-gate 	} else {
7270Sstevel@tonic-gate 		mdb_printf("Unknown pagetable - assuming level/addr 0");
7280Sstevel@tonic-gate 		level = 0;	/* assume level == 0 for PFN */
7290Sstevel@tonic-gate 		base = 0;
7300Sstevel@tonic-gate 		pagesize = MMU_PAGESIZE;
7310Sstevel@tonic-gate 	}
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	paddr = pfn << MMU_PAGESHIFT;
7340Sstevel@tonic-gate 	for (entry = 0; entry < mmu.ptes_per_table; ++entry) {
7350Sstevel@tonic-gate 		len = mdb_pread(&buf, mmu.pte_size,
7360Sstevel@tonic-gate 		    paddr + entry * mmu.pte_size);
7370Sstevel@tonic-gate 		if (len != mmu.pte_size)
7380Sstevel@tonic-gate 			return (DCMD_ERR);
7390Sstevel@tonic-gate 		if (mmu.pte_size == sizeof (x86pte_t))
7400Sstevel@tonic-gate 			pte = buf;
7410Sstevel@tonic-gate 		else
7420Sstevel@tonic-gate 			pte = *pte32;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 		if (pte == 0)
7450Sstevel@tonic-gate 			continue;
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 		mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize);
7480Sstevel@tonic-gate 		do_pte_dcmd(level, pte);
7490Sstevel@tonic-gate 	}
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate done:
7520Sstevel@tonic-gate 	return (DCMD_OK);
7530Sstevel@tonic-gate }
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate /*
7560Sstevel@tonic-gate  * given a PFN as its address argument, prints out the uses of it
7570Sstevel@tonic-gate  */
7580Sstevel@tonic-gate /*ARGSUSED*/
7590Sstevel@tonic-gate int
7600Sstevel@tonic-gate ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
7610Sstevel@tonic-gate {
7620Sstevel@tonic-gate 	/*
7630Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
7640Sstevel@tonic-gate 	 */
7650Sstevel@tonic-gate 	get_mmu();
7660Sstevel@tonic-gate 	if (mmu.num_level == 0)
7670Sstevel@tonic-gate 		return (DCMD_ERR);
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
7700Sstevel@tonic-gate 		return (DCMD_USAGE);
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	return (do_ptable_dcmd((pfn_t)addr));
7730Sstevel@tonic-gate }
774