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 (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Joyent, Inc.
24 */
25
26 #include <mdb/mdb_modapi.h>
27 #include <mdb/mdb_ctf.h>
28 #include <sys/cpuvar.h>
29 #include <sys/systm.h>
30 #include <sys/traptrace.h>
31 #include <sys/x_call.h>
32 #include <sys/xc_levels.h>
33 #include <sys/avintr.h>
34 #include <sys/systm.h>
35 #include <sys/trap.h>
36 #include <sys/mutex.h>
37 #include <sys/mutex_impl.h>
38 #include "i86mmu.h"
39 #include "unix_sup.h"
40 #include <sys/apix.h>
41 #include <sys/x86_archext.h>
42 #include <sys/bitmap.h>
43 #include <sys/controlregs.h>
392 }
393
394 static struct {
395 uchar_t t_marker;
396 char *t_name;
397 int (*t_hdlr)(trap_trace_rec_t *);
398 } ttrace_hdlr[] = {
399 { TT_SYSCALL, "sysc", ttrace_syscall },
400 { TT_SYSENTER, "syse", ttrace_syscall },
401 { TT_SYSC, "asys", ttrace_syscall },
402 { TT_SYSC64, "sc64", ttrace_syscall },
403 { TT_INTERRUPT, "intr", ttrace_interrupt },
404 { TT_TRAP, "trap", ttrace_trap },
405 { TT_EVENT, "evnt", ttrace_trap },
406 { 0, NULL, NULL }
407 };
408
409 typedef struct ttrace_dcmd {
410 processorid_t ttd_cpu;
411 uint_t ttd_extended;
412 trap_trace_ctl_t ttd_ttc[NCPU];
413 } ttrace_dcmd_t;
414
415 #if defined(__amd64)
416
417 #define DUMP(reg) #reg, regs->r_##reg
418 #define THREEREGS " %3s: %16lx %3s: %16lx %3s: %16lx\n"
419
420 static void
421 ttrace_dumpregs(trap_trace_rec_t *rec)
422 {
423 struct regs *regs = &rec->ttr_regs;
424
425 mdb_printf(THREEREGS, DUMP(rdi), DUMP(rsi), DUMP(rdx));
426 mdb_printf(THREEREGS, DUMP(rcx), DUMP(r8), DUMP(r9));
427 mdb_printf(THREEREGS, DUMP(rax), DUMP(rbx), DUMP(rbp));
428 mdb_printf(THREEREGS, DUMP(r10), DUMP(r11), DUMP(r12));
429 mdb_printf(THREEREGS, DUMP(r13), DUMP(r14), DUMP(r15));
430 mdb_printf(THREEREGS, DUMP(ds), DUMP(es), DUMP(fs));
431 mdb_printf(THREEREGS, DUMP(gs), "trp", regs->r_trapno, DUMP(err));
432 mdb_printf(THREEREGS, DUMP(rip), DUMP(cs), DUMP(rfl));
433 mdb_printf(THREEREGS, DUMP(rsp), DUMP(ss), "cr2", rec->ttr_cr2);
434 mdb_printf("\n");
435 }
436
437 #else
438
439 #define DUMP(reg) #reg, regs->r_##reg
440 #define FOURREGS " %3s: %08x %3s: %08x %3s: %08x %3s: %08x\n"
441
442 static void
443 ttrace_dumpregs(trap_trace_rec_t *rec)
444 {
445 struct regs *regs = &rec->ttr_regs;
446
447 mdb_printf(FOURREGS, DUMP(gs), DUMP(fs), DUMP(es), DUMP(ds));
448 mdb_printf(FOURREGS, DUMP(edi), DUMP(esi), DUMP(ebp), DUMP(esp));
449 mdb_printf(FOURREGS, DUMP(ebx), DUMP(edx), DUMP(ecx), DUMP(eax));
450 mdb_printf(FOURREGS, "trp", regs->r_trapno, DUMP(err),
451 DUMP(pc), DUMP(cs));
452 mdb_printf(FOURREGS, DUMP(efl), "usp", regs->r_uesp, DUMP(ss),
453 "cr2", rec->ttr_cr2);
461 {
462 struct regs *regs = &rec->ttr_regs;
463 processorid_t cpu = -1, i;
464
465 for (i = 0; i < NCPU; i++) {
466 if (addr >= dcmd->ttd_ttc[i].ttc_first &&
467 addr < dcmd->ttd_ttc[i].ttc_limit) {
468 cpu = i;
469 break;
470 }
471 }
472
473 if (cpu == -1) {
474 mdb_warn("couldn't find %p in any trap trace ctl\n", addr);
475 return (WALK_ERR);
476 }
477
478 if (dcmd->ttd_cpu != -1 && cpu != dcmd->ttd_cpu)
479 return (WALK_NEXT);
480
481 mdb_printf("%3d %15llx ", cpu, rec->ttr_stamp);
482
483 for (i = 0; ttrace_hdlr[i].t_hdlr != NULL; i++) {
484 if (rec->ttr_marker != ttrace_hdlr[i].t_marker)
485 continue;
486 mdb_printf("%4s ", ttrace_hdlr[i].t_name);
487 if (ttrace_hdlr[i].t_hdlr(rec) == -1)
488 return (WALK_ERR);
489 }
490
491 mdb_printf(" %a\n", regs->r_pc);
492
493 if (dcmd->ttd_extended == FALSE)
494 return (WALK_NEXT);
495
496 if (rec->ttr_marker == TT_INTERRUPT)
497 ttrace_intr_detail(rec);
498 else
499 ttrace_dumpregs(rec);
500
520 {
521 ttrace_dcmd_t dcmd;
522 trap_trace_ctl_t *ttc = dcmd.ttd_ttc;
523 trap_trace_rec_t rec;
524 size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU;
525
526 if (!ttrace_ttr_size_check())
527 return (WALK_ERR);
528
529 bzero(&dcmd, sizeof (dcmd));
530 dcmd.ttd_cpu = -1;
531 dcmd.ttd_extended = FALSE;
532
533 if (mdb_readsym(ttc, ttc_size, "trap_trace_ctl") == -1) {
534 mdb_warn("symbol 'trap_trace_ctl' not found; "
535 "non-TRAPTRACE kernel?\n");
536 return (DCMD_ERR);
537 }
538
539 if (mdb_getopts(argc, argv,
540 'x', MDB_OPT_SETBITS, TRUE, &dcmd.ttd_extended, NULL) != argc)
541 return (DCMD_USAGE);
542
543 if (DCMD_HDRSPEC(flags)) {
544 mdb_printf("%3s %15s %4s %2s %-*s%s\n", "CPU",
545 "TIMESTAMP", "TYPE", "Vec", TT_HDLR_WIDTH, "HANDLER",
546 " EIP");
547 }
548
549 if (flags & DCMD_ADDRSPEC) {
550 if (addr >= NCPU) {
551 if (mdb_vread(&rec, sizeof (rec), addr) == -1) {
552 mdb_warn("couldn't read trap trace record "
553 "at %p", addr);
554 return (DCMD_ERR);
555 }
556
557 if (ttrace_walk(addr, &rec, &dcmd) == WALK_ERR)
558 return (DCMD_ERR);
559
560 return (DCMD_OK);
730 "that correspond to that address space\n");
731 }
732
733 static void
734 report_maps_help(void)
735 {
736 mdb_printf(
737 "Given a PFN, report HAT structures that map the page, or use\n"
738 "the page as a pagetable.\n"
739 "\n"
740 "-m Interpret the PFN as an MFN (machine frame number)\n");
741 }
742
743 static void
744 ptable_help(void)
745 {
746 mdb_printf(
747 "Given a PFN holding a page table, print its contents, and\n"
748 "the address of the corresponding htable structure.\n"
749 "\n"
750 "-m Interpret the PFN as an MFN (machine frame number)\n");
751 }
752
753 /*
754 * NSEC_SHIFT is replicated here (it is not defined in a header file),
755 * but for amusement, the reader is directed to the comment that explains
756 * the rationale for this particular value on x86. Spoiler: the value is
757 * selected to accommodate 60 MHz Pentiums! (And a confession: if the voice
758 * in that comment sounds too familiar, it's because your author also wrote
759 * that code -- some fifteen years prior to this writing in 2011...)
760 */
761 #define NSEC_SHIFT 5
762
763 /*ARGSUSED*/
764 static int
765 scalehrtime_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
766 {
767 uint32_t nsec_scale;
768 hrtime_t tsc = addr, hrt;
769 unsigned int *tscp = (unsigned int *)&tsc;
770 uintptr_t scalehrtimef;
771 uint64_t scale;
772 GElf_Sym sym;
869 return (DCMD_ERR);
870 }
871
872 if (mdb_readstr(name, sizeof (name), nptr) == -1) {
873 mdb_warn("failed to read feature %d", ii);
874 mdb_free(fset, sz);
875 return (DCMD_ERR);
876 }
877 mdb_printf("%s\n", name);
878 }
879
880 mdb_free(fset, sz);
881 return (DCMD_OK);
882 }
883
884 #ifdef _KMDB
885 /* ARGSUSED */
886 static int
887 crregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
888 {
889 ulong_t cr0, cr4;
890 static const mdb_bitmask_t cr0_flag_bits[] = {
891 { "PE", CR0_PE, CR0_PE },
892 { "MP", CR0_MP, CR0_MP },
893 { "EM", CR0_EM, CR0_EM },
894 { "TS", CR0_TS, CR0_TS },
895 { "ET", CR0_ET, CR0_ET },
896 { "NE", CR0_NE, CR0_NE },
897 { "WP", CR0_WP, CR0_WP },
898 { "AM", CR0_AM, CR0_AM },
899 { "NW", CR0_NW, CR0_NW },
900 { "CD", CR0_CD, CR0_CD },
901 { "PG", CR0_PG, CR0_PG },
902 { NULL, 0, 0 }
903 };
904
905 static const mdb_bitmask_t cr4_flag_bits[] = {
906 { "VME", CR4_VME, CR4_VME },
907 { "PVI", CR4_PVI, CR4_PVI },
908 { "TSD", CR4_TSD, CR4_TSD },
909 { "DE", CR4_DE, CR4_DE },
910 { "PSE", CR4_PSE, CR4_PSE },
911 { "PAE", CR4_PAE, CR4_PAE },
912 { "MCE", CR4_MCE, CR4_MCE },
913 { "PGE", CR4_PGE, CR4_PGE },
914 { "PCE", CR4_PCE, CR4_PCE },
915 { "OSFXSR", CR4_OSFXSR, CR4_OSFXSR },
916 { "OSXMMEXCPT", CR4_OSXMMEXCPT, CR4_OSXMMEXCPT },
917 { "VMXE", CR4_VMXE, CR4_VMXE },
918 { "SMXE", CR4_SMXE, CR4_SMXE },
919 { "OSXSAVE", CR4_OSXSAVE, CR4_OSXSAVE },
920 { "SMEP", CR4_SMEP, CR4_SMEP },
921 { "SMAP", CR4_SMAP, CR4_SMAP },
922 { NULL, 0, 0 }
923 };
924
925 cr0 = kmdb_unix_getcr0();
926 cr4 = kmdb_unix_getcr4();
927 mdb_printf("%%cr0 = 0x%08x <%b>\n", cr0, cr0, cr0_flag_bits);
928 mdb_printf("%%cr4 = 0x%08x <%b>\n", cr4, cr4, cr4_flag_bits);
929 return (DCMD_OK);
930 }
931 #endif
932
933 static const mdb_dcmd_t dcmds[] = {
934 { "gate_desc", ":", "dump a gate descriptor", gate_desc },
935 { "idt", ":[-v]", "dump an IDT", idt },
936 { "ttrace", "[-x]", "dump trap trace buffers", ttrace },
937 { "vatopfn", ":[-a as]", "translate address to physical page",
938 va2pfn_dcmd },
939 { "report_maps", ":[-m]",
940 "Given PFN, report mappings / page table usage",
941 report_maps_dcmd, report_maps_help },
942 { "htables", "", "Given hat_t *, lists all its htable_t * values",
943 htables_dcmd, htables_help },
944 { "ptable", ":[-m]", "Given PFN, dump contents of a page table",
945 ptable_dcmd, ptable_help },
946 { "pte", ":[-p XXXXX] [-l N]", "print human readable page table entry",
947 pte_dcmd },
948 { "pfntomfn", ":", "convert physical page to hypervisor machine page",
949 pfntomfn_dcmd },
950 { "mfntopfn", ":", "convert hypervisor machine page to physical page",
951 mfntopfn_dcmd },
952 { "memseg_list", ":", "show memseg list", memseg_list },
953 { "scalehrtime", ":",
954 "scale an unscaled high-res time", scalehrtime_cmd },
955 { "x86_featureset", NULL, "dump the x86_featureset vector",
956 x86_featureset_cmd },
957 #ifdef _KMDB
958 { "crregs", NULL, "dump control registers", crregs_dcmd },
959 #endif
960 { NULL }
961 };
962
963 static const mdb_walker_t walkers[] = {
964 { "ttrace", "walks trap trace buffers in reverse chronological order",
965 ttrace_walk_init, ttrace_walk_step, ttrace_walk_fini },
966 { "mutex_owner", "walks the owner of a mutex",
|
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 (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2018 Joyent, Inc.
24 */
25
26 #include <mdb/mdb_modapi.h>
27 #include <mdb/mdb_ctf.h>
28 #include <sys/cpuvar.h>
29 #include <sys/systm.h>
30 #include <sys/traptrace.h>
31 #include <sys/x_call.h>
32 #include <sys/xc_levels.h>
33 #include <sys/avintr.h>
34 #include <sys/systm.h>
35 #include <sys/trap.h>
36 #include <sys/mutex.h>
37 #include <sys/mutex_impl.h>
38 #include "i86mmu.h"
39 #include "unix_sup.h"
40 #include <sys/apix.h>
41 #include <sys/x86_archext.h>
42 #include <sys/bitmap.h>
43 #include <sys/controlregs.h>
392 }
393
394 static struct {
395 uchar_t t_marker;
396 char *t_name;
397 int (*t_hdlr)(trap_trace_rec_t *);
398 } ttrace_hdlr[] = {
399 { TT_SYSCALL, "sysc", ttrace_syscall },
400 { TT_SYSENTER, "syse", ttrace_syscall },
401 { TT_SYSC, "asys", ttrace_syscall },
402 { TT_SYSC64, "sc64", ttrace_syscall },
403 { TT_INTERRUPT, "intr", ttrace_interrupt },
404 { TT_TRAP, "trap", ttrace_trap },
405 { TT_EVENT, "evnt", ttrace_trap },
406 { 0, NULL, NULL }
407 };
408
409 typedef struct ttrace_dcmd {
410 processorid_t ttd_cpu;
411 uint_t ttd_extended;
412 uintptr_t ttd_kthread;
413 trap_trace_ctl_t ttd_ttc[NCPU];
414 } ttrace_dcmd_t;
415
416 #if defined(__amd64)
417
418 #define DUMP(reg) #reg, regs->r_##reg
419 #define THREEREGS " %3s: %16lx %3s: %16lx %3s: %16lx\n"
420
421 static void
422 ttrace_dumpregs(trap_trace_rec_t *rec)
423 {
424 struct regs *regs = &rec->ttr_regs;
425
426 mdb_printf(THREEREGS, DUMP(rdi), DUMP(rsi), DUMP(rdx));
427 mdb_printf(THREEREGS, DUMP(rcx), DUMP(r8), DUMP(r9));
428 mdb_printf(THREEREGS, DUMP(rax), DUMP(rbx), DUMP(rbp));
429 mdb_printf(THREEREGS, DUMP(r10), DUMP(r11), DUMP(r12));
430 mdb_printf(THREEREGS, DUMP(r13), DUMP(r14), DUMP(r15));
431 mdb_printf(THREEREGS, DUMP(ds), DUMP(es), DUMP(fs));
432 mdb_printf(THREEREGS, DUMP(gs), "trp", regs->r_trapno, DUMP(err));
433 mdb_printf(THREEREGS, DUMP(rip), DUMP(cs), DUMP(rfl));
434 mdb_printf(THREEREGS, DUMP(rsp), DUMP(ss), "cr2", rec->ttr_cr2);
435 mdb_printf(" %3s: %16lx %3s: %16lx\n",
436 "fsb", regs->__r_fsbase,
437 "gsb", regs->__r_gsbase);
438 mdb_printf("\n");
439 }
440
441 #else
442
443 #define DUMP(reg) #reg, regs->r_##reg
444 #define FOURREGS " %3s: %08x %3s: %08x %3s: %08x %3s: %08x\n"
445
446 static void
447 ttrace_dumpregs(trap_trace_rec_t *rec)
448 {
449 struct regs *regs = &rec->ttr_regs;
450
451 mdb_printf(FOURREGS, DUMP(gs), DUMP(fs), DUMP(es), DUMP(ds));
452 mdb_printf(FOURREGS, DUMP(edi), DUMP(esi), DUMP(ebp), DUMP(esp));
453 mdb_printf(FOURREGS, DUMP(ebx), DUMP(edx), DUMP(ecx), DUMP(eax));
454 mdb_printf(FOURREGS, "trp", regs->r_trapno, DUMP(err),
455 DUMP(pc), DUMP(cs));
456 mdb_printf(FOURREGS, DUMP(efl), "usp", regs->r_uesp, DUMP(ss),
457 "cr2", rec->ttr_cr2);
465 {
466 struct regs *regs = &rec->ttr_regs;
467 processorid_t cpu = -1, i;
468
469 for (i = 0; i < NCPU; i++) {
470 if (addr >= dcmd->ttd_ttc[i].ttc_first &&
471 addr < dcmd->ttd_ttc[i].ttc_limit) {
472 cpu = i;
473 break;
474 }
475 }
476
477 if (cpu == -1) {
478 mdb_warn("couldn't find %p in any trap trace ctl\n", addr);
479 return (WALK_ERR);
480 }
481
482 if (dcmd->ttd_cpu != -1 && cpu != dcmd->ttd_cpu)
483 return (WALK_NEXT);
484
485 if (dcmd->ttd_kthread != 0 &&
486 dcmd->ttd_kthread != rec->ttr_curthread)
487 return (WALK_NEXT);
488
489 mdb_printf("%3d %15llx ", cpu, rec->ttr_stamp);
490
491 for (i = 0; ttrace_hdlr[i].t_hdlr != NULL; i++) {
492 if (rec->ttr_marker != ttrace_hdlr[i].t_marker)
493 continue;
494 mdb_printf("%4s ", ttrace_hdlr[i].t_name);
495 if (ttrace_hdlr[i].t_hdlr(rec) == -1)
496 return (WALK_ERR);
497 }
498
499 mdb_printf(" %a\n", regs->r_pc);
500
501 if (dcmd->ttd_extended == FALSE)
502 return (WALK_NEXT);
503
504 if (rec->ttr_marker == TT_INTERRUPT)
505 ttrace_intr_detail(rec);
506 else
507 ttrace_dumpregs(rec);
508
528 {
529 ttrace_dcmd_t dcmd;
530 trap_trace_ctl_t *ttc = dcmd.ttd_ttc;
531 trap_trace_rec_t rec;
532 size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU;
533
534 if (!ttrace_ttr_size_check())
535 return (WALK_ERR);
536
537 bzero(&dcmd, sizeof (dcmd));
538 dcmd.ttd_cpu = -1;
539 dcmd.ttd_extended = FALSE;
540
541 if (mdb_readsym(ttc, ttc_size, "trap_trace_ctl") == -1) {
542 mdb_warn("symbol 'trap_trace_ctl' not found; "
543 "non-TRAPTRACE kernel?\n");
544 return (DCMD_ERR);
545 }
546
547 if (mdb_getopts(argc, argv,
548 'x', MDB_OPT_SETBITS, TRUE, &dcmd.ttd_extended,
549 't', MDB_OPT_UINTPTR, &dcmd.ttd_kthread, NULL) != argc)
550 return (DCMD_USAGE);
551
552 if (DCMD_HDRSPEC(flags)) {
553 mdb_printf("%3s %15s %4s %2s %-*s%s\n", "CPU",
554 "TIMESTAMP", "TYPE", "Vec", TT_HDLR_WIDTH, "HANDLER",
555 " EIP");
556 }
557
558 if (flags & DCMD_ADDRSPEC) {
559 if (addr >= NCPU) {
560 if (mdb_vread(&rec, sizeof (rec), addr) == -1) {
561 mdb_warn("couldn't read trap trace record "
562 "at %p", addr);
563 return (DCMD_ERR);
564 }
565
566 if (ttrace_walk(addr, &rec, &dcmd) == WALK_ERR)
567 return (DCMD_ERR);
568
569 return (DCMD_OK);
739 "that correspond to that address space\n");
740 }
741
742 static void
743 report_maps_help(void)
744 {
745 mdb_printf(
746 "Given a PFN, report HAT structures that map the page, or use\n"
747 "the page as a pagetable.\n"
748 "\n"
749 "-m Interpret the PFN as an MFN (machine frame number)\n");
750 }
751
752 static void
753 ptable_help(void)
754 {
755 mdb_printf(
756 "Given a PFN holding a page table, print its contents, and\n"
757 "the address of the corresponding htable structure.\n"
758 "\n"
759 "-m Interpret the PFN as an MFN (machine frame number)\n"
760 "-l force page table level (3 is top)\n");
761 }
762
763 static void
764 ptmap_help(void)
765 {
766 mdb_printf(
767 "Report all mappings represented by the page table hierarchy\n"
768 "rooted at the given cr3 value / physical address.\n"
769 "\n"
770 "-w run ::whatis on mapping start addresses\n");
771 }
772
773 /*
774 * NSEC_SHIFT is replicated here (it is not defined in a header file),
775 * but for amusement, the reader is directed to the comment that explains
776 * the rationale for this particular value on x86. Spoiler: the value is
777 * selected to accommodate 60 MHz Pentiums! (And a confession: if the voice
778 * in that comment sounds too familiar, it's because your author also wrote
779 * that code -- some fifteen years prior to this writing in 2011...)
780 */
781 #define NSEC_SHIFT 5
782
783 /*ARGSUSED*/
784 static int
785 scalehrtime_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
786 {
787 uint32_t nsec_scale;
788 hrtime_t tsc = addr, hrt;
789 unsigned int *tscp = (unsigned int *)&tsc;
790 uintptr_t scalehrtimef;
791 uint64_t scale;
792 GElf_Sym sym;
889 return (DCMD_ERR);
890 }
891
892 if (mdb_readstr(name, sizeof (name), nptr) == -1) {
893 mdb_warn("failed to read feature %d", ii);
894 mdb_free(fset, sz);
895 return (DCMD_ERR);
896 }
897 mdb_printf("%s\n", name);
898 }
899
900 mdb_free(fset, sz);
901 return (DCMD_OK);
902 }
903
904 #ifdef _KMDB
905 /* ARGSUSED */
906 static int
907 crregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
908 {
909 ulong_t cr0, cr2, cr3, cr4;
910 static const mdb_bitmask_t cr0_flag_bits[] = {
911 { "PE", CR0_PE, CR0_PE },
912 { "MP", CR0_MP, CR0_MP },
913 { "EM", CR0_EM, CR0_EM },
914 { "TS", CR0_TS, CR0_TS },
915 { "ET", CR0_ET, CR0_ET },
916 { "NE", CR0_NE, CR0_NE },
917 { "WP", CR0_WP, CR0_WP },
918 { "AM", CR0_AM, CR0_AM },
919 { "NW", CR0_NW, CR0_NW },
920 { "CD", CR0_CD, CR0_CD },
921 { "PG", CR0_PG, CR0_PG },
922 { NULL, 0, 0 }
923 };
924
925 static const mdb_bitmask_t cr3_flag_bits[] = {
926 { "PCD", CR3_PCD, CR3_PCD },
927 { "PWT", CR3_PWT, CR3_PWT },
928 { NULL, 0, 0, }
929 };
930
931 static const mdb_bitmask_t cr4_flag_bits[] = {
932 { "VME", CR4_VME, CR4_VME },
933 { "PVI", CR4_PVI, CR4_PVI },
934 { "TSD", CR4_TSD, CR4_TSD },
935 { "DE", CR4_DE, CR4_DE },
936 { "PSE", CR4_PSE, CR4_PSE },
937 { "PAE", CR4_PAE, CR4_PAE },
938 { "MCE", CR4_MCE, CR4_MCE },
939 { "PGE", CR4_PGE, CR4_PGE },
940 { "PCE", CR4_PCE, CR4_PCE },
941 { "OSFXSR", CR4_OSFXSR, CR4_OSFXSR },
942 { "OSXMMEXCPT", CR4_OSXMMEXCPT, CR4_OSXMMEXCPT },
943 { "VMXE", CR4_VMXE, CR4_VMXE },
944 { "SMXE", CR4_SMXE, CR4_SMXE },
945 { "PCIDE", CR4_PCIDE, CR4_PCIDE },
946 { "OSXSAVE", CR4_OSXSAVE, CR4_OSXSAVE },
947 { "SMEP", CR4_SMEP, CR4_SMEP },
948 { "SMAP", CR4_SMAP, CR4_SMAP },
949 { NULL, 0, 0 }
950 };
951
952 cr0 = kmdb_unix_getcr0();
953 cr2 = kmdb_unix_getcr2();
954 cr3 = kmdb_unix_getcr3();
955 cr4 = kmdb_unix_getcr4();
956 mdb_printf("%%cr0 = 0x%lx <%b>\n", cr0, cr0, cr0_flag_bits);
957 mdb_printf("%%cr2 = 0x%lx <%a>\n", cr2, cr2);
958
959 if ((cr4 & CR4_PCIDE)) {
960 mdb_printf("%%cr3 = 0x%lx <pfn:0x%lx pcid:%lu>\n", cr3,
961 cr3 >> MMU_PAGESHIFT, cr3 & MMU_PAGEOFFSET);
962 } else {
963 mdb_printf("%%cr3 = 0x%lx <pfn:0x%lx flags:%b>\n", cr3,
964 cr3 >> MMU_PAGESHIFT, cr3, cr3_flag_bits);
965 }
966
967 mdb_printf("%%cr4 = 0x%lx <%b>\n", cr4, cr4, cr4_flag_bits);
968
969 return (DCMD_OK);
970 }
971 #endif
972
973 static const mdb_dcmd_t dcmds[] = {
974 { "gate_desc", ":", "dump a gate descriptor", gate_desc },
975 { "idt", ":[-v]", "dump an IDT", idt },
976 { "ttrace", "[-x] [-t kthread]", "dump trap trace buffers", ttrace },
977 { "vatopfn", ":[-a as]", "translate address to physical page",
978 va2pfn_dcmd },
979 { "report_maps", ":[-m]",
980 "Given PFN, report mappings / page table usage",
981 report_maps_dcmd, report_maps_help },
982 { "htables", "", "Given hat_t *, lists all its htable_t * values",
983 htables_dcmd, htables_help },
984 { "ptable", ":[-lm]", "Given PFN, dump contents of a page table",
985 ptable_dcmd, ptable_help },
986 { "ptmap", ":", "Given a cr3 value, dump all mappings",
987 ptmap_dcmd, ptmap_help },
988 { "pte", ":[-l N]", "print human readable page table entry",
989 pte_dcmd },
990 { "pfntomfn", ":", "convert physical page to hypervisor machine page",
991 pfntomfn_dcmd },
992 { "mfntopfn", ":", "convert hypervisor machine page to physical page",
993 mfntopfn_dcmd },
994 { "memseg_list", ":", "show memseg list", memseg_list },
995 { "scalehrtime", ":",
996 "scale an unscaled high-res time", scalehrtime_cmd },
997 { "x86_featureset", NULL, "dump the x86_featureset vector",
998 x86_featureset_cmd },
999 #ifdef _KMDB
1000 { "crregs", NULL, "dump control registers", crregs_dcmd },
1001 #endif
1002 { NULL }
1003 };
1004
1005 static const mdb_walker_t walkers[] = {
1006 { "ttrace", "walks trap trace buffers in reverse chronological order",
1007 ttrace_walk_init, ttrace_walk_step, ttrace_walk_fini },
1008 { "mutex_owner", "walks the owner of a mutex",
|