1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * This part of the file contains the mdb support for dcmds: 31*0Sstevel@tonic-gate * ::memseg_list 32*0Sstevel@tonic-gate * ::page_num2pp 33*0Sstevel@tonic-gate * and walkers for: 34*0Sstevel@tonic-gate * memseg - a memseg list walker for ::memseg_list 35*0Sstevel@tonic-gate * 36*0Sstevel@tonic-gate */ 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate #include <sys/types.h> 39*0Sstevel@tonic-gate #include <sys/machparam.h> 40*0Sstevel@tonic-gate #include <sys/controlregs.h> 41*0Sstevel@tonic-gate #include <vm/as.h> 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 44*0Sstevel@tonic-gate #include <mdb/mdb_target.h> 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate #include <vm/page.h> 47*0Sstevel@tonic-gate #include <vm/hat_i86.h> 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate struct pfn2pp { 50*0Sstevel@tonic-gate pfn_t pfn; 51*0Sstevel@tonic-gate page_t *pp; 52*0Sstevel@tonic-gate }; 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate static int do_va2pfn(uintptr_t, struct as *, int, physaddr_t *); 55*0Sstevel@tonic-gate static void get_mmu(void); 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate int 58*0Sstevel@tonic-gate platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap) 59*0Sstevel@tonic-gate { 60*0Sstevel@tonic-gate if (asp == NULL) 61*0Sstevel@tonic-gate return (DCMD_ERR); 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate /* 64*0Sstevel@tonic-gate * The kernel has to at least have made it thru mmu_init() 65*0Sstevel@tonic-gate */ 66*0Sstevel@tonic-gate get_mmu(); 67*0Sstevel@tonic-gate if (mmu.num_level == 0) 68*0Sstevel@tonic-gate return (DCMD_ERR); 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate return (do_va2pfn(addr, asp, 0, pap)); 71*0Sstevel@tonic-gate } 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate /*ARGSUSED*/ 75*0Sstevel@tonic-gate int 76*0Sstevel@tonic-gate page_num2pp_cb(uintptr_t addr, void *ignored, uintptr_t *data) 77*0Sstevel@tonic-gate { 78*0Sstevel@tonic-gate struct memseg ms, *msp = &ms; 79*0Sstevel@tonic-gate struct pfn2pp *p = (struct pfn2pp *)data; 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate if (mdb_vread(msp, sizeof (struct memseg), addr) == -1) { 82*0Sstevel@tonic-gate mdb_warn("can't read memseg at %#lx", addr); 83*0Sstevel@tonic-gate return (DCMD_ERR); 84*0Sstevel@tonic-gate } 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate if (p->pfn >= msp->pages_base && p->pfn < msp->pages_end) { 87*0Sstevel@tonic-gate p->pp = msp->pages + (p->pfn - msp->pages_base); 88*0Sstevel@tonic-gate return (WALK_DONE); 89*0Sstevel@tonic-gate } 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate return (WALK_NEXT); 92*0Sstevel@tonic-gate } 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate /* 95*0Sstevel@tonic-gate * ::page_num2pp dcmd 96*0Sstevel@tonic-gate */ 97*0Sstevel@tonic-gate /*ARGSUSED*/ 98*0Sstevel@tonic-gate int 99*0Sstevel@tonic-gate page_num2pp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 100*0Sstevel@tonic-gate { 101*0Sstevel@tonic-gate struct pfn2pp pfn2pp; 102*0Sstevel@tonic-gate page_t page; 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0) { 105*0Sstevel@tonic-gate mdb_warn("page frame number missing\n"); 106*0Sstevel@tonic-gate return (DCMD_USAGE); 107*0Sstevel@tonic-gate } 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate pfn2pp.pfn = (pfn_t)addr; 110*0Sstevel@tonic-gate pfn2pp.pp = NULL; 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate if (mdb_walk("memseg", (mdb_walk_cb_t)page_num2pp_cb, 113*0Sstevel@tonic-gate (void *)&pfn2pp) == -1) { 114*0Sstevel@tonic-gate mdb_warn("can't walk memseg"); 115*0Sstevel@tonic-gate return (DCMD_ERR); 116*0Sstevel@tonic-gate } 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate if (pfn2pp.pp == NULL) 119*0Sstevel@tonic-gate return (DCMD_ERR); 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate mdb_printf("%x has page at %p\n", pfn2pp.pfn, pfn2pp.pp); 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate if (mdb_vread(&page, sizeof (page_t), 124*0Sstevel@tonic-gate (uintptr_t)pfn2pp.pp) == -1) { 125*0Sstevel@tonic-gate mdb_warn("can't read page at %p", &page); 126*0Sstevel@tonic-gate return (DCMD_ERR); 127*0Sstevel@tonic-gate } 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate if (page.p_pagenum != pfn2pp.pfn) { 130*0Sstevel@tonic-gate mdb_warn("WARNING! Found page structure contains " 131*0Sstevel@tonic-gate "different pagenumber %x\n", page.p_pagenum); 132*0Sstevel@tonic-gate } 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate return (DCMD_OK); 135*0Sstevel@tonic-gate } 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate /* 142*0Sstevel@tonic-gate * ::memseg_list dcmd and walker to implement it. 143*0Sstevel@tonic-gate */ 144*0Sstevel@tonic-gate /*ARGSUSED*/ 145*0Sstevel@tonic-gate int 146*0Sstevel@tonic-gate memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 147*0Sstevel@tonic-gate { 148*0Sstevel@tonic-gate struct memseg ms; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) { 151*0Sstevel@tonic-gate if (mdb_pwalk_dcmd("memseg", "memseg_list", 152*0Sstevel@tonic-gate 0, NULL, 0) == -1) { 153*0Sstevel@tonic-gate mdb_warn("can't walk memseg"); 154*0Sstevel@tonic-gate return (DCMD_ERR); 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate return (DCMD_OK); 157*0Sstevel@tonic-gate } 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) 160*0Sstevel@tonic-gate mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR", 161*0Sstevel@tonic-gate "PAGES", "EPAGES", "BASE", "END"); 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) { 164*0Sstevel@tonic-gate mdb_warn("can't read memseg at %#lx", addr); 165*0Sstevel@tonic-gate return (DCMD_ERR); 166*0Sstevel@tonic-gate } 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr, 169*0Sstevel@tonic-gate ms.pages, ms.epages, ms.pages_base, ms.pages_end); 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate return (DCMD_OK); 172*0Sstevel@tonic-gate } 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate /* 175*0Sstevel@tonic-gate * walk the memseg structures 176*0Sstevel@tonic-gate */ 177*0Sstevel@tonic-gate int 178*0Sstevel@tonic-gate memseg_walk_init(mdb_walk_state_t *wsp) 179*0Sstevel@tonic-gate { 180*0Sstevel@tonic-gate if (wsp->walk_addr != NULL) { 181*0Sstevel@tonic-gate mdb_warn("memseg only supports global walks\n"); 182*0Sstevel@tonic-gate return (WALK_ERR); 183*0Sstevel@tonic-gate } 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) { 186*0Sstevel@tonic-gate mdb_warn("symbol 'memsegs' not found"); 187*0Sstevel@tonic-gate return (WALK_ERR); 188*0Sstevel@tonic-gate } 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP); 191*0Sstevel@tonic-gate return (WALK_NEXT); 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate int 196*0Sstevel@tonic-gate memseg_walk_step(mdb_walk_state_t *wsp) 197*0Sstevel@tonic-gate { 198*0Sstevel@tonic-gate int status; 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate if (wsp->walk_addr == 0) { 201*0Sstevel@tonic-gate return (WALK_DONE); 202*0Sstevel@tonic-gate } 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate if (mdb_vread(wsp->walk_data, sizeof (struct memseg), 205*0Sstevel@tonic-gate wsp->walk_addr) == -1) { 206*0Sstevel@tonic-gate mdb_warn("failed to read struct memseg at %p", wsp->walk_addr); 207*0Sstevel@tonic-gate return (WALK_DONE); 208*0Sstevel@tonic-gate } 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 211*0Sstevel@tonic-gate wsp->walk_cbdata); 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next); 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate return (status); 216*0Sstevel@tonic-gate } 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate void 219*0Sstevel@tonic-gate memseg_walk_fini(mdb_walk_state_t *wsp) 220*0Sstevel@tonic-gate { 221*0Sstevel@tonic-gate mdb_free(wsp->walk_data, sizeof (struct memseg)); 222*0Sstevel@tonic-gate } 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /* 225*0Sstevel@tonic-gate * HAT related dcmds: 226*0Sstevel@tonic-gate * 227*0Sstevel@tonic-gate * ::pte [-p XXXXXXXX] [-l 0/1/2/3] 228*0Sstevel@tonic-gate * 229*0Sstevel@tonic-gate * dcmd that interprets the -p argument as a page table entry and 230*0Sstevel@tonic-gate * prints it in more human readable form. The PTE is assumed to be in 231*0Sstevel@tonic-gate * a level 0 page table, unless -l specifies another level. 232*0Sstevel@tonic-gate * 233*0Sstevel@tonic-gate * ::vatopfn [-v] [-a as] 234*0Sstevel@tonic-gate * 235*0Sstevel@tonic-gate * Given a virtual address, returns the PFN, if any, mapped at the address. 236*0Sstevel@tonic-gate * -v shows the intermediate htable/page table entries used to resolve the 237*0Sstevel@tonic-gate * mapping. By default the virtual address is assumed to be in the kernel's 238*0Sstevel@tonic-gate * address space. -a is used to specify a different address space. 239*0Sstevel@tonic-gate */ 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate struct hat *khat; /* value of kas.a_hat */ 242*0Sstevel@tonic-gate struct hat_mmu_info mmu; 243*0Sstevel@tonic-gate uintptr_t kernelbase; 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate /* 246*0Sstevel@tonic-gate * read mmu parameters from kernel 247*0Sstevel@tonic-gate */ 248*0Sstevel@tonic-gate static void 249*0Sstevel@tonic-gate get_mmu(void) 250*0Sstevel@tonic-gate { 251*0Sstevel@tonic-gate struct as kas; 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate if (mmu.num_level != 0) 254*0Sstevel@tonic-gate return; 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1) 257*0Sstevel@tonic-gate mdb_warn("Can't use HAT information before mmu_init()\n"); 258*0Sstevel@tonic-gate if (mdb_readsym(&kas, sizeof (kas), "kas") == -1) 259*0Sstevel@tonic-gate mdb_warn("Couldn't find kas - kernel's struct as\n"); 260*0Sstevel@tonic-gate if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1) 261*0Sstevel@tonic-gate mdb_warn("Couldn't find kernelbase\n"); 262*0Sstevel@tonic-gate khat = kas.a_hat; 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate /* 266*0Sstevel@tonic-gate * Print a PTE in more human friendly way. The PTE is assumed to be in 267*0Sstevel@tonic-gate * a level 0 page table, unless -l specifies another level. 268*0Sstevel@tonic-gate * 269*0Sstevel@tonic-gate * The PTE value can be specified as the -p option, since on a 32 bit kernel 270*0Sstevel@tonic-gate * with PAE running it's larger than a uintptr_t. 271*0Sstevel@tonic-gate */ 272*0Sstevel@tonic-gate static int 273*0Sstevel@tonic-gate do_pte_dcmd(int level, uint64_t pte) 274*0Sstevel@tonic-gate { 275*0Sstevel@tonic-gate static char *attr[] = { 276*0Sstevel@tonic-gate "wrback", "wrthru", "uncached", "uncached", 277*0Sstevel@tonic-gate "wrback", "wrthru", "wrcombine", "uncached"}; 278*0Sstevel@tonic-gate int pat_index = 0; 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate mdb_printf("PTE=%llx: ", pte); 281*0Sstevel@tonic-gate if (PTE_GET(pte, mmu.pt_nx)) 282*0Sstevel@tonic-gate mdb_printf("noexec "); 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate mdb_printf("page=0x%llx ", PTE2PFN(pte, level)); 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate if (PTE_GET(pte, PT_NOCONSIST)) 287*0Sstevel@tonic-gate mdb_printf("noconsist "); 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate if (PTE_GET(pte, PT_NOSYNC)) 290*0Sstevel@tonic-gate mdb_printf("nosync "); 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate if (PTE_GET(pte, mmu.pt_global)) 293*0Sstevel@tonic-gate mdb_printf("global "); 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate if (level > 0 && PTE_GET(pte, PT_PAGESIZE)) 296*0Sstevel@tonic-gate mdb_printf("largepage "); 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate if (level > 0 && PTE_GET(pte, PT_MOD)) 299*0Sstevel@tonic-gate mdb_printf("mod "); 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate if (level > 0 && PTE_GET(pte, PT_REF)) 302*0Sstevel@tonic-gate mdb_printf("ref "); 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate if (PTE_GET(pte, PT_USER)) 305*0Sstevel@tonic-gate mdb_printf("user "); 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate if (PTE_GET(pte, PT_WRITABLE)) 308*0Sstevel@tonic-gate mdb_printf("write "); 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate /* 311*0Sstevel@tonic-gate * Report non-standard cacheability 312*0Sstevel@tonic-gate */ 313*0Sstevel@tonic-gate pat_index = 0; 314*0Sstevel@tonic-gate if (level > 0) { 315*0Sstevel@tonic-gate if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE)) 316*0Sstevel@tonic-gate pat_index += 4; 317*0Sstevel@tonic-gate } else { 318*0Sstevel@tonic-gate if (PTE_GET(pte, PT_PAT_4K)) 319*0Sstevel@tonic-gate pat_index += 4; 320*0Sstevel@tonic-gate } 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate if (PTE_GET(pte, PT_NOCACHE)) 323*0Sstevel@tonic-gate pat_index += 2; 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate if (PTE_GET(pte, PT_WRITETHRU)) 326*0Sstevel@tonic-gate pat_index += 1; 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate if (pat_index != 0) 329*0Sstevel@tonic-gate mdb_printf("%s", attr[pat_index]); 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate if (PTE_GET(pte, PT_VALID) == 0) 332*0Sstevel@tonic-gate mdb_printf(" !VALID "); 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate mdb_printf("\n"); 335*0Sstevel@tonic-gate return (DCMD_OK); 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate /* 339*0Sstevel@tonic-gate * Print a PTE in more human friendly way. The PTE is assumed to be in 340*0Sstevel@tonic-gate * a level 0 page table, unless -l specifies another level. 341*0Sstevel@tonic-gate * 342*0Sstevel@tonic-gate * The PTE value can be specified as the -p option, since on a 32 bit kernel 343*0Sstevel@tonic-gate * with PAE running it's larger than a uintptr_t. 344*0Sstevel@tonic-gate */ 345*0Sstevel@tonic-gate /*ARGSUSED*/ 346*0Sstevel@tonic-gate int 347*0Sstevel@tonic-gate pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 348*0Sstevel@tonic-gate { 349*0Sstevel@tonic-gate int level = 0; 350*0Sstevel@tonic-gate uint64_t pte = 0; 351*0Sstevel@tonic-gate char *level_str = NULL; 352*0Sstevel@tonic-gate char *pte_str = NULL; 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate /* 355*0Sstevel@tonic-gate * The kernel has to at least have made it thru mmu_init() 356*0Sstevel@tonic-gate */ 357*0Sstevel@tonic-gate get_mmu(); 358*0Sstevel@tonic-gate if (mmu.num_level == 0) 359*0Sstevel@tonic-gate return (DCMD_ERR); 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate if (mdb_getopts(argc, argv, 362*0Sstevel@tonic-gate 'p', MDB_OPT_STR, &pte_str, 363*0Sstevel@tonic-gate 'l', MDB_OPT_STR, &level_str) != argc) 364*0Sstevel@tonic-gate return (DCMD_USAGE); 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate /* 367*0Sstevel@tonic-gate * parse the PTE to decode, if it's 0, we don't do anything 368*0Sstevel@tonic-gate */ 369*0Sstevel@tonic-gate if (pte_str != NULL) { 370*0Sstevel@tonic-gate pte = mdb_strtoull(pte_str); 371*0Sstevel@tonic-gate } else { 372*0Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0) 373*0Sstevel@tonic-gate return (DCMD_USAGE); 374*0Sstevel@tonic-gate pte = addr; 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate if (pte == 0) 377*0Sstevel@tonic-gate return (DCMD_OK); 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate /* 380*0Sstevel@tonic-gate * parse the level if supplied 381*0Sstevel@tonic-gate */ 382*0Sstevel@tonic-gate if (level_str != NULL) { 383*0Sstevel@tonic-gate level = mdb_strtoull(level_str); 384*0Sstevel@tonic-gate if (level < 0 || level > mmu.max_level) 385*0Sstevel@tonic-gate return (DCMD_ERR); 386*0Sstevel@tonic-gate } 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate return (do_pte_dcmd(level, pte)); 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate static int 392*0Sstevel@tonic-gate do_va2pfn(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap) 393*0Sstevel@tonic-gate { 394*0Sstevel@tonic-gate struct as as; 395*0Sstevel@tonic-gate struct hat *hatp; 396*0Sstevel@tonic-gate struct hat hat; 397*0Sstevel@tonic-gate htable_t *ht; 398*0Sstevel@tonic-gate htable_t htable; 399*0Sstevel@tonic-gate uintptr_t base; 400*0Sstevel@tonic-gate int h; 401*0Sstevel@tonic-gate int level; 402*0Sstevel@tonic-gate int found = 0; 403*0Sstevel@tonic-gate x86pte_t pte; 404*0Sstevel@tonic-gate x86pte_t buf; 405*0Sstevel@tonic-gate x86pte32_t *pte32 = (x86pte32_t *)&buf; 406*0Sstevel@tonic-gate physaddr_t paddr; 407*0Sstevel@tonic-gate size_t len; 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate if (asp != NULL) { 410*0Sstevel@tonic-gate if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) { 411*0Sstevel@tonic-gate mdb_warn("Couldn't read struct as\n"); 412*0Sstevel@tonic-gate return (DCMD_ERR); 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate hatp = as.a_hat; 415*0Sstevel@tonic-gate } else { 416*0Sstevel@tonic-gate hatp = khat; 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate /* 420*0Sstevel@tonic-gate * read the hat and its hash table 421*0Sstevel@tonic-gate */ 422*0Sstevel@tonic-gate if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) { 423*0Sstevel@tonic-gate mdb_warn("Couldn't read struct hat\n"); 424*0Sstevel@tonic-gate return (DCMD_ERR); 425*0Sstevel@tonic-gate } 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate /* 428*0Sstevel@tonic-gate * read the htable hashtable 429*0Sstevel@tonic-gate */ 430*0Sstevel@tonic-gate *pap = 0; 431*0Sstevel@tonic-gate for (level = 0; level <= mmu.max_level; ++level) { 432*0Sstevel@tonic-gate if (level == mmu.max_level) 433*0Sstevel@tonic-gate base = 0; 434*0Sstevel@tonic-gate else 435*0Sstevel@tonic-gate base = addr & mmu.level_mask[level + 1]; 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate for (h = 0; h < hat.hat_num_hash; ++h) { 438*0Sstevel@tonic-gate if (mdb_vread(&ht, sizeof (htable_t *), 439*0Sstevel@tonic-gate (uintptr_t)(hat.hat_ht_hash + h)) == -1) { 440*0Sstevel@tonic-gate mdb_warn("Couldn't read htable\n"); 441*0Sstevel@tonic-gate return (DCMD_ERR); 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate for (; ht != NULL; ht = htable.ht_next) { 444*0Sstevel@tonic-gate if (mdb_vread(&htable, sizeof (htable_t), 445*0Sstevel@tonic-gate (uintptr_t)ht) == -1) { 446*0Sstevel@tonic-gate mdb_warn("Couldn't read htable\n"); 447*0Sstevel@tonic-gate return (DCMD_ERR); 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate if (htable.ht_vaddr != base || 450*0Sstevel@tonic-gate htable.ht_level != level) 451*0Sstevel@tonic-gate continue; 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate /* 454*0Sstevel@tonic-gate * found - read the page table entry 455*0Sstevel@tonic-gate */ 456*0Sstevel@tonic-gate paddr = htable.ht_pfn << MMU_PAGESHIFT; 457*0Sstevel@tonic-gate paddr += ((addr - base) >> 458*0Sstevel@tonic-gate mmu.level_shift[level]) << 459*0Sstevel@tonic-gate mmu.pte_size_shift; 460*0Sstevel@tonic-gate len = mdb_pread(&buf, mmu.pte_size, paddr); 461*0Sstevel@tonic-gate if (len != mmu.pte_size) 462*0Sstevel@tonic-gate return (DCMD_ERR); 463*0Sstevel@tonic-gate if (mmu.pte_size == sizeof (x86pte_t)) 464*0Sstevel@tonic-gate pte = buf; 465*0Sstevel@tonic-gate else 466*0Sstevel@tonic-gate pte = *pte32; 467*0Sstevel@tonic-gate 468*0Sstevel@tonic-gate if (!found) { 469*0Sstevel@tonic-gate if (PTE_IS_LGPG(pte, level)) 470*0Sstevel@tonic-gate paddr = pte & PT_PADDR_LGPG; 471*0Sstevel@tonic-gate else 472*0Sstevel@tonic-gate paddr = pte & PT_PADDR; 473*0Sstevel@tonic-gate paddr += addr & mmu.level_offset[level]; 474*0Sstevel@tonic-gate *pap = paddr; 475*0Sstevel@tonic-gate found = 1; 476*0Sstevel@tonic-gate } 477*0Sstevel@tonic-gate if (print_level == 0) 478*0Sstevel@tonic-gate continue; 479*0Sstevel@tonic-gate mdb_printf("\tlevel=%d htable=%p pte=%llx\n", 480*0Sstevel@tonic-gate level, ht, pte); 481*0Sstevel@tonic-gate } 482*0Sstevel@tonic-gate } 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate done: 486*0Sstevel@tonic-gate if (!found) 487*0Sstevel@tonic-gate return (DCMD_ERR); 488*0Sstevel@tonic-gate return (DCMD_OK); 489*0Sstevel@tonic-gate } 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate int 492*0Sstevel@tonic-gate va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 493*0Sstevel@tonic-gate { 494*0Sstevel@tonic-gate uintptr_t addrspace; 495*0Sstevel@tonic-gate char *addrspace_str = NULL; 496*0Sstevel@tonic-gate uint64_t physaddr; 497*0Sstevel@tonic-gate int rc; 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate /* 500*0Sstevel@tonic-gate * The kernel has to at least have made it thru mmu_init() 501*0Sstevel@tonic-gate */ 502*0Sstevel@tonic-gate get_mmu(); 503*0Sstevel@tonic-gate if (mmu.num_level == 0) 504*0Sstevel@tonic-gate return (DCMD_ERR); 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate if (mdb_getopts(argc, argv, 507*0Sstevel@tonic-gate 'a', MDB_OPT_STR, &addrspace_str) != argc) 508*0Sstevel@tonic-gate return (DCMD_USAGE); 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0) 511*0Sstevel@tonic-gate return (DCMD_USAGE); 512*0Sstevel@tonic-gate 513*0Sstevel@tonic-gate /* 514*0Sstevel@tonic-gate * parse the address space 515*0Sstevel@tonic-gate */ 516*0Sstevel@tonic-gate if (addrspace_str != NULL) 517*0Sstevel@tonic-gate addrspace = mdb_strtoull(addrspace_str); 518*0Sstevel@tonic-gate else 519*0Sstevel@tonic-gate addrspace = 0; 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate rc = do_va2pfn(addr, (struct as *)addrspace, 1, &physaddr); 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate if (rc == DCMD_OK) 524*0Sstevel@tonic-gate mdb_printf("Virtual %p maps Physical %llx\n", addr, physaddr); 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate return (rc); 527*0Sstevel@tonic-gate } 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate /* 530*0Sstevel@tonic-gate * Report all hat's that either use PFN as a page table or that map the page. 531*0Sstevel@tonic-gate */ 532*0Sstevel@tonic-gate static int 533*0Sstevel@tonic-gate do_report_maps(pfn_t pfn) 534*0Sstevel@tonic-gate { 535*0Sstevel@tonic-gate struct hat *hatp, *end; 536*0Sstevel@tonic-gate struct hat hat; 537*0Sstevel@tonic-gate htable_t *ht; 538*0Sstevel@tonic-gate htable_t htable; 539*0Sstevel@tonic-gate uintptr_t base; 540*0Sstevel@tonic-gate int h; 541*0Sstevel@tonic-gate int level; 542*0Sstevel@tonic-gate int entry; 543*0Sstevel@tonic-gate x86pte_t pte; 544*0Sstevel@tonic-gate x86pte_t buf; 545*0Sstevel@tonic-gate x86pte32_t *pte32 = (x86pte32_t *)&buf; 546*0Sstevel@tonic-gate physaddr_t paddr; 547*0Sstevel@tonic-gate size_t len; 548*0Sstevel@tonic-gate int count; 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate if (mdb_vread(&hat, sizeof (hat), (uintptr_t)khat) == -1) { 551*0Sstevel@tonic-gate mdb_warn("Couldn't read khat\n"); 552*0Sstevel@tonic-gate return (DCMD_ERR); 553*0Sstevel@tonic-gate } 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate end = hat.hat_next; 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate /* 558*0Sstevel@tonic-gate * The hats are kept in a circular list with khat at the head, but 559*0Sstevel@tonic-gate * not part of the list proper. Accordingly, we know when we pass 560*0Sstevel@tonic-gate * knat.hat_next a second time that we've iterated through every 561*0Sstevel@tonic-gate * hat structure. 562*0Sstevel@tonic-gate */ 563*0Sstevel@tonic-gate for (hatp = khat, count = 0; hatp != end || count++ == 0; 564*0Sstevel@tonic-gate hatp = hat.hat_next) { 565*0Sstevel@tonic-gate /* 566*0Sstevel@tonic-gate * read the hat and its hash table 567*0Sstevel@tonic-gate */ 568*0Sstevel@tonic-gate if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) { 569*0Sstevel@tonic-gate mdb_warn("Couldn't read struct hat\n"); 570*0Sstevel@tonic-gate return (DCMD_ERR); 571*0Sstevel@tonic-gate } 572*0Sstevel@tonic-gate 573*0Sstevel@tonic-gate /* 574*0Sstevel@tonic-gate * read the htable hashtable 575*0Sstevel@tonic-gate */ 576*0Sstevel@tonic-gate paddr = 0; 577*0Sstevel@tonic-gate for (h = 0; h < hat.hat_num_hash; ++h) { 578*0Sstevel@tonic-gate if (mdb_vread(&ht, sizeof (htable_t *), 579*0Sstevel@tonic-gate (uintptr_t)(hat.hat_ht_hash + h)) == -1) { 580*0Sstevel@tonic-gate mdb_warn("Couldn't read htable\n"); 581*0Sstevel@tonic-gate return (DCMD_ERR); 582*0Sstevel@tonic-gate } 583*0Sstevel@tonic-gate for (; ht != NULL; ht = htable.ht_next) { 584*0Sstevel@tonic-gate if (mdb_vread(&htable, sizeof (htable_t), 585*0Sstevel@tonic-gate (uintptr_t)ht) == -1) { 586*0Sstevel@tonic-gate mdb_warn("Couldn't read htable\n"); 587*0Sstevel@tonic-gate return (DCMD_ERR); 588*0Sstevel@tonic-gate } 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate /* 591*0Sstevel@tonic-gate * only report kernel addresses once 592*0Sstevel@tonic-gate */ 593*0Sstevel@tonic-gate if (hatp != khat && 594*0Sstevel@tonic-gate htable.ht_vaddr >= kernelbase) 595*0Sstevel@tonic-gate continue; 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate /* 598*0Sstevel@tonic-gate * Is the PFN a pagetable itself? 599*0Sstevel@tonic-gate */ 600*0Sstevel@tonic-gate if (htable.ht_pfn == pfn) { 601*0Sstevel@tonic-gate mdb_printf("Pagetable for " 602*0Sstevel@tonic-gate "hat=%p htable=%p\n", hatp, ht); 603*0Sstevel@tonic-gate continue; 604*0Sstevel@tonic-gate } 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate /* 607*0Sstevel@tonic-gate * otherwise, examine page mappings 608*0Sstevel@tonic-gate */ 609*0Sstevel@tonic-gate level = htable.ht_level; 610*0Sstevel@tonic-gate if (level > mmu.max_page_level) 611*0Sstevel@tonic-gate continue; 612*0Sstevel@tonic-gate paddr = htable.ht_pfn << MMU_PAGESHIFT; 613*0Sstevel@tonic-gate for (entry = 0; entry < htable.ht_num_ptes; 614*0Sstevel@tonic-gate ++entry) { 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate base = htable.ht_vaddr + entry * 617*0Sstevel@tonic-gate mmu.level_size[level]; 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate /* 620*0Sstevel@tonic-gate * only report kernel addresses once 621*0Sstevel@tonic-gate */ 622*0Sstevel@tonic-gate if (hatp != khat && 623*0Sstevel@tonic-gate base >= kernelbase) 624*0Sstevel@tonic-gate continue; 625*0Sstevel@tonic-gate 626*0Sstevel@tonic-gate len = mdb_pread(&buf, mmu.pte_size, 627*0Sstevel@tonic-gate paddr + entry * mmu.pte_size); 628*0Sstevel@tonic-gate if (len != mmu.pte_size) 629*0Sstevel@tonic-gate return (DCMD_ERR); 630*0Sstevel@tonic-gate if (mmu.pte_size == sizeof (x86pte_t)) 631*0Sstevel@tonic-gate pte = buf; 632*0Sstevel@tonic-gate else 633*0Sstevel@tonic-gate pte = *pte32; 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate if ((pte & PT_VALID) == 0) 636*0Sstevel@tonic-gate continue; 637*0Sstevel@tonic-gate if (level == 0 || !(pte & PT_PAGESIZE)) 638*0Sstevel@tonic-gate pte &= PT_PADDR; 639*0Sstevel@tonic-gate else 640*0Sstevel@tonic-gate pte &= PT_PADDR_LGPG; 641*0Sstevel@tonic-gate if ((pte >> MMU_PAGESHIFT) != pfn) 642*0Sstevel@tonic-gate continue; 643*0Sstevel@tonic-gate mdb_printf("hat=%p maps addr=%p\n", 644*0Sstevel@tonic-gate hatp, (caddr_t)base); 645*0Sstevel@tonic-gate } 646*0Sstevel@tonic-gate } 647*0Sstevel@tonic-gate } 648*0Sstevel@tonic-gate } 649*0Sstevel@tonic-gate 650*0Sstevel@tonic-gate done: 651*0Sstevel@tonic-gate return (DCMD_OK); 652*0Sstevel@tonic-gate } 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate /* 655*0Sstevel@tonic-gate * given a PFN as its address argument, prints out the uses of it 656*0Sstevel@tonic-gate */ 657*0Sstevel@tonic-gate /*ARGSUSED*/ 658*0Sstevel@tonic-gate int 659*0Sstevel@tonic-gate report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 660*0Sstevel@tonic-gate { 661*0Sstevel@tonic-gate /* 662*0Sstevel@tonic-gate * The kernel has to at least have made it thru mmu_init() 663*0Sstevel@tonic-gate */ 664*0Sstevel@tonic-gate get_mmu(); 665*0Sstevel@tonic-gate if (mmu.num_level == 0) 666*0Sstevel@tonic-gate return (DCMD_ERR); 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0) 669*0Sstevel@tonic-gate return (DCMD_USAGE); 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate return (do_report_maps((pfn_t)addr)); 672*0Sstevel@tonic-gate } 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate /* 675*0Sstevel@tonic-gate * Dump the page table at the given PFN 676*0Sstevel@tonic-gate */ 677*0Sstevel@tonic-gate static int 678*0Sstevel@tonic-gate do_ptable_dcmd(pfn_t pfn) 679*0Sstevel@tonic-gate { 680*0Sstevel@tonic-gate struct hat *hatp, *end; 681*0Sstevel@tonic-gate struct hat hat; 682*0Sstevel@tonic-gate htable_t *ht; 683*0Sstevel@tonic-gate htable_t htable; 684*0Sstevel@tonic-gate uintptr_t base; 685*0Sstevel@tonic-gate int h; 686*0Sstevel@tonic-gate int level; 687*0Sstevel@tonic-gate int entry; 688*0Sstevel@tonic-gate uintptr_t pagesize; 689*0Sstevel@tonic-gate x86pte_t pte; 690*0Sstevel@tonic-gate x86pte_t buf; 691*0Sstevel@tonic-gate x86pte32_t *pte32 = (x86pte32_t *)&buf; 692*0Sstevel@tonic-gate physaddr_t paddr; 693*0Sstevel@tonic-gate size_t len; 694*0Sstevel@tonic-gate int count; 695*0Sstevel@tonic-gate 696*0Sstevel@tonic-gate if (mdb_vread(&hat, sizeof (hat), (uintptr_t)khat) == -1) { 697*0Sstevel@tonic-gate mdb_warn("Couldn't read khat\n"); 698*0Sstevel@tonic-gate return (DCMD_ERR); 699*0Sstevel@tonic-gate } 700*0Sstevel@tonic-gate 701*0Sstevel@tonic-gate end = hat.hat_next; 702*0Sstevel@tonic-gate 703*0Sstevel@tonic-gate /* 704*0Sstevel@tonic-gate * The hats are kept in a circular list with khat at the head, but 705*0Sstevel@tonic-gate * not part of the list proper. Accordingly, we know when we pass 706*0Sstevel@tonic-gate * knat.hat_next a second time that we've iterated through every 707*0Sstevel@tonic-gate * hat structure. 708*0Sstevel@tonic-gate */ 709*0Sstevel@tonic-gate for (hatp = khat, count = 0; hatp != end || count++ == 0; 710*0Sstevel@tonic-gate hatp = hat.hat_next) { 711*0Sstevel@tonic-gate /* 712*0Sstevel@tonic-gate * read the hat and its hash table 713*0Sstevel@tonic-gate */ 714*0Sstevel@tonic-gate if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) { 715*0Sstevel@tonic-gate mdb_warn("Couldn't read struct hat\n"); 716*0Sstevel@tonic-gate return (DCMD_ERR); 717*0Sstevel@tonic-gate } 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate /* 720*0Sstevel@tonic-gate * read the htable hashtable 721*0Sstevel@tonic-gate */ 722*0Sstevel@tonic-gate paddr = 0; 723*0Sstevel@tonic-gate for (h = 0; h < hat.hat_num_hash; ++h) { 724*0Sstevel@tonic-gate if (mdb_vread(&ht, sizeof (htable_t *), 725*0Sstevel@tonic-gate (uintptr_t)(hat.hat_ht_hash + h)) == -1) { 726*0Sstevel@tonic-gate mdb_warn("Couldn't read htable\n"); 727*0Sstevel@tonic-gate return (DCMD_ERR); 728*0Sstevel@tonic-gate } 729*0Sstevel@tonic-gate for (; ht != NULL; ht = htable.ht_next) { 730*0Sstevel@tonic-gate if (mdb_vread(&htable, sizeof (htable_t), 731*0Sstevel@tonic-gate (uintptr_t)ht) == -1) { 732*0Sstevel@tonic-gate mdb_warn("Couldn't read htable\n"); 733*0Sstevel@tonic-gate return (DCMD_ERR); 734*0Sstevel@tonic-gate } 735*0Sstevel@tonic-gate 736*0Sstevel@tonic-gate /* 737*0Sstevel@tonic-gate * Is this the PFN for this htable 738*0Sstevel@tonic-gate */ 739*0Sstevel@tonic-gate if (htable.ht_pfn == pfn) 740*0Sstevel@tonic-gate goto found_it; 741*0Sstevel@tonic-gate } 742*0Sstevel@tonic-gate } 743*0Sstevel@tonic-gate } 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate found_it: 746*0Sstevel@tonic-gate if (htable.ht_pfn == pfn) { 747*0Sstevel@tonic-gate mdb_printf("htable=%p\n", ht); 748*0Sstevel@tonic-gate level = htable.ht_level; 749*0Sstevel@tonic-gate base = htable.ht_vaddr; 750*0Sstevel@tonic-gate pagesize = mmu.level_size[level]; 751*0Sstevel@tonic-gate } else { 752*0Sstevel@tonic-gate mdb_printf("Unknown pagetable - assuming level/addr 0"); 753*0Sstevel@tonic-gate level = 0; /* assume level == 0 for PFN */ 754*0Sstevel@tonic-gate base = 0; 755*0Sstevel@tonic-gate pagesize = MMU_PAGESIZE; 756*0Sstevel@tonic-gate } 757*0Sstevel@tonic-gate 758*0Sstevel@tonic-gate paddr = pfn << MMU_PAGESHIFT; 759*0Sstevel@tonic-gate for (entry = 0; entry < mmu.ptes_per_table; ++entry) { 760*0Sstevel@tonic-gate len = mdb_pread(&buf, mmu.pte_size, 761*0Sstevel@tonic-gate paddr + entry * mmu.pte_size); 762*0Sstevel@tonic-gate if (len != mmu.pte_size) 763*0Sstevel@tonic-gate return (DCMD_ERR); 764*0Sstevel@tonic-gate if (mmu.pte_size == sizeof (x86pte_t)) 765*0Sstevel@tonic-gate pte = buf; 766*0Sstevel@tonic-gate else 767*0Sstevel@tonic-gate pte = *pte32; 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate if (pte == 0) 770*0Sstevel@tonic-gate continue; 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize); 773*0Sstevel@tonic-gate do_pte_dcmd(level, pte); 774*0Sstevel@tonic-gate } 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate done: 777*0Sstevel@tonic-gate return (DCMD_OK); 778*0Sstevel@tonic-gate } 779*0Sstevel@tonic-gate 780*0Sstevel@tonic-gate /* 781*0Sstevel@tonic-gate * given a PFN as its address argument, prints out the uses of it 782*0Sstevel@tonic-gate */ 783*0Sstevel@tonic-gate /*ARGSUSED*/ 784*0Sstevel@tonic-gate int 785*0Sstevel@tonic-gate ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 786*0Sstevel@tonic-gate { 787*0Sstevel@tonic-gate /* 788*0Sstevel@tonic-gate * The kernel has to at least have made it thru mmu_init() 789*0Sstevel@tonic-gate */ 790*0Sstevel@tonic-gate get_mmu(); 791*0Sstevel@tonic-gate if (mmu.num_level == 0) 792*0Sstevel@tonic-gate return (DCMD_ERR); 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0) 795*0Sstevel@tonic-gate return (DCMD_USAGE); 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate return (do_ptable_dcmd((pfn_t)addr)); 798*0Sstevel@tonic-gate } 799