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