From: Sandipan Das Define the new VMCB fields that will be used to save and restore the state of the following Last Branch Record Extension Version 2 (LbrExtV2) related MSRs. * Last Branch Stack Select (MSR 0xc000010e) * Debug Extension Control (MSR 0xc000010f) * LBR v2 Branch FROM (MSRs 0xc0010300..0xc001031e) * LBR v2 Branch To (MSRs 0xc0010301..0xc001031f) Signed-off-by: Sandipan Das Signed-off-by: Shivansh Dhiman --- arch/x86/include/asm/svm.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index aa63431ba92c..fbcf6c4dbb92 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -368,8 +368,15 @@ struct vmcb_save_area { u64 br_to; u64 last_excp_from; u64 last_excp_to; - u8 reserved_0x298[72]; + u64 dbg_extn_cfg; + u8 reserved_0x2a0[64]; u64 spec_ctrl; /* Guest version of SPEC_CTRL at 0x2E0 */ + u8 reserved_0x2e8[904]; + struct { + u64 lbr_stack_from; + u64 lbr_stack_to; + } __packed lbr[16]; + u64 lbr_select; } __packed; /* Save area definition for SEV-ES and SEV-SNP guests */ @@ -552,7 +559,7 @@ struct vmcb { }; } __packed; -#define EXPECTED_VMCB_SAVE_AREA_SIZE 744 +#define EXPECTED_VMCB_SAVE_AREA_SIZE 1912 #define EXPECTED_GHCB_SAVE_AREA_SIZE 1032 #define EXPECTED_SEV_ES_SAVE_AREA_SIZE 1648 #define EXPECTED_VMCB_CONTROL_AREA_SIZE 1024 @@ -577,7 +584,8 @@ static inline void __unused_size_checks(void) BUILD_BUG_RESERVED_OFFSET(vmcb_save_area, 0xd8); BUILD_BUG_RESERVED_OFFSET(vmcb_save_area, 0x180); BUILD_BUG_RESERVED_OFFSET(vmcb_save_area, 0x248); - BUILD_BUG_RESERVED_OFFSET(vmcb_save_area, 0x298); + BUILD_BUG_RESERVED_OFFSET(vmcb_save_area, 0x2a0); + BUILD_BUG_RESERVED_OFFSET(vmcb_save_area, 0x2e8); BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0xc8); BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0xcc); -- 2.43.0 Define the LbrExtV2 KVM feature (CPUID 0x80000022.EAX[1]) and plumb the host LBR stack depth out of the core PMU driver, so KVM can later report the depth the hardware actually supports rather than assuming a value. Signed-off-by: Sandipan Das Co-developed-by: Shivansh Dhiman Signed-off-by: Shivansh Dhiman --- arch/x86/events/core.c | 1 + arch/x86/include/asm/perf_event.h | 1 + arch/x86/kvm/reverse_cpuid.h | 2 ++ 3 files changed, 4 insertions(+) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 4b9e105309c6..4acbca1a88a1 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -3138,6 +3138,7 @@ void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap) cap->bit_width_fixed = cap->num_counters_fixed ? x86_pmu.cntval_bits : 0; cap->events_mask = (unsigned int)x86_pmu.events_maskl; cap->events_mask_len = x86_pmu.events_mask_len; + cap->num_branches_lbr = x86_pmu.lbr_nr; cap->pebs_ept = x86_pmu.pebs_ept; cap->mediated = !!(pmu.capabilities & PERF_PMU_CAP_MEDIATED_VPMU); } diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index 1eb13673e889..f18cf0986e12 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -306,6 +306,7 @@ struct x86_pmu_capability { int bit_width_fixed; unsigned int events_mask; int events_mask_len; + int num_branches_lbr; unsigned int pebs_ept :1; unsigned int mediated :1; }; diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h index 657f5f743ed9..b4abd839af1d 100644 --- a/arch/x86/kvm/reverse_cpuid.h +++ b/arch/x86/kvm/reverse_cpuid.h @@ -71,6 +71,7 @@ /* CPUID level 0x80000022 (EAX) */ #define KVM_X86_FEATURE_PERFMON_V2 KVM_X86_FEATURE(CPUID_8000_0022_EAX, 0) +#define KVM_X86_FEATURE_AMD_LBR_V2 KVM_X86_FEATURE(CPUID_8000_0022_EAX, 1) /* CPUID level 0x80000021 (ECX) */ #define KVM_X86_FEATURE_TSA_SQ_NO KVM_X86_FEATURE(CPUID_8000_0021_ECX, 1) @@ -146,6 +147,7 @@ static __always_inline u32 __feature_translate(int x86_feature) KVM_X86_TRANSLATE_FEATURE(SGX_EDECCSSA); KVM_X86_TRANSLATE_FEATURE(CONSTANT_TSC); KVM_X86_TRANSLATE_FEATURE(PERFMON_V2); + KVM_X86_TRANSLATE_FEATURE(AMD_LBR_V2); KVM_X86_TRANSLATE_FEATURE(RRSBA_CTRL); KVM_X86_TRANSLATE_FEATURE(BHI_CTRL); KVM_X86_TRANSLATE_FEATURE(TSA_SQ_NO); -- 2.43.0 Back the LBR v2 MSRs with their VMCB save-area fields in svm_{get,set}_msr(). This is required when guest accesses to these MSRs are intercepted. This allows the guest to retain the values of these MSRs on VMRUN/#VMEXIT cycle when vLBR is disabled. Signed-off-by: Shivansh Dhiman --- arch/x86/include/asm/svm.h | 2 ++ arch/x86/kvm/svm/svm.c | 68 ++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/svm/svm.h | 2 ++ 3 files changed, 72 insertions(+) diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index fbcf6c4dbb92..f3bc97bc6aca 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -253,6 +253,8 @@ struct __attribute__ ((__packed__)) vmcb_control_area { #define SVM_TSC_RATIO_MAX 0x000000ffffffffffULL #define SVM_TSC_RATIO_DEFAULT 0x0100000000ULL +#define SVM_LBR_V2_STACK_SIZE 16 + /* AVIC */ #define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK (0xFFULL) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index ef69a51ab27f..13ac62604ca0 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -744,6 +744,12 @@ static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu) svm->lbr_msrs_intercepted = intercept; } +static bool svm_lbrv2_supported(struct kvm_vcpu *vcpu) +{ + return guest_cpu_cap_has(vcpu, X86_FEATURE_AMD_LBR_V2) && + kvm_vcpu_has_mediated_pmu(vcpu); +} + void svm_vcpu_free_msrpm(void *msrpm) { __free_pages(virt_to_page(msrpm), get_order(MSRPM_SIZE)); @@ -2787,6 +2793,19 @@ static u64 *svm_vmcb_lbr(struct vcpu_svm *svm, u32 msr) return &svm->vmcb->save.br_from; } +static u64 *svm_vmcb_lbrv2(struct vcpu_svm *svm, u32 msr) +{ + u32 offset = msr - MSR_AMD_SAMP_BR_FROM; + u32 idx = offset >> 1; + + if (WARN_ON_ONCE(idx >= SVM_LBR_V2_STACK_SIZE)) + return &svm->vmcb->save.lbr[0].lbr_stack_from; + + if (offset & 1) + return &svm->vmcb->save.lbr[idx].lbr_stack_to; + return &svm->vmcb->save.lbr[idx].lbr_stack_from; +} + static bool sev_es_prevent_msr_access(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { @@ -2882,6 +2901,21 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_IA32_LASTINTTOIP: msr_info->data = lbrv ? *svm_vmcb_lbr(svm, msr_info->index) : 0; break; + case MSR_AMD_DBG_EXTN_CFG: + if (!svm_lbrv2_supported(vcpu)) + return KVM_MSR_RET_UNSUPPORTED; + msr_info->data = svm->vmcb->save.dbg_extn_cfg; + break; + case MSR_AMD64_LBR_SELECT: + if (!svm_lbrv2_supported(vcpu)) + return KVM_MSR_RET_UNSUPPORTED; + msr_info->data = svm->vmcb->save.lbr_select; + break; + case MSR_AMD_SAMP_BR_FROM ... MSR_AMD_SAMP_BR_FROM + 31: + if (!svm_lbrv2_supported(vcpu)) + return KVM_MSR_RET_UNSUPPORTED; + msr_info->data = *svm_vmcb_lbrv2(svm, msr_info->index); + break; case MSR_VM_HSAVE_PA: msr_info->data = svm->nested.hsave_msr; break; @@ -3181,6 +3215,40 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) *svm_vmcb_lbr(svm, ecx) = data; vmcb_mark_dirty(svm->vmcb, VMCB_LBR); break; + case MSR_AMD_DBG_EXTN_CFG: + if (!svm_lbrv2_supported(vcpu)) + return KVM_MSR_RET_UNSUPPORTED; + + if (data & DBG_EXTN_CFG_RESERVED_BITS) + return 1; + + if (svm->vmcb->save.dbg_extn_cfg == data) + break; + + svm->vmcb->save.dbg_extn_cfg = data; + vmcb_mark_dirty(svm->vmcb, VMCB_LBR); + svm_update_lbrv(vcpu); + break; + case MSR_AMD64_LBR_SELECT: + if (!svm_lbrv2_supported(vcpu)) + return KVM_MSR_RET_UNSUPPORTED; + + if (data & LBR_SELECT_RESERVED_BITS) + return 1; + + if (svm->vmcb->save.lbr_select == data) + break; + + svm->vmcb->save.lbr_select = data; + vmcb_mark_dirty(svm->vmcb, VMCB_LBR); + break; + case MSR_AMD_SAMP_BR_FROM ... MSR_AMD_SAMP_BR_FROM + 31: + if (!svm_lbrv2_supported(vcpu)) + return KVM_MSR_RET_UNSUPPORTED; + + *svm_vmcb_lbrv2(svm, ecx) = data; + vmcb_mark_dirty(svm->vmcb, VMCB_LBR); + break; case MSR_VM_HSAVE_PA: /* * Old kernels did not validate the value written to diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 716be21fba33..f62bf19024cc 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -784,6 +784,8 @@ BUILD_SVM_MSR_BITMAP_HELPERS(void, clear, __clear) BUILD_SVM_MSR_BITMAP_HELPERS(void, set, __set) #define DEBUGCTL_RESERVED_BITS (~DEBUGCTLMSR_LBR) +#define DBG_EXTN_CFG_RESERVED_BITS (~DBG_EXTN_CFG_LBRV2EN) +#define LBR_SELECT_RESERVED_BITS (~GENMASK_ULL(8, 0)) /* svm.c */ extern bool dump_invalid_vmcb; -- 2.43.0 Enable V_LBR so hardware saves and restores the guest's LBR v2 state in the VMCB, and pass the LBR v2 MSRs through (by disabling interception) to the guest while it is set. V_LBR is enabled lazily, only once the guest turns on branch recording, just like legacy LBR keys off DEBUGCTL. Co-developed-by: Sandipan Das Signed-off-by: Sandipan Das Signed-off-by: Shivansh Dhiman --- arch/x86/kvm/svm/svm.c | 46 ++++++++++++++++++++++++++++++++++++++++-- arch/x86/kvm/svm/svm.h | 1 + 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 13ac62604ca0..04e386b838d3 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -750,6 +750,41 @@ static bool svm_lbrv2_supported(struct kvm_vcpu *vcpu) kvm_vcpu_has_mediated_pmu(vcpu); } +static bool svm_lbrv2_active(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + return svm_lbrv2_supported(vcpu) && + (svm->vmcb->save.dbg_extn_cfg & DBG_EXTN_CFG_LBRV2EN); +} + +static void svm_recalc_lbrv2_msr_intercepts(struct kvm_vcpu *vcpu) +{ + struct vcpu_svm *svm = to_svm(vcpu); + bool intercept = !svm_lbrv2_active(vcpu); + int i; + + if (intercept == svm->lbrv2_msrs_intercepted) + return; + + for (i = 0; i < 32; i++) + svm_set_intercept_for_msr(vcpu, MSR_AMD_SAMP_BR_FROM + i, MSR_TYPE_RW, intercept); + + svm_set_intercept_for_msr(vcpu, MSR_AMD64_LBR_SELECT, MSR_TYPE_RW, intercept); + + /* + * DBG_EXTN_CFG stays permanently intercepted for non-SEV-ES guests so + * KVM can observe LBRV2EN and lazily toggle V_LBR. SEV-ES+ guests must + * delegate LBR virtualization to the processor (per the APM), where + * intercepting LBR MSRs can be fatal, so toggle it with the rest. See + * commit b7e4be0a224f ("KVM: SEV-ES: Delegate LBR virtualization to the + * processor"). + */ + if (is_sev_es_guest(vcpu)) + svm_set_intercept_for_msr(vcpu, MSR_AMD_DBG_EXTN_CFG, MSR_TYPE_RW, intercept); + + svm->lbrv2_msrs_intercepted = intercept; +} + void svm_vcpu_free_msrpm(void *msrpm) { __free_pages(virt_to_page(msrpm), get_order(MSRPM_SIZE)); @@ -805,8 +840,10 @@ static void svm_recalc_msr_intercepts(struct kvm_vcpu *vcpu) svm_disable_intercept_for_msr(vcpu, MSR_SYSCALL_MASK, MSR_TYPE_RW); #endif - if (lbrv) + if (lbrv) { svm_recalc_lbr_msr_intercepts(vcpu); + svm_recalc_lbrv2_msr_intercepts(vcpu); + } if (cpu_feature_enabled(X86_FEATURE_IBPB)) svm_set_intercept_for_msr(vcpu, MSR_IA32_PRED_CMD, MSR_TYPE_W, @@ -874,6 +911,7 @@ void svm_enable_lbrv(struct kvm_vcpu *vcpu) { __svm_enable_lbrv(vcpu); svm_recalc_lbr_msr_intercepts(vcpu); + svm_recalc_lbrv2_msr_intercepts(vcpu); } static void __svm_disable_lbrv(struct kvm_vcpu *vcpu) @@ -886,9 +924,11 @@ void svm_update_lbrv(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); bool current_enable_lbrv = svm->vmcb->control.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR; + bool enable_lbrv = (svm->vmcb->save.dbgctl & DEBUGCTLMSR_LBR) || (is_guest_mode(vcpu) && guest_cpu_cap_has(vcpu, X86_FEATURE_LBRV) && - (svm->nested.ctl.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR)); + (svm->nested.ctl.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR)) || + svm_lbrv2_active(vcpu); if (enable_lbrv && !current_enable_lbrv) __svm_enable_lbrv(vcpu); @@ -902,6 +942,7 @@ void svm_update_lbrv(struct kvm_vcpu *vcpu) * do, so always recalculate the intercepts here. */ svm_recalc_lbr_msr_intercepts(vcpu); + svm_recalc_lbrv2_msr_intercepts(vcpu); } void disable_nmi_singlestep(struct vcpu_svm *svm) @@ -1347,6 +1388,7 @@ static int svm_vcpu_create(struct kvm_vcpu *vcpu) svm->x2avic_msrs_intercepted = true; svm->lbr_msrs_intercepted = true; + svm->lbrv2_msrs_intercepted = true; svm->vmcb01.ptr = page_address(vmcb01_page); svm->vmcb01.pa = __sme_set(page_to_pfn(vmcb01_page) << PAGE_SHIFT); diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index f62bf19024cc..01dae3828a7a 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -363,6 +363,7 @@ struct vcpu_svm { bool avic_irq_window; bool x2avic_msrs_intercepted; bool lbr_msrs_intercepted; + bool lbrv2_msrs_intercepted; /* Guest GIF value, used when vGIF is not enabled */ bool guest_gif; -- 2.43.0 Now that LBR v2 is fully virtualized, advertise it and report the LBR stack depth in CPUID. Gate the advertisement on LBR virtualization, the mediated PMU, PerfMonV2 and a 16-entry host stack, so KVM never exposes a configuration it cannot faithfully virtualize, and drop the feature for a vCPU whose CPUID is set with an unsupported stack size. Co-developed-by: Sandipan Das Signed-off-by: Sandipan Das Signed-off-by: Shivansh Dhiman --- arch/x86/kvm/cpuid.c | 6 ++++++ arch/x86/kvm/svm/svm.c | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 2698fa42cd97..d450a5b2499d 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -1267,6 +1267,7 @@ void kvm_initialize_cpu_caps(void) kvm_cpu_cap_init(CPUID_8000_0022_EAX, F(PERFMON_V2), + SCATTERED_F(AMD_LBR_V2), ); if (!static_cpu_has_bug(X86_BUG_NULL_SEG)) @@ -1883,6 +1884,11 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) cpuid_entry_override(entry, CPUID_8000_0022_EAX); ebx.split.num_core_pmc = kvm_pmu_cap.num_counters_gp; + + if (kvm_cpu_cap_has(X86_FEATURE_AMD_LBR_V2)) + ebx.split.lbr_v2_stack_sz = + min(kvm_pmu_cap.num_branches_lbr, SVM_LBR_V2_STACK_SIZE); + entry->ebx = ebx.full; break; } diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 04e386b838d3..4b84498e93be 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4820,6 +4820,20 @@ static bool svm_has_emulated_msr(struct kvm *kvm, u32 index) return true; } +static int cpuid_query_lbrv2_stack_size(struct kvm_vcpu *vcpu) +{ + struct kvm_cpuid_entry2 *entry; + + entry = kvm_find_cpuid_entry(vcpu, 0x80000000); + if (!entry || entry->eax < 0x80000022) + goto not_found; + entry = kvm_find_cpuid_entry(vcpu, 0x80000022); + if (entry) + return (entry->ebx >> 4) & 0x3f; +not_found: + return 0; +} + static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -4846,6 +4860,10 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) if (guest_cpuid_is_intel_compatible(vcpu)) guest_cpu_cap_clear(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD); + if (guest_cpu_cap_has(vcpu, X86_FEATURE_AMD_LBR_V2) && + cpuid_query_lbrv2_stack_size(vcpu) != SVM_LBR_V2_STACK_SIZE) + guest_cpu_cap_clear(vcpu, X86_FEATURE_AMD_LBR_V2); + if (is_sev_guest(vcpu)) sev_vcpu_after_set_cpuid(svm); } @@ -5692,6 +5710,10 @@ static __init void svm_set_cpu_caps(void) if (kvm_pmu_cap.version != 2 || !kvm_cpu_cap_has(X86_FEATURE_PERFCTR_CORE)) kvm_cpu_cap_clear(X86_FEATURE_PERFMON_V2); + + if (!lbrv || !enable_mediated_pmu || + !kvm_cpu_cap_has(X86_FEATURE_PERFMON_V2)) + kvm_cpu_cap_clear(X86_FEATURE_AMD_LBR_V2); } /* CPUID 0x8000001F (SME/SEV features) */ -- 2.43.0 Add support for the LBR and PMC freeze-on-PMI feature (CPUID 0x80000022.EAX[2]). This feature is very often used with LBRv2. Permit the guest to enable freezing via DEBUGCTL only when the feature is advertised to it, and advertise it accordingly. Signed-off-by: Shivansh Dhiman --- arch/x86/kvm/cpuid.c | 1 + arch/x86/kvm/reverse_cpuid.h | 6 ++++-- arch/x86/kvm/svm/svm.c | 4 ++++ arch/x86/kvm/svm/svm.h | 4 +++- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index d450a5b2499d..03501b3145eb 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -1268,6 +1268,7 @@ void kvm_initialize_cpu_caps(void) kvm_cpu_cap_init(CPUID_8000_0022_EAX, F(PERFMON_V2), SCATTERED_F(AMD_LBR_V2), + SCATTERED_F(AMD_LBR_PMC_FREEZE), ); if (!static_cpu_has_bug(X86_BUG_NULL_SEG)) diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h index b4abd839af1d..9a58f91eb173 100644 --- a/arch/x86/kvm/reverse_cpuid.h +++ b/arch/x86/kvm/reverse_cpuid.h @@ -70,8 +70,9 @@ #define KVM_X86_FEATURE_CONSTANT_TSC KVM_X86_FEATURE(CPUID_8000_0007_EDX, 8) /* CPUID level 0x80000022 (EAX) */ -#define KVM_X86_FEATURE_PERFMON_V2 KVM_X86_FEATURE(CPUID_8000_0022_EAX, 0) -#define KVM_X86_FEATURE_AMD_LBR_V2 KVM_X86_FEATURE(CPUID_8000_0022_EAX, 1) +#define KVM_X86_FEATURE_PERFMON_V2 KVM_X86_FEATURE(CPUID_8000_0022_EAX, 0) +#define KVM_X86_FEATURE_AMD_LBR_V2 KVM_X86_FEATURE(CPUID_8000_0022_EAX, 1) +#define KVM_X86_FEATURE_AMD_LBR_PMC_FREEZE KVM_X86_FEATURE(CPUID_8000_0022_EAX, 2) /* CPUID level 0x80000021 (ECX) */ #define KVM_X86_FEATURE_TSA_SQ_NO KVM_X86_FEATURE(CPUID_8000_0021_ECX, 1) @@ -148,6 +149,7 @@ static __always_inline u32 __feature_translate(int x86_feature) KVM_X86_TRANSLATE_FEATURE(CONSTANT_TSC); KVM_X86_TRANSLATE_FEATURE(PERFMON_V2); KVM_X86_TRANSLATE_FEATURE(AMD_LBR_V2); + KVM_X86_TRANSLATE_FEATURE(AMD_LBR_PMC_FREEZE); KVM_X86_TRANSLATE_FEATURE(RRSBA_CTRL); KVM_X86_TRANSLATE_FEATURE(BHI_CTRL); KVM_X86_TRANSLATE_FEATURE(TSA_SQ_NO); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 4b84498e93be..3ec91c1c58dc 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -3236,6 +3236,10 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) data &= ~DEBUGCTLMSR_BTF; } + if ((data & DEBUGCTL_LBR_PMC_FREEZE_BITS) && + !guest_cpu_cap_has(vcpu, X86_FEATURE_AMD_LBR_PMC_FREEZE)) + return 1; + if (data & DEBUGCTL_RESERVED_BITS) return 1; diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 01dae3828a7a..105a71d69d68 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -784,7 +784,9 @@ BUILD_SVM_MSR_BITMAP_HELPERS(bool, test, test) BUILD_SVM_MSR_BITMAP_HELPERS(void, clear, __clear) BUILD_SVM_MSR_BITMAP_HELPERS(void, set, __set) -#define DEBUGCTL_RESERVED_BITS (~DEBUGCTLMSR_LBR) +#define DEBUGCTL_LBR_PMC_FREEZE_BITS (DEBUGCTLMSR_FREEZE_LBRS_ON_PMI | \ + DEBUGCTLMSR_FREEZE_PERFMON_ON_PMI) +#define DEBUGCTL_RESERVED_BITS (~(DEBUGCTLMSR_LBR | DEBUGCTL_LBR_PMC_FREEZE_BITS)) #define DBG_EXTN_CFG_RESERVED_BITS (~DBG_EXTN_CFG_LBRV2EN) #define LBR_SELECT_RESERVED_BITS (~GENMASK_ULL(8, 0)) -- 2.43.0 PERFMON_V2 is a scattered feature, so enumerate it with SCATTERED_F() instead of F(). No functional change intended. Signed-off-by: Shivansh Dhiman --- arch/x86/kvm/cpuid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 03501b3145eb..51b691f91442 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -1266,7 +1266,7 @@ void kvm_initialize_cpu_caps(void) ); kvm_cpu_cap_init(CPUID_8000_0022_EAX, - F(PERFMON_V2), + SCATTERED_F(PERFMON_V2), SCATTERED_F(AMD_LBR_V2), SCATTERED_F(AMD_LBR_PMC_FREEZE), ); -- 2.43.0