From: Neeraj Upadhyay Set the SVM nested exception bit in EVENT_INJECTION_CTL when injecting a nested exception using FRED event delivery to ensure: 1) A nested exception is injected on a correct stack level. 2) The nested bit defined in FRED stack frame is set. The event stack level used by FRED event delivery depends on whether the event was a nested exception encountered during delivery of an earlier event, because a nested exception is "regarded" as happening on ring 0. E.g., when #PF is configured to use stack level 1 in IA32_FRED_STKLVLS MSR: - nested #PF will be delivered on the stack pointed by FRED_RSP1 MSR when encountered in ring 3 and ring 0. - normal #PF will be delivered on the stack pointed by FRED_RSP0 MSR when encountered in ring 3. The SVM nested-exception support ensures a correct event stack level is chosen when a VM entry injects a nested exception. Signed-off-by: Neeraj Upadhyay Co-developed-by: Shivansh Dhiman Signed-off-by: Shivansh Dhiman Reviewed-by: Nikunj A Dadhania --- Changes in v3: * Use ex->is_nested to check for nested exceptions. Changes in v2: * Replace variable 'nested' with 'is_nested' (Sean Christopherson). * Formatted variables in reverse fir-tree order (Sean Christopherson). --- arch/x86/include/asm/svm.h | 1 + arch/x86/kvm/svm/svm.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index 0570581e251a..1a6d4509b05b 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -664,6 +664,7 @@ static inline void __unused_size_checks(void) #define SVM_EVTINJ_VALID (1 << 31) #define SVM_EVTINJ_VALID_ERR (1 << 11) +#define SVM_EVTINJ_NESTED_EXCEPTION (1 << 13) #define SVM_EVTINJ_RESERVED_BITS ~(SVM_EVTINJ_VEC_MASK | SVM_EVTINJ_TYPE_MASK | \ SVM_EVTINJ_VALID_ERR | SVM_EVTINJ_VALID) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 6c15e8480d25..fb6b94405f88 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -389,6 +389,7 @@ static int svm_update_soft_interrupt_rip(struct kvm_vcpu *vcpu, u8 vector) static void svm_inject_exception(struct kvm_vcpu *vcpu) { struct kvm_queued_exception *ex = &vcpu->arch.exception; + bool is_nested = is_fred_enabled(vcpu) && ex->is_nested; struct vcpu_svm *svm = to_svm(vcpu); kvm_deliver_exception_payload(vcpu, ex); @@ -400,6 +401,7 @@ static void svm_inject_exception(struct kvm_vcpu *vcpu) svm->vmcb->control.event_inj = ex->vector | SVM_EVTINJ_VALID | (ex->has_error_code ? SVM_EVTINJ_VALID_ERR : 0) + | (is_nested ? SVM_EVTINJ_NESTED_EXCEPTION : 0) | SVM_EVTINJ_TYPE_EXEPT; if (is_fred_enabled(vcpu)) @@ -4502,7 +4504,8 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu) kvm_requeue_exception(vcpu, vector, exitintinfo & SVM_EXITINTINFO_VALID_ERR, - error_code, false, event_data); + error_code, exitintinfo & SVM_EVTINJ_NESTED_EXCEPTION, + event_data); break; } case SVM_EXITINTINFO_TYPE_INTR: -- 2.43.0