Print this page
8956 Implement KPTI
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>


   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 }