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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
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
31 *
32 */
33
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>
42
43 #include <mdb/mdb_modapi.h>
44 #include <mdb/mdb_target.h>
45
46 #include <vm/page.h>
47 #include <vm/hat_i86.h>
48
49 struct pfn2pp {
50 pfn_t pfn;
51 page_t *pp;
52 };
53
54 static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *);
55 static void init_mmu(void);
56
57 int
58 platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
59 {
60 if (asp == NULL)
61 return (DCMD_ERR);
62
63 init_mmu();
64
65 if (mmu.num_level == 0)
66 return (DCMD_ERR);
67
68 return (do_va2pa(addr, asp, 0, pap, NULL));
381 }
382
383 mdb_printf("%lr\n", mfn);
384
385 if (flags & DCMD_LOOP)
386 mdb_set_dot(addr + 1);
387 return (DCMD_OK);
388 }
389
390 static pfn_t
391 pte2mfn(x86pte_t pte, uint_t level)
392 {
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);
399 }
400
401 /*
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.
404 *
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.
407 */
408 static int
409 do_pte_dcmd(int level, uint64_t pte)
410 {
411 static char *attr[] = {
412 "wrback", "wrthru", "uncached", "uncached",
413 "wrback", "wrthru", "wrcombine", "uncached"};
414 int pat_index = 0;
415 pfn_t mfn;
416
417 mdb_printf("pte=%llr: ", pte);
418 if (PTE_GET(pte, mmu.pt_nx))
419 mdb_printf("noexec ");
420
421 mfn = pte2mfn(pte, level);
422 mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn);
423
424 if (PTE_GET(pte, PT_NOCONSIST))
425 mdb_printf("noconsist ");
426
427 if (PTE_GET(pte, PT_NOSYNC))
428 mdb_printf("nosync ");
429
430 if (PTE_GET(pte, mmu.pt_global))
431 mdb_printf("global ");
432
433 if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
434 mdb_printf("largepage ");
435
436 if (level > 0 && PTE_GET(pte, PT_MOD))
437 mdb_printf("mod ");
438
439 if (level > 0 && PTE_GET(pte, PT_REF))
440 mdb_printf("ref ");
441
442 if (PTE_GET(pte, PT_USER))
443 mdb_printf("user ");
459
460 if (PTE_GET(pte, PT_NOCACHE))
461 pat_index += 2;
462
463 if (PTE_GET(pte, PT_WRITETHRU))
464 pat_index += 1;
465
466 if (pat_index != 0)
467 mdb_printf("%s", attr[pat_index]);
468
469 if (PTE_GET(pte, PT_VALID) == 0)
470 mdb_printf(" !VALID ");
471
472 mdb_printf("\n");
473 return (DCMD_OK);
474 }
475
476 /*
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.
479 *
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.
482 */
483 /*ARGSUSED*/
484 int
485 pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
486 {
487 int level = 0;
488 uint64_t pte = 0;
489 char *level_str = NULL;
490 char *pte_str = NULL;
491
492 init_mmu();
493
494 if (mmu.num_level == 0)
495 return (DCMD_ERR);
496
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);
501
502 /*
503 * parse the PTE to decode, if it's 0, we don't do anything
504 */
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;
511 }
512 if (pte == 0)
513 return (DCMD_OK);
514
515 /*
516 * parse the level if supplied
517 */
518 if (level_str != NULL) {
519 level = mdb_strtoull(level_str);
520 if (level < 0 || level > mmu.max_level)
521 return (DCMD_ERR);
522 }
523
524 return (do_pte_dcmd(level, pte));
525 }
526
527 static size_t
528 va2entry(htable_t *htable, uintptr_t addr)
529 {
530 size_t entry = (addr - htable->ht_vaddr);
531
532 entry >>= mmu.level_shift[htable->ht_level];
533 return (entry & HTABLE_NUM_PTES(htable) - 1);
534 }
535
536 static x86pte_t
537 get_pte(hat_t *hat, htable_t *htable, uintptr_t addr)
538 {
539 x86pte_t buf;
540 x86pte32_t *pte32 = (x86pte32_t *)&buf;
541 size_t len;
542
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);
551 }
552
553 if (len != mmu.pte_size)
554 return (0);
555
556 if (mmu.pte_size == sizeof (x86pte_t))
557 return (buf);
558 return (*pte32);
559 }
560
561 static int
562 do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap,
563 pfn_t *mfnp)
564 {
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;
576
577 if (asp != NULL) {
578 if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -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);
609 }
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);
615 }
616
617 if (htable.ht_vaddr != base ||
618 htable.ht_level != level)
619 continue;
620
621 pte = get_pte(&hat, &htable, addr);
622
623 if (print_level) {
624 mdb_printf("\tlevel=%d htable=%p "
625 "pte=%llr\n", level, ht, pte);
626 }
627
628 if (!PTE_ISVALID(pte)) {
629 mdb_printf("Address %p is unmapped.\n",
630 addr);
631 return (DCMD_ERR);
632 }
633
634 if (found)
635 continue;
636
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)
708 mdb_printf("\n");
709
710 return (DCMD_OK);
711 }
712
713 /*
714 * Report all hat's that either use PFN as a page table or that map the page.
715 */
716 static int
717 do_report_maps(pfn_t pfn)
718 {
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;
732
733 /*
734 * The hats are kept in a list with khat at the head.
735 */
736 for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
737 /*
738 * read the hat and its hash table
739 */
740 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
741 mdb_warn("Couldn't read struct hat\n");
742 return (DCMD_ERR);
743 }
744
745 /*
746 * read the htable hashtable
747 */
748 paddr = 0;
749 for (h = 0; h < hat.hat_num_hash; ++h) {
779 * otherwise, examine page mappings
780 */
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) {
788
789 base = htable.ht_vaddr + entry *
790 mmu.level_size[level];
791
792 /*
793 * only report kernel addresses once
794 */
795 if (hatp != khat &&
796 base >= kernelbase)
797 continue;
798
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;
807
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);
818 }
819 }
820 }
821 }
822
823 done:
824 return (DCMD_OK);
825 }
826
837 init_mmu();
838
839 if (mmu.num_level == 0)
840 return (DCMD_ERR);
841
842 if ((flags & DCMD_ADDRSPEC) == 0)
843 return (DCMD_USAGE);
844
845 if (mdb_getopts(argc, argv,
846 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
847 return (DCMD_USAGE);
848
849 pfn = (pfn_t)addr;
850 if (mflag)
851 pfn = mdb_mfn_to_pfn(pfn);
852
853 return (do_report_maps(pfn));
854 }
855
856 static int
857 do_ptable_dcmd(pfn_t pfn)
858 {
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;
873
874 /*
875 * The hats are kept in a list with khat at the head.
876 */
877 for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
878 /*
879 * read the hat and its hash table
880 */
881 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
882 mdb_warn("Couldn't read struct hat\n");
883 return (DCMD_ERR);
884 }
885
886 /*
887 * read the htable hashtable
888 */
889 paddr = 0;
890 for (h = 0; h < hat.hat_num_hash; ++h) {
895 }
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);
901 }
902
903 /*
904 * Is this the PFN for this htable
905 */
906 if (htable.ht_pfn == pfn)
907 goto found_it;
908 }
909 }
910 }
911
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;
923 }
924
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;
935
936 if (pte == 0)
937 continue;
938
939 mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize);
940 do_pte_dcmd(level, pte);
941 }
942
943 done:
944 return (DCMD_OK);
945 }
946
947 /*
948 * Dump the page table at the given PFN
949 */
950 /*ARGSUSED*/
951 int
952 ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
953 {
954 pfn_t pfn;
955 uint_t mflag = 0;
956
957 init_mmu();
958
959 if (mmu.num_level == 0)
960 return (DCMD_ERR);
961
962 if ((flags & DCMD_ADDRSPEC) == 0)
963 return (DCMD_USAGE);
964
965 if (mdb_getopts(argc, argv,
966 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
967 return (DCMD_USAGE);
968
969 pfn = (pfn_t)addr;
970 if (mflag)
971 pfn = mdb_mfn_to_pfn(pfn);
972
973 return (do_ptable_dcmd(pfn));
974 }
975
976 static int
977 do_htables_dcmd(hat_t *hatp)
978 {
979 struct hat hat;
980 htable_t *ht;
981 htable_t htable;
982 int h;
983
984 /*
985 * read the hat and its hash table
986 */
987 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
988 mdb_warn("Couldn't read struct hat\n");
989 return (DCMD_ERR);
990 }
991
992 /*
993 * read the htable hashtable
1013 /*
1014 * Dump the htables for the given hat
1015 */
1016 /*ARGSUSED*/
1017 int
1018 htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1019 {
1020 hat_t *hat;
1021
1022 init_mmu();
1023
1024 if (mmu.num_level == 0)
1025 return (DCMD_ERR);
1026
1027 if ((flags & DCMD_ADDRSPEC) == 0)
1028 return (DCMD_USAGE);
1029
1030 hat = (hat_t *)addr;
1031
1032 return (do_htables_dcmd(hat));
1033 }
|
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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2018 Joyent, Inc.
26 */
27
28 /*
29 * This part of the file contains the mdb support for dcmds:
30 * ::memseg_list
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 #define VA_SIGN_BIT (1UL << 47)
52 #define VA_SIGN_EXTEND(va) (((va) ^ VA_SIGN_BIT) - VA_SIGN_BIT)
53
54 struct pfn2pp {
55 pfn_t pfn;
56 page_t *pp;
57 };
58
59 static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *);
60 static void init_mmu(void);
61
62 int
63 platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
64 {
65 if (asp == NULL)
66 return (DCMD_ERR);
67
68 init_mmu();
69
70 if (mmu.num_level == 0)
71 return (DCMD_ERR);
72
73 return (do_va2pa(addr, asp, 0, pap, NULL));
386 }
387
388 mdb_printf("%lr\n", mfn);
389
390 if (flags & DCMD_LOOP)
391 mdb_set_dot(addr + 1);
392 return (DCMD_OK);
393 }
394
395 static pfn_t
396 pte2mfn(x86pte_t pte, uint_t level)
397 {
398 pfn_t mfn;
399 if (level > 0 && (pte & PT_PAGESIZE))
400 mfn = mmu_btop(pte & PT_PADDR_LGPG);
401 else
402 mfn = mmu_btop(pte & PT_PADDR);
403 return (mfn);
404 }
405
406 static int
407 do_pte_dcmd(int level, uint64_t pte)
408 {
409 static char *attr[] = {
410 "wrback", "wrthru", "uncached", "uncached",
411 "wrback", "wrthru", "wrcombine", "uncached"};
412 int pat_index = 0;
413 pfn_t mfn;
414
415 mdb_printf("pte=0x%llr: ", pte);
416
417 mfn = pte2mfn(pte, level);
418 mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn);
419
420 if (PTE_GET(pte, mmu.pt_nx))
421 mdb_printf("noexec ");
422
423 if (PTE_GET(pte, PT_NOCONSIST))
424 mdb_printf("noconsist ");
425
426 if (PTE_GET(pte, PT_NOSYNC))
427 mdb_printf("nosync ");
428
429 if (PTE_GET(pte, mmu.pt_global))
430 mdb_printf("global ");
431
432 if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
433 mdb_printf("largepage ");
434
435 if (level > 0 && PTE_GET(pte, PT_MOD))
436 mdb_printf("mod ");
437
438 if (level > 0 && PTE_GET(pte, PT_REF))
439 mdb_printf("ref ");
440
441 if (PTE_GET(pte, PT_USER))
442 mdb_printf("user ");
458
459 if (PTE_GET(pte, PT_NOCACHE))
460 pat_index += 2;
461
462 if (PTE_GET(pte, PT_WRITETHRU))
463 pat_index += 1;
464
465 if (pat_index != 0)
466 mdb_printf("%s", attr[pat_index]);
467
468 if (PTE_GET(pte, PT_VALID) == 0)
469 mdb_printf(" !VALID ");
470
471 mdb_printf("\n");
472 return (DCMD_OK);
473 }
474
475 /*
476 * Print a PTE in more human friendly way. The PTE is assumed to be in
477 * a level 0 page table, unless -l specifies another level.
478 */
479 /*ARGSUSED*/
480 int
481 pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
482 {
483 uint64_t level = 0;
484
485 init_mmu();
486
487 if (mmu.num_level == 0)
488 return (DCMD_ERR);
489
490 if ((flags & DCMD_ADDRSPEC) == 0)
491 return (DCMD_USAGE);
492
493 if (mdb_getopts(argc, argv,
494 'l', MDB_OPT_UINT64, &level) != argc)
495 return (DCMD_USAGE);
496
497 if (level > mmu.max_level) {
498 mdb_warn("invalid level %lu\n", level);
499 return (DCMD_ERR);
500 }
501
502 if (addr == 0)
503 return (DCMD_OK);
504
505 return (do_pte_dcmd((int)level, addr));
506 }
507
508 static size_t
509 va2entry(htable_t *htable, uintptr_t addr)
510 {
511 size_t entry = (addr - htable->ht_vaddr);
512
513 entry >>= mmu.level_shift[htable->ht_level];
514 return (entry & HTABLE_NUM_PTES(htable) - 1);
515 }
516
517 static x86pte_t
518 get_pte(hat_t *hat, htable_t *htable, uintptr_t addr)
519 {
520 x86pte_t buf;
521
522 if (htable->ht_flags & HTABLE_COPIED) {
523 uintptr_t ptr = (uintptr_t)hat->hat_copied_ptes;
524 ptr += va2entry(htable, addr) << mmu.pte_size_shift;
525 return (*(x86pte_t *)ptr);
526 }
527
528 paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn);
529 paddr += va2entry(htable, addr) << mmu.pte_size_shift;
530
531 if ((mdb_pread(&buf, mmu.pte_size, paddr)) == mmu.pte_size)
532 return (buf);
533
534 return (0);
535 }
536
537 static int
538 do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap,
539 pfn_t *mfnp)
540 {
541 struct as as;
542 struct hat *hatp;
543 struct hat hat;
544 htable_t *ht;
545 htable_t htable;
546 uintptr_t base;
547 int h;
548 int level;
549 int found = 0;
550 x86pte_t pte;
551 physaddr_t paddr;
552
553 if (asp != NULL) {
554 if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
580 for (h = 0; h < hat.hat_num_hash; ++h) {
581 if (mdb_vread(&ht, sizeof (htable_t *),
582 (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
583 mdb_warn("Couldn't read htable\n");
584 return (DCMD_ERR);
585 }
586 for (; ht != NULL; ht = htable.ht_next) {
587 if (mdb_vread(&htable, sizeof (htable_t),
588 (uintptr_t)ht) == -1) {
589 mdb_warn("Couldn't read htable\n");
590 return (DCMD_ERR);
591 }
592
593 if (htable.ht_vaddr != base ||
594 htable.ht_level != level)
595 continue;
596
597 pte = get_pte(&hat, &htable, addr);
598
599 if (print_level) {
600 mdb_printf("\tlevel=%d htable=0x%p "
601 "pte=0x%llr\n", level, ht, pte);
602 }
603
604 if (!PTE_ISVALID(pte)) {
605 mdb_printf("Address %p is unmapped.\n",
606 addr);
607 return (DCMD_ERR);
608 }
609
610 if (found)
611 continue;
612
613 if (PTE_IS_LGPG(pte, level))
614 paddr = mdb_ma_to_pa(pte &
615 PT_PADDR_LGPG);
616 else
617 paddr = mdb_ma_to_pa(pte & PT_PADDR);
618 paddr += addr & mmu.level_offset[level];
619 if (pap != NULL)
620 *pap = paddr;
621 if (mfnp != NULL)
684 mdb_printf("\n");
685
686 return (DCMD_OK);
687 }
688
689 /*
690 * Report all hat's that either use PFN as a page table or that map the page.
691 */
692 static int
693 do_report_maps(pfn_t pfn)
694 {
695 struct hat *hatp;
696 struct hat hat;
697 htable_t *ht;
698 htable_t htable;
699 uintptr_t base;
700 int h;
701 int level;
702 int entry;
703 x86pte_t pte;
704 physaddr_t paddr;
705 size_t len;
706
707 /*
708 * The hats are kept in a list with khat at the head.
709 */
710 for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
711 /*
712 * read the hat and its hash table
713 */
714 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
715 mdb_warn("Couldn't read struct hat\n");
716 return (DCMD_ERR);
717 }
718
719 /*
720 * read the htable hashtable
721 */
722 paddr = 0;
723 for (h = 0; h < hat.hat_num_hash; ++h) {
753 * otherwise, examine page mappings
754 */
755 level = htable.ht_level;
756 if (level > mmu.max_page_level)
757 continue;
758 paddr = mmu_ptob((physaddr_t)htable.ht_pfn);
759 for (entry = 0;
760 entry < HTABLE_NUM_PTES(&htable);
761 ++entry) {
762
763 base = htable.ht_vaddr + entry *
764 mmu.level_size[level];
765
766 /*
767 * only report kernel addresses once
768 */
769 if (hatp != khat &&
770 base >= kernelbase)
771 continue;
772
773 len = mdb_pread(&pte, mmu.pte_size,
774 paddr + entry * mmu.pte_size);
775 if (len != mmu.pte_size)
776 return (DCMD_ERR);
777
778 if ((pte & PT_VALID) == 0)
779 continue;
780 if (level == 0 || !(pte & PT_PAGESIZE))
781 pte &= PT_PADDR;
782 else
783 pte &= PT_PADDR_LGPG;
784 if (mmu_btop(mdb_ma_to_pa(pte)) != pfn)
785 continue;
786 mdb_printf("hat=%p maps addr=%p\n",
787 hatp, (caddr_t)base);
788 }
789 }
790 }
791 }
792
793 done:
794 return (DCMD_OK);
795 }
796
807 init_mmu();
808
809 if (mmu.num_level == 0)
810 return (DCMD_ERR);
811
812 if ((flags & DCMD_ADDRSPEC) == 0)
813 return (DCMD_USAGE);
814
815 if (mdb_getopts(argc, argv,
816 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
817 return (DCMD_USAGE);
818
819 pfn = (pfn_t)addr;
820 if (mflag)
821 pfn = mdb_mfn_to_pfn(pfn);
822
823 return (do_report_maps(pfn));
824 }
825
826 static int
827 do_ptable_dcmd(pfn_t pfn, uint64_t level)
828 {
829 struct hat *hatp;
830 struct hat hat;
831 htable_t *ht;
832 htable_t htable;
833 uintptr_t base;
834 int h;
835 int entry;
836 uintptr_t pagesize;
837 x86pte_t pte;
838 x86pte_t buf;
839 physaddr_t paddr;
840 size_t len;
841
842 /*
843 * The hats are kept in a list with khat at the head.
844 */
845 for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
846 /*
847 * read the hat and its hash table
848 */
849 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
850 mdb_warn("Couldn't read struct hat\n");
851 return (DCMD_ERR);
852 }
853
854 /*
855 * read the htable hashtable
856 */
857 paddr = 0;
858 for (h = 0; h < hat.hat_num_hash; ++h) {
863 }
864 for (; ht != NULL; ht = htable.ht_next) {
865 if (mdb_vread(&htable, sizeof (htable_t),
866 (uintptr_t)ht) == -1) {
867 mdb_warn("Couldn't read htable\n");
868 return (DCMD_ERR);
869 }
870
871 /*
872 * Is this the PFN for this htable
873 */
874 if (htable.ht_pfn == pfn)
875 goto found_it;
876 }
877 }
878 }
879
880 found_it:
881 if (htable.ht_pfn == pfn) {
882 mdb_printf("htable=%p\n", ht);
883 if (level == (uint64_t)-1) {
884 level = htable.ht_level;
885 } else if (htable.ht_level != level) {
886 mdb_warn("htable has level %d but forcing level %lu\n",
887 htable.ht_level, level);
888 }
889 base = htable.ht_vaddr;
890 pagesize = mmu.level_size[level];
891 } else {
892 if (level == (uint64_t)-1)
893 level = 0;
894 mdb_warn("couldn't find matching htable, using level=%lu, "
895 "base address=0x0\n", level);
896 base = 0;
897 pagesize = mmu.level_size[level];
898 }
899
900 paddr = mmu_ptob((physaddr_t)pfn);
901 for (entry = 0; entry < mmu.ptes_per_table; ++entry) {
902 len = mdb_pread(&buf, mmu.pte_size,
903 paddr + entry * mmu.pte_size);
904 if (len != mmu.pte_size)
905 return (DCMD_ERR);
906 pte = buf;
907
908 if (pte == 0)
909 continue;
910
911 mdb_printf("[%3d] va=0x%p ", entry,
912 VA_SIGN_EXTEND(base + entry * pagesize));
913 do_pte_dcmd(level, pte);
914 }
915
916 done:
917 return (DCMD_OK);
918 }
919
920 /*
921 * Dump the page table at the given PFN
922 */
923 /*ARGSUSED*/
924 int
925 ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
926 {
927 pfn_t pfn;
928 uint_t mflag = 0;
929 uint64_t level = (uint64_t)-1;
930
931 init_mmu();
932
933 if (mmu.num_level == 0)
934 return (DCMD_ERR);
935
936 if ((flags & DCMD_ADDRSPEC) == 0)
937 return (DCMD_USAGE);
938
939 if (mdb_getopts(argc, argv,
940 'm', MDB_OPT_SETBITS, TRUE, &mflag,
941 'l', MDB_OPT_UINT64, &level, NULL) != argc)
942 return (DCMD_USAGE);
943
944 if (level != (uint64_t)-1 && level > mmu.max_level) {
945 mdb_warn("invalid level %lu\n", level);
946 return (DCMD_ERR);
947 }
948
949 pfn = (pfn_t)addr;
950 if (mflag)
951 pfn = mdb_mfn_to_pfn(pfn);
952
953 return (do_ptable_dcmd(pfn, level));
954 }
955
956 static int
957 do_htables_dcmd(hat_t *hatp)
958 {
959 struct hat hat;
960 htable_t *ht;
961 htable_t htable;
962 int h;
963
964 /*
965 * read the hat and its hash table
966 */
967 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
968 mdb_warn("Couldn't read struct hat\n");
969 return (DCMD_ERR);
970 }
971
972 /*
973 * read the htable hashtable
993 /*
994 * Dump the htables for the given hat
995 */
996 /*ARGSUSED*/
997 int
998 htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
999 {
1000 hat_t *hat;
1001
1002 init_mmu();
1003
1004 if (mmu.num_level == 0)
1005 return (DCMD_ERR);
1006
1007 if ((flags & DCMD_ADDRSPEC) == 0)
1008 return (DCMD_USAGE);
1009
1010 hat = (hat_t *)addr;
1011
1012 return (do_htables_dcmd(hat));
1013 }
1014
1015 static uintptr_t
1016 entry2va(size_t *entries)
1017 {
1018 uintptr_t va = 0;
1019
1020 for (level_t l = mmu.max_level; l >= 0; l--)
1021 va += entries[l] << mmu.level_shift[l];
1022
1023 return (VA_SIGN_EXTEND(va));
1024 }
1025
1026 static void
1027 ptmap_report(size_t *entries, uintptr_t start,
1028 boolean_t user, boolean_t writable, boolean_t wflag)
1029 {
1030 uint64_t curva = entry2va(entries);
1031
1032 mdb_printf("mapped %s,%s range of %lu bytes: %a-%a\n",
1033 user ? "user" : "kernel", writable ? "writable" : "read-only",
1034 curva - start, start, curva - 1);
1035 if (wflag && start >= kernelbase)
1036 (void) mdb_call_dcmd("whatis", start, DCMD_ADDRSPEC, 0, NULL);
1037 }
1038
1039 int
1040 ptmap_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1041 {
1042 physaddr_t paddrs[MAX_NUM_LEVEL] = { 0, };
1043 size_t entry[MAX_NUM_LEVEL] = { 0, };
1044 uintptr_t start = (uintptr_t)-1;
1045 boolean_t writable = B_FALSE;
1046 boolean_t user = B_FALSE;
1047 boolean_t wflag = B_FALSE;
1048 level_t curlevel;
1049
1050 if ((flags & DCMD_ADDRSPEC) == 0)
1051 return (DCMD_USAGE);
1052
1053 if (mdb_getopts(argc, argv,
1054 'w', MDB_OPT_SETBITS, TRUE, &wflag, NULL) != argc)
1055 return (DCMD_USAGE);
1056
1057 init_mmu();
1058
1059 if (mmu.num_level == 0)
1060 return (DCMD_ERR);
1061
1062 curlevel = mmu.max_level;
1063
1064 paddrs[curlevel] = addr & MMU_PAGEMASK;
1065
1066 for (;;) {
1067 physaddr_t pte_addr;
1068 x86pte_t pte;
1069
1070 pte_addr = paddrs[curlevel] +
1071 (entry[curlevel] << mmu.pte_size_shift);
1072
1073 if (mdb_pread(&pte, sizeof (pte), pte_addr) != sizeof (pte)) {
1074 mdb_warn("couldn't read pte at %p", pte_addr);
1075 return (DCMD_ERR);
1076 }
1077
1078 if (PTE_GET(pte, PT_VALID) == 0) {
1079 if (start != (uintptr_t)-1) {
1080 ptmap_report(entry, start,
1081 user, writable, wflag);
1082 start = (uintptr_t)-1;
1083 }
1084 } else if (curlevel == 0 || PTE_GET(pte, PT_PAGESIZE)) {
1085 if (start == (uintptr_t)-1) {
1086 start = entry2va(entry);
1087 user = PTE_GET(pte, PT_USER);
1088 writable = PTE_GET(pte, PT_WRITABLE);
1089 } else if (user != PTE_GET(pte, PT_USER) ||
1090 writable != PTE_GET(pte, PT_WRITABLE)) {
1091 ptmap_report(entry, start,
1092 user, writable, wflag);
1093 start = entry2va(entry);
1094 user = PTE_GET(pte, PT_USER);
1095 writable = PTE_GET(pte, PT_WRITABLE);
1096 }
1097 } else {
1098 /* Descend a level. */
1099 physaddr_t pa = mmu_ptob(pte2mfn(pte, curlevel));
1100 paddrs[--curlevel] = pa;
1101 entry[curlevel] = 0;
1102 continue;
1103 }
1104
1105 while (++entry[curlevel] == mmu.ptes_per_table) {
1106 /* Ascend back up. */
1107 entry[curlevel] = 0;
1108 if (curlevel == mmu.max_level) {
1109 if (start != (uintptr_t)-1) {
1110 ptmap_report(entry, start,
1111 user, writable, wflag);
1112 }
1113 goto out;
1114 }
1115
1116 curlevel++;
1117 }
1118 }
1119
1120 out:
1121 return (DCMD_OK);
1122 }
|