linux/arch/x86/kvm
Sean Christopherson eea6f395ca x86/fpu: Clear XSTATE_BV[i] in guest XSAVE state whenever XFD[i]=1
commit b45f721775 upstream.

When loading guest XSAVE state via KVM_SET_XSAVE, and when updating XFD in
response to a guest WRMSR, clear XFD-disabled features in the saved (or to
be restored) XSTATE_BV to ensure KVM doesn't attempt to load state for
features that are disabled via the guest's XFD.  Because the kernel
executes XRSTOR with the guest's XFD, saving XSTATE_BV[i]=1 with XFD[i]=1
will cause XRSTOR to #NM and panic the kernel.

E.g. if fpu_update_guest_xfd() sets XFD without clearing XSTATE_BV:

  ------------[ cut here ]------------
  WARNING: arch/x86/kernel/traps.c:1524 at exc_device_not_available+0x101/0x110, CPU#29: amx_test/848
  Modules linked in: kvm_intel kvm irqbypass
  CPU: 29 UID: 1000 PID: 848 Comm: amx_test Not tainted 6.19.0-rc2-ffa07f7fd437-x86_amx_nm_xfd_non_init-vm #171 NONE
  Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
  RIP: 0010:exc_device_not_available+0x101/0x110
  Call Trace:
   <TASK>
   asm_exc_device_not_available+0x1a/0x20
  RIP: 0010:restore_fpregs_from_fpstate+0x36/0x90
   switch_fpu_return+0x4a/0xb0
   kvm_arch_vcpu_ioctl_run+0x1245/0x1e40 [kvm]
   kvm_vcpu_ioctl+0x2c3/0x8f0 [kvm]
   __x64_sys_ioctl+0x8f/0xd0
   do_syscall_64+0x62/0x940
   entry_SYSCALL_64_after_hwframe+0x4b/0x53
   </TASK>
  ---[ end trace 0000000000000000 ]---

This can happen if the guest executes WRMSR(MSR_IA32_XFD) to set XFD[18] = 1,
and a host IRQ triggers kernel_fpu_begin() prior to the vmexit handler's
call to fpu_update_guest_xfd().

and if userspace stuffs XSTATE_BV[i]=1 via KVM_SET_XSAVE:

  ------------[ cut here ]------------
  WARNING: arch/x86/kernel/traps.c:1524 at exc_device_not_available+0x101/0x110, CPU#14: amx_test/867
  Modules linked in: kvm_intel kvm irqbypass
  CPU: 14 UID: 1000 PID: 867 Comm: amx_test Not tainted 6.19.0-rc2-2dace9faccd6-x86_amx_nm_xfd_non_init-vm #168 NONE
  Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
  RIP: 0010:exc_device_not_available+0x101/0x110
  Call Trace:
   <TASK>
   asm_exc_device_not_available+0x1a/0x20
  RIP: 0010:restore_fpregs_from_fpstate+0x36/0x90
   fpu_swap_kvm_fpstate+0x6b/0x120
   kvm_load_guest_fpu+0x30/0x80 [kvm]
   kvm_arch_vcpu_ioctl_run+0x85/0x1e40 [kvm]
   kvm_vcpu_ioctl+0x2c3/0x8f0 [kvm]
   __x64_sys_ioctl+0x8f/0xd0
   do_syscall_64+0x62/0x940
   entry_SYSCALL_64_after_hwframe+0x4b/0x53
   </TASK>
  ---[ end trace 0000000000000000 ]---

The new behavior is consistent with the AMX architecture.  Per Intel's SDM,
XSAVE saves XSTATE_BV as '0' for components that are disabled via XFD
(and non-compacted XSAVE saves the initial configuration of the state
component):

  If XSAVE, XSAVEC, XSAVEOPT, or XSAVES is saving the state component i,
  the instruction does not generate #NM when XCR0[i] = IA32_XFD[i] = 1;
  instead, it operates as if XINUSE[i] = 0 (and the state component was
  in its initial state): it saves bit i of XSTATE_BV field of the XSAVE
  header as 0; in addition, XSAVE saves the initial configuration of the
  state component (the other instructions do not save state component i).

Alternatively, KVM could always do XRSTOR with XFD=0, e.g. by using
a constant XFD based on the set of enabled features when XSAVEing for
a struct fpu_guest.  However, having XSTATE_BV[i]=1 for XFD-disabled
features can only happen in the above interrupt case, or in similar
scenarios involving preemption on preemptible kernels, because
fpu_swap_kvm_fpstate()'s call to save_fpregs_to_fpstate() saves the
outgoing FPU state with the current XFD; and that is (on all but the
first WRMSR to XFD) the guest XFD.

Therefore, XFD can only go out of sync with XSTATE_BV in the above
interrupt case, or in similar scenarios involving preemption on
preemptible kernels, and it we can consider it (de facto) part of KVM
ABI that KVM_GET_XSAVE returns XSTATE_BV[i]=0 for XFD-disabled features.

Reported-by: Paolo Bonzini <pbonzini@redhat.com>
Cc: stable@vger.kernel.org
Fixes: 820a6ee944 ("kvm: x86: Add emulation for IA32_XFD", 2022-01-14)
Signed-off-by: Sean Christopherson <seanjc@google.com>
[Move clearing of XSTATE_BV from fpu_copy_uabi_to_guest_fpstate
 to kvm_vcpu_ioctl_x86_set_xsave. - Paolo]
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
History 2026-01-23 11:21:12 +01:00
..
mmu KVM: x86: Export KVM-internal symbols for sub-modules only 2025-09-30 13:40:02 -04:00
svm KVM: nSVM: Clear exit_code_hi in VMCB when synthesizing nested VM-Exits 2026-01-02 12:57:21 +01:00
vmx KVM: nVMX: Immediately refresh APICv controls as needed on nested VM-Exit 2026-01-02 12:57:21 +01:00
.gitignore KVM: x86: use a separate asm-offsets.c file 2022-11-09 12:10:17 -05:00
cpuid.c KVM: x86: Apply runtime updates to current CPUID during KVM_SET_CPUID{,2} 2026-01-02 12:57:21 +01:00
cpuid.h Merge branch 'kvm-tdx-initial' into HEAD 2025-04-07 07:36:33 -04:00
debugfs.c KVM: Get rid of return value from kvm_arch_create_vm_debugfs() 2024-02-23 21:44:58 +00:00
emulate.c - Remove a bunch of asm implementing condition flags testing in KVM's 2025-10-11 11:19:16 -07:00
fpu.h KVM: x86: Move FPU register accessors into fpu.h 2021-06-17 13:09:24 -04:00
hyperv.c KVM: x86: Export KVM-internal symbols for sub-modules only 2025-09-30 13:40:02 -04:00
hyperv.h KVM: x86: Drop superfluous kvm_hv_set_sint() => kvm_hv_synic_set_irq() wrapper 2025-06-20 13:52:43 -07:00
i8254.c Significant patch series in this pull request: 2025-08-03 16:23:09 -07:00
i8254.h KVM: x86: Move IRQ mask notifier infrastructure to I/O APIC emulation 2025-06-20 13:52:52 -07:00
i8259.c KVM: x86: Move IRQ mask notifier infrastructure to I/O APIC emulation 2025-06-20 13:52:52 -07:00
ioapic.c arch/x86/kvm/ioapic: Remove license boilerplate with bad FSF address 2025-08-19 11:59:29 -07:00
ioapic.h KVM: x86: Move IRQ mask notifier infrastructure to I/O APIC emulation 2025-06-20 13:52:52 -07:00
irq.c KVM: x86: Export KVM-internal symbols for sub-modules only 2025-09-30 13:40:02 -04:00
irq.h KVM: x86: Move kvm_irq_delivery_to_apic() from irq.c to lapic.c 2025-09-10 12:05:09 -07:00
Kconfig - Remove a bunch of asm implementing condition flags testing in KVM's 2025-10-11 11:19:16 -07:00
kvm-asm-offsets.c KVM: SVM: move MSR_IA32_SPEC_CTRL save/restore to assembly 2022-11-09 12:25:53 -05:00
kvm_cache_regs.h KVM: VMX: Make CR4.CET a guest owned bit 2025-09-23 10:03:09 -07:00
kvm_emulate.h KVM: x86: Don't (re)check L1 intercepts when completing userspace I/O 2025-08-19 10:53:40 -07:00
kvm_onhyperv.c KVM: x86: Export KVM-internal symbols for sub-modules only 2025-09-30 13:40:02 -04:00
kvm_onhyperv.h KVM: x86: Move Hyper-V partition assist page out of Hyper-V emulation context 2023-12-07 09:34:01 -08:00
lapic.c KVM: x86: Fix VM hard lockup after prolonged inactivity with periodic HV timer 2026-01-02 12:57:20 +01:00
lapic.h KVM: x86: Move kvm_intr_is_single_vcpu() to lapic.c 2025-09-30 13:40:02 -04:00
Makefile KVM: x86: Fold irq_comm.c into irq.c 2025-06-20 13:52:52 -07:00
mmu.h KVM: x86/mmu: WARN on attempt to check permissions for Shadow Stack #PF 2025-09-23 09:16:53 -07:00
mtrr.c KVM: x86: drop x86.h include from cpuid.h 2024-11-01 09:22:23 -07:00
pmu.c KVM: x86/pmu: Don't try to get perf capabilities for hybrid CPUs 2025-10-10 14:25:12 -07:00
pmu.h Generic: 2025-10-06 12:37:34 -07:00
reverse_cpuid.h KVM: x86: Advertise support for the immediate form of MSR instructions 2025-08-19 11:59:47 -07:00
smm.c KVM: x86: Export KVM-internal symbols for sub-modules only 2025-09-30 13:40:02 -04:00
smm.h KVM: x86: Save and reload SSP to/from SMRAM 2025-09-23 09:11:22 -07:00
trace.h KVM: x86: Define AMD's #HV, #VC, and #SX exception vectors 2025-09-23 09:29:03 -07:00
tss.h License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
x86.c x86/fpu: Clear XSTATE_BV[i] in guest XSAVE state whenever XFD[i]=1 2026-01-23 11:21:12 +01:00
x86.h KVM: x86: Allow setting CR4.CET if IBT or SHSTK is supported 2025-09-23 09:17:48 -07:00
xen.c KVM: x86/xen: Fix cleanup logic in emulation of Xen schedop poll hypercalls 2025-07-23 23:48:54 +02:00
xen.h KVM: x86: Update Xen TSC leaves during CPUID emulation 2025-02-25 07:09:55 -08:00