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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox