17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5a85a6733Sjosephb * Common Development and Distribution License (the "License"). 6a85a6733Sjosephb * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*cbdcbd05SJonathan Adams * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * This part of the file contains the mdb support for dcmds: 287c478bd9Sstevel@tonic-gate * ::memseg_list 297c478bd9Sstevel@tonic-gate * and walkers for: 307c478bd9Sstevel@tonic-gate * memseg - a memseg list walker for ::memseg_list 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <sys/types.h> 357c478bd9Sstevel@tonic-gate #include <sys/machparam.h> 367c478bd9Sstevel@tonic-gate #include <sys/controlregs.h> 37ae115bc7Smrj #include <sys/mach_mmu.h> 38843e1988Sjohnlev #ifdef __xpv 39843e1988Sjohnlev #include <sys/hypervisor.h> 40843e1988Sjohnlev #endif 417c478bd9Sstevel@tonic-gate #include <vm/as.h> 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 447c478bd9Sstevel@tonic-gate #include <mdb/mdb_target.h> 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate #include <vm/page.h> 477c478bd9Sstevel@tonic-gate #include <vm/hat_i86.h> 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate struct pfn2pp { 507c478bd9Sstevel@tonic-gate pfn_t pfn; 517c478bd9Sstevel@tonic-gate page_t *pp; 527c478bd9Sstevel@tonic-gate }; 537c478bd9Sstevel@tonic-gate 54ae115bc7Smrj static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *); 55843e1988Sjohnlev static void init_mmu(void); 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate int 587c478bd9Sstevel@tonic-gate platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap) 597c478bd9Sstevel@tonic-gate { 607c478bd9Sstevel@tonic-gate if (asp == NULL) 617c478bd9Sstevel@tonic-gate return (DCMD_ERR); 627c478bd9Sstevel@tonic-gate 63843e1988Sjohnlev init_mmu(); 64843e1988Sjohnlev 657c478bd9Sstevel@tonic-gate if (mmu.num_level == 0) 667c478bd9Sstevel@tonic-gate return (DCMD_ERR); 677c478bd9Sstevel@tonic-gate 68ae115bc7Smrj return (do_va2pa(addr, asp, 0, pap, NULL)); 697c478bd9Sstevel@tonic-gate } 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* 727c478bd9Sstevel@tonic-gate * ::memseg_list dcmd and walker to implement it. 737c478bd9Sstevel@tonic-gate */ 747c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 757c478bd9Sstevel@tonic-gate int 767c478bd9Sstevel@tonic-gate memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 777c478bd9Sstevel@tonic-gate { 787c478bd9Sstevel@tonic-gate struct memseg ms; 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) { 817c478bd9Sstevel@tonic-gate if (mdb_pwalk_dcmd("memseg", "memseg_list", 827c478bd9Sstevel@tonic-gate 0, NULL, 0) == -1) { 837c478bd9Sstevel@tonic-gate mdb_warn("can't walk memseg"); 847c478bd9Sstevel@tonic-gate return (DCMD_ERR); 857c478bd9Sstevel@tonic-gate } 867c478bd9Sstevel@tonic-gate return (DCMD_OK); 877c478bd9Sstevel@tonic-gate } 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) 907c478bd9Sstevel@tonic-gate mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR", 91843e1988Sjohnlev "PAGES", "EPAGES", "BASE", "END"); 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) { 947c478bd9Sstevel@tonic-gate mdb_warn("can't read memseg at %#lx", addr); 957c478bd9Sstevel@tonic-gate return (DCMD_ERR); 967c478bd9Sstevel@tonic-gate } 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr, 99843e1988Sjohnlev ms.pages, ms.epages, ms.pages_base, ms.pages_end); 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate return (DCMD_OK); 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate /* 1057c478bd9Sstevel@tonic-gate * walk the memseg structures 1067c478bd9Sstevel@tonic-gate */ 1077c478bd9Sstevel@tonic-gate int 1087c478bd9Sstevel@tonic-gate memseg_walk_init(mdb_walk_state_t *wsp) 1097c478bd9Sstevel@tonic-gate { 1107c478bd9Sstevel@tonic-gate if (wsp->walk_addr != NULL) { 1117c478bd9Sstevel@tonic-gate mdb_warn("memseg only supports global walks\n"); 1127c478bd9Sstevel@tonic-gate return (WALK_ERR); 1137c478bd9Sstevel@tonic-gate } 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) { 1167c478bd9Sstevel@tonic-gate mdb_warn("symbol 'memsegs' not found"); 1177c478bd9Sstevel@tonic-gate return (WALK_ERR); 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP); 1217c478bd9Sstevel@tonic-gate return (WALK_NEXT); 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate int 1267c478bd9Sstevel@tonic-gate memseg_walk_step(mdb_walk_state_t *wsp) 1277c478bd9Sstevel@tonic-gate { 1287c478bd9Sstevel@tonic-gate int status; 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate if (wsp->walk_addr == 0) { 1317c478bd9Sstevel@tonic-gate return (WALK_DONE); 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate if (mdb_vread(wsp->walk_data, sizeof (struct memseg), 1357c478bd9Sstevel@tonic-gate wsp->walk_addr) == -1) { 1367c478bd9Sstevel@tonic-gate mdb_warn("failed to read struct memseg at %p", wsp->walk_addr); 1377c478bd9Sstevel@tonic-gate return (WALK_DONE); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1417c478bd9Sstevel@tonic-gate wsp->walk_cbdata); 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate return (status); 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate void 1497c478bd9Sstevel@tonic-gate memseg_walk_fini(mdb_walk_state_t *wsp) 1507c478bd9Sstevel@tonic-gate { 1517c478bd9Sstevel@tonic-gate mdb_free(wsp->walk_data, sizeof (struct memseg)); 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* 155ae115bc7Smrj * Now HAT related dcmds. 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate 158843e1988Sjohnlev static struct hat *khat; /* value of kas.a_hat */ 1597c478bd9Sstevel@tonic-gate struct hat_mmu_info mmu; 1607c478bd9Sstevel@tonic-gate uintptr_t kernelbase; 1617c478bd9Sstevel@tonic-gate 162843e1988Sjohnlev /* 163843e1988Sjohnlev * stuff for i86xpv images 164843e1988Sjohnlev */ 165843e1988Sjohnlev static int is_xpv; 166843e1988Sjohnlev static uintptr_t mfn_list_addr; /* kernel MFN list address */ 167843e1988Sjohnlev uintptr_t xen_virt_start; /* address of mfn_to_pfn[] table */ 168843e1988Sjohnlev ulong_t mfn_count; /* number of pfn's in the MFN list */ 169843e1988Sjohnlev pfn_t *mfn_list; /* local MFN list copy */ 170843e1988Sjohnlev 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * read mmu parameters from kernel 1737c478bd9Sstevel@tonic-gate */ 1747c478bd9Sstevel@tonic-gate static void 175843e1988Sjohnlev init_mmu(void) 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate struct as kas; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate if (mmu.num_level != 0) 1807c478bd9Sstevel@tonic-gate return; 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1) 1837c478bd9Sstevel@tonic-gate mdb_warn("Can't use HAT information before mmu_init()\n"); 1847c478bd9Sstevel@tonic-gate if (mdb_readsym(&kas, sizeof (kas), "kas") == -1) 1857c478bd9Sstevel@tonic-gate mdb_warn("Couldn't find kas - kernel's struct as\n"); 1867c478bd9Sstevel@tonic-gate if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1) 1877c478bd9Sstevel@tonic-gate mdb_warn("Couldn't find kernelbase\n"); 1887c478bd9Sstevel@tonic-gate khat = kas.a_hat; 189843e1988Sjohnlev 190843e1988Sjohnlev /* 191843e1988Sjohnlev * Is this a paravirtualized domain image? 192843e1988Sjohnlev */ 193843e1988Sjohnlev if (mdb_readsym(&mfn_list_addr, sizeof (mfn_list_addr), 194843e1988Sjohnlev "mfn_list") == -1 || 195843e1988Sjohnlev mdb_readsym(&xen_virt_start, sizeof (xen_virt_start), 196843e1988Sjohnlev "xen_virt_start") == -1 || 197843e1988Sjohnlev mdb_readsym(&mfn_count, sizeof (mfn_count), "mfn_count") == -1) { 198843e1988Sjohnlev mfn_list_addr = NULL; 199843e1988Sjohnlev } 200843e1988Sjohnlev 201843e1988Sjohnlev is_xpv = mfn_list_addr != NULL; 202843e1988Sjohnlev 203843e1988Sjohnlev #ifndef _KMDB 204843e1988Sjohnlev /* 205843e1988Sjohnlev * recreate the local mfn_list 206843e1988Sjohnlev */ 207843e1988Sjohnlev if (is_xpv) { 208843e1988Sjohnlev size_t sz = mfn_count * sizeof (pfn_t); 209843e1988Sjohnlev mfn_list = mdb_zalloc(sz, UM_SLEEP); 210843e1988Sjohnlev 211843e1988Sjohnlev if (mdb_vread(mfn_list, sz, (uintptr_t)mfn_list_addr) == -1) { 212843e1988Sjohnlev mdb_warn("Failed to read MFN list\n"); 213843e1988Sjohnlev mdb_free(mfn_list, sz); 214843e1988Sjohnlev mfn_list = NULL; 215843e1988Sjohnlev } 216843e1988Sjohnlev } 217843e1988Sjohnlev #endif 218843e1988Sjohnlev } 219843e1988Sjohnlev 220843e1988Sjohnlev void 221843e1988Sjohnlev free_mmu(void) 222843e1988Sjohnlev { 223843e1988Sjohnlev #ifdef __xpv 224843e1988Sjohnlev if (mfn_list != NULL) 225843e1988Sjohnlev mdb_free(mfn_list, mfn_count * sizeof (mfn_t)); 226843e1988Sjohnlev #endif 227843e1988Sjohnlev } 228843e1988Sjohnlev 229843e1988Sjohnlev #ifdef __xpv 230843e1988Sjohnlev 231843e1988Sjohnlev #ifdef _KMDB 232843e1988Sjohnlev 233843e1988Sjohnlev /* 234843e1988Sjohnlev * Convert between MFNs and PFNs. Since we're in kmdb we can go directly 235843e1988Sjohnlev * through the machine to phys mapping and the MFN list. 236843e1988Sjohnlev */ 237843e1988Sjohnlev 238843e1988Sjohnlev pfn_t 239843e1988Sjohnlev mdb_mfn_to_pfn(mfn_t mfn) 240843e1988Sjohnlev { 241843e1988Sjohnlev pfn_t pfn; 242843e1988Sjohnlev mfn_t tmp; 243843e1988Sjohnlev pfn_t *pfn_list; 244843e1988Sjohnlev 245843e1988Sjohnlev if (mfn_list_addr == NULL) 246843e1988Sjohnlev return (-(pfn_t)1); 247843e1988Sjohnlev 248843e1988Sjohnlev pfn_list = (pfn_t *)xen_virt_start; 249843e1988Sjohnlev if (mdb_vread(&pfn, sizeof (pfn), (uintptr_t)(pfn_list + mfn)) == -1) 250843e1988Sjohnlev return (-(pfn_t)1); 251843e1988Sjohnlev 252843e1988Sjohnlev if (mdb_vread(&tmp, sizeof (tmp), 253843e1988Sjohnlev (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1) 254843e1988Sjohnlev return (-(pfn_t)1); 255843e1988Sjohnlev 256843e1988Sjohnlev if (pfn >= mfn_count || tmp != mfn) 257843e1988Sjohnlev return (-(pfn_t)1); 258843e1988Sjohnlev 259843e1988Sjohnlev return (pfn); 260843e1988Sjohnlev } 261843e1988Sjohnlev 262843e1988Sjohnlev mfn_t 263843e1988Sjohnlev mdb_pfn_to_mfn(pfn_t pfn) 264843e1988Sjohnlev { 265843e1988Sjohnlev mfn_t mfn; 266843e1988Sjohnlev 267843e1988Sjohnlev init_mmu(); 268843e1988Sjohnlev 269843e1988Sjohnlev if (mfn_list_addr == NULL || pfn >= mfn_count) 270843e1988Sjohnlev return (-(mfn_t)1); 271843e1988Sjohnlev 272843e1988Sjohnlev if (mdb_vread(&mfn, sizeof (mfn), 273843e1988Sjohnlev (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1) 274843e1988Sjohnlev return (-(mfn_t)1); 275843e1988Sjohnlev 276843e1988Sjohnlev return (mfn); 277843e1988Sjohnlev } 278843e1988Sjohnlev 279843e1988Sjohnlev #else /* _KMDB */ 280843e1988Sjohnlev 281843e1988Sjohnlev /* 282843e1988Sjohnlev * Convert between MFNs and PFNs. Since a crash dump doesn't include the 283843e1988Sjohnlev * MFN->PFN translation table (it's part of the hypervisor, not our image) 284843e1988Sjohnlev * we do the MFN->PFN translation by searching the PFN->MFN (mfn_list) 285843e1988Sjohnlev * table, if it's there. 286843e1988Sjohnlev */ 287843e1988Sjohnlev 288843e1988Sjohnlev pfn_t 289843e1988Sjohnlev mdb_mfn_to_pfn(mfn_t mfn) 290843e1988Sjohnlev { 291843e1988Sjohnlev pfn_t pfn; 292843e1988Sjohnlev 293843e1988Sjohnlev init_mmu(); 294843e1988Sjohnlev 295843e1988Sjohnlev if (mfn_list == NULL) 296843e1988Sjohnlev return (-(pfn_t)1); 297843e1988Sjohnlev 298843e1988Sjohnlev for (pfn = 0; pfn < mfn_count; ++pfn) { 299843e1988Sjohnlev if (mfn_list[pfn] != mfn) 300843e1988Sjohnlev continue; 301843e1988Sjohnlev return (pfn); 302843e1988Sjohnlev } 303843e1988Sjohnlev 304843e1988Sjohnlev return (-(pfn_t)1); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 307843e1988Sjohnlev mfn_t 308843e1988Sjohnlev mdb_pfn_to_mfn(pfn_t pfn) 309843e1988Sjohnlev { 310843e1988Sjohnlev init_mmu(); 311843e1988Sjohnlev 312843e1988Sjohnlev if (mfn_list == NULL || pfn >= mfn_count) 313843e1988Sjohnlev return (-(mfn_t)1); 314843e1988Sjohnlev 315843e1988Sjohnlev return (mfn_list[pfn]); 316843e1988Sjohnlev } 317843e1988Sjohnlev 318843e1988Sjohnlev #endif /* _KMDB */ 319843e1988Sjohnlev 320843e1988Sjohnlev static paddr_t 321843e1988Sjohnlev mdb_ma_to_pa(uint64_t ma) 322843e1988Sjohnlev { 323843e1988Sjohnlev pfn_t pfn = mdb_mfn_to_pfn(mmu_btop(ma)); 324843e1988Sjohnlev if (pfn == -(pfn_t)1) 325843e1988Sjohnlev return (-(paddr_t)1); 326843e1988Sjohnlev 327843e1988Sjohnlev return (mmu_ptob((paddr_t)pfn) | (ma & (MMU_PAGESIZE - 1))); 328843e1988Sjohnlev } 329843e1988Sjohnlev 330843e1988Sjohnlev #else /* __xpv */ 331843e1988Sjohnlev 332ae115bc7Smrj #define mdb_ma_to_pa(ma) (ma) 333ae115bc7Smrj #define mdb_mfn_to_pfn(mfn) (mfn) 334ae115bc7Smrj #define mdb_pfn_to_mfn(pfn) (pfn) 335ae115bc7Smrj 336843e1988Sjohnlev #endif /* __xpv */ 337843e1988Sjohnlev 338843e1988Sjohnlev /* 339843e1988Sjohnlev * ::mfntopfn dcmd translates hypervisor machine page number 340843e1988Sjohnlev * to physical page number 341843e1988Sjohnlev */ 342843e1988Sjohnlev /*ARGSUSED*/ 343843e1988Sjohnlev int 344843e1988Sjohnlev mfntopfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 345843e1988Sjohnlev { 346843e1988Sjohnlev pfn_t pfn; 347843e1988Sjohnlev 348843e1988Sjohnlev if ((flags & DCMD_ADDRSPEC) == 0) { 349843e1988Sjohnlev mdb_warn("MFN missing\n"); 350843e1988Sjohnlev return (DCMD_USAGE); 351843e1988Sjohnlev } 352843e1988Sjohnlev 353843e1988Sjohnlev if ((pfn = mdb_mfn_to_pfn((pfn_t)addr)) == -(pfn_t)1) { 354843e1988Sjohnlev mdb_warn("Invalid mfn %lr\n", (pfn_t)addr); 355843e1988Sjohnlev return (DCMD_ERR); 356843e1988Sjohnlev } 357843e1988Sjohnlev 358843e1988Sjohnlev mdb_printf("%lr\n", pfn); 359843e1988Sjohnlev 360843e1988Sjohnlev return (DCMD_OK); 361843e1988Sjohnlev } 362843e1988Sjohnlev 363843e1988Sjohnlev /* 364843e1988Sjohnlev * ::pfntomfn dcmd translates physical page number to 365843e1988Sjohnlev * hypervisor machine page number 366843e1988Sjohnlev */ 367843e1988Sjohnlev /*ARGSUSED*/ 368843e1988Sjohnlev int 369843e1988Sjohnlev pfntomfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 370843e1988Sjohnlev { 371843e1988Sjohnlev pfn_t mfn; 372843e1988Sjohnlev 373843e1988Sjohnlev if ((flags & DCMD_ADDRSPEC) == 0) { 374843e1988Sjohnlev mdb_warn("PFN missing\n"); 375843e1988Sjohnlev return (DCMD_USAGE); 376843e1988Sjohnlev } 377843e1988Sjohnlev 378843e1988Sjohnlev if ((mfn = mdb_pfn_to_mfn((pfn_t)addr)) == -(pfn_t)1) { 379843e1988Sjohnlev mdb_warn("Invalid pfn %lr\n", (pfn_t)addr); 380843e1988Sjohnlev return (DCMD_ABORT); 381843e1988Sjohnlev } 382843e1988Sjohnlev 383843e1988Sjohnlev mdb_printf("%lr\n", mfn); 384843e1988Sjohnlev 385843e1988Sjohnlev if (flags & DCMD_LOOP) 386843e1988Sjohnlev mdb_set_dot(addr + 1); 387843e1988Sjohnlev return (DCMD_OK); 388843e1988Sjohnlev } 389843e1988Sjohnlev 390ae115bc7Smrj static pfn_t 391ae115bc7Smrj pte2mfn(x86pte_t pte, uint_t level) 392ae115bc7Smrj { 393ae115bc7Smrj pfn_t mfn; 394ae115bc7Smrj if (level > 0 && (pte & PT_PAGESIZE)) 395ae115bc7Smrj mfn = mmu_btop(pte & PT_PADDR_LGPG); 396ae115bc7Smrj else 397ae115bc7Smrj mfn = mmu_btop(pte & PT_PADDR); 398ae115bc7Smrj return (mfn); 399ae115bc7Smrj } 400ae115bc7Smrj 4017c478bd9Sstevel@tonic-gate /* 4027c478bd9Sstevel@tonic-gate * Print a PTE in more human friendly way. The PTE is assumed to be in 4037c478bd9Sstevel@tonic-gate * a level 0 page table, unless -l specifies another level. 4047c478bd9Sstevel@tonic-gate * 4057c478bd9Sstevel@tonic-gate * The PTE value can be specified as the -p option, since on a 32 bit kernel 4067c478bd9Sstevel@tonic-gate * with PAE running it's larger than a uintptr_t. 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate static int 4097c478bd9Sstevel@tonic-gate do_pte_dcmd(int level, uint64_t pte) 4107c478bd9Sstevel@tonic-gate { 4117c478bd9Sstevel@tonic-gate static char *attr[] = { 4127c478bd9Sstevel@tonic-gate "wrback", "wrthru", "uncached", "uncached", 4137c478bd9Sstevel@tonic-gate "wrback", "wrthru", "wrcombine", "uncached"}; 4147c478bd9Sstevel@tonic-gate int pat_index = 0; 415ae115bc7Smrj pfn_t mfn; 4167c478bd9Sstevel@tonic-gate 417ae115bc7Smrj mdb_printf("pte=%llr: ", pte); 4187c478bd9Sstevel@tonic-gate if (PTE_GET(pte, mmu.pt_nx)) 4197c478bd9Sstevel@tonic-gate mdb_printf("noexec "); 4207c478bd9Sstevel@tonic-gate 421ae115bc7Smrj mfn = pte2mfn(pte, level); 422843e1988Sjohnlev mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn); 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_NOCONSIST)) 4257c478bd9Sstevel@tonic-gate mdb_printf("noconsist "); 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_NOSYNC)) 4287c478bd9Sstevel@tonic-gate mdb_printf("nosync "); 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate if (PTE_GET(pte, mmu.pt_global)) 4317c478bd9Sstevel@tonic-gate mdb_printf("global "); 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate if (level > 0 && PTE_GET(pte, PT_PAGESIZE)) 4347c478bd9Sstevel@tonic-gate mdb_printf("largepage "); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate if (level > 0 && PTE_GET(pte, PT_MOD)) 4377c478bd9Sstevel@tonic-gate mdb_printf("mod "); 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate if (level > 0 && PTE_GET(pte, PT_REF)) 4407c478bd9Sstevel@tonic-gate mdb_printf("ref "); 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_USER)) 4437c478bd9Sstevel@tonic-gate mdb_printf("user "); 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_WRITABLE)) 4467c478bd9Sstevel@tonic-gate mdb_printf("write "); 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate /* 4497c478bd9Sstevel@tonic-gate * Report non-standard cacheability 4507c478bd9Sstevel@tonic-gate */ 4517c478bd9Sstevel@tonic-gate pat_index = 0; 4527c478bd9Sstevel@tonic-gate if (level > 0) { 4537c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE)) 4547c478bd9Sstevel@tonic-gate pat_index += 4; 4557c478bd9Sstevel@tonic-gate } else { 4567c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_PAT_4K)) 4577c478bd9Sstevel@tonic-gate pat_index += 4; 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_NOCACHE)) 4617c478bd9Sstevel@tonic-gate pat_index += 2; 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_WRITETHRU)) 4647c478bd9Sstevel@tonic-gate pat_index += 1; 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate if (pat_index != 0) 4677c478bd9Sstevel@tonic-gate mdb_printf("%s", attr[pat_index]); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate if (PTE_GET(pte, PT_VALID) == 0) 4707c478bd9Sstevel@tonic-gate mdb_printf(" !VALID "); 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate mdb_printf("\n"); 4737c478bd9Sstevel@tonic-gate return (DCMD_OK); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate /* 4777c478bd9Sstevel@tonic-gate * Print a PTE in more human friendly way. The PTE is assumed to be in 4787c478bd9Sstevel@tonic-gate * a level 0 page table, unless -l specifies another level. 4797c478bd9Sstevel@tonic-gate * 4807c478bd9Sstevel@tonic-gate * The PTE value can be specified as the -p option, since on a 32 bit kernel 4817c478bd9Sstevel@tonic-gate * with PAE running it's larger than a uintptr_t. 4827c478bd9Sstevel@tonic-gate */ 4837c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4847c478bd9Sstevel@tonic-gate int 4857c478bd9Sstevel@tonic-gate pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4867c478bd9Sstevel@tonic-gate { 4877c478bd9Sstevel@tonic-gate int level = 0; 4887c478bd9Sstevel@tonic-gate uint64_t pte = 0; 4897c478bd9Sstevel@tonic-gate char *level_str = NULL; 4907c478bd9Sstevel@tonic-gate char *pte_str = NULL; 4917c478bd9Sstevel@tonic-gate 492843e1988Sjohnlev init_mmu(); 493843e1988Sjohnlev 4947c478bd9Sstevel@tonic-gate if (mmu.num_level == 0) 4957c478bd9Sstevel@tonic-gate return (DCMD_ERR); 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate if (mdb_getopts(argc, argv, 4987c478bd9Sstevel@tonic-gate 'p', MDB_OPT_STR, &pte_str, 4997c478bd9Sstevel@tonic-gate 'l', MDB_OPT_STR, &level_str) != argc) 5007c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate /* 5037c478bd9Sstevel@tonic-gate * parse the PTE to decode, if it's 0, we don't do anything 5047c478bd9Sstevel@tonic-gate */ 5057c478bd9Sstevel@tonic-gate if (pte_str != NULL) { 5067c478bd9Sstevel@tonic-gate pte = mdb_strtoull(pte_str); 5077c478bd9Sstevel@tonic-gate } else { 5087c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0) 5097c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 5107c478bd9Sstevel@tonic-gate pte = addr; 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate if (pte == 0) 5137c478bd9Sstevel@tonic-gate return (DCMD_OK); 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate /* 5167c478bd9Sstevel@tonic-gate * parse the level if supplied 5177c478bd9Sstevel@tonic-gate */ 5187c478bd9Sstevel@tonic-gate if (level_str != NULL) { 5197c478bd9Sstevel@tonic-gate level = mdb_strtoull(level_str); 5207c478bd9Sstevel@tonic-gate if (level < 0 || level > mmu.max_level) 5217c478bd9Sstevel@tonic-gate return (DCMD_ERR); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate return (do_pte_dcmd(level, pte)); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate 527ae115bc7Smrj static size_t 528ae115bc7Smrj va2entry(htable_t *htable, uintptr_t addr) 529ae115bc7Smrj { 530ae115bc7Smrj size_t entry = (addr - htable->ht_vaddr); 531ae115bc7Smrj 532ae115bc7Smrj entry >>= mmu.level_shift[htable->ht_level]; 533ae115bc7Smrj return (entry & HTABLE_NUM_PTES(htable) - 1); 534ae115bc7Smrj } 535ae115bc7Smrj 536ae115bc7Smrj static x86pte_t 537ae115bc7Smrj get_pte(hat_t *hat, htable_t *htable, uintptr_t addr) 538ae115bc7Smrj { 539ae115bc7Smrj x86pte_t buf; 540ae115bc7Smrj x86pte32_t *pte32 = (x86pte32_t *)&buf; 541ae115bc7Smrj size_t len; 542ae115bc7Smrj 543ae115bc7Smrj if (htable->ht_flags & HTABLE_VLP) { 544ae115bc7Smrj uintptr_t ptr = (uintptr_t)hat->hat_vlp_ptes; 545ae115bc7Smrj ptr += va2entry(htable, addr) << mmu.pte_size_shift; 546ae115bc7Smrj len = mdb_vread(&buf, mmu.pte_size, ptr); 547ae115bc7Smrj } else { 548ae115bc7Smrj paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn); 549ae115bc7Smrj paddr += va2entry(htable, addr) << mmu.pte_size_shift; 550ae115bc7Smrj len = mdb_pread(&buf, mmu.pte_size, paddr); 551ae115bc7Smrj } 552ae115bc7Smrj 553ae115bc7Smrj if (len != mmu.pte_size) 554ae115bc7Smrj return (0); 555ae115bc7Smrj 556ae115bc7Smrj if (mmu.pte_size == sizeof (x86pte_t)) 557ae115bc7Smrj return (buf); 558ae115bc7Smrj return (*pte32); 559ae115bc7Smrj } 560ae115bc7Smrj 5617c478bd9Sstevel@tonic-gate static int 562ae115bc7Smrj do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap, 563ae115bc7Smrj pfn_t *mfnp) 5647c478bd9Sstevel@tonic-gate { 5657c478bd9Sstevel@tonic-gate struct as as; 5667c478bd9Sstevel@tonic-gate struct hat *hatp; 5677c478bd9Sstevel@tonic-gate struct hat hat; 5687c478bd9Sstevel@tonic-gate htable_t *ht; 5697c478bd9Sstevel@tonic-gate htable_t htable; 5707c478bd9Sstevel@tonic-gate uintptr_t base; 5717c478bd9Sstevel@tonic-gate int h; 5727c478bd9Sstevel@tonic-gate int level; 5737c478bd9Sstevel@tonic-gate int found = 0; 5747c478bd9Sstevel@tonic-gate x86pte_t pte; 5757c478bd9Sstevel@tonic-gate physaddr_t paddr; 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate if (asp != NULL) { 5787c478bd9Sstevel@tonic-gate if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) { 5797c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read struct as\n"); 5807c478bd9Sstevel@tonic-gate return (DCMD_ERR); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate hatp = as.a_hat; 5837c478bd9Sstevel@tonic-gate } else { 5847c478bd9Sstevel@tonic-gate hatp = khat; 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate /* 5887c478bd9Sstevel@tonic-gate * read the hat and its hash table 5897c478bd9Sstevel@tonic-gate */ 5907c478bd9Sstevel@tonic-gate if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) { 5917c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read struct hat\n"); 5927c478bd9Sstevel@tonic-gate return (DCMD_ERR); 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate /* 5967c478bd9Sstevel@tonic-gate * read the htable hashtable 5977c478bd9Sstevel@tonic-gate */ 5987c478bd9Sstevel@tonic-gate for (level = 0; level <= mmu.max_level; ++level) { 599ae115bc7Smrj if (level == TOP_LEVEL(&hat)) 6007c478bd9Sstevel@tonic-gate base = 0; 6017c478bd9Sstevel@tonic-gate else 6027c478bd9Sstevel@tonic-gate base = addr & mmu.level_mask[level + 1]; 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate for (h = 0; h < hat.hat_num_hash; ++h) { 6057c478bd9Sstevel@tonic-gate if (mdb_vread(&ht, sizeof (htable_t *), 6067c478bd9Sstevel@tonic-gate (uintptr_t)(hat.hat_ht_hash + h)) == -1) { 6077c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read htable\n"); 6087c478bd9Sstevel@tonic-gate return (DCMD_ERR); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate for (; ht != NULL; ht = htable.ht_next) { 6117c478bd9Sstevel@tonic-gate if (mdb_vread(&htable, sizeof (htable_t), 6127c478bd9Sstevel@tonic-gate (uintptr_t)ht) == -1) { 6137c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read htable\n"); 6147c478bd9Sstevel@tonic-gate return (DCMD_ERR); 6157c478bd9Sstevel@tonic-gate } 616ae115bc7Smrj 6177c478bd9Sstevel@tonic-gate if (htable.ht_vaddr != base || 6187c478bd9Sstevel@tonic-gate htable.ht_level != level) 6197c478bd9Sstevel@tonic-gate continue; 6207c478bd9Sstevel@tonic-gate 621ae115bc7Smrj pte = get_pte(&hat, &htable, addr); 6227c478bd9Sstevel@tonic-gate 623ae115bc7Smrj if (print_level) { 624ae115bc7Smrj mdb_printf("\tlevel=%d htable=%p " 625ae115bc7Smrj "pte=%llr\n", level, ht, pte); 6267c478bd9Sstevel@tonic-gate } 627ae115bc7Smrj 628ae115bc7Smrj if (!PTE_ISVALID(pte)) { 629ae115bc7Smrj mdb_printf("Address %p is unmapped.\n", 630ae115bc7Smrj addr); 631ae115bc7Smrj return (DCMD_ERR); 632ae115bc7Smrj } 633ae115bc7Smrj 634ae115bc7Smrj if (found) 6357c478bd9Sstevel@tonic-gate continue; 636ae115bc7Smrj 637ae115bc7Smrj if (PTE_IS_LGPG(pte, level)) 638ae115bc7Smrj paddr = mdb_ma_to_pa(pte & 639ae115bc7Smrj PT_PADDR_LGPG); 640ae115bc7Smrj else 641ae115bc7Smrj paddr = mdb_ma_to_pa(pte & PT_PADDR); 642ae115bc7Smrj paddr += addr & mmu.level_offset[level]; 643ae115bc7Smrj if (pap != NULL) 644ae115bc7Smrj *pap = paddr; 645ae115bc7Smrj if (mfnp != NULL) 646ae115bc7Smrj *mfnp = pte2mfn(pte, level); 647ae115bc7Smrj found = 1; 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate done: 6537c478bd9Sstevel@tonic-gate if (!found) 6547c478bd9Sstevel@tonic-gate return (DCMD_ERR); 6557c478bd9Sstevel@tonic-gate return (DCMD_OK); 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate int 6597c478bd9Sstevel@tonic-gate va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 6607c478bd9Sstevel@tonic-gate { 6617c478bd9Sstevel@tonic-gate uintptr_t addrspace; 6627c478bd9Sstevel@tonic-gate char *addrspace_str = NULL; 663ae115bc7Smrj int piped = flags & DCMD_PIPE_OUT; 664ae115bc7Smrj pfn_t pfn; 665ae115bc7Smrj pfn_t mfn; 6667c478bd9Sstevel@tonic-gate int rc; 6677c478bd9Sstevel@tonic-gate 668843e1988Sjohnlev init_mmu(); 669843e1988Sjohnlev 6707c478bd9Sstevel@tonic-gate if (mmu.num_level == 0) 6717c478bd9Sstevel@tonic-gate return (DCMD_ERR); 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate if (mdb_getopts(argc, argv, 6747c478bd9Sstevel@tonic-gate 'a', MDB_OPT_STR, &addrspace_str) != argc) 6757c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0) 6787c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate /* 6817c478bd9Sstevel@tonic-gate * parse the address space 6827c478bd9Sstevel@tonic-gate */ 6837c478bd9Sstevel@tonic-gate if (addrspace_str != NULL) 6847c478bd9Sstevel@tonic-gate addrspace = mdb_strtoull(addrspace_str); 6857c478bd9Sstevel@tonic-gate else 6867c478bd9Sstevel@tonic-gate addrspace = 0; 6877c478bd9Sstevel@tonic-gate 688ae115bc7Smrj rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn); 689ae115bc7Smrj 690ae115bc7Smrj if (rc != DCMD_OK) 691ae115bc7Smrj return (rc); 692ae115bc7Smrj 693ae115bc7Smrj if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) { 694ae115bc7Smrj mdb_warn("Invalid mfn %lr\n", mfn); 695ae115bc7Smrj return (DCMD_ERR); 696ae115bc7Smrj } 697ae115bc7Smrj 698ae115bc7Smrj if (piped) { 699ae115bc7Smrj mdb_printf("0x%lr\n", pfn); 700ae115bc7Smrj return (DCMD_OK); 701ae115bc7Smrj } 7027c478bd9Sstevel@tonic-gate 703ae115bc7Smrj mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn); 7047c478bd9Sstevel@tonic-gate 705843e1988Sjohnlev if (is_xpv) 706843e1988Sjohnlev mdb_printf(" (mfn 0x%lr)", mfn); 707843e1988Sjohnlev 708ae115bc7Smrj mdb_printf("\n"); 709ae115bc7Smrj 710ae115bc7Smrj return (DCMD_OK); 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate /* 7147c478bd9Sstevel@tonic-gate * Report all hat's that either use PFN as a page table or that map the page. 7157c478bd9Sstevel@tonic-gate */ 7167c478bd9Sstevel@tonic-gate static int 7177c478bd9Sstevel@tonic-gate do_report_maps(pfn_t pfn) 7187c478bd9Sstevel@tonic-gate { 719a85a6733Sjosephb struct hat *hatp; 7207c478bd9Sstevel@tonic-gate struct hat hat; 7217c478bd9Sstevel@tonic-gate htable_t *ht; 7227c478bd9Sstevel@tonic-gate htable_t htable; 7237c478bd9Sstevel@tonic-gate uintptr_t base; 7247c478bd9Sstevel@tonic-gate int h; 7257c478bd9Sstevel@tonic-gate int level; 7267c478bd9Sstevel@tonic-gate int entry; 7277c478bd9Sstevel@tonic-gate x86pte_t pte; 7287c478bd9Sstevel@tonic-gate x86pte_t buf; 7297c478bd9Sstevel@tonic-gate x86pte32_t *pte32 = (x86pte32_t *)&buf; 7307c478bd9Sstevel@tonic-gate physaddr_t paddr; 7317c478bd9Sstevel@tonic-gate size_t len; 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate /* 734a85a6733Sjosephb * The hats are kept in a list with khat at the head. 7357c478bd9Sstevel@tonic-gate */ 736a85a6733Sjosephb for (hatp = khat; hatp != NULL; hatp = hat.hat_next) { 7377c478bd9Sstevel@tonic-gate /* 7387c478bd9Sstevel@tonic-gate * read the hat and its hash table 7397c478bd9Sstevel@tonic-gate */ 7407c478bd9Sstevel@tonic-gate if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) { 7417c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read struct hat\n"); 7427c478bd9Sstevel@tonic-gate return (DCMD_ERR); 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate /* 7467c478bd9Sstevel@tonic-gate * read the htable hashtable 7477c478bd9Sstevel@tonic-gate */ 7487c478bd9Sstevel@tonic-gate paddr = 0; 7497c478bd9Sstevel@tonic-gate for (h = 0; h < hat.hat_num_hash; ++h) { 7507c478bd9Sstevel@tonic-gate if (mdb_vread(&ht, sizeof (htable_t *), 7517c478bd9Sstevel@tonic-gate (uintptr_t)(hat.hat_ht_hash + h)) == -1) { 7527c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read htable\n"); 7537c478bd9Sstevel@tonic-gate return (DCMD_ERR); 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate for (; ht != NULL; ht = htable.ht_next) { 7567c478bd9Sstevel@tonic-gate if (mdb_vread(&htable, sizeof (htable_t), 7577c478bd9Sstevel@tonic-gate (uintptr_t)ht) == -1) { 7587c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read htable\n"); 7597c478bd9Sstevel@tonic-gate return (DCMD_ERR); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate /* 7637c478bd9Sstevel@tonic-gate * only report kernel addresses once 7647c478bd9Sstevel@tonic-gate */ 7657c478bd9Sstevel@tonic-gate if (hatp != khat && 7667c478bd9Sstevel@tonic-gate htable.ht_vaddr >= kernelbase) 7677c478bd9Sstevel@tonic-gate continue; 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate /* 7707c478bd9Sstevel@tonic-gate * Is the PFN a pagetable itself? 7717c478bd9Sstevel@tonic-gate */ 7727c478bd9Sstevel@tonic-gate if (htable.ht_pfn == pfn) { 7737c478bd9Sstevel@tonic-gate mdb_printf("Pagetable for " 7747c478bd9Sstevel@tonic-gate "hat=%p htable=%p\n", hatp, ht); 7757c478bd9Sstevel@tonic-gate continue; 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate /* 7797c478bd9Sstevel@tonic-gate * otherwise, examine page mappings 7807c478bd9Sstevel@tonic-gate */ 7817c478bd9Sstevel@tonic-gate level = htable.ht_level; 7827c478bd9Sstevel@tonic-gate if (level > mmu.max_page_level) 7837c478bd9Sstevel@tonic-gate continue; 784ae115bc7Smrj paddr = mmu_ptob((physaddr_t)htable.ht_pfn); 785ae115bc7Smrj for (entry = 0; 786ae115bc7Smrj entry < HTABLE_NUM_PTES(&htable); 7877c478bd9Sstevel@tonic-gate ++entry) { 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate base = htable.ht_vaddr + entry * 7907c478bd9Sstevel@tonic-gate mmu.level_size[level]; 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate /* 7937c478bd9Sstevel@tonic-gate * only report kernel addresses once 7947c478bd9Sstevel@tonic-gate */ 7957c478bd9Sstevel@tonic-gate if (hatp != khat && 7967c478bd9Sstevel@tonic-gate base >= kernelbase) 7977c478bd9Sstevel@tonic-gate continue; 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate len = mdb_pread(&buf, mmu.pte_size, 8007c478bd9Sstevel@tonic-gate paddr + entry * mmu.pte_size); 8017c478bd9Sstevel@tonic-gate if (len != mmu.pte_size) 8027c478bd9Sstevel@tonic-gate return (DCMD_ERR); 8037c478bd9Sstevel@tonic-gate if (mmu.pte_size == sizeof (x86pte_t)) 8047c478bd9Sstevel@tonic-gate pte = buf; 8057c478bd9Sstevel@tonic-gate else 8067c478bd9Sstevel@tonic-gate pte = *pte32; 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate if ((pte & PT_VALID) == 0) 8097c478bd9Sstevel@tonic-gate continue; 8107c478bd9Sstevel@tonic-gate if (level == 0 || !(pte & PT_PAGESIZE)) 8117c478bd9Sstevel@tonic-gate pte &= PT_PADDR; 8127c478bd9Sstevel@tonic-gate else 8137c478bd9Sstevel@tonic-gate pte &= PT_PADDR_LGPG; 814ae115bc7Smrj if (mmu_btop(mdb_ma_to_pa(pte)) != pfn) 8157c478bd9Sstevel@tonic-gate continue; 8167c478bd9Sstevel@tonic-gate mdb_printf("hat=%p maps addr=%p\n", 817843e1988Sjohnlev hatp, (caddr_t)base); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate } 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate done: 8247c478bd9Sstevel@tonic-gate return (DCMD_OK); 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate /* 8287c478bd9Sstevel@tonic-gate * given a PFN as its address argument, prints out the uses of it 8297c478bd9Sstevel@tonic-gate */ 8307c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8317c478bd9Sstevel@tonic-gate int 8327c478bd9Sstevel@tonic-gate report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 8337c478bd9Sstevel@tonic-gate { 834ae115bc7Smrj pfn_t pfn; 835ae115bc7Smrj uint_t mflag = 0; 836ae115bc7Smrj 837843e1988Sjohnlev init_mmu(); 838843e1988Sjohnlev 8397c478bd9Sstevel@tonic-gate if (mmu.num_level == 0) 8407c478bd9Sstevel@tonic-gate return (DCMD_ERR); 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0) 8437c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 8447c478bd9Sstevel@tonic-gate 845ae115bc7Smrj if (mdb_getopts(argc, argv, 846ae115bc7Smrj 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc) 847ae115bc7Smrj return (DCMD_USAGE); 848ae115bc7Smrj 849ae115bc7Smrj pfn = (pfn_t)addr; 850ae115bc7Smrj if (mflag) 851ae115bc7Smrj pfn = mdb_mfn_to_pfn(pfn); 852ae115bc7Smrj 853ae115bc7Smrj return (do_report_maps(pfn)); 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate static int 8577c478bd9Sstevel@tonic-gate do_ptable_dcmd(pfn_t pfn) 8587c478bd9Sstevel@tonic-gate { 859a85a6733Sjosephb struct hat *hatp; 8607c478bd9Sstevel@tonic-gate struct hat hat; 8617c478bd9Sstevel@tonic-gate htable_t *ht; 8627c478bd9Sstevel@tonic-gate htable_t htable; 8637c478bd9Sstevel@tonic-gate uintptr_t base; 8647c478bd9Sstevel@tonic-gate int h; 8657c478bd9Sstevel@tonic-gate int level; 8667c478bd9Sstevel@tonic-gate int entry; 8677c478bd9Sstevel@tonic-gate uintptr_t pagesize; 8687c478bd9Sstevel@tonic-gate x86pte_t pte; 8697c478bd9Sstevel@tonic-gate x86pte_t buf; 8707c478bd9Sstevel@tonic-gate x86pte32_t *pte32 = (x86pte32_t *)&buf; 8717c478bd9Sstevel@tonic-gate physaddr_t paddr; 8727c478bd9Sstevel@tonic-gate size_t len; 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate /* 875a85a6733Sjosephb * The hats are kept in a list with khat at the head. 8767c478bd9Sstevel@tonic-gate */ 877a85a6733Sjosephb for (hatp = khat; hatp != NULL; hatp = hat.hat_next) { 8787c478bd9Sstevel@tonic-gate /* 8797c478bd9Sstevel@tonic-gate * read the hat and its hash table 8807c478bd9Sstevel@tonic-gate */ 8817c478bd9Sstevel@tonic-gate if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) { 8827c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read struct hat\n"); 8837c478bd9Sstevel@tonic-gate return (DCMD_ERR); 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate /* 8877c478bd9Sstevel@tonic-gate * read the htable hashtable 8887c478bd9Sstevel@tonic-gate */ 8897c478bd9Sstevel@tonic-gate paddr = 0; 8907c478bd9Sstevel@tonic-gate for (h = 0; h < hat.hat_num_hash; ++h) { 8917c478bd9Sstevel@tonic-gate if (mdb_vread(&ht, sizeof (htable_t *), 8927c478bd9Sstevel@tonic-gate (uintptr_t)(hat.hat_ht_hash + h)) == -1) { 8937c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read htable\n"); 8947c478bd9Sstevel@tonic-gate return (DCMD_ERR); 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate for (; ht != NULL; ht = htable.ht_next) { 8977c478bd9Sstevel@tonic-gate if (mdb_vread(&htable, sizeof (htable_t), 8987c478bd9Sstevel@tonic-gate (uintptr_t)ht) == -1) { 8997c478bd9Sstevel@tonic-gate mdb_warn("Couldn't read htable\n"); 9007c478bd9Sstevel@tonic-gate return (DCMD_ERR); 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate /* 9047c478bd9Sstevel@tonic-gate * Is this the PFN for this htable 9057c478bd9Sstevel@tonic-gate */ 9067c478bd9Sstevel@tonic-gate if (htable.ht_pfn == pfn) 9077c478bd9Sstevel@tonic-gate goto found_it; 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate found_it: 9137c478bd9Sstevel@tonic-gate if (htable.ht_pfn == pfn) { 9147c478bd9Sstevel@tonic-gate mdb_printf("htable=%p\n", ht); 9157c478bd9Sstevel@tonic-gate level = htable.ht_level; 9167c478bd9Sstevel@tonic-gate base = htable.ht_vaddr; 9177c478bd9Sstevel@tonic-gate pagesize = mmu.level_size[level]; 9187c478bd9Sstevel@tonic-gate } else { 9197c478bd9Sstevel@tonic-gate mdb_printf("Unknown pagetable - assuming level/addr 0"); 9207c478bd9Sstevel@tonic-gate level = 0; /* assume level == 0 for PFN */ 9217c478bd9Sstevel@tonic-gate base = 0; 9227c478bd9Sstevel@tonic-gate pagesize = MMU_PAGESIZE; 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate 925ae115bc7Smrj paddr = mmu_ptob((physaddr_t)pfn); 9267c478bd9Sstevel@tonic-gate for (entry = 0; entry < mmu.ptes_per_table; ++entry) { 9277c478bd9Sstevel@tonic-gate len = mdb_pread(&buf, mmu.pte_size, 9287c478bd9Sstevel@tonic-gate paddr + entry * mmu.pte_size); 9297c478bd9Sstevel@tonic-gate if (len != mmu.pte_size) 9307c478bd9Sstevel@tonic-gate return (DCMD_ERR); 9317c478bd9Sstevel@tonic-gate if (mmu.pte_size == sizeof (x86pte_t)) 9327c478bd9Sstevel@tonic-gate pte = buf; 9337c478bd9Sstevel@tonic-gate else 9347c478bd9Sstevel@tonic-gate pte = *pte32; 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate if (pte == 0) 9377c478bd9Sstevel@tonic-gate continue; 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize); 9407c478bd9Sstevel@tonic-gate do_pte_dcmd(level, pte); 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate done: 9447c478bd9Sstevel@tonic-gate return (DCMD_OK); 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate /* 948ae115bc7Smrj * Dump the page table at the given PFN 9497c478bd9Sstevel@tonic-gate */ 9507c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9517c478bd9Sstevel@tonic-gate int 9527c478bd9Sstevel@tonic-gate ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 9537c478bd9Sstevel@tonic-gate { 954ae115bc7Smrj pfn_t pfn; 955ae115bc7Smrj uint_t mflag = 0; 956ae115bc7Smrj 957843e1988Sjohnlev init_mmu(); 958843e1988Sjohnlev 959ae115bc7Smrj if (mmu.num_level == 0) 960ae115bc7Smrj return (DCMD_ERR); 961ae115bc7Smrj 962ae115bc7Smrj if ((flags & DCMD_ADDRSPEC) == 0) 963ae115bc7Smrj return (DCMD_USAGE); 964ae115bc7Smrj 965ae115bc7Smrj if (mdb_getopts(argc, argv, 966ae115bc7Smrj 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc) 967ae115bc7Smrj return (DCMD_USAGE); 968ae115bc7Smrj 969ae115bc7Smrj pfn = (pfn_t)addr; 970ae115bc7Smrj if (mflag) 971ae115bc7Smrj pfn = mdb_mfn_to_pfn(pfn); 972ae115bc7Smrj 973ae115bc7Smrj return (do_ptable_dcmd(pfn)); 974ae115bc7Smrj } 975ae115bc7Smrj 976ae115bc7Smrj static int 977ae115bc7Smrj do_htables_dcmd(hat_t *hatp) 978ae115bc7Smrj { 979ae115bc7Smrj struct hat hat; 980ae115bc7Smrj htable_t *ht; 981ae115bc7Smrj htable_t htable; 982ae115bc7Smrj int h; 983ae115bc7Smrj 984ae115bc7Smrj /* 985ae115bc7Smrj * read the hat and its hash table 986ae115bc7Smrj */ 987ae115bc7Smrj if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) { 988ae115bc7Smrj mdb_warn("Couldn't read struct hat\n"); 989ae115bc7Smrj return (DCMD_ERR); 990ae115bc7Smrj } 991ae115bc7Smrj 992ae115bc7Smrj /* 993ae115bc7Smrj * read the htable hashtable 994ae115bc7Smrj */ 995ae115bc7Smrj for (h = 0; h < hat.hat_num_hash; ++h) { 996ae115bc7Smrj if (mdb_vread(&ht, sizeof (htable_t *), 997ae115bc7Smrj (uintptr_t)(hat.hat_ht_hash + h)) == -1) { 998ae115bc7Smrj mdb_warn("Couldn't read htable ptr\\n"); 999ae115bc7Smrj return (DCMD_ERR); 1000ae115bc7Smrj } 1001ae115bc7Smrj for (; ht != NULL; ht = htable.ht_next) { 1002ae115bc7Smrj mdb_printf("%p\n", ht); 1003ae115bc7Smrj if (mdb_vread(&htable, sizeof (htable_t), 1004ae115bc7Smrj (uintptr_t)ht) == -1) { 1005ae115bc7Smrj mdb_warn("Couldn't read htable\n"); 1006ae115bc7Smrj return (DCMD_ERR); 1007ae115bc7Smrj } 1008ae115bc7Smrj } 1009ae115bc7Smrj } 1010ae115bc7Smrj return (DCMD_OK); 1011ae115bc7Smrj } 1012ae115bc7Smrj 1013ae115bc7Smrj /* 1014ae115bc7Smrj * Dump the htables for the given hat 1015ae115bc7Smrj */ 1016ae115bc7Smrj /*ARGSUSED*/ 1017ae115bc7Smrj int 1018ae115bc7Smrj htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1019ae115bc7Smrj { 1020ae115bc7Smrj hat_t *hat; 1021ae115bc7Smrj 1022843e1988Sjohnlev init_mmu(); 1023843e1988Sjohnlev 10247c478bd9Sstevel@tonic-gate if (mmu.num_level == 0) 10257c478bd9Sstevel@tonic-gate return (DCMD_ERR); 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) == 0) 10287c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 10297c478bd9Sstevel@tonic-gate 1030ae115bc7Smrj hat = (hat_t *)addr; 1031ae115bc7Smrj 1032ae115bc7Smrj return (do_htables_dcmd(hat)); 10337c478bd9Sstevel@tonic-gate } 1034