1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * This part of the file contains the mdb support for dcmds:
28 * ::memseg_list
29 * and walkers for:
30 * memseg - a memseg list walker for ::memseg_list
31 *
32 */
33
34 #include <sys/types.h>
35 #include <sys/machparam.h>
36 #include <sys/controlregs.h>
37 #include <sys/mach_mmu.h>
38 #ifdef __xpv
39 #include <sys/hypervisor.h>
40 #endif
41 #include <vm/as.h>
42
43 #include <mdb/mdb_modapi.h>
44 #include <mdb/mdb_target.h>
45
46 #include <vm/page.h>
47 #include <vm/hat_i86.h>
48
49 struct pfn2pp {
50 pfn_t pfn;
51 page_t *pp;
52 };
53
54 static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *);
55 static void init_mmu(void);
56
57 int
platform_vtop(uintptr_t addr,struct as * asp,physaddr_t * pap)58 platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
59 {
60 if (asp == NULL)
61 return (DCMD_ERR);
62
63 init_mmu();
64
65 if (mmu.num_level == 0)
66 return (DCMD_ERR);
67
68 return (do_va2pa(addr, asp, 0, pap, NULL));
69 }
70
71 /*
72 * ::memseg_list dcmd and walker to implement it.
73 */
74 /*ARGSUSED*/
75 int
memseg_list(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)76 memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
77 {
78 struct memseg ms;
79
80 if (!(flags & DCMD_ADDRSPEC)) {
81 if (mdb_pwalk_dcmd("memseg", "memseg_list",
82 0, NULL, 0) == -1) {
83 mdb_warn("can't walk memseg");
84 return (DCMD_ERR);
85 }
86 return (DCMD_OK);
87 }
88
89 if (DCMD_HDRSPEC(flags))
90 mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
91 "PAGES", "EPAGES", "BASE", "END");
92
93 if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
94 mdb_warn("can't read memseg at %#lx", addr);
95 return (DCMD_ERR);
96 }
97
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);
100
101 return (DCMD_OK);
102 }
103
104 /*
105 * walk the memseg structures
106 */
107 int
memseg_walk_init(mdb_walk_state_t * wsp)108 memseg_walk_init(mdb_walk_state_t *wsp)
109 {
110 if (wsp->walk_addr != NULL) {
111 mdb_warn("memseg only supports global walks\n");
112 return (WALK_ERR);
113 }
114
115 if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
116 mdb_warn("symbol 'memsegs' not found");
117 return (WALK_ERR);
118 }
119
120 wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
121 return (WALK_NEXT);
122
123 }
124
125 int
memseg_walk_step(mdb_walk_state_t * wsp)126 memseg_walk_step(mdb_walk_state_t *wsp)
127 {
128 int status;
129
130 if (wsp->walk_addr == 0) {
131 return (WALK_DONE);
132 }
133
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);
137 return (WALK_DONE);
138 }
139
140 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
141 wsp->walk_cbdata);
142
143 wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
144
145 return (status);
146 }
147
148 void
memseg_walk_fini(mdb_walk_state_t * wsp)149 memseg_walk_fini(mdb_walk_state_t *wsp)
150 {
151 mdb_free(wsp->walk_data, sizeof (struct memseg));
152 }
153
154 /*
155 * Now HAT related dcmds.
156 */
157
158 static struct hat *khat; /* value of kas.a_hat */
159 struct hat_mmu_info mmu;
160 uintptr_t kernelbase;
161
162 /*
163 * stuff for i86xpv images
164 */
165 static int is_xpv;
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 */
170
171 /*
172 * read mmu parameters from kernel
173 */
174 static void
init_mmu(void)175 init_mmu(void)
176 {
177 struct as kas;
178
179 if (mmu.num_level != 0)
180 return;
181
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");
188 khat = kas.a_hat;
189
190 /*
191 * Is this a paravirtualized domain image?
192 */
193 if (mdb_readsym(&mfn_list_addr, sizeof (mfn_list_addr),
194 "mfn_list") == -1 ||
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;
199 }
200
201 is_xpv = mfn_list_addr != NULL;
202
203 #ifndef _KMDB
204 /*
205 * recreate the local mfn_list
206 */
207 if (is_xpv) {
208 size_t sz = mfn_count * sizeof (pfn_t);
209 mfn_list = mdb_zalloc(sz, UM_SLEEP);
210
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);
214 mfn_list = NULL;
215 }
216 }
217 #endif
218 }
219
220 void
free_mmu(void)221 free_mmu(void)
222 {
223 #ifdef __xpv
224 if (mfn_list != NULL)
225 mdb_free(mfn_list, mfn_count * sizeof (mfn_t));
226 #endif
227 }
228
229 #ifdef __xpv
230
231 #ifdef _KMDB
232
233 /*
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.
236 */
237
238 pfn_t
mdb_mfn_to_pfn(mfn_t mfn)239 mdb_mfn_to_pfn(mfn_t mfn)
240 {
241 pfn_t pfn;
242 mfn_t tmp;
243 pfn_t *pfn_list;
244
245 if (mfn_list_addr == NULL)
246 return (-(pfn_t)1);
247
248 pfn_list = (pfn_t *)xen_virt_start;
249 if (mdb_vread(&pfn, sizeof (pfn), (uintptr_t)(pfn_list + mfn)) == -1)
250 return (-(pfn_t)1);
251
252 if (mdb_vread(&tmp, sizeof (tmp),
253 (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
254 return (-(pfn_t)1);
255
256 if (pfn >= mfn_count || tmp != mfn)
257 return (-(pfn_t)1);
258
259 return (pfn);
260 }
261
262 mfn_t
mdb_pfn_to_mfn(pfn_t pfn)263 mdb_pfn_to_mfn(pfn_t pfn)
264 {
265 mfn_t mfn;
266
267 init_mmu();
268
269 if (mfn_list_addr == NULL || pfn >= mfn_count)
270 return (-(mfn_t)1);
271
272 if (mdb_vread(&mfn, sizeof (mfn),
273 (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
274 return (-(mfn_t)1);
275
276 return (mfn);
277 }
278
279 #else /* _KMDB */
280
281 /*
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.
286 */
287
288 pfn_t
mdb_mfn_to_pfn(mfn_t mfn)289 mdb_mfn_to_pfn(mfn_t mfn)
290 {
291 pfn_t pfn;
292
293 init_mmu();
294
295 if (mfn_list == NULL)
296 return (-(pfn_t)1);
297
298 for (pfn = 0; pfn < mfn_count; ++pfn) {
299 if (mfn_list[pfn] != mfn)
300 continue;
301 return (pfn);
302 }
303
304 return (-(pfn_t)1);
305 }
306
307 mfn_t
mdb_pfn_to_mfn(pfn_t pfn)308 mdb_pfn_to_mfn(pfn_t pfn)
309 {
310 init_mmu();
311
312 if (mfn_list == NULL || pfn >= mfn_count)
313 return (-(mfn_t)1);
314
315 return (mfn_list[pfn]);
316 }
317
318 #endif /* _KMDB */
319
320 static paddr_t
mdb_ma_to_pa(uint64_t ma)321 mdb_ma_to_pa(uint64_t ma)
322 {
323 pfn_t pfn = mdb_mfn_to_pfn(mmu_btop(ma));
324 if (pfn == -(pfn_t)1)
325 return (-(paddr_t)1);
326
327 return (mmu_ptob((paddr_t)pfn) | (ma & (MMU_PAGESIZE - 1)));
328 }
329
330 #else /* __xpv */
331
332 #define mdb_ma_to_pa(ma) (ma)
333 #define mdb_mfn_to_pfn(mfn) (mfn)
334 #define mdb_pfn_to_mfn(pfn) (pfn)
335
336 #endif /* __xpv */
337
338 /*
339 * ::mfntopfn dcmd translates hypervisor machine page number
340 * to physical page number
341 */
342 /*ARGSUSED*/
343 int
mfntopfn_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)344 mfntopfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
345 {
346 pfn_t pfn;
347
348 if ((flags & DCMD_ADDRSPEC) == 0) {
349 mdb_warn("MFN missing\n");
350 return (DCMD_USAGE);
351 }
352
353 if ((pfn = mdb_mfn_to_pfn((pfn_t)addr)) == -(pfn_t)1) {
354 mdb_warn("Invalid mfn %lr\n", (pfn_t)addr);
355 return (DCMD_ERR);
356 }
357
358 mdb_printf("%lr\n", pfn);
359
360 return (DCMD_OK);
361 }
362
363 /*
364 * ::pfntomfn dcmd translates physical page number to
365 * hypervisor machine page number
366 */
367 /*ARGSUSED*/
368 int
pfntomfn_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)369 pfntomfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
370 {
371 pfn_t mfn;
372
373 if ((flags & DCMD_ADDRSPEC) == 0) {
374 mdb_warn("PFN missing\n");
375 return (DCMD_USAGE);
376 }
377
378 if ((mfn = mdb_pfn_to_mfn((pfn_t)addr)) == -(pfn_t)1) {
379 mdb_warn("Invalid pfn %lr\n", (pfn_t)addr);
380 return (DCMD_ABORT);
381 }
382
383 mdb_printf("%lr\n", mfn);
384
385 if (flags & DCMD_LOOP)
386 mdb_set_dot(addr + 1);
387 return (DCMD_OK);
388 }
389
390 static pfn_t
pte2mfn(x86pte_t pte,uint_t level)391 pte2mfn(x86pte_t pte, uint_t level)
392 {
393 pfn_t mfn;
394 if (level > 0 && (pte & PT_PAGESIZE))
395 mfn = mmu_btop(pte & PT_PADDR_LGPG);
396 else
397 mfn = mmu_btop(pte & PT_PADDR);
398 return (mfn);
399 }
400
401 /*
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.
404 *
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.
407 */
408 static int
do_pte_dcmd(int level,uint64_t pte)409 do_pte_dcmd(int level, uint64_t pte)
410 {
411 static char *attr[] = {
412 "wrback", "wrthru", "uncached", "uncached",
413 "wrback", "wrthru", "wrcombine", "uncached"};
414 int pat_index = 0;
415 pfn_t mfn;
416
417 mdb_printf("pte=%llr: ", pte);
418 if (PTE_GET(pte, mmu.pt_nx))
419 mdb_printf("noexec ");
420
421 mfn = pte2mfn(pte, level);
422 mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn);
423
424 if (PTE_GET(pte, PT_NOCONSIST))
425 mdb_printf("noconsist ");
426
427 if (PTE_GET(pte, PT_NOSYNC))
428 mdb_printf("nosync ");
429
430 if (PTE_GET(pte, mmu.pt_global))
431 mdb_printf("global ");
432
433 if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
434 mdb_printf("largepage ");
435
436 if (level > 0 && PTE_GET(pte, PT_MOD))
437 mdb_printf("mod ");
438
439 if (level > 0 && PTE_GET(pte, PT_REF))
440 mdb_printf("ref ");
441
442 if (PTE_GET(pte, PT_USER))
443 mdb_printf("user ");
444
445 if (PTE_GET(pte, PT_WRITABLE))
446 mdb_printf("write ");
447
448 /*
449 * Report non-standard cacheability
450 */
451 pat_index = 0;
452 if (level > 0) {
453 if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE))
454 pat_index += 4;
455 } else {
456 if (PTE_GET(pte, PT_PAT_4K))
457 pat_index += 4;
458 }
459
460 if (PTE_GET(pte, PT_NOCACHE))
461 pat_index += 2;
462
463 if (PTE_GET(pte, PT_WRITETHRU))
464 pat_index += 1;
465
466 if (pat_index != 0)
467 mdb_printf("%s", attr[pat_index]);
468
469 if (PTE_GET(pte, PT_VALID) == 0)
470 mdb_printf(" !VALID ");
471
472 mdb_printf("\n");
473 return (DCMD_OK);
474 }
475
476 /*
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.
479 *
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.
482 */
483 /*ARGSUSED*/
484 int
pte_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)485 pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
486 {
487 int level = 0;
488 uint64_t pte = 0;
489 char *level_str = NULL;
490 char *pte_str = NULL;
491
492 init_mmu();
493
494 if (mmu.num_level == 0)
495 return (DCMD_ERR);
496
497 if (mdb_getopts(argc, argv,
498 'p', MDB_OPT_STR, &pte_str,
499 'l', MDB_OPT_STR, &level_str) != argc)
500 return (DCMD_USAGE);
501
502 /*
503 * parse the PTE to decode, if it's 0, we don't do anything
504 */
505 if (pte_str != NULL) {
506 pte = mdb_strtoull(pte_str);
507 } else {
508 if ((flags & DCMD_ADDRSPEC) == 0)
509 return (DCMD_USAGE);
510 pte = addr;
511 }
512 if (pte == 0)
513 return (DCMD_OK);
514
515 /*
516 * parse the level if supplied
517 */
518 if (level_str != NULL) {
519 level = mdb_strtoull(level_str);
520 if (level < 0 || level > mmu.max_level)
521 return (DCMD_ERR);
522 }
523
524 return (do_pte_dcmd(level, pte));
525 }
526
527 static size_t
va2entry(htable_t * htable,uintptr_t addr)528 va2entry(htable_t *htable, uintptr_t addr)
529 {
530 size_t entry = (addr - htable->ht_vaddr);
531
532 entry >>= mmu.level_shift[htable->ht_level];
533 return (entry & HTABLE_NUM_PTES(htable) - 1);
534 }
535
536 static x86pte_t
get_pte(hat_t * hat,htable_t * htable,uintptr_t addr)537 get_pte(hat_t *hat, htable_t *htable, uintptr_t addr)
538 {
539 x86pte_t buf;
540 x86pte32_t *pte32 = (x86pte32_t *)&buf;
541 size_t len;
542
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);
547 } else {
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);
551 }
552
553 if (len != mmu.pte_size)
554 return (0);
555
556 if (mmu.pte_size == sizeof (x86pte_t))
557 return (buf);
558 return (*pte32);
559 }
560
561 static int
do_va2pa(uintptr_t addr,struct as * asp,int print_level,physaddr_t * pap,pfn_t * mfnp)562 do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap,
563 pfn_t *mfnp)
564 {
565 struct as as;
566 struct hat *hatp;
567 struct hat hat;
568 htable_t *ht;
569 htable_t htable;
570 uintptr_t base;
571 int h;
572 int level;
573 int found = 0;
574 x86pte_t pte;
575 physaddr_t paddr;
576
577 if (asp != NULL) {
578 if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
579 mdb_warn("Couldn't read struct as\n");
580 return (DCMD_ERR);
581 }
582 hatp = as.a_hat;
583 } else {
584 hatp = khat;
585 }
586
587 /*
588 * read the hat and its hash table
589 */
590 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
591 mdb_warn("Couldn't read struct hat\n");
592 return (DCMD_ERR);
593 }
594
595 /*
596 * read the htable hashtable
597 */
598 for (level = 0; level <= mmu.max_level; ++level) {
599 if (level == TOP_LEVEL(&hat))
600 base = 0;
601 else
602 base = addr & mmu.level_mask[level + 1];
603
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");
608 return (DCMD_ERR);
609 }
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");
614 return (DCMD_ERR);
615 }
616
617 if (htable.ht_vaddr != base ||
618 htable.ht_level != level)
619 continue;
620
621 pte = get_pte(&hat, &htable, addr);
622
623 if (print_level) {
624 mdb_printf("\tlevel=%d htable=%p "
625 "pte=%llr\n", level, ht, pte);
626 }
627
628 if (!PTE_ISVALID(pte)) {
629 mdb_printf("Address %p is unmapped.\n",
630 addr);
631 return (DCMD_ERR);
632 }
633
634 if (found)
635 continue;
636
637 if (PTE_IS_LGPG(pte, level))
638 paddr = mdb_ma_to_pa(pte &
639 PT_PADDR_LGPG);
640 else
641 paddr = mdb_ma_to_pa(pte & PT_PADDR);
642 paddr += addr & mmu.level_offset[level];
643 if (pap != NULL)
644 *pap = paddr;
645 if (mfnp != NULL)
646 *mfnp = pte2mfn(pte, level);
647 found = 1;
648 }
649 }
650 }
651
652 done:
653 if (!found)
654 return (DCMD_ERR);
655 return (DCMD_OK);
656 }
657
658 int
va2pfn_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)659 va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
660 {
661 uintptr_t addrspace;
662 char *addrspace_str = NULL;
663 int piped = flags & DCMD_PIPE_OUT;
664 pfn_t pfn;
665 pfn_t mfn;
666 int rc;
667
668 init_mmu();
669
670 if (mmu.num_level == 0)
671 return (DCMD_ERR);
672
673 if (mdb_getopts(argc, argv,
674 'a', MDB_OPT_STR, &addrspace_str) != argc)
675 return (DCMD_USAGE);
676
677 if ((flags & DCMD_ADDRSPEC) == 0)
678 return (DCMD_USAGE);
679
680 /*
681 * parse the address space
682 */
683 if (addrspace_str != NULL)
684 addrspace = mdb_strtoull(addrspace_str);
685 else
686 addrspace = 0;
687
688 rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn);
689
690 if (rc != DCMD_OK)
691 return (rc);
692
693 if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) {
694 mdb_warn("Invalid mfn %lr\n", mfn);
695 return (DCMD_ERR);
696 }
697
698 if (piped) {
699 mdb_printf("0x%lr\n", pfn);
700 return (DCMD_OK);
701 }
702
703 mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn);
704
705 if (is_xpv)
706 mdb_printf(" (mfn 0x%lr)", mfn);
707
708 mdb_printf("\n");
709
710 return (DCMD_OK);
711 }
712
713 /*
714 * Report all hat's that either use PFN as a page table or that map the page.
715 */
716 static int
do_report_maps(pfn_t pfn)717 do_report_maps(pfn_t pfn)
718 {
719 struct hat *hatp;
720 struct hat hat;
721 htable_t *ht;
722 htable_t htable;
723 uintptr_t base;
724 int h;
725 int level;
726 int entry;
727 x86pte_t pte;
728 x86pte_t buf;
729 x86pte32_t *pte32 = (x86pte32_t *)&buf;
730 physaddr_t paddr;
731 size_t len;
732
733 /*
734 * The hats are kept in a list with khat at the head.
735 */
736 for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
737 /*
738 * read the hat and its hash table
739 */
740 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
741 mdb_warn("Couldn't read struct hat\n");
742 return (DCMD_ERR);
743 }
744
745 /*
746 * read the htable hashtable
747 */
748 paddr = 0;
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");
753 return (DCMD_ERR);
754 }
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");
759 return (DCMD_ERR);
760 }
761
762 /*
763 * only report kernel addresses once
764 */
765 if (hatp != khat &&
766 htable.ht_vaddr >= kernelbase)
767 continue;
768
769 /*
770 * Is the PFN a pagetable itself?
771 */
772 if (htable.ht_pfn == pfn) {
773 mdb_printf("Pagetable for "
774 "hat=%p htable=%p\n", hatp, ht);
775 continue;
776 }
777
778 /*
779 * otherwise, examine page mappings
780 */
781 level = htable.ht_level;
782 if (level > mmu.max_page_level)
783 continue;
784 paddr = mmu_ptob((physaddr_t)htable.ht_pfn);
785 for (entry = 0;
786 entry < HTABLE_NUM_PTES(&htable);
787 ++entry) {
788
789 base = htable.ht_vaddr + entry *
790 mmu.level_size[level];
791
792 /*
793 * only report kernel addresses once
794 */
795 if (hatp != khat &&
796 base >= kernelbase)
797 continue;
798
799 len = mdb_pread(&buf, mmu.pte_size,
800 paddr + entry * mmu.pte_size);
801 if (len != mmu.pte_size)
802 return (DCMD_ERR);
803 if (mmu.pte_size == sizeof (x86pte_t))
804 pte = buf;
805 else
806 pte = *pte32;
807
808 if ((pte & PT_VALID) == 0)
809 continue;
810 if (level == 0 || !(pte & PT_PAGESIZE))
811 pte &= PT_PADDR;
812 else
813 pte &= PT_PADDR_LGPG;
814 if (mmu_btop(mdb_ma_to_pa(pte)) != pfn)
815 continue;
816 mdb_printf("hat=%p maps addr=%p\n",
817 hatp, (caddr_t)base);
818 }
819 }
820 }
821 }
822
823 done:
824 return (DCMD_OK);
825 }
826
827 /*
828 * given a PFN as its address argument, prints out the uses of it
829 */
830 /*ARGSUSED*/
831 int
report_maps_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)832 report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
833 {
834 pfn_t pfn;
835 uint_t mflag = 0;
836
837 init_mmu();
838
839 if (mmu.num_level == 0)
840 return (DCMD_ERR);
841
842 if ((flags & DCMD_ADDRSPEC) == 0)
843 return (DCMD_USAGE);
844
845 if (mdb_getopts(argc, argv,
846 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
847 return (DCMD_USAGE);
848
849 pfn = (pfn_t)addr;
850 if (mflag)
851 pfn = mdb_mfn_to_pfn(pfn);
852
853 return (do_report_maps(pfn));
854 }
855
856 static int
do_ptable_dcmd(pfn_t pfn)857 do_ptable_dcmd(pfn_t pfn)
858 {
859 struct hat *hatp;
860 struct hat hat;
861 htable_t *ht;
862 htable_t htable;
863 uintptr_t base;
864 int h;
865 int level;
866 int entry;
867 uintptr_t pagesize;
868 x86pte_t pte;
869 x86pte_t buf;
870 x86pte32_t *pte32 = (x86pte32_t *)&buf;
871 physaddr_t paddr;
872 size_t len;
873
874 /*
875 * The hats are kept in a list with khat at the head.
876 */
877 for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
878 /*
879 * read the hat and its hash table
880 */
881 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
882 mdb_warn("Couldn't read struct hat\n");
883 return (DCMD_ERR);
884 }
885
886 /*
887 * read the htable hashtable
888 */
889 paddr = 0;
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");
894 return (DCMD_ERR);
895 }
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");
900 return (DCMD_ERR);
901 }
902
903 /*
904 * Is this the PFN for this htable
905 */
906 if (htable.ht_pfn == pfn)
907 goto found_it;
908 }
909 }
910 }
911
912 found_it:
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];
918 } else {
919 mdb_printf("Unknown pagetable - assuming level/addr 0");
920 level = 0; /* assume level == 0 for PFN */
921 base = 0;
922 pagesize = MMU_PAGESIZE;
923 }
924
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)
930 return (DCMD_ERR);
931 if (mmu.pte_size == sizeof (x86pte_t))
932 pte = buf;
933 else
934 pte = *pte32;
935
936 if (pte == 0)
937 continue;
938
939 mdb_printf("[%3d] va=%p ", entry, base + entry * pagesize);
940 do_pte_dcmd(level, pte);
941 }
942
943 done:
944 return (DCMD_OK);
945 }
946
947 /*
948 * Dump the page table at the given PFN
949 */
950 /*ARGSUSED*/
951 int
ptable_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)952 ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
953 {
954 pfn_t pfn;
955 uint_t mflag = 0;
956
957 init_mmu();
958
959 if (mmu.num_level == 0)
960 return (DCMD_ERR);
961
962 if ((flags & DCMD_ADDRSPEC) == 0)
963 return (DCMD_USAGE);
964
965 if (mdb_getopts(argc, argv,
966 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
967 return (DCMD_USAGE);
968
969 pfn = (pfn_t)addr;
970 if (mflag)
971 pfn = mdb_mfn_to_pfn(pfn);
972
973 return (do_ptable_dcmd(pfn));
974 }
975
976 static int
do_htables_dcmd(hat_t * hatp)977 do_htables_dcmd(hat_t *hatp)
978 {
979 struct hat hat;
980 htable_t *ht;
981 htable_t htable;
982 int h;
983
984 /*
985 * read the hat and its hash table
986 */
987 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
988 mdb_warn("Couldn't read struct hat\n");
989 return (DCMD_ERR);
990 }
991
992 /*
993 * read the htable hashtable
994 */
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");
999 return (DCMD_ERR);
1000 }
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");
1006 return (DCMD_ERR);
1007 }
1008 }
1009 }
1010 return (DCMD_OK);
1011 }
1012
1013 /*
1014 * Dump the htables for the given hat
1015 */
1016 /*ARGSUSED*/
1017 int
htables_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1018 htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1019 {
1020 hat_t *hat;
1021
1022 init_mmu();
1023
1024 if (mmu.num_level == 0)
1025 return (DCMD_ERR);
1026
1027 if ((flags & DCMD_ADDRSPEC) == 0)
1028 return (DCMD_USAGE);
1029
1030 hat = (hat_t *)addr;
1031
1032 return (do_htables_dcmd(hat));
1033 }
1034