From: Jay Wang <wanjay@amazon.com>
To: Herbert Xu <herbert@gondor.apana.org.au>,
"David S . Miller" <davem@davemloft.net>,
<linux-crypto@vger.kernel.org>,
Masahiro Yamada <masahiroy@kernel.org>,
<linux-kbuild@vger.kernel.org>
Cc: Jay Wang <jay.wang.upstream@gmail.com>,
Vegard Nossum <vegard.nossum@oracle.com>,
Nicolai Stange <nstange@suse.de>,
Ilia Okomin <ilya.okomin@oracle.com>,
Hazem Mohamed Abuelfotoh <abuehaze@amazon.com>,
Bjoern Doebel <doebel@amazon.de>,
Martin Pohlack <mpohlack@amazon.de>,
Benjamin Herrenschmidt <benh@amazon.com>,
Nathan Chancellor <nathan@kernel.org>,
Nicolas Schier <nsc@kernel.org>,
Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>, Thomas Gleixner <tglx@kernel.org>,
Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
"H . Peter Anvin" <hpa@zytor.com>,
Luis Chamberlain <mcgrof@kernel.org>,
Petr Pavlu <petr.pavlu@suse.com>,
Daniel Gomez <da.gomez@kernel.org>,
Sami Tolvanen <samitolvanen@google.com>,
David Howells <dhowells@redhat.com>,
"David Woodhouse" <dwmw2@infradead.org>,
Jarkko Sakkinen <jarkko@kernel.org>,
"Ignat Korchagin" <ignat@linux.win>,
Lukas Wunner <lukas@wunner.de>,
"Alexei Starovoitov" <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
"Andrii Nakryiko" <andrii@kernel.org>,
<linux-arm-kernel@lists.infradead.org>, <x86@kernel.org>,
<linux-modules@vger.kernel.org>
Subject: [PATCH v2 13/19] Execute crypto initcalls during module initialization
Date: Sat, 18 Apr 2026 00:20:21 +0000 [thread overview]
Message-ID: <20260418002032.2877-14-wanjay@amazon.com> (raw)
In-Reply-To: <20260418002032.2877-1-wanjay@amazon.com>
After moving builtin cryptos into the standalone crypto module, to ensure
all such cryptos are properly initialized as they were builtin, the
initcalls of the cryptos should be executed at proper booting time.
To do so, this patch adds run_initcalls() function to execute the
initialization calls of the collected cryptos right after the module is
loaded. The function iterates through initcalls in the __fips_initcalls
section (which stores all function addresses of the collected crypto
initcalls) and executes them.
A key consideration is to ensure the crypto initcalls are executed in
proper order, for instance, some crypto initcalls are ought to execute
at `late_initcall` boot time level while some should be executed at
`module_init` boot time level. To do so, this patch enables coordination
between kernel and the crypto module initialization to preserve proper
execution order by hijacking the kernel initialization function
`do_initcall_level` with added synchronization helpers.
Signed-off-by: Jay Wang <wanjay@amazon.com>
---
crypto/fips140/fips140-loader.c | 93 +++++++++++++++++++++++++++++++++
crypto/fips140/fips140-module.c | 67 ++++++++++++++++++++++++
crypto/fips140/fips140-module.h | 12 +++++
include/linux/init.h | 10 ++++
init/main.c | 4 ++
5 files changed, 186 insertions(+)
diff --git a/crypto/fips140/fips140-loader.c b/crypto/fips140/fips140-loader.c
index 490fb7276befb..ab9a3f9c5599e 100644
--- a/crypto/fips140/fips140-loader.c
+++ b/crypto/fips140/fips140-loader.c
@@ -100,3 +100,96 @@ static int fips_loader_init(void)
vfree(vmalloc_mem); // Free after successful module loading
return ret;
}
+
+/* FIPS140 synchronization between kernel and module
+ *
+ * Synchronization levels map kernel initcall levels to FIPS module levels:
+ * - Level 0: subsys_initcall (kernel init level 4) - Basic subsystem initialization
+ * - Level 1: device_initcall (kernel init level 6) - Device driver initialization
+ * - Level 2: late_initcall (kernel init level 7) - Late system initialization
+ *
+ * The kernel marks each level complete and waits for the FIPS module to
+ * complete the corresponding level before proceeding to ensure proper
+ * initialization ordering between kernel crypto and FIPS module.
+ */
+atomic_t fips140_kernel_level_complete = ATOMIC_INIT(0);
+atomic_t fips140_module_level_complete = ATOMIC_INIT(0);
+
+/* Wait queues for efficient synchronization */
+DECLARE_WAIT_QUEUE_HEAD(fips140_kernel_wq);
+DECLARE_WAIT_QUEUE_HEAD(fips140_module_wq);
+
+void fips140_mark_kernel_level_complete(int level)
+{
+ atomic_or(1 << level, &fips140_kernel_level_complete);
+ wake_up(&fips140_kernel_wq);
+}
+
+bool fips140_is_kernel_level_complete(int level)
+{
+ return atomic_read(&fips140_kernel_level_complete) & (1 << level);
+}
+
+bool fips140_is_module_level_complete(int level)
+{
+ return atomic_read(&fips140_module_level_complete) & (1 << level);
+}
+
+void fips140_mark_module_level_complete(int level)
+{
+ atomic_or(1 << level, &fips140_module_level_complete);
+ wake_up(&fips140_module_wq);
+}
+
+static int fips140_sync_thread(void *data)
+{
+ pr_info("FIPS 140: starting sync thread\n");
+
+ /* Call FIPS loader explicitly */
+ int ret = fips_loader_init();
+ if (ret)
+ panic("FIPS 140: loader initialization failed: %d\n", ret);
+
+ pr_info("FIPS 140: sync thread finished\n");
+ return 0;
+}
+
+void __init start_fips140_loader(void)
+{
+ struct task_struct *task;
+
+ task = kthread_run(fips140_sync_thread, NULL, "fips140_sync");
+ if (IS_ERR(task)) {
+ panic("FIPS 140: failed to create sync thread\n");
+ }
+}
+
+void __init wait_until_fips140_level_sync(int level)
+{
+ /* Map kernel initcall levels to FIPS module levels */
+ int fips_level = -1;
+ if (level == 3) { /* Start FIPS loader thread at arch_initcall_sync level */
+ start_fips140_loader();
+ fips_level = 0;
+ } else if (level == 4) /* subsys_initcall */
+ fips_level = 1;
+ else if (level == 6) /* device_initcall */
+ fips_level = 2;
+ else if (level == 7) /* late_initcall */
+ fips_level = 3;
+
+ if (fips_level >= 0) {
+ /* Mark kernel level complete and wait for module level completion */
+ fips140_mark_kernel_level_complete(fips_level);
+ wait_event(fips140_module_wq, fips140_is_module_level_complete(fips_level));
+ }
+}
+
+EXPORT_SYMBOL(fips140_kernel_level_complete);
+EXPORT_SYMBOL(fips140_module_level_complete);
+EXPORT_SYMBOL(fips140_kernel_wq);
+EXPORT_SYMBOL(fips140_module_wq);
+EXPORT_SYMBOL(fips140_mark_kernel_level_complete);
+EXPORT_SYMBOL(fips140_is_kernel_level_complete);
+EXPORT_SYMBOL(fips140_is_module_level_complete);
+EXPORT_SYMBOL(fips140_mark_module_level_complete);
\ No newline at end of file
diff --git a/crypto/fips140/fips140-module.c b/crypto/fips140/fips140-module.c
index a942de8780efb..8767d98baacd9 100644
--- a/crypto/fips140/fips140-module.c
+++ b/crypto/fips140/fips140-module.c
@@ -16,9 +16,76 @@
#define CRYPTO_INTERNAL "CRYPTO_INTERNAL"
+/*
+ * Run FIPS module initcalls level by level, synchronizing with the
+ * kernel's initcall progression.
+ *
+ * Initcall section mapping (see include/linux/module.h):
+ * Level 0 (.fips_initcall0) <- subsys_initcall()
+ * Syncs with kernel subsys_initcall (initcall level 4)
+ * Level 1 (.fips_initcall1) <- module_init()
+ * Syncs with kernel device_initcall (initcall level 6)
+ * Level 2 (.fips_initcall2) <- late_initcall()
+ * Syncs with kernel late_initcall (initcall level 7)
+ */
+
+static int __init run_initcalls(void)
+{
+ typedef int (*initcall_t)(void);
+
+ extern initcall_t __fips140_initcall0_start[], __fips140_initcall0_end[];
+ extern initcall_t __fips140_initcall1_start[], __fips140_initcall1_end[];
+ extern initcall_t __fips140_initcall2_start[], __fips140_initcall2_end[];
+
+ initcall_t *starts[] = {
+ __fips140_initcall0_start,
+ __fips140_initcall1_start,
+ __fips140_initcall2_start,
+ };
+
+ initcall_t *ends[] = {
+ __fips140_initcall0_end,
+ __fips140_initcall1_end,
+ __fips140_initcall2_end,
+ };
+
+ pr_info("FIPS 140: run_initcalls starting\n");
+
+ for (int level = 0; level < ARRAY_SIZE(starts); level++) {
+
+ /* Run FIPS initcalls for this level */
+ for (initcall_t *initcall = starts[level]; initcall < ends[level]; ++initcall) {
+ int ret;
+ initcall_t fn = *initcall;
+
+ ret = fn();
+ if (!ret || ret == -ENODEV)
+ continue;
+
+ pr_err("FIPS 140: initcall %pS failed: %d\n", fn, ret);
+ }
+
+ if (level < 2)
+ fips140_mark_module_level_complete(level + 1);
+ /* Wait for kernel to complete this level */
+ wait_event(fips140_kernel_wq, fips140_is_kernel_level_complete(level + 1));
+ }
+
+ pr_info("FIPS 140: run_initcalls finished\n");
+ return 0;
+}
+
/* Initialize the FIPS 140 module */
static int __init fips140_init(void)
{
+ /* Signal that module is loaded and address placeholders are populated */
+ fips140_mark_module_level_complete(0);
+ wait_event(fips140_kernel_wq, fips140_is_kernel_level_complete(0));
+
+ pr_info("loading " FIPS140_MODULE_NAME "\n");
+
+ run_initcalls();
+ fips140_mark_module_level_complete(3);
return 0;
}
diff --git a/crypto/fips140/fips140-module.h b/crypto/fips140/fips140-module.h
index ed2b6e17969fc..e95dac8eeda9e 100644
--- a/crypto/fips140/fips140-module.h
+++ b/crypto/fips140/fips140-module.h
@@ -10,5 +10,17 @@
#include <linux/crypto.h>
#include <crypto/algapi.h>
#include <linux/init.h>
+#include <linux/atomic.h>
+#include <linux/wait.h>
+
+/* FIPS140 synchronization between kernel and module */
+extern atomic_t fips140_kernel_level_complete;
+extern atomic_t fips140_module_level_complete;
+extern wait_queue_head_t fips140_kernel_wq;
+
+void fips140_mark_kernel_level_complete(int level);
+bool fips140_is_kernel_level_complete(int level);
+bool fips140_is_module_level_complete(int level);
+void fips140_mark_module_level_complete(int level);
#endif /* _CRYPTO_FIPS140_MODULE_H */
diff --git a/include/linux/init.h b/include/linux/init.h
index 40331923b9f4a..eefbdfac1d41b 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -392,4 +392,14 @@ void __init parse_early_options(char *cmdline);
#define __exit_p(x) NULL
#endif
+#if defined(CONFIG_CRYPTO_FIPS140_EXTMOD) && !defined(__ASSEMBLY__)
+/* FIPS140 synchronization between kernel and module */
+void fips140_mark_kernel_level_complete(int level);
+bool fips140_is_kernel_level_complete(int level);
+bool fips140_is_module_level_complete(int level);
+void fips140_mark_module_level_complete(int level);
+void start_fips140_loader(void);
+void wait_until_fips140_level_sync(int level);
+#endif /* CONFIG_CRYPTO_FIPS140_EXTMOD && !__ASSEMBLY__ */
+
#endif /* _LINUX_INIT_H */
diff --git a/init/main.c b/init/main.c
index 96f93bb06c490..8ef50419b42e4 100644
--- a/init/main.c
+++ b/init/main.c
@@ -1452,6 +1452,10 @@ static void __init do_initcall_level(int level, char *command_line)
do_trace_initcall_level(initcall_level_names[level]);
for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
do_one_initcall(initcall_from_entry(fn));
+
+#ifdef CONFIG_CRYPTO_FIPS140_EXTMOD
+ wait_until_fips140_level_sync(level);
+#endif
}
static void __init do_initcalls(void)
--
2.47.3
next prev parent reply other threads:[~2026-04-18 0:23 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-18 0:20 [PATCH v2 00/19] crypto: Standalone crypto module Jay Wang
2026-04-18 0:20 ` [PATCH v2 01/19] crypto: add Kconfig options for standalone " Jay Wang
2026-04-18 0:20 ` [PATCH v2 02/19] crypto: add module entry for standalone crypto kernel module Jay Wang
2026-04-18 0:20 ` [PATCH v2 03/19] build: special compilation rule for building the standalone crypto module Jay Wang
2026-04-18 0:20 ` [PATCH v2 04/19] build: Add ELF marker for crypto-objs-m modules Jay Wang
2026-04-18 0:20 ` [PATCH v2 05/19] module: allow kernel module loading directly from memory Jay Wang
2026-04-18 0:20 ` [PATCH v2 06/19] crypto: add pluggable interface for module symbols referenced by the main kernel Jay Wang
2026-04-18 0:20 ` [PATCH v2 07/19] crypto: dedicated ELF sections for collected crypto initcalls Jay Wang
2026-04-18 0:20 ` [PATCH v2 08/19] crypto: fips140: add crypto module loader Jay Wang
2026-04-18 0:20 ` [PATCH v2 09/19] build: embed the standalone crypto module into vmlinux Jay Wang
2026-04-18 0:20 ` [PATCH v2 10/19] module: skip modversion checks for crypto modules Jay Wang
2026-04-18 0:20 ` [PATCH v2 11/19] build: add CONFIG_DEBUG_INFO_BTF_MODULES support for the standalone crypto kernel module Jay Wang
2026-04-18 0:20 ` [PATCH v2 12/19] Allow selective crypto module loading at boot based on FIPS mode Jay Wang
2026-04-18 0:20 ` Jay Wang [this message]
2026-04-18 0:20 ` [PATCH v2 14/19] crypto/algapi.c: skip crypto_check_module_sig() for the standalone crypto module Jay Wang
2026-04-18 0:20 ` [PATCH v2 15/19] crypto: fips140: add module integrity self-check Jay Wang
2026-04-18 0:20 ` [PATCH v2 16/19] crypto: convert exported symbols in architecture-independent crypto to pluggable symbols Jay Wang
2026-04-18 0:20 ` [PATCH v2 17/19] x86/crypto: convert exported symbols in x86 " Jay Wang
2026-04-18 0:20 ` [PATCH v2 18/19] arm64/crypto: convert exported symbols in arm64 " Jay Wang
2026-04-18 0:20 ` [PATCH v2 19/19] Add standalone crypto kernel module technical documentation Jay Wang
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=20260418002032.2877-14-wanjay@amazon.com \
--to=wanjay@amazon.com \
--cc=abuehaze@amazon.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=benh@amazon.com \
--cc=bp@alien8.de \
--cc=catalin.marinas@arm.com \
--cc=da.gomez@kernel.org \
--cc=daniel@iogearbox.net \
--cc=dave.hansen@linux.intel.com \
--cc=davem@davemloft.net \
--cc=dhowells@redhat.com \
--cc=doebel@amazon.de \
--cc=dwmw2@infradead.org \
--cc=herbert@gondor.apana.org.au \
--cc=hpa@zytor.com \
--cc=ignat@linux.win \
--cc=ilya.okomin@oracle.com \
--cc=jarkko@kernel.org \
--cc=jay.wang.upstream@gmail.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-kbuild@vger.kernel.org \
--cc=linux-modules@vger.kernel.org \
--cc=lukas@wunner.de \
--cc=masahiroy@kernel.org \
--cc=mcgrof@kernel.org \
--cc=mingo@redhat.com \
--cc=mpohlack@amazon.de \
--cc=nathan@kernel.org \
--cc=nsc@kernel.org \
--cc=nstange@suse.de \
--cc=petr.pavlu@suse.com \
--cc=samitolvanen@google.com \
--cc=tglx@kernel.org \
--cc=vegard.nossum@oracle.com \
--cc=will@kernel.org \
--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