--- /dev/null
+From clopez@suse.de Thu Jul 9 15:28:56 2026
+From: "Carlos López" <clopez@suse.de>
+Date: Thu, 9 Jul 2026 15:21:08 +0200
+Subject: KVM: VMX: Grab vmcs12 on CR8 interception update iff vCPU is in guest mode
+To: stable@vger.kernel.org
+Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, gregkh@linuxfoundation.org, "Sean Christopherson" <seanjc@google.com>, "syzbot ci" <syzbot+ci493c6d734b63e050@syzkaller.appspotmail.com>, "Paolo Bonzini" <pbonzini@redhat.com>, "Carlos López" <clopez@suse.de>, "Thomas Gleixner" <tglx@kernel.org>, "Ingo Molnar" <mingo@redhat.com>, "Borislav Petkov" <bp@alien8.de>, "Dave Hansen" <dave.hansen@linux.intel.com>, x86@kernel.org (maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT)), "H. Peter Anvin" <hpa@zytor.com>
+Message-ID: <20260709132109.3423488-4-clopez@suse.de>
+
+From: Sean Christopherson <seanjc@google.com>
+
+[ Upstream commit 7ef78d71ca713d8c00f7c34ddcf276c808143f77 ]
+
+When updating CR8 intercepts, get vmcs12 if and only if the vCPU is in
+guest mode so that a future change can have update CR8 intercepts during
+vCPU creation, without running afoul of get_vmcs12()'s lockdep assertion.
+
+ ------------[ cut here ]------------
+ debug_locks && !(lock_is_held(&(&vcpu->mutex)->dep_map) || !refcount_read(&vcpu->kvm->users_count))
+ WARNING: arch/x86/kvm/vmx/nested.h:61 at get_vmcs12 arch/x86/kvm/vmx/nested.h:60 [inline], CPU#0: syz.2.19/5879
+ WARNING: arch/x86/kvm/vmx/nested.h:61 at vmx_update_cr8_intercept+0x3de/0x4e0 arch/x86/kvm/vmx/vmx.c:6879, CPU#0: syz.2.19/5879
+ Modules linked in:
+ CPU: 0 UID: 0 PID: 5879 Comm: syz.2.19 Not tainted syzkaller #0 PREEMPT(full)
+ Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
+ RIP: 0010:get_vmcs12 arch/x86/kvm/vmx/nested.h:60 [inline]
+ RIP: 0010:vmx_update_cr8_intercept+0x3de/0x4e0 arch/x86/kvm/vmx/vmx.c:6879
+ Call Trace:
+ <TASK>
+ apic_update_ppr arch/x86/kvm/lapic.c:984 [inline]
+ kvm_lapic_reset+0x1c24/0x2980 arch/x86/kvm/lapic.c:3023
+ kvm_vcpu_reset+0x44c/0x1bf0 arch/x86/kvm/x86.c:12986
+ kvm_arch_vcpu_create+0x746/0x8b0 arch/x86/kvm/x86.c:12847
+ kvm_vm_ioctl_create_vcpu+0x428/0x930 virt/kvm/kvm_main.c:4201
+ kvm_vm_ioctl+0x893/0xd50 virt/kvm/kvm_main.c:5159
+ vfs_ioctl fs/ioctl.c:51 [inline]
+ __do_sys_ioctl fs/ioctl.c:597 [inline]
+ __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+ </TASK>
+
+No functional change intended.
+
+Reported-by: syzbot ci <syzbot+ci493c6d734b63e050@syzkaller.appspotmail.com>
+Closes: https://lore.kernel.org/all/6a2adf3b.3b0a2d4e.8c8d1.0012.GAE@google.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Message-ID: <20260618174347.1981064-2-seanjc@google.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Carlos López <clopez@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/vmx/vmx.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/arch/x86/kvm/vmx/vmx.c
++++ b/arch/x86/kvm/vmx/vmx.c
+@@ -6855,11 +6855,10 @@ int vmx_handle_exit(struct kvm_vcpu *vcp
+
+ void vmx_update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
+ {
+- struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+ int tpr_threshold;
+
+ if (is_guest_mode(vcpu) &&
+- nested_cpu_has(vmcs12, CPU_BASED_TPR_SHADOW))
++ nested_cpu_has(get_vmcs12(vcpu), CPU_BASED_TPR_SHADOW))
+ return;
+
+ guard(vmx_vmcs01)(vcpu);
--- /dev/null
+From clopez@suse.de Thu Jul 9 15:28:57 2026
+From: "Carlos López" <clopez@suse.de>
+Date: Thu, 9 Jul 2026 15:21:07 +0200
+Subject: KVM: x86: Move update_cr8_intercept() to lapic.c
+To: stable@vger.kernel.org
+Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, gregkh@linuxfoundation.org, "Sean Christopherson" <seanjc@google.com>, "Kai Huang" <kai.huang@intel.com>, "Yosry Ahmed" <yosry@kernel.org>, "Carlos López" <clopez@suse.de>, "Paolo Bonzini" <pbonzini@redhat.com>, "Thomas Gleixner" <tglx@kernel.org>, "Ingo Molnar" <mingo@redhat.com>, "Borislav Petkov" <bp@alien8.de>, "Dave Hansen" <dave.hansen@linux.intel.com>, x86@kernel.org (maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT)), "H. Peter Anvin" <hpa@zytor.com>
+Message-ID: <20260709132109.3423488-3-clopez@suse.de>
+
+From: Sean Christopherson <seanjc@google.com>
+
+[ Upstream Commit c7722e5e1daeeabbd9f969554d52bb7158120b27 ]
+
+Move update_cr8_intercept() to lapic.c so that it's globally visible
+in anticipation of extracting most of the register-specific code out of
+x86.c and into a new compilation unit. Opportunistically prefix the
+helper kvm_lapic_ to make its role/scope more obvious.
+
+No functional change intended.
+
+Reviewed-by: Kai Huang <kai.huang@intel.com>
+Reviewed-by: Yosry Ahmed <yosry@kernel.org>
+Link: https://patch.msgid.link/20260529222223.870923-14-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Carlos López <clopez@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/lapic.c | 26 ++++++++++++++++++++++++++
+ arch/x86/kvm/lapic.h | 1 +
+ arch/x86/kvm/x86.c | 34 +++-------------------------------
+ 3 files changed, 30 insertions(+), 31 deletions(-)
+
+--- a/arch/x86/kvm/lapic.c
++++ b/arch/x86/kvm/lapic.c
+@@ -2744,6 +2744,32 @@ u64 kvm_lapic_get_cr8(struct kvm_vcpu *v
+ return (tpr & 0xf0) >> 4;
+ }
+
++void kvm_lapic_update_cr8_intercept(struct kvm_vcpu *vcpu)
++{
++ int max_irr, tpr;
++
++ if (!kvm_x86_ops.update_cr8_intercept)
++ return;
++
++ if (!lapic_in_kernel(vcpu))
++ return;
++
++ if (vcpu->arch.apic->apicv_active)
++ return;
++
++ if (!vcpu->arch.apic->vapic_addr)
++ max_irr = kvm_lapic_find_highest_irr(vcpu);
++ else
++ max_irr = -1;
++
++ if (max_irr != -1)
++ max_irr >>= 4;
++
++ tpr = kvm_lapic_get_cr8(vcpu);
++
++ kvm_x86_call(update_cr8_intercept)(vcpu, tpr, max_irr);
++}
++
+ static void __kvm_apic_set_base(struct kvm_vcpu *vcpu, u64 value)
+ {
+ u64 old_value = vcpu->arch.apic_base;
+--- a/arch/x86/kvm/lapic.h
++++ b/arch/x86/kvm/lapic.h
+@@ -100,6 +100,7 @@ int kvm_apic_accept_events(struct kvm_vc
+ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event);
+ u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
+ void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
++void kvm_lapic_update_cr8_intercept(struct kvm_vcpu *vcpu);
+ void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu);
+ void kvm_apic_set_version(struct kvm_vcpu *vcpu);
+ void kvm_apic_after_set_mcg_cap(struct kvm_vcpu *vcpu);
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -128,7 +128,6 @@ static u64 __read_mostly efer_reserved_b
+ KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST | \
+ KVM_X2APIC_DISABLE_SUPPRESS_EOI_BROADCAST)
+
+-static void update_cr8_intercept(struct kvm_vcpu *vcpu);
+ static void process_nmi(struct kvm_vcpu *vcpu);
+ static void __kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags);
+ static void store_regs(struct kvm_vcpu *vcpu);
+@@ -5340,7 +5339,7 @@ static int kvm_vcpu_ioctl_set_lapic(stru
+ r = kvm_apic_set_state(vcpu, s);
+ if (r)
+ return r;
+- update_cr8_intercept(vcpu);
++ kvm_lapic_update_cr8_intercept(vcpu);
+
+ return 0;
+ }
+@@ -10595,33 +10594,6 @@ static void post_kvm_run_save(struct kvm
+ kvm_run->flags |= KVM_RUN_X86_GUEST_MODE;
+ }
+
+-static void update_cr8_intercept(struct kvm_vcpu *vcpu)
+-{
+- int max_irr, tpr;
+-
+- if (!kvm_x86_ops.update_cr8_intercept)
+- return;
+-
+- if (!lapic_in_kernel(vcpu))
+- return;
+-
+- if (vcpu->arch.apic->apicv_active)
+- return;
+-
+- if (!vcpu->arch.apic->vapic_addr)
+- max_irr = kvm_lapic_find_highest_irr(vcpu);
+- else
+- max_irr = -1;
+-
+- if (max_irr != -1)
+- max_irr >>= 4;
+-
+- tpr = kvm_lapic_get_cr8(vcpu);
+-
+- kvm_x86_call(update_cr8_intercept)(vcpu, tpr, max_irr);
+-}
+-
+-
+ int kvm_check_nested_events(struct kvm_vcpu *vcpu)
+ {
+ if (kvm_test_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
+@@ -11362,7 +11334,7 @@ static int vcpu_enter_guest(struct kvm_v
+ kvm_x86_call(enable_irq_window)(vcpu);
+
+ if (kvm_lapic_enabled(vcpu)) {
+- update_cr8_intercept(vcpu);
++ kvm_lapic_update_cr8_intercept(vcpu);
+ kvm_lapic_sync_to_vapic(vcpu);
+ }
+ }
+@@ -12511,7 +12483,7 @@ static int __set_sregs_common(struct kvm
+ kvm_set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
+ kvm_set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
+
+- update_cr8_intercept(vcpu);
++ kvm_lapic_update_cr8_intercept(vcpu);
+
+ /* Older userspace won't unhalt the vcpu on reset. */
+ if (kvm_vcpu_is_bsp(vcpu) && kvm_rip_read(vcpu) == 0xfff0 &&
--- /dev/null
+From clopez@suse.de Thu Jul 9 15:29:01 2026
+From: "Carlos López" <clopez@suse.de>
+Date: Thu, 9 Jul 2026 15:21:09 +0200
+Subject: KVM: x86: Unconditionally recompute CR8 intercept on PPR update
+To: stable@vger.kernel.org
+Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, gregkh@linuxfoundation.org, "Carlos López" <clopez@suse.de>, "Stefano Garzarella" <sgarzare@redhat.com>, "Sean Christopherson" <seanjc@google.com>, "Paolo Bonzini" <pbonzini@redhat.com>, "Thomas Gleixner" <tglx@kernel.org>, "Ingo Molnar" <mingo@redhat.com>, "Borislav Petkov" <bp@alien8.de>, "Dave Hansen" <dave.hansen@linux.intel.com>, x86@kernel.org (maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT)), "H. Peter Anvin" <hpa@zytor.com>, "Roman Kagan" <rkagan@virtuozzo.com>
+Message-ID: <20260709132109.3423488-5-clopez@suse.de>
+
+From: "Carlos López" <clopez@suse.de>
+
+[ Upstream commit bb365a506b1e6fb050c0fceaad354fe395385ef0 ]
+
+The TPR_THRESHOLD field in the VMCS is used by VMX to induce VM exits
+when the guest's virtual TPR falls under the specified threshold,
+allowing KVM to inject previously masked interrupts.
+
+KVM handles these VM exits in handle_tpr_below_threshold().
+Commit eb90f3417a0c ("KVM: vmx: speed up TPR below threshold vmexits")
+optimized this function by calling apic_update_ppr() instead of raising
+KVM_REQ_EVENT. apic_update_ppr() then raises KVM_REQ_EVENT if there is
+a pending, deliverable interrupt.
+
+However, if there are no new interrupts pending, apic_update_ppr() does
+not issue the request. Thus, kvm_lapic_update_cr8_intercept() and
+vmx_update_cr8_intercept() are not called before VM entry, which results
+in a high, stale TPR_THRESHOLD. This is problematic due to the following
+sentence in 28.2.1.1 "VM-Execution Control Fields" in the SDM:
+
+ The following check is performed if the “use TPR shadow” VM-execution
+ control is 1 and the “virtualize APIC accesses” and “virtual-interrupt
+ delivery” VM-execution controls are both 0: the value of bits 3:0 of
+ the TPR threshold VM-execution control field should not be greater
+ than the value of bits 7:4 of VTPR.
+
+This error condition is typically not observed when KVM runs on a bare
+metal system because modern processors support APICv, which enables
+virtual-interrupt delivery, and which KVM uses when possible. This
+causes the processor to no longer generate TPR-below-threshold exits
+and to no longer check TPR_THRESHOLD on entry. However, when running
+on older platforms, or under nested virtualization on a hypervisor that
+does not support virtual-interrupt delivery and enforces this check
+(like Hyper-V) this can cause a VM entry failure with hardware error
+0x7, as seen in [1].
+
+Call kvm_lapic_update_cr8_intercept() if apic_update_ppr() does not
+find a deliverable interrupt (and thus does not raise KVM_REQ_EVENT).
+Remove calls to kvm_lapic_update_cr8_intercept() on paths that end up in
+apic_update_ppr(), as they now become redundant. This ensures that any
+path that updates the guest's PPR also figures out if KVM needs to wait
+for a TPR change (using TPR_THRESHOLD on VMX or CR8 intercepts on SVM).
+
+Link: https://github.com/coconut-svsm/svsm/issues/1081 [1]
+Tested-by: Stefano Garzarella <sgarzare@redhat.com>
+Cc: stable@vger.kernel.org
+Fixes: eb90f3417a0c ("KVM: vmx: speed up TPR below threshold vmexits")
+Signed-off-by: Carlos López <clopez@suse.de>
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Message-ID: <20260618174347.1981064-3-seanjc@google.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/lapic.c | 2 ++
+ arch/x86/kvm/x86.c | 5 +----
+ 2 files changed, 3 insertions(+), 4 deletions(-)
+
+--- a/arch/x86/kvm/lapic.c
++++ b/arch/x86/kvm/lapic.c
+@@ -980,6 +980,8 @@ static void apic_update_ppr(struct kvm_l
+ if (__apic_update_ppr(apic, &ppr) &&
+ apic_has_interrupt_for_ppr(apic, ppr) != -1)
+ kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
++ else
++ kvm_lapic_update_cr8_intercept(apic->vcpu);
+ }
+
+ void kvm_apic_update_ppr(struct kvm_vcpu *vcpu)
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -5339,7 +5339,6 @@ static int kvm_vcpu_ioctl_set_lapic(stru
+ r = kvm_apic_set_state(vcpu, s);
+ if (r)
+ return r;
+- kvm_lapic_update_cr8_intercept(vcpu);
+
+ return 0;
+ }
+@@ -12453,8 +12452,6 @@ static int __set_sregs_common(struct kvm
+ kvm_register_mark_dirty(vcpu, VCPU_EXREG_CR3);
+ kvm_x86_call(post_set_cr3)(vcpu, sregs->cr3);
+
+- kvm_set_cr8(vcpu, sregs->cr8);
+-
+ *mmu_reset_needed |= vcpu->arch.efer != sregs->efer;
+ kvm_x86_call(set_efer)(vcpu, sregs->efer);
+
+@@ -12483,7 +12480,7 @@ static int __set_sregs_common(struct kvm
+ kvm_set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
+ kvm_set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
+
+- kvm_lapic_update_cr8_intercept(vcpu);
++ kvm_set_cr8(vcpu, sregs->cr8);
+
+ /* Older userspace won't unhalt the vcpu on reset. */
+ if (kvm_vcpu_is_bsp(vcpu) && kvm_rip_read(vcpu) == 0xfff0 &&
mm-khugepaged-write-all-dirty-file-folios-when-colla.patch
slab-recognize-gfp-parameter-as-optional-in-kernel-doc.patch
perf-trace-beauty-fcntl-fix-build-with-older-kernel-headers.patch
+kvm-x86-move-update_cr8_intercept-to-lapic.c.patch
+kvm-vmx-grab-vmcs12-on-cr8-interception-update-iff-vcpu-is-in-guest-mode.patch
+kvm-x86-unconditionally-recompute-cr8-intercept-on-ppr-update.patch