mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/3] Move memory acceptance x86 arch code into EFI stub
@ 2026-09-14 18:37 Ard Biesheuvel
  2026-09-14 18:37 ` [PATCH 1/3] x86/tdx: Share tdx_panic() with the " Ard Biesheuvel
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Ard Biesheuvel @ 2026-09-14 18:37 UTC (permalink / raw)
  To: linux-efi
  Cc: linux-kernel, x86, Ard Biesheuvel, Kiryl Shutsemau (Meta),
	Borislav Petkov

This is a follow-up to [0].

Move arch_accept_memory(), which is only called by the EFI stub and
never by the decompressor on a non-EFI boot, into the EFI stub, and
avoid relying directly on decompressor APIs such as error().

Instead, call tdx_panic() on a failure to accept memory in a TDX guest.

This makes the decompressor's implementation of panic() obsolete, and
allows it to be removed. This is a prerequisite for dropping the
implementation of snprintf() from the EFI stub entirely, which is what
the series containing [0] implements.

[0] http://lore.kernel.org/r/20260909115530.1924665-13-ardb+git@google.com

Cc: Kiryl Shutsemau (Meta) <kas@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>

Ard Biesheuvel (3):
  x86/tdx: Share tdx_panic() with the EFI stub
  x86/boot: Move unaccepted memory handling out of the decompressor
  x86/boot: Drop unused implementation of panic()

 arch/x86/boot/compressed/error.c        | 19 ---------
 arch/x86/boot/compressed/error.h        |  1 -
 arch/x86/boot/compressed/mem.c          | 42 --------------------
 arch/x86/boot/compressed/sev.h          |  2 -
 arch/x86/coco/tdx/tdx-shared.c          | 35 ++++++++++++++++
 arch/x86/coco/tdx/tdx.c                 | 35 ----------------
 arch/x86/include/asm/sev.h              |  2 +
 arch/x86/include/asm/shared/tdx.h       |  1 +
 drivers/firmware/efi/libstub/x86-stub.c | 40 +++++++++++++++++++
 9 files changed, 78 insertions(+), 99 deletions(-)


base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
-- 
2.47.3


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] x86/tdx: Share tdx_panic() with the EFI stub
  2026-09-14 18:37 [PATCH 0/3] Move memory acceptance x86 arch code into EFI stub Ard Biesheuvel
@ 2026-09-14 18:37 ` Ard Biesheuvel
  2026-09-14 18:37 ` [PATCH 2/3] x86/boot: Move unaccepted memory handling out of the decompressor Ard Biesheuvel
  2026-09-14 18:37 ` [PATCH 3/3] x86/boot: Drop unused implementation of panic() Ard Biesheuvel
  2 siblings, 0 replies; 4+ messages in thread
From: Ard Biesheuvel @ 2026-09-14 18:37 UTC (permalink / raw)
  To: linux-efi
  Cc: linux-kernel, x86, Ard Biesheuvel, Kiryl Shutsemau (Meta),
	Borislav Petkov

Move the implementation of tdx_panic() into the source file that is
shared with the decompressor and the EFI stub.

Use memcpy() and strnlen() instead of strtomem_pad(), as the latter does
not exist in the early boot code.

Note that __tdx_hypercall() may call __tdx_hypercall_failed() if the
hypercall returns with an error (while it should never return to begin
with). __tdx_hypercall_failed() calls the decompressor's error()
routine, which prints a message and then loops forever.

When called from the EFI stub, this error() call may attempt to use port
I/O to the default serial port rather than the TDX hypercalls which the
decompressor uses normally to print diagnostics to the console, but this
is fine: given that this situation only occurs after a catastrophic
error, and a subsequent spurious return from tdx_panic(), whether
error() uses port I/O or not is rather moot at that point, as long as it
never returns.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 arch/x86/coco/tdx/tdx-shared.c    | 35 ++++++++++++++++++++
 arch/x86/coco/tdx/tdx.c           | 35 --------------------
 arch/x86/include/asm/shared/tdx.h |  1 +
 3 files changed, 36 insertions(+), 35 deletions(-)

diff --git a/arch/x86/coco/tdx/tdx-shared.c b/arch/x86/coco/tdx/tdx-shared.c
index 1655aa56a0a5..5fc36c8b35db 100644
--- a/arch/x86/coco/tdx/tdx-shared.c
+++ b/arch/x86/coco/tdx/tdx-shared.c
@@ -89,3 +89,38 @@ noinstr u64 __tdx_hypercall(struct tdx_module_args *args)
 	/* TDVMCALL leaf return code is in R10 */
 	return args->r10;
 }
+
+void __noreturn tdx_panic(const char *msg)
+{
+	struct tdx_module_args args = {
+		.r10 = TDX_HYPERCALL_STANDARD,
+		.r11 = TDVMCALL_REPORT_FATAL_ERROR,
+		.r12 = 0, /* Error code: 0 is Panic */
+	};
+	union {
+		/* Define register order according to the GHCI */
+		struct { u64 r14, r15, rbx, rdi, rsi, r8, r9, rdx; };
+
+		char bytes[64] __nonstring;
+	} message = {};
+
+	/* VMM assumes '\0' in byte 65, if the message took all 64 bytes */
+	memcpy(message.bytes, msg, strnlen(msg, sizeof(message)));
+
+	args.r8  = message.r8;
+	args.r9  = message.r9;
+	args.r14 = message.r14;
+	args.r15 = message.r15;
+	args.rdi = message.rdi;
+	args.rsi = message.rsi;
+	args.rbx = message.rbx;
+	args.rdx = message.rdx;
+
+	/*
+	 * This hypercall should never return and it is not safe
+	 * to keep the guest running. Call it forever if it
+	 * happens to return.
+	 */
+	while (1)
+		__tdx_hypercall(&args);
+}
diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
index f904a636d449..a9a16d0fb5c2 100644
--- a/arch/x86/coco/tdx/tdx.c
+++ b/arch/x86/coco/tdx/tdx.c
@@ -198,41 +198,6 @@ u64 tdx_hcall_get_quote(u8 *buf, size_t size)
 }
 EXPORT_SYMBOL_GPL(tdx_hcall_get_quote);
 
-static void __noreturn tdx_panic(const char *msg)
-{
-	struct tdx_module_args args = {
-		.r10 = TDX_HYPERCALL_STANDARD,
-		.r11 = TDVMCALL_REPORT_FATAL_ERROR,
-		.r12 = 0, /* Error code: 0 is Panic */
-	};
-	union {
-		/* Define register order according to the GHCI */
-		struct { u64 r14, r15, rbx, rdi, rsi, r8, r9, rdx; };
-
-		char bytes[64] __nonstring;
-	} message;
-
-	/* VMM assumes '\0' in byte 65, if the message took all 64 bytes */
-	strtomem_pad(message.bytes, msg, '\0');
-
-	args.r8  = message.r8;
-	args.r9  = message.r9;
-	args.r14 = message.r14;
-	args.r15 = message.r15;
-	args.rdi = message.rdi;
-	args.rsi = message.rsi;
-	args.rbx = message.rbx;
-	args.rdx = message.rdx;
-
-	/*
-	 * This hypercall should never return and it is not safe
-	 * to keep the guest running. Call it forever if it
-	 * happens to return.
-	 */
-	while (1)
-		__tdx_hypercall(&args);
-}
-
 /*
  * The kernel cannot handle #VEs when accessing normal kernel memory. Ensure
  * that no #VE will be delivered for accesses to TD-private memory.
diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/shared/tdx.h
index f20e91d7ac35..e5785258e547 100644
--- a/arch/x86/include/asm/shared/tdx.h
+++ b/arch/x86/include/asm/shared/tdx.h
@@ -171,6 +171,7 @@ static inline u64 _tdx_hypercall(u64 fn, u64 r12, u64 r13, u64 r14, u64 r15)
 	return __tdx_hypercall(&args);
 }
 
+void __noreturn tdx_panic(const char *msg);
 
 /* Called from __tdx_hypercall() for unrecoverable failure */
 void __noreturn __tdx_hypercall_failed(void);
-- 
2.47.3


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 2/3] x86/boot: Move unaccepted memory handling out of the decompressor
  2026-09-14 18:37 [PATCH 0/3] Move memory acceptance x86 arch code into EFI stub Ard Biesheuvel
  2026-09-14 18:37 ` [PATCH 1/3] x86/tdx: Share tdx_panic() with the " Ard Biesheuvel
@ 2026-09-14 18:37 ` Ard Biesheuvel
  2026-09-14 18:37 ` [PATCH 3/3] x86/boot: Drop unused implementation of panic() Ard Biesheuvel
  2 siblings, 0 replies; 4+ messages in thread
From: Ard Biesheuvel @ 2026-09-14 18:37 UTC (permalink / raw)
  To: linux-efi
  Cc: linux-kernel, x86, Ard Biesheuvel, Kiryl Shutsemau (Meta),
	Borislav Petkov

arch_accept_memory() is an arch-specific hook that is required by the
EFI stub when processing memory that the firmware reports to the OS as
EFI_UNACCEPTED_MEMORY.

This hook is called after ExitBootServices() has been called, as before
that point, the EFI memory map may get updated behind the back of the
running EFI stub, making it difficult to get a stable view on it while
iterating over the entries.

Currently, the x86 version of this hook is implemented in its
decompressor rather than in the EFI stub itself, in a manner that is
problematic: when an error occurs, it calls the decompressor's error()
routine, but without having gone through the decompressor initialization
code. This means it will resort to direct port I/O rather than the
hypercall based interface that TDX guests would use otherwise.

Conceptually, code that is only called from the EFI stub, and never by
the decompressor when doing legacy boot, belongs in the EFI stub and not
in the decompressor.

So move it into the x86-specific EFI stub code, replacing the error() on
the TDX path with tdx_panic(), and dropping the error() when no CC
support is detected - the kernel can decide what to do in this case
after it has booted.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 arch/x86/boot/compressed/mem.c          | 42 --------------------
 arch/x86/boot/compressed/sev.h          |  2 -
 arch/x86/include/asm/sev.h              |  2 +
 drivers/firmware/efi/libstub/x86-stub.c | 40 +++++++++++++++++++
 4 files changed, 42 insertions(+), 44 deletions(-)

diff --git a/arch/x86/boot/compressed/mem.c b/arch/x86/boot/compressed/mem.c
index 0e9f84ab4bdc..1721af3a8039 100644
--- a/arch/x86/boot/compressed/mem.c
+++ b/arch/x86/boot/compressed/mem.c
@@ -2,48 +2,6 @@
 
 #include "error.h"
 #include "misc.h"
-#include "tdx.h"
-#include "sev.h"
-#include <asm/shared/tdx.h>
-
-/*
- * accept_memory() and process_unaccepted_memory() called from EFI stub which
- * runs before decompressor and its early_tdx_detect().
- *
- * Enumerate TDX directly from the early users.
- */
-static bool early_is_tdx_guest(void)
-{
-	static bool once;
-	static bool is_tdx;
-
-	if (!IS_ENABLED(CONFIG_INTEL_TDX_GUEST))
-		return false;
-
-	if (!once) {
-		u32 eax, sig[3];
-
-		cpuid_count(TDX_CPUID_LEAF_ID, 0, &eax,
-			    &sig[0], &sig[2],  &sig[1]);
-		is_tdx = !memcmp(TDX_IDENT, sig, sizeof(sig));
-		once = true;
-	}
-
-	return is_tdx;
-}
-
-void arch_accept_memory(phys_addr_t start, phys_addr_t end)
-{
-	/* Platform-specific memory-acceptance call goes here */
-	if (early_is_tdx_guest()) {
-		if (!tdx_accept_memory(start, end))
-			panic("TDX: Failed to accept memory\n");
-	} else if (early_is_sevsnp_guest()) {
-		snp_accept_memory(start, end);
-	} else {
-		error("Cannot accept memory: unknown platform\n");
-	}
-}
 
 bool init_unaccepted_memory(void)
 {
diff --git a/arch/x86/boot/compressed/sev.h b/arch/x86/boot/compressed/sev.h
index 22637b416b46..62e50c2e71ed 100644
--- a/arch/x86/boot/compressed/sev.h
+++ b/arch/x86/boot/compressed/sev.h
@@ -14,7 +14,6 @@
 
 void snp_accept_memory(phys_addr_t start, phys_addr_t end);
 u64 sev_get_status(void);
-bool early_is_sevsnp_guest(void);
 
 static inline u64 sev_es_rd_ghcb_msr(void)
 {
@@ -37,7 +36,6 @@ static inline void sev_es_wr_ghcb_msr(u64 val)
 
 static inline void snp_accept_memory(phys_addr_t start, phys_addr_t end) { }
 static inline u64 sev_get_status(void) { return 0; }
-static inline bool early_is_sevsnp_guest(void) { return false; }
 
 #endif
 
diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index 9e7a077c445d..843bf463d14d 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -464,6 +464,8 @@ static __always_inline void sev_es_nmi_complete(void)
 extern int __init sev_es_efi_map_ghcbs_cas(pgd_t *pgd);
 extern void sev_enable(struct boot_params *bp);
 
+bool early_is_sevsnp_guest(void);
+
 /*
  * RMPADJUST modifies the RMP permissions of a page of a lesser-
  * privileged (numerically higher) VMPL.
diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
index cef32e2c82d8..5009623e4a37 100644
--- a/drivers/firmware/efi/libstub/x86-stub.c
+++ b/drivers/firmware/efi/libstub/x86-stub.c
@@ -10,6 +10,7 @@
 #include <linux/pci.h>
 #include <linux/stddef.h>
 
+#include <asm/cpuid/api.h>
 #include <asm/efi.h>
 #include <asm/e820/types.h>
 #include <asm/setup.h>
@@ -17,6 +18,7 @@
 #include <asm/boot.h>
 #include <asm/kaslr.h>
 #include <asm/sev.h>
+#include <asm/shared/tdx.h>
 
 #include "efistub.h"
 #include "x86-stub.h"
@@ -1068,3 +1070,41 @@ void efi64_stub_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg,
 		      struct boot_params *boot_params);
 #endif
 #endif
+
+#ifdef CONFIG_UNACCEPTED_MEMORY
+/*
+ * process_unaccepted_memory() is called after ExitBootServices(), and so these
+ * memory acceptance routines cannot rely on EFI protocols for detecting the
+ * presence of TDX or SEV-SNP, or emit any kind of output if any error
+ * conditions are detected.
+ */
+static bool early_is_tdx_guest(void)
+{
+	static bool once;
+	static bool is_tdx;
+
+	if (!IS_ENABLED(CONFIG_INTEL_TDX_GUEST))
+		return false;
+
+	if (!once) {
+		u32 eax, sig[3];
+
+		cpuid_count(TDX_CPUID_LEAF_ID, 0, &eax,
+			    &sig[0], &sig[2],  &sig[1]);
+		is_tdx = !memcmp(TDX_IDENT, sig, sizeof(sig));
+		once = true;
+	}
+
+	return is_tdx;
+}
+
+void arch_accept_memory(phys_addr_t start, phys_addr_t end)
+{
+	if (early_is_tdx_guest()) {
+		if (!tdx_accept_memory(start, end))
+			tdx_panic("Failed to accept memory");
+	} else if (early_is_sevsnp_guest()) {
+		snp_accept_memory(start, end);
+	}
+}
+#endif
-- 
2.47.3


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 3/3] x86/boot: Drop unused implementation of panic()
  2026-09-14 18:37 [PATCH 0/3] Move memory acceptance x86 arch code into EFI stub Ard Biesheuvel
  2026-09-14 18:37 ` [PATCH 1/3] x86/tdx: Share tdx_panic() with the " Ard Biesheuvel
  2026-09-14 18:37 ` [PATCH 2/3] x86/boot: Move unaccepted memory handling out of the decompressor Ard Biesheuvel
@ 2026-09-14 18:37 ` Ard Biesheuvel
  2 siblings, 0 replies; 4+ messages in thread
From: Ard Biesheuvel @ 2026-09-14 18:37 UTC (permalink / raw)
  To: linux-efi
  Cc: linux-kernel, x86, Ard Biesheuvel, Kiryl Shutsemau (Meta),
	Borislav Petkov

The decompressor has its own implementation of panic(), which is based
on the vsnprintf() routine provided by the EFI stub.

The decompressor's panic() has no remaining users, and is implemented in
terms of the EFI stub's snprintf() implementation, which is going away
(and relying on the EFI stub from code that does not execute in the
context of the EFI boot services is a bad idea in general).

So drop it.

Acked-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 arch/x86/boot/compressed/error.c | 19 -------------------
 arch/x86/boot/compressed/error.h |  1 -
 2 files changed, 20 deletions(-)

diff --git a/arch/x86/boot/compressed/error.c b/arch/x86/boot/compressed/error.c
index 19a8251de506..ce5ed7d8265e 100644
--- a/arch/x86/boot/compressed/error.c
+++ b/arch/x86/boot/compressed/error.c
@@ -22,22 +22,3 @@ void error(char *m)
 	while (1)
 		asm("hlt");
 }
-
-/* EFI libstub  provides vsnprintf() */
-#ifdef CONFIG_EFI_STUB
-void panic(const char *fmt, ...)
-{
-	static char buf[1024];
-	va_list args;
-	int len;
-
-	va_start(args, fmt);
-	len = vsnprintf(buf, sizeof(buf), fmt, args);
-	va_end(args);
-
-	if (len && buf[len - 1] == '\n')
-		buf[len - 1] = '\0';
-
-	error(buf);
-}
-#endif
diff --git a/arch/x86/boot/compressed/error.h b/arch/x86/boot/compressed/error.h
index 31f9e080d61a..87062dea9a20 100644
--- a/arch/x86/boot/compressed/error.h
+++ b/arch/x86/boot/compressed/error.h
@@ -6,6 +6,5 @@
 
 void warn(const char *m);
 void error(char *m) __noreturn;
-void panic(const char *fmt, ...) __noreturn __cold;
 
 #endif /* BOOT_COMPRESSED_ERROR_H */
-- 
2.47.3


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-09-14 18:38 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-14 18:37 [PATCH 0/3] Move memory acceptance x86 arch code into EFI stub Ard Biesheuvel
2026-09-14 18:37 ` [PATCH 1/3] x86/tdx: Share tdx_panic() with the " Ard Biesheuvel
2026-09-14 18:37 ` [PATCH 2/3] x86/boot: Move unaccepted memory handling out of the decompressor Ard Biesheuvel
2026-09-14 18:37 ` [PATCH 3/3] x86/boot: Drop unused implementation of panic() Ard Biesheuvel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®