Skip to content

Commit 656d962

Browse files
yosrym93sean-jc
authored andcommitted
KVM: x86: Generalize IBRS virtualization on emulated VM-exit
Commit 2e7eab8 ("KVM: VMX: Execute IBPB on emulated VM-exit when guest has IBRS") added an IBPB in the emulated VM-exit path on Intel to properly virtualize IBRS by providing separate predictor modes for L1 and L2. AMD requires similar handling, except when IbrsSameMode is enumerated by the host CPU (which is the case on most/all AMD CPUs). With IbrsSameMode, hardware IBRS is sufficient and no extra handling is needed from KVM. Generalize the handling in nested_vmx_vmexit() by moving it into a generic function, add the AMD handling, and use it in nested_svm_vmexit() too. The main reason for using a generic function is to have a single place to park the huge comment about virtualizing IBRS. Signed-off-by: Yosry Ahmed <[email protected]> Reviewed-by: Jim Mattson <[email protected]> Link: https://lore.kernel.org/r/[email protected] [sean: use kvm_nested_vmexit_handle_spec_ctrl() for the helper] Signed-off-by: Sean Christopherson <[email protected]>
1 parent 65ca287 commit 656d962

File tree

3 files changed

+21
-10
lines changed

3 files changed

+21
-10
lines changed

arch/x86/kvm/svm/nested.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,8 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
10411041

10421042
nested_svm_copy_common_state(svm->nested.vmcb02.ptr, svm->vmcb01.ptr);
10431043

1044+
kvm_nested_vmexit_handle_ibrs(vcpu);
1045+
10441046
svm_switch_vmcb(svm, &svm->vmcb01);
10451047

10461048
/*

arch/x86/kvm/vmx/nested.c

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5020,16 +5020,7 @@ void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
50205020

50215021
vmx_switch_vmcs(vcpu, &vmx->vmcs01);
50225022

5023-
/*
5024-
* If IBRS is advertised to the vCPU, KVM must flush the indirect
5025-
* branch predictors when transitioning from L2 to L1, as L1 expects
5026-
* hardware (KVM in this case) to provide separate predictor modes.
5027-
* Bare metal isolates VMX root (host) from VMX non-root (guest), but
5028-
* doesn't isolate different VMCSs, i.e. in this case, doesn't provide
5029-
* separate modes for L2 vs L1.
5030-
*/
5031-
if (guest_cpu_cap_has(vcpu, X86_FEATURE_SPEC_CTRL))
5032-
indirect_branch_prediction_barrier();
5023+
kvm_nested_vmexit_handle_ibrs(vcpu);
50335024

50345025
/* Update any VMCS fields that might have changed while L2 ran */
50355026
vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);

arch/x86/kvm/x86.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,24 @@ static inline void kvm_leave_nested(struct kvm_vcpu *vcpu)
121121
kvm_x86_ops.nested_ops->leave_nested(vcpu);
122122
}
123123

124+
/*
125+
* If IBRS is advertised to the vCPU, KVM must flush the indirect branch
126+
* predictors when transitioning from L2 to L1, as L1 expects hardware (KVM in
127+
* this case) to provide separate predictor modes. Bare metal isolates the host
128+
* from the guest, but doesn't isolate different guests from one another (in
129+
* this case L1 and L2). The exception is if bare metal supports same mode IBRS,
130+
* which offers protection within the same mode, and hence protects L1 from L2.
131+
*/
132+
static inline void kvm_nested_vmexit_handle_ibrs(struct kvm_vcpu *vcpu)
133+
{
134+
if (cpu_feature_enabled(X86_FEATURE_AMD_IBRS_SAME_MODE))
135+
return;
136+
137+
if (guest_cpu_cap_has(vcpu, X86_FEATURE_SPEC_CTRL) ||
138+
guest_cpu_cap_has(vcpu, X86_FEATURE_AMD_IBRS))
139+
indirect_branch_prediction_barrier();
140+
}
141+
124142
static inline bool kvm_vcpu_has_run(struct kvm_vcpu *vcpu)
125143
{
126144
return vcpu->arch.last_vmentry_cpu != -1;

0 commit comments

Comments
 (0)