// SPDX-License-Identifier: GPL-2.0 #include "debug.h" #include "evsel.h" #include "kvm-stat.h" #include bool kvm_exit_event(struct evsel *evsel) { uint16_t e_machine = evsel__e_machine(evsel, /*e_flags=*/NULL); return evsel__name_is(evsel, kvm_exit_trace(e_machine)); } void exit_event_get_key(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { uint16_t e_machine = evsel__e_machine(evsel, /*e_flags=*/NULL); key->info = 0; key->key = evsel__intval(evsel, sample, kvm_exit_reason(e_machine)); } bool exit_event_begin(struct evsel *evsel, struct perf_sample *sample, struct event_key *key) { if (kvm_exit_event(evsel)) { exit_event_get_key(evsel, sample, key); return true; } return false; } bool kvm_entry_event(struct evsel *evsel) { uint16_t e_machine = evsel__e_machine(evsel, /*e_flags=*/NULL); return evsel__name_is(evsel, kvm_entry_trace(e_machine)); } bool exit_event_end(struct evsel *evsel, struct perf_sample *sample __maybe_unused, struct event_key *key __maybe_unused) { return kvm_entry_event(evsel); } static const char *get_exit_reason(struct perf_kvm_stat *kvm, struct exit_reasons_table *tbl, u64 exit_code) { while (tbl->reason != NULL) { if (tbl->exit_code == exit_code) return tbl->reason; tbl++; } pr_err("unknown kvm exit code:%lld on %s\n", (unsigned long long)exit_code, kvm->exit_reasons_isa); return "UNKNOWN"; } void exit_event_decode_key(struct perf_kvm_stat *kvm, struct event_key *key, char *decode) { const char *exit_reason = get_exit_reason(kvm, key->exit_reasons, key->key); scnprintf(decode, KVM_EVENT_NAME_LEN, "%s", exit_reason); } int setup_kvm_events_tp(struct perf_kvm_stat *kvm, uint16_t e_machine) { switch (e_machine) { case EM_PPC: case EM_PPC64: return __setup_kvm_events_tp_powerpc(kvm); default: return 0; } } int cpu_isa_init(struct perf_kvm_stat *kvm, uint16_t e_machine, const char *cpuid) { switch (e_machine) { case EM_AARCH64: return __cpu_isa_init_arm64(kvm); case EM_LOONGARCH: return __cpu_isa_init_loongarch(kvm); case EM_PPC: case EM_PPC64: return __cpu_isa_init_powerpc(kvm); case EM_RISCV: return __cpu_isa_init_riscv(kvm); case EM_S390: return __cpu_isa_init_s390(kvm, cpuid); case EM_X86_64: case EM_386: return __cpu_isa_init_x86(kvm, cpuid); default: pr_err("Unsupported kvm-stat host %d\n", e_machine); return -1; } } const char *vcpu_id_str(uint16_t e_machine) { switch (e_machine) { case EM_AARCH64: case EM_RISCV: case EM_S390: return "id"; case EM_LOONGARCH: case EM_PPC: case EM_PPC64: case EM_X86_64: case EM_386: return "vcpu_id"; default: pr_err("Unsupported kvm-stat host %d\n", e_machine); return NULL; } } const char *kvm_exit_reason(uint16_t e_machine) { switch (e_machine) { case EM_AARCH64: return "ret"; case EM_LOONGARCH: return "reason"; case EM_PPC: case EM_PPC64: return "trap"; case EM_RISCV: return "scause"; case EM_S390: return "icptcode"; case EM_X86_64: case EM_386: return "exit_reason"; default: pr_err("Unsupported kvm-stat host %d\n", e_machine); return NULL; } } const char *kvm_entry_trace(uint16_t e_machine) { switch (e_machine) { case EM_AARCH64: case EM_RISCV: case EM_X86_64: case EM_386: return "kvm:kvm_entry"; case EM_LOONGARCH: return "kvm:kvm_enter"; case EM_PPC: case EM_PPC64: return "kvm_hv:kvm_guest_enter"; case EM_S390: return "kvm:kvm_s390_sie_enter"; default: pr_err("Unsupported kvm-stat host %d\n", e_machine); return NULL; } } const char *kvm_exit_trace(uint16_t e_machine) { switch (e_machine) { case EM_AARCH64: case EM_LOONGARCH: case EM_RISCV: case EM_X86_64: case EM_386: return "kvm:kvm_exit"; case EM_PPC: case EM_PPC64: return "kvm_hv:kvm_guest_exit"; case EM_S390: return "kvm:kvm_s390_sie_exit"; default: pr_err("Unsupported kvm-stat host %d\n", e_machine); return NULL; } } const char * const *kvm_events_tp(uint16_t e_machine) { switch (e_machine) { case EM_AARCH64: return __kvm_events_tp_arm64(); case EM_LOONGARCH: return __kvm_events_tp_loongarch(); case EM_PPC: case EM_PPC64: return __kvm_events_tp_powerpc(); case EM_RISCV: return __kvm_events_tp_riscv(); case EM_S390: return __kvm_events_tp_s390(); case EM_X86_64: case EM_386: return __kvm_events_tp_x86(); default: pr_err("Unsupported kvm-stat host %d\n", e_machine); return NULL; } } const struct kvm_reg_events_ops *kvm_reg_events_ops(uint16_t e_machine) { switch (e_machine) { case EM_AARCH64: return __kvm_reg_events_ops_arm64(); case EM_LOONGARCH: return __kvm_reg_events_ops_loongarch(); case EM_PPC: case EM_PPC64: return __kvm_reg_events_ops_powerpc(); case EM_RISCV: return __kvm_reg_events_ops_riscv(); case EM_S390: return __kvm_reg_events_ops_s390(); case EM_X86_64: case EM_386: return __kvm_reg_events_ops_x86(); default: pr_err("Unsupported kvm-stat host %d\n", e_machine); return NULL; } } const char * const *kvm_skip_events(uint16_t e_machine) { switch (e_machine) { case EM_AARCH64: return __kvm_skip_events_arm64(); case EM_LOONGARCH: return __kvm_skip_events_loongarch(); case EM_PPC: case EM_PPC64: return __kvm_skip_events_powerpc(); case EM_RISCV: return __kvm_skip_events_riscv(); case EM_S390: return __kvm_skip_events_s390(); case EM_X86_64: case EM_386: return __kvm_skip_events_x86(); default: pr_err("Unsupported kvm-stat host %d\n", e_machine); return NULL; } } int kvm_add_default_arch_event(uint16_t e_machine, int *argc, const char **argv) { switch (e_machine) { case EM_PPC: case EM_PPC64: return __kvm_add_default_arch_event_powerpc(argc, argv); case EM_X86_64: case EM_386: return __kvm_add_default_arch_event_x86(argc, argv); default: return 0; } }