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 /*
22*cbdcbd05SJonathan Adams  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * This part of the file contains the mdb support for dcmds:
287c478bd9Sstevel@tonic-gate  *	::memseg_list
297c478bd9Sstevel@tonic-gate  * and walkers for:
307c478bd9Sstevel@tonic-gate  *	memseg - a memseg list walker for ::memseg_list
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <sys/machparam.h>
367c478bd9Sstevel@tonic-gate #include <sys/controlregs.h>
37ae115bc7Smrj #include <sys/mach_mmu.h>
38843e1988Sjohnlev #ifdef __xpv
39843e1988Sjohnlev #include <sys/hypervisor.h>
40843e1988Sjohnlev #endif
417c478bd9Sstevel@tonic-gate #include <vm/as.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
447c478bd9Sstevel@tonic-gate #include <mdb/mdb_target.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include <vm/page.h>
477c478bd9Sstevel@tonic-gate #include <vm/hat_i86.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate struct pfn2pp {
507c478bd9Sstevel@tonic-gate 	pfn_t pfn;
517c478bd9Sstevel@tonic-gate 	page_t *pp;
527c478bd9Sstevel@tonic-gate };
537c478bd9Sstevel@tonic-gate 
54ae115bc7Smrj static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *);
55843e1988Sjohnlev static void init_mmu(void);
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate int
587c478bd9Sstevel@tonic-gate platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
597c478bd9Sstevel@tonic-gate {
607c478bd9Sstevel@tonic-gate 	if (asp == NULL)
617c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
627c478bd9Sstevel@tonic-gate 
63843e1988Sjohnlev 	init_mmu();
64843e1988Sjohnlev 
657c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
667c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
677c478bd9Sstevel@tonic-gate 
68ae115bc7Smrj 	return (do_va2pa(addr, asp, 0, pap, NULL));
697c478bd9Sstevel@tonic-gate }
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate  * ::memseg_list dcmd and walker to implement it.
737c478bd9Sstevel@tonic-gate  */
747c478bd9Sstevel@tonic-gate /*ARGSUSED*/
757c478bd9Sstevel@tonic-gate int
767c478bd9Sstevel@tonic-gate memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate 	struct memseg ms;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
817c478bd9Sstevel@tonic-gate 		if (mdb_pwalk_dcmd("memseg", "memseg_list",
827c478bd9Sstevel@tonic-gate 		    0, NULL, 0) == -1) {
837c478bd9Sstevel@tonic-gate 			mdb_warn("can't walk memseg");
847c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
857c478bd9Sstevel@tonic-gate 		}
867c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
877c478bd9Sstevel@tonic-gate 	}
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
907c478bd9Sstevel@tonic-gate 		mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
91843e1988Sjohnlev 		    "PAGES", "EPAGES", "BASE", "END");
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
947c478bd9Sstevel@tonic-gate 		mdb_warn("can't read memseg at %#lx", addr);
957c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
967c478bd9Sstevel@tonic-gate 	}
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr,
99843e1988Sjohnlev 	    ms.pages, ms.epages, ms.pages_base, ms.pages_end);
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate  * walk the memseg structures
1067c478bd9Sstevel@tonic-gate  */
1077c478bd9Sstevel@tonic-gate int
1087c478bd9Sstevel@tonic-gate memseg_walk_init(mdb_walk_state_t *wsp)
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr != NULL) {
1117c478bd9Sstevel@tonic-gate 		mdb_warn("memseg only supports global walks\n");
1127c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
1137c478bd9Sstevel@tonic-gate 	}
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
1167c478bd9Sstevel@tonic-gate 		mdb_warn("symbol 'memsegs' not found");
1177c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
1187c478bd9Sstevel@tonic-gate 	}
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
1217c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate int
1267c478bd9Sstevel@tonic-gate memseg_walk_step(mdb_walk_state_t *wsp)
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate 	int status;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == 0) {
1317c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
1327c478bd9Sstevel@tonic-gate 	}
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (struct memseg),
1357c478bd9Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
1367c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read struct memseg at %p", wsp->walk_addr);
1377c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
1387c478bd9Sstevel@tonic-gate 	}
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1417c478bd9Sstevel@tonic-gate 	    wsp->walk_cbdata);
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	return (status);
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate void
1497c478bd9Sstevel@tonic-gate memseg_walk_fini(mdb_walk_state_t *wsp)
1507c478bd9Sstevel@tonic-gate {
1517c478bd9Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct memseg));
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate /*
155ae115bc7Smrj  * Now HAT related dcmds.
1567c478bd9Sstevel@tonic-gate  */
1577c478bd9Sstevel@tonic-gate 
158843e1988Sjohnlev static struct hat *khat;		/* value of kas.a_hat */
1597c478bd9Sstevel@tonic-gate struct hat_mmu_info mmu;
1607c478bd9Sstevel@tonic-gate uintptr_t kernelbase;
1617c478bd9Sstevel@tonic-gate 
162843e1988Sjohnlev /*
163843e1988Sjohnlev  * stuff for i86xpv images
164843e1988Sjohnlev  */
165843e1988Sjohnlev static int is_xpv;
166843e1988Sjohnlev static uintptr_t mfn_list_addr; /* kernel MFN list address */
167843e1988Sjohnlev uintptr_t xen_virt_start; /* address of mfn_to_pfn[] table */
168843e1988Sjohnlev ulong_t mfn_count;	/* number of pfn's in the MFN list */
169843e1988Sjohnlev pfn_t *mfn_list;	/* local MFN list copy */
170843e1988Sjohnlev 
1717c478bd9Sstevel@tonic-gate /*
1727c478bd9Sstevel@tonic-gate  * read mmu parameters from kernel
1737c478bd9Sstevel@tonic-gate  */
1747c478bd9Sstevel@tonic-gate static void
175843e1988Sjohnlev init_mmu(void)
1767c478bd9Sstevel@tonic-gate {
1777c478bd9Sstevel@tonic-gate 	struct as kas;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	if (mmu.num_level != 0)
1807c478bd9Sstevel@tonic-gate 		return;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1)
1837c478bd9Sstevel@tonic-gate 		mdb_warn("Can't use HAT information before mmu_init()\n");
1847c478bd9Sstevel@tonic-gate 	if (mdb_readsym(&kas, sizeof (kas), "kas") == -1)
1857c478bd9Sstevel@tonic-gate 		mdb_warn("Couldn't find kas - kernel's struct as\n");
1867c478bd9Sstevel@tonic-gate 	if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1)
1877c478bd9Sstevel@tonic-gate 		mdb_warn("Couldn't find kernelbase\n");
1887c478bd9Sstevel@tonic-gate 	khat = kas.a_hat;
189843e1988Sjohnlev 
190843e1988Sjohnlev 	/*
191843e1988Sjohnlev 	 * Is this a paravirtualized domain image?
192843e1988Sjohnlev 	 */
193843e1988Sjohnlev 	if (mdb_readsym(&mfn_list_addr, sizeof (mfn_list_addr),
194843e1988Sjohnlev 	    "mfn_list") == -1 ||
195843e1988Sjohnlev 	    mdb_readsym(&xen_virt_start, sizeof (xen_virt_start),
196843e1988Sjohnlev 	    "xen_virt_start") == -1 ||
197843e1988Sjohnlev 	    mdb_readsym(&mfn_count, sizeof (mfn_count), "mfn_count") == -1) {
198843e1988Sjohnlev 		mfn_list_addr = NULL;
199843e1988Sjohnlev 	}
200843e1988Sjohnlev 
201843e1988Sjohnlev 	is_xpv = mfn_list_addr != NULL;
202843e1988Sjohnlev 
203843e1988Sjohnlev #ifndef _KMDB
204843e1988Sjohnlev 	/*
205843e1988Sjohnlev 	 * recreate the local mfn_list
206843e1988Sjohnlev 	 */
207843e1988Sjohnlev 	if (is_xpv) {
208843e1988Sjohnlev 		size_t sz = mfn_count * sizeof (pfn_t);
209843e1988Sjohnlev 		mfn_list = mdb_zalloc(sz, UM_SLEEP);
210843e1988Sjohnlev 
211843e1988Sjohnlev 		if (mdb_vread(mfn_list, sz, (uintptr_t)mfn_list_addr) == -1) {
212843e1988Sjohnlev 			mdb_warn("Failed to read MFN list\n");
213843e1988Sjohnlev 			mdb_free(mfn_list, sz);
214843e1988Sjohnlev 			mfn_list = NULL;
215843e1988Sjohnlev 		}
216843e1988Sjohnlev 	}
217843e1988Sjohnlev #endif
218843e1988Sjohnlev }
219843e1988Sjohnlev 
220843e1988Sjohnlev void
221843e1988Sjohnlev free_mmu(void)
222843e1988Sjohnlev {
223843e1988Sjohnlev #ifdef __xpv
224843e1988Sjohnlev 	if (mfn_list != NULL)
225843e1988Sjohnlev 		mdb_free(mfn_list, mfn_count * sizeof (mfn_t));
226843e1988Sjohnlev #endif
227843e1988Sjohnlev }
228843e1988Sjohnlev 
229843e1988Sjohnlev #ifdef __xpv
230843e1988Sjohnlev 
231843e1988Sjohnlev #ifdef _KMDB
232843e1988Sjohnlev 
233843e1988Sjohnlev /*
234843e1988Sjohnlev  * Convert between MFNs and PFNs.  Since we're in kmdb we can go directly
235843e1988Sjohnlev  * through the machine to phys mapping and the MFN list.
236843e1988Sjohnlev  */
237843e1988Sjohnlev 
238843e1988Sjohnlev pfn_t
239843e1988Sjohnlev mdb_mfn_to_pfn(mfn_t mfn)
240843e1988Sjohnlev {
241843e1988Sjohnlev 	pfn_t pfn;
242843e1988Sjohnlev 	mfn_t tmp;
243843e1988Sjohnlev 	pfn_t *pfn_list;
244843e1988Sjohnlev 
245843e1988Sjohnlev 	if (mfn_list_addr == NULL)
246843e1988Sjohnlev 		return (-(pfn_t)1);
247843e1988Sjohnlev 
248843e1988Sjohnlev 	pfn_list = (pfn_t *)xen_virt_start;
249843e1988Sjohnlev 	if (mdb_vread(&pfn, sizeof (pfn), (uintptr_t)(pfn_list + mfn)) == -1)
250843e1988Sjohnlev 		return (-(pfn_t)1);
251843e1988Sjohnlev 
252843e1988Sjohnlev 	if (mdb_vread(&tmp, sizeof (tmp),
253843e1988Sjohnlev 	    (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
254843e1988Sjohnlev 		return (-(pfn_t)1);
255843e1988Sjohnlev 
256843e1988Sjohnlev 	if (pfn >= mfn_count || tmp != mfn)
257843e1988Sjohnlev 		return (-(pfn_t)1);
258843e1988Sjohnlev 
259843e1988Sjohnlev 	return (pfn);
260843e1988Sjohnlev }
261843e1988Sjohnlev 
262843e1988Sjohnlev mfn_t
263843e1988Sjohnlev mdb_pfn_to_mfn(pfn_t pfn)
264843e1988Sjohnlev {
265843e1988Sjohnlev 	mfn_t mfn;
266843e1988Sjohnlev 
267843e1988Sjohnlev 	init_mmu();
268843e1988Sjohnlev 
269843e1988Sjohnlev 	if (mfn_list_addr == NULL || pfn >= mfn_count)
270843e1988Sjohnlev 		return (-(mfn_t)1);
271843e1988Sjohnlev 
272843e1988Sjohnlev 	if (mdb_vread(&mfn, sizeof (mfn),
273843e1988Sjohnlev 	    (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
274843e1988Sjohnlev 		return (-(mfn_t)1);
275843e1988Sjohnlev 
276843e1988Sjohnlev 	return (mfn);
277843e1988Sjohnlev }
278843e1988Sjohnlev 
279843e1988Sjohnlev #else /* _KMDB */
280843e1988Sjohnlev 
281843e1988Sjohnlev /*
282843e1988Sjohnlev  * Convert between MFNs and PFNs.  Since a crash dump doesn't include the
283843e1988Sjohnlev  * MFN->PFN translation table (it's part of the hypervisor, not our image)
284843e1988Sjohnlev  * we do the MFN->PFN translation by searching the PFN->MFN (mfn_list)
285843e1988Sjohnlev  * table, if it's there.
286843e1988Sjohnlev  */
287843e1988Sjohnlev 
288843e1988Sjohnlev pfn_t
289843e1988Sjohnlev mdb_mfn_to_pfn(mfn_t mfn)
290843e1988Sjohnlev {
291843e1988Sjohnlev 	pfn_t pfn;
292843e1988Sjohnlev 
293843e1988Sjohnlev 	init_mmu();
294843e1988Sjohnlev 
295843e1988Sjohnlev 	if (mfn_list == NULL)
296843e1988Sjohnlev 		return (-(pfn_t)1);
297843e1988Sjohnlev 
298843e1988Sjohnlev 	for (pfn = 0; pfn < mfn_count; ++pfn) {
299843e1988Sjohnlev 		if (mfn_list[pfn] != mfn)
300843e1988Sjohnlev 			continue;
301843e1988Sjohnlev 		return (pfn);
302843e1988Sjohnlev 	}
303843e1988Sjohnlev 
304843e1988Sjohnlev 	return (-(pfn_t)1);
3057c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate 
307843e1988Sjohnlev mfn_t
308843e1988Sjohnlev mdb_pfn_to_mfn(pfn_t pfn)
309843e1988Sjohnlev {
310843e1988Sjohnlev 	init_mmu();
311843e1988Sjohnlev 
312843e1988Sjohnlev 	if (mfn_list == NULL || pfn >= mfn_count)
313843e1988Sjohnlev 		return (-(mfn_t)1);
314843e1988Sjohnlev 
315843e1988Sjohnlev 	return (mfn_list[pfn]);
316843e1988Sjohnlev }
317843e1988Sjohnlev 
318843e1988Sjohnlev #endif /* _KMDB */
319843e1988Sjohnlev 
320843e1988Sjohnlev static paddr_t
321843e1988Sjohnlev mdb_ma_to_pa(uint64_t ma)
322843e1988Sjohnlev {
323843e1988Sjohnlev 	pfn_t pfn = mdb_mfn_to_pfn(mmu_btop(ma));
324843e1988Sjohnlev 	if (pfn == -(pfn_t)1)
325843e1988Sjohnlev 		return (-(paddr_t)1);
326843e1988Sjohnlev 
327843e1988Sjohnlev 	return (mmu_ptob((paddr_t)pfn) | (ma & (MMU_PAGESIZE - 1)));
328843e1988Sjohnlev }
329843e1988Sjohnlev 
330843e1988Sjohnlev #else /* __xpv */
331843e1988Sjohnlev 
332ae115bc7Smrj #define	mdb_ma_to_pa(ma) (ma)
333ae115bc7Smrj #define	mdb_mfn_to_pfn(mfn) (mfn)
334ae115bc7Smrj #define	mdb_pfn_to_mfn(pfn) (pfn)
335ae115bc7Smrj 
336843e1988Sjohnlev #endif /* __xpv */
337843e1988Sjohnlev 
338843e1988Sjohnlev /*
339843e1988Sjohnlev  * ::mfntopfn dcmd translates hypervisor machine page number
340843e1988Sjohnlev  * to physical page number
341843e1988Sjohnlev  */
342843e1988Sjohnlev /*ARGSUSED*/
343843e1988Sjohnlev int
344843e1988Sjohnlev mfntopfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
345843e1988Sjohnlev {
346843e1988Sjohnlev 	pfn_t pfn;
347843e1988Sjohnlev 
348843e1988Sjohnlev 	if ((flags & DCMD_ADDRSPEC) == 0) {
349843e1988Sjohnlev 		mdb_warn("MFN missing\n");
350843e1988Sjohnlev 		return (DCMD_USAGE);
351843e1988Sjohnlev 	}
352843e1988Sjohnlev 
353843e1988Sjohnlev 	if ((pfn = mdb_mfn_to_pfn((pfn_t)addr)) == -(pfn_t)1) {
354843e1988Sjohnlev 		mdb_warn("Invalid mfn %lr\n", (pfn_t)addr);
355843e1988Sjohnlev 		return (DCMD_ERR);
356843e1988Sjohnlev 	}
357843e1988Sjohnlev 
358843e1988Sjohnlev 	mdb_printf("%lr\n", pfn);
359843e1988Sjohnlev 
360843e1988Sjohnlev 	return (DCMD_OK);
361843e1988Sjohnlev }
362843e1988Sjohnlev 
363843e1988Sjohnlev /*
364843e1988Sjohnlev  * ::pfntomfn dcmd translates physical page number to
365843e1988Sjohnlev  * hypervisor machine page number
366843e1988Sjohnlev  */
367843e1988Sjohnlev /*ARGSUSED*/
368843e1988Sjohnlev int
369843e1988Sjohnlev pfntomfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
370843e1988Sjohnlev {
371843e1988Sjohnlev 	pfn_t mfn;
372843e1988Sjohnlev 
373843e1988Sjohnlev 	if ((flags & DCMD_ADDRSPEC) == 0) {
374843e1988Sjohnlev 		mdb_warn("PFN missing\n");
375843e1988Sjohnlev 		return (DCMD_USAGE);
376843e1988Sjohnlev 	}
377843e1988Sjohnlev 
378843e1988Sjohnlev 	if ((mfn = mdb_pfn_to_mfn((pfn_t)addr)) == -(pfn_t)1) {
379843e1988Sjohnlev 		mdb_warn("Invalid pfn %lr\n", (pfn_t)addr);
380843e1988Sjohnlev 		return (DCMD_ABORT);
381843e1988Sjohnlev 	}
382843e1988Sjohnlev 
383843e1988Sjohnlev 	mdb_printf("%lr\n", mfn);
384843e1988Sjohnlev 
385843e1988Sjohnlev 	if (flags & DCMD_LOOP)
386843e1988Sjohnlev 		mdb_set_dot(addr + 1);
387843e1988Sjohnlev 	return (DCMD_OK);
388843e1988Sjohnlev }
389843e1988Sjohnlev 
390ae115bc7Smrj static pfn_t
391ae115bc7Smrj pte2mfn(x86pte_t pte, uint_t level)
392ae115bc7Smrj {
393ae115bc7Smrj 	pfn_t mfn;
394ae115bc7Smrj 	if (level > 0 && (pte & PT_PAGESIZE))
395ae115bc7Smrj 		mfn = mmu_btop(pte & PT_PADDR_LGPG);
396ae115bc7Smrj 	else
397ae115bc7Smrj 		mfn = mmu_btop(pte & PT_PADDR);
398ae115bc7Smrj 	return (mfn);
399ae115bc7Smrj }
400ae115bc7Smrj 
4017c478bd9Sstevel@tonic-gate /*
4027c478bd9Sstevel@tonic-gate  * Print a PTE in more human friendly way. The PTE is assumed to be in
4037c478bd9Sstevel@tonic-gate  * a level 0 page table, unless -l specifies another level.
4047c478bd9Sstevel@tonic-gate  *
4057c478bd9Sstevel@tonic-gate  * The PTE value can be specified as the -p option, since on a 32 bit kernel
4067c478bd9Sstevel@tonic-gate  * with PAE running it's larger than a uintptr_t.
4077c478bd9Sstevel@tonic-gate  */
4087c478bd9Sstevel@tonic-gate static int
4097c478bd9Sstevel@tonic-gate do_pte_dcmd(int level, uint64_t pte)
4107c478bd9Sstevel@tonic-gate {
4117c478bd9Sstevel@tonic-gate 	static char *attr[] = {
4127c478bd9Sstevel@tonic-gate 	    "wrback", "wrthru", "uncached", "uncached",
4137c478bd9Sstevel@tonic-gate 	    "wrback", "wrthru", "wrcombine", "uncached"};
4147c478bd9Sstevel@tonic-gate 	int pat_index = 0;
415ae115bc7Smrj 	pfn_t mfn;
4167c478bd9Sstevel@tonic-gate 
417ae115bc7Smrj 	mdb_printf("pte=%llr: ", pte);
4187c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, mmu.pt_nx))
4197c478bd9Sstevel@tonic-gate 		mdb_printf("noexec ");
4207c478bd9Sstevel@tonic-gate 
421ae115bc7Smrj 	mfn = pte2mfn(pte, level);
422843e1988Sjohnlev 	mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn);
4237c478bd9Sstevel@tonic-gate 
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  * The PTE value can be specified as the -p option, since on a 32 bit kernel
4817c478bd9Sstevel@tonic-gate  * with PAE running it's larger than a uintptr_t.
4827c478bd9Sstevel@tonic-gate  */
4837c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4847c478bd9Sstevel@tonic-gate int
4857c478bd9Sstevel@tonic-gate pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4867c478bd9Sstevel@tonic-gate {
4877c478bd9Sstevel@tonic-gate 	int level = 0;
4887c478bd9Sstevel@tonic-gate 	uint64_t pte = 0;
4897c478bd9Sstevel@tonic-gate 	char *level_str = NULL;
4907c478bd9Sstevel@tonic-gate 	char *pte_str = NULL;
4917c478bd9Sstevel@tonic-gate 
492843e1988Sjohnlev 	init_mmu();
493843e1988Sjohnlev 
4947c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
4957c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
4987c478bd9Sstevel@tonic-gate 	    'p', MDB_OPT_STR, &pte_str,
4997c478bd9Sstevel@tonic-gate 	    'l', MDB_OPT_STR, &level_str) != argc)
5007c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	/*
5037c478bd9Sstevel@tonic-gate 	 * parse the PTE to decode, if it's 0, we don't do anything
5047c478bd9Sstevel@tonic-gate 	 */
5057c478bd9Sstevel@tonic-gate 	if (pte_str != NULL) {
5067c478bd9Sstevel@tonic-gate 		pte = mdb_strtoull(pte_str);
5077c478bd9Sstevel@tonic-gate 	} else {
5087c478bd9Sstevel@tonic-gate 		if ((flags & DCMD_ADDRSPEC) == 0)
5097c478bd9Sstevel@tonic-gate 			return (DCMD_USAGE);
5107c478bd9Sstevel@tonic-gate 		pte = addr;
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate 	if (pte == 0)
5137c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	/*
5167c478bd9Sstevel@tonic-gate 	 * parse the level if supplied
5177c478bd9Sstevel@tonic-gate 	 */
5187c478bd9Sstevel@tonic-gate 	if (level_str != NULL) {
5197c478bd9Sstevel@tonic-gate 		level = mdb_strtoull(level_str);
5207c478bd9Sstevel@tonic-gate 		if (level < 0 || level > mmu.max_level)
5217c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	return (do_pte_dcmd(level, pte));
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate 
527ae115bc7Smrj static size_t
528ae115bc7Smrj va2entry(htable_t *htable, uintptr_t addr)
529ae115bc7Smrj {
530ae115bc7Smrj 	size_t entry = (addr - htable->ht_vaddr);
531ae115bc7Smrj 
532ae115bc7Smrj 	entry >>= mmu.level_shift[htable->ht_level];
533ae115bc7Smrj 	return (entry & HTABLE_NUM_PTES(htable) - 1);
534ae115bc7Smrj }
535ae115bc7Smrj 
536ae115bc7Smrj static x86pte_t
537ae115bc7Smrj get_pte(hat_t *hat, htable_t *htable, uintptr_t addr)
538ae115bc7Smrj {
539ae115bc7Smrj 	x86pte_t buf;
540ae115bc7Smrj 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
541ae115bc7Smrj 	size_t len;
542ae115bc7Smrj 
543ae115bc7Smrj 	if (htable->ht_flags & HTABLE_VLP) {
544ae115bc7Smrj 		uintptr_t ptr = (uintptr_t)hat->hat_vlp_ptes;
545ae115bc7Smrj 		ptr += va2entry(htable, addr) << mmu.pte_size_shift;
546ae115bc7Smrj 		len = mdb_vread(&buf, mmu.pte_size, ptr);
547ae115bc7Smrj 	} else {
548ae115bc7Smrj 		paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn);
549ae115bc7Smrj 		paddr += va2entry(htable, addr) << mmu.pte_size_shift;
550ae115bc7Smrj 		len = mdb_pread(&buf, mmu.pte_size, paddr);
551ae115bc7Smrj 	}
552ae115bc7Smrj 
553ae115bc7Smrj 	if (len != mmu.pte_size)
554ae115bc7Smrj 		return (0);
555ae115bc7Smrj 
556ae115bc7Smrj 	if (mmu.pte_size == sizeof (x86pte_t))
557ae115bc7Smrj 		return (buf);
558ae115bc7Smrj 	return (*pte32);
559ae115bc7Smrj }
560ae115bc7Smrj 
5617c478bd9Sstevel@tonic-gate static int
562ae115bc7Smrj do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap,
563ae115bc7Smrj     pfn_t *mfnp)
5647c478bd9Sstevel@tonic-gate {
5657c478bd9Sstevel@tonic-gate 	struct as as;
5667c478bd9Sstevel@tonic-gate 	struct hat *hatp;
5677c478bd9Sstevel@tonic-gate 	struct hat hat;
5687c478bd9Sstevel@tonic-gate 	htable_t *ht;
5697c478bd9Sstevel@tonic-gate 	htable_t htable;
5707c478bd9Sstevel@tonic-gate 	uintptr_t base;
5717c478bd9Sstevel@tonic-gate 	int h;
5727c478bd9Sstevel@tonic-gate 	int level;
5737c478bd9Sstevel@tonic-gate 	int found = 0;
5747c478bd9Sstevel@tonic-gate 	x86pte_t pte;
5757c478bd9Sstevel@tonic-gate 	physaddr_t paddr;
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	if (asp != NULL) {
5787c478bd9Sstevel@tonic-gate 		if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
5797c478bd9Sstevel@tonic-gate 			mdb_warn("Couldn't read struct as\n");
5807c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
5817c478bd9Sstevel@tonic-gate 		}
5827c478bd9Sstevel@tonic-gate 		hatp = as.a_hat;
5837c478bd9Sstevel@tonic-gate 	} else {
5847c478bd9Sstevel@tonic-gate 		hatp = khat;
5857c478bd9Sstevel@tonic-gate 	}
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	/*
5887c478bd9Sstevel@tonic-gate 	 * read the hat and its hash table
5897c478bd9Sstevel@tonic-gate 	 */
5907c478bd9Sstevel@tonic-gate 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
5917c478bd9Sstevel@tonic-gate 		mdb_warn("Couldn't read struct hat\n");
5927c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	/*
5967c478bd9Sstevel@tonic-gate 	 * read the htable hashtable
5977c478bd9Sstevel@tonic-gate 	 */
5987c478bd9Sstevel@tonic-gate 	for (level = 0; level <= mmu.max_level; ++level) {
599ae115bc7Smrj 		if (level == TOP_LEVEL(&hat))
6007c478bd9Sstevel@tonic-gate 			base = 0;
6017c478bd9Sstevel@tonic-gate 		else
6027c478bd9Sstevel@tonic-gate 			base = addr & mmu.level_mask[level + 1];
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
6057c478bd9Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
6067c478bd9Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
6077c478bd9Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
6087c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
6097c478bd9Sstevel@tonic-gate 			}
6107c478bd9Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
6117c478bd9Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
6127c478bd9Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
6137c478bd9Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
6147c478bd9Sstevel@tonic-gate 					return (DCMD_ERR);
6157c478bd9Sstevel@tonic-gate 				}
616ae115bc7Smrj 
6177c478bd9Sstevel@tonic-gate 				if (htable.ht_vaddr != base ||
6187c478bd9Sstevel@tonic-gate 				    htable.ht_level != level)
6197c478bd9Sstevel@tonic-gate 					continue;
6207c478bd9Sstevel@tonic-gate 
621ae115bc7Smrj 				pte = get_pte(&hat, &htable, addr);
6227c478bd9Sstevel@tonic-gate 
623ae115bc7Smrj 				if (print_level) {
624ae115bc7Smrj 					mdb_printf("\tlevel=%d htable=%p "
625ae115bc7Smrj 					    "pte=%llr\n", level, ht, pte);
6267c478bd9Sstevel@tonic-gate 				}
627ae115bc7Smrj 
628ae115bc7Smrj 				if (!PTE_ISVALID(pte)) {
629ae115bc7Smrj 					mdb_printf("Address %p is unmapped.\n",
630ae115bc7Smrj 					    addr);
631ae115bc7Smrj 					return (DCMD_ERR);
632ae115bc7Smrj 				}
633ae115bc7Smrj 
634ae115bc7Smrj 				if (found)
6357c478bd9Sstevel@tonic-gate 					continue;
636ae115bc7Smrj 
637ae115bc7Smrj 				if (PTE_IS_LGPG(pte, level))
638ae115bc7Smrj 					paddr = mdb_ma_to_pa(pte &
639ae115bc7Smrj 					    PT_PADDR_LGPG);
640ae115bc7Smrj 				else
641ae115bc7Smrj 					paddr = mdb_ma_to_pa(pte & PT_PADDR);
642ae115bc7Smrj 				paddr += addr & mmu.level_offset[level];
643ae115bc7Smrj 				if (pap != NULL)
644ae115bc7Smrj 					*pap = paddr;
645ae115bc7Smrj 				if (mfnp != NULL)
646ae115bc7Smrj 					*mfnp = pte2mfn(pte, level);
647ae115bc7Smrj 				found = 1;
6487c478bd9Sstevel@tonic-gate 			}
6497c478bd9Sstevel@tonic-gate 		}
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate done:
6537c478bd9Sstevel@tonic-gate 	if (!found)
6547c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
6557c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate int
6597c478bd9Sstevel@tonic-gate va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6607c478bd9Sstevel@tonic-gate {
6617c478bd9Sstevel@tonic-gate 	uintptr_t addrspace;
6627c478bd9Sstevel@tonic-gate 	char *addrspace_str = NULL;
663ae115bc7Smrj 	int piped = flags & DCMD_PIPE_OUT;
664ae115bc7Smrj 	pfn_t pfn;
665ae115bc7Smrj 	pfn_t mfn;
6667c478bd9Sstevel@tonic-gate 	int rc;
6677c478bd9Sstevel@tonic-gate 
668843e1988Sjohnlev 	init_mmu();
669843e1988Sjohnlev 
6707c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
6717c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
6747c478bd9Sstevel@tonic-gate 	    'a', MDB_OPT_STR, &addrspace_str) != argc)
6757c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
6787c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	/*
6817c478bd9Sstevel@tonic-gate 	 * parse the address space
6827c478bd9Sstevel@tonic-gate 	 */
6837c478bd9Sstevel@tonic-gate 	if (addrspace_str != NULL)
6847c478bd9Sstevel@tonic-gate 		addrspace = mdb_strtoull(addrspace_str);
6857c478bd9Sstevel@tonic-gate 	else
6867c478bd9Sstevel@tonic-gate 		addrspace = 0;
6877c478bd9Sstevel@tonic-gate 
688ae115bc7Smrj 	rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn);
689ae115bc7Smrj 
690ae115bc7Smrj 	if (rc != DCMD_OK)
691ae115bc7Smrj 		return (rc);
692ae115bc7Smrj 
693ae115bc7Smrj 	if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) {
694ae115bc7Smrj 		mdb_warn("Invalid mfn %lr\n", mfn);
695ae115bc7Smrj 		return (DCMD_ERR);
696ae115bc7Smrj 	}
697ae115bc7Smrj 
698ae115bc7Smrj 	if (piped) {
699ae115bc7Smrj 		mdb_printf("0x%lr\n", pfn);
700ae115bc7Smrj 		return (DCMD_OK);
701ae115bc7Smrj 	}
7027c478bd9Sstevel@tonic-gate 
703ae115bc7Smrj 	mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn);
7047c478bd9Sstevel@tonic-gate 
705843e1988Sjohnlev 	if (is_xpv)
706843e1988Sjohnlev 		mdb_printf(" (mfn 0x%lr)", mfn);
707843e1988Sjohnlev 
708ae115bc7Smrj 	mdb_printf("\n");
709ae115bc7Smrj 
710ae115bc7Smrj 	return (DCMD_OK);
7117c478bd9Sstevel@tonic-gate }
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate /*
7147c478bd9Sstevel@tonic-gate  * Report all hat's that either use PFN as a page table or that map the page.
7157c478bd9Sstevel@tonic-gate  */
7167c478bd9Sstevel@tonic-gate static int
7177c478bd9Sstevel@tonic-gate do_report_maps(pfn_t pfn)
7187c478bd9Sstevel@tonic-gate {
719a85a6733Sjosephb 	struct hat *hatp;
7207c478bd9Sstevel@tonic-gate 	struct hat hat;
7217c478bd9Sstevel@tonic-gate 	htable_t *ht;
7227c478bd9Sstevel@tonic-gate 	htable_t htable;
7237c478bd9Sstevel@tonic-gate 	uintptr_t base;
7247c478bd9Sstevel@tonic-gate 	int h;
7257c478bd9Sstevel@tonic-gate 	int level;
7267c478bd9Sstevel@tonic-gate 	int entry;
7277c478bd9Sstevel@tonic-gate 	x86pte_t pte;
7287c478bd9Sstevel@tonic-gate 	x86pte_t buf;
7297c478bd9Sstevel@tonic-gate 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
7307c478bd9Sstevel@tonic-gate 	physaddr_t paddr;
7317c478bd9Sstevel@tonic-gate 	size_t len;
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	/*
734a85a6733Sjosephb 	 * The hats are kept in a list with khat at the head.
7357c478bd9Sstevel@tonic-gate 	 */
736a85a6733Sjosephb 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
7377c478bd9Sstevel@tonic-gate 		/*
7387c478bd9Sstevel@tonic-gate 		 * read the hat and its hash table
7397c478bd9Sstevel@tonic-gate 		 */
7407c478bd9Sstevel@tonic-gate 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
7417c478bd9Sstevel@tonic-gate 			mdb_warn("Couldn't read struct hat\n");
7427c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
7437c478bd9Sstevel@tonic-gate 		}
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 		/*
7467c478bd9Sstevel@tonic-gate 		 * read the htable hashtable
7477c478bd9Sstevel@tonic-gate 		 */
7487c478bd9Sstevel@tonic-gate 		paddr = 0;
7497c478bd9Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
7507c478bd9Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
7517c478bd9Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
7527c478bd9Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
7537c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
7547c478bd9Sstevel@tonic-gate 			}
7557c478bd9Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
7567c478bd9Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
7577c478bd9Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
7587c478bd9Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
7597c478bd9Sstevel@tonic-gate 					return (DCMD_ERR);
7607c478bd9Sstevel@tonic-gate 				}
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 				/*
7637c478bd9Sstevel@tonic-gate 				 * only report kernel addresses once
7647c478bd9Sstevel@tonic-gate 				 */
7657c478bd9Sstevel@tonic-gate 				if (hatp != khat &&
7667c478bd9Sstevel@tonic-gate 				    htable.ht_vaddr >= kernelbase)
7677c478bd9Sstevel@tonic-gate 					continue;
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 				/*
7707c478bd9Sstevel@tonic-gate 				 * Is the PFN a pagetable itself?
7717c478bd9Sstevel@tonic-gate 				 */
7727c478bd9Sstevel@tonic-gate 				if (htable.ht_pfn == pfn) {
7737c478bd9Sstevel@tonic-gate 					mdb_printf("Pagetable for "
7747c478bd9Sstevel@tonic-gate 					    "hat=%p htable=%p\n", hatp, ht);
7757c478bd9Sstevel@tonic-gate 					continue;
7767c478bd9Sstevel@tonic-gate 				}
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 				/*
7797c478bd9Sstevel@tonic-gate 				 * otherwise, examine page mappings
7807c478bd9Sstevel@tonic-gate 				 */
7817c478bd9Sstevel@tonic-gate 				level = htable.ht_level;
7827c478bd9Sstevel@tonic-gate 				if (level > mmu.max_page_level)
7837c478bd9Sstevel@tonic-gate 					continue;
784ae115bc7Smrj 				paddr = mmu_ptob((physaddr_t)htable.ht_pfn);
785ae115bc7Smrj 				for (entry = 0;
786ae115bc7Smrj 				    entry < HTABLE_NUM_PTES(&htable);
7877c478bd9Sstevel@tonic-gate 				    ++entry) {
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 					base = htable.ht_vaddr + entry *
7907c478bd9Sstevel@tonic-gate 					    mmu.level_size[level];
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 					/*
7937c478bd9Sstevel@tonic-gate 					 * only report kernel addresses once
7947c478bd9Sstevel@tonic-gate 					 */
7957c478bd9Sstevel@tonic-gate 					if (hatp != khat &&
7967c478bd9Sstevel@tonic-gate 					    base >= kernelbase)
7977c478bd9Sstevel@tonic-gate 						continue;
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 					len = mdb_pread(&buf, mmu.pte_size,
8007c478bd9Sstevel@tonic-gate 					    paddr + entry * mmu.pte_size);
8017c478bd9Sstevel@tonic-gate 					if (len != mmu.pte_size)
8027c478bd9Sstevel@tonic-gate 						return (DCMD_ERR);
8037c478bd9Sstevel@tonic-gate 					if (mmu.pte_size == sizeof (x86pte_t))
8047c478bd9Sstevel@tonic-gate 						pte = buf;
8057c478bd9Sstevel@tonic-gate 					else
8067c478bd9Sstevel@tonic-gate 						pte = *pte32;
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 					if ((pte & PT_VALID) == 0)
8097c478bd9Sstevel@tonic-gate 						continue;
8107c478bd9Sstevel@tonic-gate 					if (level == 0 || !(pte & PT_PAGESIZE))
8117c478bd9Sstevel@tonic-gate 						pte &= PT_PADDR;
8127c478bd9Sstevel@tonic-gate 					else
8137c478bd9Sstevel@tonic-gate 						pte &= PT_PADDR_LGPG;
814ae115bc7Smrj 					if (mmu_btop(mdb_ma_to_pa(pte)) != pfn)
8157c478bd9Sstevel@tonic-gate 						continue;
8167c478bd9Sstevel@tonic-gate 					mdb_printf("hat=%p maps addr=%p\n",
817843e1988Sjohnlev 					    hatp, (caddr_t)base);
8187c478bd9Sstevel@tonic-gate 				}
8197c478bd9Sstevel@tonic-gate 			}
8207c478bd9Sstevel@tonic-gate 		}
8217c478bd9Sstevel@tonic-gate 	}
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate done:
8247c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
8257c478bd9Sstevel@tonic-gate }
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate /*
8287c478bd9Sstevel@tonic-gate  * given a PFN as its address argument, prints out the uses of it
8297c478bd9Sstevel@tonic-gate  */
8307c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8317c478bd9Sstevel@tonic-gate int
8327c478bd9Sstevel@tonic-gate report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
8337c478bd9Sstevel@tonic-gate {
834ae115bc7Smrj 	pfn_t pfn;
835ae115bc7Smrj 	uint_t mflag = 0;
836ae115bc7Smrj 
837843e1988Sjohnlev 	init_mmu();
838843e1988Sjohnlev 
8397c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
8407c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
8437c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
8447c478bd9Sstevel@tonic-gate 
845ae115bc7Smrj 	if (mdb_getopts(argc, argv,
846ae115bc7Smrj 	    'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
847ae115bc7Smrj 		return (DCMD_USAGE);
848ae115bc7Smrj 
849ae115bc7Smrj 	pfn = (pfn_t)addr;
850ae115bc7Smrj 	if (mflag)
851ae115bc7Smrj 		pfn = mdb_mfn_to_pfn(pfn);
852ae115bc7Smrj 
853ae115bc7Smrj 	return (do_report_maps(pfn));
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate static int
8577c478bd9Sstevel@tonic-gate do_ptable_dcmd(pfn_t pfn)
8587c478bd9Sstevel@tonic-gate {
859a85a6733Sjosephb 	struct hat *hatp;
8607c478bd9Sstevel@tonic-gate 	struct hat hat;
8617c478bd9Sstevel@tonic-gate 	htable_t *ht;
8627c478bd9Sstevel@tonic-gate 	htable_t htable;
8637c478bd9Sstevel@tonic-gate 	uintptr_t base;
8647c478bd9Sstevel@tonic-gate 	int h;
8657c478bd9Sstevel@tonic-gate 	int level;
8667c478bd9Sstevel@tonic-gate 	int entry;
8677c478bd9Sstevel@tonic-gate 	uintptr_t pagesize;
8687c478bd9Sstevel@tonic-gate 	x86pte_t pte;
8697c478bd9Sstevel@tonic-gate 	x86pte_t buf;
8707c478bd9Sstevel@tonic-gate 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
8717c478bd9Sstevel@tonic-gate 	physaddr_t paddr;
8727c478bd9Sstevel@tonic-gate 	size_t len;
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	/*
875a85a6733Sjosephb 	 * The hats are kept in a list with khat at the head.
8767c478bd9Sstevel@tonic-gate 	 */
877a85a6733Sjosephb 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
8787c478bd9Sstevel@tonic-gate 		/*
8797c478bd9Sstevel@tonic-gate 		 * read the hat and its hash table
8807c478bd9Sstevel@tonic-gate 		 */
8817c478bd9Sstevel@tonic-gate 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
8827c478bd9Sstevel@tonic-gate 			mdb_warn("Couldn't read struct hat\n");
8837c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
8847c478bd9Sstevel@tonic-gate 		}
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 		/*
8877c478bd9Sstevel@tonic-gate 		 * read the htable hashtable
8887c478bd9Sstevel@tonic-gate 		 */
8897c478bd9Sstevel@tonic-gate 		paddr = 0;
8907c478bd9Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
8917c478bd9Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
8927c478bd9Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
8937c478bd9Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
8947c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
8957c478bd9Sstevel@tonic-gate 			}
8967c478bd9Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
8977c478bd9Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
8987c478bd9Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
8997c478bd9Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
9007c478bd9Sstevel@tonic-gate 					return (DCMD_ERR);
9017c478bd9Sstevel@tonic-gate 				}
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 				/*
9047c478bd9Sstevel@tonic-gate 				 * Is this the PFN for this htable
9057c478bd9Sstevel@tonic-gate 				 */
9067c478bd9Sstevel@tonic-gate 				if (htable.ht_pfn == pfn)
9077c478bd9Sstevel@tonic-gate 					goto found_it;
9087c478bd9Sstevel@tonic-gate 			}
9097c478bd9Sstevel@tonic-gate 		}
9107c478bd9Sstevel@tonic-gate 	}
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate found_it:
9137c478bd9Sstevel@tonic-gate 	if (htable.ht_pfn == pfn) {
9147c478bd9Sstevel@tonic-gate 		mdb_printf("htable=%p\n", ht);
9157c478bd9Sstevel@tonic-gate 		level = htable.ht_level;
9167c478bd9Sstevel@tonic-gate 		base = htable.ht_vaddr;
9177c478bd9Sstevel@tonic-gate 		pagesize = mmu.level_size[level];
9187c478bd9Sstevel@tonic-gate 	} else {
9197c478bd9Sstevel@tonic-gate 		mdb_printf("Unknown pagetable - assuming level/addr 0");
9207c478bd9Sstevel@tonic-gate 		level = 0;	/* assume level == 0 for PFN */
9217c478bd9Sstevel@tonic-gate 		base = 0;
9227c478bd9Sstevel@tonic-gate 		pagesize = MMU_PAGESIZE;
9237c478bd9Sstevel@tonic-gate 	}
9247c478bd9Sstevel@tonic-gate 
925ae115bc7Smrj 	paddr = mmu_ptob((physaddr_t)pfn);
9267c478bd9Sstevel@tonic-gate 	for (entry = 0; entry < mmu.ptes_per_table; ++entry) {
9277c478bd9Sstevel@tonic-gate 		len = mdb_pread(&buf, mmu.pte_size,
9287c478bd9Sstevel@tonic-gate 		    paddr + entry * mmu.pte_size);
9297c478bd9Sstevel@tonic-gate 		if (len != mmu.pte_size)
9307c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
9317c478bd9Sstevel@tonic-gate 		if (mmu.pte_size == sizeof (x86pte_t))
9327c478bd9Sstevel@tonic-gate 			pte = buf;
9337c478bd9Sstevel@tonic-gate 		else
9347c478bd9Sstevel@tonic-gate 			pte = *pte32;
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 		if (pte == 0)
9377c478bd9Sstevel@tonic-gate 			continue;
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 		mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize);
9407c478bd9Sstevel@tonic-gate 		do_pte_dcmd(level, pte);
9417c478bd9Sstevel@tonic-gate 	}
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate done:
9447c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
9457c478bd9Sstevel@tonic-gate }
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate /*
948ae115bc7Smrj  * Dump the page table at the given PFN
9497c478bd9Sstevel@tonic-gate  */
9507c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9517c478bd9Sstevel@tonic-gate int
9527c478bd9Sstevel@tonic-gate ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
9537c478bd9Sstevel@tonic-gate {
954ae115bc7Smrj 	pfn_t pfn;
955ae115bc7Smrj 	uint_t mflag = 0;
956ae115bc7Smrj 
957843e1988Sjohnlev 	init_mmu();
958843e1988Sjohnlev 
959ae115bc7Smrj 	if (mmu.num_level == 0)
960ae115bc7Smrj 		return (DCMD_ERR);
961ae115bc7Smrj 
962ae115bc7Smrj 	if ((flags & DCMD_ADDRSPEC) == 0)
963ae115bc7Smrj 		return (DCMD_USAGE);
964ae115bc7Smrj 
965ae115bc7Smrj 	if (mdb_getopts(argc, argv,
966ae115bc7Smrj 	    'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
967ae115bc7Smrj 		return (DCMD_USAGE);
968ae115bc7Smrj 
969ae115bc7Smrj 	pfn = (pfn_t)addr;
970ae115bc7Smrj 	if (mflag)
971ae115bc7Smrj 		pfn = mdb_mfn_to_pfn(pfn);
972ae115bc7Smrj 
973ae115bc7Smrj 	return (do_ptable_dcmd(pfn));
974ae115bc7Smrj }
975ae115bc7Smrj 
976ae115bc7Smrj static int
977ae115bc7Smrj do_htables_dcmd(hat_t *hatp)
978ae115bc7Smrj {
979ae115bc7Smrj 	struct hat hat;
980ae115bc7Smrj 	htable_t *ht;
981ae115bc7Smrj 	htable_t htable;
982ae115bc7Smrj 	int h;
983ae115bc7Smrj 
984ae115bc7Smrj 	/*
985ae115bc7Smrj 	 * read the hat and its hash table
986ae115bc7Smrj 	 */
987ae115bc7Smrj 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
988ae115bc7Smrj 		mdb_warn("Couldn't read struct hat\n");
989ae115bc7Smrj 		return (DCMD_ERR);
990ae115bc7Smrj 	}
991ae115bc7Smrj 
992ae115bc7Smrj 	/*
993ae115bc7Smrj 	 * read the htable hashtable
994ae115bc7Smrj 	 */
995ae115bc7Smrj 	for (h = 0; h < hat.hat_num_hash; ++h) {
996ae115bc7Smrj 		if (mdb_vread(&ht, sizeof (htable_t *),
997ae115bc7Smrj 		    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
998ae115bc7Smrj 			mdb_warn("Couldn't read htable ptr\\n");
999ae115bc7Smrj 			return (DCMD_ERR);
1000ae115bc7Smrj 		}
1001ae115bc7Smrj 		for (; ht != NULL; ht = htable.ht_next) {
1002ae115bc7Smrj 			mdb_printf("%p\n", ht);
1003ae115bc7Smrj 			if (mdb_vread(&htable, sizeof (htable_t),
1004ae115bc7Smrj 			    (uintptr_t)ht) == -1) {
1005ae115bc7Smrj 				mdb_warn("Couldn't read htable\n");
1006ae115bc7Smrj 				return (DCMD_ERR);
1007ae115bc7Smrj 			}
1008ae115bc7Smrj 		}
1009ae115bc7Smrj 	}
1010ae115bc7Smrj 	return (DCMD_OK);
1011ae115bc7Smrj }
1012ae115bc7Smrj 
1013ae115bc7Smrj /*
1014ae115bc7Smrj  * Dump the htables for the given hat
1015ae115bc7Smrj  */
1016ae115bc7Smrj /*ARGSUSED*/
1017ae115bc7Smrj int
1018ae115bc7Smrj htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1019ae115bc7Smrj {
1020ae115bc7Smrj 	hat_t *hat;
1021ae115bc7Smrj 
1022843e1988Sjohnlev 	init_mmu();
1023843e1988Sjohnlev 
10247c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
10257c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
10287c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
10297c478bd9Sstevel@tonic-gate 
1030ae115bc7Smrj 	hat = (hat_t *)addr;
1031ae115bc7Smrj 
1032ae115bc7Smrj 	return (do_htables_dcmd(hat));
10337c478bd9Sstevel@tonic-gate }
1034