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