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 }