dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / mdb / i86pc / modules / unix / i86mmu.c
blob3e31c959bbbf991748572d4e1d237748cfea738b
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 #include <vm/as.h>
40 #include <mdb/mdb_modapi.h>
41 #include <mdb/mdb_target.h>
43 #include <vm/page.h>
44 #include <vm/hat_i86.h>
46 struct pfn2pp {
47 pfn_t pfn;
48 page_t *pp;
51 static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *);
52 static void init_mmu(void);
54 int
55 platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
57 if (asp == NULL)
58 return (DCMD_ERR);
60 init_mmu();
62 if (mmu.num_level == 0)
63 return (DCMD_ERR);
65 return (do_va2pa(addr, asp, 0, pap, NULL));
69 * ::memseg_list dcmd and walker to implement it.
71 /*ARGSUSED*/
72 int
73 memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
75 struct memseg ms;
77 if (!(flags & DCMD_ADDRSPEC)) {
78 if (mdb_pwalk_dcmd("memseg", "memseg_list",
79 0, NULL, 0) == -1) {
80 mdb_warn("can't walk memseg");
81 return (DCMD_ERR);
83 return (DCMD_OK);
86 if (DCMD_HDRSPEC(flags))
87 mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
88 "PAGES", "EPAGES", "BASE", "END");
90 if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
91 mdb_warn("can't read memseg at %#lx", addr);
92 return (DCMD_ERR);
95 mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr,
96 ms.pages, ms.epages, ms.pages_base, ms.pages_end);
98 return (DCMD_OK);
102 * walk the memseg structures
105 memseg_walk_init(mdb_walk_state_t *wsp)
107 if (wsp->walk_addr != (uintptr_t)NULL) {
108 mdb_warn("memseg only supports global walks\n");
109 return (WALK_ERR);
112 if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
113 mdb_warn("symbol 'memsegs' not found");
114 return (WALK_ERR);
117 wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
118 return (WALK_NEXT);
123 memseg_walk_step(mdb_walk_state_t *wsp)
125 int status;
127 if (wsp->walk_addr == (uintptr_t)NULL) {
128 return (WALK_DONE);
131 if (mdb_vread(wsp->walk_data, sizeof (struct memseg),
132 wsp->walk_addr) == -1) {
133 mdb_warn("failed to read struct memseg at %p", wsp->walk_addr);
134 return (WALK_DONE);
137 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
138 wsp->walk_cbdata);
140 wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
142 return (status);
145 void
146 memseg_walk_fini(mdb_walk_state_t *wsp)
148 mdb_free(wsp->walk_data, sizeof (struct memseg));
152 * Now HAT related dcmds.
155 static struct hat *khat; /* value of kas.a_hat */
156 struct hat_mmu_info mmu;
157 uintptr_t kernelbase;
160 * stuff for i86xpv images
162 static int is_xpv;
163 static uintptr_t mfn_list_addr; /* kernel MFN list address */
164 uintptr_t xen_virt_start; /* address of mfn_to_pfn[] table */
165 ulong_t mfn_count; /* number of pfn's in the MFN list */
166 pfn_t *mfn_list; /* local MFN list copy */
169 * read mmu parameters from kernel
171 static void
172 init_mmu(void)
174 struct as kas;
176 if (mmu.num_level != 0)
177 return;
179 if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1)
180 mdb_warn("Can't use HAT information before mmu_init()\n");
181 if (mdb_readsym(&kas, sizeof (kas), "kas") == -1)
182 mdb_warn("Couldn't find kas - kernel's struct as\n");
183 if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1)
184 mdb_warn("Couldn't find kernelbase\n");
185 khat = kas.a_hat;
188 * Is this a paravirtualized domain image?
190 if (mdb_readsym(&mfn_list_addr, sizeof (mfn_list_addr),
191 "mfn_list") == -1 ||
192 mdb_readsym(&xen_virt_start, sizeof (xen_virt_start),
193 "xen_virt_start") == -1 ||
194 mdb_readsym(&mfn_count, sizeof (mfn_count), "mfn_count") == -1) {
195 mfn_list_addr = (uintptr_t)NULL;
198 is_xpv = mfn_list_addr != (uintptr_t)NULL;
200 #ifndef _KMDB
202 * recreate the local mfn_list
204 if (is_xpv) {
205 size_t sz = mfn_count * sizeof (pfn_t);
206 mfn_list = mdb_zalloc(sz, UM_SLEEP);
208 if (mdb_vread(mfn_list, sz, (uintptr_t)mfn_list_addr) == -1) {
209 mdb_warn("Failed to read MFN list\n");
210 mdb_free(mfn_list, sz);
211 mfn_list = NULL;
214 #endif
217 void
218 free_mmu(void)
223 #define mdb_ma_to_pa(ma) (ma)
224 #define mdb_mfn_to_pfn(mfn) (mfn)
225 #define mdb_pfn_to_mfn(pfn) (pfn)
229 * ::mfntopfn dcmd translates hypervisor machine page number
230 * to physical page number
232 /*ARGSUSED*/
234 mfntopfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
236 pfn_t pfn;
238 if ((flags & DCMD_ADDRSPEC) == 0) {
239 mdb_warn("MFN missing\n");
240 return (DCMD_USAGE);
243 if ((pfn = mdb_mfn_to_pfn((pfn_t)addr)) == -(pfn_t)1) {
244 mdb_warn("Invalid mfn %lr\n", (pfn_t)addr);
245 return (DCMD_ERR);
248 mdb_printf("%lr\n", pfn);
250 return (DCMD_OK);
254 * ::pfntomfn dcmd translates physical page number to
255 * hypervisor machine page number
257 /*ARGSUSED*/
259 pfntomfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
261 pfn_t mfn;
263 if ((flags & DCMD_ADDRSPEC) == 0) {
264 mdb_warn("PFN missing\n");
265 return (DCMD_USAGE);
268 if ((mfn = mdb_pfn_to_mfn((pfn_t)addr)) == -(pfn_t)1) {
269 mdb_warn("Invalid pfn %lr\n", (pfn_t)addr);
270 return (DCMD_ABORT);
273 mdb_printf("%lr\n", mfn);
275 if (flags & DCMD_LOOP)
276 mdb_set_dot(addr + 1);
277 return (DCMD_OK);
280 static pfn_t
281 pte2mfn(x86pte_t pte, uint_t level)
283 pfn_t mfn;
284 if (level > 0 && (pte & PT_PAGESIZE))
285 mfn = mmu_btop(pte & PT_PADDR_LGPG);
286 else
287 mfn = mmu_btop(pte & PT_PADDR);
288 return (mfn);
292 * Print a PTE in more human friendly way. The PTE is assumed to be in
293 * a level 0 page table, unless -l specifies another level.
295 * The PTE value can be specified as the -p option, since on a 32 bit kernel
296 * with PAE running it's larger than a uintptr_t.
298 static int
299 do_pte_dcmd(int level, uint64_t pte)
301 static char *attr[] = {
302 "wrback", "wrthru", "uncached", "uncached",
303 "wrback", "wrthru", "wrcombine", "uncached"};
304 int pat_index = 0;
305 pfn_t mfn;
307 mdb_printf("pte=%llr: ", pte);
308 if (PTE_GET(pte, mmu.pt_nx))
309 mdb_printf("noexec ");
311 mfn = pte2mfn(pte, level);
312 mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn);
314 if (PTE_GET(pte, PT_NOCONSIST))
315 mdb_printf("noconsist ");
317 if (PTE_GET(pte, PT_NOSYNC))
318 mdb_printf("nosync ");
320 if (PTE_GET(pte, mmu.pt_global))
321 mdb_printf("global ");
323 if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
324 mdb_printf("largepage ");
326 if (level > 0 && PTE_GET(pte, PT_MOD))
327 mdb_printf("mod ");
329 if (level > 0 && PTE_GET(pte, PT_REF))
330 mdb_printf("ref ");
332 if (PTE_GET(pte, PT_USER))
333 mdb_printf("user ");
335 if (PTE_GET(pte, PT_WRITABLE))
336 mdb_printf("write ");
339 * Report non-standard cacheability
341 pat_index = 0;
342 if (level > 0) {
343 if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE))
344 pat_index += 4;
345 } else {
346 if (PTE_GET(pte, PT_PAT_4K))
347 pat_index += 4;
350 if (PTE_GET(pte, PT_NOCACHE))
351 pat_index += 2;
353 if (PTE_GET(pte, PT_WRITETHRU))
354 pat_index += 1;
356 if (pat_index != 0)
357 mdb_printf("%s", attr[pat_index]);
359 if (PTE_GET(pte, PT_VALID) == 0)
360 mdb_printf(" !VALID ");
362 mdb_printf("\n");
363 return (DCMD_OK);
367 * Print a PTE in more human friendly way. The PTE is assumed to be in
368 * a level 0 page table, unless -l specifies another level.
370 * The PTE value can be specified as the -p option, since on a 32 bit kernel
371 * with PAE running it's larger than a uintptr_t.
373 /*ARGSUSED*/
375 pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
377 int level = 0;
378 uint64_t pte = 0;
379 char *level_str = NULL;
380 char *pte_str = NULL;
382 init_mmu();
384 if (mmu.num_level == 0)
385 return (DCMD_ERR);
387 if (mdb_getopts(argc, argv,
388 'p', MDB_OPT_STR, &pte_str,
389 'l', MDB_OPT_STR, &level_str) != argc)
390 return (DCMD_USAGE);
393 * parse the PTE to decode, if it's 0, we don't do anything
395 if (pte_str != NULL) {
396 pte = mdb_strtoull(pte_str);
397 } else {
398 if ((flags & DCMD_ADDRSPEC) == 0)
399 return (DCMD_USAGE);
400 pte = addr;
402 if (pte == 0)
403 return (DCMD_OK);
406 * parse the level if supplied
408 if (level_str != NULL) {
409 level = mdb_strtoull(level_str);
410 if (level < 0 || level > mmu.max_level)
411 return (DCMD_ERR);
414 return (do_pte_dcmd(level, pte));
417 static size_t
418 va2entry(htable_t *htable, uintptr_t addr)
420 size_t entry = (addr - htable->ht_vaddr);
422 entry >>= mmu.level_shift[htable->ht_level];
423 return (entry & HTABLE_NUM_PTES(htable) - 1);
426 static x86pte_t
427 get_pte(hat_t *hat, htable_t *htable, uintptr_t addr)
429 x86pte_t buf;
430 x86pte32_t *pte32 = (x86pte32_t *)&buf;
431 size_t len;
433 if (htable->ht_flags & HTABLE_VLP) {
434 uintptr_t ptr = (uintptr_t)hat->hat_vlp_ptes;
435 ptr += va2entry(htable, addr) << mmu.pte_size_shift;
436 len = mdb_vread(&buf, mmu.pte_size, ptr);
437 } else {
438 paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn);
439 paddr += va2entry(htable, addr) << mmu.pte_size_shift;
440 len = mdb_pread(&buf, mmu.pte_size, paddr);
443 if (len != mmu.pte_size)
444 return (0);
446 if (mmu.pte_size == sizeof (x86pte_t))
447 return (buf);
448 return (*pte32);
451 static int
452 do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap,
453 pfn_t *mfnp)
455 struct as as;
456 struct hat *hatp;
457 struct hat hat;
458 htable_t *ht;
459 htable_t htable;
460 uintptr_t base;
461 int h;
462 int level;
463 int found = 0;
464 x86pte_t pte;
465 physaddr_t paddr;
467 if (asp != NULL) {
468 if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
469 mdb_warn("Couldn't read struct as\n");
470 return (DCMD_ERR);
472 hatp = as.a_hat;
473 } else {
474 hatp = khat;
478 * read the hat and its hash table
480 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
481 mdb_warn("Couldn't read struct hat\n");
482 return (DCMD_ERR);
486 * read the htable hashtable
488 for (level = 0; level <= mmu.max_level; ++level) {
489 if (level == TOP_LEVEL(&hat))
490 base = 0;
491 else
492 base = addr & mmu.level_mask[level + 1];
494 for (h = 0; h < hat.hat_num_hash; ++h) {
495 if (mdb_vread(&ht, sizeof (htable_t *),
496 (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
497 mdb_warn("Couldn't read htable\n");
498 return (DCMD_ERR);
500 for (; ht != NULL; ht = htable.ht_next) {
501 if (mdb_vread(&htable, sizeof (htable_t),
502 (uintptr_t)ht) == -1) {
503 mdb_warn("Couldn't read htable\n");
504 return (DCMD_ERR);
507 if (htable.ht_vaddr != base ||
508 htable.ht_level != level)
509 continue;
511 pte = get_pte(&hat, &htable, addr);
513 if (print_level) {
514 mdb_printf("\tlevel=%d htable=%p "
515 "pte=%llr\n", level, ht, pte);
518 if (!PTE_ISVALID(pte)) {
519 mdb_printf("Address %p is unmapped.\n",
520 addr);
521 return (DCMD_ERR);
524 if (found)
525 continue;
527 if (PTE_IS_LGPG(pte, level))
528 paddr = mdb_ma_to_pa(pte &
529 PT_PADDR_LGPG);
530 else
531 paddr = mdb_ma_to_pa(pte & PT_PADDR);
532 paddr += addr & mmu.level_offset[level];
533 if (pap != NULL)
534 *pap = paddr;
535 if (mfnp != NULL)
536 *mfnp = pte2mfn(pte, level);
537 found = 1;
542 done:
543 if (!found)
544 return (DCMD_ERR);
545 return (DCMD_OK);
549 va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
551 uintptr_t addrspace;
552 char *addrspace_str = NULL;
553 int piped = flags & DCMD_PIPE_OUT;
554 pfn_t pfn;
555 pfn_t mfn;
556 int rc;
558 init_mmu();
560 if (mmu.num_level == 0)
561 return (DCMD_ERR);
563 if (mdb_getopts(argc, argv,
564 'a', MDB_OPT_STR, &addrspace_str) != argc)
565 return (DCMD_USAGE);
567 if ((flags & DCMD_ADDRSPEC) == 0)
568 return (DCMD_USAGE);
571 * parse the address space
573 if (addrspace_str != NULL)
574 addrspace = mdb_strtoull(addrspace_str);
575 else
576 addrspace = 0;
578 rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn);
580 if (rc != DCMD_OK)
581 return (rc);
583 if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) {
584 mdb_warn("Invalid mfn %lr\n", mfn);
585 return (DCMD_ERR);
588 if (piped) {
589 mdb_printf("0x%lr\n", pfn);
590 return (DCMD_OK);
593 mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn);
595 if (is_xpv)
596 mdb_printf(" (mfn 0x%lr)", mfn);
598 mdb_printf("\n");
600 return (DCMD_OK);
604 * Report all hat's that either use PFN as a page table or that map the page.
606 static int
607 do_report_maps(pfn_t pfn)
609 struct hat *hatp;
610 struct hat hat;
611 htable_t *ht;
612 htable_t htable;
613 uintptr_t base;
614 int h;
615 int level;
616 int entry;
617 x86pte_t pte;
618 x86pte_t buf;
619 x86pte32_t *pte32 = (x86pte32_t *)&buf;
620 physaddr_t paddr;
621 size_t len;
624 * The hats are kept in a list with khat at the head.
626 for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
628 * read the hat and its hash table
630 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
631 mdb_warn("Couldn't read struct hat\n");
632 return (DCMD_ERR);
636 * read the htable hashtable
638 paddr = 0;
639 for (h = 0; h < hat.hat_num_hash; ++h) {
640 if (mdb_vread(&ht, sizeof (htable_t *),
641 (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
642 mdb_warn("Couldn't read htable\n");
643 return (DCMD_ERR);
645 for (; ht != NULL; ht = htable.ht_next) {
646 if (mdb_vread(&htable, sizeof (htable_t),
647 (uintptr_t)ht) == -1) {
648 mdb_warn("Couldn't read htable\n");
649 return (DCMD_ERR);
653 * only report kernel addresses once
655 if (hatp != khat &&
656 htable.ht_vaddr >= kernelbase)
657 continue;
660 * Is the PFN a pagetable itself?
662 if (htable.ht_pfn == pfn) {
663 mdb_printf("Pagetable for "
664 "hat=%p htable=%p\n", hatp, ht);
665 continue;
669 * otherwise, examine page mappings
671 level = htable.ht_level;
672 if (level > mmu.max_page_level)
673 continue;
674 paddr = mmu_ptob((physaddr_t)htable.ht_pfn);
675 for (entry = 0;
676 entry < HTABLE_NUM_PTES(&htable);
677 ++entry) {
679 base = htable.ht_vaddr + entry *
680 mmu.level_size[level];
683 * only report kernel addresses once
685 if (hatp != khat &&
686 base >= kernelbase)
687 continue;
689 len = mdb_pread(&buf, mmu.pte_size,
690 paddr + entry * mmu.pte_size);
691 if (len != mmu.pte_size)
692 return (DCMD_ERR);
693 if (mmu.pte_size == sizeof (x86pte_t))
694 pte = buf;
695 else
696 pte = *pte32;
698 if ((pte & PT_VALID) == 0)
699 continue;
700 if (level == 0 || !(pte & PT_PAGESIZE))
701 pte &= PT_PADDR;
702 else
703 pte &= PT_PADDR_LGPG;
704 if (mmu_btop(mdb_ma_to_pa(pte)) != pfn)
705 continue;
706 mdb_printf("hat=%p maps addr=%p\n",
707 hatp, (caddr_t)base);
713 done:
714 return (DCMD_OK);
718 * given a PFN as its address argument, prints out the uses of it
720 /*ARGSUSED*/
722 report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
724 pfn_t pfn;
725 uint_t mflag = 0;
727 init_mmu();
729 if (mmu.num_level == 0)
730 return (DCMD_ERR);
732 if ((flags & DCMD_ADDRSPEC) == 0)
733 return (DCMD_USAGE);
735 if (mdb_getopts(argc, argv,
736 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
737 return (DCMD_USAGE);
739 pfn = (pfn_t)addr;
740 if (mflag)
741 pfn = mdb_mfn_to_pfn(pfn);
743 return (do_report_maps(pfn));
746 static int
747 do_ptable_dcmd(pfn_t pfn)
749 struct hat *hatp;
750 struct hat hat;
751 htable_t *ht;
752 htable_t htable;
753 uintptr_t base;
754 int h;
755 int level;
756 int entry;
757 uintptr_t pagesize;
758 x86pte_t pte;
759 x86pte_t buf;
760 x86pte32_t *pte32 = (x86pte32_t *)&buf;
761 physaddr_t paddr;
762 size_t len;
765 * The hats are kept in a list with khat at the head.
767 for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
769 * read the hat and its hash table
771 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
772 mdb_warn("Couldn't read struct hat\n");
773 return (DCMD_ERR);
777 * read the htable hashtable
779 paddr = 0;
780 for (h = 0; h < hat.hat_num_hash; ++h) {
781 if (mdb_vread(&ht, sizeof (htable_t *),
782 (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
783 mdb_warn("Couldn't read htable\n");
784 return (DCMD_ERR);
786 for (; ht != NULL; ht = htable.ht_next) {
787 if (mdb_vread(&htable, sizeof (htable_t),
788 (uintptr_t)ht) == -1) {
789 mdb_warn("Couldn't read htable\n");
790 return (DCMD_ERR);
794 * Is this the PFN for this htable
796 if (htable.ht_pfn == pfn)
797 goto found_it;
802 found_it:
803 if (htable.ht_pfn == pfn) {
804 mdb_printf("htable=%p\n", ht);
805 level = htable.ht_level;
806 base = htable.ht_vaddr;
807 pagesize = mmu.level_size[level];
808 } else {
809 mdb_printf("Unknown pagetable - assuming level/addr 0");
810 level = 0; /* assume level == 0 for PFN */
811 base = 0;
812 pagesize = MMU_PAGESIZE;
815 paddr = mmu_ptob((physaddr_t)pfn);
816 for (entry = 0; entry < mmu.ptes_per_table; ++entry) {
817 len = mdb_pread(&buf, mmu.pte_size,
818 paddr + entry * mmu.pte_size);
819 if (len != mmu.pte_size)
820 return (DCMD_ERR);
821 if (mmu.pte_size == sizeof (x86pte_t))
822 pte = buf;
823 else
824 pte = *pte32;
826 if (pte == 0)
827 continue;
829 mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize);
830 do_pte_dcmd(level, pte);
833 done:
834 return (DCMD_OK);
838 * Dump the page table at the given PFN
840 /*ARGSUSED*/
842 ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
844 pfn_t pfn;
845 uint_t mflag = 0;
847 init_mmu();
849 if (mmu.num_level == 0)
850 return (DCMD_ERR);
852 if ((flags & DCMD_ADDRSPEC) == 0)
853 return (DCMD_USAGE);
855 if (mdb_getopts(argc, argv,
856 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
857 return (DCMD_USAGE);
859 pfn = (pfn_t)addr;
860 if (mflag)
861 pfn = mdb_mfn_to_pfn(pfn);
863 return (do_ptable_dcmd(pfn));
866 static int
867 do_htables_dcmd(hat_t *hatp)
869 struct hat hat;
870 htable_t *ht;
871 htable_t htable;
872 int h;
875 * read the hat and its hash table
877 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
878 mdb_warn("Couldn't read struct hat\n");
879 return (DCMD_ERR);
883 * read the htable hashtable
885 for (h = 0; h < hat.hat_num_hash; ++h) {
886 if (mdb_vread(&ht, sizeof (htable_t *),
887 (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
888 mdb_warn("Couldn't read htable ptr\\n");
889 return (DCMD_ERR);
891 for (; ht != NULL; ht = htable.ht_next) {
892 mdb_printf("%p\n", ht);
893 if (mdb_vread(&htable, sizeof (htable_t),
894 (uintptr_t)ht) == -1) {
895 mdb_warn("Couldn't read htable\n");
896 return (DCMD_ERR);
900 return (DCMD_OK);
904 * Dump the htables for the given hat
906 /*ARGSUSED*/
908 htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
910 hat_t *hat;
912 init_mmu();
914 if (mmu.num_level == 0)
915 return (DCMD_ERR);
917 if ((flags & DCMD_ADDRSPEC) == 0)
918 return (DCMD_USAGE);
920 hat = (hat_t *)addr;
922 return (do_htables_dcmd(hat));