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