4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/machparam.h>
29 #include <vm/hat_sfmmu.h>
31 #include <mdb/mdb_modapi.h>
32 #include <mdb/mdb_target.h>
33 #include <mdb/mdb_ctf.h>
39 #define SFMMU_VTOP_DBG_SYMBOL 1
40 #define SFMMU_VTOP_DBG_VERBOSE 2
41 #define SFMMU_VTOP_DBG_DEBUG 4
42 #define SFMMU_VTOP_DBG_ALL (SFMMU_VTOP_DBG_SYMBOL|SFMMU_VTOP_DBG_VERBOSE|\
45 #define SFMMU_VTOP_DBG_SYM if (sfmmu_vtop_dbg & SFMMU_VTOP_DBG_SYMBOL) \
47 #define SFMMU_VTOP_DBG_VRB if (sfmmu_vtop_dbg & SFMMU_VTOP_DBG_VERBOSE) \
49 #define SFMMU_VTOP_DBG_DBG if (sfmmu_vtop_dbg & SFMMU_VTOP_DBG_DEBUG) \
52 #define SFMMU_VTOP_READSYM(dest, synm, where) \
53 if (mdb_readsym(&(dest), sizeof (dest), (synm)) == -1) \
54 mdb_warn("%s: couldn't find or read '%s'\n", (where), (synm));
57 struct hme_blk hmx_hmeblk
;
58 struct sf_hment hmx_hmes
[NHMENTS
- 1];
61 int sfmmu_vtop(uintptr_t, uint_t
, int, const mdb_arg_t
*);
62 static int sfmmu_vtop_common(struct as
*, uintptr_t, physaddr_t
*);
63 static int sfmmu_vtop_impl(uintptr_t, sfmmu_t
*, sfmmu_t
*, physaddr_t
*);
64 static void sfmmu_vtop_print_hmeblk(struct hme_blk
*);
65 static struct sf_hment
*mdb_sfmmu_hblktohme(struct hme_blk
*, caddr_t
, int *);
67 int sfmmu_vtop_dbg_wanted
= 0; /* set this as desired */
68 int sfmmu_vtop_dbg
= 0;
71 * ::sfmmu_vtop [[-v] -a as]
72 * Extended version of the vtop builtin. The optional <as> argument is
73 * used as base address space for translating a virtual address into a
74 * physical address. The verbose option ("-v") shows intermediate
75 * translation steps. If <as> or kas is ommitted, the builtin ::vtop
79 sfmmu_vtop(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
82 struct as
*asp
= NULL
;
87 sfmmu_vtop_dbg
= sfmmu_vtop_dbg_wanted
;
89 if (mdb_getopts(argc
, argv
,
90 'v', MDB_OPT_SETBITS
, TRUE
, &verbose
,
91 'a', MDB_OPT_STR
, &asnmp
,
95 if (verbose
!= 0 && asnmp
== NULL
) {
96 mdb_warn("-v requires -a option\n");
100 if (verbose
!= 0 && (sfmmu_vtop_dbg
& SFMMU_VTOP_DBG_VERBOSE
) == 0) {
101 sfmmu_vtop_dbg
|= SFMMU_VTOP_DBG_VERBOSE
;
107 SFMMU_VTOP_DBG_DBG("asnmp=%p asnm=%s\n", asnmp
, asnmp
);
108 if (strcmp(asnmp
, "kas") == 0) {
109 if (mdb_lookup_by_name("kas", &sym
) == -1) {
110 mdb_warn("couldn't find 'kas'\n");
113 asp
= (struct as
*)sym
.st_value
;
114 SFMMU_VTOP_DBG_SYM("kas &sym=%p\n", &sym
);
117 asp
= (struct as
*)mdb_strtoull(asnmp
);
119 SFMMU_VTOP_DBG_DBG("asp=0x%p\n", asp
);
123 SFMMU_VTOP_DBG_DBG("sfmmu_vtop: call standard vtop\n");
124 return (mdb_call_dcmd("vtop", addr
, flags
, argc
, argv
));
127 if ((ret
= sfmmu_vtop_common(asp
, addr
, &paddr
)) == -1L) {
128 mdb_printf("no mapping found for addr=%p\n", addr
);
133 mdb_printf("address space %p: virtual %lr mapped to physical "
134 "%llr", asp
, addr
, paddr
);
143 sfmmu_vtop_common(struct as
*asp
, uintptr_t addr
, physaddr_t
*pap
)
146 struct as
*masp
= &mas
;
149 sfmmu_t
*mhatp
= &mhat
;
152 if (mdb_vread(masp
, sizeof (mas
), (uintptr_t)asp
) == -1) {
153 mdb_warn("couldn't read as at %p\n", asp
);
159 SFMMU_VTOP_DBG_DBG("hatp=%p addr=%p masp=%p\n", hatp
, addr
, masp
);
161 if (mdb_vread(mhatp
, sizeof (mhat
), (uintptr_t)hatp
) == -1) {
162 mdb_warn("couldn't read hat at %p\n", hatp
);
165 if (mhatp
->sfmmu_as
!= asp
) {
166 mdb_warn("%p is not a valid address space\n", asp
);
170 ret
= sfmmu_vtop_impl(addr
, hatp
, mhatp
, pap
);
176 sfmmu_vtop_impl(uintptr_t addr
, sfmmu_t
*sfmmup
, sfmmu_t
*msfmmup
,
179 struct hmehash_bucket
*uhme_hash
;
180 struct hmehash_bucket
*khme_hash
;
184 struct hmehash_bucket mbucket
;
185 struct hmehash_bucket
*hmebp
;
186 struct hmehash_bucket
*shmebp
;
190 struct hme_blk
*hmeblkp
= NULL
;
191 struct hme_blks_max mhmeblkmax
;
193 struct sf_hment
*sfhmep
;
198 ism_blk_t
*sism_blkp
;
199 sfmmu_t
*ism_hatid
= NULL
;
207 SFMMU_VTOP_READSYM(uhme_hash
, "uhme_hash", "sfmmu_vtop_impl");
208 SFMMU_VTOP_DBG_DBG("uhme_hash=%p\t", uhme_hash
);
209 SFMMU_VTOP_READSYM(uhmehash_num
, "uhmehash_num", "sfmmu_vtop_impl");
210 SFMMU_VTOP_DBG_DBG("uhmehash_num=%lx\n", uhmehash_num
);
211 SFMMU_VTOP_READSYM(khme_hash
, "khme_hash", "sfmmu_vtop_impl");
212 SFMMU_VTOP_DBG_DBG("khme_hash=%p\t", khme_hash
);
213 SFMMU_VTOP_READSYM(khmehash_num
, "khmehash_num", "sfmmu_vtop_impl");
214 SFMMU_VTOP_DBG_DBG("khmehash_num=%lx\n", khmehash_num
);
215 SFMMU_VTOP_READSYM(ksfmmup
, "ksfmmup", "sfmmu_vtop_impl");
216 SFMMU_VTOP_DBG_DBG("ksfmmup=%p\n", ksfmmup
);
218 ism_blkp
= sism_blkp
= msfmmup
->sfmmu_iblk
;
219 while (ism_blkp
!= NULL
&& ism_hatid
== NULL
) {
220 SFMMU_VTOP_DBG_DBG("ism_blkp=%p\n", ism_blkp
);
221 if (mdb_vread(&mism_blk
, sizeof (mism_blk
),
222 (uintptr_t)ism_blkp
) == -1) {
223 mdb_warn("couldn't read ism_blk at %p\n", ism_blkp
);
226 ism_blkp
= &mism_blk
;
227 ism_map
= ism_blkp
->iblk_maps
;
228 for (i
= 0; ism_map
[i
].imap_ismhat
&& i
< ISM_MAP_SLOTS
; i
++) {
229 if ((caddr_t
)addr
>= ism_start(ism_map
[i
]) &&
230 (caddr_t
)addr
< ism_end(ism_map
[i
])) {
231 sfmmup
= ism_hatid
= ism_map
[i
].imap_ismhat
;
232 addr
= (caddr_t
)addr
- ism_start(ism_map
[i
]);
233 SFMMU_VTOP_DBG_VRB("ism_blkp=%p inx=%d\n",
235 SFMMU_VTOP_DBG_DBG("ism map=%p ism hat=%p "
237 (caddr_t
)&ism_map
[i
] - (caddr_t
)ism_blkp
238 + (caddr_t
)sism_blkp
, sfmmup
, addr
);
242 ism_blkp
= sism_blkp
= ism_blkp
->iblk_next
;
245 hblktag
.htag_id
= sfmmup
;
247 SFMMU_VTOP_DBG_DBG("-hashno=%d-\n", hashno
);
248 hmeshift
= HME_HASH_SHIFT(hashno
);
249 SFMMU_VTOP_DBG_DBG("hmeshift=%d\n", hmeshift
);
250 hblktag
.htag_bspage
= HME_HASH_BSPAGE(addr
, hmeshift
);
251 hblktag
.htag_rehash
= hashno
;
254 SFMMU_VTOP_DBG_DBG("hblktag=%lx %lx\n",
255 (uint64_t)hblktag
.htag_tag
[0],
256 (uint64_t)hblktag
.htag_tag
[1]);
258 SFMMU_VTOP_DBG_DBG("hblktag=%llx\n",
259 (uint64_t)hblktag
.htag_tag
);
262 hmebp
= shmebp
= HME_HASH_FUNCTION(sfmmup
, addr
, hmeshift
);
263 SFMMU_VTOP_DBG_DBG("hmebp=%p\n", hmebp
);
265 if (mdb_vread(&mbucket
, sizeof (mbucket
),
266 (uintptr_t)hmebp
) == -1) {
267 mdb_warn("couldn't read mbucket at %p\n", hmebp
);
273 for (hmeblkp
= hmebp
->hmeblkp
; hmeblkp
;
274 hmeblkp
= hmeblkp
->hblk_next
) {
276 SFMMU_VTOP_DBG_DBG("hmeblkp=%p\n", hmeblkp
);
281 if (mdb_vread(&mhmeblkmax
, sizeof (struct hme_blk
),
282 (uintptr_t)hmeblkp
) == -1) {
283 mdb_warn("couldn't read hme_blk at %p\n",
288 thmeblkp
= (uintptr_t)hmeblkp
;
289 hmeblkp
= &mhmeblkmax
.hmx_hmeblk
;
291 if (HTAGS_EQ(hmeblkp
->hblk_tag
, hblktag
)) {
297 if (hmeblkp
!= NULL
) {
298 sfmmu_vtop_print_hmeblk(hmeblkp
);
300 sfhmep
= mdb_sfmmu_hblktohme(hmeblkp
, (caddr_t
)addr
,
303 SFMMU_VTOP_DBG_DBG("sfhmeinx=%d ", sfhmeinx
);
306 thmeblkp
+= sizeof (struct hme_blk
) +
307 sizeof (struct sf_hment
) * (sfhmeinx
- 1);
309 if (mdb_vread(sfhmep
, sizeof (struct sf_hment
),
311 mdb_warn("couldn't read msfhme at %p\n",
317 SFMMU_VTOP_DBG_VRB("sfmmup=%p hmebp=%p hmeblkp=%p\n",
318 sfmmup
, shmebp
, thmeblkp
);
320 tte
= sfhmep
->hme_tte
;
321 SFMMU_VTOP_DBG_VRB("tte=%llx ", tte
.ll
);
322 if (TTE_IS_VALID(&tte
)) {
323 start_pfn
= TTE_TO_TTEPFN(&tte
);
324 *pap
= (start_pfn
<< MMU_PAGESHIFT
) +
325 (addr
& TTE_PAGE_OFFSET(tte
.tte_size
));
326 pfn
= *pap
>> MMU_PAGESHIFT
;
327 pp
= (sfhmep
->hme_page
!= 0) ?
328 sfhmep
->hme_page
+ (pfn
- start_pfn
) :
330 SFMMU_VTOP_DBG_VRB("pfn=%lx pp=%p\n",
339 } while (HME_REHASH(msfmmup
) && (hashno
<= MAX_HASHCNT
));
345 sfmmu_vtop_print_hmeblk(struct hme_blk
*hmeblkp
)
348 if ((sfmmu_vtop_dbg
& SFMMU_VTOP_DBG_DEBUG
) == NULL
)
351 mdb_printf(" hblk_nextpa=%llx\n", hmeblkp
->hblk_nextpa
);
353 mdb_printf(" hblktag=%lx %lx\n", hmeblkp
->hblk_tag
.htag_tag
[0],
354 hmeblkp
->hblk_tag
.htag_tag
[1]);
356 mdb_printf(" hblktag=%llx\n", hmeblkp
->hblk_tag
.htag_tag
);
358 mdb_printf(" hblk_next=%p\n", hmeblkp
->hblk_next
);
359 mdb_printf(" hblk_shadow=%p\n", hmeblkp
->hblk_shadow
);
360 mdb_printf(" hblk_span=%d\n", hmeblkp
->hblk_span
);
361 mdb_printf(" hblk_ttesz=%d\n", hmeblkp
->hblk_ttesz
);
362 if (hmeblkp
->hblk_shw_bit
== 0) {
363 mdb_printf(" hblk_hmecnt=%d\n", hmeblkp
->hblk_hmecnt
);
364 mdb_printf(" hblk_vcnt=%d\n", hmeblkp
->hblk_vcnt
);
366 mdb_printf(" hblk_shw_mask=%x\n", hmeblkp
->hblk_shw_mask
);
370 static struct sf_hment
*
371 mdb_sfmmu_hblktohme(struct hme_blk
*hmeblkp
, caddr_t addr
, int *hmenump
)
375 if (get_hblk_ttesz(hmeblkp
) == TTE8K
) {
376 index
= (((uintptr_t)addr
>> MMU_PAGESHIFT
) & (NHMENTS
-1));
383 return (&hmeblkp
->hblk_hme
[index
]);
391 memseg_list(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
395 if (!(flags
& DCMD_ADDRSPEC
)) {
396 if (mdb_pwalk_dcmd("memseg", "memseg_list",
398 mdb_warn("can't walk memseg");
404 if (DCMD_HDRSPEC(flags
))
405 mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
406 "PAGES", "EPAGES", "BASE", "END");
408 if (mdb_vread(&ms
, sizeof (struct memseg
), addr
) == -1) {
409 mdb_warn("can't read memseg at %#lx", addr
);
413 mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr
,
414 ms
.pages
, ms
.epages
, ms
.pages_base
, ms
.pages_end
);
420 * walk the memseg structures
423 memseg_walk_init(mdb_walk_state_t
*wsp
)
425 if (wsp
->walk_addr
!= NULL
) {
426 mdb_warn("memseg only supports global walks\n");
430 if (mdb_readvar(&wsp
->walk_addr
, "memsegs") == -1) {
431 mdb_warn("symbol 'memsegs' not found");
435 wsp
->walk_data
= mdb_alloc(sizeof (struct memseg
), UM_SLEEP
);
441 memseg_walk_step(mdb_walk_state_t
*wsp
)
445 if (wsp
->walk_addr
== 0) {
449 if (mdb_vread(wsp
->walk_data
, sizeof (struct memseg
),
450 wsp
->walk_addr
) == -1) {
451 mdb_warn("failed to read struct memseg at %p", wsp
->walk_addr
);
455 status
= wsp
->walk_callback(wsp
->walk_addr
, wsp
->walk_data
,
458 wsp
->walk_addr
= (uintptr_t)(((struct memseg
*)wsp
->walk_data
)->next
);
464 memseg_walk_fini(mdb_walk_state_t
*wsp
)
466 mdb_free(wsp
->walk_data
, sizeof (struct memseg
));
470 platform_vtop(uintptr_t addr
, struct as
*asp
, physaddr_t
*pap
)
474 sfmmu_vtop_dbg
= sfmmu_vtop_dbg_wanted
;
476 SFMMU_VTOP_DBG_DBG("platform_vtop: called.\n");
482 if ((rv
= sfmmu_vtop_common(asp
, addr
, pap
)) == 0) {
483 mdb_printf("address space %p: ", asp
);
495 mdb_printf("-l\tlist valid TSB entries.\n"
496 "-a\tlist all TSB entries. Can only be used with -l.\n");
503 tsbinfo_list(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
505 uint_t lflag
= 0, aflag
= 0;
506 struct tsb_info tsbinfo
;
507 unsigned int entries
= 0;
508 struct tsbe
*tsbp
, *tsbend
, *tsbstart
;
513 #define FLAGS_SIZE sizeof ("RELOC,FLUSH,SWAPPED")
514 char tsbflags
[FLAGS_SIZE
+ 1];
516 static const mdb_bitmask_t ttesz_mask_bits
[] = {
517 { "8K", TSB8K
, TSB8K
},
518 { "64K", TSB64K
, TSB64K
},
519 { "512K", TSB512K
, TSB512K
},
520 { "4M", TSB4M
, TSB4M
},
521 { "32M", TSB32M
, TSB32M
},
522 { "256M", TSB256M
, TSB256M
},
526 static const mdb_bitmask_t flags_bits
[] = {
527 { "RELOC", TSB_RELOC_FLAG
, TSB_RELOC_FLAG
},
528 { "FLUSH", TSB_FLUSH_NEEDED
, TSB_FLUSH_NEEDED
},
529 { "SWAPPED", TSB_SWAPPED
, TSB_SWAPPED
},
533 if (!(flags
& DCMD_ADDRSPEC
)) {
537 if (mdb_getopts(argc
, argv
,
538 'l', MDB_OPT_SETBITS
, TRUE
, &lflag
,
539 'a', MDB_OPT_SETBITS
, TRUE
, &aflag
,
544 /* -a only valid with -l */
545 if (aflag
&& !lflag
) {
550 if (DCMD_HDRSPEC(flags
) || lflag
) {
551 mdb_printf("%<u>%-?s %-?s %-8s %-*s %s%</u>\n", "TSBINFO",
552 "TSB", "SIZE", FLAGS_SIZE
, "FLAGS", "TTE SIZES");
555 if (mdb_vread(&tsbinfo
, sizeof (struct tsb_info
), addr
) == -1) {
556 mdb_warn("failed to read struct tsb_info at %p", addr
);
560 mdb_printf("%0?lx ", addr
);
562 /* Print a "-" if the TSB is swapped out. */
563 if ((tsbinfo
.tsb_flags
& TSB_SWAPPED
) == 0) {
564 mdb_printf("%0?lx ", tsbinfo
.tsb_va
);
566 mdb_printf("%0?-s ", "-");
569 tsbbytes
= TSB_BYTES(tsbinfo
.tsb_szc
);
573 if (tsbbytes
>= MB
) {
574 mdb_snprintf(tsbsize
, sizeof (tsbsize
), "%dM", tsbbytes
/ MB
);
576 mdb_snprintf(tsbsize
, sizeof (tsbsize
), "%dK", tsbbytes
/ KB
);
580 mdb_printf("%-8s ", tsbsize
);
582 if (tsbinfo
.tsb_flags
== 0) {
583 mdb_printf("%-*s ", FLAGS_SIZE
, "-");
585 mdb_snprintf(tsbflags
, sizeof (tsbflags
), "%b",
586 tsbinfo
.tsb_flags
, flags_bits
);
587 mdb_printf("%-*s ", FLAGS_SIZE
, tsbflags
);
590 mdb_printf("%b\n", tsbinfo
.tsb_ttesz_mask
, ttesz_mask_bits
);
592 /* Print TSB entries? */
595 if ((tsbinfo
.tsb_flags
& TSB_SWAPPED
) == 0) {
597 entries
= TSB_ENTRIES(tsbinfo
.tsb_szc
);
599 tsbp
= mdb_alloc(sizeof (struct tsbe
) * entries
,
602 if (mdb_vread(tsbp
, sizeof (struct tsbe
) * entries
,
603 (uintptr_t)tsbinfo
.tsb_va
) == -1) {
604 mdb_warn("failed to read TSB at %p",
610 "TSB @ %lx (%d entries)\n"
612 "%<u>%-?s %1s %1s %-11s "
613 "%1s %1s %1s %1s %1s %1s %8s "
614 "%1s %1s %1s %1s %1s %1s %1s "
615 "%1s %1s %1s %1s %1s %1s%</u>\n",
616 tsbinfo
.tsb_va
, entries
, "", "TAG", "TTE",
617 "ADDR", "I", "L", "VA 63:22",
618 "V", "S", "N", "I", "H", "S", "PA 42:13",
619 "N", "U", "R", "W", "E", "X", "L",
620 "P", "V", "E", "P", "W", "G");
622 tsbend
= tsbp
+ entries
;
623 for (tsbstart
= tsbp
; tsbp
< tsbend
; tsbp
++) {
625 (tsbp
->tte_tag
.tag_invalid
== 0)) {
628 (((uint64_t)tsbp
->tte_tag
.tag_vahi
630 tsbp
->tte_tag
.tag_valo
);
631 pa
= (tsbp
->tte_data
.tte_pahi
<< 19) +
632 tsbp
->tte_data
.tte_palo
;
633 mdb_printf("%0?lx %-1u %-1u %011lx "
634 "%1u %-1u %-1u %-1u %-1u %1u %08x "
635 "%1u %1u %1u %1u %1u %1u %1u "
636 "%1u %1u %1u %1u %1u %1u\n",
637 tsbinfo
.tsb_va
+ (tsbp
- tsbstart
)
638 * sizeof (struct tsbe
),
639 tsbp
->tte_tag
.tag_invalid
,
640 tsbp
->tte_tag
.tag_locked
, va
,
641 tsbp
->tte_data
.tte_val
,
642 tsbp
->tte_data
.tte_size
,
643 tsbp
->tte_data
.tte_nfo
,
644 tsbp
->tte_data
.tte_ie
,
645 tsbp
->tte_data
.tte_hmenum
,
649 tsbp
->tte_data
.tte_size2
,
652 tsbp
->tte_data
.tte_no_sync
,
653 tsbp
->tte_data
.tte_suspend
,
654 tsbp
->tte_data
.tte_ref
,
655 tsbp
->tte_data
.tte_wr_perm
,
659 tsbp
->tte_data
.tte_exec_synth
,
661 tsbp
->tte_data
.tte_exec_perm
,
662 tsbp
->tte_data
.tte_lock
,
663 tsbp
->tte_data
.tte_cp
,
664 tsbp
->tte_data
.tte_cv
,
665 tsbp
->tte_data
.tte_se
,
666 tsbp
->tte_data
.tte_priv
,
667 tsbp
->tte_data
.tte_hwwr
,
671 tsbp
->tte_data
.tte_glb
678 mdb_printf("\n"); /* blank line for readability */
680 mdb_free(tsbstart
, sizeof (struct tsbe
) * entries
);
684 mdb_printf("TSB swapped out\n");