diff --git a/arch/x86/include/uapi/asm/pvm_trace.h b/arch/x86/include/uapi/asm/pvm_trace.h new file mode 100644 index 00000000000000..f3a45b945f7605 --- /dev/null +++ b/arch/x86/include/uapi/asm/pvm_trace.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef UAPI_KVM_X86_PVM_TRACE_H +#define UAPI_KVM_X86_PVM_TRACE_H + +#include + +#define NMI_VECTOR 0x02 +#define PVM_EXIT_REASONS_FAILED_VMENTRY 1025 + +#define PVM_EXIT_REASONS_SHIFT 16 +#define PVM_EXIT_REASONS_SYSCALL BIT(PVM_EXIT_REASONS_SHIFT) +#define PVM_EXIT_REASONS_HYPERCALL (2UL << PVM_EXIT_REASONS_SHIFT) +#define PVM_EXIT_REASONS_ERETU (3UL << PVM_EXIT_REASONS_SHIFT) +#define PVM_EXIT_REASONS_ERETS (4UL << PVM_EXIT_REASONS_SHIFT) +#define PVM_EXIT_REASONS_INTERRUPT (5UL << PVM_EXIT_REASONS_SHIFT) +#define PVM_EXIT_REASONS_INT80 (6UL << PVM_EXIT_REASONS_SHIFT) + +#define PVM_EXIT_REASONS_HC_IRQ_WIN (PVM_EXIT_REASONS_HYPERCALL + 1) +#define PVM_EXIT_REASONS_HC_IRQ_HALT (PVM_EXIT_REASONS_HYPERCALL + 2) +#define PVM_EXIT_REASONS_HC_LOAD_PGTBL (PVM_EXIT_REASONS_HYPERCALL + 3) +#define PVM_EXIT_REASONS_HC_TLB_FLUSH (PVM_EXIT_REASONS_HYPERCALL + 4) +#define PVM_EXIT_REASONS_HC_TLB_FLUSH_CURRENT (PVM_EXIT_REASONS_HYPERCALL + 5) +#define PVM_EXIT_REASONS_HC_TLB_INVLPG (PVM_EXIT_REASONS_HYPERCALL + 6) +#define PVM_EXIT_REASONS_HC_LOAD_GS (PVM_EXIT_REASONS_HYPERCALL + 7) +#define PVM_EXIT_REASONS_HC_RDMSR (PVM_EXIT_REASONS_HYPERCALL + 8) +#define PVM_EXIT_REASONS_HC_WRMSR (PVM_EXIT_REASONS_HYPERCALL + 9) +#define PVM_EXIT_REASONS_HC_LOAD_TLS (PVM_EXIT_REASONS_HYPERCALL + 10) + +#define PVM_EXIT_REASONS \ + { DE_VECTOR, "DE excp" }, \ + { DB_VECTOR, "DB excp" }, \ + { NMI_VECTOR, "NMI excp" }, \ + { BP_VECTOR, "BP excp" }, \ + { OF_VECTOR, "OF excp" }, \ + { BR_VECTOR, "BR excp" }, \ + { UD_VECTOR, "UD excp" }, \ + { NM_VECTOR, "NM excp" }, \ + { DF_VECTOR, "DF excp" }, \ + { TS_VECTOR, "TS excp" }, \ + { SS_VECTOR, "SS excp" }, \ + { GP_VECTOR, "GP excp" }, \ + { PF_VECTOR, "PF excp" }, \ + { MF_VECTOR, "MF excp" }, \ + { AC_VECTOR, "AC excp" }, \ + { MC_VECTOR, "MC excp" }, \ + { XM_VECTOR, "XM excp" }, \ + { VE_VECTOR, "VE excp" }, \ + { PVM_EXIT_REASONS_SYSCALL, "SYSCALL" }, \ + { PVM_EXIT_REASONS_HYPERCALL, "HYPERCALL" }, \ + { PVM_EXIT_REASONS_ERETU, "ERETU" }, \ + { PVM_EXIT_REASONS_ERETS, "ERETS" }, \ + { PVM_EXIT_REASONS_INTERRUPT, "INTERRUPT" }, \ + { PVM_EXIT_REASONS_INT80, "INT80" }, \ + { PVM_EXIT_REASONS_HC_IRQ_WIN, "HC_IRQ_WIN" }, \ + { PVM_EXIT_REASONS_HC_IRQ_HALT, "HC_IRQ_HALT" }, \ + { PVM_EXIT_REASONS_HC_LOAD_PGTBL, "HC_LOAD_PGTBL" }, \ + { PVM_EXIT_REASONS_HC_TLB_FLUSH, "HC_TLB_FLUSH" }, \ + { PVM_EXIT_REASONS_HC_TLB_FLUSH_CURRENT, "HC_TLB_FLUSH_CURRENT" },\ + { PVM_EXIT_REASONS_HC_TLB_INVLPG, "HC_TLB_INVLPG" }, \ + { PVM_EXIT_REASONS_HC_LOAD_GS, "HC_LOAD_GS" }, \ + { PVM_EXIT_REASONS_HC_RDMSR, "HC_RDMSR" }, \ + { PVM_EXIT_REASONS_HC_WRMSR, "HC_WRMSR" }, \ + { PVM_EXIT_REASONS_HC_LOAD_TLS, "HC_LOAD_TLS" }, \ + { PVM_EXIT_REASONS_FAILED_VMENTRY, "FAILED_VMENTRY" } + +#endif /* UAPI_KVM_X86_PVM_TRACE_H */ diff --git a/arch/x86/kvm/pvm/pvm.c b/arch/x86/kvm/pvm/pvm.c index 8c5de0212c6d5f..817e1694277d1d 100644 --- a/arch/x86/kvm/pvm/pvm.c +++ b/arch/x86/kvm/pvm/pvm.c @@ -2441,6 +2441,34 @@ static u32 pvm_get_syscall_exit_reason(struct kvm_vcpu *vcpu) return PVM_EXIT_REASONS_SYSCALL; } +static u64 pvm_get_hypercall_exit_reason(struct kvm_vcpu *vcpu) +{ + switch (kvm_rax_read(vcpu)) { + case PVM_HC_IRQ_WIN: + return PVM_EXIT_REASONS_HC_IRQ_WIN; + case PVM_HC_IRQ_HALT: + return PVM_EXIT_REASONS_HC_IRQ_HALT; + case PVM_HC_LOAD_PGTBL: + return PVM_EXIT_REASONS_HC_LOAD_PGTBL; + case PVM_HC_TLB_FLUSH: + return PVM_EXIT_REASONS_HC_TLB_FLUSH; + case PVM_HC_TLB_FLUSH_CURRENT: + return PVM_EXIT_REASONS_HC_TLB_FLUSH_CURRENT; + case PVM_HC_TLB_INVLPG: + return PVM_EXIT_REASONS_HC_TLB_INVLPG; + case PVM_HC_LOAD_GS: + return PVM_EXIT_REASONS_HC_LOAD_GS; + case PVM_HC_RDMSR: + return PVM_EXIT_REASONS_HC_RDMSR; + case PVM_HC_WRMSR: + return PVM_EXIT_REASONS_HC_WRMSR; + case PVM_HC_LOAD_TLS: + return PVM_EXIT_REASONS_HC_LOAD_TLS; + default: + return 0; + } +} + static void pvm_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason, u64 *info1, u64 *info2, u32 *intr_info, u32 *error_code) { @@ -2453,12 +2481,17 @@ static void pvm_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason, u64 *info1, u6 else if (pvm->exit_vector >= FIRST_EXTERNAL_VECTOR && pvm->exit_vector < NR_VECTORS) *reason = PVM_EXIT_REASONS_INTERRUPT; + else if (pvm->exit_vector == SWITCH_EXIT_REASONS_FAILED_VMETNRY) + *reason = PVM_FAILED_VMENTRY_VECTOR; else *reason = pvm->exit_vector; *info1 = pvm->exit_vector; *info2 = pvm->exit_error_code; *intr_info = pvm->exit_vector; *error_code = pvm->exit_error_code; + + if (*reason == PVM_EXIT_REASONS_HYPERCALL) + *info2 = pvm_get_hypercall_exit_reason(vcpu); } static void pvm_handle_exit_irqoff(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/pvm/pvm.h b/arch/x86/kvm/pvm/pvm.h index 4708699c679f2c..ffebd29da0d763 100644 --- a/arch/x86/kvm/pvm/pvm.h +++ b/arch/x86/kvm/pvm/pvm.h @@ -36,6 +36,17 @@ #define PVM_EXIT_REASONS_INTERRUPT (5UL << PVM_EXIT_REASONS_SHIFT) #define PVM_EXIT_REASONS_INT80 (6UL << PVM_EXIT_REASONS_SHIFT) +#define PVM_EXIT_REASONS_HC_IRQ_WIN (PVM_EXIT_REASONS_HYPERCALL + 1) +#define PVM_EXIT_REASONS_HC_IRQ_HALT (PVM_EXIT_REASONS_HYPERCALL + 2) +#define PVM_EXIT_REASONS_HC_LOAD_PGTBL (PVM_EXIT_REASONS_HYPERCALL + 3) +#define PVM_EXIT_REASONS_HC_TLB_FLUSH (PVM_EXIT_REASONS_HYPERCALL + 4) +#define PVM_EXIT_REASONS_HC_TLB_FLUSH_CURRENT (PVM_EXIT_REASONS_HYPERCALL + 5) +#define PVM_EXIT_REASONS_HC_TLB_INVLPG (PVM_EXIT_REASONS_HYPERCALL + 6) +#define PVM_EXIT_REASONS_HC_LOAD_GS (PVM_EXIT_REASONS_HYPERCALL + 7) +#define PVM_EXIT_REASONS_HC_RDMSR (PVM_EXIT_REASONS_HYPERCALL + 8) +#define PVM_EXIT_REASONS_HC_WRMSR (PVM_EXIT_REASONS_HYPERCALL + 9) +#define PVM_EXIT_REASONS_HC_LOAD_TLS (PVM_EXIT_REASONS_HYPERCALL + 10) + #define PVM_EXIT_REASONS \ { DE_VECTOR, "DE excp" }, \ { DB_VECTOR, "DB excp" }, \ @@ -61,6 +72,16 @@ { PVM_EXIT_REASONS_ERETS, "ERETS" }, \ { PVM_EXIT_REASONS_INTERRUPT, "INTERRUPT" }, \ { PVM_EXIT_REASONS_INT80, "INT80" }, \ + { PVM_EXIT_REASONS_HC_IRQ_WIN, "HC_IRQ_WIN" }, \ + { PVM_EXIT_REASONS_HC_IRQ_HALT, "HC_IRQ_HALT" }, \ + { PVM_EXIT_REASONS_HC_LOAD_PGTBL, "HC_LOAD_PGTBL" }, \ + { PVM_EXIT_REASONS_HC_TLB_FLUSH, "HC_TLB_FLUSH" }, \ + { PVM_EXIT_REASONS_HC_TLB_FLUSH_CURRENT, "HC_TLB_FLUSH_CURRENT" },\ + { PVM_EXIT_REASONS_HC_TLB_INVLPG, "HC_TLB_INVLPG" }, \ + { PVM_EXIT_REASONS_HC_LOAD_GS, "HC_LOAD_GS" }, \ + { PVM_EXIT_REASONS_HC_RDMSR, "HC_RDMSR" }, \ + { PVM_EXIT_REASONS_HC_WRMSR, "HC_WRMSR" }, \ + { PVM_EXIT_REASONS_HC_LOAD_TLS, "HC_LOAD_TLS" }, \ { PVM_FAILED_VMENTRY_VECTOR, "FAILED_VMENTRY" } #define PT_L4_SHIFT 39 diff --git a/tools/arch/x86/include/uapi/asm/pvm_trace.h b/tools/arch/x86/include/uapi/asm/pvm_trace.h new file mode 100644 index 00000000000000..f3a45b945f7605 --- /dev/null +++ b/tools/arch/x86/include/uapi/asm/pvm_trace.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef UAPI_KVM_X86_PVM_TRACE_H +#define UAPI_KVM_X86_PVM_TRACE_H + +#include + +#define NMI_VECTOR 0x02 +#define PVM_EXIT_REASONS_FAILED_VMENTRY 1025 + +#define PVM_EXIT_REASONS_SHIFT 16 +#define PVM_EXIT_REASONS_SYSCALL BIT(PVM_EXIT_REASONS_SHIFT) +#define PVM_EXIT_REASONS_HYPERCALL (2UL << PVM_EXIT_REASONS_SHIFT) +#define PVM_EXIT_REASONS_ERETU (3UL << PVM_EXIT_REASONS_SHIFT) +#define PVM_EXIT_REASONS_ERETS (4UL << PVM_EXIT_REASONS_SHIFT) +#define PVM_EXIT_REASONS_INTERRUPT (5UL << PVM_EXIT_REASONS_SHIFT) +#define PVM_EXIT_REASONS_INT80 (6UL << PVM_EXIT_REASONS_SHIFT) + +#define PVM_EXIT_REASONS_HC_IRQ_WIN (PVM_EXIT_REASONS_HYPERCALL + 1) +#define PVM_EXIT_REASONS_HC_IRQ_HALT (PVM_EXIT_REASONS_HYPERCALL + 2) +#define PVM_EXIT_REASONS_HC_LOAD_PGTBL (PVM_EXIT_REASONS_HYPERCALL + 3) +#define PVM_EXIT_REASONS_HC_TLB_FLUSH (PVM_EXIT_REASONS_HYPERCALL + 4) +#define PVM_EXIT_REASONS_HC_TLB_FLUSH_CURRENT (PVM_EXIT_REASONS_HYPERCALL + 5) +#define PVM_EXIT_REASONS_HC_TLB_INVLPG (PVM_EXIT_REASONS_HYPERCALL + 6) +#define PVM_EXIT_REASONS_HC_LOAD_GS (PVM_EXIT_REASONS_HYPERCALL + 7) +#define PVM_EXIT_REASONS_HC_RDMSR (PVM_EXIT_REASONS_HYPERCALL + 8) +#define PVM_EXIT_REASONS_HC_WRMSR (PVM_EXIT_REASONS_HYPERCALL + 9) +#define PVM_EXIT_REASONS_HC_LOAD_TLS (PVM_EXIT_REASONS_HYPERCALL + 10) + +#define PVM_EXIT_REASONS \ + { DE_VECTOR, "DE excp" }, \ + { DB_VECTOR, "DB excp" }, \ + { NMI_VECTOR, "NMI excp" }, \ + { BP_VECTOR, "BP excp" }, \ + { OF_VECTOR, "OF excp" }, \ + { BR_VECTOR, "BR excp" }, \ + { UD_VECTOR, "UD excp" }, \ + { NM_VECTOR, "NM excp" }, \ + { DF_VECTOR, "DF excp" }, \ + { TS_VECTOR, "TS excp" }, \ + { SS_VECTOR, "SS excp" }, \ + { GP_VECTOR, "GP excp" }, \ + { PF_VECTOR, "PF excp" }, \ + { MF_VECTOR, "MF excp" }, \ + { AC_VECTOR, "AC excp" }, \ + { MC_VECTOR, "MC excp" }, \ + { XM_VECTOR, "XM excp" }, \ + { VE_VECTOR, "VE excp" }, \ + { PVM_EXIT_REASONS_SYSCALL, "SYSCALL" }, \ + { PVM_EXIT_REASONS_HYPERCALL, "HYPERCALL" }, \ + { PVM_EXIT_REASONS_ERETU, "ERETU" }, \ + { PVM_EXIT_REASONS_ERETS, "ERETS" }, \ + { PVM_EXIT_REASONS_INTERRUPT, "INTERRUPT" }, \ + { PVM_EXIT_REASONS_INT80, "INT80" }, \ + { PVM_EXIT_REASONS_HC_IRQ_WIN, "HC_IRQ_WIN" }, \ + { PVM_EXIT_REASONS_HC_IRQ_HALT, "HC_IRQ_HALT" }, \ + { PVM_EXIT_REASONS_HC_LOAD_PGTBL, "HC_LOAD_PGTBL" }, \ + { PVM_EXIT_REASONS_HC_TLB_FLUSH, "HC_TLB_FLUSH" }, \ + { PVM_EXIT_REASONS_HC_TLB_FLUSH_CURRENT, "HC_TLB_FLUSH_CURRENT" },\ + { PVM_EXIT_REASONS_HC_TLB_INVLPG, "HC_TLB_INVLPG" }, \ + { PVM_EXIT_REASONS_HC_LOAD_GS, "HC_LOAD_GS" }, \ + { PVM_EXIT_REASONS_HC_RDMSR, "HC_RDMSR" }, \ + { PVM_EXIT_REASONS_HC_WRMSR, "HC_WRMSR" }, \ + { PVM_EXIT_REASONS_HC_LOAD_TLS, "HC_LOAD_TLS" }, \ + { PVM_EXIT_REASONS_FAILED_VMENTRY, "FAILED_VMENTRY" } + +#endif /* UAPI_KVM_X86_PVM_TRACE_H */ diff --git a/tools/perf/arch/x86/util/kvm-stat.c b/tools/perf/arch/x86/util/kvm-stat.c index 424716518b7559..30eb3a4b3d52ae 100644 --- a/tools/perf/arch/x86/util/kvm-stat.c +++ b/tools/perf/arch/x86/util/kvm-stat.c @@ -6,9 +6,12 @@ #include #include #include +#include +#include define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS); define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS); +define_exit_reasons_table(pvm_exit_reasons, PVM_EXIT_REASONS); static struct kvm_events_ops exit_events = { .is_begin_event = exit_event_begin, @@ -198,9 +201,39 @@ const char * const kvm_skip_events[] = { NULL, }; +#define INITSTATE_PATH_MAX 256 +#define INITSTATE_MAX 16 + +static bool module_is_live(const char *module_name) +{ + char initstate_path[INITSTATE_PATH_MAX]; + char initstate[INITSTATE_MAX]; + bool ret = false; + struct stat st; + FILE *fp; + + snprintf(initstate_path, sizeof(initstate_path), + "/sys/module/%s/initstate", module_name); + + if (!stat(initstate_path, &st) && S_ISREG(st.st_mode)) { + fp = fopen(initstate_path, "r"); + if (fp) { + if (fgets(initstate, sizeof(initstate), fp)) + ret = !strncmp(initstate, "live", 4); + + fclose(fp); + } + } + + return ret; +} + int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid) { - if (strstr(cpuid, "Intel")) { + if (module_is_live("kvm_pvm")) { + kvm->exit_reasons = pvm_exit_reasons; + kvm->exit_reasons_isa = "PVM"; + } else if (strstr(cpuid, "Intel")) { kvm->exit_reasons = vmx_exit_reasons; kvm->exit_reasons_isa = "VMX"; } else if (strstr(cpuid, "AMD") || strstr(cpuid, "Hygon")) { diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 71165036e4cac8..d7121391000cb2 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -620,7 +621,11 @@ void exit_event_get_key(struct evsel *evsel, struct event_key *key) { key->info = 0; + key->info2 = evsel__intval(evsel, sample, "info2"); key->key = evsel__intval(evsel, sample, kvm_exit_reason); + + if (key->key == PVM_EXIT_REASONS_HYPERCALL) + key->key = key->info2; } bool kvm_exit_event(struct evsel *evsel) diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 66ba33dbcef22b..5ac0698ab3ac84 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -50,6 +50,7 @@ FILES=( "arch/powerpc/include/uapi/asm/perf_regs.h" "arch/s390/include/uapi/asm/perf_regs.h" "arch/x86/include/uapi/asm/perf_regs.h" + "arch/x86/include/uapi/asm/pvm_trace.h" "arch/x86/include/uapi/asm/kvm.h" "arch/x86/include/uapi/asm/kvm_perf.h" "arch/x86/include/uapi/asm/svm.h" diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h index 3e9ac754c3d1f0..db4a6d179f532d 100644 --- a/tools/perf/util/kvm-stat.h +++ b/tools/perf/util/kvm-stat.h @@ -23,6 +23,7 @@ struct event_key { #define INVALID_KEY (~0ULL) u64 key; int info; + u64 info2; struct exit_reasons_table *exit_reasons; };