Hardware does not save/restore FRED_RSP0 for Non-SEV-ES guests. Save it in svm_prepare_host_switch() and restore it in svm_prepare_switch_to_guest() so that the correct physical CPU state is updated. Also, synchronize the current value of MSR_IA32_FRED_RSP0 in hardware to the kernel's local cache. Note that the desired host's RSP0 will be set when the CPU exits to userspace for servicing vCPU tasks. Co-developed-by: Neeraj Upadhyay Signed-off-by: Neeraj Upadhyay Signed-off-by: Shivansh Dhiman --- Changes in v3: * Keep the guest's FRED_RSP0 in a new vcpu_svm field, msr_guest_fred_rsp0. The VMCB has no FRED_RSP0 field for non-SEV-ES guests. * Zero msr_guest_fred_rsp0 on RESET. * Added the svm_manages_fred_rsp0() helper. Changes in v2: * Moved FRED MSRs save/restore logic from svm_vcpu_enter_exit() to svm_prepare_[host_switch/switch_to_guest]() to reduce some MSR accesses. * While switching to host, added a safety check on guest_state_loaded. --- arch/x86/kvm/svm/svm.c | 28 +++++++++++++++++++++++++++- arch/x86/kvm/svm/svm.h | 2 ++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index e212f53d262a..c1263a3b3e73 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1234,6 +1234,7 @@ static void init_vmcb(struct kvm_vcpu *vcpu, bool init_event) save->idtr.limit = 0xffff; if (!init_event) { + svm->msr_guest_fred_rsp0 = 0; save->fred_rsp1 = 0; save->fred_rsp2 = 0; save->fred_rsp3 = 0; @@ -1458,6 +1459,11 @@ static void svm_srso_vm_init(void) { } static void svm_srso_vm_destroy(void) { } #endif +static bool svm_manages_fred_rsp0(struct kvm_vcpu *vcpu) +{ + return !is_sev_es_guest(vcpu) && guest_cpu_cap_has(vcpu, X86_FEATURE_FRED); +} + static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -1495,12 +1501,32 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu) sd->bp_spec_reduce_set = true; msr_set_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_BP_SPEC_REDUCE_BIT); } + + /* Hardware does not save/restore FRED_RSP0 for Non-SEV-ES guests. */ + if (svm_manages_fred_rsp0(vcpu)) + wrmsrq(MSR_IA32_FRED_RSP0, svm->msr_guest_fred_rsp0); + svm->guest_state_loaded = true; } static void svm_prepare_host_switch(struct kvm_vcpu *vcpu) { - to_svm(vcpu)->guest_state_loaded = false; + struct vcpu_svm *svm = to_svm(vcpu); + + if (!svm->guest_state_loaded) + return; + + /* + * Hardware does not save/restore FRED_RSP0 for Non-SEV-ES guests. + * Also, sync hardware MSR value to per-CPU cache. This helps in + * restoring Host RSP0 when exiting to userspace in fred_update_rsp0(). + */ + if (svm_manages_fred_rsp0(vcpu)) { + rdmsrq(MSR_IA32_FRED_RSP0, svm->msr_guest_fred_rsp0); + fred_sync_rsp0(svm->msr_guest_fred_rsp0); + } + + svm->guest_state_loaded = false; } static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index e958943b8162..581289cc6e0b 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -362,6 +362,8 @@ struct vcpu_svm { bool guest_state_loaded; + u64 msr_guest_fred_rsp0; + bool avic_irq_window; bool x2avic_msrs_intercepted; bool lbr_msrs_intercepted; -- 2.43.0