mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 19:13:47 +02:00
KVM: SVM: Recalc instructions intercepts when EFER.SVME is toggled
The AMD APM states that VMRUN, VMLOAD, VMSAVE, CLGI, VMMCALL, and INVLPGA instructions should generate a #UD when EFER.SVME is cleared. Currently, when VMLOAD, VMSAVE, or CLGI are executed in L1 with EFER.SVME cleared, no #UD is generated in certain cases. This is because the intercepts for these instructions are cleared based on whether or not vls or vgif is enabled. The #UD fails to be generated when the intercepts are absent. Fix the missing #UD generation by ensuring that all relevant instructions have intercepts set when SVME.EFER is disabled. VMMCALL is special because KVM's ABI is that VMCALL/VMMCALL are always supported for L1 and never fault. Signed-off-by: Kevin Cheng <chengkev@google.com> [sean: isolate Intel CPU "compatibility" in EFER.SVME=1 path] Reviewed-by: Yosry Ahmed <yosry@kernel.org> Link: https://patch.msgid.link/20260304003010.1108257-3-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
parent
69f779f79e
commit
460c7eb2e7
|
|
@ -245,6 +245,8 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
|
|||
if (svm_gp_erratum_intercept && !sev_guest(vcpu->kvm))
|
||||
set_exception_intercept(svm, GP_VECTOR);
|
||||
}
|
||||
|
||||
kvm_make_request(KVM_REQ_RECALC_INTERCEPTS, vcpu);
|
||||
}
|
||||
|
||||
svm->vmcb->save.efer = efer | EFER_SVME;
|
||||
|
|
@ -1032,27 +1034,31 @@ static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu)
|
|||
}
|
||||
|
||||
/*
|
||||
* No need to toggle VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK here, it is
|
||||
* always set if vls is enabled. If the intercepts are set, the bit is
|
||||
* meaningless anyway.
|
||||
* Intercept instructions that #UD if EFER.SVME=0, as SVME must be set
|
||||
* even when running the guest, i.e. hardware will only ever see
|
||||
* EFER.SVME=1.
|
||||
*
|
||||
* No need to toggle any of the vgif/vls/etc. enable bits here, as they
|
||||
* are set when the VMCB is initialized and never cleared (if the
|
||||
* relevant intercepts are set, the enablements are meaningless anyway).
|
||||
*/
|
||||
if (guest_cpuid_is_intel_compatible(vcpu)) {
|
||||
if (!(vcpu->arch.efer & EFER_SVME)) {
|
||||
svm_set_intercept(svm, INTERCEPT_VMLOAD);
|
||||
svm_set_intercept(svm, INTERCEPT_VMSAVE);
|
||||
svm_set_intercept(svm, INTERCEPT_CLGI);
|
||||
svm_set_intercept(svm, INTERCEPT_STGI);
|
||||
} else {
|
||||
/*
|
||||
* If hardware supports Virtual VMLOAD VMSAVE then enable it
|
||||
* in VMCB and clear intercepts to avoid #VMEXIT.
|
||||
*/
|
||||
if (vls) {
|
||||
if (guest_cpuid_is_intel_compatible(vcpu)) {
|
||||
svm_set_intercept(svm, INTERCEPT_VMLOAD);
|
||||
svm_set_intercept(svm, INTERCEPT_VMSAVE);
|
||||
} else if (vls) {
|
||||
svm_clr_intercept(svm, INTERCEPT_VMLOAD);
|
||||
svm_clr_intercept(svm, INTERCEPT_VMSAVE);
|
||||
}
|
||||
}
|
||||
|
||||
if (vgif) {
|
||||
svm_clr_intercept(svm, INTERCEPT_STGI);
|
||||
svm_clr_intercept(svm, INTERCEPT_CLGI);
|
||||
|
||||
/*
|
||||
* Process pending events when clearing STGI/CLGI intercepts if
|
||||
|
|
@ -1060,8 +1066,13 @@ static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu)
|
|||
* that KVM re-evaluates if the intercept needs to be set again
|
||||
* to track when GIF is re-enabled (e.g. for NMI injection).
|
||||
*/
|
||||
if (svm_has_pending_gif_event(svm))
|
||||
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
|
||||
if (vgif) {
|
||||
svm_clr_intercept(svm, INTERCEPT_CLGI);
|
||||
svm_clr_intercept(svm, INTERCEPT_STGI);
|
||||
|
||||
if (svm_has_pending_gif_event(svm))
|
||||
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
|
||||
}
|
||||
}
|
||||
|
||||
if (kvm_need_rdpmc_intercept(vcpu))
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user