1 // SPDX-License-Identifier: GPL-2.0 2 #include "debug.h" 3 #include "env.h" 4 #include "evsel.h" 5 #include "kvm-stat.h" 6 #include <dwarf-regs.h> 7 #include <subcmd/parse-options.h> 8 9 bool kvm_exit_event(struct evsel *evsel) 10 { 11 uint16_t e_machine = evsel__e_machine(evsel, /*e_flags=*/NULL); 12 13 return evsel__name_is(evsel, kvm_exit_trace(e_machine)); 14 } 15 16 void exit_event_get_key(struct perf_sample *sample, 17 struct event_key *key) 18 { 19 uint16_t e_machine = evsel__e_machine(sample->evsel, /*e_flags=*/NULL); 20 21 key->info = 0; 22 key->key = perf_sample__intval(sample, kvm_exit_reason(e_machine)); 23 } 24 25 26 bool exit_event_begin(struct perf_sample *sample, struct event_key *key) 27 { 28 if (kvm_exit_event(sample->evsel)) { 29 exit_event_get_key(sample, key); 30 return true; 31 } 32 33 return false; 34 } 35 36 bool kvm_entry_event(struct evsel *evsel) 37 { 38 uint16_t e_machine = evsel__e_machine(evsel, /*e_flags=*/NULL); 39 40 return evsel__name_is(evsel, kvm_entry_trace(e_machine)); 41 } 42 43 bool exit_event_end(struct perf_sample *sample, 44 struct event_key *key __maybe_unused) 45 { 46 return kvm_entry_event(sample->evsel); 47 } 48 49 static const char *get_exit_reason(struct perf_kvm_stat *kvm, 50 struct exit_reasons_table *tbl, 51 u64 exit_code) 52 { 53 while (tbl->reason != NULL) { 54 if (tbl->exit_code == exit_code) 55 return tbl->reason; 56 tbl++; 57 } 58 59 pr_err("unknown kvm exit code:%lld on %s\n", 60 (unsigned long long)exit_code, kvm->exit_reasons_isa); 61 return "UNKNOWN"; 62 } 63 64 void exit_event_decode_key(struct perf_kvm_stat *kvm, 65 struct event_key *key, 66 char *decode) 67 { 68 const char *exit_reason = get_exit_reason(kvm, key->exit_reasons, 69 key->key); 70 71 scnprintf(decode, KVM_EVENT_NAME_LEN, "%s", exit_reason); 72 } 73 74 int setup_kvm_events_tp(struct perf_kvm_stat *kvm, uint16_t e_machine) 75 { 76 switch (e_machine) { 77 case EM_PPC: 78 case EM_PPC64: 79 return __setup_kvm_events_tp_powerpc(kvm); 80 default: 81 return 0; 82 } 83 } 84 85 int cpu_isa_init(struct perf_kvm_stat *kvm, uint16_t e_machine, const char *cpuid) 86 { 87 switch (e_machine) { 88 case EM_AARCH64: 89 return __cpu_isa_init_arm64(kvm); 90 case EM_LOONGARCH: 91 return __cpu_isa_init_loongarch(kvm); 92 case EM_PPC: 93 case EM_PPC64: 94 return __cpu_isa_init_powerpc(kvm); 95 case EM_RISCV: 96 return __cpu_isa_init_riscv(kvm); 97 case EM_S390: 98 return __cpu_isa_init_s390(kvm, cpuid); 99 case EM_X86_64: 100 case EM_386: 101 return __cpu_isa_init_x86(kvm, cpuid); 102 default: 103 pr_err("Unsupported kvm-stat host %d\n", e_machine); 104 return -1; 105 } 106 } 107 108 const char *vcpu_id_str(uint16_t e_machine) 109 { 110 switch (e_machine) { 111 case EM_AARCH64: 112 case EM_RISCV: 113 case EM_S390: 114 return "id"; 115 case EM_LOONGARCH: 116 case EM_PPC: 117 case EM_PPC64: 118 case EM_X86_64: 119 case EM_386: 120 return "vcpu_id"; 121 default: 122 pr_err("Unsupported kvm-stat host %d\n", e_machine); 123 return NULL; 124 } 125 } 126 127 const char *kvm_exit_reason(uint16_t e_machine) 128 { 129 switch (e_machine) { 130 case EM_AARCH64: 131 return "ret"; 132 case EM_LOONGARCH: 133 return "reason"; 134 case EM_PPC: 135 case EM_PPC64: 136 return "trap"; 137 case EM_RISCV: 138 return "scause"; 139 case EM_S390: 140 return "icptcode"; 141 case EM_X86_64: 142 case EM_386: 143 return "exit_reason"; 144 default: 145 pr_err("Unsupported kvm-stat host %d\n", e_machine); 146 return NULL; 147 } 148 } 149 150 const char *kvm_entry_trace(uint16_t e_machine) 151 { 152 switch (e_machine) { 153 case EM_AARCH64: 154 case EM_RISCV: 155 case EM_X86_64: 156 case EM_386: 157 return "kvm:kvm_entry"; 158 case EM_LOONGARCH: 159 return "kvm:kvm_enter"; 160 case EM_PPC: 161 case EM_PPC64: 162 return "kvm_hv:kvm_guest_enter"; 163 case EM_S390: 164 return "kvm:kvm_s390_sie_enter"; 165 default: 166 pr_err("Unsupported kvm-stat host %d\n", e_machine); 167 return NULL; 168 } 169 } 170 171 const char *kvm_exit_trace(uint16_t e_machine) 172 { 173 switch (e_machine) { 174 case EM_AARCH64: 175 case EM_LOONGARCH: 176 case EM_RISCV: 177 case EM_X86_64: 178 case EM_386: 179 return "kvm:kvm_exit"; 180 case EM_PPC: 181 case EM_PPC64: 182 return "kvm_hv:kvm_guest_exit"; 183 case EM_S390: 184 return "kvm:kvm_s390_sie_exit"; 185 default: 186 pr_err("Unsupported kvm-stat host %d\n", e_machine); 187 return NULL; 188 } 189 } 190 191 const char * const *kvm_events_tp(uint16_t e_machine) 192 { 193 switch (e_machine) { 194 case EM_AARCH64: 195 return __kvm_events_tp_arm64(); 196 case EM_LOONGARCH: 197 return __kvm_events_tp_loongarch(); 198 case EM_PPC: 199 case EM_PPC64: 200 return __kvm_events_tp_powerpc(); 201 case EM_RISCV: 202 return __kvm_events_tp_riscv(); 203 case EM_S390: 204 return __kvm_events_tp_s390(); 205 case EM_X86_64: 206 case EM_386: 207 return __kvm_events_tp_x86(); 208 default: 209 pr_err("Unsupported kvm-stat host %d\n", e_machine); 210 return NULL; 211 } 212 } 213 214 const struct kvm_reg_events_ops *kvm_reg_events_ops(uint16_t e_machine) 215 { 216 switch (e_machine) { 217 case EM_AARCH64: 218 return __kvm_reg_events_ops_arm64(); 219 case EM_LOONGARCH: 220 return __kvm_reg_events_ops_loongarch(); 221 case EM_PPC: 222 case EM_PPC64: 223 return __kvm_reg_events_ops_powerpc(); 224 case EM_RISCV: 225 return __kvm_reg_events_ops_riscv(); 226 case EM_S390: 227 return __kvm_reg_events_ops_s390(); 228 case EM_X86_64: 229 case EM_386: 230 return __kvm_reg_events_ops_x86(); 231 default: 232 pr_err("Unsupported kvm-stat host %d\n", e_machine); 233 return NULL; 234 } 235 } 236 237 const char * const *kvm_skip_events(uint16_t e_machine) 238 { 239 switch (e_machine) { 240 case EM_AARCH64: 241 return __kvm_skip_events_arm64(); 242 case EM_LOONGARCH: 243 return __kvm_skip_events_loongarch(); 244 case EM_PPC: 245 case EM_PPC64: 246 return __kvm_skip_events_powerpc(); 247 case EM_RISCV: 248 return __kvm_skip_events_riscv(); 249 case EM_S390: 250 return __kvm_skip_events_s390(); 251 case EM_X86_64: 252 case EM_386: 253 return __kvm_skip_events_x86(); 254 default: 255 pr_err("Unsupported kvm-stat host %d\n", e_machine); 256 return NULL; 257 } 258 } 259 260 int kvm_add_default_arch_event(uint16_t e_machine, int *argc, const char **argv) 261 { 262 switch (e_machine) { 263 case EM_PPC: 264 case EM_PPC64: 265 return __kvm_add_default_arch_event_powerpc(argc, argv); 266 case EM_X86_64: 267 case EM_386: 268 return __kvm_add_default_arch_event_x86(argc, argv); 269 default: 270 return 0; 271 } 272 } 273 274 bool kvm_need_default_arch_event(uint16_t e_machine, int argc, const char **argv) 275 { 276 const char **tmp_argv; 277 bool event = false; 278 int i; 279 280 const struct option event_options[] = { 281 OPT_BOOLEAN('e', "event", &event, NULL), 282 OPT_BOOLEAN(0, "pfm-events", &event, NULL), 283 OPT_END() 284 }; 285 286 switch (e_machine) { 287 case EM_PPC: 288 case EM_PPC64: 289 break; 290 case EM_X86_64: 291 case EM_386: 292 if (!x86__is_intel_cpu()) 293 return false; 294 break; 295 default: 296 return false; 297 } 298 299 /* parse_options() may change the argv, let's make a copy */ 300 tmp_argv = calloc(argc + 1, sizeof(char *)); 301 if (!tmp_argv) 302 return false; 303 304 for (i = 0; i < argc; i++) 305 tmp_argv[i] = argv[i]; 306 307 parse_options(argc, tmp_argv, event_options, NULL, PARSE_OPT_KEEP_UNKNOWN); 308 free(tmp_argv); 309 310 return !event; 311 } 312