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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 #pragma ident "%Z%%M% %I% %E% SMI" 26 27 /* 28 * This part of the file contains the mdb support for dcmds: 29 * ::memseg_list 30 * ::page_num2pp 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 struct pfn2pp { 52 pfn_t pfn; 53 page_t *pp; 54 }; 55 56 static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *); 57 static void init_mmu(void); 58 59 int 60 platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap) 61 { 62 if (asp == NULL) 63 return (DCMD_ERR); 64 65 init_mmu(); 66 67 if (mmu.num_level == 0) 68 return (DCMD_ERR); 69 70 return (do_va2pa(addr, asp, 0, pap, NULL)); 71 } 72 73 74 /*ARGSUSED*/ 75 int 76 page_num2pp_cb(uintptr_t addr, void *ignored, uintptr_t *data) 77 { 78 struct memseg ms, *msp = &ms; 79 struct pfn2pp *p = (struct pfn2pp *)data; 80 81 if (mdb_vread(msp, sizeof (struct memseg), addr) == -1) { 82 mdb_warn("can't read memseg at %#lx", addr); 83 return (DCMD_ERR); 84 } 85 86 if (p->pfn >= msp->pages_base && p->pfn < msp->pages_end) { 87 p->pp = msp->pages + (p->pfn - msp->pages_base); 88 return (WALK_DONE); 89 } 90 91 return (WALK_NEXT); 92 } 93 94 /* 95 * ::page_num2pp dcmd 96 */ 97 /*ARGSUSED*/ 98 int 99 page_num2pp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 100 { 101 struct pfn2pp pfn2pp; 102 page_t page; 103 104 if ((flags & DCMD_ADDRSPEC) == 0) { 105 mdb_warn("page frame number missing\n"); 106 return (DCMD_USAGE); 107 } 108 109 pfn2pp.pfn = (pfn_t)addr; 110 pfn2pp.pp = NULL; 111 112 if (mdb_walk("memseg", (mdb_walk_cb_t)page_num2pp_cb, 113 (void *)&pfn2pp) == -1) { 114 mdb_warn("can't walk memseg"); 115 return (DCMD_ERR); 116 } 117 118 if (pfn2pp.pp == NULL) 119 return (DCMD_ERR); 120 121 mdb_printf("%x has page at %p\n", pfn2pp.pfn, pfn2pp.pp); 122 123 if (mdb_vread(&page, sizeof (page_t), 124 (uintptr_t)pfn2pp.pp) == -1) { 125 mdb_warn("can't read page at %p", &page); 126 return (DCMD_ERR); 127 } 128 129 if (page.p_pagenum != pfn2pp.pfn) { 130 mdb_warn("WARNING! Found page structure contains " 131 "different pagenumber %x\n", page.p_pagenum); 132 } 133 134 return (DCMD_OK); 135 } 136 137 138 /* 139 * ::memseg_list dcmd and walker to implement it. 140 */ 141 /*ARGSUSED*/ 142 int 143 memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 144 { 145 struct memseg ms; 146 147 if (!(flags & DCMD_ADDRSPEC)) { 148 if (mdb_pwalk_dcmd("memseg", "memseg_list", 149 0, NULL, 0) == -1) { 150 mdb_warn("can't walk memseg"); 151 return (DCMD_ERR); 152 } 153 return (DCMD_OK); 154 } 155 156 if (DCMD_HDRSPEC(flags)) 157 mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR", 158 "PAGES", "EPAGES", "BASE", "END"); 159 160 if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) { 161 mdb_warn("can't read memseg at %#lx", addr); 162 return (DCMD_ERR); 163 } 164 165 mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr, 166 ms.pages, ms.epages, ms.pages_base, ms.pages_end); 167 168 return (DCMD_OK); 169 } 170 171 /* 172 * walk the memseg structures 173 */ 174 int 175 memseg_walk_init(mdb_walk_state_t *wsp) 176 { 177 if (wsp->walk_addr != NULL) { 178 mdb_warn("memseg only supports global walks\n"); 179 return (WALK_ERR); 180 } 181 182 if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) { 183 mdb_warn("symbol 'memsegs' not found"); 184 return (WALK_ERR); 185 } 186 187 wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP); 188 return (WALK_NEXT); 189 190 } 191 192 int 193 memseg_walk_step(mdb_walk_state_t *wsp) 194 { 195 int status; 196 197 if (wsp->walk_addr == 0) { 198 return (WALK_DONE); 199 } 200 201 if (mdb_vread(wsp->walk_data, sizeof (struct memseg), 202 wsp->walk_addr) == -1) { 203 mdb_warn("failed to read struct memseg at %p", wsp->walk_addr); 204 return (WALK_DONE); 205 } 206 207 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 208 wsp->walk_cbdata); 209 210 wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next); 211 212 return (status); 213 } 214 215 void 216 memseg_walk_fini(mdb_walk_state_t *wsp) 217 { 218 mdb_free(wsp->walk_data, sizeof (struct memseg)); 219 } 220 221 /* 222 * Now HAT related dcmds. 223 */ 224 225 static struct hat *khat; /* value of kas.a_hat */ 226 struct hat_mmu_info mmu; 227 uintptr_t kernelbase; 228 229 /* 230 * stuff for i86xpv images 231 */ 232 static int is_xpv; 233 static uintptr_t mfn_list_addr; /* kernel MFN list address */ 234 uintptr_t xen_virt_start; /* address of mfn_to_pfn[] table */ 235 ulong_t mfn_count; /* number of pfn's in the MFN list */ 236 pfn_t *mfn_list; /* local MFN list copy */ 237 238 /* 239 * read mmu parameters from kernel 240 */ 241 static void 242 init_mmu(void) 243 { 244 struct as kas; 245 246 if (mmu.num_level != 0) 247 return; 248 249 if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1) 250 mdb_warn("Can't use HAT information before mmu_init()\n"); 251 if (mdb_readsym(&kas, sizeof (kas), "kas") == -1) 252 mdb_warn("Couldn't find kas - kernel's struct as\n"); 253 if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1) 254 mdb_warn("Couldn't find kernelbase\n"); 255 khat = kas.a_hat; 256 257 /* 258 * Is this a paravirtualized domain image? 259 */ 260 if (mdb_readsym(&mfn_list_addr, sizeof (mfn_list_addr), 261 "mfn_list") == -1 || 262 mdb_readsym(&xen_virt_start, sizeof (xen_virt_start), 263 "xen_virt_start") == -1 || 264 mdb_readsym(&mfn_count, sizeof (mfn_count), "mfn_count") == -1) { 265 mfn_list_addr = NULL; 266 } 267 268 is_xpv = mfn_list_addr != NULL; 269 270 #ifndef _KMDB 271 /* 272 * recreate the local mfn_list 273 */ 274 if (is_xpv) { 275 size_t sz = mfn_count * sizeof (pfn_t); 276 mfn_list = mdb_zalloc(sz, UM_SLEEP); 277 278 if (mdb_vread(mfn_list, sz, (uintptr_t)mfn_list_addr) == -1) { 279 mdb_warn("Failed to read MFN list\n"); 280 mdb_free(mfn_list, sz); 281 mfn_list = NULL; 282 } 283 } 284 #endif 285 } 286 287 void 288 free_mmu(void) 289 { 290 #ifdef __xpv 291 if (mfn_list != NULL) 292 mdb_free(mfn_list, mfn_count * sizeof (mfn_t)); 293 #endif 294 } 295 296 #ifdef __xpv 297 298 #ifdef _KMDB 299 300 /* 301 * Convert between MFNs and PFNs. Since we're in kmdb we can go directly 302 * through the machine to phys mapping and the MFN list. 303 */ 304 305 pfn_t 306 mdb_mfn_to_pfn(mfn_t mfn) 307 { 308 pfn_t pfn; 309 mfn_t tmp; 310 pfn_t *pfn_list; 311 312 if (mfn_list_addr == NULL) 313 return (-(pfn_t)1); 314 315 pfn_list = (pfn_t *)xen_virt_start; 316 if (mdb_vread(&pfn, sizeof (pfn), (uintptr_t)(pfn_list + mfn)) == -1) 317 return (-(pfn_t)1); 318 319 if (mdb_vread(&tmp, sizeof (tmp), 320 (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1) 321 return (-(pfn_t)1); 322 323 if (pfn >= mfn_count || tmp != mfn) 324 return (-(pfn_t)1); 325 326 return (pfn); 327 } 328 329 mfn_t 330 mdb_pfn_to_mfn(pfn_t pfn) 331 { 332 mfn_t mfn; 333 334 init_mmu(); 335 336 if (mfn_list_addr == NULL || pfn >= mfn_count) 337 return (-(mfn_t)1); 338 339 if (mdb_vread(&mfn, sizeof (mfn), 340 (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1) 341 return (-(mfn_t)1); 342 343 return (mfn); 344 } 345 346 #else /* _KMDB */ 347 348 /* 349 * Convert between MFNs and PFNs. Since a crash dump doesn't include the 350 * MFN->PFN translation table (it's part of the hypervisor, not our image) 351 * we do the MFN->PFN translation by searching the PFN->MFN (mfn_list) 352 * table, if it's there. 353 */ 354 355 pfn_t 356 mdb_mfn_to_pfn(mfn_t mfn) 357 { 358 pfn_t pfn; 359 360 init_mmu(); 361 362 if (mfn_list == NULL) 363 return (-(pfn_t)1); 364 365 for (pfn = 0; pfn < mfn_count; ++pfn) { 366 if (mfn_list[pfn] != mfn) 367 continue; 368 return (pfn); 369 } 370 371 return (-(pfn_t)1); 372 } 373 374 mfn_t 375 mdb_pfn_to_mfn(pfn_t pfn) 376 { 377 init_mmu(); 378 379 if (mfn_list == NULL || pfn >= mfn_count) 380 return (-(mfn_t)1); 381 382 return (mfn_list[pfn]); 383 } 384 385 #endif /* _KMDB */ 386 387 static paddr_t 388 mdb_ma_to_pa(uint64_t ma) 389 { 390 pfn_t pfn = mdb_mfn_to_pfn(mmu_btop(ma)); 391 if (pfn == -(pfn_t)1) 392 return (-(paddr_t)1); 393 394 return (mmu_ptob((paddr_t)pfn) | (ma & (MMU_PAGESIZE - 1))); 395 } 396 397 #else /* __xpv */ 398 399 #define mdb_ma_to_pa(ma) (ma) 400 #define mdb_mfn_to_pfn(mfn) (mfn) 401 #define mdb_pfn_to_mfn(pfn) (pfn) 402 403 #endif /* __xpv */ 404 405 /* 406 * ::mfntopfn dcmd translates hypervisor machine page number 407 * to physical page number 408 */ 409 /*ARGSUSED*/ 410 int 411 mfntopfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 412 { 413 pfn_t pfn; 414 415 if ((flags & DCMD_ADDRSPEC) == 0) { 416 mdb_warn("MFN missing\n"); 417 return (DCMD_USAGE); 418 } 419 420 if ((pfn = mdb_mfn_to_pfn((pfn_t)addr)) == -(pfn_t)1) { 421 mdb_warn("Invalid mfn %lr\n", (pfn_t)addr); 422 return (DCMD_ERR); 423 } 424 425 mdb_printf("%lr\n", pfn); 426 427 return (DCMD_OK); 428 } 429 430 /* 431 * ::pfntomfn dcmd translates physical page number to 432 * hypervisor machine page number 433 */ 434 /*ARGSUSED*/ 435 int 436 pfntomfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 437 { 438 pfn_t mfn; 439 440 if ((flags & DCMD_ADDRSPEC) == 0) { 441 mdb_warn("PFN missing\n"); 442 return (DCMD_USAGE); 443 } 444 445 if ((mfn = mdb_pfn_to_mfn((pfn_t)addr)) == -(pfn_t)1) { 446 mdb_warn("Invalid pfn %lr\n", (pfn_t)addr); 447 return (DCMD_ABORT); 448 } 449 450 mdb_printf("%lr\n", mfn); 451 452 if (flags & DCMD_LOOP) 453 mdb_set_dot(addr + 1); 454 return (DCMD_OK); 455 } 456 457 static pfn_t 458 pte2mfn(x86pte_t pte, uint_t level) 459 { 460 pfn_t mfn; 461 if (level > 0 && (pte & PT_PAGESIZE)) 462 mfn = mmu_btop(pte & PT_PADDR_LGPG); 463 else 464 mfn = mmu_btop(pte & PT_PADDR); 465 return (mfn); 466 } 467 468 /* 469 * Print a PTE in more human friendly way. The PTE is assumed to be in 470 * a level 0 page table, unless -l specifies another level. 471 * 472 * The PTE value can be specified as the -p option, since on a 32 bit kernel 473 * with PAE running it's larger than a uintptr_t. 474 */ 475 static int 476 do_pte_dcmd(int level, uint64_t pte) 477 { 478 static char *attr[] = { 479 "wrback", "wrthru", "uncached", "uncached", 480 "wrback", "wrthru", "wrcombine", "uncached"}; 481 int pat_index = 0; 482 pfn_t mfn; 483 484 mdb_printf("pte=%llr: ", pte); 485 if (PTE_GET(pte, mmu.pt_nx)) 486 mdb_printf("noexec "); 487 488 mfn = pte2mfn(pte, level); 489 mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn); 490 491 if (PTE_GET(pte, PT_NOCONSIST)) 492 mdb_printf("noconsist "); 493 494 if (PTE_GET(pte, PT_NOSYNC)) 495 mdb_printf("nosync "); 496 497 if (PTE_GET(pte, mmu.pt_global)) 498 mdb_printf("global "); 499 500 if (level > 0 && PTE_GET(pte, PT_PAGESIZE)) 501 mdb_printf("largepage "); 502 503 if (level > 0 && PTE_GET(pte, PT_MOD)) 504 mdb_printf("mod "); 505 506 if (level > 0 && PTE_GET(pte, PT_REF)) 507 mdb_printf("ref "); 508 509 if (PTE_GET(pte, PT_USER)) 510 mdb_printf("user "); 511 512 if (PTE_GET(pte, PT_WRITABLE)) 513 mdb_printf("write "); 514 515 /* 516 * Report non-standard cacheability 517 */ 518 pat_index = 0; 519 if (level > 0) { 520 if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE)) 521 pat_index += 4; 522 } else { 523 if (PTE_GET(pte, PT_PAT_4K)) 524 pat_index += 4; 525 } 526 527 if (PTE_GET(pte, PT_NOCACHE)) 528 pat_index += 2; 529 530 if (PTE_GET(pte, PT_WRITETHRU)) 531 pat_index += 1; 532 533 if (pat_index != 0) 534 mdb_printf("%s", attr[pat_index]); 535 536 if (PTE_GET(pte, PT_VALID) == 0) 537 mdb_printf(" !VALID "); 538 539 mdb_printf("\n"); 540 return (DCMD_OK); 541 } 542 543 /* 544 * Print a PTE in more human friendly way. The PTE is assumed to be in 545 * a level 0 page table, unless -l specifies another level. 546 * 547 * The PTE value can be specified as the -p option, since on a 32 bit kernel 548 * with PAE running it's larger than a uintptr_t. 549 */ 550 /*ARGSUSED*/ 551 int 552 pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 553 { 554 int level = 0; 555 uint64_t pte = 0; 556 char *level_str = NULL; 557 char *pte_str = NULL; 558 559 init_mmu(); 560 561 if (mmu.num_level == 0) 562 return (DCMD_ERR); 563 564 if (mdb_getopts(argc, argv, 565 'p', MDB_OPT_STR, &pte_str, 566 'l', MDB_OPT_STR, &level_str) != argc) 567 return (DCMD_USAGE); 568 569 /* 570 * parse the PTE to decode, if it's 0, we don't do anything 571 */ 572 if (pte_str != NULL) { 573 pte = mdb_strtoull(pte_str); 574 } else { 575 if ((flags & DCMD_ADDRSPEC) == 0) 576 return (DCMD_USAGE); 577 pte = addr; 578 } 579 if (pte == 0) 580 return (DCMD_OK); 581 582 /* 583 * parse the level if supplied 584 */ 585 if (level_str != NULL) { 586 level = mdb_strtoull(level_str); 587 if (level < 0 || level > mmu.max_level) 588 return (DCMD_ERR); 589 } 590 591 return (do_pte_dcmd(level, pte)); 592 } 593 594 static size_t 595 va2entry(htable_t *htable, uintptr_t addr) 596 { 597 size_t entry = (addr - htable->ht_vaddr); 598 599 entry >>= mmu.level_shift[htable->ht_level]; 600 return (entry & HTABLE_NUM_PTES(htable) - 1); 601 } 602 603 static x86pte_t 604 get_pte(hat_t *hat, htable_t *htable, uintptr_t addr) 605 { 606 x86pte_t buf; 607 x86pte32_t *pte32 = (x86pte32_t *)&buf; 608 size_t len; 609 610 if (htable->ht_flags & HTABLE_VLP) { 611 uintptr_t ptr = (uintptr_t)hat->hat_vlp_ptes; 612 ptr += va2entry(htable, addr) << mmu.pte_size_shift; 613 len = mdb_vread(&buf, mmu.pte_size, ptr); 614 } else { 615 paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn); 616 paddr += va2entry(htable, addr) << mmu.pte_size_shift; 617 len = mdb_pread(&buf, mmu.pte_size, paddr); 618 } 619 620 if (len != mmu.pte_size) 621 return (0); 622 623 if (mmu.pte_size == sizeof (x86pte_t)) 624 return (buf); 625 return (*pte32); 626 } 627 628 static int 629 do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap, 630 pfn_t *mfnp) 631 { 632 struct as as; 633 struct hat *hatp; 634 struct hat hat; 635 htable_t *ht; 636 htable_t htable; 637 uintptr_t base; 638 int h; 639 int level; 640 int found = 0; 641 x86pte_t pte; 642 physaddr_t paddr; 643 644 if (asp != NULL) { 645 if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) { 646 mdb_warn("Couldn't read struct as\n"); 647 return (DCMD_ERR); 648 } 649 hatp = as.a_hat; 650 } else { 651 hatp = khat; 652 } 653 654 /* 655 * read the hat and its hash table 656 */ 657 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) { 658 mdb_warn("Couldn't read struct hat\n"); 659 return (DCMD_ERR); 660 } 661 662 /* 663 * read the htable hashtable 664 */ 665 for (level = 0; level <= mmu.max_level; ++level) { 666 if (level == TOP_LEVEL(&hat)) 667 base = 0; 668 else 669 base = addr & mmu.level_mask[level + 1]; 670 671 for (h = 0; h < hat.hat_num_hash; ++h) { 672 if (mdb_vread(&ht, sizeof (htable_t *), 673 (uintptr_t)(hat.hat_ht_hash + h)) == -1) { 674 mdb_warn("Couldn't read htable\n"); 675 return (DCMD_ERR); 676 } 677 for (; ht != NULL; ht = htable.ht_next) { 678 if (mdb_vread(&htable, sizeof (htable_t), 679 (uintptr_t)ht) == -1) { 680 mdb_warn("Couldn't read htable\n"); 681 return (DCMD_ERR); 682 } 683 684 if (htable.ht_vaddr != base || 685 htable.ht_level != level) 686 continue; 687 688 pte = get_pte(&hat, &htable, addr); 689 690 if (print_level) { 691 mdb_printf("\tlevel=%d htable=%p " 692 "pte=%llr\n", level, ht, pte); 693 } 694 695 if (!PTE_ISVALID(pte)) { 696 mdb_printf("Address %p is unmapped.\n", 697 addr); 698 return (DCMD_ERR); 699 } 700 701 if (found) 702 continue; 703 704 if (PTE_IS_LGPG(pte, level)) 705 paddr = mdb_ma_to_pa(pte & 706 PT_PADDR_LGPG); 707 else 708 paddr = mdb_ma_to_pa(pte & PT_PADDR); 709 paddr += addr & mmu.level_offset[level]; 710 if (pap != NULL) 711 *pap = paddr; 712 if (mfnp != NULL) 713 *mfnp = pte2mfn(pte, level); 714 found = 1; 715 } 716 } 717 } 718 719 done: 720 if (!found) 721 return (DCMD_ERR); 722 return (DCMD_OK); 723 } 724 725 int 726 va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 727 { 728 uintptr_t addrspace; 729 char *addrspace_str = NULL; 730 int piped = flags & DCMD_PIPE_OUT; 731 pfn_t pfn; 732 pfn_t mfn; 733 int rc; 734 735 init_mmu(); 736 737 if (mmu.num_level == 0) 738 return (DCMD_ERR); 739 740 if (mdb_getopts(argc, argv, 741 'a', MDB_OPT_STR, &addrspace_str) != argc) 742 return (DCMD_USAGE); 743 744 if ((flags & DCMD_ADDRSPEC) == 0) 745 return (DCMD_USAGE); 746 747 /* 748 * parse the address space 749 */ 750 if (addrspace_str != NULL) 751 addrspace = mdb_strtoull(addrspace_str); 752 else 753 addrspace = 0; 754 755 rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn); 756 757 if (rc != DCMD_OK) 758 return (rc); 759 760 if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) { 761 mdb_warn("Invalid mfn %lr\n", mfn); 762 return (DCMD_ERR); 763 } 764 765 if (piped) { 766 mdb_printf("0x%lr\n", pfn); 767 return (DCMD_OK); 768 } 769 770 mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn); 771 772 if (is_xpv) 773 mdb_printf(" (mfn 0x%lr)", mfn); 774 775 mdb_printf("\n"); 776 777 return (DCMD_OK); 778 } 779 780 /* 781 * Report all hat's that either use PFN as a page table or that map the page. 782 */ 783 static int 784 do_report_maps(pfn_t pfn) 785 { 786 struct hat *hatp; 787 struct hat hat; 788 htable_t *ht; 789 htable_t htable; 790 uintptr_t base; 791 int h; 792 int level; 793 int entry; 794 x86pte_t pte; 795 x86pte_t buf; 796 x86pte32_t *pte32 = (x86pte32_t *)&buf; 797 physaddr_t paddr; 798 size_t len; 799 800 /* 801 * The hats are kept in a list with khat at the head. 802 */ 803 for (hatp = khat; hatp != NULL; hatp = hat.hat_next) { 804 /* 805 * read the hat and its hash table 806 */ 807 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) { 808 mdb_warn("Couldn't read struct hat\n"); 809 return (DCMD_ERR); 810 } 811 812 /* 813 * read the htable hashtable 814 */ 815 paddr = 0; 816 for (h = 0; h < hat.hat_num_hash; ++h) { 817 if (mdb_vread(&ht, sizeof (htable_t *), 818 (uintptr_t)(hat.hat_ht_hash + h)) == -1) { 819 mdb_warn("Couldn't read htable\n"); 820 return (DCMD_ERR); 821 } 822 for (; ht != NULL; ht = htable.ht_next) { 823 if (mdb_vread(&htable, sizeof (htable_t), 824 (uintptr_t)ht) == -1) { 825 mdb_warn("Couldn't read htable\n"); 826 return (DCMD_ERR); 827 } 828 829 /* 830 * only report kernel addresses once 831 */ 832 if (hatp != khat && 833 htable.ht_vaddr >= kernelbase) 834 continue; 835 836 /* 837 * Is the PFN a pagetable itself? 838 */ 839 if (htable.ht_pfn == pfn) { 840 mdb_printf("Pagetable for " 841 "hat=%p htable=%p\n", hatp, ht); 842 continue; 843 } 844 845 /* 846 * otherwise, examine page mappings 847 */ 848 level = htable.ht_level; 849 if (level > mmu.max_page_level) 850 continue; 851 paddr = mmu_ptob((physaddr_t)htable.ht_pfn); 852 for (entry = 0; 853 entry < HTABLE_NUM_PTES(&htable); 854 ++entry) { 855 856 base = htable.ht_vaddr + entry * 857 mmu.level_size[level]; 858 859 /* 860 * only report kernel addresses once 861 */ 862 if (hatp != khat && 863 base >= kernelbase) 864 continue; 865 866 len = mdb_pread(&buf, mmu.pte_size, 867 paddr + entry * mmu.pte_size); 868 if (len != mmu.pte_size) 869 return (DCMD_ERR); 870 if (mmu.pte_size == sizeof (x86pte_t)) 871 pte = buf; 872 else 873 pte = *pte32; 874 875 if ((pte & PT_VALID) == 0) 876 continue; 877 if (level == 0 || !(pte & PT_PAGESIZE)) 878 pte &= PT_PADDR; 879 else 880 pte &= PT_PADDR_LGPG; 881 if (mmu_btop(mdb_ma_to_pa(pte)) != pfn) 882 continue; 883 mdb_printf("hat=%p maps addr=%p\n", 884 hatp, (caddr_t)base); 885 } 886 } 887 } 888 } 889 890 done: 891 return (DCMD_OK); 892 } 893 894 /* 895 * given a PFN as its address argument, prints out the uses of it 896 */ 897 /*ARGSUSED*/ 898 int 899 report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 900 { 901 pfn_t pfn; 902 uint_t mflag = 0; 903 904 init_mmu(); 905 906 if (mmu.num_level == 0) 907 return (DCMD_ERR); 908 909 if ((flags & DCMD_ADDRSPEC) == 0) 910 return (DCMD_USAGE); 911 912 if (mdb_getopts(argc, argv, 913 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc) 914 return (DCMD_USAGE); 915 916 pfn = (pfn_t)addr; 917 if (mflag) 918 pfn = mdb_mfn_to_pfn(pfn); 919 920 return (do_report_maps(pfn)); 921 } 922 923 static int 924 do_ptable_dcmd(pfn_t pfn) 925 { 926 struct hat *hatp; 927 struct hat hat; 928 htable_t *ht; 929 htable_t htable; 930 uintptr_t base; 931 int h; 932 int level; 933 int entry; 934 uintptr_t pagesize; 935 x86pte_t pte; 936 x86pte_t buf; 937 x86pte32_t *pte32 = (x86pte32_t *)&buf; 938 physaddr_t paddr; 939 size_t len; 940 941 /* 942 * The hats are kept in a list with khat at the head. 943 */ 944 for (hatp = khat; hatp != NULL; hatp = hat.hat_next) { 945 /* 946 * read the hat and its hash table 947 */ 948 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) { 949 mdb_warn("Couldn't read struct hat\n"); 950 return (DCMD_ERR); 951 } 952 953 /* 954 * read the htable hashtable 955 */ 956 paddr = 0; 957 for (h = 0; h < hat.hat_num_hash; ++h) { 958 if (mdb_vread(&ht, sizeof (htable_t *), 959 (uintptr_t)(hat.hat_ht_hash + h)) == -1) { 960 mdb_warn("Couldn't read htable\n"); 961 return (DCMD_ERR); 962 } 963 for (; ht != NULL; ht = htable.ht_next) { 964 if (mdb_vread(&htable, sizeof (htable_t), 965 (uintptr_t)ht) == -1) { 966 mdb_warn("Couldn't read htable\n"); 967 return (DCMD_ERR); 968 } 969 970 /* 971 * Is this the PFN for this htable 972 */ 973 if (htable.ht_pfn == pfn) 974 goto found_it; 975 } 976 } 977 } 978 979 found_it: 980 if (htable.ht_pfn == pfn) { 981 mdb_printf("htable=%p\n", ht); 982 level = htable.ht_level; 983 base = htable.ht_vaddr; 984 pagesize = mmu.level_size[level]; 985 } else { 986 mdb_printf("Unknown pagetable - assuming level/addr 0"); 987 level = 0; /* assume level == 0 for PFN */ 988 base = 0; 989 pagesize = MMU_PAGESIZE; 990 } 991 992 paddr = mmu_ptob((physaddr_t)pfn); 993 for (entry = 0; entry < mmu.ptes_per_table; ++entry) { 994 len = mdb_pread(&buf, mmu.pte_size, 995 paddr + entry * mmu.pte_size); 996 if (len != mmu.pte_size) 997 return (DCMD_ERR); 998 if (mmu.pte_size == sizeof (x86pte_t)) 999 pte = buf; 1000 else 1001 pte = *pte32; 1002 1003 if (pte == 0) 1004 continue; 1005 1006 mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize); 1007 do_pte_dcmd(level, pte); 1008 } 1009 1010 done: 1011 return (DCMD_OK); 1012 } 1013 1014 /* 1015 * Dump the page table at the given PFN 1016 */ 1017 /*ARGSUSED*/ 1018 int 1019 ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1020 { 1021 pfn_t pfn; 1022 uint_t mflag = 0; 1023 1024 init_mmu(); 1025 1026 if (mmu.num_level == 0) 1027 return (DCMD_ERR); 1028 1029 if ((flags & DCMD_ADDRSPEC) == 0) 1030 return (DCMD_USAGE); 1031 1032 if (mdb_getopts(argc, argv, 1033 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc) 1034 return (DCMD_USAGE); 1035 1036 pfn = (pfn_t)addr; 1037 if (mflag) 1038 pfn = mdb_mfn_to_pfn(pfn); 1039 1040 return (do_ptable_dcmd(pfn)); 1041 } 1042 1043 static int 1044 do_htables_dcmd(hat_t *hatp) 1045 { 1046 struct hat hat; 1047 htable_t *ht; 1048 htable_t htable; 1049 int h; 1050 1051 /* 1052 * read the hat and its hash table 1053 */ 1054 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) { 1055 mdb_warn("Couldn't read struct hat\n"); 1056 return (DCMD_ERR); 1057 } 1058 1059 /* 1060 * read the htable hashtable 1061 */ 1062 for (h = 0; h < hat.hat_num_hash; ++h) { 1063 if (mdb_vread(&ht, sizeof (htable_t *), 1064 (uintptr_t)(hat.hat_ht_hash + h)) == -1) { 1065 mdb_warn("Couldn't read htable ptr\\n"); 1066 return (DCMD_ERR); 1067 } 1068 for (; ht != NULL; ht = htable.ht_next) { 1069 mdb_printf("%p\n", ht); 1070 if (mdb_vread(&htable, sizeof (htable_t), 1071 (uintptr_t)ht) == -1) { 1072 mdb_warn("Couldn't read htable\n"); 1073 return (DCMD_ERR); 1074 } 1075 } 1076 } 1077 return (DCMD_OK); 1078 } 1079 1080 /* 1081 * Dump the htables for the given hat 1082 */ 1083 /*ARGSUSED*/ 1084 int 1085 htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1086 { 1087 hat_t *hat; 1088 1089 init_mmu(); 1090 1091 if (mmu.num_level == 0) 1092 return (DCMD_ERR); 1093 1094 if ((flags & DCMD_ADDRSPEC) == 0) 1095 return (DCMD_USAGE); 1096 1097 hat = (hat_t *)addr; 1098 1099 return (do_htables_dcmd(hat)); 1100 } 1101