Re: [PATCH v3 1/2] x86/kvm/vmx: Move IRQ/NMI dispatch from KVM into x86 core
From: Bezdeka, Florian
Date: Tue May 26 2026 - 06:08:49 EST
Hi Peter,
On Fri, 2026-05-08 at 11:18 +0200, Peter Zijlstra wrote:
> Move the VMX interrupt dispatch magic into the x86 core code. This
> isolates KVM from the FRED/IDT decisions and reduces the amount of
> EXPORT_SYMBOL_FOR_KVM().
>
> Suggested-by: Sean Christopherson <seanjc@xxxxxxxxxx>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
> Tested-by: "Verma, Vishal L" <vishal.l.verma@xxxxxxxxx>
> ---
> Changes since v2:
> - one more IS_ENABLED(CONFIG_KVM_INTEL) (Yan Zhao)
> - fixed idt_do_interrupt_irqoff() prototype (Binbin Wu)
>
> arch/x86/entry/Makefile | 2 -
> arch/x86/entry/common.c | 48 ++++++++++++++++++++++++++++++++++++
> arch/x86/entry/entry.S | 46 ++++++++++++++++++++++++++++++++++
> arch/x86/entry/entry_64_fred.S | 1
> arch/x86/include/asm/desc.h | 4 +++
> arch/x86/include/asm/desc_defs.h | 2 -
> arch/x86/include/asm/entry-common.h | 2 +
> arch/x86/include/asm/fred.h | 1
> arch/x86/kernel/idt.c | 15 +++++++++++
> arch/x86/kernel/nmi.c | 1
> arch/x86/kvm/vmx/vmenter.S | 46 ----------------------------------
> arch/x86/kvm/vmx/vmx.c | 20 ++-------------
> 12 files changed, 120 insertions(+), 68 deletions(-)
>
> --- a/arch/x86/entry/Makefile
> +++ b/arch/x86/entry/Makefile
> @@ -13,7 +13,7 @@ CFLAGS_REMOVE_syscall_64.o = $(CC_FLAGS_
> CFLAGS_syscall_32.o += -fno-stack-protector
> CFLAGS_syscall_64.o += -fno-stack-protector
>
> -obj-y := entry.o entry_$(BITS).o syscall_$(BITS).o
> +obj-y := entry.o entry_$(BITS).o syscall_$(BITS).o common.o
>
> obj-y += vdso/
> obj-y += vsyscall/
> --- /dev/null
> +++ b/arch/x86/entry/common.c
> @@ -0,0 +1,48 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#include <linux/entry-common.h>
> +#include <linux/kvm_types.h>
> +#include <asm/fred.h>
> +#include <asm/desc.h>
> +
> +#if IS_ENABLED(CONFIG_KVM_INTEL)
> +/*
> + * On VMX, NMIs and IRQs (as configured by KVM) are acknowledged by hardware as
> + * part of the VM-Exit, i.e. the event itself is consumed as part the VM-Exit.
> + * x86_entry_from_kvm() is invoked by KVM to effectively forward NMIs and IRQs
> + * to the kernel for servicing. On SVM, a.k.a. AMD, the NMI/IRQ VM-Exit is
> + * purely a signal that an NMI/IRQ is pending, i.e. the event that triggered
> + * the VM-Exit is held pending until it's unblocked in the host.
> + */
> +noinstr void x86_entry_from_kvm(unsigned int event_type, unsigned int vector)
> +{
> + if (event_type == EVENT_TYPE_EXTINT) {
> +#ifdef CONFIG_X86_64
> + /*
> + * Use FRED dispatch, even when running IDT. The dispatch
> + * tables are kept in sync between FRED and IDT, and the FRED
> + * dispatch works well with CFI.
> + */
> + fred_entry_from_kvm(event_type, vector);
Seems this landed in 7.1-rc5.
I'm seeing a build failure here:
arch/x86/entry/common.c: In function ‘x86_entry_from_kvm’:
arch/x86/entry/common.c:27:17: error: implicit declaration of function ‘fred_entry_from_kvm’; did you mean ‘idt_entry_from_kvm’? [-Wimplicit-function-declaration]
27 | fred_entry_from_kvm(event_type, vector);
| ^~~~~~~~~~~~~~~~~~~
| idt_entry_from_kvm
arch/x86/entry/common.c:50:24: error: ‘return’ with a value, in function returning void [-Wreturn-mismatch]
50 | return fred_entry_from_kvm(event_type, vector);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
arch/x86/entry/common.c:18:14: note: declared here
18 | noinstr void x86_entry_from_kvm(unsigned int event_type, unsigned int vector)
| ^~~~~~~~~~~~~~~~~~
> +#else
> + idt_entry_from_kvm(vector);
> +#endif
> + return;
> + }
> +
> + WARN_ON_ONCE(event_type != EVENT_TYPE_NMI);
> +
> +#ifdef CONFIG_X86_64
> + if (cpu_feature_enabled(X86_FEATURE_FRED))
> + return fred_entry_from_kvm(event_type, vector);
> +#endif
> +
> + /*
> + * Notably, we must use IDT dispatch for NMI when running in IDT mode.
> + * The FRED NMI context is significantly different and will not work
> + * right (speficially FRED fixed the NMI recursion issue).
> + */
> + idt_entry_from_kvm(vector);
> +}
> +EXPORT_SYMBOL_FOR_KVM(x86_entry_from_kvm);
> +#endif
>
[snip]
> --- a/arch/x86/include/asm/entry-common.h
> +++ b/arch/x86/include/asm/entry-common.h
> @@ -97,4 +97,6 @@ static __always_inline void arch_exit_to
> }
> #define arch_exit_to_user_mode arch_exit_to_user_mode
>
> +extern void x86_entry_from_kvm(unsigned int entry_type, unsigned int vector);
> +
> #endif
> --- a/arch/x86/include/asm/fred.h
> +++ b/arch/x86/include/asm/fred.h
> @@ -110,7 +110,6 @@ static __always_inline unsigned long fre
> static inline void cpu_init_fred_exceptions(void) { }
> static inline void cpu_init_fred_rsps(void) { }
> static inline void fred_complete_exception_setup(void) { }
> -static inline void fred_entry_from_kvm(unsigned int type, unsigned int vector) { }
That seems still necessary for the !CONFIG_X86_FRED case.
> static inline void fred_sync_rsp0(unsigned long rsp0) { }
> static inline void fred_update_rsp0(void) { }
> #endif /* CONFIG_X86_FRED */
[snip]