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>
39 #include <sys/hypervisor.h>
43 #include <mdb/mdb_modapi.h>
44 #include <mdb/mdb_target.h>
47 #include <vm/hat_i86.h>
54 static int do_va2pa(uintptr_t, struct as
*, int, physaddr_t
*, pfn_t
*);
55 static void init_mmu(void);
58 platform_vtop(uintptr_t addr
, struct as
*asp
, physaddr_t
*pap
)
65 if (mmu
.num_level
== 0)
68 return (do_va2pa(addr
, asp
, 0, pap
, NULL
));
72 * ::memseg_list dcmd and walker to implement it.
76 memseg_list(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
80 if (!(flags
& DCMD_ADDRSPEC
)) {
81 if (mdb_pwalk_dcmd("memseg", "memseg_list",
83 mdb_warn("can't walk memseg");
89 if (DCMD_HDRSPEC(flags
))
90 mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
91 "PAGES", "EPAGES", "BASE", "END");
93 if (mdb_vread(&ms
, sizeof (struct memseg
), addr
) == -1) {
94 mdb_warn("can't read memseg at %#lx", addr
);
98 mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr
,
99 ms
.pages
, ms
.epages
, ms
.pages_base
, ms
.pages_end
);
105 * walk the memseg structures
108 memseg_walk_init(mdb_walk_state_t
*wsp
)
110 if (wsp
->walk_addr
!= NULL
) {
111 mdb_warn("memseg only supports global walks\n");
115 if (mdb_readvar(&wsp
->walk_addr
, "memsegs") == -1) {
116 mdb_warn("symbol 'memsegs' not found");
120 wsp
->walk_data
= mdb_alloc(sizeof (struct memseg
), UM_SLEEP
);
126 memseg_walk_step(mdb_walk_state_t
*wsp
)
130 if (wsp
->walk_addr
== 0) {
134 if (mdb_vread(wsp
->walk_data
, sizeof (struct memseg
),
135 wsp
->walk_addr
) == -1) {
136 mdb_warn("failed to read struct memseg at %p", wsp
->walk_addr
);
140 status
= wsp
->walk_callback(wsp
->walk_addr
, wsp
->walk_data
,
143 wsp
->walk_addr
= (uintptr_t)(((struct memseg
*)wsp
->walk_data
)->next
);
149 memseg_walk_fini(mdb_walk_state_t
*wsp
)
151 mdb_free(wsp
->walk_data
, sizeof (struct memseg
));
155 * Now HAT related dcmds.
158 static struct hat
*khat
; /* value of kas.a_hat */
159 struct hat_mmu_info mmu
;
160 uintptr_t kernelbase
;
163 * stuff for i86xpv images
166 static uintptr_t mfn_list_addr
; /* kernel MFN list address */
167 uintptr_t xen_virt_start
; /* address of mfn_to_pfn[] table */
168 ulong_t mfn_count
; /* number of pfn's in the MFN list */
169 pfn_t
*mfn_list
; /* local MFN list copy */
172 * read mmu parameters from kernel
179 if (mmu
.num_level
!= 0)
182 if (mdb_readsym(&mmu
, sizeof (mmu
), "mmu") == -1)
183 mdb_warn("Can't use HAT information before mmu_init()\n");
184 if (mdb_readsym(&kas
, sizeof (kas
), "kas") == -1)
185 mdb_warn("Couldn't find kas - kernel's struct as\n");
186 if (mdb_readsym(&kernelbase
, sizeof (kernelbase
), "kernelbase") == -1)
187 mdb_warn("Couldn't find kernelbase\n");
191 * Is this a paravirtualized domain image?
193 if (mdb_readsym(&mfn_list_addr
, sizeof (mfn_list_addr
),
195 mdb_readsym(&xen_virt_start
, sizeof (xen_virt_start
),
196 "xen_virt_start") == -1 ||
197 mdb_readsym(&mfn_count
, sizeof (mfn_count
), "mfn_count") == -1) {
198 mfn_list_addr
= NULL
;
201 is_xpv
= mfn_list_addr
!= NULL
;
205 * recreate the local mfn_list
208 size_t sz
= mfn_count
* sizeof (pfn_t
);
209 mfn_list
= mdb_zalloc(sz
, UM_SLEEP
);
211 if (mdb_vread(mfn_list
, sz
, (uintptr_t)mfn_list_addr
) == -1) {
212 mdb_warn("Failed to read MFN list\n");
213 mdb_free(mfn_list
, sz
);
224 if (mfn_list
!= NULL
)
225 mdb_free(mfn_list
, mfn_count
* sizeof (mfn_t
));
234 * Convert between MFNs and PFNs. Since we're in kmdb we can go directly
235 * through the machine to phys mapping and the MFN list.
239 mdb_mfn_to_pfn(mfn_t mfn
)
245 if (mfn_list_addr
== NULL
)
248 pfn_list
= (pfn_t
*)xen_virt_start
;
249 if (mdb_vread(&pfn
, sizeof (pfn
), (uintptr_t)(pfn_list
+ mfn
)) == -1)
252 if (mdb_vread(&tmp
, sizeof (tmp
),
253 (uintptr_t)(mfn_list_addr
+ (pfn
* sizeof (mfn_t
)))) == -1)
256 if (pfn
>= mfn_count
|| tmp
!= mfn
)
263 mdb_pfn_to_mfn(pfn_t pfn
)
269 if (mfn_list_addr
== NULL
|| pfn
>= mfn_count
)
272 if (mdb_vread(&mfn
, sizeof (mfn
),
273 (uintptr_t)(mfn_list_addr
+ (pfn
* sizeof (mfn_t
)))) == -1)
282 * Convert between MFNs and PFNs. Since a crash dump doesn't include the
283 * MFN->PFN translation table (it's part of the hypervisor, not our image)
284 * we do the MFN->PFN translation by searching the PFN->MFN (mfn_list)
285 * table, if it's there.
289 mdb_mfn_to_pfn(mfn_t mfn
)
295 if (mfn_list
== NULL
)
298 for (pfn
= 0; pfn
< mfn_count
; ++pfn
) {
299 if (mfn_list
[pfn
] != mfn
)
308 mdb_pfn_to_mfn(pfn_t pfn
)
312 if (mfn_list
== NULL
|| pfn
>= mfn_count
)
315 return (mfn_list
[pfn
]);
321 mdb_ma_to_pa(uint64_t ma
)
323 pfn_t pfn
= mdb_mfn_to_pfn(mmu_btop(ma
));
324 if (pfn
== -(pfn_t
)1)
325 return (-(paddr_t
)1);
327 return (mmu_ptob((paddr_t
)pfn
) | (ma
& (MMU_PAGESIZE
- 1)));
332 #define mdb_ma_to_pa(ma) (ma)
333 #define mdb_mfn_to_pfn(mfn) (mfn)
334 #define mdb_pfn_to_mfn(pfn) (pfn)
339 * ::mfntopfn dcmd translates hypervisor machine page number
340 * to physical page number
344 mfntopfn_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
348 if ((flags
& DCMD_ADDRSPEC
) == 0) {
349 mdb_warn("MFN missing\n");
353 if ((pfn
= mdb_mfn_to_pfn((pfn_t
)addr
)) == -(pfn_t
)1) {
354 mdb_warn("Invalid mfn %lr\n", (pfn_t
)addr
);
358 mdb_printf("%lr\n", pfn
);
364 * ::pfntomfn dcmd translates physical page number to
365 * hypervisor machine page number
369 pfntomfn_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
373 if ((flags
& DCMD_ADDRSPEC
) == 0) {
374 mdb_warn("PFN missing\n");
378 if ((mfn
= mdb_pfn_to_mfn((pfn_t
)addr
)) == -(pfn_t
)1) {
379 mdb_warn("Invalid pfn %lr\n", (pfn_t
)addr
);
383 mdb_printf("%lr\n", mfn
);
385 if (flags
& DCMD_LOOP
)
386 mdb_set_dot(addr
+ 1);
391 pte2mfn(x86pte_t pte
, uint_t level
)
394 if (level
> 0 && (pte
& PT_PAGESIZE
))
395 mfn
= mmu_btop(pte
& PT_PADDR_LGPG
);
397 mfn
= mmu_btop(pte
& PT_PADDR
);
402 * Print a PTE in more human friendly way. The PTE is assumed to be in
403 * a level 0 page table, unless -l specifies another level.
405 * The PTE value can be specified as the -p option, since on a 32 bit kernel
406 * with PAE running it's larger than a uintptr_t.
409 do_pte_dcmd(int level
, uint64_t pte
)
411 static char *attr
[] = {
412 "wrback", "wrthru", "uncached", "uncached",
413 "wrback", "wrthru", "wrcombine", "uncached"};
417 mdb_printf("pte=%llr: ", pte
);
418 if (PTE_GET(pte
, mmu
.pt_nx
))
419 mdb_printf("noexec ");
421 mfn
= pte2mfn(pte
, level
);
422 mdb_printf("%s=0x%lr ", is_xpv
? "mfn" : "pfn", mfn
);
424 if (PTE_GET(pte
, PT_NOCONSIST
))
425 mdb_printf("noconsist ");
427 if (PTE_GET(pte
, PT_NOSYNC
))
428 mdb_printf("nosync ");
430 if (PTE_GET(pte
, mmu
.pt_global
))
431 mdb_printf("global ");
433 if (level
> 0 && PTE_GET(pte
, PT_PAGESIZE
))
434 mdb_printf("largepage ");
436 if (level
> 0 && PTE_GET(pte
, PT_MOD
))
439 if (level
> 0 && PTE_GET(pte
, PT_REF
))
442 if (PTE_GET(pte
, PT_USER
))
445 if (PTE_GET(pte
, PT_WRITABLE
))
446 mdb_printf("write ");
449 * Report non-standard cacheability
453 if (PTE_GET(pte
, PT_PAGESIZE
) && PTE_GET(pte
, PT_PAT_LARGE
))
456 if (PTE_GET(pte
, PT_PAT_4K
))
460 if (PTE_GET(pte
, PT_NOCACHE
))
463 if (PTE_GET(pte
, PT_WRITETHRU
))
467 mdb_printf("%s", attr
[pat_index
]);
469 if (PTE_GET(pte
, PT_VALID
) == 0)
470 mdb_printf(" !VALID ");
477 * Print a PTE in more human friendly way. The PTE is assumed to be in
478 * a level 0 page table, unless -l specifies another level.
480 * The PTE value can be specified as the -p option, since on a 32 bit kernel
481 * with PAE running it's larger than a uintptr_t.
485 pte_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
489 char *level_str
= NULL
;
490 char *pte_str
= NULL
;
494 if (mmu
.num_level
== 0)
497 if (mdb_getopts(argc
, argv
,
498 'p', MDB_OPT_STR
, &pte_str
,
499 'l', MDB_OPT_STR
, &level_str
) != argc
)
503 * parse the PTE to decode, if it's 0, we don't do anything
505 if (pte_str
!= NULL
) {
506 pte
= mdb_strtoull(pte_str
);
508 if ((flags
& DCMD_ADDRSPEC
) == 0)
516 * parse the level if supplied
518 if (level_str
!= NULL
) {
519 level
= mdb_strtoull(level_str
);
520 if (level
< 0 || level
> mmu
.max_level
)
524 return (do_pte_dcmd(level
, pte
));
528 va2entry(htable_t
*htable
, uintptr_t addr
)
530 size_t entry
= (addr
- htable
->ht_vaddr
);
532 entry
>>= mmu
.level_shift
[htable
->ht_level
];
533 return (entry
& HTABLE_NUM_PTES(htable
) - 1);
537 get_pte(hat_t
*hat
, htable_t
*htable
, uintptr_t addr
)
540 x86pte32_t
*pte32
= (x86pte32_t
*)&buf
;
543 if (htable
->ht_flags
& HTABLE_VLP
) {
544 uintptr_t ptr
= (uintptr_t)hat
->hat_vlp_ptes
;
545 ptr
+= va2entry(htable
, addr
) << mmu
.pte_size_shift
;
546 len
= mdb_vread(&buf
, mmu
.pte_size
, ptr
);
548 paddr_t paddr
= mmu_ptob((paddr_t
)htable
->ht_pfn
);
549 paddr
+= va2entry(htable
, addr
) << mmu
.pte_size_shift
;
550 len
= mdb_pread(&buf
, mmu
.pte_size
, paddr
);
553 if (len
!= mmu
.pte_size
)
556 if (mmu
.pte_size
== sizeof (x86pte_t
))
562 do_va2pa(uintptr_t addr
, struct as
*asp
, int print_level
, physaddr_t
*pap
,
578 if (mdb_vread(&as
, sizeof (as
), (uintptr_t)asp
) == -1) {
579 mdb_warn("Couldn't read struct as\n");
588 * read the hat and its hash table
590 if (mdb_vread(&hat
, sizeof (hat
), (uintptr_t)hatp
) == -1) {
591 mdb_warn("Couldn't read struct hat\n");
596 * read the htable hashtable
598 for (level
= 0; level
<= mmu
.max_level
; ++level
) {
599 if (level
== TOP_LEVEL(&hat
))
602 base
= addr
& mmu
.level_mask
[level
+ 1];
604 for (h
= 0; h
< hat
.hat_num_hash
; ++h
) {
605 if (mdb_vread(&ht
, sizeof (htable_t
*),
606 (uintptr_t)(hat
.hat_ht_hash
+ h
)) == -1) {
607 mdb_warn("Couldn't read htable\n");
610 for (; ht
!= NULL
; ht
= htable
.ht_next
) {
611 if (mdb_vread(&htable
, sizeof (htable_t
),
612 (uintptr_t)ht
) == -1) {
613 mdb_warn("Couldn't read htable\n");
617 if (htable
.ht_vaddr
!= base
||
618 htable
.ht_level
!= level
)
621 pte
= get_pte(&hat
, &htable
, addr
);
624 mdb_printf("\tlevel=%d htable=%p "
625 "pte=%llr\n", level
, ht
, pte
);
628 if (!PTE_ISVALID(pte
)) {
629 mdb_printf("Address %p is unmapped.\n",
637 if (PTE_IS_LGPG(pte
, level
))
638 paddr
= mdb_ma_to_pa(pte
&
641 paddr
= mdb_ma_to_pa(pte
& PT_PADDR
);
642 paddr
+= addr
& mmu
.level_offset
[level
];
646 *mfnp
= pte2mfn(pte
, level
);
659 va2pfn_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
662 char *addrspace_str
= NULL
;
663 int piped
= flags
& DCMD_PIPE_OUT
;
670 if (mmu
.num_level
== 0)
673 if (mdb_getopts(argc
, argv
,
674 'a', MDB_OPT_STR
, &addrspace_str
) != argc
)
677 if ((flags
& DCMD_ADDRSPEC
) == 0)
681 * parse the address space
683 if (addrspace_str
!= NULL
)
684 addrspace
= mdb_strtoull(addrspace_str
);
688 rc
= do_va2pa(addr
, (struct as
*)addrspace
, !piped
, NULL
, &mfn
);
693 if ((pfn
= mdb_mfn_to_pfn(mfn
)) == -(pfn_t
)1) {
694 mdb_warn("Invalid mfn %lr\n", mfn
);
699 mdb_printf("0x%lr\n", pfn
);
703 mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr
, pfn
);
706 mdb_printf(" (mfn 0x%lr)", mfn
);
714 * Report all hat's that either use PFN as a page table or that map the page.
717 do_report_maps(pfn_t pfn
)
729 x86pte32_t
*pte32
= (x86pte32_t
*)&buf
;
734 * The hats are kept in a list with khat at the head.
736 for (hatp
= khat
; hatp
!= NULL
; hatp
= hat
.hat_next
) {
738 * read the hat and its hash table
740 if (mdb_vread(&hat
, sizeof (hat
), (uintptr_t)hatp
) == -1) {
741 mdb_warn("Couldn't read struct hat\n");
746 * read the htable hashtable
749 for (h
= 0; h
< hat
.hat_num_hash
; ++h
) {
750 if (mdb_vread(&ht
, sizeof (htable_t
*),
751 (uintptr_t)(hat
.hat_ht_hash
+ h
)) == -1) {
752 mdb_warn("Couldn't read htable\n");
755 for (; ht
!= NULL
; ht
= htable
.ht_next
) {
756 if (mdb_vread(&htable
, sizeof (htable_t
),
757 (uintptr_t)ht
) == -1) {
758 mdb_warn("Couldn't read htable\n");
763 * only report kernel addresses once
766 htable
.ht_vaddr
>= kernelbase
)
770 * Is the PFN a pagetable itself?
772 if (htable
.ht_pfn
== pfn
) {
773 mdb_printf("Pagetable for "
774 "hat=%p htable=%p\n", hatp
, ht
);
779 * otherwise, examine page mappings
781 level
= htable
.ht_level
;
782 if (level
> mmu
.max_page_level
)
784 paddr
= mmu_ptob((physaddr_t
)htable
.ht_pfn
);
786 entry
< HTABLE_NUM_PTES(&htable
);
789 base
= htable
.ht_vaddr
+ entry
*
790 mmu
.level_size
[level
];
793 * only report kernel addresses once
799 len
= mdb_pread(&buf
, mmu
.pte_size
,
800 paddr
+ entry
* mmu
.pte_size
);
801 if (len
!= mmu
.pte_size
)
803 if (mmu
.pte_size
== sizeof (x86pte_t
))
808 if ((pte
& PT_VALID
) == 0)
810 if (level
== 0 || !(pte
& PT_PAGESIZE
))
813 pte
&= PT_PADDR_LGPG
;
814 if (mmu_btop(mdb_ma_to_pa(pte
)) != pfn
)
816 mdb_printf("hat=%p maps addr=%p\n",
817 hatp
, (caddr_t
)base
);
828 * given a PFN as its address argument, prints out the uses of it
832 report_maps_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
839 if (mmu
.num_level
== 0)
842 if ((flags
& DCMD_ADDRSPEC
) == 0)
845 if (mdb_getopts(argc
, argv
,
846 'm', MDB_OPT_SETBITS
, TRUE
, &mflag
, NULL
) != argc
)
851 pfn
= mdb_mfn_to_pfn(pfn
);
853 return (do_report_maps(pfn
));
857 do_ptable_dcmd(pfn_t pfn
)
870 x86pte32_t
*pte32
= (x86pte32_t
*)&buf
;
875 * The hats are kept in a list with khat at the head.
877 for (hatp
= khat
; hatp
!= NULL
; hatp
= hat
.hat_next
) {
879 * read the hat and its hash table
881 if (mdb_vread(&hat
, sizeof (hat
), (uintptr_t)hatp
) == -1) {
882 mdb_warn("Couldn't read struct hat\n");
887 * read the htable hashtable
890 for (h
= 0; h
< hat
.hat_num_hash
; ++h
) {
891 if (mdb_vread(&ht
, sizeof (htable_t
*),
892 (uintptr_t)(hat
.hat_ht_hash
+ h
)) == -1) {
893 mdb_warn("Couldn't read htable\n");
896 for (; ht
!= NULL
; ht
= htable
.ht_next
) {
897 if (mdb_vread(&htable
, sizeof (htable_t
),
898 (uintptr_t)ht
) == -1) {
899 mdb_warn("Couldn't read htable\n");
904 * Is this the PFN for this htable
906 if (htable
.ht_pfn
== pfn
)
913 if (htable
.ht_pfn
== pfn
) {
914 mdb_printf("htable=%p\n", ht
);
915 level
= htable
.ht_level
;
916 base
= htable
.ht_vaddr
;
917 pagesize
= mmu
.level_size
[level
];
919 mdb_printf("Unknown pagetable - assuming level/addr 0");
920 level
= 0; /* assume level == 0 for PFN */
922 pagesize
= MMU_PAGESIZE
;
925 paddr
= mmu_ptob((physaddr_t
)pfn
);
926 for (entry
= 0; entry
< mmu
.ptes_per_table
; ++entry
) {
927 len
= mdb_pread(&buf
, mmu
.pte_size
,
928 paddr
+ entry
* mmu
.pte_size
);
929 if (len
!= mmu
.pte_size
)
931 if (mmu
.pte_size
== sizeof (x86pte_t
))
939 mdb_printf("[%3d] va=%p ", entry
, base
+ entry
* pagesize
);
940 do_pte_dcmd(level
, pte
);
948 * Dump the page table at the given PFN
952 ptable_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
959 if (mmu
.num_level
== 0)
962 if ((flags
& DCMD_ADDRSPEC
) == 0)
965 if (mdb_getopts(argc
, argv
,
966 'm', MDB_OPT_SETBITS
, TRUE
, &mflag
, NULL
) != argc
)
971 pfn
= mdb_mfn_to_pfn(pfn
);
973 return (do_ptable_dcmd(pfn
));
977 do_htables_dcmd(hat_t
*hatp
)
985 * read the hat and its hash table
987 if (mdb_vread(&hat
, sizeof (hat
), (uintptr_t)hatp
) == -1) {
988 mdb_warn("Couldn't read struct hat\n");
993 * read the htable hashtable
995 for (h
= 0; h
< hat
.hat_num_hash
; ++h
) {
996 if (mdb_vread(&ht
, sizeof (htable_t
*),
997 (uintptr_t)(hat
.hat_ht_hash
+ h
)) == -1) {
998 mdb_warn("Couldn't read htable ptr\\n");
1001 for (; ht
!= NULL
; ht
= htable
.ht_next
) {
1002 mdb_printf("%p\n", ht
);
1003 if (mdb_vread(&htable
, sizeof (htable_t
),
1004 (uintptr_t)ht
) == -1) {
1005 mdb_warn("Couldn't read htable\n");
1014 * Dump the htables for the given hat
1018 htables_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1024 if (mmu
.num_level
== 0)
1027 if ((flags
& DCMD_ADDRSPEC
) == 0)
1028 return (DCMD_USAGE
);
1030 hat
= (hat_t
*)addr
;
1032 return (do_htables_dcmd(hat
));