Print this page
9452 ptable_dcmd() needs a little cleanup
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/mdb/i86pc/modules/unix/i86mmu.c
+++ new/usr/src/cmd/mdb/i86pc/modules/unix/i86mmu.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 *
25 25 * Copyright 2018 Joyent, Inc.
26 26 */
27 27
28 28 /*
29 29 * This part of the file contains the mdb support for dcmds:
30 30 * ::memseg_list
31 31 * and walkers for:
32 32 * memseg - a memseg list walker for ::memseg_list
33 33 *
34 34 */
35 35
36 36 #include <sys/types.h>
37 37 #include <sys/machparam.h>
38 38 #include <sys/controlregs.h>
39 39 #include <sys/mach_mmu.h>
40 40 #ifdef __xpv
41 41 #include <sys/hypervisor.h>
42 42 #endif
43 43 #include <vm/as.h>
44 44
45 45 #include <mdb/mdb_modapi.h>
46 46 #include <mdb/mdb_target.h>
47 47
48 48 #include <vm/page.h>
49 49 #include <vm/hat_i86.h>
50 50
51 51 #define VA_SIGN_BIT (1UL << 47)
52 52 #define VA_SIGN_EXTEND(va) (((va) ^ VA_SIGN_BIT) - VA_SIGN_BIT)
53 53
54 54 struct pfn2pp {
55 55 pfn_t pfn;
56 56 page_t *pp;
57 57 };
58 58
59 59 static int do_va2pa(uintptr_t, struct as *, int, physaddr_t *, pfn_t *);
60 60 static void init_mmu(void);
61 61
62 62 int
63 63 platform_vtop(uintptr_t addr, struct as *asp, physaddr_t *pap)
64 64 {
65 65 if (asp == NULL)
66 66 return (DCMD_ERR);
67 67
68 68 init_mmu();
69 69
70 70 if (mmu.num_level == 0)
71 71 return (DCMD_ERR);
72 72
73 73 return (do_va2pa(addr, asp, 0, pap, NULL));
74 74 }
75 75
76 76 /*
77 77 * ::memseg_list dcmd and walker to implement it.
78 78 */
79 79 /*ARGSUSED*/
80 80 int
81 81 memseg_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
82 82 {
83 83 struct memseg ms;
84 84
85 85 if (!(flags & DCMD_ADDRSPEC)) {
86 86 if (mdb_pwalk_dcmd("memseg", "memseg_list",
87 87 0, NULL, 0) == -1) {
88 88 mdb_warn("can't walk memseg");
89 89 return (DCMD_ERR);
90 90 }
91 91 return (DCMD_OK);
92 92 }
93 93
94 94 if (DCMD_HDRSPEC(flags))
95 95 mdb_printf("%<u>%?s %?s %?s %?s %?s%</u>\n", "ADDR",
96 96 "PAGES", "EPAGES", "BASE", "END");
97 97
98 98 if (mdb_vread(&ms, sizeof (struct memseg), addr) == -1) {
99 99 mdb_warn("can't read memseg at %#lx", addr);
100 100 return (DCMD_ERR);
101 101 }
102 102
103 103 mdb_printf("%0?lx %0?lx %0?lx %0?lx %0?lx\n", addr,
104 104 ms.pages, ms.epages, ms.pages_base, ms.pages_end);
105 105
106 106 return (DCMD_OK);
107 107 }
108 108
109 109 /*
110 110 * walk the memseg structures
111 111 */
112 112 int
113 113 memseg_walk_init(mdb_walk_state_t *wsp)
114 114 {
115 115 if (wsp->walk_addr != NULL) {
116 116 mdb_warn("memseg only supports global walks\n");
117 117 return (WALK_ERR);
118 118 }
119 119
120 120 if (mdb_readvar(&wsp->walk_addr, "memsegs") == -1) {
121 121 mdb_warn("symbol 'memsegs' not found");
122 122 return (WALK_ERR);
123 123 }
124 124
125 125 wsp->walk_data = mdb_alloc(sizeof (struct memseg), UM_SLEEP);
126 126 return (WALK_NEXT);
127 127
128 128 }
129 129
130 130 int
131 131 memseg_walk_step(mdb_walk_state_t *wsp)
132 132 {
133 133 int status;
134 134
135 135 if (wsp->walk_addr == 0) {
136 136 return (WALK_DONE);
137 137 }
138 138
139 139 if (mdb_vread(wsp->walk_data, sizeof (struct memseg),
140 140 wsp->walk_addr) == -1) {
141 141 mdb_warn("failed to read struct memseg at %p", wsp->walk_addr);
142 142 return (WALK_DONE);
143 143 }
144 144
145 145 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
146 146 wsp->walk_cbdata);
147 147
148 148 wsp->walk_addr = (uintptr_t)(((struct memseg *)wsp->walk_data)->next);
149 149
150 150 return (status);
151 151 }
152 152
153 153 void
154 154 memseg_walk_fini(mdb_walk_state_t *wsp)
155 155 {
156 156 mdb_free(wsp->walk_data, sizeof (struct memseg));
157 157 }
158 158
159 159 /*
160 160 * Now HAT related dcmds.
161 161 */
162 162
163 163 static struct hat *khat; /* value of kas.a_hat */
164 164 struct hat_mmu_info mmu;
165 165 uintptr_t kernelbase;
166 166
167 167 /*
168 168 * stuff for i86xpv images
169 169 */
170 170 static int is_xpv;
171 171 static uintptr_t mfn_list_addr; /* kernel MFN list address */
172 172 uintptr_t xen_virt_start; /* address of mfn_to_pfn[] table */
173 173 ulong_t mfn_count; /* number of pfn's in the MFN list */
174 174 pfn_t *mfn_list; /* local MFN list copy */
175 175
176 176 /*
177 177 * read mmu parameters from kernel
178 178 */
179 179 static void
180 180 init_mmu(void)
181 181 {
182 182 struct as kas;
183 183
184 184 if (mmu.num_level != 0)
185 185 return;
186 186
187 187 if (mdb_readsym(&mmu, sizeof (mmu), "mmu") == -1)
188 188 mdb_warn("Can't use HAT information before mmu_init()\n");
189 189 if (mdb_readsym(&kas, sizeof (kas), "kas") == -1)
190 190 mdb_warn("Couldn't find kas - kernel's struct as\n");
191 191 if (mdb_readsym(&kernelbase, sizeof (kernelbase), "kernelbase") == -1)
192 192 mdb_warn("Couldn't find kernelbase\n");
193 193 khat = kas.a_hat;
194 194
195 195 /*
196 196 * Is this a paravirtualized domain image?
197 197 */
198 198 if (mdb_readsym(&mfn_list_addr, sizeof (mfn_list_addr),
199 199 "mfn_list") == -1 ||
200 200 mdb_readsym(&xen_virt_start, sizeof (xen_virt_start),
201 201 "xen_virt_start") == -1 ||
202 202 mdb_readsym(&mfn_count, sizeof (mfn_count), "mfn_count") == -1) {
203 203 mfn_list_addr = NULL;
204 204 }
205 205
206 206 is_xpv = mfn_list_addr != NULL;
207 207
208 208 #ifndef _KMDB
209 209 /*
210 210 * recreate the local mfn_list
211 211 */
212 212 if (is_xpv) {
213 213 size_t sz = mfn_count * sizeof (pfn_t);
214 214 mfn_list = mdb_zalloc(sz, UM_SLEEP);
215 215
216 216 if (mdb_vread(mfn_list, sz, (uintptr_t)mfn_list_addr) == -1) {
217 217 mdb_warn("Failed to read MFN list\n");
218 218 mdb_free(mfn_list, sz);
219 219 mfn_list = NULL;
220 220 }
221 221 }
222 222 #endif
223 223 }
224 224
225 225 void
226 226 free_mmu(void)
227 227 {
228 228 #ifdef __xpv
229 229 if (mfn_list != NULL)
230 230 mdb_free(mfn_list, mfn_count * sizeof (mfn_t));
231 231 #endif
232 232 }
233 233
234 234 #ifdef __xpv
235 235
236 236 #ifdef _KMDB
237 237
238 238 /*
239 239 * Convert between MFNs and PFNs. Since we're in kmdb we can go directly
240 240 * through the machine to phys mapping and the MFN list.
241 241 */
242 242
243 243 pfn_t
244 244 mdb_mfn_to_pfn(mfn_t mfn)
245 245 {
246 246 pfn_t pfn;
247 247 mfn_t tmp;
248 248 pfn_t *pfn_list;
249 249
250 250 if (mfn_list_addr == NULL)
251 251 return (-(pfn_t)1);
252 252
253 253 pfn_list = (pfn_t *)xen_virt_start;
254 254 if (mdb_vread(&pfn, sizeof (pfn), (uintptr_t)(pfn_list + mfn)) == -1)
255 255 return (-(pfn_t)1);
256 256
257 257 if (mdb_vread(&tmp, sizeof (tmp),
258 258 (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
259 259 return (-(pfn_t)1);
260 260
261 261 if (pfn >= mfn_count || tmp != mfn)
262 262 return (-(pfn_t)1);
263 263
264 264 return (pfn);
265 265 }
266 266
267 267 mfn_t
268 268 mdb_pfn_to_mfn(pfn_t pfn)
269 269 {
270 270 mfn_t mfn;
271 271
272 272 init_mmu();
273 273
274 274 if (mfn_list_addr == NULL || pfn >= mfn_count)
275 275 return (-(mfn_t)1);
276 276
277 277 if (mdb_vread(&mfn, sizeof (mfn),
278 278 (uintptr_t)(mfn_list_addr + (pfn * sizeof (mfn_t)))) == -1)
279 279 return (-(mfn_t)1);
280 280
281 281 return (mfn);
282 282 }
283 283
284 284 #else /* _KMDB */
285 285
286 286 /*
287 287 * Convert between MFNs and PFNs. Since a crash dump doesn't include the
288 288 * MFN->PFN translation table (it's part of the hypervisor, not our image)
289 289 * we do the MFN->PFN translation by searching the PFN->MFN (mfn_list)
290 290 * table, if it's there.
291 291 */
292 292
293 293 pfn_t
294 294 mdb_mfn_to_pfn(mfn_t mfn)
295 295 {
296 296 pfn_t pfn;
297 297
298 298 init_mmu();
299 299
300 300 if (mfn_list == NULL)
301 301 return (-(pfn_t)1);
302 302
303 303 for (pfn = 0; pfn < mfn_count; ++pfn) {
304 304 if (mfn_list[pfn] != mfn)
305 305 continue;
306 306 return (pfn);
307 307 }
308 308
309 309 return (-(pfn_t)1);
310 310 }
311 311
312 312 mfn_t
313 313 mdb_pfn_to_mfn(pfn_t pfn)
314 314 {
315 315 init_mmu();
316 316
317 317 if (mfn_list == NULL || pfn >= mfn_count)
318 318 return (-(mfn_t)1);
319 319
320 320 return (mfn_list[pfn]);
321 321 }
322 322
323 323 #endif /* _KMDB */
324 324
325 325 static paddr_t
326 326 mdb_ma_to_pa(uint64_t ma)
327 327 {
328 328 pfn_t pfn = mdb_mfn_to_pfn(mmu_btop(ma));
329 329 if (pfn == -(pfn_t)1)
330 330 return (-(paddr_t)1);
331 331
332 332 return (mmu_ptob((paddr_t)pfn) | (ma & (MMU_PAGESIZE - 1)));
333 333 }
334 334
335 335 #else /* __xpv */
336 336
337 337 #define mdb_ma_to_pa(ma) (ma)
338 338 #define mdb_mfn_to_pfn(mfn) (mfn)
339 339 #define mdb_pfn_to_mfn(pfn) (pfn)
340 340
341 341 #endif /* __xpv */
342 342
343 343 /*
344 344 * ::mfntopfn dcmd translates hypervisor machine page number
345 345 * to physical page number
346 346 */
347 347 /*ARGSUSED*/
348 348 int
349 349 mfntopfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
350 350 {
351 351 pfn_t pfn;
352 352
353 353 if ((flags & DCMD_ADDRSPEC) == 0) {
354 354 mdb_warn("MFN missing\n");
355 355 return (DCMD_USAGE);
356 356 }
357 357
358 358 if ((pfn = mdb_mfn_to_pfn((pfn_t)addr)) == -(pfn_t)1) {
359 359 mdb_warn("Invalid mfn %lr\n", (pfn_t)addr);
360 360 return (DCMD_ERR);
361 361 }
362 362
363 363 mdb_printf("%lr\n", pfn);
364 364
365 365 return (DCMD_OK);
366 366 }
367 367
368 368 /*
369 369 * ::pfntomfn dcmd translates physical page number to
370 370 * hypervisor machine page number
371 371 */
372 372 /*ARGSUSED*/
373 373 int
374 374 pfntomfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
375 375 {
376 376 pfn_t mfn;
377 377
378 378 if ((flags & DCMD_ADDRSPEC) == 0) {
379 379 mdb_warn("PFN missing\n");
380 380 return (DCMD_USAGE);
381 381 }
382 382
383 383 if ((mfn = mdb_pfn_to_mfn((pfn_t)addr)) == -(pfn_t)1) {
384 384 mdb_warn("Invalid pfn %lr\n", (pfn_t)addr);
385 385 return (DCMD_ABORT);
386 386 }
387 387
388 388 mdb_printf("%lr\n", mfn);
389 389
390 390 if (flags & DCMD_LOOP)
391 391 mdb_set_dot(addr + 1);
392 392 return (DCMD_OK);
393 393 }
394 394
395 395 static pfn_t
396 396 pte2mfn(x86pte_t pte, uint_t level)
397 397 {
398 398 pfn_t mfn;
399 399 if (level > 0 && (pte & PT_PAGESIZE))
400 400 mfn = mmu_btop(pte & PT_PADDR_LGPG);
401 401 else
402 402 mfn = mmu_btop(pte & PT_PADDR);
403 403 return (mfn);
404 404 }
405 405
406 406 static int
407 407 do_pte_dcmd(int level, uint64_t pte)
408 408 {
409 409 static char *attr[] = {
410 410 "wrback", "wrthru", "uncached", "uncached",
411 411 "wrback", "wrthru", "wrcombine", "uncached"};
412 412 int pat_index = 0;
413 413 pfn_t mfn;
414 414
415 415 mdb_printf("pte=0x%llr: ", pte);
416 416
417 417 mfn = pte2mfn(pte, level);
418 418 mdb_printf("%s=0x%lr ", is_xpv ? "mfn" : "pfn", mfn);
419 419
420 420 if (PTE_GET(pte, mmu.pt_nx))
421 421 mdb_printf("noexec ");
422 422
423 423 if (PTE_GET(pte, PT_NOCONSIST))
424 424 mdb_printf("noconsist ");
425 425
426 426 if (PTE_GET(pte, PT_NOSYNC))
427 427 mdb_printf("nosync ");
428 428
429 429 if (PTE_GET(pte, mmu.pt_global))
430 430 mdb_printf("global ");
431 431
432 432 if (level > 0 && PTE_GET(pte, PT_PAGESIZE))
433 433 mdb_printf("largepage ");
434 434
435 435 if (level > 0 && PTE_GET(pte, PT_MOD))
436 436 mdb_printf("mod ");
437 437
438 438 if (level > 0 && PTE_GET(pte, PT_REF))
439 439 mdb_printf("ref ");
440 440
441 441 if (PTE_GET(pte, PT_USER))
442 442 mdb_printf("user ");
443 443
444 444 if (PTE_GET(pte, PT_WRITABLE))
445 445 mdb_printf("write ");
446 446
447 447 /*
448 448 * Report non-standard cacheability
449 449 */
450 450 pat_index = 0;
451 451 if (level > 0) {
452 452 if (PTE_GET(pte, PT_PAGESIZE) && PTE_GET(pte, PT_PAT_LARGE))
453 453 pat_index += 4;
454 454 } else {
455 455 if (PTE_GET(pte, PT_PAT_4K))
456 456 pat_index += 4;
457 457 }
458 458
459 459 if (PTE_GET(pte, PT_NOCACHE))
460 460 pat_index += 2;
461 461
462 462 if (PTE_GET(pte, PT_WRITETHRU))
463 463 pat_index += 1;
464 464
465 465 if (pat_index != 0)
466 466 mdb_printf("%s", attr[pat_index]);
467 467
468 468 if (PTE_GET(pte, PT_VALID) == 0)
469 469 mdb_printf(" !VALID ");
470 470
471 471 mdb_printf("\n");
472 472 return (DCMD_OK);
473 473 }
474 474
475 475 /*
476 476 * Print a PTE in more human friendly way. The PTE is assumed to be in
477 477 * a level 0 page table, unless -l specifies another level.
478 478 */
479 479 /*ARGSUSED*/
480 480 int
481 481 pte_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
482 482 {
483 483 uint64_t level = 0;
484 484
485 485 init_mmu();
486 486
487 487 if (mmu.num_level == 0)
488 488 return (DCMD_ERR);
489 489
490 490 if ((flags & DCMD_ADDRSPEC) == 0)
491 491 return (DCMD_USAGE);
492 492
493 493 if (mdb_getopts(argc, argv,
494 494 'l', MDB_OPT_UINT64, &level) != argc)
495 495 return (DCMD_USAGE);
496 496
497 497 if (level > mmu.max_level) {
498 498 mdb_warn("invalid level %lu\n", level);
499 499 return (DCMD_ERR);
500 500 }
501 501
502 502 if (addr == 0)
503 503 return (DCMD_OK);
504 504
505 505 return (do_pte_dcmd((int)level, addr));
506 506 }
507 507
508 508 static size_t
509 509 va2entry(htable_t *htable, uintptr_t addr)
510 510 {
511 511 size_t entry = (addr - htable->ht_vaddr);
512 512
513 513 entry >>= mmu.level_shift[htable->ht_level];
514 514 return (entry & HTABLE_NUM_PTES(htable) - 1);
515 515 }
516 516
517 517 static x86pte_t
518 518 get_pte(hat_t *hat, htable_t *htable, uintptr_t addr)
519 519 {
520 520 x86pte_t buf;
521 521
522 522 if (htable->ht_flags & HTABLE_COPIED) {
523 523 uintptr_t ptr = (uintptr_t)hat->hat_copied_ptes;
524 524 ptr += va2entry(htable, addr) << mmu.pte_size_shift;
525 525 return (*(x86pte_t *)ptr);
526 526 }
527 527
528 528 paddr_t paddr = mmu_ptob((paddr_t)htable->ht_pfn);
529 529 paddr += va2entry(htable, addr) << mmu.pte_size_shift;
530 530
531 531 if ((mdb_pread(&buf, mmu.pte_size, paddr)) == mmu.pte_size)
532 532 return (buf);
533 533
534 534 return (0);
535 535 }
536 536
537 537 static int
538 538 do_va2pa(uintptr_t addr, struct as *asp, int print_level, physaddr_t *pap,
539 539 pfn_t *mfnp)
540 540 {
541 541 struct as as;
542 542 struct hat *hatp;
543 543 struct hat hat;
544 544 htable_t *ht;
545 545 htable_t htable;
546 546 uintptr_t base;
547 547 int h;
548 548 int level;
549 549 int found = 0;
550 550 x86pte_t pte;
551 551 physaddr_t paddr;
552 552
553 553 if (asp != NULL) {
554 554 if (mdb_vread(&as, sizeof (as), (uintptr_t)asp) == -1) {
555 555 mdb_warn("Couldn't read struct as\n");
556 556 return (DCMD_ERR);
557 557 }
558 558 hatp = as.a_hat;
559 559 } else {
560 560 hatp = khat;
561 561 }
562 562
563 563 /*
564 564 * read the hat and its hash table
565 565 */
566 566 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
567 567 mdb_warn("Couldn't read struct hat\n");
568 568 return (DCMD_ERR);
569 569 }
570 570
571 571 /*
572 572 * read the htable hashtable
573 573 */
574 574 for (level = 0; level <= mmu.max_level; ++level) {
575 575 if (level == TOP_LEVEL(&hat))
576 576 base = 0;
577 577 else
578 578 base = addr & mmu.level_mask[level + 1];
579 579
580 580 for (h = 0; h < hat.hat_num_hash; ++h) {
581 581 if (mdb_vread(&ht, sizeof (htable_t *),
582 582 (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
583 583 mdb_warn("Couldn't read htable\n");
584 584 return (DCMD_ERR);
585 585 }
586 586 for (; ht != NULL; ht = htable.ht_next) {
587 587 if (mdb_vread(&htable, sizeof (htable_t),
588 588 (uintptr_t)ht) == -1) {
589 589 mdb_warn("Couldn't read htable\n");
590 590 return (DCMD_ERR);
591 591 }
592 592
593 593 if (htable.ht_vaddr != base ||
594 594 htable.ht_level != level)
595 595 continue;
596 596
597 597 pte = get_pte(&hat, &htable, addr);
598 598
599 599 if (print_level) {
600 600 mdb_printf("\tlevel=%d htable=0x%p "
601 601 "pte=0x%llr\n", level, ht, pte);
602 602 }
603 603
604 604 if (!PTE_ISVALID(pte)) {
605 605 mdb_printf("Address %p is unmapped.\n",
606 606 addr);
607 607 return (DCMD_ERR);
608 608 }
609 609
610 610 if (found)
611 611 continue;
612 612
613 613 if (PTE_IS_LGPG(pte, level))
614 614 paddr = mdb_ma_to_pa(pte &
615 615 PT_PADDR_LGPG);
616 616 else
617 617 paddr = mdb_ma_to_pa(pte & PT_PADDR);
618 618 paddr += addr & mmu.level_offset[level];
619 619 if (pap != NULL)
620 620 *pap = paddr;
621 621 if (mfnp != NULL)
622 622 *mfnp = pte2mfn(pte, level);
623 623 found = 1;
624 624 }
625 625 }
626 626 }
627 627
628 628 done:
629 629 if (!found)
630 630 return (DCMD_ERR);
631 631 return (DCMD_OK);
632 632 }
633 633
634 634 int
635 635 va2pfn_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
636 636 {
637 637 uintptr_t addrspace;
638 638 char *addrspace_str = NULL;
639 639 int piped = flags & DCMD_PIPE_OUT;
640 640 pfn_t pfn;
641 641 pfn_t mfn;
642 642 int rc;
643 643
644 644 init_mmu();
645 645
646 646 if (mmu.num_level == 0)
647 647 return (DCMD_ERR);
648 648
649 649 if (mdb_getopts(argc, argv,
650 650 'a', MDB_OPT_STR, &addrspace_str) != argc)
651 651 return (DCMD_USAGE);
652 652
653 653 if ((flags & DCMD_ADDRSPEC) == 0)
654 654 return (DCMD_USAGE);
655 655
656 656 /*
657 657 * parse the address space
658 658 */
659 659 if (addrspace_str != NULL)
660 660 addrspace = mdb_strtoull(addrspace_str);
661 661 else
662 662 addrspace = 0;
663 663
664 664 rc = do_va2pa(addr, (struct as *)addrspace, !piped, NULL, &mfn);
665 665
666 666 if (rc != DCMD_OK)
667 667 return (rc);
668 668
669 669 if ((pfn = mdb_mfn_to_pfn(mfn)) == -(pfn_t)1) {
670 670 mdb_warn("Invalid mfn %lr\n", mfn);
671 671 return (DCMD_ERR);
672 672 }
673 673
674 674 if (piped) {
675 675 mdb_printf("0x%lr\n", pfn);
676 676 return (DCMD_OK);
677 677 }
678 678
679 679 mdb_printf("Virtual address 0x%p maps pfn 0x%lr", addr, pfn);
680 680
681 681 if (is_xpv)
682 682 mdb_printf(" (mfn 0x%lr)", mfn);
683 683
684 684 mdb_printf("\n");
685 685
686 686 return (DCMD_OK);
687 687 }
688 688
689 689 /*
690 690 * Report all hat's that either use PFN as a page table or that map the page.
691 691 */
692 692 static int
693 693 do_report_maps(pfn_t pfn)
694 694 {
695 695 struct hat *hatp;
696 696 struct hat hat;
697 697 htable_t *ht;
698 698 htable_t htable;
699 699 uintptr_t base;
700 700 int h;
701 701 int level;
702 702 int entry;
703 703 x86pte_t pte;
704 704 physaddr_t paddr;
705 705 size_t len;
706 706
707 707 /*
708 708 * The hats are kept in a list with khat at the head.
709 709 */
710 710 for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
711 711 /*
712 712 * read the hat and its hash table
713 713 */
714 714 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
715 715 mdb_warn("Couldn't read struct hat\n");
716 716 return (DCMD_ERR);
717 717 }
718 718
719 719 /*
720 720 * read the htable hashtable
721 721 */
722 722 paddr = 0;
723 723 for (h = 0; h < hat.hat_num_hash; ++h) {
724 724 if (mdb_vread(&ht, sizeof (htable_t *),
725 725 (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
726 726 mdb_warn("Couldn't read htable\n");
727 727 return (DCMD_ERR);
728 728 }
729 729 for (; ht != NULL; ht = htable.ht_next) {
730 730 if (mdb_vread(&htable, sizeof (htable_t),
731 731 (uintptr_t)ht) == -1) {
732 732 mdb_warn("Couldn't read htable\n");
733 733 return (DCMD_ERR);
734 734 }
735 735
736 736 /*
737 737 * only report kernel addresses once
738 738 */
739 739 if (hatp != khat &&
740 740 htable.ht_vaddr >= kernelbase)
741 741 continue;
742 742
743 743 /*
744 744 * Is the PFN a pagetable itself?
745 745 */
746 746 if (htable.ht_pfn == pfn) {
747 747 mdb_printf("Pagetable for "
748 748 "hat=%p htable=%p\n", hatp, ht);
749 749 continue;
750 750 }
751 751
752 752 /*
753 753 * otherwise, examine page mappings
754 754 */
755 755 level = htable.ht_level;
756 756 if (level > mmu.max_page_level)
757 757 continue;
758 758 paddr = mmu_ptob((physaddr_t)htable.ht_pfn);
759 759 for (entry = 0;
760 760 entry < HTABLE_NUM_PTES(&htable);
761 761 ++entry) {
762 762
763 763 base = htable.ht_vaddr + entry *
764 764 mmu.level_size[level];
765 765
766 766 /*
767 767 * only report kernel addresses once
768 768 */
769 769 if (hatp != khat &&
770 770 base >= kernelbase)
771 771 continue;
772 772
773 773 len = mdb_pread(&pte, mmu.pte_size,
774 774 paddr + entry * mmu.pte_size);
775 775 if (len != mmu.pte_size)
776 776 return (DCMD_ERR);
777 777
778 778 if ((pte & PT_VALID) == 0)
779 779 continue;
780 780 if (level == 0 || !(pte & PT_PAGESIZE))
781 781 pte &= PT_PADDR;
782 782 else
783 783 pte &= PT_PADDR_LGPG;
784 784 if (mmu_btop(mdb_ma_to_pa(pte)) != pfn)
785 785 continue;
786 786 mdb_printf("hat=%p maps addr=%p\n",
787 787 hatp, (caddr_t)base);
788 788 }
789 789 }
790 790 }
791 791 }
792 792
793 793 done:
794 794 return (DCMD_OK);
795 795 }
796 796
797 797 /*
798 798 * given a PFN as its address argument, prints out the uses of it
799 799 */
800 800 /*ARGSUSED*/
801 801 int
802 802 report_maps_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
803 803 {
804 804 pfn_t pfn;
805 805 uint_t mflag = 0;
806 806
807 807 init_mmu();
808 808
809 809 if (mmu.num_level == 0)
810 810 return (DCMD_ERR);
811 811
812 812 if ((flags & DCMD_ADDRSPEC) == 0)
813 813 return (DCMD_USAGE);
814 814
815 815 if (mdb_getopts(argc, argv,
816 816 'm', MDB_OPT_SETBITS, TRUE, &mflag, NULL) != argc)
817 817 return (DCMD_USAGE);
818 818
819 819 pfn = (pfn_t)addr;
820 820 if (mflag)
821 821 pfn = mdb_mfn_to_pfn(pfn);
822 822
823 823 return (do_report_maps(pfn));
824 824 }
825 825
826 826 static int
827 827 do_ptable_dcmd(pfn_t pfn, uint64_t level)
↓ open down ↓ |
827 lines elided |
↑ open up ↑ |
828 828 {
829 829 struct hat *hatp;
830 830 struct hat hat;
831 831 htable_t *ht;
832 832 htable_t htable;
833 833 uintptr_t base;
834 834 int h;
835 835 int entry;
836 836 uintptr_t pagesize;
837 837 x86pte_t pte;
838 - x86pte_t buf;
839 838 physaddr_t paddr;
840 839 size_t len;
841 840
842 841 /*
843 842 * The hats are kept in a list with khat at the head.
844 843 */
845 844 for (hatp = khat; hatp != NULL; hatp = hat.hat_next) {
846 845 /*
847 846 * read the hat and its hash table
848 847 */
849 848 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
850 849 mdb_warn("Couldn't read struct hat\n");
851 850 return (DCMD_ERR);
852 851 }
853 852
854 853 /*
855 854 * read the htable hashtable
856 855 */
857 856 paddr = 0;
858 857 for (h = 0; h < hat.hat_num_hash; ++h) {
859 858 if (mdb_vread(&ht, sizeof (htable_t *),
860 859 (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
861 860 mdb_warn("Couldn't read htable\n");
862 861 return (DCMD_ERR);
863 862 }
864 863 for (; ht != NULL; ht = htable.ht_next) {
865 864 if (mdb_vread(&htable, sizeof (htable_t),
866 865 (uintptr_t)ht) == -1) {
867 866 mdb_warn("Couldn't read htable\n");
868 867 return (DCMD_ERR);
869 868 }
870 869
871 870 /*
872 871 * Is this the PFN for this htable
873 872 */
874 873 if (htable.ht_pfn == pfn)
875 874 goto found_it;
876 875 }
877 876 }
878 877 }
879 878
880 879 found_it:
881 880 if (htable.ht_pfn == pfn) {
882 881 mdb_printf("htable=%p\n", ht);
883 882 if (level == (uint64_t)-1) {
884 883 level = htable.ht_level;
885 884 } else if (htable.ht_level != level) {
886 885 mdb_warn("htable has level %d but forcing level %lu\n",
887 886 htable.ht_level, level);
888 887 }
889 888 base = htable.ht_vaddr;
890 889 pagesize = mmu.level_size[level];
891 890 } else {
↓ open down ↓ |
43 lines elided |
↑ open up ↑ |
892 891 if (level == (uint64_t)-1)
893 892 level = 0;
894 893 mdb_warn("couldn't find matching htable, using level=%lu, "
895 894 "base address=0x0\n", level);
896 895 base = 0;
897 896 pagesize = mmu.level_size[level];
898 897 }
899 898
900 899 paddr = mmu_ptob((physaddr_t)pfn);
901 900 for (entry = 0; entry < mmu.ptes_per_table; ++entry) {
902 - len = mdb_pread(&buf, mmu.pte_size,
901 + len = mdb_pread(&pte, mmu.pte_size,
903 902 paddr + entry * mmu.pte_size);
904 903 if (len != mmu.pte_size)
905 904 return (DCMD_ERR);
906 - pte = buf;
907 905
908 906 if (pte == 0)
909 907 continue;
910 908
911 909 mdb_printf("[%3d] va=0x%p ", entry,
912 910 VA_SIGN_EXTEND(base + entry * pagesize));
913 911 do_pte_dcmd(level, pte);
914 912 }
915 913
916 914 done:
917 915 return (DCMD_OK);
918 916 }
919 917
920 918 /*
921 919 * Dump the page table at the given PFN
922 920 */
923 921 /*ARGSUSED*/
924 922 int
925 923 ptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
926 924 {
927 925 pfn_t pfn;
928 926 uint_t mflag = 0;
929 927 uint64_t level = (uint64_t)-1;
930 928
931 929 init_mmu();
932 930
933 931 if (mmu.num_level == 0)
934 932 return (DCMD_ERR);
935 933
936 934 if ((flags & DCMD_ADDRSPEC) == 0)
937 935 return (DCMD_USAGE);
938 936
939 937 if (mdb_getopts(argc, argv,
940 938 'm', MDB_OPT_SETBITS, TRUE, &mflag,
941 939 'l', MDB_OPT_UINT64, &level, NULL) != argc)
942 940 return (DCMD_USAGE);
943 941
944 942 if (level != (uint64_t)-1 && level > mmu.max_level) {
945 943 mdb_warn("invalid level %lu\n", level);
946 944 return (DCMD_ERR);
947 945 }
948 946
949 947 pfn = (pfn_t)addr;
950 948 if (mflag)
951 949 pfn = mdb_mfn_to_pfn(pfn);
952 950
953 951 return (do_ptable_dcmd(pfn, level));
954 952 }
955 953
956 954 static int
957 955 do_htables_dcmd(hat_t *hatp)
958 956 {
959 957 struct hat hat;
960 958 htable_t *ht;
961 959 htable_t htable;
962 960 int h;
963 961
964 962 /*
965 963 * read the hat and its hash table
966 964 */
967 965 if (mdb_vread(&hat, sizeof (hat), (uintptr_t)hatp) == -1) {
968 966 mdb_warn("Couldn't read struct hat\n");
969 967 return (DCMD_ERR);
970 968 }
971 969
972 970 /*
973 971 * read the htable hashtable
974 972 */
975 973 for (h = 0; h < hat.hat_num_hash; ++h) {
976 974 if (mdb_vread(&ht, sizeof (htable_t *),
977 975 (uintptr_t)(hat.hat_ht_hash + h)) == -1) {
978 976 mdb_warn("Couldn't read htable ptr\\n");
979 977 return (DCMD_ERR);
980 978 }
981 979 for (; ht != NULL; ht = htable.ht_next) {
982 980 mdb_printf("%p\n", ht);
983 981 if (mdb_vread(&htable, sizeof (htable_t),
984 982 (uintptr_t)ht) == -1) {
985 983 mdb_warn("Couldn't read htable\n");
986 984 return (DCMD_ERR);
987 985 }
988 986 }
989 987 }
990 988 return (DCMD_OK);
991 989 }
992 990
993 991 /*
994 992 * Dump the htables for the given hat
995 993 */
996 994 /*ARGSUSED*/
997 995 int
998 996 htables_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
999 997 {
1000 998 hat_t *hat;
1001 999
1002 1000 init_mmu();
1003 1001
1004 1002 if (mmu.num_level == 0)
1005 1003 return (DCMD_ERR);
1006 1004
1007 1005 if ((flags & DCMD_ADDRSPEC) == 0)
1008 1006 return (DCMD_USAGE);
1009 1007
1010 1008 hat = (hat_t *)addr;
1011 1009
1012 1010 return (do_htables_dcmd(hat));
1013 1011 }
1014 1012
1015 1013 static uintptr_t
1016 1014 entry2va(size_t *entries)
1017 1015 {
1018 1016 uintptr_t va = 0;
1019 1017
1020 1018 for (level_t l = mmu.max_level; l >= 0; l--)
1021 1019 va += entries[l] << mmu.level_shift[l];
1022 1020
1023 1021 return (VA_SIGN_EXTEND(va));
1024 1022 }
1025 1023
1026 1024 static void
1027 1025 ptmap_report(size_t *entries, uintptr_t start,
1028 1026 boolean_t user, boolean_t writable, boolean_t wflag)
1029 1027 {
1030 1028 uint64_t curva = entry2va(entries);
1031 1029
1032 1030 mdb_printf("mapped %s,%s range of %lu bytes: %a-%a\n",
1033 1031 user ? "user" : "kernel", writable ? "writable" : "read-only",
1034 1032 curva - start, start, curva - 1);
1035 1033 if (wflag && start >= kernelbase)
1036 1034 (void) mdb_call_dcmd("whatis", start, DCMD_ADDRSPEC, 0, NULL);
1037 1035 }
1038 1036
1039 1037 int
1040 1038 ptmap_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1041 1039 {
1042 1040 physaddr_t paddrs[MAX_NUM_LEVEL] = { 0, };
1043 1041 size_t entry[MAX_NUM_LEVEL] = { 0, };
1044 1042 uintptr_t start = (uintptr_t)-1;
1045 1043 boolean_t writable = B_FALSE;
1046 1044 boolean_t user = B_FALSE;
1047 1045 boolean_t wflag = B_FALSE;
1048 1046 level_t curlevel;
1049 1047
1050 1048 if ((flags & DCMD_ADDRSPEC) == 0)
1051 1049 return (DCMD_USAGE);
1052 1050
1053 1051 if (mdb_getopts(argc, argv,
1054 1052 'w', MDB_OPT_SETBITS, TRUE, &wflag, NULL) != argc)
1055 1053 return (DCMD_USAGE);
1056 1054
1057 1055 init_mmu();
1058 1056
1059 1057 if (mmu.num_level == 0)
1060 1058 return (DCMD_ERR);
1061 1059
1062 1060 curlevel = mmu.max_level;
1063 1061
1064 1062 paddrs[curlevel] = addr & MMU_PAGEMASK;
1065 1063
1066 1064 for (;;) {
1067 1065 physaddr_t pte_addr;
1068 1066 x86pte_t pte;
1069 1067
1070 1068 pte_addr = paddrs[curlevel] +
1071 1069 (entry[curlevel] << mmu.pte_size_shift);
1072 1070
1073 1071 if (mdb_pread(&pte, sizeof (pte), pte_addr) != sizeof (pte)) {
1074 1072 mdb_warn("couldn't read pte at %p", pte_addr);
1075 1073 return (DCMD_ERR);
1076 1074 }
1077 1075
1078 1076 if (PTE_GET(pte, PT_VALID) == 0) {
1079 1077 if (start != (uintptr_t)-1) {
1080 1078 ptmap_report(entry, start,
1081 1079 user, writable, wflag);
1082 1080 start = (uintptr_t)-1;
1083 1081 }
1084 1082 } else if (curlevel == 0 || PTE_GET(pte, PT_PAGESIZE)) {
1085 1083 if (start == (uintptr_t)-1) {
1086 1084 start = entry2va(entry);
1087 1085 user = PTE_GET(pte, PT_USER);
1088 1086 writable = PTE_GET(pte, PT_WRITABLE);
1089 1087 } else if (user != PTE_GET(pte, PT_USER) ||
1090 1088 writable != PTE_GET(pte, PT_WRITABLE)) {
1091 1089 ptmap_report(entry, start,
1092 1090 user, writable, wflag);
1093 1091 start = entry2va(entry);
1094 1092 user = PTE_GET(pte, PT_USER);
1095 1093 writable = PTE_GET(pte, PT_WRITABLE);
1096 1094 }
1097 1095 } else {
1098 1096 /* Descend a level. */
1099 1097 physaddr_t pa = mmu_ptob(pte2mfn(pte, curlevel));
1100 1098 paddrs[--curlevel] = pa;
1101 1099 entry[curlevel] = 0;
1102 1100 continue;
1103 1101 }
1104 1102
1105 1103 while (++entry[curlevel] == mmu.ptes_per_table) {
1106 1104 /* Ascend back up. */
1107 1105 entry[curlevel] = 0;
1108 1106 if (curlevel == mmu.max_level) {
1109 1107 if (start != (uintptr_t)-1) {
1110 1108 ptmap_report(entry, start,
1111 1109 user, writable, wflag);
1112 1110 }
1113 1111 goto out;
1114 1112 }
1115 1113
1116 1114 curlevel++;
1117 1115 }
1118 1116 }
1119 1117
1120 1118 out:
1121 1119 return (DCMD_OK);
1122 1120 }
↓ open down ↓ |
206 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX