1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * This part of the file contains the mdb support for dcmds:
31*7c478bd9Sstevel@tonic-gate  *	::memseg_list
32*7c478bd9Sstevel@tonic-gate  *	::page_num2pp
33*7c478bd9Sstevel@tonic-gate  * and walkers for:
34*7c478bd9Sstevel@tonic-gate  *	memseg - a memseg list walker for ::memseg_list
35*7c478bd9Sstevel@tonic-gate  *
36*7c478bd9Sstevel@tonic-gate  */
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/machparam.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/controlregs.h>
41*7c478bd9Sstevel@tonic-gate #include <vm/as.h>
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
44*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_target.h>
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate #include <vm/page.h>
47*7c478bd9Sstevel@tonic-gate #include <vm/hat_i86.h>
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate struct pfn2pp {
50*7c478bd9Sstevel@tonic-gate 	pfn_t pfn;
51*7c478bd9Sstevel@tonic-gate 	page_t *pp;
52*7c478bd9Sstevel@tonic-gate };
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate static int do_va2pfn(uintptr_t, struct as *, int, physaddr_t *);
55*7c478bd9Sstevel@tonic-gate static void get_mmu(void);
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate int
58*7c478bd9Sstevel@tonic-gate platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
59*7c478bd9Sstevel@tonic-gate {
60*7c478bd9Sstevel@tonic-gate 	if (asp == NULL)
61*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate 	/*
64*7c478bd9Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
65*7c478bd9Sstevel@tonic-gate 	 */
66*7c478bd9Sstevel@tonic-gate 	get_mmu();
67*7c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
68*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate 	return (do_va2pfn(addr, asp, 0, pap));
71*7c478bd9Sstevel@tonic-gate }
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
75*7c478bd9Sstevel@tonic-gate int
76*7c478bd9Sstevel@tonic-gate page_num2pp_cb(uintptr_t addr, void *ignored, uintptr_t *data)
77*7c478bd9Sstevel@tonic-gate {
78*7c478bd9Sstevel@tonic-gate 	struct memseg ms, *msp = &ms;
79*7c478bd9Sstevel@tonic-gate 	struct pfn2pp *p = (struct pfn2pp *)data;
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(msp, sizeof (struct memseg), addr) == -1) {
82*7c478bd9Sstevel@tonic-gate 		mdb_warn("can't read memseg at %#lx", addr);
83*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
84*7c478bd9Sstevel@tonic-gate 	}
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate 	if (p->pfn >= msp->pages_base && p->pfn < msp->pages_end) {
87*7c478bd9Sstevel@tonic-gate 		p->pp = msp->pages + (p->pfn - msp->pages_base);
88*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
89*7c478bd9Sstevel@tonic-gate 	}
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
92*7c478bd9Sstevel@tonic-gate }
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate /*
95*7c478bd9Sstevel@tonic-gate  * ::page_num2pp dcmd
96*7c478bd9Sstevel@tonic-gate  */
97*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
98*7c478bd9Sstevel@tonic-gate int
99*7c478bd9Sstevel@tonic-gate page_num2pp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
100*7c478bd9Sstevel@tonic-gate {
101*7c478bd9Sstevel@tonic-gate 	struct pfn2pp pfn2pp;
102*7c478bd9Sstevel@tonic-gate 	page_t page;
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0) {
105*7c478bd9Sstevel@tonic-gate 		mdb_warn("page frame number missing\n");
106*7c478bd9Sstevel@tonic-gate 			return (DCMD_USAGE);
107*7c478bd9Sstevel@tonic-gate 	}
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	pfn2pp.pfn = (pfn_t)addr;
110*7c478bd9Sstevel@tonic-gate 	pfn2pp.pp = NULL;
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	if (mdb_walk("memseg", (mdb_walk_cb_t)page_num2pp_cb,
113*7c478bd9Sstevel@tonic-gate 	    (void *)&pfn2pp) == -1) {
114*7c478bd9Sstevel@tonic-gate 		mdb_warn("can't walk memseg");
115*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
116*7c478bd9Sstevel@tonic-gate 	}
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	if (pfn2pp.pp == NULL)
119*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 	mdb_printf("%x has page at %p\n", pfn2pp.pfn, pfn2pp.pp);
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&page, sizeof (page_t),
124*7c478bd9Sstevel@tonic-gate 	    (uintptr_t)pfn2pp.pp) == -1) {
125*7c478bd9Sstevel@tonic-gate 		mdb_warn("can't read page at %p", &page);
126*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
127*7c478bd9Sstevel@tonic-gate 	}
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate 	if (page.p_pagenum != pfn2pp.pfn) {
130*7c478bd9Sstevel@tonic-gate 		mdb_warn("WARNING! Found page structure contains "
131*7c478bd9Sstevel@tonic-gate 			"different pagenumber %x\n", page.p_pagenum);
132*7c478bd9Sstevel@tonic-gate 	}
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
135*7c478bd9Sstevel@tonic-gate }
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate /*
142*7c478bd9Sstevel@tonic-gate  * ::memseg_list dcmd and walker to implement it.
143*7c478bd9Sstevel@tonic-gate  */
144*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
145*7c478bd9Sstevel@tonic-gate int
146*7c478bd9Sstevel@tonic-gate memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
147*7c478bd9Sstevel@tonic-gate {
148*7c478bd9Sstevel@tonic-gate 	struct memseg ms;
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
151*7c478bd9Sstevel@tonic-gate 		if (mdb_pwalk_dcmd("memseg", "memseg_list",
152*7c478bd9Sstevel@tonic-gate 		    0, NULL, 0) == -1) {
153*7c478bd9Sstevel@tonic-gate 			mdb_warn("can't walk memseg");
154*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
155*7c478bd9Sstevel@tonic-gate 		}
156*7c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
157*7c478bd9Sstevel@tonic-gate 	}
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
160*7c478bd9Sstevel@tonic-gate 		mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
161*7c478bd9Sstevel@tonic-gate 			"PAGES", "EPAGES", "BASE", "END");
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
164*7c478bd9Sstevel@tonic-gate 		mdb_warn("can't read memseg at %#lx", addr);
165*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
166*7c478bd9Sstevel@tonic-gate 	}
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 	mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr,
169*7c478bd9Sstevel@tonic-gate 		ms.pages, ms.epages, ms.pages_base, ms.pages_end);
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
172*7c478bd9Sstevel@tonic-gate }
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate /*
175*7c478bd9Sstevel@tonic-gate  * walk the memseg structures
176*7c478bd9Sstevel@tonic-gate  */
177*7c478bd9Sstevel@tonic-gate int
178*7c478bd9Sstevel@tonic-gate memseg_walk_init(mdb_walk_state_t *wsp)
179*7c478bd9Sstevel@tonic-gate {
180*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr != NULL) {
181*7c478bd9Sstevel@tonic-gate 		mdb_warn("memseg only supports global walks\n");
182*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
183*7c478bd9Sstevel@tonic-gate 	}
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
186*7c478bd9Sstevel@tonic-gate 		mdb_warn("symbol 'memsegs' not found");
187*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
188*7c478bd9Sstevel@tonic-gate 	}
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
191*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate }
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate int
196*7c478bd9Sstevel@tonic-gate memseg_walk_step(mdb_walk_state_t *wsp)
197*7c478bd9Sstevel@tonic-gate {
198*7c478bd9Sstevel@tonic-gate 	int status;
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	if (wsp->walk_addr == 0) {
201*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
202*7c478bd9Sstevel@tonic-gate 	}
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (struct memseg),
205*7c478bd9Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
206*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read struct memseg at %p", wsp->walk_addr);
207*7c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
208*7c478bd9Sstevel@tonic-gate 	}
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
211*7c478bd9Sstevel@tonic-gate 	    wsp->walk_cbdata);
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	return (status);
216*7c478bd9Sstevel@tonic-gate }
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate void
219*7c478bd9Sstevel@tonic-gate memseg_walk_fini(mdb_walk_state_t *wsp)
220*7c478bd9Sstevel@tonic-gate {
221*7c478bd9Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct memseg));
222*7c478bd9Sstevel@tonic-gate }
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate /*
225*7c478bd9Sstevel@tonic-gate  * HAT related dcmds:
226*7c478bd9Sstevel@tonic-gate  *
227*7c478bd9Sstevel@tonic-gate  * ::pte [-p XXXXXXXX] [-l 0/1/2/3]
228*7c478bd9Sstevel@tonic-gate  *
229*7c478bd9Sstevel@tonic-gate  * dcmd that interprets the -p argument as a page table entry and
230*7c478bd9Sstevel@tonic-gate  * prints it in more human readable form. The PTE is assumed to be in
231*7c478bd9Sstevel@tonic-gate  * a level 0 page table, unless -l specifies another level.
232*7c478bd9Sstevel@tonic-gate  *
233*7c478bd9Sstevel@tonic-gate  * ::vatopfn [-v] [-a as]
234*7c478bd9Sstevel@tonic-gate  *
235*7c478bd9Sstevel@tonic-gate  * Given a virtual address, returns the PFN, if any, mapped at the address.
236*7c478bd9Sstevel@tonic-gate  * -v shows the intermediate htable/page table entries used to resolve the
237*7c478bd9Sstevel@tonic-gate  * mapping. By default the virtual address is assumed to be in the kernel's
238*7c478bd9Sstevel@tonic-gate  * address space.  -a is used to specify a different address space.
239*7c478bd9Sstevel@tonic-gate  */
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate struct hat *khat;		/* value of kas.a_hat */
242*7c478bd9Sstevel@tonic-gate struct hat_mmu_info mmu;
243*7c478bd9Sstevel@tonic-gate uintptr_t kernelbase;
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate /*
246*7c478bd9Sstevel@tonic-gate  * read mmu parameters from kernel
247*7c478bd9Sstevel@tonic-gate  */
248*7c478bd9Sstevel@tonic-gate static void
249*7c478bd9Sstevel@tonic-gate get_mmu(void)
250*7c478bd9Sstevel@tonic-gate {
251*7c478bd9Sstevel@tonic-gate 	struct as kas;
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	if (mmu.num_level != 0)
254*7c478bd9Sstevel@tonic-gate 		return;
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1)
257*7c478bd9Sstevel@tonic-gate 		mdb_warn("Can't use HAT information before mmu_init()\n");
258*7c478bd9Sstevel@tonic-gate 	if (mdb_readsym(&kas, sizeof (kas), "kas") == -1)
259*7c478bd9Sstevel@tonic-gate 		mdb_warn("Couldn't find kas - kernel's struct as\n");
260*7c478bd9Sstevel@tonic-gate 	if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1)
261*7c478bd9Sstevel@tonic-gate 		mdb_warn("Couldn't find kernelbase\n");
262*7c478bd9Sstevel@tonic-gate 	khat = kas.a_hat;
263*7c478bd9Sstevel@tonic-gate }
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate /*
266*7c478bd9Sstevel@tonic-gate  * Print a PTE in more human friendly way. The PTE is assumed to be in
267*7c478bd9Sstevel@tonic-gate  * a level 0 page table, unless -l specifies another level.
268*7c478bd9Sstevel@tonic-gate  *
269*7c478bd9Sstevel@tonic-gate  * The PTE value can be specified as the -p option, since on a 32 bit kernel
270*7c478bd9Sstevel@tonic-gate  * with PAE running it's larger than a uintptr_t.
271*7c478bd9Sstevel@tonic-gate  */
272*7c478bd9Sstevel@tonic-gate static int
273*7c478bd9Sstevel@tonic-gate do_pte_dcmd(int level, uint64_t pte)
274*7c478bd9Sstevel@tonic-gate {
275*7c478bd9Sstevel@tonic-gate 	static char *attr[] = {
276*7c478bd9Sstevel@tonic-gate 	    "wrback", "wrthru", "uncached", "uncached",
277*7c478bd9Sstevel@tonic-gate 	    "wrback", "wrthru", "wrcombine", "uncached"};
278*7c478bd9Sstevel@tonic-gate 	int pat_index = 0;
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	mdb_printf("PTE=%llx: ", pte);
281*7c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, mmu.pt_nx))
282*7c478bd9Sstevel@tonic-gate 		mdb_printf("noexec ");
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	mdb_printf("page=0x%llx ", PTE2PFN(pte, level));
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOCONSIST))
287*7c478bd9Sstevel@tonic-gate 		mdb_printf("noconsist ");
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOSYNC))
290*7c478bd9Sstevel@tonic-gate 		mdb_printf("nosync ");
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, mmu.pt_global))
293*7c478bd9Sstevel@tonic-gate 		mdb_printf("global ");
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
296*7c478bd9Sstevel@tonic-gate 		mdb_printf("largepage ");
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_MOD))
299*7c478bd9Sstevel@tonic-gate 		mdb_printf("mod ");
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 	if (level > 0 && PTE_GET(pte, PT_REF))
302*7c478bd9Sstevel@tonic-gate 		mdb_printf("ref ");
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, PT_USER))
305*7c478bd9Sstevel@tonic-gate 		mdb_printf("user ");
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, PT_WRITABLE))
308*7c478bd9Sstevel@tonic-gate 		mdb_printf("write ");
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	/*
311*7c478bd9Sstevel@tonic-gate 	 * Report non-standard cacheability
312*7c478bd9Sstevel@tonic-gate 	 */
313*7c478bd9Sstevel@tonic-gate 	pat_index = 0;
314*7c478bd9Sstevel@tonic-gate 	if (level > 0) {
315*7c478bd9Sstevel@tonic-gate 		if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE))
316*7c478bd9Sstevel@tonic-gate 			pat_index += 4;
317*7c478bd9Sstevel@tonic-gate 	} else {
318*7c478bd9Sstevel@tonic-gate 		if (PTE_GET(pte, PT_PAT_4K))
319*7c478bd9Sstevel@tonic-gate 			pat_index += 4;
320*7c478bd9Sstevel@tonic-gate 	}
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, PT_NOCACHE))
323*7c478bd9Sstevel@tonic-gate 		pat_index += 2;
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, PT_WRITETHRU))
326*7c478bd9Sstevel@tonic-gate 		pat_index += 1;
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	if (pat_index != 0)
329*7c478bd9Sstevel@tonic-gate 		mdb_printf("%s", attr[pat_index]);
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 	if (PTE_GET(pte, PT_VALID) == 0)
332*7c478bd9Sstevel@tonic-gate 		mdb_printf(" !VALID ");
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
335*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
336*7c478bd9Sstevel@tonic-gate }
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate /*
339*7c478bd9Sstevel@tonic-gate  * Print a PTE in more human friendly way. The PTE is assumed to be in
340*7c478bd9Sstevel@tonic-gate  * a level 0 page table, unless -l specifies another level.
341*7c478bd9Sstevel@tonic-gate  *
342*7c478bd9Sstevel@tonic-gate  * The PTE value can be specified as the -p option, since on a 32 bit kernel
343*7c478bd9Sstevel@tonic-gate  * with PAE running it's larger than a uintptr_t.
344*7c478bd9Sstevel@tonic-gate  */
345*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
346*7c478bd9Sstevel@tonic-gate int
347*7c478bd9Sstevel@tonic-gate pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
348*7c478bd9Sstevel@tonic-gate {
349*7c478bd9Sstevel@tonic-gate 	int level = 0;
350*7c478bd9Sstevel@tonic-gate 	uint64_t pte = 0;
351*7c478bd9Sstevel@tonic-gate 	char *level_str = NULL;
352*7c478bd9Sstevel@tonic-gate 	char *pte_str = NULL;
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	/*
355*7c478bd9Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
356*7c478bd9Sstevel@tonic-gate 	 */
357*7c478bd9Sstevel@tonic-gate 	get_mmu();
358*7c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
359*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
362*7c478bd9Sstevel@tonic-gate 	    'p', MDB_OPT_STR, &pte_str,
363*7c478bd9Sstevel@tonic-gate 	    'l', MDB_OPT_STR, &level_str) != argc)
364*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	/*
367*7c478bd9Sstevel@tonic-gate 	 * parse the PTE to decode, if it's 0, we don't do anything
368*7c478bd9Sstevel@tonic-gate 	 */
369*7c478bd9Sstevel@tonic-gate 	if (pte_str != NULL) {
370*7c478bd9Sstevel@tonic-gate 		pte = mdb_strtoull(pte_str);
371*7c478bd9Sstevel@tonic-gate 	} else {
372*7c478bd9Sstevel@tonic-gate 		if ((flags & DCMD_ADDRSPEC) == 0)
373*7c478bd9Sstevel@tonic-gate 			return (DCMD_USAGE);
374*7c478bd9Sstevel@tonic-gate 		pte = addr;
375*7c478bd9Sstevel@tonic-gate 	}
376*7c478bd9Sstevel@tonic-gate 	if (pte == 0)
377*7c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	/*
380*7c478bd9Sstevel@tonic-gate 	 * parse the level if supplied
381*7c478bd9Sstevel@tonic-gate 	 */
382*7c478bd9Sstevel@tonic-gate 	if (level_str != NULL) {
383*7c478bd9Sstevel@tonic-gate 		level = mdb_strtoull(level_str);
384*7c478bd9Sstevel@tonic-gate 		if (level < 0 || level > mmu.max_level)
385*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
386*7c478bd9Sstevel@tonic-gate 	}
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	return (do_pte_dcmd(level, pte));
389*7c478bd9Sstevel@tonic-gate }
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate static int
392*7c478bd9Sstevel@tonic-gate do_va2pfn(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap)
393*7c478bd9Sstevel@tonic-gate {
394*7c478bd9Sstevel@tonic-gate 	struct as as;
395*7c478bd9Sstevel@tonic-gate 	struct hat *hatp;
396*7c478bd9Sstevel@tonic-gate 	struct hat hat;
397*7c478bd9Sstevel@tonic-gate 	htable_t *ht;
398*7c478bd9Sstevel@tonic-gate 	htable_t htable;
399*7c478bd9Sstevel@tonic-gate 	uintptr_t base;
400*7c478bd9Sstevel@tonic-gate 	int h;
401*7c478bd9Sstevel@tonic-gate 	int level;
402*7c478bd9Sstevel@tonic-gate 	int found = 0;
403*7c478bd9Sstevel@tonic-gate 	x86pte_t pte;
404*7c478bd9Sstevel@tonic-gate 	x86pte_t buf;
405*7c478bd9Sstevel@tonic-gate 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
406*7c478bd9Sstevel@tonic-gate 	physaddr_t paddr;
407*7c478bd9Sstevel@tonic-gate 	size_t len;
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	if (asp != NULL) {
410*7c478bd9Sstevel@tonic-gate 		if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
411*7c478bd9Sstevel@tonic-gate 			mdb_warn("Couldn't read struct as\n");
412*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
413*7c478bd9Sstevel@tonic-gate 		}
414*7c478bd9Sstevel@tonic-gate 		hatp = as.a_hat;
415*7c478bd9Sstevel@tonic-gate 	} else {
416*7c478bd9Sstevel@tonic-gate 		hatp = khat;
417*7c478bd9Sstevel@tonic-gate 	}
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 	/*
420*7c478bd9Sstevel@tonic-gate 	 * read the hat and its hash table
421*7c478bd9Sstevel@tonic-gate 	 */
422*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
423*7c478bd9Sstevel@tonic-gate 		mdb_warn("Couldn't read struct hat\n");
424*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
425*7c478bd9Sstevel@tonic-gate 	}
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	/*
428*7c478bd9Sstevel@tonic-gate 	 * read the htable hashtable
429*7c478bd9Sstevel@tonic-gate 	 */
430*7c478bd9Sstevel@tonic-gate 	*pap = 0;
431*7c478bd9Sstevel@tonic-gate 	for (level = 0; level <= mmu.max_level; ++level) {
432*7c478bd9Sstevel@tonic-gate 		if (level == mmu.max_level)
433*7c478bd9Sstevel@tonic-gate 			base = 0;
434*7c478bd9Sstevel@tonic-gate 		else
435*7c478bd9Sstevel@tonic-gate 			base = addr & mmu.level_mask[level + 1];
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
438*7c478bd9Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
439*7c478bd9Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
440*7c478bd9Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
441*7c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
442*7c478bd9Sstevel@tonic-gate 			}
443*7c478bd9Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
444*7c478bd9Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
445*7c478bd9Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
446*7c478bd9Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
447*7c478bd9Sstevel@tonic-gate 					return (DCMD_ERR);
448*7c478bd9Sstevel@tonic-gate 				}
449*7c478bd9Sstevel@tonic-gate 				if (htable.ht_vaddr != base ||
450*7c478bd9Sstevel@tonic-gate 				    htable.ht_level != level)
451*7c478bd9Sstevel@tonic-gate 					continue;
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 				/*
454*7c478bd9Sstevel@tonic-gate 				 * found - read the page table entry
455*7c478bd9Sstevel@tonic-gate 				 */
456*7c478bd9Sstevel@tonic-gate 				paddr = htable.ht_pfn << MMU_PAGESHIFT;
457*7c478bd9Sstevel@tonic-gate 				paddr += ((addr - base) >>
458*7c478bd9Sstevel@tonic-gate 				    mmu.level_shift[level]) <<
459*7c478bd9Sstevel@tonic-gate 				    mmu.pte_size_shift;
460*7c478bd9Sstevel@tonic-gate 				len = mdb_pread(&buf, mmu.pte_size, paddr);
461*7c478bd9Sstevel@tonic-gate 				if (len != mmu.pte_size)
462*7c478bd9Sstevel@tonic-gate 					return (DCMD_ERR);
463*7c478bd9Sstevel@tonic-gate 				if (mmu.pte_size == sizeof (x86pte_t))
464*7c478bd9Sstevel@tonic-gate 					pte = buf;
465*7c478bd9Sstevel@tonic-gate 				else
466*7c478bd9Sstevel@tonic-gate 					pte = *pte32;
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 				if (!found) {
469*7c478bd9Sstevel@tonic-gate 					if (PTE_IS_LGPG(pte, level))
470*7c478bd9Sstevel@tonic-gate 						paddr = pte & PT_PADDR_LGPG;
471*7c478bd9Sstevel@tonic-gate 					else
472*7c478bd9Sstevel@tonic-gate 						paddr = pte & PT_PADDR;
473*7c478bd9Sstevel@tonic-gate 					paddr += addr & mmu.level_offset[level];
474*7c478bd9Sstevel@tonic-gate 					*pap = paddr;
475*7c478bd9Sstevel@tonic-gate 					found = 1;
476*7c478bd9Sstevel@tonic-gate 				}
477*7c478bd9Sstevel@tonic-gate 				if (print_level == 0)
478*7c478bd9Sstevel@tonic-gate 					continue;
479*7c478bd9Sstevel@tonic-gate 				mdb_printf("\tlevel=%d htable=%p pte=%llx\n",
480*7c478bd9Sstevel@tonic-gate 				    level, ht, pte);
481*7c478bd9Sstevel@tonic-gate 			}
482*7c478bd9Sstevel@tonic-gate 		}
483*7c478bd9Sstevel@tonic-gate 	}
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate done:
486*7c478bd9Sstevel@tonic-gate 	if (!found)
487*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
488*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
489*7c478bd9Sstevel@tonic-gate }
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate int
492*7c478bd9Sstevel@tonic-gate va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
493*7c478bd9Sstevel@tonic-gate {
494*7c478bd9Sstevel@tonic-gate 	uintptr_t addrspace;
495*7c478bd9Sstevel@tonic-gate 	char *addrspace_str = NULL;
496*7c478bd9Sstevel@tonic-gate 	uint64_t physaddr;
497*7c478bd9Sstevel@tonic-gate 	int rc;
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	/*
500*7c478bd9Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
501*7c478bd9Sstevel@tonic-gate 	 */
502*7c478bd9Sstevel@tonic-gate 	get_mmu();
503*7c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
504*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
507*7c478bd9Sstevel@tonic-gate 	    'a', MDB_OPT_STR, &addrspace_str) != argc)
508*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
511*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 	/*
514*7c478bd9Sstevel@tonic-gate 	 * parse the address space
515*7c478bd9Sstevel@tonic-gate 	 */
516*7c478bd9Sstevel@tonic-gate 	if (addrspace_str != NULL)
517*7c478bd9Sstevel@tonic-gate 		addrspace = mdb_strtoull(addrspace_str);
518*7c478bd9Sstevel@tonic-gate 	else
519*7c478bd9Sstevel@tonic-gate 		addrspace = 0;
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 	rc = do_va2pfn(addr, (struct as *)addrspace, 1, &physaddr);
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate 	if (rc == DCMD_OK)
524*7c478bd9Sstevel@tonic-gate 		mdb_printf("Virtual %p maps Physical %llx\n", addr, physaddr);
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 	return (rc);
527*7c478bd9Sstevel@tonic-gate }
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate /*
530*7c478bd9Sstevel@tonic-gate  * Report all hat's that either use PFN as a page table or that map the page.
531*7c478bd9Sstevel@tonic-gate  */
532*7c478bd9Sstevel@tonic-gate static int
533*7c478bd9Sstevel@tonic-gate do_report_maps(pfn_t pfn)
534*7c478bd9Sstevel@tonic-gate {
535*7c478bd9Sstevel@tonic-gate 	struct hat *hatp, *end;
536*7c478bd9Sstevel@tonic-gate 	struct hat hat;
537*7c478bd9Sstevel@tonic-gate 	htable_t *ht;
538*7c478bd9Sstevel@tonic-gate 	htable_t htable;
539*7c478bd9Sstevel@tonic-gate 	uintptr_t base;
540*7c478bd9Sstevel@tonic-gate 	int h;
541*7c478bd9Sstevel@tonic-gate 	int level;
542*7c478bd9Sstevel@tonic-gate 	int entry;
543*7c478bd9Sstevel@tonic-gate 	x86pte_t pte;
544*7c478bd9Sstevel@tonic-gate 	x86pte_t buf;
545*7c478bd9Sstevel@tonic-gate 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
546*7c478bd9Sstevel@tonic-gate 	physaddr_t paddr;
547*7c478bd9Sstevel@tonic-gate 	size_t len;
548*7c478bd9Sstevel@tonic-gate 	int count;
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)khat) == -1) {
551*7c478bd9Sstevel@tonic-gate 		mdb_warn("Couldn't read khat\n");
552*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
553*7c478bd9Sstevel@tonic-gate 	}
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	end = hat.hat_next;
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	/*
558*7c478bd9Sstevel@tonic-gate 	 * The hats are kept in a circular list with khat at the head, but
559*7c478bd9Sstevel@tonic-gate 	 * not part of the list proper. Accordingly, we know when we pass
560*7c478bd9Sstevel@tonic-gate 	 * knat.hat_next a second time that we've iterated through every
561*7c478bd9Sstevel@tonic-gate 	 * hat structure.
562*7c478bd9Sstevel@tonic-gate 	 */
563*7c478bd9Sstevel@tonic-gate 	for (hatp = khat, count = 0; hatp != end || count++ == 0;
564*7c478bd9Sstevel@tonic-gate 	    hatp = hat.hat_next) {
565*7c478bd9Sstevel@tonic-gate 		/*
566*7c478bd9Sstevel@tonic-gate 		 * read the hat and its hash table
567*7c478bd9Sstevel@tonic-gate 		 */
568*7c478bd9Sstevel@tonic-gate 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
569*7c478bd9Sstevel@tonic-gate 			mdb_warn("Couldn't read struct hat\n");
570*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
571*7c478bd9Sstevel@tonic-gate 		}
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 		/*
574*7c478bd9Sstevel@tonic-gate 		 * read the htable hashtable
575*7c478bd9Sstevel@tonic-gate 		 */
576*7c478bd9Sstevel@tonic-gate 		paddr = 0;
577*7c478bd9Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
578*7c478bd9Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
579*7c478bd9Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
580*7c478bd9Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
581*7c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
582*7c478bd9Sstevel@tonic-gate 			}
583*7c478bd9Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
584*7c478bd9Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
585*7c478bd9Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
586*7c478bd9Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
587*7c478bd9Sstevel@tonic-gate 					return (DCMD_ERR);
588*7c478bd9Sstevel@tonic-gate 				}
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 				/*
591*7c478bd9Sstevel@tonic-gate 				 * only report kernel addresses once
592*7c478bd9Sstevel@tonic-gate 				 */
593*7c478bd9Sstevel@tonic-gate 				if (hatp != khat &&
594*7c478bd9Sstevel@tonic-gate 				    htable.ht_vaddr >= kernelbase)
595*7c478bd9Sstevel@tonic-gate 					continue;
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 				/*
598*7c478bd9Sstevel@tonic-gate 				 * Is the PFN a pagetable itself?
599*7c478bd9Sstevel@tonic-gate 				 */
600*7c478bd9Sstevel@tonic-gate 				if (htable.ht_pfn == pfn) {
601*7c478bd9Sstevel@tonic-gate 					mdb_printf("Pagetable for "
602*7c478bd9Sstevel@tonic-gate 					    "hat=%p htable=%p\n", hatp, ht);
603*7c478bd9Sstevel@tonic-gate 					continue;
604*7c478bd9Sstevel@tonic-gate 				}
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 				/*
607*7c478bd9Sstevel@tonic-gate 				 * otherwise, examine page mappings
608*7c478bd9Sstevel@tonic-gate 				 */
609*7c478bd9Sstevel@tonic-gate 				level = htable.ht_level;
610*7c478bd9Sstevel@tonic-gate 				if (level > mmu.max_page_level)
611*7c478bd9Sstevel@tonic-gate 					continue;
612*7c478bd9Sstevel@tonic-gate 				paddr = htable.ht_pfn << MMU_PAGESHIFT;
613*7c478bd9Sstevel@tonic-gate 				for (entry = 0; entry < htable.ht_num_ptes;
614*7c478bd9Sstevel@tonic-gate 				    ++entry) {
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 					base = htable.ht_vaddr + entry *
617*7c478bd9Sstevel@tonic-gate 					    mmu.level_size[level];
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 					/*
620*7c478bd9Sstevel@tonic-gate 					 * only report kernel addresses once
621*7c478bd9Sstevel@tonic-gate 					 */
622*7c478bd9Sstevel@tonic-gate 					if (hatp != khat &&
623*7c478bd9Sstevel@tonic-gate 					    base >= kernelbase)
624*7c478bd9Sstevel@tonic-gate 						continue;
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 					len = mdb_pread(&buf, mmu.pte_size,
627*7c478bd9Sstevel@tonic-gate 					    paddr + entry * mmu.pte_size);
628*7c478bd9Sstevel@tonic-gate 					if (len != mmu.pte_size)
629*7c478bd9Sstevel@tonic-gate 						return (DCMD_ERR);
630*7c478bd9Sstevel@tonic-gate 					if (mmu.pte_size == sizeof (x86pte_t))
631*7c478bd9Sstevel@tonic-gate 						pte = buf;
632*7c478bd9Sstevel@tonic-gate 					else
633*7c478bd9Sstevel@tonic-gate 						pte = *pte32;
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 					if ((pte & PT_VALID) == 0)
636*7c478bd9Sstevel@tonic-gate 						continue;
637*7c478bd9Sstevel@tonic-gate 					if (level == 0 || !(pte & PT_PAGESIZE))
638*7c478bd9Sstevel@tonic-gate 						pte &= PT_PADDR;
639*7c478bd9Sstevel@tonic-gate 					else
640*7c478bd9Sstevel@tonic-gate 						pte &= PT_PADDR_LGPG;
641*7c478bd9Sstevel@tonic-gate 					if ((pte >> MMU_PAGESHIFT) != pfn)
642*7c478bd9Sstevel@tonic-gate 						continue;
643*7c478bd9Sstevel@tonic-gate 					mdb_printf("hat=%p maps addr=%p\n",
644*7c478bd9Sstevel@tonic-gate 						hatp, (caddr_t)base);
645*7c478bd9Sstevel@tonic-gate 				}
646*7c478bd9Sstevel@tonic-gate 			}
647*7c478bd9Sstevel@tonic-gate 		}
648*7c478bd9Sstevel@tonic-gate 	}
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate done:
651*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
652*7c478bd9Sstevel@tonic-gate }
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate /*
655*7c478bd9Sstevel@tonic-gate  * given a PFN as its address argument, prints out the uses of it
656*7c478bd9Sstevel@tonic-gate  */
657*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
658*7c478bd9Sstevel@tonic-gate int
659*7c478bd9Sstevel@tonic-gate report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
660*7c478bd9Sstevel@tonic-gate {
661*7c478bd9Sstevel@tonic-gate 	/*
662*7c478bd9Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
663*7c478bd9Sstevel@tonic-gate 	 */
664*7c478bd9Sstevel@tonic-gate 	get_mmu();
665*7c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
666*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
669*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 	return (do_report_maps((pfn_t)addr));
672*7c478bd9Sstevel@tonic-gate }
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate /*
675*7c478bd9Sstevel@tonic-gate  * Dump the page table at the given PFN
676*7c478bd9Sstevel@tonic-gate  */
677*7c478bd9Sstevel@tonic-gate static int
678*7c478bd9Sstevel@tonic-gate do_ptable_dcmd(pfn_t pfn)
679*7c478bd9Sstevel@tonic-gate {
680*7c478bd9Sstevel@tonic-gate 	struct hat *hatp, *end;
681*7c478bd9Sstevel@tonic-gate 	struct hat hat;
682*7c478bd9Sstevel@tonic-gate 	htable_t *ht;
683*7c478bd9Sstevel@tonic-gate 	htable_t htable;
684*7c478bd9Sstevel@tonic-gate 	uintptr_t base;
685*7c478bd9Sstevel@tonic-gate 	int h;
686*7c478bd9Sstevel@tonic-gate 	int level;
687*7c478bd9Sstevel@tonic-gate 	int entry;
688*7c478bd9Sstevel@tonic-gate 	uintptr_t pagesize;
689*7c478bd9Sstevel@tonic-gate 	x86pte_t pte;
690*7c478bd9Sstevel@tonic-gate 	x86pte_t buf;
691*7c478bd9Sstevel@tonic-gate 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
692*7c478bd9Sstevel@tonic-gate 	physaddr_t paddr;
693*7c478bd9Sstevel@tonic-gate 	size_t len;
694*7c478bd9Sstevel@tonic-gate 	int count;
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)khat) == -1) {
697*7c478bd9Sstevel@tonic-gate 		mdb_warn("Couldn't read khat\n");
698*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
699*7c478bd9Sstevel@tonic-gate 	}
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 	end = hat.hat_next;
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 	/*
704*7c478bd9Sstevel@tonic-gate 	 * The hats are kept in a circular list with khat at the head, but
705*7c478bd9Sstevel@tonic-gate 	 * not part of the list proper. Accordingly, we know when we pass
706*7c478bd9Sstevel@tonic-gate 	 * knat.hat_next a second time that we've iterated through every
707*7c478bd9Sstevel@tonic-gate 	 * hat structure.
708*7c478bd9Sstevel@tonic-gate 	 */
709*7c478bd9Sstevel@tonic-gate 	for (hatp = khat, count = 0; hatp != end || count++ == 0;
710*7c478bd9Sstevel@tonic-gate 	    hatp = hat.hat_next) {
711*7c478bd9Sstevel@tonic-gate 		/*
712*7c478bd9Sstevel@tonic-gate 		 * read the hat and its hash table
713*7c478bd9Sstevel@tonic-gate 		 */
714*7c478bd9Sstevel@tonic-gate 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
715*7c478bd9Sstevel@tonic-gate 			mdb_warn("Couldn't read struct hat\n");
716*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
717*7c478bd9Sstevel@tonic-gate 		}
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 		/*
720*7c478bd9Sstevel@tonic-gate 		 * read the htable hashtable
721*7c478bd9Sstevel@tonic-gate 		 */
722*7c478bd9Sstevel@tonic-gate 		paddr = 0;
723*7c478bd9Sstevel@tonic-gate 		for (h = 0; h < hat.hat_num_hash; ++h) {
724*7c478bd9Sstevel@tonic-gate 			if (mdb_vread(&ht, sizeof (htable_t *),
725*7c478bd9Sstevel@tonic-gate 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
726*7c478bd9Sstevel@tonic-gate 				mdb_warn("Couldn't read htable\n");
727*7c478bd9Sstevel@tonic-gate 				return (DCMD_ERR);
728*7c478bd9Sstevel@tonic-gate 			}
729*7c478bd9Sstevel@tonic-gate 			for (; ht != NULL; ht = htable.ht_next) {
730*7c478bd9Sstevel@tonic-gate 				if (mdb_vread(&htable, sizeof (htable_t),
731*7c478bd9Sstevel@tonic-gate 				    (uintptr_t)ht) == -1) {
732*7c478bd9Sstevel@tonic-gate 					mdb_warn("Couldn't read htable\n");
733*7c478bd9Sstevel@tonic-gate 					return (DCMD_ERR);
734*7c478bd9Sstevel@tonic-gate 				}
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 				/*
737*7c478bd9Sstevel@tonic-gate 				 * Is this the PFN for this htable
738*7c478bd9Sstevel@tonic-gate 				 */
739*7c478bd9Sstevel@tonic-gate 				if (htable.ht_pfn == pfn)
740*7c478bd9Sstevel@tonic-gate 					goto found_it;
741*7c478bd9Sstevel@tonic-gate 			}
742*7c478bd9Sstevel@tonic-gate 		}
743*7c478bd9Sstevel@tonic-gate 	}
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate found_it:
746*7c478bd9Sstevel@tonic-gate 	if (htable.ht_pfn == pfn) {
747*7c478bd9Sstevel@tonic-gate 		mdb_printf("htable=%p\n", ht);
748*7c478bd9Sstevel@tonic-gate 		level = htable.ht_level;
749*7c478bd9Sstevel@tonic-gate 		base = htable.ht_vaddr;
750*7c478bd9Sstevel@tonic-gate 		pagesize = mmu.level_size[level];
751*7c478bd9Sstevel@tonic-gate 	} else {
752*7c478bd9Sstevel@tonic-gate 		mdb_printf("Unknown pagetable - assuming level/addr 0");
753*7c478bd9Sstevel@tonic-gate 		level = 0;	/* assume level == 0 for PFN */
754*7c478bd9Sstevel@tonic-gate 		base = 0;
755*7c478bd9Sstevel@tonic-gate 		pagesize = MMU_PAGESIZE;
756*7c478bd9Sstevel@tonic-gate 	}
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate 	paddr = pfn << MMU_PAGESHIFT;
759*7c478bd9Sstevel@tonic-gate 	for (entry = 0; entry < mmu.ptes_per_table; ++entry) {
760*7c478bd9Sstevel@tonic-gate 		len = mdb_pread(&buf, mmu.pte_size,
761*7c478bd9Sstevel@tonic-gate 		    paddr + entry * mmu.pte_size);
762*7c478bd9Sstevel@tonic-gate 		if (len != mmu.pte_size)
763*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
764*7c478bd9Sstevel@tonic-gate 		if (mmu.pte_size == sizeof (x86pte_t))
765*7c478bd9Sstevel@tonic-gate 			pte = buf;
766*7c478bd9Sstevel@tonic-gate 		else
767*7c478bd9Sstevel@tonic-gate 			pte = *pte32;
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 		if (pte == 0)
770*7c478bd9Sstevel@tonic-gate 			continue;
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate 		mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize);
773*7c478bd9Sstevel@tonic-gate 		do_pte_dcmd(level, pte);
774*7c478bd9Sstevel@tonic-gate 	}
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate done:
777*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
778*7c478bd9Sstevel@tonic-gate }
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate /*
781*7c478bd9Sstevel@tonic-gate  * given a PFN as its address argument, prints out the uses of it
782*7c478bd9Sstevel@tonic-gate  */
783*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
784*7c478bd9Sstevel@tonic-gate int
785*7c478bd9Sstevel@tonic-gate ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
786*7c478bd9Sstevel@tonic-gate {
787*7c478bd9Sstevel@tonic-gate 	/*
788*7c478bd9Sstevel@tonic-gate 	 * The kernel has to at least have made it thru mmu_init()
789*7c478bd9Sstevel@tonic-gate 	 */
790*7c478bd9Sstevel@tonic-gate 	get_mmu();
791*7c478bd9Sstevel@tonic-gate 	if (mmu.num_level == 0)
792*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) == 0)
795*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
796*7c478bd9Sstevel@tonic-gate 
797*7c478bd9Sstevel@tonic-gate 	return (do_ptable_dcmd((pfn_t)addr));
798*7c478bd9Sstevel@tonic-gate }
799