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.
27 * This part of the file contains the mdb support for dcmds:
30 * memseg - a memseg list walker for ::memseg_list
34 #include <sys/types.h>
35 #include <sys/machparam.h>
36 #include <sys/controlregs.h>
37 #include <sys/mach_mmu.h>
40 #include <mdb/mdb_modapi.h>
41 #include <mdb/mdb_target.h>
44 #include <vm/hat_i86.h>
51 static int do_va2pa(uintptr_t, struct as
*, int, physaddr_t
*, pfn_t
*);
52 static void init_mmu(void);
55 platform_vtop(uintptr_t addr
, struct as
*asp
, physaddr_t
*pap
)
62 if (mmu
.num_level
== 0)
65 return (do_va2pa(addr
, asp
, 0, pap
, NULL
));
69 * ::memseg_list dcmd and walker to implement it.
73 memseg_list(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
77 if (!(flags
& DCMD_ADDRSPEC
)) {
78 if (mdb_pwalk_dcmd("memseg", "memseg_list",
80 mdb_warn("can't walk memseg");
86 if (DCMD_HDRSPEC(flags
))
87 mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
88 "PAGES", "EPAGES", "BASE", "END");
90 if (mdb_vread(&ms
, sizeof (struct memseg
), addr
) == -1) {
91 mdb_warn("can't read memseg at %#lx", addr
);
95 mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr
,
96 ms
.pages
, ms
.epages
, ms
.pages_base
, ms
.pages_end
);
102 * walk the memseg structures
105 memseg_walk_init(mdb_walk_state_t
*wsp
)
107 if (wsp
->walk_addr
!= (uintptr_t)NULL
) {
108 mdb_warn("memseg only supports global walks\n");
112 if (mdb_readvar(&wsp
->walk_addr
, "memsegs") == -1) {
113 mdb_warn("symbol 'memsegs' not found");
117 wsp
->walk_data
= mdb_alloc(sizeof (struct memseg
), UM_SLEEP
);
123 memseg_walk_step(mdb_walk_state_t
*wsp
)
127 if (wsp
->walk_addr
== (uintptr_t)NULL
) {
131 if (mdb_vread(wsp
->walk_data
, sizeof (struct memseg
),
132 wsp
->walk_addr
) == -1) {
133 mdb_warn("failed to read struct memseg at %p", wsp
->walk_addr
);
137 status
= wsp
->walk_callback(wsp
->walk_addr
, wsp
->walk_data
,
140 wsp
->walk_addr
= (uintptr_t)(((struct memseg
*)wsp
->walk_data
)->next
);
146 memseg_walk_fini(mdb_walk_state_t
*wsp
)
148 mdb_free(wsp
->walk_data
, sizeof (struct memseg
));
152 * Now HAT related dcmds.
155 static struct hat
*khat
; /* value of kas.a_hat */
156 struct hat_mmu_info mmu
;
157 uintptr_t kernelbase
;
160 * stuff for i86xpv images
163 static uintptr_t mfn_list_addr
; /* kernel MFN list address */
164 uintptr_t xen_virt_start
; /* address of mfn_to_pfn[] table */
165 ulong_t mfn_count
; /* number of pfn's in the MFN list */
166 pfn_t
*mfn_list
; /* local MFN list copy */
169 * read mmu parameters from kernel
176 if (mmu
.num_level
!= 0)
179 if (mdb_readsym(&mmu
, sizeof (mmu
), "mmu") == -1)
180 mdb_warn("Can't use HAT information before mmu_init()\n");
181 if (mdb_readsym(&kas
, sizeof (kas
), "kas") == -1)
182 mdb_warn("Couldn't find kas - kernel's struct as\n");
183 if (mdb_readsym(&kernelbase
, sizeof (kernelbase
), "kernelbase") == -1)
184 mdb_warn("Couldn't find kernelbase\n");
188 * Is this a paravirtualized domain image?
190 if (mdb_readsym(&mfn_list_addr
, sizeof (mfn_list_addr
),
192 mdb_readsym(&xen_virt_start
, sizeof (xen_virt_start
),
193 "xen_virt_start") == -1 ||
194 mdb_readsym(&mfn_count
, sizeof (mfn_count
), "mfn_count") == -1) {
195 mfn_list_addr
= (uintptr_t)NULL
;
198 is_xpv
= mfn_list_addr
!= (uintptr_t)NULL
;
202 * recreate the local mfn_list
205 size_t sz
= mfn_count
* sizeof (pfn_t
);
206 mfn_list
= mdb_zalloc(sz
, UM_SLEEP
);
208 if (mdb_vread(mfn_list
, sz
, (uintptr_t)mfn_list_addr
) == -1) {
209 mdb_warn("Failed to read MFN list\n");
210 mdb_free(mfn_list
, sz
);
223 #define mdb_ma_to_pa(ma) (ma)
224 #define mdb_mfn_to_pfn(mfn) (mfn)
225 #define mdb_pfn_to_mfn(pfn) (pfn)
229 * ::mfntopfn dcmd translates hypervisor machine page number
230 * to physical page number
234 mfntopfn_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
238 if ((flags
& DCMD_ADDRSPEC
) == 0) {
239 mdb_warn("MFN missing\n");
243 if ((pfn
= mdb_mfn_to_pfn((pfn_t
)addr
)) == -(pfn_t
)1) {
244 mdb_warn("Invalid mfn %lr\n", (pfn_t
)addr
);
248 mdb_printf("%lr\n", pfn
);
254 * ::pfntomfn dcmd translates physical page number to
255 * hypervisor machine page number
259 pfntomfn_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
263 if ((flags
& DCMD_ADDRSPEC
) == 0) {
264 mdb_warn("PFN missing\n");
268 if ((mfn
= mdb_pfn_to_mfn((pfn_t
)addr
)) == -(pfn_t
)1) {
269 mdb_warn("Invalid pfn %lr\n", (pfn_t
)addr
);
273 mdb_printf("%lr\n", mfn
);
275 if (flags
& DCMD_LOOP
)
276 mdb_set_dot(addr
+ 1);
281 pte2mfn(x86pte_t pte
, uint_t level
)
284 if (level
> 0 && (pte
& PT_PAGESIZE
))
285 mfn
= mmu_btop(pte
& PT_PADDR_LGPG
);
287 mfn
= mmu_btop(pte
& PT_PADDR
);
292 * Print a PTE in more human friendly way. The PTE is assumed to be in
293 * a level 0 page table, unless -l specifies another level.
295 * The PTE value can be specified as the -p option, since on a 32 bit kernel
296 * with PAE running it's larger than a uintptr_t.
299 do_pte_dcmd(int level
, uint64_t pte
)
301 static char *attr
[] = {
302 "wrback", "wrthru", "uncached", "uncached",
303 "wrback", "wrthru", "wrcombine", "uncached"};
307 mdb_printf("pte=%llr: ", pte
);
308 if (PTE_GET(pte
, mmu
.pt_nx
))
309 mdb_printf("noexec ");
311 mfn
= pte2mfn(pte
, level
);
312 mdb_printf("%s=0x%lr ", is_xpv
? "mfn" : "pfn", mfn
);
314 if (PTE_GET(pte
, PT_NOCONSIST
))
315 mdb_printf("noconsist ");
317 if (PTE_GET(pte
, PT_NOSYNC
))
318 mdb_printf("nosync ");
320 if (PTE_GET(pte
, mmu
.pt_global
))
321 mdb_printf("global ");
323 if (level
> 0 && PTE_GET(pte
, PT_PAGESIZE
))
324 mdb_printf("largepage ");
326 if (level
> 0 && PTE_GET(pte
, PT_MOD
))
329 if (level
> 0 && PTE_GET(pte
, PT_REF
))
332 if (PTE_GET(pte
, PT_USER
))
335 if (PTE_GET(pte
, PT_WRITABLE
))
336 mdb_printf("write ");
339 * Report non-standard cacheability
343 if (PTE_GET(pte
, PT_PAGESIZE
) && PTE_GET(pte
, PT_PAT_LARGE
))
346 if (PTE_GET(pte
, PT_PAT_4K
))
350 if (PTE_GET(pte
, PT_NOCACHE
))
353 if (PTE_GET(pte
, PT_WRITETHRU
))
357 mdb_printf("%s", attr
[pat_index
]);
359 if (PTE_GET(pte
, PT_VALID
) == 0)
360 mdb_printf(" !VALID ");
367 * Print a PTE in more human friendly way. The PTE is assumed to be in
368 * a level 0 page table, unless -l specifies another level.
370 * The PTE value can be specified as the -p option, since on a 32 bit kernel
371 * with PAE running it's larger than a uintptr_t.
375 pte_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
379 char *level_str
= NULL
;
380 char *pte_str
= NULL
;
384 if (mmu
.num_level
== 0)
387 if (mdb_getopts(argc
, argv
,
388 'p', MDB_OPT_STR
, &pte_str
,
389 'l', MDB_OPT_STR
, &level_str
) != argc
)
393 * parse the PTE to decode, if it's 0, we don't do anything
395 if (pte_str
!= NULL
) {
396 pte
= mdb_strtoull(pte_str
);
398 if ((flags
& DCMD_ADDRSPEC
) == 0)
406 * parse the level if supplied
408 if (level_str
!= NULL
) {
409 level
= mdb_strtoull(level_str
);
410 if (level
< 0 || level
> mmu
.max_level
)
414 return (do_pte_dcmd(level
, pte
));
418 va2entry(htable_t
*htable
, uintptr_t addr
)
420 size_t entry
= (addr
- htable
->ht_vaddr
);
422 entry
>>= mmu
.level_shift
[htable
->ht_level
];
423 return (entry
& HTABLE_NUM_PTES(htable
) - 1);
427 get_pte(hat_t
*hat
, htable_t
*htable
, uintptr_t addr
)
430 x86pte32_t
*pte32
= (x86pte32_t
*)&buf
;
433 if (htable
->ht_flags
& HTABLE_VLP
) {
434 uintptr_t ptr
= (uintptr_t)hat
->hat_vlp_ptes
;
435 ptr
+= va2entry(htable
, addr
) << mmu
.pte_size_shift
;
436 len
= mdb_vread(&buf
, mmu
.pte_size
, ptr
);
438 paddr_t paddr
= mmu_ptob((paddr_t
)htable
->ht_pfn
);
439 paddr
+= va2entry(htable
, addr
) << mmu
.pte_size_shift
;
440 len
= mdb_pread(&buf
, mmu
.pte_size
, paddr
);
443 if (len
!= mmu
.pte_size
)
446 if (mmu
.pte_size
== sizeof (x86pte_t
))
452 do_va2pa(uintptr_t addr
, struct as
*asp
, int print_level
, physaddr_t
*pap
,
468 if (mdb_vread(&as
, sizeof (as
), (uintptr_t)asp
) == -1) {
469 mdb_warn("Couldn't read struct as\n");
478 * read the hat and its hash table
480 if (mdb_vread(&hat
, sizeof (hat
), (uintptr_t)hatp
) == -1) {
481 mdb_warn("Couldn't read struct hat\n");
486 * read the htable hashtable
488 for (level
= 0; level
<= mmu
.max_level
; ++level
) {
489 if (level
== TOP_LEVEL(&hat
))
492 base
= addr
& mmu
.level_mask
[level
+ 1];
494 for (h
= 0; h
< hat
.hat_num_hash
; ++h
) {
495 if (mdb_vread(&ht
, sizeof (htable_t
*),
496 (uintptr_t)(hat
.hat_ht_hash
+ h
)) == -1) {
497 mdb_warn("Couldn't read htable\n");
500 for (; ht
!= NULL
; ht
= htable
.ht_next
) {
501 if (mdb_vread(&htable
, sizeof (htable_t
),
502 (uintptr_t)ht
) == -1) {
503 mdb_warn("Couldn't read htable\n");
507 if (htable
.ht_vaddr
!= base
||
508 htable
.ht_level
!= level
)
511 pte
= get_pte(&hat
, &htable
, addr
);
514 mdb_printf("\tlevel=%d htable=%p "
515 "pte=%llr\n", level
, ht
, pte
);
518 if (!PTE_ISVALID(pte
)) {
519 mdb_printf("Address %p is unmapped.\n",
527 if (PTE_IS_LGPG(pte
, level
))
528 paddr
= mdb_ma_to_pa(pte
&
531 paddr
= mdb_ma_to_pa(pte
& PT_PADDR
);
532 paddr
+= addr
& mmu
.level_offset
[level
];
536 *mfnp
= pte2mfn(pte
, level
);
549 va2pfn_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
552 char *addrspace_str
= NULL
;
553 int piped
= flags
& DCMD_PIPE_OUT
;
560 if (mmu
.num_level
== 0)
563 if (mdb_getopts(argc
, argv
,
564 'a', MDB_OPT_STR
, &addrspace_str
) != argc
)
567 if ((flags
& DCMD_ADDRSPEC
) == 0)
571 * parse the address space
573 if (addrspace_str
!= NULL
)
574 addrspace
= mdb_strtoull(addrspace_str
);
578 rc
= do_va2pa(addr
, (struct as
*)addrspace
, !piped
, NULL
, &mfn
);
583 if ((pfn
= mdb_mfn_to_pfn(mfn
)) == -(pfn_t
)1) {
584 mdb_warn("Invalid mfn %lr\n", mfn
);
589 mdb_printf("0x%lr\n", pfn
);
593 mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr
, pfn
);
596 mdb_printf(" (mfn 0x%lr)", mfn
);
604 * Report all hat's that either use PFN as a page table or that map the page.
607 do_report_maps(pfn_t pfn
)
619 x86pte32_t
*pte32
= (x86pte32_t
*)&buf
;
624 * The hats are kept in a list with khat at the head.
626 for (hatp
= khat
; hatp
!= NULL
; hatp
= hat
.hat_next
) {
628 * read the hat and its hash table
630 if (mdb_vread(&hat
, sizeof (hat
), (uintptr_t)hatp
) == -1) {
631 mdb_warn("Couldn't read struct hat\n");
636 * read the htable hashtable
639 for (h
= 0; h
< hat
.hat_num_hash
; ++h
) {
640 if (mdb_vread(&ht
, sizeof (htable_t
*),
641 (uintptr_t)(hat
.hat_ht_hash
+ h
)) == -1) {
642 mdb_warn("Couldn't read htable\n");
645 for (; ht
!= NULL
; ht
= htable
.ht_next
) {
646 if (mdb_vread(&htable
, sizeof (htable_t
),
647 (uintptr_t)ht
) == -1) {
648 mdb_warn("Couldn't read htable\n");
653 * only report kernel addresses once
656 htable
.ht_vaddr
>= kernelbase
)
660 * Is the PFN a pagetable itself?
662 if (htable
.ht_pfn
== pfn
) {
663 mdb_printf("Pagetable for "
664 "hat=%p htable=%p\n", hatp
, ht
);
669 * otherwise, examine page mappings
671 level
= htable
.ht_level
;
672 if (level
> mmu
.max_page_level
)
674 paddr
= mmu_ptob((physaddr_t
)htable
.ht_pfn
);
676 entry
< HTABLE_NUM_PTES(&htable
);
679 base
= htable
.ht_vaddr
+ entry
*
680 mmu
.level_size
[level
];
683 * only report kernel addresses once
689 len
= mdb_pread(&buf
, mmu
.pte_size
,
690 paddr
+ entry
* mmu
.pte_size
);
691 if (len
!= mmu
.pte_size
)
693 if (mmu
.pte_size
== sizeof (x86pte_t
))
698 if ((pte
& PT_VALID
) == 0)
700 if (level
== 0 || !(pte
& PT_PAGESIZE
))
703 pte
&= PT_PADDR_LGPG
;
704 if (mmu_btop(mdb_ma_to_pa(pte
)) != pfn
)
706 mdb_printf("hat=%p maps addr=%p\n",
707 hatp
, (caddr_t
)base
);
718 * given a PFN as its address argument, prints out the uses of it
722 report_maps_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
729 if (mmu
.num_level
== 0)
732 if ((flags
& DCMD_ADDRSPEC
) == 0)
735 if (mdb_getopts(argc
, argv
,
736 'm', MDB_OPT_SETBITS
, TRUE
, &mflag
, NULL
) != argc
)
741 pfn
= mdb_mfn_to_pfn(pfn
);
743 return (do_report_maps(pfn
));
747 do_ptable_dcmd(pfn_t pfn
)
760 x86pte32_t
*pte32
= (x86pte32_t
*)&buf
;
765 * The hats are kept in a list with khat at the head.
767 for (hatp
= khat
; hatp
!= NULL
; hatp
= hat
.hat_next
) {
769 * read the hat and its hash table
771 if (mdb_vread(&hat
, sizeof (hat
), (uintptr_t)hatp
) == -1) {
772 mdb_warn("Couldn't read struct hat\n");
777 * read the htable hashtable
780 for (h
= 0; h
< hat
.hat_num_hash
; ++h
) {
781 if (mdb_vread(&ht
, sizeof (htable_t
*),
782 (uintptr_t)(hat
.hat_ht_hash
+ h
)) == -1) {
783 mdb_warn("Couldn't read htable\n");
786 for (; ht
!= NULL
; ht
= htable
.ht_next
) {
787 if (mdb_vread(&htable
, sizeof (htable_t
),
788 (uintptr_t)ht
) == -1) {
789 mdb_warn("Couldn't read htable\n");
794 * Is this the PFN for this htable
796 if (htable
.ht_pfn
== pfn
)
803 if (htable
.ht_pfn
== pfn
) {
804 mdb_printf("htable=%p\n", ht
);
805 level
= htable
.ht_level
;
806 base
= htable
.ht_vaddr
;
807 pagesize
= mmu
.level_size
[level
];
809 mdb_printf("Unknown pagetable - assuming level/addr 0");
810 level
= 0; /* assume level == 0 for PFN */
812 pagesize
= MMU_PAGESIZE
;
815 paddr
= mmu_ptob((physaddr_t
)pfn
);
816 for (entry
= 0; entry
< mmu
.ptes_per_table
; ++entry
) {
817 len
= mdb_pread(&buf
, mmu
.pte_size
,
818 paddr
+ entry
* mmu
.pte_size
);
819 if (len
!= mmu
.pte_size
)
821 if (mmu
.pte_size
== sizeof (x86pte_t
))
829 mdb_printf("[%3d] va=%p ", entry
, base
+ entry
* pagesize
);
830 do_pte_dcmd(level
, pte
);
838 * Dump the page table at the given PFN
842 ptable_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
849 if (mmu
.num_level
== 0)
852 if ((flags
& DCMD_ADDRSPEC
) == 0)
855 if (mdb_getopts(argc
, argv
,
856 'm', MDB_OPT_SETBITS
, TRUE
, &mflag
, NULL
) != argc
)
861 pfn
= mdb_mfn_to_pfn(pfn
);
863 return (do_ptable_dcmd(pfn
));
867 do_htables_dcmd(hat_t
*hatp
)
875 * read the hat and its hash table
877 if (mdb_vread(&hat
, sizeof (hat
), (uintptr_t)hatp
) == -1) {
878 mdb_warn("Couldn't read struct hat\n");
883 * read the htable hashtable
885 for (h
= 0; h
< hat
.hat_num_hash
; ++h
) {
886 if (mdb_vread(&ht
, sizeof (htable_t
*),
887 (uintptr_t)(hat
.hat_ht_hash
+ h
)) == -1) {
888 mdb_warn("Couldn't read htable ptr\\n");
891 for (; ht
!= NULL
; ht
= htable
.ht_next
) {
892 mdb_printf("%p\n", ht
);
893 if (mdb_vread(&htable
, sizeof (htable_t
),
894 (uintptr_t)ht
) == -1) {
895 mdb_warn("Couldn't read htable\n");
904 * Dump the htables for the given hat
908 htables_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
914 if (mmu
.num_level
== 0)
917 if ((flags
& DCMD_ADDRSPEC
) == 0)
922 return (do_htables_dcmd(hat
));