x86/fpu: Remove init_task FPU state dependencies, add debugging warning for PF_KTHREAD tasks

init_task's FPU state initialization was a bit of a hack:

		__x86_init_fpu_begin = .;
		. = __x86_init_fpu_begin + 128*PAGE_SIZE;
		__x86_init_fpu_end = .;

But the init task isn't supposed to be using the FPU context
in any case, so remove the hack and add in some debug warnings.

As Linus noted in the discussion, the init task (and other
PF_KTHREAD tasks) *can* use the FPU via kernel_fpu_begin()/_end(),
but they don't need the context area because their FPU use is not
preemptible or reentrant, and they don't return to user-space.

Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Chang S. Bae <chang.seok.bae@intel.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Uros Bizjak <ubizjak@gmail.com>
Link: https://lore.kernel.org/r/20250409211127.3544993-8-mingo@kernel.org
This commit is contained in:
Ingo Molnar 2025-04-09 23:11:26 +02:00
parent c360bdc593
commit 22aafe3bcb
5 changed files with 17 additions and 14 deletions

View file

@ -516,7 +516,11 @@ struct thread_struct {
#endif
};
#ifdef CONFIG_X86_DEBUG_FPU
extern struct fpu *x86_task_fpu(struct task_struct *task);
#else
# define x86_task_fpu(task) ((struct fpu *)((void *)(task) + sizeof(*(task))))
#endif
/*
* X86 doesn't need any embedded-FPU-struct quirks:

View file

@ -51,6 +51,16 @@ static DEFINE_PER_CPU(bool, in_kernel_fpu);
*/
DEFINE_PER_CPU(struct fpu *, fpu_fpregs_owner_ctx);
#ifdef CONFIG_X86_DEBUG_FPU
struct fpu *x86_task_fpu(struct task_struct *task)
{
if (WARN_ON_ONCE(task->flags & PF_KTHREAD))
return NULL;
return (void *)task + sizeof(*task);
}
#endif
/*
* Can we use the FPU in kernel mode with the
* whole "kernel_fpu_begin/end()" sequence?
@ -599,11 +609,9 @@ int fpu_clone(struct task_struct *dst, unsigned long clone_flags, bool minimal,
*
* This is safe because task_struct size is a multiple of cacheline size.
*/
struct fpu *src_fpu = x86_task_fpu(current);
struct fpu *dst_fpu = x86_task_fpu(dst);
struct fpu *dst_fpu = (void *)dst + sizeof(*dst);
BUILD_BUG_ON(sizeof(*dst) % SMP_CACHE_BYTES != 0);
BUG_ON(!src_fpu);
/* The new task's FPU state cannot be valid in the hardware. */
dst_fpu->last_cpu = -1;
@ -666,7 +674,6 @@ int fpu_clone(struct task_struct *dst, unsigned long clone_flags, bool minimal,
if (update_fpu_shstk(dst, ssp))
return 1;
trace_x86_fpu_copy_src(src_fpu);
trace_x86_fpu_copy_dst(dst_fpu);
return 0;

View file

@ -38,7 +38,7 @@ static void fpu__init_cpu_generic(void)
/* Flush out any pending x87 state: */
#ifdef CONFIG_MATH_EMULATION
if (!boot_cpu_has(X86_FEATURE_FPU))
fpstate_init_soft(&x86_task_fpu(current)->fpstate->regs.soft);
;
else
#endif
asm volatile ("fninit");
@ -207,7 +207,6 @@ static void __init fpu__init_system_xstate_size_legacy(void)
fpu_kernel_cfg.default_size = size;
fpu_user_cfg.max_size = size;
fpu_user_cfg.default_size = size;
fpstate_reset(x86_task_fpu(current));
}
/*

View file

@ -870,9 +870,6 @@ void __init fpu__init_system_xstate(unsigned int legacy_size)
if (err)
goto out_disable;
/* Reset the state for the current task */
fpstate_reset(x86_task_fpu(current));
/*
* Update info used for ptrace frames; use standard-format size and no
* supervisor xstates:

View file

@ -181,10 +181,6 @@ SECTIONS
/* equivalent to task_pt_regs(&init_task) */
__top_init_kernel_stack = __end_init_stack - TOP_OF_KERNEL_STACK_PADDING - PTREGS_SIZE;
__x86_init_fpu_begin = .;
. = __x86_init_fpu_begin + 128*PAGE_SIZE;
__x86_init_fpu_end = .;
#ifdef CONFIG_X86_32
/* 32 bit has nosave before _edata */
NOSAVE_DATA