8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / mdb / i86pc / modules / unix / i86mmu.c
blobef89d2331235614268c23344bc81fcfbfb3428e9
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * This part of the file contains the mdb support for dcmds:
28 * ::memseg_list
29 * and walkers for:
30 * memseg - a memseg list walker for ::memseg_list
34 #include <sys/types.h>
35 #include <sys/machparam.h>
36 #include <sys/controlregs.h>
37 #include <sys/mach_mmu.h>
38 #ifdef __xpv
39 #include <sys/hypervisor.h>
40 #endif
41 #include <vm/as.h>
43 #include <mdb/mdb_modapi.h>
44 #include <mdb/mdb_target.h>
46 #include <vm/page.h>
47 #include <vm/hat_i86.h>
49 struct pfn2pp {
50 pfn_t pfn;
51 page_t *pp;
54 static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *);
55 static void init_mmu(void);
57 int
58 platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
60 if (asp == NULL)
61 return (DCMD_ERR);
63 init_mmu();
65 if (mmu.num_level == 0)
66 return (DCMD_ERR);
68 return (do_va2pa(addr, asp, 0, pap, NULL));
72 * ::memseg_list dcmd and walker to implement it.
74 /*ARGSUSED*/
75 int
76 memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
78 struct memseg ms;
80 if (!(flags & DCMD_ADDRSPEC)) {
81 if (mdb_pwalk_dcmd("memseg", "memseg_list",
82 0, NULL, 0) == -1) {
83 mdb_warn("can't walk memseg");
84 return (DCMD_ERR);
86 return (DCMD_OK);
89 if (DCMD_HDRSPEC(flags))
90 mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
91 "PAGES", "EPAGES", "BASE", "END");
93 if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
94 mdb_warn("can't read memseg at %#lx", addr);
95 return (DCMD_ERR);
98 mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr,
99 ms.pages, ms.epages, ms.pages_base, ms.pages_end);
101 return (DCMD_OK);
105 * walk the memseg structures
108 memseg_walk_init(mdb_walk_state_t *wsp)
110 if (wsp->walk_addr != NULL) {
111 mdb_warn("memseg only supports global walks\n");
112 return (WALK_ERR);
115 if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
116 mdb_warn("symbol 'memsegs' not found");
117 return (WALK_ERR);
120 wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
121 return (WALK_NEXT);
126 memseg_walk_step(mdb_walk_state_t *wsp)
128 int status;
130 if (wsp->walk_addr == 0) {
131 return (WALK_DONE);
134 if (mdb_vread(wsp->walk_data, sizeof (struct memseg),
135 wsp->walk_addr) == -1) {
136 mdb_warn("failed to read struct memseg at %p", wsp->walk_addr);
137 return (WALK_DONE);
140 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
141 wsp->walk_cbdata);
143 wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
145 return (status);
148 void
149 memseg_walk_fini(mdb_walk_state_t *wsp)
151 mdb_free(wsp->walk_data, sizeof (struct memseg));
155 * Now HAT related dcmds.
158 static struct hat *khat; /* value of kas.a_hat */
159 struct hat_mmu_info mmu;
160 uintptr_t kernelbase;
163 * stuff for i86xpv images
165 static int is_xpv;
166 static uintptr_t mfn_list_addr; /* kernel MFN list address */
167 uintptr_t xen_virt_start; /* address of mfn_to_pfn[] table */
168 ulong_t mfn_count; /* number of pfn's in the MFN list */
169 pfn_t *mfn_list; /* local MFN list copy */
172 * read mmu parameters from kernel
174 static void
175 init_mmu(void)
177 struct as kas;
179 if (mmu.num_level != 0)
180 return;
182 if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1)
183 mdb_warn("Can't use HAT information before mmu_init()\n");
184 if (mdb_readsym(&kas, sizeof (kas), "kas") == -1)
185 mdb_warn("Couldn't find kas - kernel's struct as\n");
186 if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1)
187 mdb_warn("Couldn't find kernelbase\n");
188 khat = kas.a_hat;
191 * Is this a paravirtualized domain image?
193 if (mdb_readsym(&mfn_list_addr, sizeof (mfn_list_addr),
194 "mfn_list") == -1 ||
195 mdb_readsym(&xen_virt_start, sizeof (xen_virt_start),
196 "xen_virt_start") == -1 ||
197 mdb_readsym(&mfn_count, sizeof (mfn_count), "mfn_count") == -1) {
198 mfn_list_addr = NULL;
201 is_xpv = mfn_list_addr != NULL;
203 #ifndef _KMDB
205 * recreate the local mfn_list
207 if (is_xpv) {
208 size_t sz = mfn_count * sizeof (pfn_t);
209 mfn_list = mdb_zalloc(sz, UM_SLEEP);
211 if (mdb_vread(mfn_list, sz, (uintptr_t)mfn_list_addr) == -1) {
212 mdb_warn("Failed to read MFN list\n");
213 mdb_free(mfn_list, sz);
214 mfn_list = NULL;
217 #endif
220 void
221 free_mmu(void)
223 #ifdef __xpv
224 if (mfn_list != NULL)
225 mdb_free(mfn_list, mfn_count * sizeof (mfn_t));
226 #endif
229 #ifdef __xpv
231 #ifdef _KMDB
234 * Convert between MFNs and PFNs. Since we're in kmdb we can go directly
235 * through the machine to phys mapping and the MFN list.
238 pfn_t
239 mdb_mfn_to_pfn(mfn_t mfn)
241 pfn_t pfn;
242 mfn_t tmp;
243 pfn_t *pfn_list;
245 if (mfn_list_addr == NULL)
246 return (-(pfn_t)1);
248 pfn_list = (pfn_t *)xen_virt_start;
249 if (mdb_vread(&pfn, sizeof (pfn), (uintptr_t)(pfn_list + mfn)) == -1)
250 return (-(pfn_t)1);
252 if (mdb_vread(&tmp, sizeof (tmp),
253 (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
254 return (-(pfn_t)1);
256 if (pfn >= mfn_count || tmp != mfn)
257 return (-(pfn_t)1);
259 return (pfn);
262 mfn_t
263 mdb_pfn_to_mfn(pfn_t pfn)
265 mfn_t mfn;
267 init_mmu();
269 if (mfn_list_addr == NULL || pfn >= mfn_count)
270 return (-(mfn_t)1);
272 if (mdb_vread(&mfn, sizeof (mfn),
273 (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
274 return (-(mfn_t)1);
276 return (mfn);
279 #else /* _KMDB */
282 * Convert between MFNs and PFNs. Since a crash dump doesn't include the
283 * MFN->PFN translation table (it's part of the hypervisor, not our image)
284 * we do the MFN->PFN translation by searching the PFN->MFN (mfn_list)
285 * table, if it's there.
288 pfn_t
289 mdb_mfn_to_pfn(mfn_t mfn)
291 pfn_t pfn;
293 init_mmu();
295 if (mfn_list == NULL)
296 return (-(pfn_t)1);
298 for (pfn = 0; pfn < mfn_count; ++pfn) {
299 if (mfn_list[pfn] != mfn)
300 continue;
301 return (pfn);
304 return (-(pfn_t)1);
307 mfn_t
308 mdb_pfn_to_mfn(pfn_t pfn)
310 init_mmu();
312 if (mfn_list == NULL || pfn >= mfn_count)
313 return (-(mfn_t)1);
315 return (mfn_list[pfn]);
318 #endif /* _KMDB */
320 static paddr_t
321 mdb_ma_to_pa(uint64_t ma)
323 pfn_t pfn = mdb_mfn_to_pfn(mmu_btop(ma));
324 if (pfn == -(pfn_t)1)
325 return (-(paddr_t)1);
327 return (mmu_ptob((paddr_t)pfn) | (ma & (MMU_PAGESIZE - 1)));
330 #else /* __xpv */
332 #define mdb_ma_to_pa(ma) (ma)
333 #define mdb_mfn_to_pfn(mfn) (mfn)
334 #define mdb_pfn_to_mfn(pfn) (pfn)
336 #endif /* __xpv */
339 * ::mfntopfn dcmd translates hypervisor machine page number
340 * to physical page number
342 /*ARGSUSED*/
344 mfntopfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
346 pfn_t pfn;
348 if ((flags & DCMD_ADDRSPEC) == 0) {
349 mdb_warn("MFN missing\n");
350 return (DCMD_USAGE);
353 if ((pfn = mdb_mfn_to_pfn((pfn_t)addr)) == -(pfn_t)1) {
354 mdb_warn("Invalid mfn %lr\n", (pfn_t)addr);
355 return (DCMD_ERR);
358 mdb_printf("%lr\n", pfn);
360 return (DCMD_OK);
364 * ::pfntomfn dcmd translates physical page number to
365 * hypervisor machine page number
367 /*ARGSUSED*/
369 pfntomfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
371 pfn_t mfn;
373 if ((flags & DCMD_ADDRSPEC) == 0) {
374 mdb_warn("PFN missing\n");
375 return (DCMD_USAGE);
378 if ((mfn = mdb_pfn_to_mfn((pfn_t)addr)) == -(pfn_t)1) {
379 mdb_warn("Invalid pfn %lr\n", (pfn_t)addr);
380 return (DCMD_ABORT);
383 mdb_printf("%lr\n", mfn);
385 if (flags & DCMD_LOOP)
386 mdb_set_dot(addr + 1);
387 return (DCMD_OK);
390 static pfn_t
391 pte2mfn(x86pte_t pte, uint_t level)
393 pfn_t mfn;
394 if (level > 0 && (pte & PT_PAGESIZE))
395 mfn = mmu_btop(pte & PT_PADDR_LGPG);
396 else
397 mfn = mmu_btop(pte & PT_PADDR);
398 return (mfn);
402 * Print a PTE in more human friendly way. The PTE is assumed to be in
403 * a level 0 page table, unless -l specifies another level.
405 * The PTE value can be specified as the -p option, since on a 32 bit kernel
406 * with PAE running it's larger than a uintptr_t.
408 static int
409 do_pte_dcmd(int level, uint64_t pte)
411 static char *attr[] = {
412 "wrback", "wrthru", "uncached", "uncached",
413 "wrback", "wrthru", "wrcombine", "uncached"};
414 int pat_index = 0;
415 pfn_t mfn;
417 mdb_printf("pte=%llr: ", pte);
418 if (PTE_GET(pte, mmu.pt_nx))
419 mdb_printf("noexec ");
421 mfn = pte2mfn(pte, level);
422 mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn);
424 if (PTE_GET(pte, PT_NOCONSIST))
425 mdb_printf("noconsist ");
427 if (PTE_GET(pte, PT_NOSYNC))
428 mdb_printf("nosync ");
430 if (PTE_GET(pte, mmu.pt_global))
431 mdb_printf("global ");
433 if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
434 mdb_printf("largepage ");
436 if (level > 0 && PTE_GET(pte, PT_MOD))
437 mdb_printf("mod ");
439 if (level > 0 && PTE_GET(pte, PT_REF))
440 mdb_printf("ref ");
442 if (PTE_GET(pte, PT_USER))
443 mdb_printf("user ");
445 if (PTE_GET(pte, PT_WRITABLE))
446 mdb_printf("write ");
449 * Report non-standard cacheability
451 pat_index = 0;
452 if (level > 0) {
453 if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE))
454 pat_index += 4;
455 } else {
456 if (PTE_GET(pte, PT_PAT_4K))
457 pat_index += 4;
460 if (PTE_GET(pte, PT_NOCACHE))
461 pat_index += 2;
463 if (PTE_GET(pte, PT_WRITETHRU))
464 pat_index += 1;
466 if (pat_index != 0)
467 mdb_printf("%s", attr[pat_index]);
469 if (PTE_GET(pte, PT_VALID) == 0)
470 mdb_printf(" !VALID ");
472 mdb_printf("\n");
473 return (DCMD_OK);
477 * Print a PTE in more human friendly way. The PTE is assumed to be in
478 * a level 0 page table, unless -l specifies another level.
480 * The PTE value can be specified as the -p option, since on a 32 bit kernel
481 * with PAE running it's larger than a uintptr_t.
483 /*ARGSUSED*/
485 pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
487 int level = 0;
488 uint64_t pte = 0;
489 char *level_str = NULL;
490 char *pte_str = NULL;
492 init_mmu();
494 if (mmu.num_level == 0)
495 return (DCMD_ERR);
497 if (mdb_getopts(argc, argv,
498 'p', MDB_OPT_STR, &pte_str,
499 'l', MDB_OPT_STR, &level_str) != argc)
500 return (DCMD_USAGE);
503 * parse the PTE to decode, if it's 0, we don't do anything
505 if (pte_str != NULL) {
506 pte = mdb_strtoull(pte_str);
507 } else {
508 if ((flags & DCMD_ADDRSPEC) == 0)
509 return (DCMD_USAGE);
510 pte = addr;
512 if (pte == 0)
513 return (DCMD_OK);
516 * parse the level if supplied
518 if (level_str != NULL) {
519 level = mdb_strtoull(level_str);
520 if (level < 0 || level > mmu.max_level)
521 return (DCMD_ERR);
524 return (do_pte_dcmd(level, pte));
527 static size_t
528 va2entry(htable_t *htable, uintptr_t addr)
530 size_t entry = (addr - htable->ht_vaddr);
532 entry >>= mmu.level_shift[htable->ht_level];
533 return (entry & HTABLE_NUM_PTES(htable) - 1);
536 static x86pte_t
537 get_pte(hat_t *hat, htable_t *htable, uintptr_t addr)
539 x86pte_t buf;
540 x86pte32_t *pte32 = (x86pte32_t *)&buf;
541 size_t len;
543 if (htable->ht_flags & HTABLE_VLP) {
544 uintptr_t ptr = (uintptr_t)hat->hat_vlp_ptes;
545 ptr += va2entry(htable, addr) << mmu.pte_size_shift;
546 len = mdb_vread(&buf, mmu.pte_size, ptr);
547 } else {
548 paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn);
549 paddr += va2entry(htable, addr) << mmu.pte_size_shift;
550 len = mdb_pread(&buf, mmu.pte_size, paddr);
553 if (len != mmu.pte_size)
554 return (0);
556 if (mmu.pte_size == sizeof (x86pte_t))
557 return (buf);
558 return (*pte32);
561 static int
562 do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap,
563 pfn_t *mfnp)
565 struct as as;
566 struct hat *hatp;
567 struct hat hat;
568 htable_t *ht;
569 htable_t htable;
570 uintptr_t base;
571 int h;
572 int level;
573 int found = 0;
574 x86pte_t pte;
575 physaddr_t paddr;
577 if (asp != NULL) {
578 if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
579 mdb_warn("Couldn't read struct as\n");
580 return (DCMD_ERR);
582 hatp = as.a_hat;
583 } else {
584 hatp = khat;
588 * read the hat and its hash table
590 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
591 mdb_warn("Couldn't read struct hat\n");
592 return (DCMD_ERR);
596 * read the htable hashtable
598 for (level = 0; level <= mmu.max_level; ++level) {
599 if (level == TOP_LEVEL(&hat))
600 base = 0;
601 else
602 base = addr & mmu.level_mask[level + 1];
604 for (h = 0; h < hat.hat_num_hash; ++h) {
605 if (mdb_vread(&ht, sizeof (htable_t *),
606 (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
607 mdb_warn("Couldn't read htable\n");
608 return (DCMD_ERR);
610 for (; ht != NULL; ht = htable.ht_next) {
611 if (mdb_vread(&htable, sizeof (htable_t),
612 (uintptr_t)ht) == -1) {
613 mdb_warn("Couldn't read htable\n");
614 return (DCMD_ERR);
617 if (htable.ht_vaddr != base ||
618 htable.ht_level != level)
619 continue;
621 pte = get_pte(&hat, &htable, addr);
623 if (print_level) {
624 mdb_printf("\tlevel=%d htable=%p "
625 "pte=%llr\n", level, ht, pte);
628 if (!PTE_ISVALID(pte)) {
629 mdb_printf("Address %p is unmapped.\n",
630 addr);
631 return (DCMD_ERR);
634 if (found)
635 continue;
637 if (PTE_IS_LGPG(pte, level))
638 paddr = mdb_ma_to_pa(pte &
639 PT_PADDR_LGPG);
640 else
641 paddr = mdb_ma_to_pa(pte & PT_PADDR);
642 paddr += addr & mmu.level_offset[level];
643 if (pap != NULL)
644 *pap = paddr;
645 if (mfnp != NULL)
646 *mfnp = pte2mfn(pte, level);
647 found = 1;
652 done:
653 if (!found)
654 return (DCMD_ERR);
655 return (DCMD_OK);
659 va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
661 uintptr_t addrspace;
662 char *addrspace_str = NULL;
663 int piped = flags & DCMD_PIPE_OUT;
664 pfn_t pfn;
665 pfn_t mfn;
666 int rc;
668 init_mmu();
670 if (mmu.num_level == 0)
671 return (DCMD_ERR);
673 if (mdb_getopts(argc, argv,
674 'a', MDB_OPT_STR, &addrspace_str) != argc)
675 return (DCMD_USAGE);
677 if ((flags & DCMD_ADDRSPEC) == 0)
678 return (DCMD_USAGE);
681 * parse the address space
683 if (addrspace_str != NULL)
684 addrspace = mdb_strtoull(addrspace_str);
685 else
686 addrspace = 0;
688 rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn);
690 if (rc != DCMD_OK)
691 return (rc);
693 if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) {
694 mdb_warn("Invalid mfn %lr\n", mfn);
695 return (DCMD_ERR);
698 if (piped) {
699 mdb_printf("0x%lr\n", pfn);
700 return (DCMD_OK);
703 mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn);
705 if (is_xpv)
706 mdb_printf(" (mfn 0x%lr)", mfn);
708 mdb_printf("\n");
710 return (DCMD_OK);
714 * Report all hat's that either use PFN as a page table or that map the page.
716 static int
717 do_report_maps(pfn_t pfn)
719 struct hat *hatp;
720 struct hat hat;
721 htable_t *ht;
722 htable_t htable;
723 uintptr_t base;
724 int h;
725 int level;
726 int entry;
727 x86pte_t pte;
728 x86pte_t buf;
729 x86pte32_t *pte32 = (x86pte32_t *)&buf;
730 physaddr_t paddr;
731 size_t len;
734 * The hats are kept in a list with khat at the head.
736 for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
738 * read the hat and its hash table
740 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
741 mdb_warn("Couldn't read struct hat\n");
742 return (DCMD_ERR);
746 * read the htable hashtable
748 paddr = 0;
749 for (h = 0; h < hat.hat_num_hash; ++h) {
750 if (mdb_vread(&ht, sizeof (htable_t *),
751 (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
752 mdb_warn("Couldn't read htable\n");
753 return (DCMD_ERR);
755 for (; ht != NULL; ht = htable.ht_next) {
756 if (mdb_vread(&htable, sizeof (htable_t),
757 (uintptr_t)ht) == -1) {
758 mdb_warn("Couldn't read htable\n");
759 return (DCMD_ERR);
763 * only report kernel addresses once
765 if (hatp != khat &&
766 htable.ht_vaddr >= kernelbase)
767 continue;
770 * Is the PFN a pagetable itself?
772 if (htable.ht_pfn == pfn) {
773 mdb_printf("Pagetable for "
774 "hat=%p htable=%p\n", hatp, ht);
775 continue;
779 * otherwise, examine page mappings
781 level = htable.ht_level;
782 if (level > mmu.max_page_level)
783 continue;
784 paddr = mmu_ptob((physaddr_t)htable.ht_pfn);
785 for (entry = 0;
786 entry < HTABLE_NUM_PTES(&htable);
787 ++entry) {
789 base = htable.ht_vaddr + entry *
790 mmu.level_size[level];
793 * only report kernel addresses once
795 if (hatp != khat &&
796 base >= kernelbase)
797 continue;
799 len = mdb_pread(&buf, mmu.pte_size,
800 paddr + entry * mmu.pte_size);
801 if (len != mmu.pte_size)
802 return (DCMD_ERR);
803 if (mmu.pte_size == sizeof (x86pte_t))
804 pte = buf;
805 else
806 pte = *pte32;
808 if ((pte & PT_VALID) == 0)
809 continue;
810 if (level == 0 || !(pte & PT_PAGESIZE))
811 pte &= PT_PADDR;
812 else
813 pte &= PT_PADDR_LGPG;
814 if (mmu_btop(mdb_ma_to_pa(pte)) != pfn)
815 continue;
816 mdb_printf("hat=%p maps addr=%p\n",
817 hatp, (caddr_t)base);
823 done:
824 return (DCMD_OK);
828 * given a PFN as its address argument, prints out the uses of it
830 /*ARGSUSED*/
832 report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
834 pfn_t pfn;
835 uint_t mflag = 0;
837 init_mmu();
839 if (mmu.num_level == 0)
840 return (DCMD_ERR);
842 if ((flags & DCMD_ADDRSPEC) == 0)
843 return (DCMD_USAGE);
845 if (mdb_getopts(argc, argv,
846 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
847 return (DCMD_USAGE);
849 pfn = (pfn_t)addr;
850 if (mflag)
851 pfn = mdb_mfn_to_pfn(pfn);
853 return (do_report_maps(pfn));
856 static int
857 do_ptable_dcmd(pfn_t pfn)
859 struct hat *hatp;
860 struct hat hat;
861 htable_t *ht;
862 htable_t htable;
863 uintptr_t base;
864 int h;
865 int level;
866 int entry;
867 uintptr_t pagesize;
868 x86pte_t pte;
869 x86pte_t buf;
870 x86pte32_t *pte32 = (x86pte32_t *)&buf;
871 physaddr_t paddr;
872 size_t len;
875 * The hats are kept in a list with khat at the head.
877 for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
879 * read the hat and its hash table
881 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
882 mdb_warn("Couldn't read struct hat\n");
883 return (DCMD_ERR);
887 * read the htable hashtable
889 paddr = 0;
890 for (h = 0; h < hat.hat_num_hash; ++h) {
891 if (mdb_vread(&ht, sizeof (htable_t *),
892 (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
893 mdb_warn("Couldn't read htable\n");
894 return (DCMD_ERR);
896 for (; ht != NULL; ht = htable.ht_next) {
897 if (mdb_vread(&htable, sizeof (htable_t),
898 (uintptr_t)ht) == -1) {
899 mdb_warn("Couldn't read htable\n");
900 return (DCMD_ERR);
904 * Is this the PFN for this htable
906 if (htable.ht_pfn == pfn)
907 goto found_it;
912 found_it:
913 if (htable.ht_pfn == pfn) {
914 mdb_printf("htable=%p\n", ht);
915 level = htable.ht_level;
916 base = htable.ht_vaddr;
917 pagesize = mmu.level_size[level];
918 } else {
919 mdb_printf("Unknown pagetable - assuming level/addr 0");
920 level = 0; /* assume level == 0 for PFN */
921 base = 0;
922 pagesize = MMU_PAGESIZE;
925 paddr = mmu_ptob((physaddr_t)pfn);
926 for (entry = 0; entry < mmu.ptes_per_table; ++entry) {
927 len = mdb_pread(&buf, mmu.pte_size,
928 paddr + entry * mmu.pte_size);
929 if (len != mmu.pte_size)
930 return (DCMD_ERR);
931 if (mmu.pte_size == sizeof (x86pte_t))
932 pte = buf;
933 else
934 pte = *pte32;
936 if (pte == 0)
937 continue;
939 mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize);
940 do_pte_dcmd(level, pte);
943 done:
944 return (DCMD_OK);
948 * Dump the page table at the given PFN
950 /*ARGSUSED*/
952 ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
954 pfn_t pfn;
955 uint_t mflag = 0;
957 init_mmu();
959 if (mmu.num_level == 0)
960 return (DCMD_ERR);
962 if ((flags & DCMD_ADDRSPEC) == 0)
963 return (DCMD_USAGE);
965 if (mdb_getopts(argc, argv,
966 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
967 return (DCMD_USAGE);
969 pfn = (pfn_t)addr;
970 if (mflag)
971 pfn = mdb_mfn_to_pfn(pfn);
973 return (do_ptable_dcmd(pfn));
976 static int
977 do_htables_dcmd(hat_t *hatp)
979 struct hat hat;
980 htable_t *ht;
981 htable_t htable;
982 int h;
985 * read the hat and its hash table
987 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
988 mdb_warn("Couldn't read struct hat\n");
989 return (DCMD_ERR);
993 * read the htable hashtable
995 for (h = 0; h < hat.hat_num_hash; ++h) {
996 if (mdb_vread(&ht, sizeof (htable_t *),
997 (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
998 mdb_warn("Couldn't read htable ptr\\n");
999 return (DCMD_ERR);
1001 for (; ht != NULL; ht = htable.ht_next) {
1002 mdb_printf("%p\n", ht);
1003 if (mdb_vread(&htable, sizeof (htable_t),
1004 (uintptr_t)ht) == -1) {
1005 mdb_warn("Couldn't read htable\n");
1006 return (DCMD_ERR);
1010 return (DCMD_OK);
1014 * Dump the htables for the given hat
1016 /*ARGSUSED*/
1018 htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1020 hat_t *hat;
1022 init_mmu();
1024 if (mmu.num_level == 0)
1025 return (DCMD_ERR);
1027 if ((flags & DCMD_ADDRSPEC) == 0)
1028 return (DCMD_USAGE);
1030 hat = (hat_t *)addr;
1032 return (do_htables_dcmd(hat));