xref: /illumos-gate/usr/src/cmd/mdb/i86pc/modules/unix/i86mmu.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
26 
27 /*
28  * This part of the file contains the mdb support for dcmds:
29  *	::memseg_list
30  *	::page_num2pp
31  * and walkers for:
32  *	memseg - a memseg list walker for ::memseg_list
33  *
34  */
35 
36 #include <sys/types.h>
37 #include <sys/machparam.h>
38 #include <sys/controlregs.h>
39 #include <sys/mach_mmu.h>
40 #ifdef __xpv
41 #include <sys/hypervisor.h>
42 #endif
43 #include <vm/as.h>
44 
45 #include <mdb/mdb_modapi.h>
46 #include <mdb/mdb_target.h>
47 
48 #include <vm/page.h>
49 #include <vm/hat_i86.h>
50 
51 struct pfn2pp {
52 	pfn_t pfn;
53 	page_t *pp;
54 };
55 
56 static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *);
57 static void init_mmu(void);
58 
59 int
60 platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
61 {
62 	if (asp == NULL)
63 		return (DCMD_ERR);
64 
65 	init_mmu();
66 
67 	if (mmu.num_level == 0)
68 		return (DCMD_ERR);
69 
70 	return (do_va2pa(addr, asp, 0, pap, NULL));
71 }
72 
73 
74 /*ARGSUSED*/
75 int
76 page_num2pp_cb(uintptr_t addr, void *ignored, uintptr_t *data)
77 {
78 	struct memseg ms, *msp = &ms;
79 	struct pfn2pp *p = (struct pfn2pp *)data;
80 
81 	if (mdb_vread(msp, sizeof (struct memseg), addr) == -1) {
82 		mdb_warn("can't read memseg at %#lx", addr);
83 		return (DCMD_ERR);
84 	}
85 
86 	if (p->pfn >= msp->pages_base && p->pfn < msp->pages_end) {
87 		p->pp = msp->pages + (p->pfn - msp->pages_base);
88 		return (WALK_DONE);
89 	}
90 
91 	return (WALK_NEXT);
92 }
93 
94 /*
95  * ::page_num2pp dcmd
96  */
97 /*ARGSUSED*/
98 int
99 page_num2pp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
100 {
101 	struct pfn2pp pfn2pp;
102 	page_t page;
103 
104 	if ((flags & DCMD_ADDRSPEC) == 0) {
105 		mdb_warn("page frame number missing\n");
106 			return (DCMD_USAGE);
107 	}
108 
109 	pfn2pp.pfn = (pfn_t)addr;
110 	pfn2pp.pp = NULL;
111 
112 	if (mdb_walk("memseg", (mdb_walk_cb_t)page_num2pp_cb,
113 	    (void *)&pfn2pp) == -1) {
114 		mdb_warn("can't walk memseg");
115 		return (DCMD_ERR);
116 	}
117 
118 	if (pfn2pp.pp == NULL)
119 		return (DCMD_ERR);
120 
121 	mdb_printf("%x has page at %p\n", pfn2pp.pfn, pfn2pp.pp);
122 
123 	if (mdb_vread(&page, sizeof (page_t),
124 	    (uintptr_t)pfn2pp.pp) == -1) {
125 		mdb_warn("can't read page at %p", &page);
126 		return (DCMD_ERR);
127 	}
128 
129 	if (page.p_pagenum != pfn2pp.pfn) {
130 		mdb_warn("WARNING! Found page structure contains "
131 		    "different pagenumber %x\n", page.p_pagenum);
132 	}
133 
134 	return (DCMD_OK);
135 }
136 
137 
138 /*
139  * ::memseg_list dcmd and walker to implement it.
140  */
141 /*ARGSUSED*/
142 int
143 memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
144 {
145 	struct memseg ms;
146 
147 	if (!(flags & DCMD_ADDRSPEC)) {
148 		if (mdb_pwalk_dcmd("memseg", "memseg_list",
149 		    0, NULL, 0) == -1) {
150 			mdb_warn("can't walk memseg");
151 			return (DCMD_ERR);
152 		}
153 		return (DCMD_OK);
154 	}
155 
156 	if (DCMD_HDRSPEC(flags))
157 		mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
158 		    "PAGES", "EPAGES", "BASE", "END");
159 
160 	if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
161 		mdb_warn("can't read memseg at %#lx", addr);
162 		return (DCMD_ERR);
163 	}
164 
165 	mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr,
166 	    ms.pages, ms.epages, ms.pages_base, ms.pages_end);
167 
168 	return (DCMD_OK);
169 }
170 
171 /*
172  * walk the memseg structures
173  */
174 int
175 memseg_walk_init(mdb_walk_state_t *wsp)
176 {
177 	if (wsp->walk_addr != NULL) {
178 		mdb_warn("memseg only supports global walks\n");
179 		return (WALK_ERR);
180 	}
181 
182 	if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
183 		mdb_warn("symbol 'memsegs' not found");
184 		return (WALK_ERR);
185 	}
186 
187 	wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
188 	return (WALK_NEXT);
189 
190 }
191 
192 int
193 memseg_walk_step(mdb_walk_state_t *wsp)
194 {
195 	int status;
196 
197 	if (wsp->walk_addr == 0) {
198 		return (WALK_DONE);
199 	}
200 
201 	if (mdb_vread(wsp->walk_data, sizeof (struct memseg),
202 	    wsp->walk_addr) == -1) {
203 		mdb_warn("failed to read struct memseg at %p", wsp->walk_addr);
204 		return (WALK_DONE);
205 	}
206 
207 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
208 	    wsp->walk_cbdata);
209 
210 	wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
211 
212 	return (status);
213 }
214 
215 void
216 memseg_walk_fini(mdb_walk_state_t *wsp)
217 {
218 	mdb_free(wsp->walk_data, sizeof (struct memseg));
219 }
220 
221 /*
222  * Now HAT related dcmds.
223  */
224 
225 static struct hat *khat;		/* value of kas.a_hat */
226 struct hat_mmu_info mmu;
227 uintptr_t kernelbase;
228 
229 /*
230  * stuff for i86xpv images
231  */
232 static int is_xpv;
233 static uintptr_t mfn_list_addr; /* kernel MFN list address */
234 uintptr_t xen_virt_start; /* address of mfn_to_pfn[] table */
235 ulong_t mfn_count;	/* number of pfn's in the MFN list */
236 pfn_t *mfn_list;	/* local MFN list copy */
237 
238 /*
239  * read mmu parameters from kernel
240  */
241 static void
242 init_mmu(void)
243 {
244 	struct as kas;
245 
246 	if (mmu.num_level != 0)
247 		return;
248 
249 	if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1)
250 		mdb_warn("Can't use HAT information before mmu_init()\n");
251 	if (mdb_readsym(&kas, sizeof (kas), "kas") == -1)
252 		mdb_warn("Couldn't find kas - kernel's struct as\n");
253 	if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1)
254 		mdb_warn("Couldn't find kernelbase\n");
255 	khat = kas.a_hat;
256 
257 	/*
258 	 * Is this a paravirtualized domain image?
259 	 */
260 	if (mdb_readsym(&mfn_list_addr, sizeof (mfn_list_addr),
261 	    "mfn_list") == -1 ||
262 	    mdb_readsym(&xen_virt_start, sizeof (xen_virt_start),
263 	    "xen_virt_start") == -1 ||
264 	    mdb_readsym(&mfn_count, sizeof (mfn_count), "mfn_count") == -1) {
265 		mfn_list_addr = NULL;
266 	}
267 
268 	is_xpv = mfn_list_addr != NULL;
269 
270 #ifndef _KMDB
271 	/*
272 	 * recreate the local mfn_list
273 	 */
274 	if (is_xpv) {
275 		size_t sz = mfn_count * sizeof (pfn_t);
276 		mfn_list = mdb_zalloc(sz, UM_SLEEP);
277 
278 		if (mdb_vread(mfn_list, sz, (uintptr_t)mfn_list_addr) == -1) {
279 			mdb_warn("Failed to read MFN list\n");
280 			mdb_free(mfn_list, sz);
281 			mfn_list = NULL;
282 		}
283 	}
284 #endif
285 }
286 
287 void
288 free_mmu(void)
289 {
290 #ifdef __xpv
291 	if (mfn_list != NULL)
292 		mdb_free(mfn_list, mfn_count * sizeof (mfn_t));
293 #endif
294 }
295 
296 #ifdef __xpv
297 
298 #ifdef _KMDB
299 
300 /*
301  * Convert between MFNs and PFNs.  Since we're in kmdb we can go directly
302  * through the machine to phys mapping and the MFN list.
303  */
304 
305 pfn_t
306 mdb_mfn_to_pfn(mfn_t mfn)
307 {
308 	pfn_t pfn;
309 	mfn_t tmp;
310 	pfn_t *pfn_list;
311 
312 	if (mfn_list_addr == NULL)
313 		return (-(pfn_t)1);
314 
315 	pfn_list = (pfn_t *)xen_virt_start;
316 	if (mdb_vread(&pfn, sizeof (pfn), (uintptr_t)(pfn_list + mfn)) == -1)
317 		return (-(pfn_t)1);
318 
319 	if (mdb_vread(&tmp, sizeof (tmp),
320 	    (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
321 		return (-(pfn_t)1);
322 
323 	if (pfn >= mfn_count || tmp != mfn)
324 		return (-(pfn_t)1);
325 
326 	return (pfn);
327 }
328 
329 mfn_t
330 mdb_pfn_to_mfn(pfn_t pfn)
331 {
332 	mfn_t mfn;
333 
334 	init_mmu();
335 
336 	if (mfn_list_addr == NULL || pfn >= mfn_count)
337 		return (-(mfn_t)1);
338 
339 	if (mdb_vread(&mfn, sizeof (mfn),
340 	    (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
341 		return (-(mfn_t)1);
342 
343 	return (mfn);
344 }
345 
346 #else /* _KMDB */
347 
348 /*
349  * Convert between MFNs and PFNs.  Since a crash dump doesn't include the
350  * MFN->PFN translation table (it's part of the hypervisor, not our image)
351  * we do the MFN->PFN translation by searching the PFN->MFN (mfn_list)
352  * table, if it's there.
353  */
354 
355 pfn_t
356 mdb_mfn_to_pfn(mfn_t mfn)
357 {
358 	pfn_t pfn;
359 
360 	init_mmu();
361 
362 	if (mfn_list == NULL)
363 		return (-(pfn_t)1);
364 
365 	for (pfn = 0; pfn < mfn_count; ++pfn) {
366 		if (mfn_list[pfn] != mfn)
367 			continue;
368 		return (pfn);
369 	}
370 
371 	return (-(pfn_t)1);
372 }
373 
374 mfn_t
375 mdb_pfn_to_mfn(pfn_t pfn)
376 {
377 	init_mmu();
378 
379 	if (mfn_list == NULL || pfn >= mfn_count)
380 		return (-(mfn_t)1);
381 
382 	return (mfn_list[pfn]);
383 }
384 
385 #endif /* _KMDB */
386 
387 static paddr_t
388 mdb_ma_to_pa(uint64_t ma)
389 {
390 	pfn_t pfn = mdb_mfn_to_pfn(mmu_btop(ma));
391 	if (pfn == -(pfn_t)1)
392 		return (-(paddr_t)1);
393 
394 	return (mmu_ptob((paddr_t)pfn) | (ma & (MMU_PAGESIZE - 1)));
395 }
396 
397 #else /* __xpv */
398 
399 #define	mdb_ma_to_pa(ma) (ma)
400 #define	mdb_mfn_to_pfn(mfn) (mfn)
401 #define	mdb_pfn_to_mfn(pfn) (pfn)
402 
403 #endif /* __xpv */
404 
405 /*
406  * ::mfntopfn dcmd translates hypervisor machine page number
407  * to physical page number
408  */
409 /*ARGSUSED*/
410 int
411 mfntopfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
412 {
413 	pfn_t pfn;
414 
415 	if ((flags & DCMD_ADDRSPEC) == 0) {
416 		mdb_warn("MFN missing\n");
417 		return (DCMD_USAGE);
418 	}
419 
420 	if ((pfn = mdb_mfn_to_pfn((pfn_t)addr)) == -(pfn_t)1) {
421 		mdb_warn("Invalid mfn %lr\n", (pfn_t)addr);
422 		return (DCMD_ERR);
423 	}
424 
425 	mdb_printf("%lr\n", pfn);
426 
427 	return (DCMD_OK);
428 }
429 
430 /*
431  * ::pfntomfn dcmd translates physical page number to
432  * hypervisor machine page number
433  */
434 /*ARGSUSED*/
435 int
436 pfntomfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
437 {
438 	pfn_t mfn;
439 
440 	if ((flags & DCMD_ADDRSPEC) == 0) {
441 		mdb_warn("PFN missing\n");
442 		return (DCMD_USAGE);
443 	}
444 
445 	if ((mfn = mdb_pfn_to_mfn((pfn_t)addr)) == -(pfn_t)1) {
446 		mdb_warn("Invalid pfn %lr\n", (pfn_t)addr);
447 		return (DCMD_ABORT);
448 	}
449 
450 	mdb_printf("%lr\n", mfn);
451 
452 	if (flags & DCMD_LOOP)
453 		mdb_set_dot(addr + 1);
454 	return (DCMD_OK);
455 }
456 
457 static pfn_t
458 pte2mfn(x86pte_t pte, uint_t level)
459 {
460 	pfn_t mfn;
461 	if (level > 0 && (pte & PT_PAGESIZE))
462 		mfn = mmu_btop(pte & PT_PADDR_LGPG);
463 	else
464 		mfn = mmu_btop(pte & PT_PADDR);
465 	return (mfn);
466 }
467 
468 /*
469  * Print a PTE in more human friendly way. The PTE is assumed to be in
470  * a level 0 page table, unless -l specifies another level.
471  *
472  * The PTE value can be specified as the -p option, since on a 32 bit kernel
473  * with PAE running it's larger than a uintptr_t.
474  */
475 static int
476 do_pte_dcmd(int level, uint64_t pte)
477 {
478 	static char *attr[] = {
479 	    "wrback", "wrthru", "uncached", "uncached",
480 	    "wrback", "wrthru", "wrcombine", "uncached"};
481 	int pat_index = 0;
482 	pfn_t mfn;
483 
484 	mdb_printf("pte=%llr: ", pte);
485 	if (PTE_GET(pte, mmu.pt_nx))
486 		mdb_printf("noexec ");
487 
488 	mfn = pte2mfn(pte, level);
489 	mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn);
490 
491 	if (PTE_GET(pte, PT_NOCONSIST))
492 		mdb_printf("noconsist ");
493 
494 	if (PTE_GET(pte, PT_NOSYNC))
495 		mdb_printf("nosync ");
496 
497 	if (PTE_GET(pte, mmu.pt_global))
498 		mdb_printf("global ");
499 
500 	if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
501 		mdb_printf("largepage ");
502 
503 	if (level > 0 && PTE_GET(pte, PT_MOD))
504 		mdb_printf("mod ");
505 
506 	if (level > 0 && PTE_GET(pte, PT_REF))
507 		mdb_printf("ref ");
508 
509 	if (PTE_GET(pte, PT_USER))
510 		mdb_printf("user ");
511 
512 	if (PTE_GET(pte, PT_WRITABLE))
513 		mdb_printf("write ");
514 
515 	/*
516 	 * Report non-standard cacheability
517 	 */
518 	pat_index = 0;
519 	if (level > 0) {
520 		if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE))
521 			pat_index += 4;
522 	} else {
523 		if (PTE_GET(pte, PT_PAT_4K))
524 			pat_index += 4;
525 	}
526 
527 	if (PTE_GET(pte, PT_NOCACHE))
528 		pat_index += 2;
529 
530 	if (PTE_GET(pte, PT_WRITETHRU))
531 		pat_index += 1;
532 
533 	if (pat_index != 0)
534 		mdb_printf("%s", attr[pat_index]);
535 
536 	if (PTE_GET(pte, PT_VALID) == 0)
537 		mdb_printf(" !VALID ");
538 
539 	mdb_printf("\n");
540 	return (DCMD_OK);
541 }
542 
543 /*
544  * Print a PTE in more human friendly way. The PTE is assumed to be in
545  * a level 0 page table, unless -l specifies another level.
546  *
547  * The PTE value can be specified as the -p option, since on a 32 bit kernel
548  * with PAE running it's larger than a uintptr_t.
549  */
550 /*ARGSUSED*/
551 int
552 pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
553 {
554 	int level = 0;
555 	uint64_t pte = 0;
556 	char *level_str = NULL;
557 	char *pte_str = NULL;
558 
559 	init_mmu();
560 
561 	if (mmu.num_level == 0)
562 		return (DCMD_ERR);
563 
564 	if (mdb_getopts(argc, argv,
565 	    'p', MDB_OPT_STR, &pte_str,
566 	    'l', MDB_OPT_STR, &level_str) != argc)
567 		return (DCMD_USAGE);
568 
569 	/*
570 	 * parse the PTE to decode, if it's 0, we don't do anything
571 	 */
572 	if (pte_str != NULL) {
573 		pte = mdb_strtoull(pte_str);
574 	} else {
575 		if ((flags & DCMD_ADDRSPEC) == 0)
576 			return (DCMD_USAGE);
577 		pte = addr;
578 	}
579 	if (pte == 0)
580 		return (DCMD_OK);
581 
582 	/*
583 	 * parse the level if supplied
584 	 */
585 	if (level_str != NULL) {
586 		level = mdb_strtoull(level_str);
587 		if (level < 0 || level > mmu.max_level)
588 			return (DCMD_ERR);
589 	}
590 
591 	return (do_pte_dcmd(level, pte));
592 }
593 
594 static size_t
595 va2entry(htable_t *htable, uintptr_t addr)
596 {
597 	size_t entry = (addr - htable->ht_vaddr);
598 
599 	entry >>= mmu.level_shift[htable->ht_level];
600 	return (entry & HTABLE_NUM_PTES(htable) - 1);
601 }
602 
603 static x86pte_t
604 get_pte(hat_t *hat, htable_t *htable, uintptr_t addr)
605 {
606 	x86pte_t buf;
607 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
608 	size_t len;
609 
610 	if (htable->ht_flags & HTABLE_VLP) {
611 		uintptr_t ptr = (uintptr_t)hat->hat_vlp_ptes;
612 		ptr += va2entry(htable, addr) << mmu.pte_size_shift;
613 		len = mdb_vread(&buf, mmu.pte_size, ptr);
614 	} else {
615 		paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn);
616 		paddr += va2entry(htable, addr) << mmu.pte_size_shift;
617 		len = mdb_pread(&buf, mmu.pte_size, paddr);
618 	}
619 
620 	if (len != mmu.pte_size)
621 		return (0);
622 
623 	if (mmu.pte_size == sizeof (x86pte_t))
624 		return (buf);
625 	return (*pte32);
626 }
627 
628 static int
629 do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap,
630     pfn_t *mfnp)
631 {
632 	struct as as;
633 	struct hat *hatp;
634 	struct hat hat;
635 	htable_t *ht;
636 	htable_t htable;
637 	uintptr_t base;
638 	int h;
639 	int level;
640 	int found = 0;
641 	x86pte_t pte;
642 	physaddr_t paddr;
643 
644 	if (asp != NULL) {
645 		if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
646 			mdb_warn("Couldn't read struct as\n");
647 			return (DCMD_ERR);
648 		}
649 		hatp = as.a_hat;
650 	} else {
651 		hatp = khat;
652 	}
653 
654 	/*
655 	 * read the hat and its hash table
656 	 */
657 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
658 		mdb_warn("Couldn't read struct hat\n");
659 		return (DCMD_ERR);
660 	}
661 
662 	/*
663 	 * read the htable hashtable
664 	 */
665 	for (level = 0; level <= mmu.max_level; ++level) {
666 		if (level == TOP_LEVEL(&hat))
667 			base = 0;
668 		else
669 			base = addr & mmu.level_mask[level + 1];
670 
671 		for (h = 0; h < hat.hat_num_hash; ++h) {
672 			if (mdb_vread(&ht, sizeof (htable_t *),
673 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
674 				mdb_warn("Couldn't read htable\n");
675 				return (DCMD_ERR);
676 			}
677 			for (; ht != NULL; ht = htable.ht_next) {
678 				if (mdb_vread(&htable, sizeof (htable_t),
679 				    (uintptr_t)ht) == -1) {
680 					mdb_warn("Couldn't read htable\n");
681 					return (DCMD_ERR);
682 				}
683 
684 				if (htable.ht_vaddr != base ||
685 				    htable.ht_level != level)
686 					continue;
687 
688 				pte = get_pte(&hat, &htable, addr);
689 
690 				if (print_level) {
691 					mdb_printf("\tlevel=%d htable=%p "
692 					    "pte=%llr\n", level, ht, pte);
693 				}
694 
695 				if (!PTE_ISVALID(pte)) {
696 					mdb_printf("Address %p is unmapped.\n",
697 					    addr);
698 					return (DCMD_ERR);
699 				}
700 
701 				if (found)
702 					continue;
703 
704 				if (PTE_IS_LGPG(pte, level))
705 					paddr = mdb_ma_to_pa(pte &
706 					    PT_PADDR_LGPG);
707 				else
708 					paddr = mdb_ma_to_pa(pte & PT_PADDR);
709 				paddr += addr & mmu.level_offset[level];
710 				if (pap != NULL)
711 					*pap = paddr;
712 				if (mfnp != NULL)
713 					*mfnp = pte2mfn(pte, level);
714 				found = 1;
715 			}
716 		}
717 	}
718 
719 done:
720 	if (!found)
721 		return (DCMD_ERR);
722 	return (DCMD_OK);
723 }
724 
725 int
726 va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
727 {
728 	uintptr_t addrspace;
729 	char *addrspace_str = NULL;
730 	int piped = flags & DCMD_PIPE_OUT;
731 	pfn_t pfn;
732 	pfn_t mfn;
733 	int rc;
734 
735 	init_mmu();
736 
737 	if (mmu.num_level == 0)
738 		return (DCMD_ERR);
739 
740 	if (mdb_getopts(argc, argv,
741 	    'a', MDB_OPT_STR, &addrspace_str) != argc)
742 		return (DCMD_USAGE);
743 
744 	if ((flags & DCMD_ADDRSPEC) == 0)
745 		return (DCMD_USAGE);
746 
747 	/*
748 	 * parse the address space
749 	 */
750 	if (addrspace_str != NULL)
751 		addrspace = mdb_strtoull(addrspace_str);
752 	else
753 		addrspace = 0;
754 
755 	rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn);
756 
757 	if (rc != DCMD_OK)
758 		return (rc);
759 
760 	if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) {
761 		mdb_warn("Invalid mfn %lr\n", mfn);
762 		return (DCMD_ERR);
763 	}
764 
765 	if (piped) {
766 		mdb_printf("0x%lr\n", pfn);
767 		return (DCMD_OK);
768 	}
769 
770 	mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn);
771 
772 	if (is_xpv)
773 		mdb_printf(" (mfn 0x%lr)", mfn);
774 
775 	mdb_printf("\n");
776 
777 	return (DCMD_OK);
778 }
779 
780 /*
781  * Report all hat's that either use PFN as a page table or that map the page.
782  */
783 static int
784 do_report_maps(pfn_t pfn)
785 {
786 	struct hat *hatp;
787 	struct hat hat;
788 	htable_t *ht;
789 	htable_t htable;
790 	uintptr_t base;
791 	int h;
792 	int level;
793 	int entry;
794 	x86pte_t pte;
795 	x86pte_t buf;
796 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
797 	physaddr_t paddr;
798 	size_t len;
799 
800 	/*
801 	 * The hats are kept in a list with khat at the head.
802 	 */
803 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
804 		/*
805 		 * read the hat and its hash table
806 		 */
807 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
808 			mdb_warn("Couldn't read struct hat\n");
809 			return (DCMD_ERR);
810 		}
811 
812 		/*
813 		 * read the htable hashtable
814 		 */
815 		paddr = 0;
816 		for (h = 0; h < hat.hat_num_hash; ++h) {
817 			if (mdb_vread(&ht, sizeof (htable_t *),
818 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
819 				mdb_warn("Couldn't read htable\n");
820 				return (DCMD_ERR);
821 			}
822 			for (; ht != NULL; ht = htable.ht_next) {
823 				if (mdb_vread(&htable, sizeof (htable_t),
824 				    (uintptr_t)ht) == -1) {
825 					mdb_warn("Couldn't read htable\n");
826 					return (DCMD_ERR);
827 				}
828 
829 				/*
830 				 * only report kernel addresses once
831 				 */
832 				if (hatp != khat &&
833 				    htable.ht_vaddr >= kernelbase)
834 					continue;
835 
836 				/*
837 				 * Is the PFN a pagetable itself?
838 				 */
839 				if (htable.ht_pfn == pfn) {
840 					mdb_printf("Pagetable for "
841 					    "hat=%p htable=%p\n", hatp, ht);
842 					continue;
843 				}
844 
845 				/*
846 				 * otherwise, examine page mappings
847 				 */
848 				level = htable.ht_level;
849 				if (level > mmu.max_page_level)
850 					continue;
851 				paddr = mmu_ptob((physaddr_t)htable.ht_pfn);
852 				for (entry = 0;
853 				    entry < HTABLE_NUM_PTES(&htable);
854 				    ++entry) {
855 
856 					base = htable.ht_vaddr + entry *
857 					    mmu.level_size[level];
858 
859 					/*
860 					 * only report kernel addresses once
861 					 */
862 					if (hatp != khat &&
863 					    base >= kernelbase)
864 						continue;
865 
866 					len = mdb_pread(&buf, mmu.pte_size,
867 					    paddr + entry * mmu.pte_size);
868 					if (len != mmu.pte_size)
869 						return (DCMD_ERR);
870 					if (mmu.pte_size == sizeof (x86pte_t))
871 						pte = buf;
872 					else
873 						pte = *pte32;
874 
875 					if ((pte & PT_VALID) == 0)
876 						continue;
877 					if (level == 0 || !(pte & PT_PAGESIZE))
878 						pte &= PT_PADDR;
879 					else
880 						pte &= PT_PADDR_LGPG;
881 					if (mmu_btop(mdb_ma_to_pa(pte)) != pfn)
882 						continue;
883 					mdb_printf("hat=%p maps addr=%p\n",
884 					    hatp, (caddr_t)base);
885 				}
886 			}
887 		}
888 	}
889 
890 done:
891 	return (DCMD_OK);
892 }
893 
894 /*
895  * given a PFN as its address argument, prints out the uses of it
896  */
897 /*ARGSUSED*/
898 int
899 report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
900 {
901 	pfn_t pfn;
902 	uint_t mflag = 0;
903 
904 	init_mmu();
905 
906 	if (mmu.num_level == 0)
907 		return (DCMD_ERR);
908 
909 	if ((flags & DCMD_ADDRSPEC) == 0)
910 		return (DCMD_USAGE);
911 
912 	if (mdb_getopts(argc, argv,
913 	    'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
914 		return (DCMD_USAGE);
915 
916 	pfn = (pfn_t)addr;
917 	if (mflag)
918 		pfn = mdb_mfn_to_pfn(pfn);
919 
920 	return (do_report_maps(pfn));
921 }
922 
923 static int
924 do_ptable_dcmd(pfn_t pfn)
925 {
926 	struct hat *hatp;
927 	struct hat hat;
928 	htable_t *ht;
929 	htable_t htable;
930 	uintptr_t base;
931 	int h;
932 	int level;
933 	int entry;
934 	uintptr_t pagesize;
935 	x86pte_t pte;
936 	x86pte_t buf;
937 	x86pte32_t *pte32 = (x86pte32_t *)&buf;
938 	physaddr_t paddr;
939 	size_t len;
940 
941 	/*
942 	 * The hats are kept in a list with khat at the head.
943 	 */
944 	for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
945 		/*
946 		 * read the hat and its hash table
947 		 */
948 		if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
949 			mdb_warn("Couldn't read struct hat\n");
950 			return (DCMD_ERR);
951 		}
952 
953 		/*
954 		 * read the htable hashtable
955 		 */
956 		paddr = 0;
957 		for (h = 0; h < hat.hat_num_hash; ++h) {
958 			if (mdb_vread(&ht, sizeof (htable_t *),
959 			    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
960 				mdb_warn("Couldn't read htable\n");
961 				return (DCMD_ERR);
962 			}
963 			for (; ht != NULL; ht = htable.ht_next) {
964 				if (mdb_vread(&htable, sizeof (htable_t),
965 				    (uintptr_t)ht) == -1) {
966 					mdb_warn("Couldn't read htable\n");
967 					return (DCMD_ERR);
968 				}
969 
970 				/*
971 				 * Is this the PFN for this htable
972 				 */
973 				if (htable.ht_pfn == pfn)
974 					goto found_it;
975 			}
976 		}
977 	}
978 
979 found_it:
980 	if (htable.ht_pfn == pfn) {
981 		mdb_printf("htable=%p\n", ht);
982 		level = htable.ht_level;
983 		base = htable.ht_vaddr;
984 		pagesize = mmu.level_size[level];
985 	} else {
986 		mdb_printf("Unknown pagetable - assuming level/addr 0");
987 		level = 0;	/* assume level == 0 for PFN */
988 		base = 0;
989 		pagesize = MMU_PAGESIZE;
990 	}
991 
992 	paddr = mmu_ptob((physaddr_t)pfn);
993 	for (entry = 0; entry < mmu.ptes_per_table; ++entry) {
994 		len = mdb_pread(&buf, mmu.pte_size,
995 		    paddr + entry * mmu.pte_size);
996 		if (len != mmu.pte_size)
997 			return (DCMD_ERR);
998 		if (mmu.pte_size == sizeof (x86pte_t))
999 			pte = buf;
1000 		else
1001 			pte = *pte32;
1002 
1003 		if (pte == 0)
1004 			continue;
1005 
1006 		mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize);
1007 		do_pte_dcmd(level, pte);
1008 	}
1009 
1010 done:
1011 	return (DCMD_OK);
1012 }
1013 
1014 /*
1015  * Dump the page table at the given PFN
1016  */
1017 /*ARGSUSED*/
1018 int
1019 ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1020 {
1021 	pfn_t pfn;
1022 	uint_t mflag = 0;
1023 
1024 	init_mmu();
1025 
1026 	if (mmu.num_level == 0)
1027 		return (DCMD_ERR);
1028 
1029 	if ((flags & DCMD_ADDRSPEC) == 0)
1030 		return (DCMD_USAGE);
1031 
1032 	if (mdb_getopts(argc, argv,
1033 	    'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
1034 		return (DCMD_USAGE);
1035 
1036 	pfn = (pfn_t)addr;
1037 	if (mflag)
1038 		pfn = mdb_mfn_to_pfn(pfn);
1039 
1040 	return (do_ptable_dcmd(pfn));
1041 }
1042 
1043 static int
1044 do_htables_dcmd(hat_t *hatp)
1045 {
1046 	struct hat hat;
1047 	htable_t *ht;
1048 	htable_t htable;
1049 	int h;
1050 
1051 	/*
1052 	 * read the hat and its hash table
1053 	 */
1054 	if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
1055 		mdb_warn("Couldn't read struct hat\n");
1056 		return (DCMD_ERR);
1057 	}
1058 
1059 	/*
1060 	 * read the htable hashtable
1061 	 */
1062 	for (h = 0; h < hat.hat_num_hash; ++h) {
1063 		if (mdb_vread(&ht, sizeof (htable_t *),
1064 		    (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
1065 			mdb_warn("Couldn't read htable ptr\\n");
1066 			return (DCMD_ERR);
1067 		}
1068 		for (; ht != NULL; ht = htable.ht_next) {
1069 			mdb_printf("%p\n", ht);
1070 			if (mdb_vread(&htable, sizeof (htable_t),
1071 			    (uintptr_t)ht) == -1) {
1072 				mdb_warn("Couldn't read htable\n");
1073 				return (DCMD_ERR);
1074 			}
1075 		}
1076 	}
1077 	return (DCMD_OK);
1078 }
1079 
1080 /*
1081  * Dump the htables for the given hat
1082  */
1083 /*ARGSUSED*/
1084 int
1085 htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1086 {
1087 	hat_t *hat;
1088 
1089 	init_mmu();
1090 
1091 	if (mmu.num_level == 0)
1092 		return (DCMD_ERR);
1093 
1094 	if ((flags & DCMD_ADDRSPEC) == 0)
1095 		return (DCMD_USAGE);
1096 
1097 	hat = (hat_t *)addr;
1098 
1099 	return (do_htables_dcmd(hat));
1100 }
1101