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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Debugging functionality unique to 64-bit AMD processors. 30 */ 31 32 #include <kmdb/kvm_cpu_impl.h> 33 #include <kmdb/kmdb_dpi.h> 34 #include <kmdb/kmdb_kdi.h> 35 #include <kmdb/kvm.h> 36 #include <mdb/mdb_err.h> 37 #include <mdb/mdb.h> 38 39 #include <sys/x86_archext.h> 40 41 typedef struct kmt_cpu_amd { 42 uint64_t amd_debugctl; /* value for debugctl MSR */ 43 const kdi_msr_t *amd_msrs; /* MSR r/w list */ 44 uint_t amd_family; /* CPUID family */ 45 uint_t amd_model; /* CPUID model */ 46 } kmt_cpu_amd_t; 47 48 /* 49 * The debugctl value in this struct needs to outlive the destruction of the 50 * kmt_cpu_t. It needs to be around for the final exit from the debugger so 51 * we can do the final write of the debugctl MSR. 52 */ 53 static kmt_cpu_amd_t kmt_cpu_amd; 54 55 static void 56 kmt_amd_branch(uint_t cpuid, const char *label, uint_t msr) 57 { 58 char buf[BUFSIZ]; 59 uintptr_t addr; 60 61 addr = (uintptr_t)kmdb_dpi_msr_get_by_cpu(cpuid, msr); 62 63 mdb_printf("%s: %p %A\n", label, addr, addr); 64 65 if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target, 66 MDB_TGT_AS_VIRT, buf, sizeof (buf), addr) != addr) 67 mdb_printf("%*s %s\n", strlen(label), "", buf); 68 } 69 70 /* 71 * MSRs for AMD processors with simple branch tracing facilities. We'll use 72 * this array if we can access listed LBR/LEX MSRs. 73 */ 74 static const kdi_msr_t kmt_amd_msrs[] = { 75 { MSR_DEBUGCTL, KDI_MSR_CLEARENTRY }, 76 { MSR_DEBUGCTL, KDI_MSR_WRITEDELAY, &kmt_cpu_amd.amd_debugctl }, 77 { MSR_LBR_TO, KDI_MSR_READ }, 78 { MSR_LBR_FROM, KDI_MSR_READ }, 79 { MSR_LEX_TO, KDI_MSR_READ }, 80 { MSR_LEX_FROM, KDI_MSR_READ }, 81 { NULL } 82 }; 83 84 /* 85 * Fallback MSR list for use if we can't read the LBR/LEX MSRs. 86 */ 87 static const kdi_msr_t kmt_amdunk_msrs[] = { 88 { MSR_DEBUGCTL, KDI_MSR_CLEARENTRY }, 89 { MSR_DEBUGCTL, KDI_MSR_WRITEDELAY, &kmt_cpu_amd.amd_debugctl }, 90 { NULL } 91 }; 92 93 /*ARGSUSED*/ 94 static void 95 kmt_amd_destroy(kmt_cpu_t *cpu) 96 { 97 /* Leave LBR on */ 98 99 mdb_free(cpu, sizeof (kmt_cpu_t)); 100 } 101 102 /*ARGSUSED*/ 103 static const char * 104 kmt_amd_name(kmt_cpu_t *cpu) 105 { 106 return ("AMD"); 107 } 108 109 /*ARGSUSED*/ 110 static void 111 kmt_amd_btf_clear(mdb_tgt_t *t, int id, void *arg) 112 { 113 kmt_cpu_amd_t *amd = arg; 114 kreg_t efl; 115 116 amd->amd_debugctl &= ~DEBUGCTL_BTF; 117 118 (void) kmdb_dpi_get_register("rflags", &efl); 119 efl &= ~(1 << KREG_EFLAGS_TF_SHIFT); 120 (void) kmdb_dpi_set_register("rflags", efl); 121 } 122 123 /* Enable branch stepping, to be disabled on the next debugger entry */ 124 static int 125 kmt_amd_step_branch(kmt_cpu_t *cpu, mdb_tgt_t *t) 126 { 127 kmt_cpu_amd_t *amd = cpu->kmt_cpu_data; 128 kreg_t efl; 129 130 (void) kmdb_dpi_get_register("rflags", &efl); 131 (void) kmdb_dpi_set_register("rflags", 132 (efl | (1 << KREG_EFLAGS_TF_SHIFT))); 133 134 amd->amd_debugctl |= DEBUGCTL_BTF; 135 136 return (mdb_tgt_add_fault(t, KMT_TRAP_ALL, 137 MDB_TGT_SPEC_HIDDEN | MDB_TGT_SPEC_TEMPORARY, 138 kmt_amd_btf_clear, amd)); 139 } 140 141 static kmt_cpu_ops_t kmt_amd_ops = { 142 kmt_amd_destroy, 143 kmt_amd_name, 144 kmt_amd_step_branch 145 }; 146 147 /*ARGSUSED*/ 148 static int 149 kmt_amd_branches(uintptr_t addr, uint_t flags, int argc, 150 const mdb_arg_t *argv) 151 { 152 intptr_t cpuid = DPI_MASTER_CPUID; 153 154 if (kmt_cpu_amd.amd_msrs == kmt_amdunk_msrs) { 155 warn("branch tracing unavailable on unknown AMD CPU " 156 "(id: %x/%x)\n", kmt_cpu_amd.amd_family, 157 kmt_cpu_amd.amd_model); 158 return (DCMD_ERR); 159 } 160 161 if (mdb_getopts(argc, argv, 162 'c', MDB_OPT_UINTPTR, &cpuid, 163 NULL) != argc) 164 return (DCMD_USAGE); 165 166 kmt_amd_branch(cpuid, "LastBranchToIP ", MSR_LBR_TO); 167 kmt_amd_branch(cpuid, "LastBranchFromIP ", MSR_LBR_FROM); 168 kmt_amd_branch(cpuid, "LastExceptionToIP ", MSR_LEX_TO); 169 kmt_amd_branch(cpuid, "LastExceptionFromIP", MSR_LEX_FROM); 170 171 return (0); 172 } 173 174 static const mdb_dcmd_t kmt_amd_dcmds[] = { 175 { "branches", NULL, "describe the recently-taken branches", 176 kmt_amd_branches }, 177 { NULL } 178 }; 179 180 kmt_cpu_t * 181 kmt_cpu_amd_create(mdb_tgt_t *t) 182 { 183 uint_t vendor, family, model; 184 kmt_cpu_t *cpu; 185 186 if (kmdb_kdi_get_cpuinfo(&vendor, &family, &model) < 0) 187 return (NULL); /* errno is set for us */ 188 189 if (vendor != X86_VENDOR_AMD) { 190 (void) set_errno(ENOTSUP); 191 return (NULL); 192 } 193 194 kmt_cpu_amd.amd_family = family; 195 kmt_cpu_amd.amd_model = model; 196 kmt_cpu_amd.amd_msrs = kmt_amdunk_msrs; 197 kmt_cpu_amd.amd_debugctl = DEBUGCTL_LBR; /* Enable LBR on resume */ 198 199 cpu = mdb_zalloc(sizeof (kmt_cpu_t), UM_SLEEP); 200 cpu->kmt_cpu_ops = &kmt_amd_ops; 201 cpu->kmt_cpu_data = &kmt_cpu_amd; 202 203 /* 204 * Use the LBR/LEX MSRs if this CPU supports them. 205 */ 206 if (kmt_msr_validate(kmt_amd_msrs)) 207 kmt_cpu_amd.amd_msrs = kmt_amd_msrs; 208 209 (void) mdb_tgt_register_dcmds(t, kmt_amd_dcmds, MDB_MOD_FORCE); 210 kmdb_dpi_msr_add(kmt_cpu_amd.amd_msrs); 211 212 return (cpu); 213 } 214