1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 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));
  69 }
  70 
  71 /*
  72  * ::memseg_list dcmd and walker to implement it.
  73  */
  74 /*ARGSUSED*/
  75 int
  76 memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
  77 {
  78         struct memseg ms;
  79 
  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);
  85                 }
  86                 return (DCMD_OK);
  87         }
  88 
  89         if (DCMD_HDRSPEC(flags))
  90                 mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
  91                     "PAGES", "EPAGES", "BASE", "END");
  92 
  93         if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
  94                 mdb_warn("can't read memseg at %#lx", addr);
  95                 return (DCMD_ERR);
  96         }
  97 
  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);
 100 
 101         return (DCMD_OK);
 102 }
 103 
 104 /*
 105  * walk the memseg structures
 106  */
 107 int
 108 memseg_walk_init(mdb_walk_state_t *wsp)
 109 {
 110         if (wsp->walk_addr != NULL) {
 111                 mdb_warn("memseg only supports global walks\n");
 112                 return (WALK_ERR);
 113         }
 114 
 115         if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
 116                 mdb_warn("symbol 'memsegs' not found");
 117                 return (WALK_ERR);
 118         }
 119 
 120         wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
 121         return (WALK_NEXT);
 122 
 123 }
 124 
 125 int
 126 memseg_walk_step(mdb_walk_state_t *wsp)
 127 {
 128         int status;
 129 
 130         if (wsp->walk_addr == 0) {
 131                 return (WALK_DONE);
 132         }
 133 
 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);
 138         }
 139 
 140         status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
 141             wsp->walk_cbdata);
 142 
 143         wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
 144 
 145         return (status);
 146 }
 147 
 148 void
 149 memseg_walk_fini(mdb_walk_state_t *wsp)
 150 {
 151         mdb_free(wsp->walk_data, sizeof (struct memseg));
 152 }
 153 
 154 /*
 155  * Now HAT related dcmds.
 156  */
 157 
 158 static struct hat *khat;                /* value of kas.a_hat */
 159 struct hat_mmu_info mmu;
 160 uintptr_t kernelbase;
 161 
 162 /*
 163  * stuff for i86xpv images
 164  */
 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 */
 170 
 171 /*
 172  * read mmu parameters from kernel
 173  */
 174 static void
 175 init_mmu(void)
 176 {
 177         struct as kas;
 178 
 179         if (mmu.num_level != 0)
 180                 return;
 181 
 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;
 189 
 190         /*
 191          * Is this a paravirtualized domain image?
 192          */
 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;
 199         }
 200 
 201         is_xpv = mfn_list_addr != NULL;
 202 
 203 #ifndef _KMDB
 204         /*
 205          * recreate the local mfn_list
 206          */
 207         if (is_xpv) {
 208                 size_t sz = mfn_count * sizeof (pfn_t);
 209                 mfn_list = mdb_zalloc(sz, UM_SLEEP);
 210 
 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;
 215                 }
 216         }
 217 #endif
 218 }
 219 
 220 void
 221 free_mmu(void)
 222 {
 223 #ifdef __xpv
 224         if (mfn_list != NULL)
 225                 mdb_free(mfn_list, mfn_count * sizeof (mfn_t));
 226 #endif
 227 }
 228 
 229 #ifdef __xpv
 230 
 231 #ifdef _KMDB
 232 
 233 /*
 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.
 236  */
 237 
 238 pfn_t
 239 mdb_mfn_to_pfn(mfn_t mfn)
 240 {
 241         pfn_t pfn;
 242         mfn_t tmp;
 243         pfn_t *pfn_list;
 244 
 245         if (mfn_list_addr == NULL)
 246                 return (-(pfn_t)1);
 247 
 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);
 251 
 252         if (mdb_vread(&tmp, sizeof (tmp),
 253             (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
 254                 return (-(pfn_t)1);
 255 
 256         if (pfn >= mfn_count || tmp != mfn)
 257                 return (-(pfn_t)1);
 258 
 259         return (pfn);
 260 }
 261 
 262 mfn_t
 263 mdb_pfn_to_mfn(pfn_t pfn)
 264 {
 265         mfn_t mfn;
 266 
 267         init_mmu();
 268 
 269         if (mfn_list_addr == NULL || pfn >= mfn_count)
 270                 return (-(mfn_t)1);
 271 
 272         if (mdb_vread(&mfn, sizeof (mfn),
 273             (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
 274                 return (-(mfn_t)1);
 275 
 276         return (mfn);
 277 }
 278 
 279 #else /* _KMDB */
 280 
 281 /*
 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.
 286  */
 287 
 288 pfn_t
 289 mdb_mfn_to_pfn(mfn_t mfn)
 290 {
 291         pfn_t pfn;
 292 
 293         init_mmu();
 294 
 295         if (mfn_list == NULL)
 296                 return (-(pfn_t)1);
 297 
 298         for (pfn = 0; pfn < mfn_count; ++pfn) {
 299                 if (mfn_list[pfn] != mfn)
 300                         continue;
 301                 return (pfn);
 302         }
 303 
 304         return (-(pfn_t)1);
 305 }
 306 
 307 mfn_t
 308 mdb_pfn_to_mfn(pfn_t pfn)
 309 {
 310         init_mmu();
 311 
 312         if (mfn_list == NULL || pfn >= mfn_count)
 313                 return (-(mfn_t)1);
 314 
 315         return (mfn_list[pfn]);
 316 }
 317 
 318 #endif /* _KMDB */
 319 
 320 static paddr_t
 321 mdb_ma_to_pa(uint64_t ma)
 322 {
 323         pfn_t pfn = mdb_mfn_to_pfn(mmu_btop(ma));
 324         if (pfn == -(pfn_t)1)
 325                 return (-(paddr_t)1);
 326 
 327         return (mmu_ptob((paddr_t)pfn) | (ma & (MMU_PAGESIZE - 1)));
 328 }
 329 
 330 #else /* __xpv */
 331 
 332 #define mdb_ma_to_pa(ma) (ma)
 333 #define mdb_mfn_to_pfn(mfn) (mfn)
 334 #define mdb_pfn_to_mfn(pfn) (pfn)
 335 
 336 #endif /* __xpv */
 337 
 338 /*
 339  * ::mfntopfn dcmd translates hypervisor machine page number
 340  * to physical page number
 341  */
 342 /*ARGSUSED*/
 343 int
 344 mfntopfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 345 {
 346         pfn_t pfn;
 347 
 348         if ((flags & DCMD_ADDRSPEC) == 0) {
 349                 mdb_warn("MFN missing\n");
 350                 return (DCMD_USAGE);
 351         }
 352 
 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);
 356         }
 357 
 358         mdb_printf("%lr\n", pfn);
 359 
 360         return (DCMD_OK);
 361 }
 362 
 363 /*
 364  * ::pfntomfn dcmd translates physical page number to
 365  * hypervisor machine page number
 366  */
 367 /*ARGSUSED*/
 368 int
 369 pfntomfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 370 {
 371         pfn_t mfn;
 372 
 373         if ((flags & DCMD_ADDRSPEC) == 0) {
 374                 mdb_warn("PFN missing\n");
 375                 return (DCMD_USAGE);
 376         }
 377 
 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);
 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 ");
 444 
 445         if (PTE_GET(pte, PT_WRITABLE))
 446                 mdb_printf("write ");
 447 
 448         /*
 449          * Report non-standard cacheability
 450          */
 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;
 458         }
 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) {
 579                         mdb_warn("Couldn't read struct as\n");
 580                         return (DCMD_ERR);
 581                 }
 582                 hatp = as.a_hat;
 583         } else {
 584                 hatp = khat;
 585         }
 586 
 587         /*
 588          * read the hat and its hash table
 589          */
 590         if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
 591                 mdb_warn("Couldn't read struct hat\n");
 592                 return (DCMD_ERR);
 593         }
 594 
 595         /*
 596          * read the htable hashtable
 597          */
 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];
 603 
 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)
 646                                         *mfnp = pte2mfn(pte, level);
 647                                 found = 1;
 648                         }
 649                 }
 650         }
 651 
 652 done:
 653         if (!found)
 654                 return (DCMD_ERR);
 655         return (DCMD_OK);
 656 }
 657 
 658 int
 659 va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 660 {
 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;
 667 
 668         init_mmu();
 669 
 670         if (mmu.num_level == 0)
 671                 return (DCMD_ERR);
 672 
 673         if (mdb_getopts(argc, argv,
 674             'a', MDB_OPT_STR, &addrspace_str) != argc)
 675                 return (DCMD_USAGE);
 676 
 677         if ((flags & DCMD_ADDRSPEC) == 0)
 678                 return (DCMD_USAGE);
 679 
 680         /*
 681          * parse the address space
 682          */
 683         if (addrspace_str != NULL)
 684                 addrspace = mdb_strtoull(addrspace_str);
 685         else
 686                 addrspace = 0;
 687 
 688         rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn);
 689 
 690         if (rc != DCMD_OK)
 691                 return (rc);
 692 
 693         if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) {
 694                 mdb_warn("Invalid mfn %lr\n", mfn);
 695                 return (DCMD_ERR);
 696         }
 697 
 698         if (piped) {
 699                 mdb_printf("0x%lr\n", pfn);
 700                 return (DCMD_OK);
 701         }
 702 
 703         mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn);
 704 
 705         if (is_xpv)
 706                 mdb_printf(" (mfn 0x%lr)", mfn);
 707 
 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) {
 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);
 754                         }
 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);
 760                                 }
 761 
 762                                 /*
 763                                  * only report kernel addresses once
 764                                  */
 765                                 if (hatp != khat &&
 766                                     htable.ht_vaddr >= kernelbase)
 767                                         continue;
 768 
 769                                 /*
 770                                  * Is the PFN a pagetable itself?
 771                                  */
 772                                 if (htable.ht_pfn == pfn) {
 773                                         mdb_printf("Pagetable for "
 774                                             "hat=%p htable=%p\n", hatp, ht);
 775                                         continue;
 776                                 }
 777 
 778                                 /*
 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 
 827 /*
 828  * given a PFN as its address argument, prints out the uses of it
 829  */
 830 /*ARGSUSED*/
 831 int
 832 report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 833 {
 834         pfn_t pfn;
 835         uint_t mflag = 0;
 836 
 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) {
 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);
 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
 994          */
 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);
1000                 }
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);
1007                         }
1008                 }
1009         }
1010         return (DCMD_OK);
1011 }
1012 
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 }