From: Greg Kroah-Hartman Date: Sat, 25 Jul 2026 06:55:46 +0000 (+0200) Subject: 7.1-stable patches X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=ee235887e829682df7c44782182c462bccd38ec2;p=thirdparty%2Fkernel%2Fstable-queue.git 7.1-stable patches added patches: kvm-nvmx-hide-shadow-vmcs-right-after-vmclear.patch kvm-x86-check-for-invalid-obsolete-root-after-making-mmu-pages-available.patch kvm-x86-mmu-fix-use-after-free-on-vendor-module-reload.patch kvm-x86-only-reset-tsc-deadline-timer-in-apic_timer_expired-on-kvm_run.patch risc-v-kvm-serialize-virtual-interrupt-pending-state-updates.patch --- diff --git a/queue-7.1/kvm-nvmx-hide-shadow-vmcs-right-after-vmclear.patch b/queue-7.1/kvm-nvmx-hide-shadow-vmcs-right-after-vmclear.patch new file mode 100644 index 0000000000..605fb8974e --- /dev/null +++ b/queue-7.1/kvm-nvmx-hide-shadow-vmcs-right-after-vmclear.patch @@ -0,0 +1,54 @@ +From 622ebfac01ba4f9c0060cebd41257fe46fc4a0b3 Mon Sep 17 00:00:00 2001 +From: Hyunwoo Kim +Date: Fri, 17 Jul 2026 12:30:11 +0200 +Subject: KVM: nVMX: Hide shadow VMCS right after VMCLEAR + +From: Hyunwoo Kim + +commit 622ebfac01ba4f9c0060cebd41257fe46fc4a0b3 upstream. + +free_nested() frees the shadow VMCS while vmcs01 still points to it. But +because it is asynchronous with respect to loaded_vmcs_clear(), the vCPU +might migrate before the pointer is cleared and __loaded_vmcs_clear() +may then execute VMCLEAR. + +The VMCS needs to stay attached until its explicit VMCLEAR completes, but +then it can be hidden and the page safely freed. + +Fixes: 355f4fb1405e ("kvm: nVMX: VMCLEAR an active shadow VMCS after last use") +Cc: stable@vger.kernel.org +Signed-off-by: Hyunwoo Kim +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kvm/vmx/nested.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +--- a/arch/x86/kvm/vmx/nested.c ++++ b/arch/x86/kvm/vmx/nested.c +@@ -336,6 +336,7 @@ static void nested_put_vmcs12_pages(stru + static void free_nested(struct kvm_vcpu *vcpu) + { + struct vcpu_vmx *vmx = to_vmx(vcpu); ++ struct vmcs *shadow_vmcs; + + if (WARN_ON_ONCE(vmx->loaded_vmcs != &vmx->vmcs01)) + vmx_switch_vmcs(vcpu, &vmx->vmcs01); +@@ -353,9 +354,15 @@ static void free_nested(struct kvm_vcpu + vmx->nested.current_vmptr = INVALID_GPA; + if (enable_shadow_vmcs) { + vmx_disable_shadow_vmcs(vmx); +- vmcs_clear(vmx->vmcs01.shadow_vmcs); +- free_vmcs(vmx->vmcs01.shadow_vmcs); ++ ++ /* ++ * Keep the pointer visible until after VMCLEAR, so migration ++ * can clear an active shadow VMCS on the old CPU. ++ */ ++ shadow_vmcs = vmx->vmcs01.shadow_vmcs; ++ vmcs_clear(shadow_vmcs); + vmx->vmcs01.shadow_vmcs = NULL; ++ free_vmcs(shadow_vmcs); + } + kfree(vmx->nested.cached_vmcs12); + vmx->nested.cached_vmcs12 = NULL; diff --git a/queue-7.1/kvm-x86-check-for-invalid-obsolete-root-after-making-mmu-pages-available.patch b/queue-7.1/kvm-x86-check-for-invalid-obsolete-root-after-making-mmu-pages-available.patch new file mode 100644 index 0000000000..637e4a94ae --- /dev/null +++ b/queue-7.1/kvm-x86-check-for-invalid-obsolete-root-after-making-mmu-pages-available.patch @@ -0,0 +1,86 @@ +From 2abd5287f08319fa35764566b15c6e22cb1068db Mon Sep 17 00:00:00 2001 +From: Sean Christopherson +Date: Mon, 13 Jul 2026 08:15:33 -0700 +Subject: KVM: x86: Check for invalid/obsolete root *after* making MMU pages available + +From: Sean Christopherson + +commit 2abd5287f08319fa35764566b15c6e22cb1068db upstream. + +Check for a "stale" page fault, i.e. for an invalid and/or obsolete root, +after making MMU pages available for the shadow MMU. If reclaiming shadow +pages zaps an in-use root, i.e. marks it invalid, then KVM will attempt to +map memory into an invalid root. On its own, populating an invalid root is +"fine", but because child shadow pages inherit their parent's role, any +children created during the map/fetch will be created as invalid pages, +thus violating KVM's invariant that invalid pages are never on the list of +active MMU pages. + +Note, the underlying flaw has existed since KVM first started tracking +invalid roots in 2008 (commit 2e53d63acba7, "KVM: MMU: ignore zapped root +pagetables"), but the true badness only came along in 2020 (Linux 5.9) +with the invariant that invalid shadow pages can't be on the list of +active pages. + +Note #2, inheriting role.invalid when creating child shadow pages is also +far from ideal; that flaw will be addressed separately. + +Reported-by: Hyunwoo Kim +Fixes: f95eec9bed76 ("KVM: x86/mmu: Don't put invalid SPs back on the list of active pages") +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kvm/mmu/mmu.c | 9 +++++---- + arch/x86/kvm/mmu/paging_tmpl.h | 10 ++++++---- + 2 files changed, 11 insertions(+), 8 deletions(-) + +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -4837,16 +4837,17 @@ static int direct_page_fault(struct kvm_ + if (r != RET_PF_CONTINUE) + return r; + +- r = RET_PF_RETRY; + write_lock(&vcpu->kvm->mmu_lock); + +- if (is_page_fault_stale(vcpu, fault)) +- goto out_unlock; +- + r = make_mmu_pages_available(vcpu); + if (r) + goto out_unlock; + ++ if (is_page_fault_stale(vcpu, fault)) { ++ r = RET_PF_RETRY; ++ goto out_unlock; ++ } ++ + r = direct_map(vcpu, fault); + + out_unlock: +--- a/arch/x86/kvm/mmu/paging_tmpl.h ++++ b/arch/x86/kvm/mmu/paging_tmpl.h +@@ -827,15 +827,17 @@ static int FNAME(page_fault)(struct kvm_ + } + #endif + +- r = RET_PF_RETRY; + write_lock(&vcpu->kvm->mmu_lock); + +- if (is_page_fault_stale(vcpu, fault)) +- goto out_unlock; +- + r = make_mmu_pages_available(vcpu); + if (r) + goto out_unlock; ++ ++ if (is_page_fault_stale(vcpu, fault)) { ++ r = RET_PF_RETRY; ++ goto out_unlock; ++ } ++ + r = FNAME(fetch)(vcpu, fault, &walker); + + out_unlock: diff --git a/queue-7.1/kvm-x86-mmu-fix-use-after-free-on-vendor-module-reload.patch b/queue-7.1/kvm-x86-mmu-fix-use-after-free-on-vendor-module-reload.patch new file mode 100644 index 0000000000..ea580d6e0b --- /dev/null +++ b/queue-7.1/kvm-x86-mmu-fix-use-after-free-on-vendor-module-reload.patch @@ -0,0 +1,76 @@ +From 52f2f7c30126037975389aa04d24c506a5177c35 Mon Sep 17 00:00:00 2001 +From: Phil Rosenthal +Date: Sat, 18 Jul 2026 12:50:23 -0400 +Subject: KVM: x86/mmu: Fix use-after-free on vendor module reload + +From: Phil Rosenthal + +commit 52f2f7c30126037975389aa04d24c506a5177c35 upstream. + +mmu_destroy_caches() destroys pte_list_desc_cache and +mmu_page_header_cache, but leaves both pointers unchanged. The pointers +live in kvm.ko, and therefore survive when a vendor module is unloaded +while kvm.ko remains loaded. + +If creation of pte_list_desc_cache fails during a subsequent vendor +module load, its assignment sets pte_list_desc_cache to NULL and the +error path calls mmu_destroy_caches(). mmu_page_header_cache still +points to the cache destroyed during the preceding vendor module +unload. Passing that stale pointer to kmem_cache_destroy() causes a +slab use-after-free. + +Reproduce the issue on a v7.1.3 kernel with CONFIG_KASAN=y, +CONFIG_KASAN_GENERIC=y, CONFIG_KVM=m, and CONFIG_KVM_INTEL=m. A +one-shot test hook forces pte_list_desc_cache to NULL on the second +invocation of kvm_mmu_vendor_module_init(): + + 1. Load kvm.ko and kvm-intel.ko, creating both caches. + 2. Unload only kvm_intel, leaving kvm.ko loaded. + 3. Reload kvm_intel and force initialization through the -ENOMEM path. + +KASAN reports: + + BUG: KASAN: slab-use-after-free in + kvm_mmu_vendor_module_init+0x5b/0x170 [kvm] + ... + kmem_cache_destroy+0x21/0x1d0 + kvm_mmu_vendor_module_init+0x5b/0x170 [kvm] + ... + Allocated by task 16817: + __kmem_cache_create_args+0x12c/0x3b0 + __kmem_cache_create.constprop.0+0xb6/0xf0 [kvm] + kvm_mmu_vendor_module_init+0x13b/0x170 [kvm] + ... + Freed by task 16820: + kmem_cache_destroy+0x117/0x1d0 + kvm_mmu_vendor_module_exit+0x21/0x30 [kvm] + +Clear both pointers immediately after destroying their caches so that +the stored state reflects the caches' lifetime and repeated cleanup is +safe. + +With the fix applied, the same injected vendor module reload fails with +-ENOMEM as expected and produces no KASAN report. + +Fixes: cb498ea2ce1d ("KVM: Portability: Combine kvm_init and kvm_init_x86") +Cc: stable@vger.kernel.org +Signed-off-by: Phil Rosenthal +Message-ID: <20260718-kvm-mmu-cache-uaf-v3-1-e103b93c74e1@phil.gs> +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kvm/mmu/mmu.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -7502,7 +7502,9 @@ void kvm_mmu_invalidate_mmio_sptes(struc + static void mmu_destroy_caches(void) + { + kmem_cache_destroy(pte_list_desc_cache); ++ pte_list_desc_cache = NULL; + kmem_cache_destroy(mmu_page_header_cache); ++ mmu_page_header_cache = NULL; + } + + static void kvm_wake_nx_recovery_thread(struct kvm *kvm) diff --git a/queue-7.1/kvm-x86-only-reset-tsc-deadline-timer-in-apic_timer_expired-on-kvm_run.patch b/queue-7.1/kvm-x86-only-reset-tsc-deadline-timer-in-apic_timer_expired-on-kvm_run.patch new file mode 100644 index 0000000000..0e6345a960 --- /dev/null +++ b/queue-7.1/kvm-x86-only-reset-tsc-deadline-timer-in-apic_timer_expired-on-kvm_run.patch @@ -0,0 +1,64 @@ +From e800decd9c0ac4349bcd8f8f9b29fd21fe93165e Mon Sep 17 00:00:00 2001 +From: Venkatesh Srinivas +Date: Wed, 15 Jul 2026 23:42:35 +0000 +Subject: KVM: x86: Only reset TSC Deadline Timer in apic_timer_expired on KVM_RUN + +From: Venkatesh Srinivas + +commit e800decd9c0ac4349bcd8f8f9b29fd21fe93165e upstream. + +On Intel platforms with a VMX preemption timer and APICv, if a VMM +calls KVM_GET_LAPIC before KVM_GET_MSRS to save the vCPU state, it is +possible to lose a pending timer interrupt. + +If the thread running these ioctls is migrated to another core after +calling KVM_GET_LAPIC but before KVM_GET_MSRS and the guest is using +their LAPIC timer in TSC-deadline mode, not only does the save LAPIC +state not carry the pending interrupt, the TSCDEADLINE MSR will be +zeroed. + +After migration across CPUs, KVM_GET_MSRS calls vcpu_load, posting the +interrupt and clearing the MSR: +vcpu_load() -> + kvm_arch_vcpu_load() -> + kvm_lapic_restart_hv_timer() -> + start_hv_timer() -> + apic_timer_expired() -> + kvm_apic_inject_pending_timer_irqs() + . post interrupt into the LAPIC state + . clear IA32_TSCDEADLINE + +The saved LAPIC state will be missing the pending interrupt and the saved +MSR will be zero. Oops. + +Fix by only posting an interrupt when we're attempting to enter the guest +(vcpu->wants_to_run == true), not for vcpu_load from other paths. + +Assisted-by: gemini:gemini-3.1-pro-preview +Debugged-by: David Matlack +Debugged-by: Sean Christopherson +Debugged-by: Jim Mattson +Debugged-by: James Houghton +Signed-off-by: Venkatesh Srinivas +Message-ID: <20260715234234.15382-2-venkateshs@chromium.org> +Reviewed-by: James Houghton +Reviewed-by: Chao Gao +Cc: stable@vger.kernel.org +Fixes: ae95f566b3d2 ("KVM: X86: TSCDEADLINE MSR emulation fastpath", 2020-05-15) +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kvm/lapic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/x86/kvm/lapic.c ++++ b/arch/x86/kvm/lapic.c +@@ -2052,7 +2052,7 @@ static void apic_timer_expired(struct kv + if (apic_lvtt_tscdeadline(apic) || ktimer->hv_timer_in_use) + ktimer->expired_tscdeadline = ktimer->tscdeadline; + +- if (!from_timer_fn && apic->apicv_active) { ++ if (!from_timer_fn && apic->apicv_active && vcpu->wants_to_run) { + WARN_ON(kvm_get_running_vcpu() != vcpu); + kvm_apic_inject_pending_timer_irqs(apic); + return; diff --git a/queue-7.1/risc-v-kvm-serialize-virtual-interrupt-pending-state-updates.patch b/queue-7.1/risc-v-kvm-serialize-virtual-interrupt-pending-state-updates.patch new file mode 100644 index 0000000000..55810d9e17 --- /dev/null +++ b/queue-7.1/risc-v-kvm-serialize-virtual-interrupt-pending-state-updates.patch @@ -0,0 +1,382 @@ +From d024a0a7879e6f37c0152aacf6d8e37b214a1738 Mon Sep 17 00:00:00 2001 +From: Xie Bo +Date: Wed, 15 Jul 2026 10:03:59 +0800 +Subject: RISC-V: KVM: Serialize virtual interrupt pending state updates + +From: Xie Bo + +commit d024a0a7879e6f37c0152aacf6d8e37b214a1738 upstream. + +KVM RISC-V tracks guest local interrupt state with two bitmaps: + + - irqs_pending: interrupts that should be visible to the guest + - irqs_pending_mask: interrupts whose pending state changed + +The current code updates those bitmaps with independent atomic bitops +and assumes a multiple-producer, single-consumer protocol. That model +does not actually hold. + +kvm_riscv_vcpu_sync_interrupts() is not a pure consumer. When the guest +changes guest-visible HVIP state, sync_interrupts() writes both +irqs_pending and irqs_pending_mask to reflect the new guest state back +into KVM state. As a result, irqs_pending and irqs_pending_mask form a +single logical state transition, but they are not updated atomically as +a pair. + +This allows a race where a newly injected interrupt is lost. For +example: + + CPU0 CPU1 + ---- ---- + kvm_riscv_vcpu_set_interrupt(VS_SOFT) + set_bit(VS_SOFT, irqs_pending) + kvm_riscv_vcpu_sync_interrupts() + sees guest-cleared HVIP.VSSIP + sets irqs_pending_mask + clear_bit(IRQ_VS_SOFT, irqs_pending) + set_bit(VS_SOFT, irqs_pending_mask) + kvm_vcpu_kick() + +After that interleaving, a later flush can update HVIP without VSSIP +even though a new virtual interrupt was injected. In practice, the +guest can remain blocked in WFI with work pending. + +The same pending/mask protocol is shared by VS soft interrupts, PMU +overflow delivery, and AIA high interrupt synchronization, so the race +is not limited to one interrupt source. + +Fix this by serializing all updates to irqs_pending and irqs_pending_mask +with a per-vCPU raw spinlock. This keeps the pending bit and the dirty +mask as one state transition across: + + - set/unset interrupt + - guest HVIP sync + - interrupt flush to guest CSR state + - vCPU reset + - AIA CSR writes that clear dirty state + +Use non-atomic bitmap operations while holding the lock. Hold the lock +across the AIA sync, flush, and pending checks as well, so both bitmap +words share the same serialization domain. + +This intentionally replaces the existing lockless protocol instead of +trying to repair it with additional barriers. The problem is not memory +ordering on a single field; it is that two separate bitmaps encode one +shared state machine while both producers and sync paths can modify +them. A per-vCPU raw spinlock keeps the fix small, local, and suitable +for backporting. + +Fixes: cce69aff689e ("RISC-V: KVM: Implement VCPU interrupts and requests handling") +Cc: stable@vger.kernel.org +Signed-off-by: Xie Bo +Reviewed-by: Anup Patel +Link: https://lore.kernel.org/r/20260715020359.1521354-2-xb@ultrarisc.com +Signed-off-by: Anup Patel +Signed-off-by: Greg Kroah-Hartman +--- + arch/riscv/include/asm/kvm_host.h | 10 ++--- + arch/riscv/kvm/aia.c | 35 +++++++++++++++---- + arch/riscv/kvm/vcpu.c | 68 ++++++++++++++++++++++++++------------ + arch/riscv/kvm/vcpu_onereg.c | 8 +++- + 4 files changed, 87 insertions(+), 34 deletions(-) + +--- a/arch/riscv/include/asm/kvm_host.h ++++ b/arch/riscv/include/asm/kvm_host.h +@@ -207,13 +207,13 @@ struct kvm_vcpu_arch { + /* + * VCPU interrupts + * +- * We have a lockless approach for tracking pending VCPU interrupts +- * implemented using atomic bitops. The irqs_pending bitmap represent +- * pending interrupts whereas irqs_pending_mask represent bits changed +- * in irqs_pending. Our approach is modeled around multiple producer +- * and single consumer problem where the consumer is the VCPU itself. ++ * The irqs_pending bitmap represents pending interrupts whereas ++ * irqs_pending_mask represents bits changed in irqs_pending. Updates ++ * to these bitmaps are serialized so vcpu interrupt sync/flush cannot ++ * drop a newly injected interrupt while syncing guest-visible HVIP. + */ + #define KVM_RISCV_VCPU_NR_IRQS 64 ++ raw_spinlock_t irqs_pending_lock; + DECLARE_BITMAP(irqs_pending, KVM_RISCV_VCPU_NR_IRQS); + DECLARE_BITMAP(irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS); + +--- a/arch/riscv/kvm/aia.c ++++ b/arch/riscv/kvm/aia.c +@@ -51,12 +51,15 @@ void kvm_riscv_vcpu_aia_flush_interrupts + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + unsigned long mask, val; + ++ lockdep_assert_held(&vcpu->arch.irqs_pending_lock); ++ + if (!kvm_riscv_aia_available()) + return; + +- if (READ_ONCE(vcpu->arch.irqs_pending_mask[1])) { +- mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[1], 0); +- val = READ_ONCE(vcpu->arch.irqs_pending[1]) & mask; ++ mask = vcpu->arch.irqs_pending_mask[1]; ++ if (mask) { ++ vcpu->arch.irqs_pending_mask[1] = 0; ++ val = vcpu->arch.irqs_pending[1] & mask; + + csr->hviph &= ~mask; + csr->hviph |= val; +@@ -67,6 +70,8 @@ void kvm_riscv_vcpu_aia_sync_interrupts( + { + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + ++ lockdep_assert_held(&vcpu->arch.irqs_pending_lock); ++ + if (kvm_riscv_aia_available()) + csr->vsieh = ncsr_read(CSR_VSIEH); + } +@@ -75,13 +80,22 @@ void kvm_riscv_vcpu_aia_sync_interrupts( + bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask) + { + unsigned long seip; ++#ifdef CONFIG_32BIT ++ unsigned long flags; ++ bool pending; ++#endif + + if (!kvm_riscv_aia_available()) + return false; + + #ifdef CONFIG_32BIT +- if (READ_ONCE(vcpu->arch.irqs_pending[1]) & +- (vcpu->arch.aia_context.guest_csr.vsieh & upper_32_bits(mask))) ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ pending = vcpu->arch.irqs_pending[1] & ++ (vcpu->arch.aia_context.guest_csr.vsieh & ++ upper_32_bits(mask)); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); ++ ++ if (pending) + return true; + #endif + +@@ -205,6 +219,9 @@ int kvm_riscv_vcpu_aia_set_csr(struct kv + { + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + unsigned long regs_max = sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long); ++#ifdef CONFIG_32BIT ++ unsigned long flags; ++#endif + + if (!riscv_isa_extension_available(vcpu->arch.isa, SSAIA)) + return -ENOENT; +@@ -217,8 +234,12 @@ int kvm_riscv_vcpu_aia_set_csr(struct kv + ((unsigned long *)csr)[reg_num] = val; + + #ifdef CONFIG_32BIT +- if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) +- WRITE_ONCE(vcpu->arch.irqs_pending_mask[1], 0); ++ if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) { ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ vcpu->arch.irqs_pending_mask[1] = 0; ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, ++ flags); ++ } + #endif + } + +--- a/arch/riscv/kvm/vcpu.c ++++ b/arch/riscv/kvm/vcpu.c +@@ -80,6 +80,7 @@ static void kvm_riscv_vcpu_context_reset + + static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset) + { ++ unsigned long flags; + bool loaded; + + /** +@@ -104,8 +105,10 @@ static void kvm_riscv_reset_vcpu(struct + + kvm_riscv_vcpu_aia_reset(vcpu); + ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); + bitmap_zero(vcpu->arch.irqs_pending, KVM_RISCV_VCPU_NR_IRQS); + bitmap_zero(vcpu->arch.irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + kvm_riscv_vcpu_pmu_reset(vcpu); + +@@ -151,6 +154,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu + + /* Setup VCPU hfence queue */ + spin_lock_init(&vcpu->arch.hfence_lock); ++ raw_spin_lock_init(&vcpu->arch.irqs_pending_lock); + + spin_lock_init(&vcpu->arch.reset_state.lock); + +@@ -352,10 +356,14 @@ void kvm_riscv_vcpu_flush_interrupts(str + { + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + unsigned long mask, val; ++ unsigned long flags; + +- if (READ_ONCE(vcpu->arch.irqs_pending_mask[0])) { +- mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[0], 0); +- val = READ_ONCE(vcpu->arch.irqs_pending[0]) & mask; ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ ++ mask = vcpu->arch.irqs_pending_mask[0]; ++ if (mask) { ++ vcpu->arch.irqs_pending_mask[0] = 0; ++ val = vcpu->arch.irqs_pending[0] & mask; + + csr->hvip &= ~mask; + csr->hvip |= val; +@@ -363,11 +371,14 @@ void kvm_riscv_vcpu_flush_interrupts(str + + /* Flush AIA high interrupts */ + kvm_riscv_vcpu_aia_flush_interrupts(vcpu); ++ ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + } + + void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu) + { + unsigned long hvip; ++ unsigned long flags; + struct kvm_vcpu_arch *v = &vcpu->arch; + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + +@@ -376,34 +387,41 @@ void kvm_riscv_vcpu_sync_interrupts(stru + + /* Sync-up HVIP.VSSIP bit changes does by Guest */ + hvip = ncsr_read(CSR_HVIP); ++ ++ raw_spin_lock_irqsave(&v->irqs_pending_lock, flags); ++ + if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) { + if (hvip & (1UL << IRQ_VS_SOFT)) { +- if (!test_and_set_bit(IRQ_VS_SOFT, +- v->irqs_pending_mask)) +- set_bit(IRQ_VS_SOFT, v->irqs_pending); ++ if (!__test_and_set_bit(IRQ_VS_SOFT, ++ v->irqs_pending_mask)) ++ __set_bit(IRQ_VS_SOFT, v->irqs_pending); + } else { +- if (!test_and_set_bit(IRQ_VS_SOFT, +- v->irqs_pending_mask)) +- clear_bit(IRQ_VS_SOFT, v->irqs_pending); ++ if (!__test_and_set_bit(IRQ_VS_SOFT, ++ v->irqs_pending_mask)) ++ __clear_bit(IRQ_VS_SOFT, v->irqs_pending); + } + } + + /* Sync up the HVIP.LCOFIP bit changes (only clear) by the guest */ + if ((csr->hvip ^ hvip) & (1UL << IRQ_PMU_OVF)) { + if (!(hvip & (1UL << IRQ_PMU_OVF)) && +- !test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask)) +- clear_bit(IRQ_PMU_OVF, v->irqs_pending); ++ !__test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask)) ++ __clear_bit(IRQ_PMU_OVF, v->irqs_pending); + } + + /* Sync-up AIA high interrupts */ + kvm_riscv_vcpu_aia_sync_interrupts(vcpu); + ++ raw_spin_unlock_irqrestore(&v->irqs_pending_lock, flags); ++ + /* Sync-up timer CSRs */ + kvm_riscv_vcpu_timer_sync(vcpu); + } + + int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + { ++ unsigned long flags; ++ + /* + * We only allow VS-mode software, timer, and external + * interrupts when irq is one of the local interrupts +@@ -416,9 +434,10 @@ int kvm_riscv_vcpu_set_interrupt(struct + irq != IRQ_PMU_OVF) + return -EINVAL; + +- set_bit(irq, vcpu->arch.irqs_pending); +- smp_mb__before_atomic(); +- set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ __set_bit(irq, vcpu->arch.irqs_pending); ++ __set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + kvm_vcpu_kick(vcpu); + +@@ -427,6 +446,8 @@ int kvm_riscv_vcpu_set_interrupt(struct + + int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + { ++ unsigned long flags; ++ + /* + * We only allow VS-mode software, timer, counter overflow and external + * interrupts when irq is one of the local interrupts +@@ -439,26 +460,33 @@ int kvm_riscv_vcpu_unset_interrupt(struc + irq != IRQ_PMU_OVF) + return -EINVAL; + +- clear_bit(irq, vcpu->arch.irqs_pending); +- smp_mb__before_atomic(); +- set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ __clear_bit(irq, vcpu->arch.irqs_pending); ++ __set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + return 0; + } + + bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask) + { ++ unsigned long flags; + unsigned long ie; ++ bool ret; + ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); + ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK) + << VSIP_TO_HVIP_SHIFT) & (unsigned long)mask; + ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK & + (unsigned long)mask; +- if (READ_ONCE(vcpu->arch.irqs_pending[0]) & ie) +- return true; ++ ret = vcpu->arch.irqs_pending[0] & ie; ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + /* Check AIA high interrupts */ +- return kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask); ++ if (!ret) ++ ret = kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask); ++ ++ return ret; + } + + void __kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu) +--- a/arch/riscv/kvm/vcpu_onereg.c ++++ b/arch/riscv/kvm/vcpu_onereg.c +@@ -276,6 +276,7 @@ static int kvm_riscv_vcpu_general_get_cs + { + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + unsigned long regs_max = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long); ++ unsigned long flags; + + if (reg_num >= regs_max) + return -ENOENT; +@@ -311,8 +312,11 @@ static int kvm_riscv_vcpu_general_set_cs + + ((unsigned long *)csr)[reg_num] = reg_val; + +- if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) +- WRITE_ONCE(vcpu->arch.irqs_pending_mask[0], 0); ++ if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ vcpu->arch.irqs_pending_mask[0] = 0; ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); ++ } + + return 0; + } diff --git a/queue-7.1/series b/queue-7.1/series index 24f64364a4..00801c7732 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -2,3 +2,8 @@ platform-x86-intel-uncore-freq-fix-current_freq_khz-.patch sched_ext-skip-ops.set_weight-for-disabled-tasks.patch drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch seqlock-allow-ubsan_alignment-to-fail-optimizing.patch +risc-v-kvm-serialize-virtual-interrupt-pending-state-updates.patch +kvm-x86-check-for-invalid-obsolete-root-after-making-mmu-pages-available.patch +kvm-x86-only-reset-tsc-deadline-timer-in-apic_timer_expired-on-kvm_run.patch +kvm-nvmx-hide-shadow-vmcs-right-after-vmclear.patch +kvm-x86-mmu-fix-use-after-free-on-vendor-module-reload.patch