| 1 | |
| 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, 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, 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, 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 |
|
| 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 | }
|