17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5a85a6733Sjosephb  * Common Development and Distribution License (the "License").
6a85a6733Sjosephb  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22cbdcbd05SJonathan Adams  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
2474ecdb51SJohn Levon  *
253b442230SJordan Paige Hendricks  * Copyright 2019 Joyent, Inc.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * This part of the file contains the mdb support for dcmds:
307c478bd9Sstevel@tonic-gate  *	::memseg_list
317c478bd9Sstevel@tonic-gate  * and walkers for:
327c478bd9Sstevel@tonic-gate  *	memseg - a memseg list walker for ::memseg_list
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <sys/types.h>
377c478bd9Sstevel@tonic-gate #include <sys/machparam.h>
387c478bd9Sstevel@tonic-gate #include <sys/controlregs.h>
39ae115bc7Smrj #include <sys/mach_mmu.h>
40843e1988Sjohnlev #ifdef __xpv
41843e1988Sjohnlev #include <sys/hypervisor.h>
42843e1988Sjohnlev #endif
437c478bd9Sstevel@tonic-gate #include <vm/as.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
467c478bd9Sstevel@tonic-gate #include <mdb/mdb_target.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #include <vm/page.h>
497c478bd9Sstevel@tonic-gate #include <vm/hat_i86.h>
507c478bd9Sstevel@tonic-gate 
5174ecdb51SJohn Levon #define	VA_SIGN_BIT (1UL << 47)
52*dea210b5SKeith M Wesolowski #define	VA_LOW_BITS	((1UL << 48) - 1)
53*dea210b5SKeith M Wesolowski #define	VA_SIGN_EXTEND(va) ((((va) & VA_LOW_BITS) ^ VA_SIGN_BIT) - VA_SIGN_BIT)
5474ecdb51SJohn Levon 
557c478bd9Sstevel@tonic-gate struct pfn2pp {
567c478bd9Sstevel@tonic-gate 	pfn_t pfn;
577c478bd9Sstevel@tonic-gate 	page_t *pp;
587c478bd9Sstevel@tonic-gate };
597c478bd9Sstevel@tonic-gate 
60ae115bc7Smrj static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *);
61843e1988Sjohnlev static void init_mmu(void);
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate int
platform_vtop(uintptr_t addr,struct as * asp,physaddr_t * pap)647c478bd9Sstevel@tonic-gate platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate 	if (asp == NULL)
677c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
687c478bd9Sstevel@tonic-gate 
69843e1988Sjohnlev 	init_mmu();
70843e1988Sjohnlev 
717c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
727c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
737c478bd9Sstevel@tonic-gate 
74ae115bc7Smrj 	return (do_va2pa(addr, asp, 0, pap, NULL));
757c478bd9Sstevel@tonic-gate }
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate /*
787c478bd9Sstevel@tonic-gate  * ::memseg_list dcmd and walker to implement it.
797c478bd9Sstevel@tonic-gate  */
807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
817c478bd9Sstevel@tonic-gate int
memseg_list(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)827c478bd9Sstevel@tonic-gate memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
837c478bd9Sstevel@tonic-gate {
847c478bd9Sstevel@tonic-gate 	struct memseg ms;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
877c478bd9Sstevel@tonic-gate 		if (mdb_pwalk_dcmd("memseg", "memseg_list",
887c478bd9Sstevel@tonic-gate 		    0, NULL, 0) == -1) {
897c478bd9Sstevel@tonic-gate 			mdb_warn("can't walk memseg");
907c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
917c478bd9Sstevel@tonic-gate 		}
927c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
937c478bd9Sstevel@tonic-gate 	}
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
967c478bd9Sstevel@tonic-gate 		mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
97843e1988Sjohnlev 		    "PAGES", "EPAGES", "BASE", "END");
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
1007c478bd9Sstevel@tonic-gate 		mdb_warn("can't read memseg at %#lx", addr);
1017c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1027c478bd9Sstevel@tonic-gate 	}
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr,
105843e1988Sjohnlev 	    ms.pages, ms.epages, ms.pages_base, ms.pages_end);
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate  * walk the memseg structures
1127c478bd9Sstevel@tonic-gate  */
1137c478bd9Sstevel@tonic-gate int
memseg_walk_init(mdb_walk_state_t * wsp)1147c478bd9Sstevel@tonic-gate memseg_walk_init(mdb_walk_state_t *wsp)
1157c478bd9Sstevel@tonic-gate {
116892ad162SToomas Soome 	if (wsp->walk_addr != 0) {
1177c478bd9Sstevel@tonic-gate 		mdb_warn("memseg only supports global walks\n");
1187c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
1197c478bd9Sstevel@tonic-gate 	}
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
1227c478bd9Sstevel@tonic-gate 		mdb_warn("symbol 'memsegs' not found");
1237c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
1247c478bd9Sstevel@tonic-gate 	}
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
1277c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate int
memseg_walk_step(mdb_walk_state_t * wsp)1327c478bd9Sstevel@tonic-gate memseg_walk_step(mdb_walk_state_t *wsp)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate 	int status;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == 0) {
1377c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
1387c478bd9Sstevel@tonic-gate 	}
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (struct memseg),
1417c478bd9Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
1427c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read struct memseg at %p", wsp->walk_addr);
1437c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
1447c478bd9Sstevel@tonic-gate 	}
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1477c478bd9Sstevel@tonic-gate 	    wsp->walk_cbdata);
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	return (status);
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate void
memseg_walk_fini(mdb_walk_state_t * wsp)1557c478bd9Sstevel@tonic-gate memseg_walk_fini(mdb_walk_state_t *wsp)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct memseg));
1587c478bd9Sstevel@tonic-gate }
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate /*
161ae115bc7Smrj  * Now HAT related dcmds.
1627c478bd9Sstevel@tonic-gate  */
1637c478bd9Sstevel@tonic-gate 
164843e1988Sjohnlev static struct hat *khat;		/* value of kas.a_hat */
1657c478bd9Sstevel@tonic-gate struct hat_mmu_info mmu;
1667c478bd9Sstevel@tonic-gate uintptr_t kernelbase;
1677c478bd9Sstevel@tonic-gate 
168843e1988Sjohnlev /*
169843e1988Sjohnlev  * stuff for i86xpv images
170843e1988Sjohnlev  */
171843e1988Sjohnlev static int is_xpv;
172843e1988Sjohnlev static uintptr_t mfn_list_addr; /* kernel MFN list address */
173843e1988Sjohnlev uintptr_t xen_virt_start; /* address of mfn_to_pfn[] table */
174843e1988Sjohnlev ulong_t mfn_count;	/* number of pfn's in the MFN list */
175843e1988Sjohnlev pfn_t *mfn_list;	/* local MFN list copy */
176843e1988Sjohnlev 
1777c478bd9Sstevel@tonic-gate /*
1787c478bd9Sstevel@tonic-gate  * read mmu parameters from kernel
1797c478bd9Sstevel@tonic-gate  */
1807c478bd9Sstevel@tonic-gate static void
init_mmu(void)181843e1988Sjohnlev init_mmu(void)
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate 	struct as kas;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	if (mmu.num_level != 0)
1867c478bd9Sstevel@tonic-gate 		return;
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1)
1897c478bd9Sstevel@tonic-gate 		mdb_warn("Can't use HAT information before mmu_init()\n");
1907c478bd9Sstevel@tonic-gate 	if (mdb_readsym(&kas, sizeof (kas), "kas") == -1)
1917c478bd9Sstevel@tonic-gate 		mdb_warn("Couldn't find kas - kernel's struct as\n");
1927c478bd9Sstevel@tonic-gate 	if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1)
1937c478bd9Sstevel@tonic-gate 		mdb_warn("Couldn't find kernelbase\n");
1947c478bd9Sstevel@tonic-gate 	khat = kas.a_hat;
195843e1988Sjohnlev 
196843e1988Sjohnlev 	/*
197843e1988Sjohnlev 	 * Is this a paravirtualized domain image?
198843e1988Sjohnlev 	 */
199843e1988Sjohnlev 	if (mdb_readsym(&mfn_list_addr, sizeof (mfn_list_addr),
200843e1988Sjohnlev 	    "mfn_list") == -1 ||
201843e1988Sjohnlev 	    mdb_readsym(&xen_virt_start, sizeof (xen_virt_start),
202843e1988Sjohnlev 	    "xen_virt_start") == -1 ||
203843e1988Sjohnlev 	    mdb_readsym(&mfn_count, sizeof (mfn_count), "mfn_count") == -1) {
204892ad162SToomas Soome 		mfn_list_addr = 0;
205843e1988Sjohnlev 	}
206843e1988Sjohnlev 
207892ad162SToomas Soome 	is_xpv = mfn_list_addr != 0;
208843e1988Sjohnlev 
209843e1988Sjohnlev #ifndef _KMDB
210843e1988Sjohnlev 	/*
211843e1988Sjohnlev 	 * recreate the local mfn_list
212843e1988Sjohnlev 	 */
213843e1988Sjohnlev 	if (is_xpv) {
214843e1988Sjohnlev 		size_t sz = mfn_count * sizeof (pfn_t);
215843e1988Sjohnlev 		mfn_list = mdb_zalloc(sz, UM_SLEEP);
216843e1988Sjohnlev 
217843e1988Sjohnlev 		if (mdb_vread(mfn_list, sz, (uintptr_t)mfn_list_addr) == -1) {
218843e1988Sjohnlev 			mdb_warn("Failed to read MFN list\n");
219843e1988Sjohnlev 			mdb_free(mfn_list, sz);
220843e1988Sjohnlev 			mfn_list = NULL;
221843e1988Sjohnlev 		}
222843e1988Sjohnlev 	}
223843e1988Sjohnlev #endif
224843e1988Sjohnlev }
225843e1988Sjohnlev 
226843e1988Sjohnlev void
free_mmu(void)227843e1988Sjohnlev free_mmu(void)
228843e1988Sjohnlev {
229843e1988Sjohnlev #ifdef __xpv
230843e1988Sjohnlev 	if (mfn_list != NULL)
231843e1988Sjohnlev 		mdb_free(mfn_list, mfn_count * sizeof (mfn_t));
232843e1988Sjohnlev #endif
233843e1988Sjohnlev }
234843e1988Sjohnlev 
235843e1988Sjohnlev #ifdef __xpv
236843e1988Sjohnlev 
237843e1988Sjohnlev #ifdef _KMDB
238843e1988Sjohnlev 
239843e1988Sjohnlev /*
240843e1988Sjohnlev  * Convert between MFNs and PFNs.  Since we're in kmdb we can go directly
241843e1988Sjohnlev  * through the machine to phys mapping and the MFN list.
242843e1988Sjohnlev  */
243843e1988Sjohnlev 
244843e1988Sjohnlev pfn_t
mdb_mfn_to_pfn(mfn_t mfn)245843e1988Sjohnlev mdb_mfn_to_pfn(mfn_t mfn)
246843e1988Sjohnlev {
247843e1988Sjohnlev 	pfn_t pfn;
248843e1988Sjohnlev 	mfn_t tmp;
249843e1988Sjohnlev 	pfn_t *pfn_list;
250843e1988Sjohnlev 
251892ad162SToomas Soome 	if (mfn_list_addr == 0)
252843e1988Sjohnlev 		return (-(pfn_t)1);
253843e1988Sjohnlev 
254843e1988Sjohnlev 	pfn_list = (pfn_t *)xen_virt_start;
255843e1988Sjohnlev 	if (mdb_vread(&pfn, sizeof (pfn), (uintptr_t)(pfn_list + mfn)) == -1)
256843e1988Sjohnlev 		return (-(pfn_t)1);
257843e1988Sjohnlev 
258843e1988Sjohnlev 	if (mdb_vread(&tmp, sizeof (tmp),
259843e1988Sjohnlev 	    (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
260843e1988Sjohnlev 		return (-(pfn_t)1);
261843e1988Sjohnlev 
262843e1988Sjohnlev 	if (pfn >= mfn_count || tmp != mfn)
263843e1988Sjohnlev 		return (-(pfn_t)1);
264843e1988Sjohnlev 
265843e1988Sjohnlev 	return (pfn);
266843e1988Sjohnlev }
267843e1988Sjohnlev 
268843e1988Sjohnlev mfn_t
mdb_pfn_to_mfn(pfn_t pfn)269843e1988Sjohnlev mdb_pfn_to_mfn(pfn_t pfn)
270843e1988Sjohnlev {
271843e1988Sjohnlev 	mfn_t mfn;
272843e1988Sjohnlev 
273843e1988Sjohnlev 	init_mmu();
274843e1988Sjohnlev 
275892ad162SToomas Soome 	if (mfn_list_addr == 0 || pfn >= mfn_count)
276843e1988Sjohnlev 		return (-(mfn_t)1);
277843e1988Sjohnlev 
278843e1988Sjohnlev 	if (mdb_vread(&mfn, sizeof (mfn),
279843e1988Sjohnlev 	    (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
280843e1988Sjohnlev 		return (-(mfn_t)1);
281843e1988Sjohnlev 
282843e1988Sjohnlev 	return (mfn);
283843e1988Sjohnlev }
284843e1988Sjohnlev 
285843e1988Sjohnlev #else /* _KMDB */
286843e1988Sjohnlev 
287843e1988Sjohnlev /*
288843e1988Sjohnlev  * Convert between MFNs and PFNs.  Since a crash dump doesn't include the
289843e1988Sjohnlev  * MFN->PFN translation table (it's part of the hypervisor, not our image)
290843e1988Sjohnlev  * we do the MFN->PFN translation by searching the PFN->MFN (mfn_list)
291843e1988Sjohnlev  * table, if it's there.
292843e1988Sjohnlev  */
293843e1988Sjohnlev 
294843e1988Sjohnlev pfn_t
mdb_mfn_to_pfn(mfn_t mfn)295843e1988Sjohnlev mdb_mfn_to_pfn(mfn_t mfn)
296843e1988Sjohnlev {
297843e1988Sjohnlev 	pfn_t pfn;
298843e1988Sjohnlev 
299843e1988Sjohnlev 	init_mmu();
300843e1988Sjohnlev 
301843e1988Sjohnlev 	if (mfn_list == NULL)
302843e1988Sjohnlev 		return (-(pfn_t)1);
303843e1988Sjohnlev 
304843e1988Sjohnlev 	for (pfn = 0; pfn < mfn_count; ++pfn) {
305843e1988Sjohnlev 		if (mfn_list[pfn] != mfn)
306843e1988Sjohnlev 			continue;
307843e1988Sjohnlev 		return (pfn);
308843e1988Sjohnlev 	}
309843e1988Sjohnlev 
310843e1988Sjohnlev 	return (-(pfn_t)1);
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate 
313843e1988Sjohnlev mfn_t
mdb_pfn_to_mfn(pfn_t pfn)314843e1988Sjohnlev mdb_pfn_to_mfn(pfn_t pfn)
315843e1988Sjohnlev {
316843e1988Sjohnlev 	init_mmu();
317843e1988Sjohnlev 
318843e1988Sjohnlev 	if (mfn_list == NULL || pfn >= mfn_count)
319843e1988Sjohnlev 		return (-(mfn_t)1);
320843e1988Sjohnlev 
321843e1988Sjohnlev 	return (mfn_list[pfn]);
322843e1988Sjohnlev }
323843e1988Sjohnlev 
324843e1988Sjohnlev #endif /* _KMDB */
325843e1988Sjohnlev 
326843e1988Sjohnlev static paddr_t
mdb_ma_to_pa(uint64_t ma)327843e1988Sjohnlev mdb_ma_to_pa(uint64_t ma)
328843e1988Sjohnlev {
329843e1988Sjohnlev 	pfn_t pfn = mdb_mfn_to_pfn(mmu_btop(ma));
330843e1988Sjohnlev 	if (pfn == -(pfn_t)1)
331843e1988Sjohnlev 		return (-(paddr_t)1);
332843e1988Sjohnlev 
333843e1988Sjohnlev 	return (mmu_ptob((paddr_t)pfn) | (ma & (MMU_PAGESIZE - 1)));
334843e1988Sjohnlev }
335843e1988Sjohnlev 
336843e1988Sjohnlev #else /* __xpv */
337843e1988Sjohnlev 
338ae115bc7Smrj #define	mdb_ma_to_pa(ma) (ma)
339ae115bc7Smrj #define	mdb_mfn_to_pfn(mfn) (mfn)
340ae115bc7Smrj #define	mdb_pfn_to_mfn(pfn) (pfn)
341ae115bc7Smrj 
342843e1988Sjohnlev #endif /* __xpv */
343843e1988Sjohnlev 
344843e1988Sjohnlev /*
345843e1988Sjohnlev  * ::mfntopfn dcmd translates hypervisor machine page number
346843e1988Sjohnlev  * to physical page number
347843e1988Sjohnlev  */
348843e1988Sjohnlev /*ARGSUSED*/
349843e1988Sjohnlev int
mfntopfn_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)350843e1988Sjohnlev mfntopfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
351843e1988Sjohnlev {
352843e1988Sjohnlev 	pfn_t pfn;
353843e1988Sjohnlev 
354843e1988Sjohnlev 	if ((flags & DCMD_ADDRSPEC) == 0) {
355843e1988Sjohnlev 		mdb_warn("MFN missing\n");
356843e1988Sjohnlev 		return (DCMD_USAGE);
357843e1988Sjohnlev 	}
358843e1988Sjohnlev 
359843e1988Sjohnlev 	if ((pfn = mdb_mfn_to_pfn((pfn_t)addr)) == -(pfn_t)1) {
360843e1988Sjohnlev 		mdb_warn("Invalid mfn %lr\n", (pfn_t)addr);
361843e1988Sjohnlev 		return (DCMD_ERR);
362843e1988Sjohnlev 	}
363843e1988Sjohnlev 
364843e1988Sjohnlev 	mdb_printf("%lr\n", pfn);
365843e1988Sjohnlev 
366843e1988Sjohnlev 	return (DCMD_OK);
367843e1988Sjohnlev }
368843e1988Sjohnlev 
369843e1988Sjohnlev /*
370843e1988Sjohnlev  * ::pfntomfn dcmd translates physical page number to
371843e1988Sjohnlev  * hypervisor machine page number
372843e1988Sjohnlev  */
373843e1988Sjohnlev /*ARGSUSED*/
374843e1988Sjohnlev int
pfntomfn_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)375843e1988Sjohnlev pfntomfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
376843e1988Sjohnlev {
377843e1988Sjohnlev 	pfn_t mfn;
378843e1988Sjohnlev 
379843e1988Sjohnlev 	if ((flags & DCMD_ADDRSPEC) == 0) {
380843e1988Sjohnlev 		mdb_warn("PFN missing\n");
381843e1988Sjohnlev 		return (DCMD_USAGE);
382843e1988Sjohnlev 	}
383843e1988Sjohnlev 
384843e1988Sjohnlev 	if ((mfn = mdb_pfn_to_mfn((pfn_t)addr)) == -(pfn_t)1) {
385843e1988Sjohnlev 		mdb_warn("Invalid pfn %lr\n", (pfn_t)addr);
386843e1988Sjohnlev 		return (DCMD_ABORT);
387843e1988Sjohnlev 	}
388843e1988Sjohnlev 
389843e1988Sjohnlev 	mdb_printf("%lr\n", mfn);
390843e1988Sjohnlev 
391843e1988Sjohnlev 	if (flags & DCMD_LOOP)
392843e1988Sjohnlev 		mdb_set_dot(addr + 1);
393843e1988Sjohnlev 	return (DCMD_OK);
394843e1988Sjohnlev }
395843e1988Sjohnlev 
396ae115bc7Smrj static pfn_t
pte2mfn(x86pte_t pte,uint_t level)397ae115bc7Smrj pte2mfn(x86pte_t pte, uint_t level)
398ae115bc7Smrj {
399ae115bc7Smrj 	pfn_t mfn;
400ae115bc7Smrj 	if (level > 0 && (pte & PT_PAGESIZE))
401ae115bc7Smrj 		mfn = mmu_btop(pte & PT_PADDR_LGPG);
402ae115bc7Smrj 	else
403ae115bc7Smrj 		mfn = mmu_btop(pte & PT_PADDR);
404ae115bc7Smrj 	return (mfn);
405ae115bc7Smrj }
406ae115bc7Smrj 
4077c478bd9Sstevel@tonic-gate static int
do_pte_dcmd(int level,uint64_t pte)4087c478bd9Sstevel@tonic-gate do_pte_dcmd(int level, uint64_t pte)
4097c478bd9Sstevel@tonic-gate {
4107c478bd9Sstevel@tonic-gate 	static char *attr[] = {
4117c478bd9Sstevel@tonic-gate 	    "wrback", "wrthru", "uncached", "uncached",
4127c478bd9Sstevel@tonic-gate 	    "wrback", "wrthru", "wrcombine", "uncached"};
4137c478bd9Sstevel@tonic-gate 	int pat_index = 0;
414ae115bc7Smrj 	pfn_t mfn;
4157c478bd9Sstevel@tonic-gate 
41674ecdb51SJohn Levon 	mdb_printf("pte=0x%llr: ", pte);
4177c478bd9Sstevel@tonic-gate 
418ae115bc7Smrj 	mfn = pte2mfn(pte, level);
419843e1988Sjohnlev 	mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn);
4207c478bd9Sstevel@tonic-gate 
42174ecdb51SJohn Levon 	if (PTE_GET(pte, mmu.pt_nx))
42274ecdb51SJohn Levon 		mdb_printf("noexec ");
42374ecdb51SJohn Levon 
4247c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOCONSIST))
4257c478bd9Sstevel@tonic-gate 		mdb_printf("noconsist ");
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOSYNC))
4287c478bd9Sstevel@tonic-gate 		mdb_printf("nosync ");
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, mmu.pt_global))
4317c478bd9Sstevel@tonic-gate 		mdb_printf("global ");
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
4347c478bd9Sstevel@tonic-gate 		mdb_printf("largepage ");
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_MOD))
4377c478bd9Sstevel@tonic-gate 		mdb_printf("mod ");
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_REF))
4407c478bd9Sstevel@tonic-gate 		mdb_printf("ref ");
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, PT_USER))
4437c478bd9Sstevel@tonic-gate 		mdb_printf("user ");
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, PT_WRITABLE))
4467c478bd9Sstevel@tonic-gate 		mdb_printf("write ");
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	/*
4497c478bd9Sstevel@tonic-gate 	 * Report non-standard cacheability
4507c478bd9Sstevel@tonic-gate 	 */
4517c478bd9Sstevel@tonic-gate 	pat_index = 0;
4527c478bd9Sstevel@tonic-gate 	if (level > 0) {
4537c478bd9Sstevel@tonic-gate 		if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE))
4547c478bd9Sstevel@tonic-gate 			pat_index += 4;
4557c478bd9Sstevel@tonic-gate 	} else {
4567c478bd9Sstevel@tonic-gate 		if (PTE_GET(pte, PT_PAT_4K))
4577c478bd9Sstevel@tonic-gate 			pat_index += 4;
4587c478bd9Sstevel@tonic-gate 	}
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOCACHE))
4617c478bd9Sstevel@tonic-gate 		pat_index += 2;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, PT_WRITETHRU))
4647c478bd9Sstevel@tonic-gate 		pat_index += 1;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	if (pat_index != 0)
4677c478bd9Sstevel@tonic-gate 		mdb_printf("%s", attr[pat_index]);
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, PT_VALID) == 0)
4707c478bd9Sstevel@tonic-gate 		mdb_printf(" !VALID ");
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
4737c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate /*
4777c478bd9Sstevel@tonic-gate  * Print a PTE in more human friendly way. The PTE is assumed to be in
4787c478bd9Sstevel@tonic-gate  * a level 0 page table, unless -l specifies another level.
4797c478bd9Sstevel@tonic-gate  */
4807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4817c478bd9Sstevel@tonic-gate int
pte_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4827c478bd9Sstevel@tonic-gate pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4837c478bd9Sstevel@tonic-gate {
48474ecdb51SJohn Levon 	uint64_t level = 0;
4857c478bd9Sstevel@tonic-gate 
486843e1988Sjohnlev 	init_mmu();
487843e1988Sjohnlev 
4887c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
4897c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
4907c478bd9Sstevel@tonic-gate 
49174ecdb51SJohn Levon 	if ((flags & DCMD_ADDRSPEC) == 0)
49274ecdb51SJohn Levon 		return (DCMD_USAGE);
49374ecdb51SJohn Levon 
4947c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
4953b442230SJordan Paige Hendricks 	    'l', MDB_OPT_UINT64, &level, NULL) != argc)
4967c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
4977c478bd9Sstevel@tonic-gate 
49874ecdb51SJohn Levon 	if (level > mmu.max_level) {
49974ecdb51SJohn Levon 		mdb_warn("invalid level %lu\n", level);
50074ecdb51SJohn Levon 		return (DCMD_ERR);
5017c478bd9Sstevel@tonic-gate 	}
5027c478bd9Sstevel@tonic-gate 
50374ecdb51SJohn Levon 	if (addr == 0)
50474ecdb51SJohn Levon 		return (DCMD_OK);
5057c478bd9Sstevel@tonic-gate 
50674ecdb51SJohn Levon 	return (do_pte_dcmd((int)level, addr));
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate 
509ae115bc7Smrj static size_t
va2entry(htable_t * htable,uintptr_t addr)510ae115bc7Smrj va2entry(htable_t *htable, uintptr_t addr)
511ae115bc7Smrj {
512ae115bc7Smrj 	size_t entry = (addr - htable->ht_vaddr);
513ae115bc7Smrj 
514ae115bc7Smrj 	entry >>= mmu.level_shift[htable->ht_level];
515ae115bc7Smrj 	return (entry & HTABLE_NUM_PTES(htable) - 1);
516ae115bc7Smrj }
517ae115bc7Smrj 
518ae115bc7Smrj static x86pte_t
get_pte(hat_t * hat,htable_t * htable,uintptr_t addr)519ae115bc7Smrj get_pte(hat_t *hat, htable_t *htable, uintptr_t addr)
520ae115bc7Smrj {
521ae115bc7Smrj 	x86pte_t buf;
522ae115bc7Smrj 
52374ecdb51SJohn Levon 	if (htable->ht_flags & HTABLE_COPIED) {
52474ecdb51SJohn Levon 		uintptr_t ptr = (uintptr_t)hat->hat_copied_ptes;
525ae115bc7Smrj 		ptr += va2entry(htable, addr) << mmu.pte_size_shift;
52674ecdb51SJohn Levon 		return (*(x86pte_t *)ptr);
527ae115bc7Smrj 	}
528ae115bc7Smrj 
52974ecdb51SJohn Levon 	paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn);
53074ecdb51SJohn Levon 	paddr += va2entry(htable, addr) << mmu.pte_size_shift;
531ae115bc7Smrj 
53274ecdb51SJohn Levon 	if ((mdb_pread(&buf, mmu.pte_size, paddr)) == mmu.pte_size)
533ae115bc7Smrj 		return (buf);
53474ecdb51SJohn Levon 
53574ecdb51SJohn Levon 	return (0);
536ae115bc7Smrj }
537ae115bc7Smrj 
5387c478bd9Sstevel@tonic-gate static int
do_va2pa(uintptr_t addr,struct as * asp,int print_level,physaddr_t * pap,pfn_t * mfnp)539ae115bc7Smrj do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap,
540ae115bc7Smrj     pfn_t *mfnp)
5417c478bd9Sstevel@tonic-gate {
5427c478bd9Sstevel@tonic-gate 	struct as as;
5437c478bd9Sstevel@tonic-gate 	struct hat *hatp;
5447c478bd9Sstevel@tonic-gate 	struct hat hat;
5457c478bd9Sstevel@tonic-gate 	htable_t *ht;
5467c478bd9Sstevel@tonic-gate 	htable_t htable;
5477c478bd9Sstevel@tonic-gate 	uintptr_t base;
5487c478bd9Sstevel@tonic-gate 	int h;
5497c478bd9Sstevel@tonic-gate 	int level;
5507c478bd9Sstevel@tonic-gate 	int found = 0;
5517c478bd9Sstevel@tonic-gate 	x86pte_t pte;
5527c478bd9Sstevel@tonic-gate 	physaddr_t paddr;
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	if (asp != NULL) {
5557c478bd9Sstevel@tonic-gate 		if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
5567c478bd9Sstevel@tonic-gate 			mdb_warn("Couldn't read struct as\n");
5577c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
5587c478bd9Sstevel@tonic-gate 		}
5597c478bd9Sstevel@tonic-gate 		hatp = as.a_hat;
5607c478bd9Sstevel@tonic-gate 	} else {
5617c478bd9Sstevel@tonic-gate 		hatp = khat;
5627c478bd9Sstevel@tonic-gate 	}
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	/*
5657c478bd9Sstevel@tonic-gate 	 * read the hat and its hash table
5667c478bd9Sstevel@tonic-gate 	 */
5677c478bd9Sstevel@tonic-gate 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
5687c478bd9Sstevel@tonic-gate 		mdb_warn("Couldn't read struct hat\n");
5697c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
5707c478bd9Sstevel@tonic-gate 	}
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	/*
5737c478bd9Sstevel@tonic-gate 	 * read the htable hashtable
5747c478bd9Sstevel@tonic-gate 	 */
5757c478bd9Sstevel@tonic-gate 	for (level = 0; level <= mmu.max_level; ++level) {
576ae115bc7Smrj 		if (level == TOP_LEVEL(&hat))
5777c478bd9Sstevel@tonic-gate 			base = 0;
5787c478bd9Sstevel@tonic-gate 		else
5797c478bd9Sstevel@tonic-gate 			base = addr & mmu.level_mask[level + 1];
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
5827c478bd9Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
5837c478bd9Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
5847c478bd9Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
5857c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
5867c478bd9Sstevel@tonic-gate 			}
5877c478bd9Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
5887c478bd9Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
5897c478bd9Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
5907c478bd9Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
5917c478bd9Sstevel@tonic-gate 					return (DCMD_ERR);
5927c478bd9Sstevel@tonic-gate 				}
593ae115bc7Smrj 
5947c478bd9Sstevel@tonic-gate 				if (htable.ht_vaddr != base ||
5957c478bd9Sstevel@tonic-gate 				    htable.ht_level != level)
5967c478bd9Sstevel@tonic-gate 					continue;
5977c478bd9Sstevel@tonic-gate 
598ae115bc7Smrj 				pte = get_pte(&hat, &htable, addr);
5997c478bd9Sstevel@tonic-gate 
600ae115bc7Smrj 				if (print_level) {
60174ecdb51SJohn Levon 					mdb_printf("\tlevel=%d htable=0x%p "
60274ecdb51SJohn Levon 					    "pte=0x%llr\n", level, ht, pte);
6037c478bd9Sstevel@tonic-gate 				}
604ae115bc7Smrj 
605ae115bc7Smrj 				if (!PTE_ISVALID(pte)) {
606ae115bc7Smrj 					mdb_printf("Address %p is unmapped.\n",
607ae115bc7Smrj 					    addr);
608ae115bc7Smrj 					return (DCMD_ERR);
609ae115bc7Smrj 				}
610ae115bc7Smrj 
611ae115bc7Smrj 				if (found)
6127c478bd9Sstevel@tonic-gate 					continue;
613ae115bc7Smrj 
614ae115bc7Smrj 				if (PTE_IS_LGPG(pte, level))
615ae115bc7Smrj 					paddr = mdb_ma_to_pa(pte &
616ae115bc7Smrj 					    PT_PADDR_LGPG);
617ae115bc7Smrj 				else
618ae115bc7Smrj 					paddr = mdb_ma_to_pa(pte & PT_PADDR);
619ae115bc7Smrj 				paddr += addr & mmu.level_offset[level];
620ae115bc7Smrj 				if (pap != NULL)
621ae115bc7Smrj 					*pap = paddr;
622ae115bc7Smrj 				if (mfnp != NULL)
623ae115bc7Smrj 					*mfnp = pte2mfn(pte, level);
624ae115bc7Smrj 				found = 1;
6257c478bd9Sstevel@tonic-gate 			}
6267c478bd9Sstevel@tonic-gate 		}
6277c478bd9Sstevel@tonic-gate 	}
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate done:
6307c478bd9Sstevel@tonic-gate 	if (!found)
6317c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
6327c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate int
va2pfn_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)6367c478bd9Sstevel@tonic-gate va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6377c478bd9Sstevel@tonic-gate {
6387c478bd9Sstevel@tonic-gate 	uintptr_t addrspace;
6397c478bd9Sstevel@tonic-gate 	char *addrspace_str = NULL;
640ae115bc7Smrj 	int piped = flags & DCMD_PIPE_OUT;
641ae115bc7Smrj 	pfn_t pfn;
642ae115bc7Smrj 	pfn_t mfn;
6437c478bd9Sstevel@tonic-gate 	int rc;
6447c478bd9Sstevel@tonic-gate 
645843e1988Sjohnlev 	init_mmu();
646843e1988Sjohnlev 
6477c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
6487c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
6513b442230SJordan Paige Hendricks 	    'a', MDB_OPT_STR, &addrspace_str, NULL) != argc)
6527c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
6557c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	/*
6587c478bd9Sstevel@tonic-gate 	 * parse the address space
6597c478bd9Sstevel@tonic-gate 	 */
6607c478bd9Sstevel@tonic-gate 	if (addrspace_str != NULL)
6617c478bd9Sstevel@tonic-gate 		addrspace = mdb_strtoull(addrspace_str);
6627c478bd9Sstevel@tonic-gate 	else
6637c478bd9Sstevel@tonic-gate 		addrspace = 0;
6647c478bd9Sstevel@tonic-gate 
665ae115bc7Smrj 	rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn);
666ae115bc7Smrj 
667ae115bc7Smrj 	if (rc != DCMD_OK)
668ae115bc7Smrj 		return (rc);
669ae115bc7Smrj 
670ae115bc7Smrj 	if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) {
671ae115bc7Smrj 		mdb_warn("Invalid mfn %lr\n", mfn);
672ae115bc7Smrj 		return (DCMD_ERR);
673ae115bc7Smrj 	}
674ae115bc7Smrj 
675ae115bc7Smrj 	if (piped) {
676ae115bc7Smrj 		mdb_printf("0x%lr\n", pfn);
677ae115bc7Smrj 		return (DCMD_OK);
678ae115bc7Smrj 	}
6797c478bd9Sstevel@tonic-gate 
680ae115bc7Smrj 	mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn);
6817c478bd9Sstevel@tonic-gate 
682843e1988Sjohnlev 	if (is_xpv)
683843e1988Sjohnlev 		mdb_printf(" (mfn 0x%lr)", mfn);
684843e1988Sjohnlev 
685ae115bc7Smrj 	mdb_printf("\n");
686ae115bc7Smrj 
687ae115bc7Smrj 	return (DCMD_OK);
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate /*
6917c478bd9Sstevel@tonic-gate  * Report all hat's that either use PFN as a page table or that map the page.
6927c478bd9Sstevel@tonic-gate  */
6937c478bd9Sstevel@tonic-gate static int
do_report_maps(pfn_t pfn)6947c478bd9Sstevel@tonic-gate do_report_maps(pfn_t pfn)
6957c478bd9Sstevel@tonic-gate {
696a85a6733Sjosephb 	struct hat *hatp;
6977c478bd9Sstevel@tonic-gate 	struct hat hat;
6987c478bd9Sstevel@tonic-gate 	htable_t *ht;
6997c478bd9Sstevel@tonic-gate 	htable_t htable;
7007c478bd9Sstevel@tonic-gate 	uintptr_t base;
7017c478bd9Sstevel@tonic-gate 	int h;
7027c478bd9Sstevel@tonic-gate 	int level;
7037c478bd9Sstevel@tonic-gate 	int entry;
7047c478bd9Sstevel@tonic-gate 	x86pte_t pte;
7057c478bd9Sstevel@tonic-gate 	physaddr_t paddr;
7067c478bd9Sstevel@tonic-gate 	size_t len;
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	/*
709a85a6733Sjosephb 	 * The hats are kept in a list with khat at the head.
7107c478bd9Sstevel@tonic-gate 	 */
711a85a6733Sjosephb 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
7127c478bd9Sstevel@tonic-gate 		/*
7137c478bd9Sstevel@tonic-gate 		 * read the hat and its hash table
7147c478bd9Sstevel@tonic-gate 		 */
7157c478bd9Sstevel@tonic-gate 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
7167c478bd9Sstevel@tonic-gate 			mdb_warn("Couldn't read struct hat\n");
7177c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
7187c478bd9Sstevel@tonic-gate 		}
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 		/*
7217c478bd9Sstevel@tonic-gate 		 * read the htable hashtable
7227c478bd9Sstevel@tonic-gate 		 */
7237c478bd9Sstevel@tonic-gate 		paddr = 0;
7247c478bd9Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
7257c478bd9Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
7267c478bd9Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
7277c478bd9Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
7287c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
7297c478bd9Sstevel@tonic-gate 			}
7307c478bd9Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
7317c478bd9Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
7327c478bd9Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
7337c478bd9Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
7347c478bd9Sstevel@tonic-gate 					return (DCMD_ERR);
7357c478bd9Sstevel@tonic-gate 				}
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 				/*
7387c478bd9Sstevel@tonic-gate 				 * only report kernel addresses once
7397c478bd9Sstevel@tonic-gate 				 */
7407c478bd9Sstevel@tonic-gate 				if (hatp != khat &&
7417c478bd9Sstevel@tonic-gate 				    htable.ht_vaddr >= kernelbase)
7427c478bd9Sstevel@tonic-gate 					continue;
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 				/*
7457c478bd9Sstevel@tonic-gate 				 * Is the PFN a pagetable itself?
7467c478bd9Sstevel@tonic-gate 				 */
7477c478bd9Sstevel@tonic-gate 				if (htable.ht_pfn == pfn) {
7487c478bd9Sstevel@tonic-gate 					mdb_printf("Pagetable for "
7497c478bd9Sstevel@tonic-gate 					    "hat=%p htable=%p\n", hatp, ht);
7507c478bd9Sstevel@tonic-gate 					continue;
7517c478bd9Sstevel@tonic-gate 				}
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 				/*
7547c478bd9Sstevel@tonic-gate 				 * otherwise, examine page mappings
7557c478bd9Sstevel@tonic-gate 				 */
7567c478bd9Sstevel@tonic-gate 				level = htable.ht_level;
7577c478bd9Sstevel@tonic-gate 				if (level > mmu.max_page_level)
7587c478bd9Sstevel@tonic-gate 					continue;
759ae115bc7Smrj 				paddr = mmu_ptob((physaddr_t)htable.ht_pfn);
760ae115bc7Smrj 				for (entry = 0;
761ae115bc7Smrj 				    entry < HTABLE_NUM_PTES(&htable);
7627c478bd9Sstevel@tonic-gate 				    ++entry) {
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 					base = htable.ht_vaddr + entry *
7657c478bd9Sstevel@tonic-gate 					    mmu.level_size[level];
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 					/*
7687c478bd9Sstevel@tonic-gate 					 * only report kernel addresses once
7697c478bd9Sstevel@tonic-gate 					 */
7707c478bd9Sstevel@tonic-gate 					if (hatp != khat &&
7717c478bd9Sstevel@tonic-gate 					    base >= kernelbase)
7727c478bd9Sstevel@tonic-gate 						continue;
7737c478bd9Sstevel@tonic-gate 
77474ecdb51SJohn Levon 					len = mdb_pread(&pte, mmu.pte_size,
7757c478bd9Sstevel@tonic-gate 					    paddr + entry * mmu.pte_size);
7767c478bd9Sstevel@tonic-gate 					if (len != mmu.pte_size)
7777c478bd9Sstevel@tonic-gate 						return (DCMD_ERR);
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 					if ((pte & PT_VALID) == 0)
7807c478bd9Sstevel@tonic-gate 						continue;
7817c478bd9Sstevel@tonic-gate 					if (level == 0 || !(pte & PT_PAGESIZE))
7827c478bd9Sstevel@tonic-gate 						pte &= PT_PADDR;
7837c478bd9Sstevel@tonic-gate 					else
7847c478bd9Sstevel@tonic-gate 						pte &= PT_PADDR_LGPG;
785ae115bc7Smrj 					if (mmu_btop(mdb_ma_to_pa(pte)) != pfn)
7867c478bd9Sstevel@tonic-gate 						continue;
7877c478bd9Sstevel@tonic-gate 					mdb_printf("hat=%p maps addr=%p\n",
788843e1988Sjohnlev 					    hatp, (caddr_t)base);
7897c478bd9Sstevel@tonic-gate 				}
7907c478bd9Sstevel@tonic-gate 			}
7917c478bd9Sstevel@tonic-gate 		}
7927c478bd9Sstevel@tonic-gate 	}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate done:
7957c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate /*
7997c478bd9Sstevel@tonic-gate  * given a PFN as its address argument, prints out the uses of it
8007c478bd9Sstevel@tonic-gate  */
8017c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8027c478bd9Sstevel@tonic-gate int
report_maps_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)8037c478bd9Sstevel@tonic-gate report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
8047c478bd9Sstevel@tonic-gate {
805ae115bc7Smrj 	pfn_t pfn;
806ae115bc7Smrj 	uint_t mflag = 0;
807ae115bc7Smrj 
808843e1988Sjohnlev 	init_mmu();
809843e1988Sjohnlev 
8107c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
8117c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
8147c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
8157c478bd9Sstevel@tonic-gate 
816ae115bc7Smrj 	if (mdb_getopts(argc, argv,
817ae115bc7Smrj 	    'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
818ae115bc7Smrj 		return (DCMD_USAGE);
819ae115bc7Smrj 
820ae115bc7Smrj 	pfn = (pfn_t)addr;
821ae115bc7Smrj 	if (mflag)
822ae115bc7Smrj 		pfn = mdb_mfn_to_pfn(pfn);
823ae115bc7Smrj 
824ae115bc7Smrj 	return (do_report_maps(pfn));
8257c478bd9Sstevel@tonic-gate }
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate static int
do_ptable_dcmd(pfn_t pfn,uint64_t level)82874ecdb51SJohn Levon do_ptable_dcmd(pfn_t pfn, uint64_t level)
8297c478bd9Sstevel@tonic-gate {
830a85a6733Sjosephb 	struct hat *hatp;
8317c478bd9Sstevel@tonic-gate 	struct hat hat;
8327c478bd9Sstevel@tonic-gate 	htable_t *ht;
8337c478bd9Sstevel@tonic-gate 	htable_t htable;
8347c478bd9Sstevel@tonic-gate 	uintptr_t base;
8357c478bd9Sstevel@tonic-gate 	int h;
8367c478bd9Sstevel@tonic-gate 	int entry;
8377c478bd9Sstevel@tonic-gate 	uintptr_t pagesize;
8387c478bd9Sstevel@tonic-gate 	x86pte_t pte;
8397c478bd9Sstevel@tonic-gate 	physaddr_t paddr;
8407c478bd9Sstevel@tonic-gate 	size_t len;
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	/*
843a85a6733Sjosephb 	 * The hats are kept in a list with khat at the head.
8447c478bd9Sstevel@tonic-gate 	 */
845a85a6733Sjosephb 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
8467c478bd9Sstevel@tonic-gate 		/*
8477c478bd9Sstevel@tonic-gate 		 * read the hat and its hash table
8487c478bd9Sstevel@tonic-gate 		 */
8497c478bd9Sstevel@tonic-gate 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
8507c478bd9Sstevel@tonic-gate 			mdb_warn("Couldn't read struct hat\n");
8517c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
8527c478bd9Sstevel@tonic-gate 		}
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 		/*
8557c478bd9Sstevel@tonic-gate 		 * read the htable hashtable
8567c478bd9Sstevel@tonic-gate 		 */
8577c478bd9Sstevel@tonic-gate 		paddr = 0;
8587c478bd9Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
8597c478bd9Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
8607c478bd9Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
8617c478bd9Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
8627c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
8637c478bd9Sstevel@tonic-gate 			}
8647c478bd9Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
8657c478bd9Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
8667c478bd9Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
8677c478bd9Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
8687c478bd9Sstevel@tonic-gate 					return (DCMD_ERR);
8697c478bd9Sstevel@tonic-gate 				}
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 				/*
8727c478bd9Sstevel@tonic-gate 				 * Is this the PFN for this htable
8737c478bd9Sstevel@tonic-gate 				 */
8747c478bd9Sstevel@tonic-gate 				if (htable.ht_pfn == pfn)
8757c478bd9Sstevel@tonic-gate 					goto found_it;
8767c478bd9Sstevel@tonic-gate 			}
8777c478bd9Sstevel@tonic-gate 		}
8787c478bd9Sstevel@tonic-gate 	}
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate found_it:
8817c478bd9Sstevel@tonic-gate 	if (htable.ht_pfn == pfn) {
8827c478bd9Sstevel@tonic-gate 		mdb_printf("htable=%p\n", ht);
88374ecdb51SJohn Levon 		if (level == (uint64_t)-1) {
88474ecdb51SJohn Levon 			level = htable.ht_level;
88574ecdb51SJohn Levon 		} else if (htable.ht_level != level) {
88674ecdb51SJohn Levon 			mdb_warn("htable has level %d but forcing level %lu\n",
88774ecdb51SJohn Levon 			    htable.ht_level, level);
88874ecdb51SJohn Levon 		}
8897c478bd9Sstevel@tonic-gate 		base = htable.ht_vaddr;
8907c478bd9Sstevel@tonic-gate 		pagesize = mmu.level_size[level];
8917c478bd9Sstevel@tonic-gate 	} else {
89274ecdb51SJohn Levon 		if (level == (uint64_t)-1)
89374ecdb51SJohn Levon 			level = 0;
89474ecdb51SJohn Levon 		mdb_warn("couldn't find matching htable, using level=%lu, "
89574ecdb51SJohn Levon 		    "base address=0x0\n", level);
8967c478bd9Sstevel@tonic-gate 		base = 0;
89774ecdb51SJohn Levon 		pagesize = mmu.level_size[level];
8987c478bd9Sstevel@tonic-gate 	}
8997c478bd9Sstevel@tonic-gate 
900ae115bc7Smrj 	paddr = mmu_ptob((physaddr_t)pfn);
9017c478bd9Sstevel@tonic-gate 	for (entry = 0; entry < mmu.ptes_per_table; ++entry) {
902ff9e88ceSJohn Levon 		len = mdb_pread(&pte, mmu.pte_size,
9037c478bd9Sstevel@tonic-gate 		    paddr + entry * mmu.pte_size);
9047c478bd9Sstevel@tonic-gate 		if (len != mmu.pte_size)
9057c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 		if (pte == 0)
9087c478bd9Sstevel@tonic-gate 			continue;
9097c478bd9Sstevel@tonic-gate 
91074ecdb51SJohn Levon 		mdb_printf("[%3d] va=0x%p ", entry,
91174ecdb51SJohn Levon 		    VA_SIGN_EXTEND(base + entry * pagesize));
9127c478bd9Sstevel@tonic-gate 		do_pte_dcmd(level, pte);
9137c478bd9Sstevel@tonic-gate 	}
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate done:
9167c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
9177c478bd9Sstevel@tonic-gate }
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate /*
920ae115bc7Smrj  * Dump the page table at the given PFN
9217c478bd9Sstevel@tonic-gate  */
9227c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9237c478bd9Sstevel@tonic-gate int
ptable_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)9247c478bd9Sstevel@tonic-gate ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
9257c478bd9Sstevel@tonic-gate {
926ae115bc7Smrj 	pfn_t pfn;
927ae115bc7Smrj 	uint_t mflag = 0;
92874ecdb51SJohn Levon 	uint64_t level = (uint64_t)-1;
929ae115bc7Smrj 
930843e1988Sjohnlev 	init_mmu();
931843e1988Sjohnlev 
932ae115bc7Smrj 	if (mmu.num_level == 0)
933ae115bc7Smrj 		return (DCMD_ERR);
934ae115bc7Smrj 
935ae115bc7Smrj 	if ((flags & DCMD_ADDRSPEC) == 0)
936ae115bc7Smrj 		return (DCMD_USAGE);
937ae115bc7Smrj 
938ae115bc7Smrj 	if (mdb_getopts(argc, argv,
93974ecdb51SJohn Levon 	    'm', MDB_OPT_SETBITS, TRUE, &mflag,
94074ecdb51SJohn Levon 	    'l', MDB_OPT_UINT64, &level, NULL) != argc)
941ae115bc7Smrj 		return (DCMD_USAGE);
942ae115bc7Smrj 
94374ecdb51SJohn Levon 	if (level != (uint64_t)-1 && level > mmu.max_level) {
94474ecdb51SJohn Levon 		mdb_warn("invalid level %lu\n", level);
94574ecdb51SJohn Levon 		return (DCMD_ERR);
94674ecdb51SJohn Levon 	}
94774ecdb51SJohn Levon 
948ae115bc7Smrj 	pfn = (pfn_t)addr;
949ae115bc7Smrj 	if (mflag)
950ae115bc7Smrj 		pfn = mdb_mfn_to_pfn(pfn);
951ae115bc7Smrj 
95274ecdb51SJohn Levon 	return (do_ptable_dcmd(pfn, level));
953ae115bc7Smrj }
954ae115bc7Smrj 
955ae115bc7Smrj static int
do_htables_dcmd(hat_t * hatp)956ae115bc7Smrj do_htables_dcmd(hat_t *hatp)
957ae115bc7Smrj {
958ae115bc7Smrj 	struct hat hat;
959ae115bc7Smrj 	htable_t *ht;
960ae115bc7Smrj 	htable_t htable;
961ae115bc7Smrj 	int h;
962ae115bc7Smrj 
963ae115bc7Smrj 	/*
964ae115bc7Smrj 	 * read the hat and its hash table
965ae115bc7Smrj 	 */
966ae115bc7Smrj 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
967ae115bc7Smrj 		mdb_warn("Couldn't read struct hat\n");
968ae115bc7Smrj 		return (DCMD_ERR);
969ae115bc7Smrj 	}
970ae115bc7Smrj 
971ae115bc7Smrj 	/*
972ae115bc7Smrj 	 * read the htable hashtable
973ae115bc7Smrj 	 */
974ae115bc7Smrj 	for (h = 0; h < hat.hat_num_hash; ++h) {
975ae115bc7Smrj 		if (mdb_vread(&ht, sizeof (htable_t *),
976ae115bc7Smrj 		    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
977ae115bc7Smrj 			mdb_warn("Couldn't read htable ptr\\n");
978ae115bc7Smrj 			return (DCMD_ERR);
979ae115bc7Smrj 		}
980ae115bc7Smrj 		for (; ht != NULL; ht = htable.ht_next) {
981ae115bc7Smrj 			mdb_printf("%p\n", ht);
982ae115bc7Smrj 			if (mdb_vread(&htable, sizeof (htable_t),
983ae115bc7Smrj 			    (uintptr_t)ht) == -1) {
984ae115bc7Smrj 				mdb_warn("Couldn't read htable\n");
985ae115bc7Smrj 				return (DCMD_ERR);
986ae115bc7Smrj 			}
987ae115bc7Smrj 		}
988ae115bc7Smrj 	}
989ae115bc7Smrj 	return (DCMD_OK);
990ae115bc7Smrj }
991ae115bc7Smrj 
992ae115bc7Smrj /*
993ae115bc7Smrj  * Dump the htables for the given hat
994ae115bc7Smrj  */
995ae115bc7Smrj /*ARGSUSED*/
996ae115bc7Smrj int
htables_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)997ae115bc7Smrj htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
998ae115bc7Smrj {
999ae115bc7Smrj 	hat_t *hat;
1000ae115bc7Smrj 
1001843e1988Sjohnlev 	init_mmu();
1002843e1988Sjohnlev 
10037c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
10047c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
10077c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
10087c478bd9Sstevel@tonic-gate 
1009ae115bc7Smrj 	hat = (hat_t *)addr;
1010ae115bc7Smrj 
1011ae115bc7Smrj 	return (do_htables_dcmd(hat));
10127c478bd9Sstevel@tonic-gate }
101374ecdb51SJohn Levon 
101474ecdb51SJohn Levon static uintptr_t
entry2va(size_t * entries)101574ecdb51SJohn Levon entry2va(size_t *entries)
101674ecdb51SJohn Levon {
101774ecdb51SJohn Levon 	uintptr_t va = 0;
101874ecdb51SJohn Levon 
101974ecdb51SJohn Levon 	for (level_t l = mmu.max_level; l >= 0; l--)
102074ecdb51SJohn Levon 		va += entries[l] << mmu.level_shift[l];
102174ecdb51SJohn Levon 
102274ecdb51SJohn Levon 	return (VA_SIGN_EXTEND(va));
102374ecdb51SJohn Levon }
102474ecdb51SJohn Levon 
102574ecdb51SJohn Levon static void
ptmap_report(size_t * entries,uintptr_t start,boolean_t user,boolean_t writable,boolean_t wflag)102674ecdb51SJohn Levon ptmap_report(size_t *entries, uintptr_t start,
102774ecdb51SJohn Levon     boolean_t user, boolean_t writable, boolean_t wflag)
102874ecdb51SJohn Levon {
102974ecdb51SJohn Levon 	uint64_t curva = entry2va(entries);
103074ecdb51SJohn Levon 
103174ecdb51SJohn Levon 	mdb_printf("mapped %s,%s range of %lu bytes: %a-%a\n",
103274ecdb51SJohn Levon 	    user ? "user" : "kernel", writable ? "writable" : "read-only",
103374ecdb51SJohn Levon 	    curva - start, start, curva - 1);
103474ecdb51SJohn Levon 	if (wflag && start >= kernelbase)
103574ecdb51SJohn Levon 		(void) mdb_call_dcmd("whatis", start, DCMD_ADDRSPEC, 0, NULL);
103674ecdb51SJohn Levon }
103774ecdb51SJohn Levon 
103874ecdb51SJohn Levon int
ptmap_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)103974ecdb51SJohn Levon ptmap_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
104074ecdb51SJohn Levon {
104174ecdb51SJohn Levon 	physaddr_t paddrs[MAX_NUM_LEVEL] = { 0, };
104274ecdb51SJohn Levon 	size_t entry[MAX_NUM_LEVEL] = { 0, };
104374ecdb51SJohn Levon 	uintptr_t start = (uintptr_t)-1;
104474ecdb51SJohn Levon 	boolean_t writable = B_FALSE;
104574ecdb51SJohn Levon 	boolean_t user = B_FALSE;
104674ecdb51SJohn Levon 	boolean_t wflag = B_FALSE;
104774ecdb51SJohn Levon 	level_t curlevel;
104874ecdb51SJohn Levon 
104974ecdb51SJohn Levon 	if ((flags & DCMD_ADDRSPEC) == 0)
105074ecdb51SJohn Levon 		return (DCMD_USAGE);
105174ecdb51SJohn Levon 
105274ecdb51SJohn Levon 	if (mdb_getopts(argc, argv,
105374ecdb51SJohn Levon 	    'w', MDB_OPT_SETBITS, TRUE, &wflag, NULL) != argc)
105474ecdb51SJohn Levon 		return (DCMD_USAGE);
105574ecdb51SJohn Levon 
105674ecdb51SJohn Levon 	init_mmu();
105774ecdb51SJohn Levon 
105874ecdb51SJohn Levon 	if (mmu.num_level == 0)
105974ecdb51SJohn Levon 		return (DCMD_ERR);
106074ecdb51SJohn Levon 
106174ecdb51SJohn Levon 	curlevel = mmu.max_level;
106274ecdb51SJohn Levon 
106374ecdb51SJohn Levon 	paddrs[curlevel] = addr & MMU_PAGEMASK;
106474ecdb51SJohn Levon 
106574ecdb51SJohn Levon 	for (;;) {
106674ecdb51SJohn Levon 		physaddr_t pte_addr;
106774ecdb51SJohn Levon 		x86pte_t pte;
106874ecdb51SJohn Levon 
106974ecdb51SJohn Levon 		pte_addr = paddrs[curlevel] +
107074ecdb51SJohn Levon 		    (entry[curlevel] << mmu.pte_size_shift);
107174ecdb51SJohn Levon 
107274ecdb51SJohn Levon 		if (mdb_pread(&pte, sizeof (pte), pte_addr) != sizeof (pte)) {
107374ecdb51SJohn Levon 			mdb_warn("couldn't read pte at %p", pte_addr);
107474ecdb51SJohn Levon 			return (DCMD_ERR);
107574ecdb51SJohn Levon 		}
107674ecdb51SJohn Levon 
107774ecdb51SJohn Levon 		if (PTE_GET(pte, PT_VALID) == 0) {
107874ecdb51SJohn Levon 			if (start != (uintptr_t)-1) {
107974ecdb51SJohn Levon 				ptmap_report(entry, start,
108074ecdb51SJohn Levon 				    user, writable, wflag);
108174ecdb51SJohn Levon 				start = (uintptr_t)-1;
108274ecdb51SJohn Levon 			}
108374ecdb51SJohn Levon 		} else if (curlevel == 0 || PTE_GET(pte, PT_PAGESIZE)) {
108474ecdb51SJohn Levon 			if (start == (uintptr_t)-1) {
108574ecdb51SJohn Levon 				start = entry2va(entry);
108674ecdb51SJohn Levon 				user = PTE_GET(pte, PT_USER);
108774ecdb51SJohn Levon 				writable = PTE_GET(pte, PT_WRITABLE);
108874ecdb51SJohn Levon 			} else if (user != PTE_GET(pte, PT_USER) ||
108974ecdb51SJohn Levon 			    writable != PTE_GET(pte, PT_WRITABLE)) {
109074ecdb51SJohn Levon 				ptmap_report(entry, start,
109174ecdb51SJohn Levon 				    user, writable, wflag);
109274ecdb51SJohn Levon 				start = entry2va(entry);
109374ecdb51SJohn Levon 				user = PTE_GET(pte, PT_USER);
109474ecdb51SJohn Levon 				writable = PTE_GET(pte, PT_WRITABLE);
109574ecdb51SJohn Levon 			}
109674ecdb51SJohn Levon 		} else {
109774ecdb51SJohn Levon 			/* Descend a level. */
109874ecdb51SJohn Levon 			physaddr_t pa = mmu_ptob(pte2mfn(pte, curlevel));
109974ecdb51SJohn Levon 			paddrs[--curlevel] = pa;
110074ecdb51SJohn Levon 			entry[curlevel] = 0;
110174ecdb51SJohn Levon 			continue;
110274ecdb51SJohn Levon 		}
110374ecdb51SJohn Levon 
110474ecdb51SJohn Levon 		while (++entry[curlevel] == mmu.ptes_per_table) {
110574ecdb51SJohn Levon 			/* Ascend back up. */
110674ecdb51SJohn Levon 			entry[curlevel] = 0;
110774ecdb51SJohn Levon 			if (curlevel == mmu.max_level) {
110874ecdb51SJohn Levon 				if (start != (uintptr_t)-1) {
110974ecdb51SJohn Levon 					ptmap_report(entry, start,
111074ecdb51SJohn Levon 					    user, writable, wflag);
111174ecdb51SJohn Levon 				}
111274ecdb51SJohn Levon 				goto out;
111374ecdb51SJohn Levon 			}
111474ecdb51SJohn Levon 
111574ecdb51SJohn Levon 			curlevel++;
111674ecdb51SJohn Levon 		}
111774ecdb51SJohn Levon 	}
111874ecdb51SJohn Levon 
111974ecdb51SJohn Levon out:
112074ecdb51SJohn Levon 	return (DCMD_OK);
112174ecdb51SJohn Levon }
1122