From: Eric Biggers <ebiggers@kernel.org>
To: x86@kernel.org
Cc: linux-kernel@vger.kernel.org, linux-crypto@vger.kernel.org,
linux-pm@vger.kernel.org, Borislav Petkov <bp@alien8.de>,
Thomas Gleixner <tglx@linutronix.de>,
Ayush Jain <Ayush.Jain3@amd.com>,
Herbert Xu <herbert@gondor.apana.org.au>,
Ard Biesheuvel <ardb@kernel.org>
Subject: [PATCH 3/3] x86/fpu: Don't support kernel-mode FPU when irqs_disabled()
Date: Fri, 16 May 2025 16:18:58 -0700 [thread overview]
Message-ID: <20250516231858.27899-4-ebiggers@kernel.org> (raw)
In-Reply-To: <20250516231858.27899-1-ebiggers@kernel.org>
From: Eric Biggers <ebiggers@google.com>
Make irq_fpu_usable() return false when irqs_disabled(). That makes the
irqs_disabled() checks in kernel_fpu_begin_mask() and kernel_fpu_end()
unnecessary, so also remove those.
Rationale:
- There's no known use case for kernel-mode FPU when irqs_disabled().
arm64 and riscv already disallow kernel-mode FPU when irqs_disabled().
__save_processor_state() previously did expect kernel_fpu_begin() and
kernel_fpu_end() to work when irqs_disabled(), but this was a
different use case and not actual kernel-mode FPU use.
- This is more efficient, since one call to irqs_disabled() replaces two
irqs_disabled() and one in_hardirq().
- This fixes irq_fpu_usable() to correctly return false during CPU
initialization. Incorrectly returning true caused the SHA-256 library
code, which is called when loading AMD microcode, to take a
SIMD-optimized code path too early, causing a crash. By correctly
returning false from irq_fpu_usable(), the generic SHA-256 code
correctly gets used instead. (Note: SIMD-optimized SHA-256 doesn't
get enabled until subsys_initcall, but CPU hotplug can happen later.)
Fixes: 11d7956d526f ("crypto: x86/sha256 - implement library instead of shash")
Reported-by: Ayush Jain <Ayush.Jain3@amd.com>
Closes: https://lore.kernel.org/r/20250516112217.GBaCcf6Yoc6LkIIryP@fat_crate.local
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
arch/x86/kernel/fpu/core.c | 49 ++++++++++++++------------------------
1 file changed, 18 insertions(+), 31 deletions(-)
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index 476393b1d5e8f..9b3c5e17f86cd 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -66,42 +66,31 @@ struct fpu *x86_task_fpu(struct task_struct *task)
* Can we use the FPU in kernel mode with the
* whole "kernel_fpu_begin/end()" sequence?
*/
bool irq_fpu_usable(void)
{
- if (WARN_ON_ONCE(in_nmi()))
- return false;
-
/*
- * 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.
+ * To ensure that (non-explicitly-nested) kernel-mode FPU is always
+ * usable in task and softirq contexts, kernel_fpu_begin() disables
+ * preemption and softirqs, and kernel_fpu_end() re-enables them. That
+ * is not compatible with hardirqs being disabled (including hardirq
+ * context), or with NMI context. Support for kernel-mode FPU is not
+ * needed in those contexts anyway. Return false in those contexts.
+ *
+ * Returning false when irqs_disabled() also eliminates the need to
+ * explicitly check whether the FPU has been initialized yet during CPU
+ * initialization. Before then, hardirqs are still disabled.
*/
+ if (irqs_disabled() || WARN_ON_ONCE(in_nmi()))
+ return false;
+
+ /* Catch any explicitly nested usage, which should never happen. */
if (this_cpu_read(in_kernel_fpu)) {
- WARN_ON_FPU(!in_hardirq());
+ WARN_ON_FPU(1);
return false;
}
-
- /*
- * When not in NMI or hard interrupt context, FPU can be used in:
- *
- * - Task context except from within fpregs_lock()'ed critical
- * regions.
- *
- * - Soft interrupt processing context which cannot happen
- * while in a fpregs_lock()'ed critical region.
- */
- if (!in_hardirq())
- return true;
-
- /*
- * In hard interrupt context it's safe when soft interrupts
- * are enabled, which means the interrupt did not hit in
- * a fpregs_lock()'ed critical region.
- */
- return !softirq_count();
+ return true;
}
EXPORT_SYMBOL(irq_fpu_usable);
/*
* Track AVX512 state use because it is known to slow the max clock
@@ -443,12 +432,11 @@ static __always_inline void __fpu_save_state(void)
__cpu_invalidate_fpregs_state();
}
void kernel_fpu_begin_mask(unsigned int kfpu_mask)
{
- if (!irqs_disabled())
- fpregs_lock();
+ fpregs_lock();
WARN_ON_FPU(!irq_fpu_usable());
WARN_ON_FPU(this_cpu_read(in_kernel_fpu));
this_cpu_write(in_kernel_fpu, true);
@@ -467,12 +455,11 @@ EXPORT_SYMBOL_GPL(kernel_fpu_begin_mask);
void kernel_fpu_end(void)
{
WARN_ON_FPU(!this_cpu_read(in_kernel_fpu));
this_cpu_write(in_kernel_fpu, false);
- if (!irqs_disabled())
- fpregs_unlock();
+ fpregs_unlock();
}
EXPORT_SYMBOL_GPL(kernel_fpu_end);
#ifdef CONFIG_PM_SLEEP
/*
--
2.49.0
next prev parent reply other threads:[~2025-05-16 23:21 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-16 23:18 [PATCH 0/3] x86: Don't support kernel-mode FPU with hardirqs disabled Eric Biggers
2025-05-16 23:18 ` [PATCH 1/3] x86/fpu: Add fpu_save_state() for __save_processor_state() Eric Biggers
2025-05-16 23:18 ` [PATCH 2/3] x86/pm: Use fpu_save_state() in __save_processor_state() Eric Biggers
2025-05-16 23:18 ` Eric Biggers [this message]
2025-05-17 7:09 ` [PATCH 3/3] x86/fpu: Don't support kernel-mode FPU when irqs_disabled() Ingo Molnar
2025-05-17 18:39 ` Eric Biggers
2025-05-18 6:34 ` Ingo Molnar
2025-05-18 13:18 ` Ard Biesheuvel
2025-05-18 20:01 ` Eric Biggers
2025-05-19 8:05 ` Ingo Molnar
2025-05-19 9:49 ` Ard Biesheuvel
2025-05-19 12:57 ` Ingo Molnar
2025-05-19 13:50 ` Ard Biesheuvel
2025-05-20 7:42 ` Ingo Molnar
2025-05-17 1:30 ` [PATCH 0/3] x86: Don't support kernel-mode FPU with hardirqs disabled Eric Biggers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250516231858.27899-4-ebiggers@kernel.org \
--to=ebiggers@kernel.org \
--cc=Ayush.Jain3@amd.com \
--cc=ardb@kernel.org \
--cc=bp@alien8.de \
--cc=herbert@gondor.apana.org.au \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=tglx@linutronix.de \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.