Commit 71b639af authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'x86-fpu-2025-03-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86/fpu updates from Ingo Molnar:

 - Improve crypto performance by making kernel-mode FPU reliably usable
   in softirqs ((Eric Biggers)

 - Fully optimize out WARN_ON_FPU() (Eric Biggers)

 - Initial steps to support Support Intel APX (Advanced Performance
   Extensions) (Chang S. Bae)

 - Fix KASAN for arch_dup_task_struct() (Benjamin Berg)

 - Refine and simplify the FPU magic number check during signal return
   (Chang S. Bae)

 - Fix inconsistencies in guest FPU xfeatures (Chao Gao, Stanislav
   Spassov)

 - selftests/x86/xstate: Introduce common code for testing extended
   states (Chang S. Bae)

 - Misc fixes and cleanups (Borislav Petkov, Colin Ian King, Uros
   Bizjak)

* tag 'x86-fpu-2025-03-22' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/fpu/xstate: Fix inconsistencies in guest FPU xfeatures
  x86/fpu: Clarify the "xa" symbolic name used in the XSTATE* macros
  x86/fpu: Use XSAVE{,OPT,C,S} and XRSTOR{,S} mnemonics in xstate.h
  x86/fpu: Improve crypto performance by making kernel-mode FPU reliably usable in softirqs
  x86/fpu/xstate: Simplify print_xstate_features()
  x86/fpu: Refine and simplify the magic number check during signal return
  selftests/x86/xstate: Fix spelling mistake "hader" -> "header"
  x86/fpu: Avoid copying dynamic FP state from init_task in arch_dup_task_struct()
  vmlinux.lds.h: Remove entry to place init_task onto init_stack
  selftests/x86/avx: Add AVX tests
  selftests/x86/xstate: Clarify supported xstates
  selftests/x86/xstate: Consolidate test invocations into a single entry
  selftests/x86/xstate: Introduce signal ABI test
  selftests/x86/xstate: Refactor ptrace ABI test
  selftests/x86/xstate: Refactor context switching test
  selftests/x86/xstate: Enumerate and name xstate components
  selftests/x86/xstate: Refactor XSAVE helpers for general use
  selftests/x86: Consolidate redundant signal helper functions
  x86/fpu: Fix guest FPU state buffer allocation size
  x86/fpu: Fully optimize out WARN_ON_FPU()
parents b58386a9 dda36608
Loading
Loading
Loading
Loading
+7 −10
Original line number Diff line number Diff line
@@ -16,10 +16,9 @@

/*
 * Use kernel_fpu_begin/end() if you intend to use FPU in kernel context. It
 * disables preemption so be careful if you intend to use it for long periods
 * of time.
 * If you intend to use the FPU in irq/softirq you need to check first with
 * irq_fpu_usable() if it is possible.
 * disables preemption and softirq processing, so be careful if you intend to
 * use it for long periods of time.  Kernel-mode FPU cannot be used in all
 * contexts -- see irq_fpu_usable() for details.
 */

/* Kernel FPU states to initialize in kernel_fpu_begin_mask() */
@@ -50,10 +49,10 @@ static inline void kernel_fpu_begin(void)
}

/*
 * Use fpregs_lock() while editing CPU's FPU registers or fpu->fpstate.
 * A context switch will (and softirq might) save CPU's FPU registers to
 * fpu->fpstate.regs and set TIF_NEED_FPU_LOAD leaving CPU's FPU registers in
 * a random state.
 * Use fpregs_lock() while editing CPU's FPU registers or fpu->fpstate, or while
 * using the FPU in kernel mode.  A context switch will (and softirq might) save
 * CPU's FPU registers to fpu->fpstate.regs and set TIF_NEED_FPU_LOAD leaving
 * CPU's FPU registers in a random state.
 *
 * local_bh_disable() protects against both preemption and soft interrupts
 * on !RT kernels.
@@ -63,8 +62,6 @@ static inline void kernel_fpu_begin(void)
 * preemptible. Disabling preemption is the right choice here as bottom
 * half processing is always in thread context on RT kernels so it
 * implicitly prevents bottom half processing as well.
 *
 * Disabling preemption also serializes against kernel_fpu_begin().
 */
static inline void fpregs_lock(void)
{
+16 −7
Original line number Diff line number Diff line
@@ -60,9 +60,16 @@ bool irq_fpu_usable(void)
	if (WARN_ON_ONCE(in_nmi()))
		return false;

	/* In kernel FPU usage already active? */
	if (this_cpu_read(in_kernel_fpu))
	/*
	 * In kernel FPU usage already active?  This detects any explicitly
	 * nested usage in task or softirq context, which is unsupported.  It
	 * also detects attempted usage in a hardirq that has interrupted a
	 * kernel-mode FPU section.
	 */
	if (this_cpu_read(in_kernel_fpu)) {
		WARN_ON_FPU(!in_hardirq());
		return false;
	}

	/*
	 * When not in NMI or hard interrupt context, FPU can be used in:
@@ -220,7 +227,7 @@ bool fpu_alloc_guest_fpstate(struct fpu_guest *gfpu)
	struct fpstate *fpstate;
	unsigned int size;

	size = fpu_user_cfg.default_size + ALIGN(offsetof(struct fpstate, regs), 64);
	size = fpu_kernel_cfg.default_size + ALIGN(offsetof(struct fpstate, regs), 64);
	fpstate = vzalloc(size);
	if (!fpstate)
		return false;
@@ -232,8 +239,8 @@ bool fpu_alloc_guest_fpstate(struct fpu_guest *gfpu)
	fpstate->is_guest	= true;

	gfpu->fpstate		= fpstate;
	gfpu->xfeatures		= fpu_user_cfg.default_features;
	gfpu->perm		= fpu_user_cfg.default_features;
	gfpu->xfeatures		= fpu_kernel_cfg.default_features;
	gfpu->perm		= fpu_kernel_cfg.default_features;

	/*
	 * KVM sets the FP+SSE bits in the XSAVE header when copying FPU state
@@ -420,7 +427,8 @@ EXPORT_SYMBOL_GPL(fpu_copy_uabi_to_guest_fpstate);

void kernel_fpu_begin_mask(unsigned int kfpu_mask)
{
	preempt_disable();
	if (!irqs_disabled())
		fpregs_lock();

	WARN_ON_FPU(!irq_fpu_usable());
	WARN_ON_FPU(this_cpu_read(in_kernel_fpu));
@@ -448,7 +456,8 @@ void kernel_fpu_end(void)
	WARN_ON_FPU(!this_cpu_read(in_kernel_fpu));

	this_cpu_write(in_kernel_fpu, false);
	preempt_enable();
	if (!irqs_disabled())
		fpregs_unlock();
}
EXPORT_SYMBOL_GPL(kernel_fpu_end);

+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ static __always_inline __pure bool use_fxsr(void)
#ifdef CONFIG_X86_DEBUG_FPU
# define WARN_ON_FPU(x) WARN_ON_ONCE(x)
#else
# define WARN_ON_FPU(x) ({ (void)(x); 0; })
# define WARN_ON_FPU(x) ({ BUILD_BUG_ON_INVALID(x); 0; })
#endif

/* Used in init.c */
+3 −8
Original line number Diff line number Diff line
@@ -27,19 +27,14 @@
static inline bool check_xstate_in_sigframe(struct fxregs_state __user *fxbuf,
					    struct _fpx_sw_bytes *fx_sw)
{
	int min_xstate_size = sizeof(struct fxregs_state) +
			      sizeof(struct xstate_header);
	void __user *fpstate = fxbuf;
	unsigned int magic2;

	if (__copy_from_user(fx_sw, &fxbuf->sw_reserved[0], sizeof(*fx_sw)))
		return false;

	/* Check for the first magic field and other error scenarios. */
	if (fx_sw->magic1 != FP_XSTATE_MAGIC1 ||
	    fx_sw->xstate_size < min_xstate_size ||
	    fx_sw->xstate_size > current->thread.fpu.fpstate->user_size ||
	    fx_sw->xstate_size > fx_sw->extended_size)
	/* Check for the first magic field */
	if (fx_sw->magic1 != FP_XSTATE_MAGIC1)
		goto setfx;

	/*
@@ -48,7 +43,7 @@ static inline bool check_xstate_in_sigframe(struct fxregs_state __user *fxbuf,
	 * fpstate layout with out copying the extended state information
	 * in the memory layout.
	 */
	if (__get_user(magic2, (__u32 __user *)(fpstate + fx_sw->xstate_size)))
	if (__get_user(magic2, (__u32 __user *)(fpstate + current->thread.fpu.fpstate->user_size)))
		return false;

	if (likely(magic2 == FP_XSTATE_MAGIC2))
+9 −21
Original line number Diff line number Diff line
@@ -259,32 +259,20 @@ static void __init setup_xstate_cache(void)
	}
}

static void __init print_xstate_feature(u64 xstate_mask)
{
	const char *feature_name;

	if (cpu_has_xfeatures(xstate_mask, &feature_name))
		pr_info("x86/fpu: Supporting XSAVE feature 0x%03Lx: '%s'\n", xstate_mask, feature_name);
}

/*
 * Print out all the supported xstate features:
 */
static void __init print_xstate_features(void)
{
	print_xstate_feature(XFEATURE_MASK_FP);
	print_xstate_feature(XFEATURE_MASK_SSE);
	print_xstate_feature(XFEATURE_MASK_YMM);
	print_xstate_feature(XFEATURE_MASK_BNDREGS);
	print_xstate_feature(XFEATURE_MASK_BNDCSR);
	print_xstate_feature(XFEATURE_MASK_OPMASK);
	print_xstate_feature(XFEATURE_MASK_ZMM_Hi256);
	print_xstate_feature(XFEATURE_MASK_Hi16_ZMM);
	print_xstate_feature(XFEATURE_MASK_PKRU);
	print_xstate_feature(XFEATURE_MASK_PASID);
	print_xstate_feature(XFEATURE_MASK_CET_USER);
	print_xstate_feature(XFEATURE_MASK_XTILE_CFG);
	print_xstate_feature(XFEATURE_MASK_XTILE_DATA);
	int i;

	for (i = 0; i < XFEATURE_MAX; i++) {
		u64 mask = BIT_ULL(i);
		const char *name;

		if (cpu_has_xfeatures(mask, &name))
			pr_info("x86/fpu: Supporting XSAVE feature 0x%03Lx: '%s'\n", mask, name);
	}
}

/*
Loading