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