FAILED: patch "[PATCH] KVM: x86: Fill kvm_run exit fields in common" failed to apply to 6.12-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x c1214f293d77c6e425a379f90d09bdb4815993a8
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026092939-nearness-debtor-eebf@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From c1214f293d77c6e425a379f90d09bdb4815993a8 Mon Sep 17 00:00:00 2001
From: Sean Christopherson <[email protected]>
Date: Mon, 21 Sep 2026 14:16:08 -0700
Subject: [PATCH] KVM: x86: Fill kvm_run exit fields in common
get_nested_state_pages() error paths
Fill kvm_run with "internal error, emulation" in the common error handling paths for getting nested state pages, as requiring each check to manually fill kvm_run is error prone and requires a non-trivial amount of copy+paste.
Specifically, both SVM and VMX fail to fill kvm_run if load_pdptrs() fails, and SVM fails to fill kvm_run if kvm_hv_verify_vp_assist() fails. If those flows fail, the *best* case scenario is that KVM will exit to userspace with KVM_EXIT_UNKNOWN. The worst case scenario is that KVM exits with a stale exit_reason and confuses userspace.
Note, SVM never exits to userspace if something goes sideways when dealing with vmcb12 assets while emulating VMRUN, i.e. lack of SVM-specific code is not a bug.
arch/x86/kvm/svm/nested.c +1 -6
@@ -2125,13 +2125,8 @@ static bool svm_get_nested_state_pages(struct kvm_vcpu *vcpu)return false; } -if (!nested_svm_merge_msrpm (vcpu)) { - vcpu->run->exit_reason =KVM_EXIT_INTERNAL_ERROR ; - vcpu->run->internal.suberror = -KVM_INTERNAL_ERROR_EMULATION ; - vcpu->run->internal.ndata =0 ; +if (!nested_svm_merge_msrpm (vcpu))return false; - }if (kvm_hv_verify_vp_assist (vcpu))return false;
arch/x86/kvm/vmx/nested.c +5 -10
@@ -3465,10 +3465,6 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu) }else {pr_debug_ratelimited ("%s: no backing for APIC-access address in vmcs12\n" , __func__); - vcpu->run->exit_reason =KVM_EXIT_INTERNAL_ERROR ; - vcpu->run->internal.suberror = -KVM_INTERNAL_ERROR_EMULATION ; - vcpu->run->internal.ndata =0 ;return false; } }
@@ -3539,11 +3535,6 @@ static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu)if (!nested_get_evmcs_page (vcpu)) {pr_debug_ratelimited ("%s: enlightened vmptrld failed\n" , __func__); - vcpu->run->exit_reason =KVM_EXIT_INTERNAL_ERROR ; - vcpu->run->internal.suberror = -KVM_INTERNAL_ERROR_EMULATION ; - vcpu->run->internal.ndata =0 ; -return false; }#endif
@@ -3915,8 +3906,12 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) vmentry_failed: vcpu->arch.nested_run_pending =0 ; -if (status ==NVMX_VMENTRY_KVM_INTERNAL_ERROR ) +if (status ==NVMX_VMENTRY_KVM_INTERNAL_ERROR ) { + vcpu->run->exit_reason =KVM_EXIT_INTERNAL_ERROR ; + vcpu->run->internal.suberror =KVM_INTERNAL_ERROR_EMULATION ; + vcpu->run->internal.ndata =0 ;return 0 ; + }if (status ==NVMX_VMENTRY_VMEXIT )return 1 ;WARN_ON_ONCE (status !=NVMX_VMENTRY_VMFAIL );
arch/x86/kvm/x86.c +3 -0
@@ -8072,6 +8072,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)if (kvm_check_request (KVM_REQ_GET_NESTED_STATE_PAGES , vcpu)) {if (unlikely (!kvm_nested_call (get_nested_state_pages)(vcpu))) { + vcpu->run->exit_reason =KVM_EXIT_INTERNAL_ERROR ; + vcpu->run->internal.suberror =KVM_INTERNAL_ERROR_EMULATION ; + vcpu->run->internal.ndata =0 ;kvm_make_request (KVM_REQ_GET_NESTED_STATE_PAGES , vcpu); r =0 ; goto out;
Sasha Levin
maintainerPATCH 1/4 KVM: move TSS constants from kvm_host.h to tss.h
From: Paolo Bonzini <[email protected]>
[ Upstream commit 35fdfa632e7cf8271189c7ae6f97e7c4b55f7f80 ]
Stable-dep-of: c1214f293d77 ("KVM: x86: Fill kvm_run exit fields in common get_nested_state_pages() error paths")
--- arch/x86/include/asm/kvm_host.h | 7 ------- arch/x86/kvm/tss.h | 7 +++++++ arch/x86/kvm/vmx/vmx.c | 1 + 3 files changed, 8 insertions(+), 7 deletions(-)
arch/x86/include/asm/kvm_host.h +0 -7
@@ -2259,13 +2259,6 @@ static inline void kvm_inject_gp(struct kvm_vcpu *vcpu, u32 error_code)kvm_queue_exception_e (vcpu,GP_VECTOR , error_code); } -#define TSS_IOPB_BASE_OFFSET 0x66 -#define TSS_BASE_SIZE 0x68 -#define TSS_IOPB_SIZE (65536 / 8) -#define TSS_REDIRECTION_SIZE (256 / 8) -#define RMODE_TSS_SIZE \ - (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1) -enum {TASK_SWITCH_CALL =0 ,TASK_SWITCH_IRET =1 ,
arch/x86/kvm/tss.h +7 -0
@@ -57,4 +57,11 @@ struct tss_segment_16 { u16 ldt; }; +#define TSS_IOPB_BASE_OFFSET 0x66 +#define TSS_BASE_SIZE 0x68 +#define TSS_IOPB_SIZE (65536 / 8) +#define TSS_REDIRECTION_SIZE (256 / 8) +#define RMODE_TSS_SIZE \ + (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1) +#endif
arch/x86/kvm/vmx/vmx.c +1 -0
@@ -71,6 +71,7 @@#include "x86.h" #include "x86_ops.h" #include "smm.h" +#include "tss.h" #include "vmx_onhyperv.h" #include "posted_intr.h"
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/4 KVM: x86: Reject nested CAP enablement if nested virtualization is disabled
From: Sean Christopherson <[email protected]>
[ Upstream commit b65699be2c606d2687593516d93e66d16a713b61 ]
Add a flag to explicitly track if nested virtualization is enabled, and use it enumerate that various nested CAPs are unsupported, and to reject enablement of said CAPs. When the nested ops hooks were moved to their own structure, KVM's NULL-by-default behavior was deliberately dropped, with the changelog asserting that all was well. That wasn't quite true; there is no danger to KVM, but now KVM is over-reporting support for KVM_CAP_NESTED_STATE and KVM_CAP_HYPERV_ENLIGHTENED_VMCS.
Stable-dep-of: c1214f293d77 ("KVM: x86: Fill kvm_run exit fields in common get_nested_state_pages() error paths")
--- arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/kvm/hyperv.c | 3 ++- arch/x86/kvm/svm/svm.c | 1 + arch/x86/kvm/vmx/vmx.c | 1 + arch/x86/kvm/x86.c | 12 +++++++----- 5 files changed, 13 insertions(+), 6 deletions(-)
arch/x86/include/asm/kvm_host.h +2 -0
@@ -1852,6 +1852,8 @@ struct kvm_x86_ops { };struct kvm_x86_nested_ops { +bool enabled; +void (*leave_nested)(struct kvm_vcpu *vcpu);bool (*is_exception_vmexit)(struct kvm_vcpu *vcpu,u8 vector,u32 error_code);
arch/x86/kvm/hyperv.c +2 -1
@@ -2798,7 +2798,8 @@ int kvm_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid, };int i, nent =ARRAY_SIZE (cpuid_entries); -if (kvm_x86_ops.nested_ops->get_evmcs_version) +if (kvm_x86_ops.nested_ops->enabled && + kvm_x86_ops.nested_ops->get_evmcs_version) evmcs_ver = kvm_x86_ops.nested_ops->get_evmcs_version (vcpu);if (cpuid->nent < nent)
arch/x86/kvm/svm/svm.c +1 -0
@@ -5491,6 +5491,7 @@ static __init int svm_hardware_setup(void)pr_info ("Nested Virtualization enabled\n" );kvm_enable_efer_bits (EFER_SVME |EFER_LMSLE ); } + svm_nested_ops.enabled = nested;/* * KVM's MMU doesn't support using 2-level paging for itself, and thus
arch/x86/kvm/vmx/vmx.c +1 -0
@@ -8571,6 +8571,7 @@ __init int vmx_hardware_setup(void)if (r)return r; } + vmx_nested_ops.enabled = nested;vmx_set_cpu_caps ();
arch/x86/kvm/x86.c +7 -5
@@ -4764,7 +4764,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r =KVM_X2APIC_API_VALID_FLAGS ;break ;case KVM_CAP_NESTED_STATE : - r = kvm_x86_ops.nested_ops->get_state ? + r = kvm_x86_ops.nested_ops->enabled ? kvm_x86_ops.nested_ops->get_state (NULL ,NULL ,0 ) :0 ;break ;#ifdef CONFIG_KVM_HYPERV
@@ -4772,7 +4772,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = kvm_x86_ops.enable_l2_tlb_flush !=NULL ;break ;case KVM_CAP_HYPERV_ENLIGHTENED_VMCS : - r = kvm_x86_ops.nested_ops->enable_evmcs !=NULL ; + r = kvm_x86_ops.nested_ops->enabled && + kvm_x86_ops.nested_ops->enable_evmcs !=NULL ;break ;#endif case KVM_CAP_SMALLER_MAXPHYADDR :
@@ -5846,7 +5847,8 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,uint16_t vmcs_version;void __user *user_ptr; -if (!kvm_x86_ops.nested_ops->enable_evmcs) +if (!kvm_x86_ops.nested_ops->enabled || + !kvm_x86_ops.nested_ops->enable_evmcs)return -ENOTTY ; r = kvm_x86_ops.nested_ops->enable_evmcs (vcpu, &vmcs_version);if (!r) {
@@ -6210,7 +6212,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,u32 user_data_size; r = -EINVAL ; -if (!kvm_x86_ops.nested_ops->get_state) +if (!kvm_x86_ops.nested_ops->enabled)break ;BUILD_BUG_ON (sizeof (user_data_size) !=sizeof (user_kvm_nested_state->size));
@@ -6240,7 +6242,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,int idx; r = -EINVAL ; -if (!kvm_x86_ops.nested_ops->set_state) +if (!kvm_x86_ops.nested_ops->enabled)break ; r = -EFAULT ;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/4 KVM: x86: Add static calls for nested virtualization ops
In reply to Sasha LevinFrom: Sean Christopherson <[email protected]>
[ Upstream commit 4b9819a50674dd40d176033f9ea2e23a70889dc6 ]
Use static calls to invoke nested virtualization ops, as many of the calls are in relatively hot paths when L2 is active, e.g. checking for events, and because there's no reason not use static calls these days.
Opportunistically use a RET0 static call for get_evmcs_version() instead of manually checking for a non-NULL vendor hook.
[6.12 dependency adaptation for c1214f293d77:
Keep the existing exception reinjection guard and vendor init/exit prototypes. Drop the translate_nested_gpa conversion, since 6.12 calls that helper directly and has no corresponding nested operation. Initialize nested static calls in the existing kvm_ops_update() instead of adding kvm_nested_ops_update(); do not import unrelated upstream setup helpers.
Prepare the remaining target contexts using the existing SVM MSRPM helper rename from 925149b6d0540, the nested_run_pending field move from 3d4470d71fbf7, and the request retry from 10180a2775493. Update all existing users of the moved field. Add braces around SVM's existing PDPTR load condition without changing its behavior, so the target patch also applies directly. These changes add no functions and leave the target's common error-exit initialization to c1214f293d77.]
[ sashal: Reduced backport -- upstream 4b9819a50674d touches 7 file(s), this
backport carries 12. Not backported here:
arch/x86/kvm/mmu.h
This note is generated from the file lists only; see the resolution record for the reasoning. ]
Stable-dep-of: c1214f293d77 ("KVM: x86: Fill kvm_run exit fields in common get_nested_state_pages() error paths")
--- arch/x86/include/asm/kvm-x86-nested-ops.h | 35 ++++++++++++++++ arch/x86/include/asm/kvm_host.h | 17 ++++++++ arch/x86/kvm/hyperv.c | 7 ++-- arch/x86/kvm/mmu/paging_tmpl.h | 2 +- arch/x86/kvm/svm/nested.c | 30 ++++++------- arch/x86/kvm/svm/svm.c | 14 +++---- arch/x86/kvm/svm/svm.h | 4 -- arch/x86/kvm/vmx/nested.c | 42 +++++++++---------- arch/x86/kvm/vmx/vmx.c | 14 +++---- arch/x86/kvm/vmx/vmx.h | 3 -- arch/x86/kvm/x86.c | 51 +++++++++++++++-------- arch/x86/kvm/x86.h | 2 +- 12 files changed, 140 insertions(+), 81 deletions(-) create mode 100644 arch/x86/include/asm/kvm-x86-nested-ops.h
arch/x86/include/asm/kvm-x86-nested-ops.h new file +35 -0
@@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#if !defined(KVM_X86_NESTED_OP ) || \ + !defined(KVM_X86_NESTED_OP_OPTIONAL ) || \ + !defined(KVM_X86_NESTED_OP_OPTIONAL_RET0 ) +#error Missing one or more KVM_X86_NESTED_OP #defines +#else +/* +* KVM_X86_NESTED_OP() and KVM_X86_NESTED_OP_OPTIONAL() are used to help +* generate both DECLARE/DEFINE_STATIC_CALL() invocations and +* "static_call_update()" calls. +* +* KVM_X86_NESTED_OP_OPTIONAL() can be used for those functions that can have +* a NULL definition. KVM_X86_NESTED_OP_OPTIONAL_RET0() can be used likewise +* to make a definition optional, but in this case the default will +* be __static_call_return0. +*/ +KVM_X86_NESTED_OP(leave_nested) +KVM_X86_NESTED_OP(is_exception_vmexit) +KVM_X86_NESTED_OP(check_events) +KVM_X86_NESTED_OP_OPTIONAL_RET0(has_events) +KVM_X86_NESTED_OP(triple_fault) +KVM_X86_NESTED_OP(get_state) +KVM_X86_NESTED_OP(set_state) +KVM_X86_NESTED_OP(get_nested_state_pages) +KVM_X86_NESTED_OP_OPTIONAL_RET0(write_log_dirty) +#ifdef CONFIG_KVM_HYPERV +KVM_X86_NESTED_OP_OPTIONAL(enable_evmcs) +KVM_X86_NESTED_OP_OPTIONAL_RET0(get_evmcs_version) +KVM_X86_NESTED_OP(hv_inject_synthetic_vmexit_post_tlb_flush) +#endif +#endif + +#undef KVM_X86_NESTED_OP +#undef KVM_X86_NESTED_OP_OPTIONAL +#undef KVM_X86_NESTED_OP_OPTIONAL_RET0
arch/x86/include/asm/kvm_host.h +17 -0
@@ -1040,6 +1040,15 @@ struct kvm_vcpu_arch {*/ bool pdptrs_from_userspace; +/* +* Set if an emulated nested VM-Enter to L2 is pending completion. KVM +* must not synthesize a VM-Exit to L1 before entering L2, as VM-Exits +* can only occur at instruction boundaries. The only exception is +* VMX's "notify" exits, which exist in large part to break the CPU out +* of infinite ucode loops, but can corrupt vCPU state in the process! +*/ +bool nested_run_pending; +#if IS_ENABLED (CONFIG_HYPERV )hpa_t hv_root_tdp;#endif
@@ -1905,6 +1914,14 @@ extern struct kvm_x86_ops kvm_x86_ops;#define KVM_X86_OP_OPTIONAL_RET0 KVM_X86_OP#include <asm/kvm-x86-ops.h> +#define kvm_nested_call (func) static_call(kvm_x86_nested_##func) + +#define KVM_X86_NESTED_OP (func) \ + DECLARE_STATIC_CALL(kvm_x86_nested_##func, *(((struct kvm_x86_nested_ops *)0)->func)); +#define KVM_X86_NESTED_OP_OPTIONAL KVM_X86_NESTED_OP +#define KVM_X86_NESTED_OP_OPTIONAL_RET0 KVM_X86_NESTED_OP +#include <asm/kvm-x86-nested-ops.h> +int kvm_x86_vendor_init (struct kvm_x86_init_ops *ops);void kvm_x86_vendor_exit (void );
arch/x86/kvm/hyperv.c +3 -4
@@ -2414,7 +2414,7 @@ static int kvm_hv_hypercall_complete(struct kvm_vcpu *vcpu, u64 result) ret =kvm_skip_emulated_instruction (vcpu);if (tlb_lock_count) - kvm_x86_ops.nested_ops->hv_inject_synthetic_vmexit_post_tlb_flush (vcpu); +kvm_nested_call (hv_inject_synthetic_vmexit_post_tlb_flush)(vcpu);return ret; }
@@ -2798,9 +2798,8 @@ int kvm_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid, };int i, nent =ARRAY_SIZE (cpuid_entries); -if (kvm_x86_ops.nested_ops->enabled && - kvm_x86_ops.nested_ops->get_evmcs_version) - evmcs_ver = kvm_x86_ops.nested_ops->get_evmcs_version (vcpu); +if (kvm_x86_ops.nested_ops->enabled) + evmcs_ver =kvm_nested_call (get_evmcs_version)(vcpu);if (cpuid->nent < nent)return -E2BIG ;
arch/x86/kvm/mmu/paging_tmpl.h +1 -1
@@ -222,7 +222,7 @@ static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu, !(pte & PT_GUEST_DIRTY_MASK)) {trace_kvm_mmu_set_dirty_bit (table_gfn, index,sizeof (pte));#if PTTYPE ==PTTYPE_EPT -if (kvm_x86_ops.nested_ops->write_log_dirty (vcpu, addr)) +if (kvm_nested_call (write_log_dirty)(vcpu, addr))return -EINVAL ;#endif pte |=PT_GUEST_DIRTY_MASK ;
arch/x86/kvm/svm/nested.c +15 -15
@@ -184,8 +184,9 @@ void recalc_intercepts(struct vcpu_svm *svm)* is optimized in that it only merges the parts where KVM MSR permission bitmap * may contain zero bits. */ -static bool nested_svm_vmrun_msrpm (struct vcpu_svm *svm) +static bool nested_svm_merge_msrpm (struct kvm_vcpu *vcpu) { +struct vcpu_svm *svm =to_svm (vcpu);int i;/*
@@ -200,7 +201,7 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)if (!svm->nested.force_msr_bitmap_recalc) {struct hv_vmcb_enlightenments *hve = &svm->nested.ctl.hv_enlightenments; -if (kvm_hv_hypercall_enabled (&svm->vcpu) && +if (kvm_hv_hypercall_enabled (vcpu) && hve->hv_enlightenments_control.msr_bitmap && (svm->nested.ctl.clean &BIT (HV_VMCB_NESTED_ENLIGHTENMENTS ))) goto set_msrpm_base_pa;
@@ -225,7 +226,7 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm) offset = svm->nested.ctl.msrpm_base_pa + (p *4 ); -if (kvm_vcpu_read_guest (&svm->vcpu, offset, &value,4 )) +if (kvm_vcpu_read_guest (vcpu, offset, &value,4 ))return false; svm->nested.msrpm[p] = svm->msrpm[p] | value;
@@ -916,16 +917,16 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)if (!npt_enabled) vmcb01->save.cr3 =kvm_read_cr3 (vcpu); - svm->nested.nested_run_pending =1 ; + vcpu->arch.nested_run_pending =1 ;if (enter_svm_guest_mode (vcpu, vmcb12_gpa, vmcb12, true)) goto out_exit_err; -if (nested_svm_vmrun_msrpm (svm)) +if (nested_svm_merge_msrpm (vcpu)) goto out; out_exit_err: - svm->nested.nested_run_pending =0 ; + vcpu->arch.nested_run_pending =0 ; svm->vmcb->control.exit_code =SVM_EXIT_ERR ; svm->vmcb->control.exit_code_hi =-1u ;
@@ -998,7 +999,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm)/* Exit Guest-Mode */ leave_guest_mode (vcpu); svm->nested.vmcb12_gpa =0 ; -WARN_ON_ONCE (svm->nested.nested_run_pending); +WARN_ON_ONCE (vcpu->arch.nested_run_pending);kvm_clear_request (KVM_REQ_GET_NESTED_STATE_PAGES , vcpu);
@@ -1247,7 +1248,7 @@ void svm_leave_nested(struct kvm_vcpu *vcpu)struct vcpu_svm *svm =to_svm (vcpu);if (is_guest_mode (vcpu)) { - svm->nested.nested_run_pending =0 ; + vcpu->arch.nested_run_pending =0 ; svm->nested.vmcb12_gpa =INVALID_GPA ;leave_guest_mode (vcpu);
@@ -1443,7 +1444,7 @@ static int svm_check_nested_events(struct kvm_vcpu *vcpu)* previously injected event, the pending exception occurred while said * event was being delivered and thus needs to be handled. */ -bool block_nested_exceptions = svm->nested.nested_run_pending; +bool block_nested_exceptions = vcpu->arch.nested_run_pending;/* * New events (not exceptions) are only recognized at instruction * boundaries. If an event needs reinjection, then KVM is handling a
@@ -1618,7 +1619,7 @@ static int svm_get_nested_state(struct kvm_vcpu *vcpu, kvm_state.size +=KVM_STATE_NESTED_SVM_VMCB_SIZE ; kvm_state.flags |=KVM_STATE_NESTED_GUEST_MODE ; -if (svm->nested.nested_run_pending) +if (vcpu->arch.nested_run_pending) kvm_state.flags |=KVM_STATE_NESTED_RUN_PENDING ; }
@@ -1757,7 +1758,7 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,svm_set_gif (svm, !!(kvm_state->flags &KVM_STATE_NESTED_GIF_SET )); - svm->nested.nested_run_pending = + vcpu->arch.nested_run_pending = !!(kvm_state->flags &KVM_STATE_NESTED_RUN_PENDING ); svm->nested.vmcb12_gpa = kvm_state->hdr.svm.vmcb_pa;
@@ -1801,13 +1802,11 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,static bool svm_get_nested_state_pages (struct kvm_vcpu *vcpu) { -struct vcpu_svm *svm =to_svm (vcpu); -if (WARN_ON (!is_guest_mode (vcpu)))return true;if (!vcpu->arch.pdptrs_from_userspace && - !nested_npt_enabled (svm) &&is_pae_paging (vcpu)) + !nested_npt_enabled (to_svm (vcpu)) &&is_pae_paging (vcpu)) {/* * Reload the guest's PDPTRs since after a migration * the guest CR3 might be restored prior to setting the nested
@@ -1815,8 +1814,9 @@ static bool svm_get_nested_state_pages(struct kvm_vcpu *vcpu)*/ if (CC (!load_pdptrs (vcpu, vcpu->arch.cr3)))return false; + } -if (!nested_svm_vmrun_msrpm (svm)) { +if (!nested_svm_merge_msrpm (vcpu)) { vcpu->run->exit_reason =KVM_EXIT_INTERNAL_ERROR ; vcpu->run->internal.suberror =KVM_INTERNAL_ERROR_EMULATION ;
arch/x86/kvm/svm/svm.c +7 -7
@@ -3151,7 +3151,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)* * For nested: * The handling of the MSR bitmap for L2 guests is done in -* nested_svm_vmrun_msrpm. +* nested_svm_merge_msrpm(). * We update the L1 MSR bit as well since it will end up * touching the MSR anyway now. */
@@ -3909,7 +3909,7 @@ bool svm_nmi_blocked(struct kvm_vcpu *vcpu)static int svm_nmi_allowed (struct kvm_vcpu *vcpu,bool for_injection) {struct vcpu_svm *svm =to_svm (vcpu); -if (svm->nested.nested_run_pending) +if (vcpu->arch.nested_run_pending)return -EBUSY ;if (svm_nmi_blocked (vcpu))
@@ -3951,7 +3951,7 @@ static int svm_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection) {struct vcpu_svm *svm =to_svm (vcpu); -if (svm->nested.nested_run_pending) +if (vcpu->arch.nested_run_pending)return -EBUSY ;if (svm_interrupt_blocked (vcpu))
@@ -4433,11 +4433,11 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)nested_sync_control_from_vmcb02 (svm);/* Track VMRUNs that have made past consistency checking */ -if (svm->nested.nested_run_pending && +if (vcpu->arch.nested_run_pending && svm->vmcb->control.exit_code !=SVM_EXIT_ERR ) ++vcpu->stat.nested_run; - svm->nested.nested_run_pending =0 ; + vcpu->arch.nested_run_pending =0 ; } svm->vmcb->control.tlb_ctl =TLB_CONTROL_DO_NOTHING ;
@@ -4818,7 +4818,7 @@ bool svm_smi_blocked(struct kvm_vcpu *vcpu)static int svm_smi_allowed (struct kvm_vcpu *vcpu,bool for_injection) {struct vcpu_svm *svm =to_svm (vcpu); -if (svm->nested.nested_run_pending) +if (vcpu->arch.nested_run_pending)return -EBUSY ;if (svm_smi_blocked (vcpu))
@@ -4940,7 +4940,7 @@ static int svm_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram)if (ret) goto unmap_save; - svm->nested.nested_run_pending =1 ; + vcpu->arch.nested_run_pending =1 ; unmap_save:kvm_vcpu_unmap (vcpu, &map_save, true);
arch/x86/kvm/svm/svm.h +0 -4
@@ -189,10 +189,6 @@ struct svm_nested_state {/* These are the merged vectors */ u32 *msrpm; -/* A VMRUN has started but has not yet been performed, so -* we cannot inject a nested vmexit yet. */ -bool nested_run_pending; -/* cache for control fields of the guest */ struct vmcb_ctrl_area_cached ctl;
arch/x86/kvm/vmx/nested.c +21 -21
163 lines not on this page · raw message
arch/x86/kvm/vmx/vmx.c +7 -7
@@ -5082,7 +5082,7 @@ bool vmx_nmi_blocked(struct kvm_vcpu *vcpu)int vmx_nmi_allowed (struct kvm_vcpu *vcpu,bool for_injection) { -if (to_vmx (vcpu)->nested.nested_run_pending) +if (vcpu->arch.nested_run_pending)return -EBUSY ;/* An NMI must not be injected into L2 if it's supposed to VM-Exit. */
@@ -5109,7 +5109,7 @@ bool vmx_interrupt_blocked(struct kvm_vcpu *vcpu)int vmx_interrupt_allowed (struct kvm_vcpu *vcpu,bool for_injection) { -if (to_vmx (vcpu)->nested.nested_run_pending) +if (vcpu->arch.nested_run_pending)return -EBUSY ;/*
@@ -6462,7 +6462,7 @@ static int __vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)* invalid guest state should never happen as that means KVM knowingly * allowed a nested VM-Enter with an invalid vmcs12. More below. */ -if (KVM_BUG_ON (vmx->nested.nested_run_pending, vcpu->kvm)) +if (KVM_BUG_ON (vcpu->arch.nested_run_pending, vcpu->kvm))return -EIO ;if (is_guest_mode (vcpu)) {
@@ -7468,11 +7468,11 @@ fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)* Track VMLAUNCH/VMRESUME that have made past guest state * checking. */ -if (vmx->nested.nested_run_pending && +if (vcpu->arch.nested_run_pending && !vmx->exit_reason.failed_vmentry) ++vcpu->stat.nested_run; - vmx->nested.nested_run_pending =0 ; + vcpu->arch.nested_run_pending =0 ; }if (unlikely (vmx->fail))
@@ -8204,7 +8204,7 @@ void vmx_setup_mce(struct kvm_vcpu *vcpu)int vmx_smi_allowed (struct kvm_vcpu *vcpu,bool for_injection) {/* we need a nested vmexit to enter SMM, postpone if run is pending */ -if (to_vmx (vcpu)->nested.nested_run_pending) +if (vcpu->arch.nested_run_pending)return -EBUSY ;return !is_smm (vcpu); }
@@ -8245,7 +8245,7 @@ int vmx_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram)if (ret)return ret; - vmx->nested.nested_run_pending =1 ; + vcpu->arch.nested_run_pending =1 ; vmx->nested.smm.guest_mode = false; }return 0 ;
arch/x86/kvm/vmx/vmx.h +0 -3
@@ -185,9 +185,6 @@ struct nested_vmx {*/ bool enlightened_vmcs_enabled; -/* L2 must run next, and mustn't decide to exit to L1. */ -bool nested_run_pending; -/* Pending MTF VM-exit into L1. */ bool mtf_pending;
arch/x86/kvm/x86.c +33 -18
138 lines not on this page · raw message
arch/x86/kvm/x86.h +1 -1
@@ -116,7 +116,7 @@ int kvm_check_nested_events(struct kvm_vcpu *vcpu);/* Forcibly leave the nested mode in cases like a vCPU reset */ static inline void kvm_leave_nested (struct kvm_vcpu *vcpu) { - kvm_x86_ops.nested_ops->leave_nested (vcpu); +kvm_nested_call (leave_nested)(vcpu); }static inline bool kvm_vcpu_has_run (struct kvm_vcpu *vcpu)
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/4 KVM: x86: Fill kvm_run exit fields in common get_nested_state_pages() error paths
In reply to Sasha LevinFrom: Sean Christopherson <[email protected]>
[ Upstream commit c1214f293d77c6e425a379f90d09bdb4815993a8 ]
Fill kvm_run with "internal error, emulation" in the common error handling paths for getting nested state pages, as requiring each check to manually fill kvm_run is error prone and requires a non-trivial amount of copy+paste.
Specifically, both SVM and VMX fail to fill kvm_run if load_pdptrs() fails, and SVM fails to fill kvm_run if kvm_hv_verify_vp_assist() fails. If those flows fail, the *best* case scenario is that KVM will exit to userspace with KVM_EXIT_UNKNOWN. The worst case scenario is that KVM exits with a stale exit_reason and confuses userspace.
Note, SVM never exits to userspace if something goes sideways when dealing with vmcb12 assets while emulating VMRUN, i.e. lack of SVM-specific code is not a bug.
--- arch/x86/kvm/svm/nested.c | 7 +------ arch/x86/kvm/vmx/nested.c | 15 +++++---------- arch/x86/kvm/x86.c | 3 +++ 3 files changed, 9 insertions(+), 16 deletions(-)
arch/x86/kvm/svm/nested.c +1 -6
@@ -1816,13 +1816,8 @@ static bool svm_get_nested_state_pages(struct kvm_vcpu *vcpu)return false; } -if (!nested_svm_merge_msrpm (vcpu)) { - vcpu->run->exit_reason =KVM_EXIT_INTERNAL_ERROR ; - vcpu->run->internal.suberror = -KVM_INTERNAL_ERROR_EMULATION ; - vcpu->run->internal.ndata =0 ; +if (!nested_svm_merge_msrpm (vcpu))return false; - }if (kvm_hv_verify_vp_assist (vcpu))return false;
arch/x86/kvm/vmx/nested.c +5 -10
@@ -3355,10 +3355,6 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu) }else {pr_debug_ratelimited ("%s: no backing for APIC-access address in vmcs12\n" , __func__); - vcpu->run->exit_reason =KVM_EXIT_INTERNAL_ERROR ; - vcpu->run->internal.suberror = -KVM_INTERNAL_ERROR_EMULATION ; - vcpu->run->internal.ndata =0 ;return false; } }
@@ -3429,11 +3425,6 @@ static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu)if (!nested_get_evmcs_page (vcpu)) {pr_debug_ratelimited ("%s: enlightened vmptrld failed\n" , __func__); - vcpu->run->exit_reason =KVM_EXIT_INTERNAL_ERROR ; - vcpu->run->internal.suberror = -KVM_INTERNAL_ERROR_EMULATION ; - vcpu->run->internal.ndata =0 ; -return false; }#endif
@@ -3831,8 +3822,12 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) vmentry_failed: vcpu->arch.nested_run_pending =0 ; -if (status ==NVMX_VMENTRY_KVM_INTERNAL_ERROR ) +if (status ==NVMX_VMENTRY_KVM_INTERNAL_ERROR ) { + vcpu->run->exit_reason =KVM_EXIT_INTERNAL_ERROR ; + vcpu->run->internal.suberror =KVM_INTERNAL_ERROR_EMULATION ; + vcpu->run->internal.ndata =0 ;return 0 ; + }if (status ==NVMX_VMENTRY_VMEXIT )return 1 ;WARN_ON_ONCE (status !=NVMX_VMENTRY_VMFAIL );
arch/x86/kvm/x86.c +3 -0
@@ -10827,6 +10827,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)if (kvm_check_request (KVM_REQ_GET_NESTED_STATE_PAGES , vcpu)) {if (unlikely (!kvm_nested_call (get_nested_state_pages)(vcpu))) { + vcpu->run->exit_reason =KVM_EXIT_INTERNAL_ERROR ; + vcpu->run->internal.suberror =KVM_INTERNAL_ERROR_EMULATION ; + vcpu->run->internal.ndata =0 ;kvm_make_request (KVM_REQ_GET_NESTED_STATE_PAGES , vcpu); r =0 ; goto out;
Signature · 1 line
2.53.0