Linux Documentation
 help / color / mirror / Atom feed
From: Jason Gunthorpe <jgg@nvidia.com>
To: Alexandre Ghiti <alex@ghiti.fr>,
	Albert Ou <aou@eecs.berkeley.edu>,
	Ard Biesheuvel <ardb@kernel.org>, Arnd Bergmann <arnd@arndb.de>,
	Catalin Marinas <catalin.marinas@arm.com>,
	Jonathan Corbet <corbet@lwn.net>, David Sterba <dsterba@suse.com>,
	Ilias Apalodimas <ilias.apalodimas@linaro.org>,
	linux-arch@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-doc@vger.kernel.org, linux-efi@vger.kernel.org,
	linux-riscv@lists.infradead.org,
	Mark Rutland <mark.rutland@arm.com>,
	Palmer Dabbelt <palmer@dabbelt.com>,
	Paul Walmsley <pjw@kernel.org>,
	Randy Dunlap <rdunlap@infradead.org>,
	Simon Glass <sjg@chromium.org>,
	Shuah Khan <skhan@linuxfoundation.org>,
	Nick Terrell <terrelln@fb.com>, Will Deacon <will@kernel.org>
Cc: Alexandre Ghiti <alexghiti@rivosinc.com>,
	Conor Dooley <conor.dooley@microchip.com>,
	linux-integrity@vger.kernel.org,
	Palmer Dabbelt <palmer@rivosinc.com>,
	patches@lists.linux.dev,
	Ross Philipson <ross.philipson@gmail.com>,
	Sami Tolvanen <samitolvanen@google.com>,
	Song Shuai <songshuaishuai@tinylab.org>
Subject: [PATCH 05/16] efi/libstub: Add a general way to get symbols from the vmlinux into zboot
Date: Thu, 24 Sep 2026 10:53:08 -0300	[thread overview]
Message-ID: <5-v1-27d06b313981+8b-arm64_drtm_jgg@nvidia.com> (raw)
In-Reply-To: <0-v1-27d06b313981+8b-arm64_drtm_jgg@nvidia.com>

Currently the zboot stub has no access to symbols in the vmlinux. In
contrast x86 has a voffsets.h header that allows the stub to know whatever
symbols it wants for the decompressed image. ARM DRTM needs another 4
symbol locations to work, and it also wants to compile the DRTM libstub
code once and have it work in both zboot and embedded.

The current solution in arm is "code_size" from commit 45dd403da851
("efi/zboot: arm64: Inject kernel code size symbol into the zboot
payload"). This is neat, but it makes the zboot and embedded cases
work differently.

The x86 voffsets.h approach is also nice, but it can only work in zboot
since it relies on 'nm vmlinux' to extract the locations. That's a
circular dependency for the embedded stub.

One idea that meets the requirements is to embed a struct of offsets
inside the vmlinux and then have both stubs know its offset from the start
of the image.

First, each arch defines what information it wants the stub to have in a
struct:

       struct efi_image_info {
	       __le64 code_size;
       };

Second, it populates the struct with the linker:

       EFI_IMAGE_INFO(
	       /* code_size */
	       EFI_IMAGE_INFO_OFFSET(__inittext_end)
       )

This approach with the linker is guaranteed to emit a value and not a
relocation. I looked at writing the struct initializer in C, but that can
result in relocations inside the struct. That seemed sketchy so I stuck
with a linker script approach.

Finally, any stub code, either in zboot or embedded can access the struct
through:

  const struct efi_image_info *efi_get_image_info(unsigned long image_base);

The makefiles arrange that both links have a "u32 efi_image_info_offset"
symbol that contains the value. For vmlinux this links to a symbol created
by the EFI_IMAGE_INFO() macro, for zboot it uses the same technique as
code_size.

Since this needs arch changes, protect it under
CONFIG_EFI_STUB_IMAGE_INFO. The arch should define the struct and use the
linker macro before enabling that config.

Since everything is linked together, and the actual location of the struct
is not fixed, this is all private within the kernel build and can't become
ABI to any bootloader.

As some follow-up work, it seems interesting to standardize on this
mechanism and remove the PROVIDE() and voffset.h alternatives. This would
also avoid needing to pass sysfb_primary_display through EFI from zboot,
for example.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/firmware/efi/Kconfig                |  3 ++
 drivers/firmware/efi/libstub/Makefile.zboot |  9 +++++
 drivers/firmware/efi/libstub/efistub.h      | 29 ++++++++++++++
 drivers/firmware/efi/libstub/zboot.lds      |  3 ++
 include/asm-generic/vmlinux.lds.h           | 42 +++++++++++++++++++++
 5 files changed, 86 insertions(+)

diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 29e0729299f5bd..3d6fb3ca2806ca 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -72,6 +72,9 @@ config EFI_RUNTIME_WRAPPERS
 config EFI_GENERIC_STUB
 	bool
 
+config EFI_STUB_IMAGE_INFO
+	bool
+
 config EFI_ZBOOT
 	bool "Enable the generic EFI decompressor"
 	depends on EFI_GENERIC_STUB && !ARM
diff --git a/drivers/firmware/efi/libstub/Makefile.zboot b/drivers/firmware/efi/libstub/Makefile.zboot
index 832deee36e48e9..6eebac66b73b18 100644
--- a/drivers/firmware/efi/libstub/Makefile.zboot
+++ b/drivers/firmware/efi/libstub/Makefile.zboot
@@ -26,8 +26,17 @@ zboot-size-len-$(CONFIG_KERNEL_ZSTD)	:= 4
 $(obj)/vmlinuz: $(obj)/vmlinux.bin FORCE
 	$(call if_changed,$(zboot-method-y))
 
+# Architectures may expose a private image information structure to the EFI
+# stub. Inject its offset into the zboot executable so it remains available
+# after the payload has been compressed.
+efi-zboot-objcopy-flags-$(CONFIG_EFI_STUB_IMAGE_INFO) = \
+	--add-symbol efi_zboot_image_info_offset=0x$$( \
+		$(NM) vmlinux | \
+		awk '$$3 == "_efi_image_info_offset" { print $$1 }')
+
 # avoid eager evaluation to prevent references to non-existent build artifacts
 OBJCOPYFLAGS_vmlinuz.o = -I binary -O $(EFI_ZBOOT_BFD_TARGET) $(EFI_ZBOOT_OBJCOPY_FLAGS) \
+			  $(efi-zboot-objcopy-flags-y) \
 			  --rename-section .data=.gzdata,load,alloc,readonly,contents
 $(obj)/vmlinuz.o: $(obj)/vmlinuz FORCE
 	$(call if_changed,objcopy)
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index fd91fc15ec810b..da01d6005a62af 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -1176,6 +1176,35 @@ void free_primary_display(struct sysfb_display_info *dpy);
 void efi_cache_sync_image(unsigned long image_base,
 			  unsigned long alloc_size);
 
+#ifdef CONFIG_EFI_STUB_IMAGE_INFO
+struct efi_image_info;
+
+static inline const struct efi_image_info *
+efi_get_image_info(unsigned long image_base)
+{
+	/*
+	 * The offset of the struct efi_image_info from the start of the kernel
+	 * image. The linker script of whatever is embedding the stub emits this
+	 * word, see EFI_IMAGE_INFO() for the vmlinux case and zboot.lds for the
+	 * zboot case.
+	 */
+	extern const u32 efi_image_info_offset;
+
+	return (const struct efi_image_info *)(image_base +
+					      efi_image_info_offset);
+}
+
+static inline void *__efi_get_image_symbol(unsigned long image_base,
+					   const __le64 *symbol)
+{
+	return (void *)(image_base + (unsigned long)le64_to_cpup(symbol));
+}
+
+#define efi_get_image_symbol(image_base, symbol) \
+	__efi_get_image_symbol(image_base,       \
+			       &efi_get_image_info(image_base)->symbol);
+#endif
+
 struct efi_smbios_record {
 	u8	type;
 	u8	length;
diff --git a/drivers/firmware/efi/libstub/zboot.lds b/drivers/firmware/efi/libstub/zboot.lds
index 367907eb7d8698..cc55aa8fb0630f 100644
--- a/drivers/firmware/efi/libstub/zboot.lds
+++ b/drivers/firmware/efi/libstub/zboot.lds
@@ -3,6 +3,7 @@
 ENTRY(__efistub_efi_zboot_header);
 
 PROVIDE(zboot_code_size = ABSOLUTE(0));
+PROVIDE(efi_zboot_image_info_offset = ABSOLUTE(0));
 
 SECTIONS
 {
@@ -24,6 +25,8 @@ SECTIONS
 		. = ALIGN(4);
 		__efistub_code_size = .;
 		LONG(zboot_code_size);
+		__efistub_efi_image_info_offset = .;
+		LONG(efi_zboot_image_info_offset);
 
 		_etext = ALIGN(4096);
 		. = _etext;
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 1786a8e4323b9f..196c0f27efcd83 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -98,6 +98,48 @@
 #define RO_EXCEPTION_TABLE
 #endif
 
+/*
+ * Architecture specific information made available to the EFI stub, see
+ * CONFIG_EFI_STUB_IMAGE_INFO. The architecture describes the data with a
+ * struct efi_image_info in its asm/image.h and emits the matching bytes here
+ * through contents, using linker expressions the compiler cannot compute.
+ *
+ * Place in the same section as INIT_DATA.
+ *
+ * The architecture must also define EFI_IMAGE_INFO_SIZE to sizeof(struct
+ * efi_image_info), and that definition has to be visible to the linker script
+ * before this macro is used. Keeping the two in sync is checked by a
+ * static_assert() next to the struct and by the ASSERT() below.
+ *
+ * The struct's offset from _text is emitted as a u32 at
+ * __efi_image_info_offset, which is what the stub's efi_get_image_info()
+ * reads. The arch has to alias it into the stub's symbol namespace. The
+ * absolute _efi_image_info_offset is the same value, it is extracted from
+ * vmlinux with nm and injected into the zboot stub, see Makefile.zboot.
+ */
+#ifdef CONFIG_EFI_STUB_IMAGE_INFO
+#define EFI_IMAGE_INFO_ENTRY(value)            \
+	LONG(DATA_LE32((value) & 0xffffffff)); \
+	LONG(DATA_LE32((value) >> 32))
+#define EFI_IMAGE_INFO_OFFSET(symbol) EFI_IMAGE_INFO_ENTRY(symbol - _text)
+
+#define EFI_IMAGE_INFO(contents)                                               \
+	.= ALIGN(8);                                                           \
+	__efi_image_info =.;                                                   \
+	contents;                                                              \
+	__efi_image_info_end =.;                                               \
+	ASSERT(__efi_image_info_end - __efi_image_info == EFI_IMAGE_INFO_SIZE, \
+	       "invalid EFI image-info size");                                 \
+	_efi_image_info_offset = ABSOLUTE(__efi_image_info - _text);           \
+	ASSERT(_efi_image_info_offset <= 0xffffffff,                           \
+	       "EFI image-info offset does not fit in u32");                   \
+	.= ALIGN(4);                                                           \
+	__efi_image_info_offset =.;                                            \
+	LONG(_efi_image_info_offset);
+#else
+#define EFI_IMAGE_INFO(contents)
+#endif
+
 /* Align . function alignment. */
 #define ALIGN_FUNCTION()  . = ALIGN(CONFIG_FUNCTION_ALIGNMENT)
 
-- 
2.43.0


  parent reply	other threads:[~2026-09-24 13:53 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
2026-09-24 13:53 ` [PATCH 01/16] efi/libstub: Fix error unwind freeing fdt in allocate_new_fdt_and_exit_boot() Jason Gunthorpe
2026-09-24 22:42   ` Jonathan Cameron
2026-09-24 23:44     ` Jason Gunthorpe
2026-09-24 13:53 ` [PATCH 02/16] efi/riscv: libstub: Don't set image_size in handle_kernel_image() Jason Gunthorpe
2026-09-24 13:53 ` [PATCH 03/16] efi/libstub: Free cmdline_ptr in efi_pe_entry Jason Gunthorpe
2026-09-24 22:49   ` Jonathan Cameron
2026-09-25 12:59     ` Jason Gunthorpe
2026-09-25 13:20       ` Ard Biesheuvel
2026-09-24 13:53 ` [PATCH 04/16] vmlinux.lds: Move DATA_LE32() from arm64 to the common linker script Jason Gunthorpe
2026-09-24 22:53   ` Jonathan Cameron
2026-09-24 23:50     ` Jason Gunthorpe
2026-09-25 13:30       ` Ard Biesheuvel
2026-09-24 13:53 ` Jason Gunthorpe [this message]
2026-09-24 13:53 ` [PATCH 06/16] arm64/efi: Use CONFIG_EFI_STUB_IMAGE_INFO for code_size Jason Gunthorpe
2026-09-24 13:53 ` [PATCH 07/16] efi/zboot: Lift efi_cache_sync_image() from efi_zboot_decompress() Jason Gunthorpe
2026-09-24 22:57   ` Jonathan Cameron
2026-09-24 23:53     ` Jason Gunthorpe
2026-09-24 13:53 ` [PATCH 08/16] efi/libstub: Add generic arch callbacks for DRTM Jason Gunthorpe
2026-09-24 13:53 ` [PATCH 09/16] efi/libstub: Have efi_kaslr_relocate_kernel() handle extra_size Jason Gunthorpe
2026-09-24 13:53 ` [PATCH 10/16] efi: Add a __efi_data_handoff section annotation Jason Gunthorpe
2026-09-24 13:53 ` [PATCH 11/16] efi/libstub: Put the stub's writable data in unique sections for DRTM Jason Gunthorpe
2026-09-24 13:53 ` [PATCH 12/16] arm64: drtm: Add macro definitions for DEN0113 Jason Gunthorpe
2026-09-25  0:29   ` Jonathan Cameron
2026-09-26 18:27     ` Jason Gunthorpe
2026-09-24 13:53 ` [PATCH 13/16] arm64: drtm: Update the linker script for EFI_STUB_DRTM Jason Gunthorpe
2026-09-24 13:53 ` [PATCH 14/16] arm64: drtm: Add drtm_entry point to head.S Jason Gunthorpe
2026-09-24 13:53 ` [PATCH 15/16] arm64: drtm: Call UNPROTECT_MEMORY Jason Gunthorpe
2026-09-24 13:53 ` [PATCH 16/16] efi/arm64: Implement ARM64 DRTM in the stub Jason Gunthorpe
2026-09-25 18:37   ` Jonathan Cameron
2026-09-26 18:45     ` Jason Gunthorpe

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=5-v1-27d06b313981+8b-arm64_drtm_jgg@nvidia.com \
    --to=jgg@nvidia.com \
    --cc=alex@ghiti.fr \
    --cc=alexghiti@rivosinc.com \
    --cc=aou@eecs.berkeley.edu \
    --cc=ardb@kernel.org \
    --cc=arnd@arndb.de \
    --cc=catalin.marinas@arm.com \
    --cc=conor.dooley@microchip.com \
    --cc=corbet@lwn.net \
    --cc=dsterba@suse.com \
    --cc=ilias.apalodimas@linaro.org \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-efi@vger.kernel.org \
    --cc=linux-integrity@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=mark.rutland@arm.com \
    --cc=palmer@dabbelt.com \
    --cc=palmer@rivosinc.com \
    --cc=patches@lists.linux.dev \
    --cc=pjw@kernel.org \
    --cc=rdunlap@infradead.org \
    --cc=ross.philipson@gmail.com \
    --cc=samitolvanen@google.com \
    --cc=sjg@chromium.org \
    --cc=skhan@linuxfoundation.org \
    --cc=songshuaishuai@tinylab.org \
    --cc=terrelln@fb.com \
    --cc=will@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