10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*3446Smrj * Common Development and Distribution License (the "License").
6*3446Smrj * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*3446Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate * Debugging functionality unique to 64-bit AMD processors.
300Sstevel@tonic-gate */
310Sstevel@tonic-gate
320Sstevel@tonic-gate #include <kmdb/kvm_cpu_impl.h>
330Sstevel@tonic-gate #include <kmdb/kmdb_dpi.h>
340Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h>
350Sstevel@tonic-gate #include <kmdb/kvm.h>
360Sstevel@tonic-gate #include <mdb/mdb_err.h>
370Sstevel@tonic-gate #include <mdb/mdb.h>
380Sstevel@tonic-gate
390Sstevel@tonic-gate #include <sys/x86_archext.h>
400Sstevel@tonic-gate
410Sstevel@tonic-gate typedef struct kmt_cpu_amd {
420Sstevel@tonic-gate uint64_t amd_debugctl; /* value for debugctl MSR */
43*3446Smrj const kdi_msr_t *amd_msrs; /* MSR r/w list */
440Sstevel@tonic-gate uint_t amd_family; /* CPUID family */
450Sstevel@tonic-gate uint_t amd_model; /* CPUID model */
460Sstevel@tonic-gate } kmt_cpu_amd_t;
470Sstevel@tonic-gate
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate * The debugctl value in this struct needs to outlive the destruction of the
500Sstevel@tonic-gate * kmt_cpu_t. It needs to be around for the final exit from the debugger so
510Sstevel@tonic-gate * we can do the final write of the debugctl MSR.
520Sstevel@tonic-gate */
530Sstevel@tonic-gate static kmt_cpu_amd_t kmt_cpu_amd;
540Sstevel@tonic-gate
550Sstevel@tonic-gate static void
kmt_amd_branch(uint_t cpuid,const char * label,uint_t msr)560Sstevel@tonic-gate kmt_amd_branch(uint_t cpuid, const char *label, uint_t msr)
570Sstevel@tonic-gate {
580Sstevel@tonic-gate char buf[BUFSIZ];
590Sstevel@tonic-gate uintptr_t addr;
600Sstevel@tonic-gate
610Sstevel@tonic-gate addr = (uintptr_t)kmdb_dpi_msr_get_by_cpu(cpuid, msr);
620Sstevel@tonic-gate
630Sstevel@tonic-gate mdb_printf("%s: %p %A\n", label, addr, addr);
640Sstevel@tonic-gate
650Sstevel@tonic-gate if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target,
660Sstevel@tonic-gate MDB_TGT_AS_VIRT, buf, sizeof (buf), addr) != addr)
670Sstevel@tonic-gate mdb_printf("%*s %s\n", strlen(label), "", buf);
680Sstevel@tonic-gate }
690Sstevel@tonic-gate
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate * MSRs for AMD processors with simple branch tracing facilities. We'll use
720Sstevel@tonic-gate * this array if we can access listed LBR/LEX MSRs.
730Sstevel@tonic-gate */
74*3446Smrj static const kdi_msr_t kmt_amd_msrs[] = {
75*3446Smrj { MSR_DEBUGCTL, KDI_MSR_CLEARENTRY },
76*3446Smrj { MSR_DEBUGCTL, KDI_MSR_WRITEDELAY, &kmt_cpu_amd.amd_debugctl },
77*3446Smrj { MSR_LBR_TO, KDI_MSR_READ },
78*3446Smrj { MSR_LBR_FROM, KDI_MSR_READ },
79*3446Smrj { MSR_LEX_TO, KDI_MSR_READ },
80*3446Smrj { MSR_LEX_FROM, KDI_MSR_READ },
810Sstevel@tonic-gate { NULL }
820Sstevel@tonic-gate };
830Sstevel@tonic-gate
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate * Fallback MSR list for use if we can't read the LBR/LEX MSRs.
860Sstevel@tonic-gate */
87*3446Smrj static const kdi_msr_t kmt_amdunk_msrs[] = {
88*3446Smrj { MSR_DEBUGCTL, KDI_MSR_CLEARENTRY },
89*3446Smrj { MSR_DEBUGCTL, KDI_MSR_WRITEDELAY, &kmt_cpu_amd.amd_debugctl },
900Sstevel@tonic-gate { NULL }
910Sstevel@tonic-gate };
920Sstevel@tonic-gate
930Sstevel@tonic-gate /*ARGSUSED*/
940Sstevel@tonic-gate static void
kmt_amd_destroy(kmt_cpu_t * cpu)950Sstevel@tonic-gate kmt_amd_destroy(kmt_cpu_t *cpu)
960Sstevel@tonic-gate {
970Sstevel@tonic-gate /* Leave LBR on */
980Sstevel@tonic-gate
990Sstevel@tonic-gate mdb_free(cpu, sizeof (kmt_cpu_t));
1000Sstevel@tonic-gate }
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate /*ARGSUSED*/
1030Sstevel@tonic-gate static const char *
kmt_amd_name(kmt_cpu_t * cpu)1040Sstevel@tonic-gate kmt_amd_name(kmt_cpu_t *cpu)
1050Sstevel@tonic-gate {
1060Sstevel@tonic-gate return ("AMD");
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate /*ARGSUSED*/
1100Sstevel@tonic-gate static void
kmt_amd_btf_clear(mdb_tgt_t * t,int id,void * arg)1110Sstevel@tonic-gate kmt_amd_btf_clear(mdb_tgt_t *t, int id, void *arg)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate kmt_cpu_amd_t *amd = arg;
1140Sstevel@tonic-gate kreg_t efl;
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate amd->amd_debugctl &= ~DEBUGCTL_BTF;
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate (void) kmdb_dpi_get_register("rflags", &efl);
1190Sstevel@tonic-gate efl &= ~(1 << KREG_EFLAGS_TF_SHIFT);
1200Sstevel@tonic-gate (void) kmdb_dpi_set_register("rflags", efl);
1210Sstevel@tonic-gate }
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate /* Enable branch stepping, to be disabled on the next debugger entry */
1240Sstevel@tonic-gate static int
kmt_amd_step_branch(kmt_cpu_t * cpu,mdb_tgt_t * t)1250Sstevel@tonic-gate kmt_amd_step_branch(kmt_cpu_t *cpu, mdb_tgt_t *t)
1260Sstevel@tonic-gate {
1270Sstevel@tonic-gate kmt_cpu_amd_t *amd = cpu->kmt_cpu_data;
1280Sstevel@tonic-gate kreg_t efl;
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate (void) kmdb_dpi_get_register("rflags", &efl);
1310Sstevel@tonic-gate (void) kmdb_dpi_set_register("rflags",
1320Sstevel@tonic-gate (efl | (1 << KREG_EFLAGS_TF_SHIFT)));
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate amd->amd_debugctl |= DEBUGCTL_BTF;
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate return (mdb_tgt_add_fault(t, KMT_TRAP_ALL,
1370Sstevel@tonic-gate MDB_TGT_SPEC_HIDDEN | MDB_TGT_SPEC_TEMPORARY,
1380Sstevel@tonic-gate kmt_amd_btf_clear, amd));
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate static kmt_cpu_ops_t kmt_amd_ops = {
1420Sstevel@tonic-gate kmt_amd_destroy,
1430Sstevel@tonic-gate kmt_amd_name,
1440Sstevel@tonic-gate kmt_amd_step_branch
1450Sstevel@tonic-gate };
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate /*ARGSUSED*/
1480Sstevel@tonic-gate static int
kmt_amd_branches(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1490Sstevel@tonic-gate kmt_amd_branches(uintptr_t addr, uint_t flags, int argc,
1500Sstevel@tonic-gate const mdb_arg_t *argv)
1510Sstevel@tonic-gate {
1520Sstevel@tonic-gate intptr_t cpuid = DPI_MASTER_CPUID;
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate if (kmt_cpu_amd.amd_msrs == kmt_amdunk_msrs) {
1550Sstevel@tonic-gate warn("branch tracing unavailable on unknown AMD CPU "
1560Sstevel@tonic-gate "(id: %x/%x)\n", kmt_cpu_amd.amd_family,
1570Sstevel@tonic-gate kmt_cpu_amd.amd_model);
1580Sstevel@tonic-gate return (DCMD_ERR);
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate if (mdb_getopts(argc, argv,
1620Sstevel@tonic-gate 'c', MDB_OPT_UINTPTR, &cpuid,
1630Sstevel@tonic-gate NULL) != argc)
1640Sstevel@tonic-gate return (DCMD_USAGE);
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate kmt_amd_branch(cpuid, "LastBranchToIP ", MSR_LBR_TO);
1670Sstevel@tonic-gate kmt_amd_branch(cpuid, "LastBranchFromIP ", MSR_LBR_FROM);
1680Sstevel@tonic-gate kmt_amd_branch(cpuid, "LastExceptionToIP ", MSR_LEX_TO);
1690Sstevel@tonic-gate kmt_amd_branch(cpuid, "LastExceptionFromIP", MSR_LEX_FROM);
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate return (0);
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate static const mdb_dcmd_t kmt_amd_dcmds[] = {
1750Sstevel@tonic-gate { "branches", NULL, "describe the recently-taken branches",
1760Sstevel@tonic-gate kmt_amd_branches },
1770Sstevel@tonic-gate { NULL }
1780Sstevel@tonic-gate };
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate kmt_cpu_t *
kmt_cpu_amd_create(mdb_tgt_t * t)1810Sstevel@tonic-gate kmt_cpu_amd_create(mdb_tgt_t *t)
1820Sstevel@tonic-gate {
1830Sstevel@tonic-gate uint_t vendor, family, model;
1840Sstevel@tonic-gate kmt_cpu_t *cpu;
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate if (kmdb_kdi_get_cpuinfo(&vendor, &family, &model) < 0)
1870Sstevel@tonic-gate return (NULL); /* errno is set for us */
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate if (vendor != X86_VENDOR_AMD) {
1900Sstevel@tonic-gate (void) set_errno(ENOTSUP);
1910Sstevel@tonic-gate return (NULL);
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate kmt_cpu_amd.amd_family = family;
1950Sstevel@tonic-gate kmt_cpu_amd.amd_model = model;
1960Sstevel@tonic-gate kmt_cpu_amd.amd_msrs = kmt_amdunk_msrs;
1970Sstevel@tonic-gate kmt_cpu_amd.amd_debugctl = DEBUGCTL_LBR; /* Enable LBR on resume */
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate cpu = mdb_zalloc(sizeof (kmt_cpu_t), UM_SLEEP);
2000Sstevel@tonic-gate cpu->kmt_cpu_ops = &kmt_amd_ops;
2010Sstevel@tonic-gate cpu->kmt_cpu_data = &kmt_cpu_amd;
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate /*
2040Sstevel@tonic-gate * Use the LBR/LEX MSRs if this CPU supports them.
2050Sstevel@tonic-gate */
2060Sstevel@tonic-gate if (kmt_msr_validate(kmt_amd_msrs))
2070Sstevel@tonic-gate kmt_cpu_amd.amd_msrs = kmt_amd_msrs;
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate (void) mdb_tgt_register_dcmds(t, kmt_amd_dcmds, MDB_MOD_FORCE);
2100Sstevel@tonic-gate kmdb_dpi_msr_add(kmt_cpu_amd.amd_msrs);
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate return (cpu);
2130Sstevel@tonic-gate }
214