Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/16] arm64: DRTM, boot portion
@ 2026-09-24 13:53 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
                   ` (15 more replies)
  0 siblings, 16 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

This is the first series for an implementation of ARM's DEN 0113
v1.4b Dynamic Root of Trust for Measurement (DRTM) launch protocol.
It is built on some generic changes to the EFI stubs that provide for
a simple, direct DRTM launch directly into vmlinux.

DRTM is a boot security technique that jumps into some platform trusted
environment prior to launching the OS. The trusted environment will
sanitize the CPU, block DMA, measure (SHA hash) the OS to a TPM, and then
jump into the OS. The security goal is to prevent tampering across the
launch: if the measurement says X, it should be impossible to tamper with
the boot such that the CPU is actually running Y. DRTM is a reaction to
the historically bad boot security in the UEFI world. It aims to make bugs
in UEFI/etc unimportant for OS security.

When I spoke to Catalin about this, he was interested in making the flow
cross arch. After looking at what AMD and Intel do, and how different the
kernel EFI flow is on x86, I have opted to do that from the perspective of
building some generic DRTM infrastructure for the arches using EFI_ZBOOT
and FDT. I've sketched out applying the same general ideas to x86 and it
works there too, but x86 is so different that not much is directly
re-used. I would argue the security/hardening work listed below is a more
important place to get commonality.

Several people have asked me about Trenchboot, which is the x86
out-of-tree DRTM implementation. In my view, ARM and Trenchboot have
converged on the same basic design. Both offer high-level functions to the
OS that don't leak out any platform-specific details. Trenchboot offers
these through an EFI mechanism from Grub, while ARM offers it through a
standardized FW based SMC API. Effectively Trenchboot is a reaction to x86
having primitives that are far too low level and far too complicated to
implement inside the EFI stub.

ARM does not suffer the same issues as x86. The EFI stub implementation
for ARM DRTM is only 400 lines in patch 16. This is because the standard
already offers a sufficient abstraction to the OS. There is no technical
reason to bounce back to Grub to hide complexity that doesn't even exist.

Further, due to how ARM has abstracted DRTM, we cannot hide the ARM
details from the post-launch Linux. The kernel must understand it is
inside an ARM-specific DLME, it must do the ARM specific ations, and it
must process the ARM-specific post-launch data structures that the FW
writes. All of the work in this series, and its followups would still be
needed if Grub was involved. There is also a sneaky ABI here, the choices
the stub makes during launch have to be matched by the vmlinux
accomodating them. Keeping this all in one source tree and one link with
no ABI is the right answer.

My hope is that this series will encourage other platforms, like RISCV, to
follow ARM's approach and not x86's. Further, I strongly suggest that the
x86 world standardize some EFI calls so the UEFI itself can provide the
platform specific DRTM implementation instead of involving Grub.

Broadly, ARM's abstraction does several key things for Linux:
 1) No TPM is required until after some ACPI is parsed. ARM has many
    different kinds of TPMs, so TPM without ACPI is hard.

 2) The launch uses a contiguous chunk of memory that can be
    perfectly overlaid on vmlinux, with space for the headers,
    measured section, unmeasured data, bss and trusted post-launch
    information. It is trivial to insert Linux into this scheme.

 3) The launch protocol is trivial. The launch directly measures a
    portion of vmlinux. About 50% of the stub code is just inspecting
    features and doing FW call compatibility work, not tricky DRTM
    things. Zero platform-specific code.

 4) The post-launch world isn't special. We don't need unique kernel
    patches to undo things that DRTM did. The normal drivers work in
    the normal way just fine.

This series is enough to perform the launch and get a working kernel
inside a Dynamic Launch Measured Environment (DLME). There are several
following security-focused topics/series that aim to further prevent
attackers in the unmeasured world from compromising the measured
kernel. Much of this list comes from internal security research at NVIDIA
on securing Linux post-DRTM.

 - The kernel command line needs to be measured, without any "early tpm"
   for Linux.

 - ARM's DRTM protocol for verifying the address map needs to be implemented

 - ARM's protocol for checking the "TCB" ACPI needs to be implemented

 - Non-TCB ACPI needs to be deferred until the TPM is discovered and
   then the tables are measured into the TPM

 - Initrd/Initramfs measurement by Linux before using it

 - Exposing the DRTM launches TCG audit log to userspace

 - TPM locality handling

 - Non-EFI boot, particularly kexec

 - FDT security

 - KASLR RNG security

These topics all largely require different maintainers and different
cross-arch solutions. Post-launch kernel defense against an adversarial
boot is a complicated topic with several different threat models people
are interested in. It has alot of overlap with the Confidential Computing
need to deal with an adversarial host.

This series is arranged to try to build re-usable things that any
arch can use to implement DRTM:
 - A technique to communicate the link layout to the zboot stub based
   on ARM's code_size trick
 - New general linker sections/etc to move mutable data out of the
   measured range
 - Cross-arch symbols __drtm_measured_start/end that allow a user
   tool to compute the measurement hash from the vmlinux itself.
   Because of the mutable values this isn't just all of vmlinux.
 - CONFIG_EFI_DRTM and general EFI stub arch hooks to plug into for
   EFI ZBOOT and FDT arches
 - Shared drtm= kernel command-line processing

For x86, it does set some user-visible expectations like how to compute a
hash for vmlinux and the drtm= parameter. IMHO, these are key areas to get
cross-arch alignment on so the user tooling, like a systemd UKI, can use
DRTM easily.

I have a slop'd up qemu that implements the SMC protocol which is very
useful for testing:
  https://github.com/jgunthorpe/qemu/commits/arm64_drtm

NVIDIA has several real HW platforms this works with, I'll get more HW
testing as the review progresses.

This is on github: https://github.com/jgunthorpe/linux/commits/arm64_drtm

I've fed it to a local Sashiko and am satisfied the remaining remarks are
not applicable, and fixed several of the previously existing bugs it
found.

Jason Gunthorpe (16):
  efi/libstub: Fix error unwind freeing fdt in
    allocate_new_fdt_and_exit_boot()
  efi/riscv: libstub: Don't set image_size in handle_kernel_image()
  efi/libstub: Free cmdline_ptr in efi_pe_entry
  vmlinux.lds: Move DATA_LE32() from arm64 to the common linker script
  efi/libstub: Add a general way to get symbols from the vmlinux into
    zboot
  arm64/efi: Use CONFIG_EFI_STUB_IMAGE_INFO for code_size
  efi/zboot: Lift efi_cache_sync_image() from efi_zboot_decompress()
  efi/libstub: Add generic arch callbacks for DRTM
  efi/libstub: Have efi_kaslr_relocate_kernel() handle extra_size
  efi: Add a __efi_data_handoff section annotation
  efi/libstub: Put the stub's writable data in unique sections for DRTM
  arm64: drtm: Add macro definitions for DEN0113
  arm64: drtm: Update the linker script for EFI_STUB_DRTM
  arm64: drtm: Add drtm_entry point to head.S
  arm64: drtm: Call UNPROTECT_MEMORY
  efi/arm64: Implement ARM64 DRTM in the stub

 .../admin-guide/kernel-parameters.txt         |  12 +
 arch/arm64/Kconfig                            |  17 +
 arch/arm64/boot/Makefile                      |   3 -
 arch/arm64/include/asm/drtm.h                 | 215 +++++++++
 arch/arm64/include/asm/image.h                |  21 +
 arch/arm64/kernel/Makefile                    |   1 +
 arch/arm64/kernel/drtm.c                      |  49 +++
 arch/arm64/kernel/head.S                      |  83 ++++
 arch/arm64/kernel/image-vars.h                |   8 +-
 arch/arm64/kernel/image.h                     |  14 -
 arch/arm64/kernel/vmlinux.lds.S               |  76 +++-
 drivers/firmware/efi/Kconfig                  |  33 ++
 drivers/firmware/efi/efi-init.c               |   2 +-
 drivers/firmware/efi/libstub/Makefile         |  11 +
 drivers/firmware/efi/libstub/Makefile.zboot   |  11 +-
 drivers/firmware/efi/libstub/arm64-drtm.c     | 414 ++++++++++++++++++
 drivers/firmware/efi/libstub/arm64-stub.c     |   6 +-
 drivers/firmware/efi/libstub/arm64.c          |   4 +-
 drivers/firmware/efi/libstub/efi-stub-entry.c |   6 +-
 .../firmware/efi/libstub/efi-stub-helper.c    |  34 ++
 drivers/firmware/efi/libstub/efistub.h        |  65 +++
 drivers/firmware/efi/libstub/fdt.c            |  12 +-
 drivers/firmware/efi/libstub/kaslr.c          |  72 ++-
 drivers/firmware/efi/libstub/riscv-stub.c     |   6 +-
 .../efi/libstub/zboot-decompress-gzip.c       |   2 -
 .../efi/libstub/zboot-decompress-zstd.c       |   2 -
 drivers/firmware/efi/libstub/zboot.c          |  26 +-
 drivers/firmware/efi/libstub/zboot.lds        |  10 +-
 include/asm-generic/vmlinux.lds.h             |  57 +++
 include/linux/efi.h                           |  12 +
 30 files changed, 1221 insertions(+), 63 deletions(-)
 create mode 100644 arch/arm64/include/asm/drtm.h
 create mode 100644 arch/arm64/kernel/drtm.c
 create mode 100644 drivers/firmware/efi/libstub/arm64-drtm.c


base-commit: df2908090cda368b01ff43709f51890076c56157
-- 
2.43.0



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

* [PATCH 01/16] efi/libstub: Fix error unwind freeing fdt in allocate_new_fdt_and_exit_boot()
  2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
@ 2026-09-24 13:53 ` Jason Gunthorpe
  2026-09-24 22:42   ` Jonathan Cameron
  2026-09-24 13:53 ` [PATCH 02/16] efi/riscv: libstub: Don't set image_size in handle_kernel_image() Jason Gunthorpe
                   ` (14 subsequent siblings)
  15 siblings, 1 reply; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

Sashiko says fdt_addr can point to either an allocated fdt or the fdt from
get_fdt() which is memory owned by FW.

Only the allocated fdt should be freed on the error unwind path. Use a
dedicated variable for the allocation's size so that the free does not get
confused.

Fixes: 4fc8e738ff3e ("efi: libstub: remove DT dependency from generic stub")
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/firmware/efi/libstub/fdt.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
index 23b3543d3041b0..5b2dd709d7b151 100644
--- a/drivers/firmware/efi/libstub/fdt.c
+++ b/drivers/firmware/efi/libstub/fdt.c
@@ -229,6 +229,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
 	u32 desc_ver;
 	efi_status_t status;
 	struct exit_boot_struct priv;
+	unsigned long fdt_size_allocated = 0;
 	unsigned long fdt_addr = 0;
 	unsigned long fdt_size = 0;
 
@@ -257,6 +258,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
 			efi_err("Failed to load device tree!\n");
 			goto fail;
 		}
+		fdt_size_allocated = fdt_size;
 	}
 
 	if (fdt_addr) {
@@ -334,7 +336,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
 	efi_free(MAX_FDT_SIZE, *new_fdt_addr);
 
 fail:
-	efi_free(fdt_size, fdt_addr);
+	efi_free(fdt_size_allocated, fdt_addr);
 	if (!efi_novamap)
 		efi_bs_call(free_pool, priv.runtime_map);
 
-- 
2.43.0



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

* [PATCH 02/16] efi/riscv: libstub: Don't set image_size in handle_kernel_image()
  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 13:53 ` Jason Gunthorpe
  2026-09-24 13:53 ` [PATCH 03/16] efi/libstub: Free cmdline_ptr in efi_pe_entry Jason Gunthorpe
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

Sashiko points out the image_size should only be set if image_addr was
reassigned to some allocated memory. If image_size is not zero then the
caller will free the image_addr pointer.

efi_kaslr_relocate_kernel() never works like that, if it changes
image_addr to allocated memory the free is done through reserve_size.

Fixes: b7ac4b8ee73d ("riscv: libstub: Implement KASLR by using generic functions")
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/firmware/efi/libstub/riscv-stub.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/firmware/efi/libstub/riscv-stub.c b/drivers/firmware/efi/libstub/riscv-stub.c
index e7d9204baee312..725b634c517919 100644
--- a/drivers/firmware/efi/libstub/riscv-stub.c
+++ b/drivers/firmware/efi/libstub/riscv-stub.c
@@ -37,17 +37,14 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 	kernel_codesize = __init_text_end - _start;
 	kernel_memsize = kernel_size + (_end - _edata);
 	*image_addr = (unsigned long)_start;
-	*image_size = kernel_memsize;
-	*reserve_size = *image_size;
+	*reserve_size = kernel_memsize;
 
 	status = efi_kaslr_relocate_kernel(image_addr,
 					   reserve_addr, reserve_size,
 					   kernel_size, kernel_codesize, kernel_memsize,
 					   efi_kaslr_get_phys_seed(image_handle));
-	if (status != EFI_SUCCESS) {
+	if (status != EFI_SUCCESS)
 		efi_err("Failed to relocate kernel\n");
-		*image_size = 0;
-	}
 
 	return status;
 }
-- 
2.43.0



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

* [PATCH 03/16] efi/libstub: Free cmdline_ptr in efi_pe_entry
  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 13:53 ` [PATCH 02/16] efi/riscv: libstub: Don't set image_size in handle_kernel_image() Jason Gunthorpe
@ 2026-09-24 13:53 ` Jason Gunthorpe
  2026-09-24 22:49   ` Jonathan Cameron
  2026-09-24 13:53 ` [PATCH 04/16] vmlinux.lds: Move DATA_LE32() from arm64 to the common linker script Jason Gunthorpe
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

Sashiko points out that efi_handle_cmdline() allocates this memory and
hands it over to the caller. If efi_pe_entry() ever returns it should be
freed. Add a __free annotation.

Fixes: 42c8ea3dca09 ("efi: libstub: Factor out EFI stub entrypoint into separate file")
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/firmware/efi/libstub/efi-stub-entry.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
index aa85e910fe595e..83fade2b0d3b84 100644
--- a/drivers/firmware/efi/libstub/efi-stub-entry.c
+++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
@@ -40,7 +40,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
 	unsigned long image_addr;
 	unsigned long image_size = 0;
 	/* addr/point and size pairs for memory management*/
-	char *cmdline_ptr = NULL;
+	char *cmdline_ptr __free(efi_pool) = NULL;
 	efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
 	unsigned long reserve_addr = 0;
 	unsigned long reserve_size = 0;
-- 
2.43.0



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

* [PATCH 04/16] vmlinux.lds: Move DATA_LE32() from arm64 to the common linker script
  2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
                   ` (2 preceding siblings ...)
  2026-09-24 13:53 ` [PATCH 03/16] efi/libstub: Free cmdline_ptr in efi_pe_entry Jason Gunthorpe
@ 2026-09-24 13:53 ` Jason Gunthorpe
  2026-09-24 22:53   ` Jonathan Cameron
  2026-09-24 13:53 ` [PATCH 05/16] efi/libstub: Add a general way to get symbols from the vmlinux into zboot Jason Gunthorpe
                   ` (11 subsequent siblings)
  15 siblings, 1 reply; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

Other arches may want to use this to get consistent fixed endian output.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 arch/arm64/kernel/image.h         | 14 --------------
 include/asm-generic/vmlinux.lds.h | 15 +++++++++++++++
 2 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h
index 7bc3ba89790191..1bff6b061b6cab 100644
--- a/arch/arm64/kernel/image.h
+++ b/arch/arm64/kernel/image.h
@@ -14,26 +14,12 @@
 #include <asm/image.h>
 
 /*
- * There aren't any ELF relocations we can use to endian-swap values known only
- * at link time (e.g. the subtraction of two symbol addresses), so we must get
- * the linker to endian-swap certain values before emitting them.
- *
  * Note that, in order for this to work when building the ELF64 PIE executable
  * (for KASLR), these values should not be referenced via R_AARCH64_ABS64
  * relocations, since these are fixed up at runtime rather than at build time
  * when PIE is in effect. So we need to split them up in 32-bit high and low
  * words.
  */
-#ifdef CONFIG_CPU_BIG_ENDIAN
-#define DATA_LE32(data)				\
-	((((data) & 0x000000ff) << 24) |	\
-	 (((data) & 0x0000ff00) << 8)  |	\
-	 (((data) & 0x00ff0000) >> 8)  |	\
-	 (((data) & 0xff000000) >> 24))
-#else
-#define DATA_LE32(data) ((data) & 0xffffffff)
-#endif
-
 #define DEFINE_IMAGE_LE64(sym, data)				\
 	sym##_lo32 = DATA_LE32((data) & 0xffffffff);		\
 	sym##_hi32 = DATA_LE32((data) >> 32)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index b2988aa12f6645..1786a8e4323b9f 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -56,6 +56,21 @@
 #define LOAD_OFFSET 0
 #endif
 
+/*
+ * There aren't any ELF relocations we can use to endian-swap values known only
+ * at link time (e.g. the subtraction of two symbol addresses), so we must get
+ * the linker to endian-swap certain values before emitting them.
+ */
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define DATA_LE32(data)				\
+	((((data) & 0x000000ff) << 24) |	\
+	 (((data) & 0x0000ff00) << 8)  |	\
+	 (((data) & 0x00ff0000) >> 8)  |	\
+	 (((data) & 0xff000000) >> 24))
+#else
+#define DATA_LE32(data) ((data) & 0xffffffff)
+#endif
+
 /*
  * Only some architectures want to have the .notes segment visible in
  * a separate PT_NOTE ELF Program Header. When this happens, it needs
-- 
2.43.0



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

* [PATCH 05/16] efi/libstub: Add a general way to get symbols from the vmlinux into zboot
  2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
                   ` (3 preceding siblings ...)
  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 13:53 ` Jason Gunthorpe
  2026-09-24 13:53 ` [PATCH 06/16] arm64/efi: Use CONFIG_EFI_STUB_IMAGE_INFO for code_size Jason Gunthorpe
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

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



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

* [PATCH 06/16] arm64/efi: Use CONFIG_EFI_STUB_IMAGE_INFO for code_size
  2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
                   ` (4 preceding siblings ...)
  2026-09-24 13:53 ` [PATCH 05/16] efi/libstub: Add a general way to get symbols from the vmlinux into zboot Jason Gunthorpe
@ 2026-09-24 13:53 ` Jason Gunthorpe
  2026-09-24 13:53 ` [PATCH 07/16] efi/zboot: Lift efi_cache_sync_image() from efi_zboot_decompress() Jason Gunthorpe
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

Pass code_size to zboot through struct efi_image_info instead of the
custom objcopy trick and remove the objcopy way.

The linker still computes code_size, it just gets placed into the struct.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 arch/arm64/Kconfig                          |  1 +
 arch/arm64/boot/Makefile                    |  3 ---
 arch/arm64/include/asm/image.h              | 11 +++++++++++
 arch/arm64/kernel/image-vars.h              |  8 +++-----
 arch/arm64/kernel/vmlinux.lds.S             |  4 ++++
 drivers/firmware/efi/libstub/Makefile.zboot |  2 +-
 drivers/firmware/efi/libstub/arm64-stub.c   |  5 ++++-
 drivers/firmware/efi/libstub/arm64.c        |  4 ++--
 drivers/firmware/efi/libstub/zboot.lds      |  3 ---
 9 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b5a51b0ef9440a..4a752835ce1116 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2532,6 +2532,7 @@ config EFI
 	select EFI_PARAMS_FROM_FDT
 	select EFI_RUNTIME_WRAPPERS
 	select EFI_STUB
+	select EFI_STUB_IMAGE_INFO
 	select EFI_GENERIC_STUB
 	imply IMA_SECURE_AND_OR_TRUSTED_BOOT
 	default y
diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile
index b5a08333bc57b5..cfbad0c210fa04 100644
--- a/arch/arm64/boot/Makefile
+++ b/arch/arm64/boot/Makefile
@@ -51,7 +51,4 @@ EFI_ZBOOT_BFD_TARGET	:= elf64-littleaarch64
 EFI_ZBOOT_MACH_TYPE	:= ARM64
 EFI_ZBOOT_FORWARD_CFI	:= $(CONFIG_ARM64_BTI_KERNEL)
 
-EFI_ZBOOT_OBJCOPY_FLAGS	= --add-symbol zboot_code_size=0x$$( \
-				$(NM) vmlinux|grep _kernel_codesize|cut -d' ' -f1)
-
 include $(srctree)/drivers/firmware/efi/libstub/Makefile.zboot
diff --git a/arch/arm64/include/asm/image.h b/arch/arm64/include/asm/image.h
index 9ba85173f85765..4a220c71f76c6a 100644
--- a/arch/arm64/include/asm/image.h
+++ b/arch/arm64/include/asm/image.h
@@ -5,6 +5,8 @@
 
 #define ARM64_IMAGE_MAGIC	"ARM\x64"
 
+#define EFI_IMAGE_INFO_SIZE	8
+
 #define ARM64_IMAGE_FLAG_BE_SHIFT		0
 #define ARM64_IMAGE_FLAG_PAGE_SIZE_SHIFT	(ARM64_IMAGE_FLAG_BE_SHIFT + 1)
 #define ARM64_IMAGE_FLAG_PHYS_BASE_SHIFT \
@@ -54,6 +56,15 @@ struct arm64_image_header {
 	__le32 res5;
 };
 
+/*
+ * This struct is filled in by the linker, see EFI_IMAGE_INFO.
+ * Any change requires updating arch/arm64/kernel/vmlinux.lds.S
+ */
+struct efi_image_info {
+	__le64 code_size;
+};
+static_assert(sizeof(struct efi_image_info) == EFI_IMAGE_INFO_SIZE);
+
 #endif /* __ASSEMBLER__ */
 
 #endif /* __ASM_IMAGE_H */
diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h
index 14beb7b9d304c1..13c0b77627d82e 100644
--- a/arch/arm64/kernel/image-vars.h
+++ b/arch/arm64/kernel/image-vars.h
@@ -35,8 +35,10 @@ PROVIDE(__efistub_caches_clean_inval_pou = __pi_caches_clean_inval_pou);
 
 PROVIDE(__efistub__text			= _text);
 PROVIDE(__efistub__end			= _end);
-PROVIDE(__efistub___inittext_end       	= __inittext_end);
 PROVIDE(__efistub__edata		= _edata);
+#ifdef CONFIG_EFI_STUB_IMAGE_INFO
+PROVIDE(__efistub_efi_image_info_offset = __efi_image_info_offset);
+#endif
 #if defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_SYSFB)
 PROVIDE(__efistub_sysfb_primary_display	= sysfb_primary_display);
 #endif
@@ -150,10 +152,6 @@ KVM_NVHE_ALIAS(kvm_protected_mode_initialized);
 
 #endif /* CONFIG_KVM */
 
-#ifdef CONFIG_EFI_ZBOOT
-_kernel_codesize = ABSOLUTE(__inittext_end - _text);
-#endif
-
 /*
  * LLD will occasionally error out with a '__init_end does not converge' error
  * if INIT_IDMAP_DIR_SIZE is defined in terms of _end, as this results in a
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index af1d720209764f..8305b47995954b 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -282,6 +282,10 @@ SECTIONS
 		CON_INITCALL
 		INIT_RAM_FS
 		*(.init.altinstructions .init.bss)	/* from the EFI stub */
+		EFI_IMAGE_INFO(
+			/* code_size */
+			EFI_IMAGE_INFO_OFFSET(__inittext_end);
+		)
 	}
 	.exit.data : {
 		EXIT_DATA
diff --git a/drivers/firmware/efi/libstub/Makefile.zboot b/drivers/firmware/efi/libstub/Makefile.zboot
index 6eebac66b73b18..de89d3d84465b5 100644
--- a/drivers/firmware/efi/libstub/Makefile.zboot
+++ b/drivers/firmware/efi/libstub/Makefile.zboot
@@ -35,7 +35,7 @@ efi-zboot-objcopy-flags-$(CONFIG_EFI_STUB_IMAGE_INFO) = \
 		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) \
+OBJCOPYFLAGS_vmlinuz.o = -I binary -O $(EFI_ZBOOT_BFD_TARGET) \
 			  $(efi-zboot-objcopy-flags-y) \
 			  --rename-section .data=.gzdata,load,alloc,readonly,contents
 $(obj)/vmlinuz.o: $(obj)/vmlinuz FORCE
diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index 2c38693561475c..1d3fc8ac13efa7 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -9,6 +9,7 @@
 
 #include <linux/efi.h>
 #include <asm/efi.h>
+#include <asm/image.h>
 #include <asm/memory.h>
 #include <asm/sections.h>
 
@@ -21,6 +22,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 				 efi_loaded_image_t *image,
 				 efi_handle_t image_handle)
 {
+	const struct efi_image_info *info;
 	unsigned long kernel_size, kernel_codesize, kernel_memsize;
 
 	if (image->image_base != _text) {
@@ -33,7 +35,8 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 			SEGMENT_ALIGN >> 10);
 
 	kernel_size = _edata - _text;
-	kernel_codesize = __inittext_end - _text;
+	info = efi_get_image_info((unsigned long)_text);
+	kernel_codesize = le64_to_cpu(info->code_size);
 	kernel_memsize = kernel_size + (_end - _edata);
 	*reserve_size = kernel_memsize;
 	*image_addr = (unsigned long)_text;
diff --git a/drivers/firmware/efi/libstub/arm64.c b/drivers/firmware/efi/libstub/arm64.c
index e57cd3de0a00f4..67d66fdea77122 100644
--- a/drivers/firmware/efi/libstub/arm64.c
+++ b/drivers/firmware/efi/libstub/arm64.c
@@ -88,11 +88,11 @@ efi_status_t check_platform_features(void)
 #define DCTYPE	"cvau"
 #endif
 
-u32 __weak code_size;
-
 void efi_cache_sync_image(unsigned long image_base,
 			  unsigned long alloc_size)
 {
+	const struct efi_image_info *info = efi_get_image_info(image_base);
+	unsigned long code_size = le64_to_cpu(info->code_size);
 	u32 ctr = read_cpuid_effective_cachetype();
 	u64 lsize = 4 << cpuid_feature_extract_unsigned_field(ctr,
 						CTR_EL0_DminLine_SHIFT);
diff --git a/drivers/firmware/efi/libstub/zboot.lds b/drivers/firmware/efi/libstub/zboot.lds
index cc55aa8fb0630f..c7c2f4dd144301 100644
--- a/drivers/firmware/efi/libstub/zboot.lds
+++ b/drivers/firmware/efi/libstub/zboot.lds
@@ -2,7 +2,6 @@
 
 ENTRY(__efistub_efi_zboot_header);
 
-PROVIDE(zboot_code_size = ABSOLUTE(0));
 PROVIDE(efi_zboot_image_info_offset = ABSOLUTE(0));
 
 SECTIONS
@@ -23,8 +22,6 @@ SECTIONS
 		*(.rodata* .init.rodata* .srodata*)
 
 		. = ALIGN(4);
-		__efistub_code_size = .;
-		LONG(zboot_code_size);
 		__efistub_efi_image_info_offset = .;
 		LONG(efi_zboot_image_info_offset);
 
-- 
2.43.0



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

* [PATCH 07/16] efi/zboot: Lift efi_cache_sync_image() from efi_zboot_decompress()
  2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
                   ` (5 preceding siblings ...)
  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 ` Jason Gunthorpe
  2026-09-24 22:57   ` Jonathan Cameron
  2026-09-24 13:53 ` [PATCH 08/16] efi/libstub: Add generic arch callbacks for DRTM Jason Gunthorpe
                   ` (8 subsequent siblings)
  15 siblings, 1 reply; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

The two decompressors duplicate this call and the next patch needs to
change the argument. Hoist it up to remove the duplication.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/firmware/efi/libstub/zboot-decompress-gzip.c | 2 --
 drivers/firmware/efi/libstub/zboot-decompress-zstd.c | 2 --
 drivers/firmware/efi/libstub/zboot.c                 | 9 ++++++---
 3 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/firmware/efi/libstub/zboot-decompress-gzip.c b/drivers/firmware/efi/libstub/zboot-decompress-gzip.c
index e97a7e9d3c980b..79cf8c48b03385 100644
--- a/drivers/firmware/efi/libstub/zboot-decompress-gzip.c
+++ b/drivers/firmware/efi/libstub/zboot-decompress-gzip.c
@@ -62,7 +62,5 @@ efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen)
 		return EFI_LOAD_ERROR;
 	}
 
-	efi_cache_sync_image((unsigned long)out, outlen);
-
 	return EFI_SUCCESS;
 }
diff --git a/drivers/firmware/efi/libstub/zboot-decompress-zstd.c b/drivers/firmware/efi/libstub/zboot-decompress-zstd.c
index bde9d94dd2e3ac..dd7f11238154e1 100644
--- a/drivers/firmware/efi/libstub/zboot-decompress-zstd.c
+++ b/drivers/firmware/efi/libstub/zboot-decompress-zstd.c
@@ -43,7 +43,5 @@ efi_status_t efi_zboot_decompress(u8 *out, unsigned long outlen)
 		return EFI_LOAD_ERROR;
 	}
 
-	efi_cache_sync_image((unsigned long)out, outlen);
-
 	return EFI_SUCCESS;
 }
diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
index 4b76f74c56dae0..960a542881d875 100644
--- a/drivers/firmware/efi/libstub/zboot.c
+++ b/drivers/firmware/efi/libstub/zboot.c
@@ -92,9 +92,12 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
 	}
 
 	// Decompress the payload into the newly allocated buffer
-	status = efi_zboot_decompress((void *)image_base, alloc_size) ?:
-	         efi_stub_common(handle, image, image_base, cmdline_ptr);
-
+	status = efi_zboot_decompress((void *)image_base, alloc_size);
+	if (status == EFI_SUCCESS) {
+		efi_cache_sync_image(image_base, alloc_size);
+		status =
+			efi_stub_common(handle, image, image_base, cmdline_ptr);
+	}
 	efi_free(alloc_size, image_base);
 	return status;
 }
-- 
2.43.0



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

* [PATCH 08/16] efi/libstub: Add generic arch callbacks for DRTM
  2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
                   ` (6 preceding siblings ...)
  2026-09-24 13:53 ` [PATCH 07/16] efi/zboot: Lift efi_cache_sync_image() from efi_zboot_decompress() Jason Gunthorpe
@ 2026-09-24 13:53 ` Jason Gunthorpe
  2026-09-24 13:53 ` [PATCH 09/16] efi/libstub: Have efi_kaslr_relocate_kernel() handle extra_size Jason Gunthorpe
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

If the architecture supports an EFI stub launched version of DRTM, it
can select the kconfig and provide the hooks under its architecture
build.

Have the common code parse a drtm=enforce|auto|off kernel command line
parameter to set the boot behavior. Support commas in the args list since
there will be more options here down the road.

efi_drtm_prepare() is called before doing any decompression or image
relocation. It should figure out if DRTM is supported, policy-permitted,
and how much memory efi_drtm_get_extra_size() should return.

The image handling is revised to allocate extra_size at the end of
the normal image. The architecture can use this to store any
information needed for the DRTM flow. It is always contiguous with
Image, which is a requirement of ARM's specification.

efi_drtm_prepare_launch() is called while still in EFI boot services after
Image is fully prepared in its final location.

efi_drtm_launch() is called after exiting boot services and must
jump into the kernel through the DRTM flow. If it returns, then the
normal launch is tried (auto mode).

The extra_size is allocated directly after the Image. Handle the
trivial zboot flow now, and vmlinux in the following patch.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 .../admin-guide/kernel-parameters.txt         | 12 +++++++
 drivers/firmware/efi/Kconfig                  | 30 ++++++++++++++++
 drivers/firmware/efi/libstub/efi-stub-entry.c |  4 +++
 .../firmware/efi/libstub/efi-stub-helper.c    | 34 ++++++++++++++++++
 drivers/firmware/efi/libstub/efistub.h        | 36 +++++++++++++++++++
 drivers/firmware/efi/libstub/fdt.c            |  8 ++++-
 drivers/firmware/efi/libstub/zboot.c          | 19 +++++++---
 7 files changed, 137 insertions(+), 6 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 68647ff4bdd24b..a576e06bd43584 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1373,6 +1373,18 @@ Kernel parameters
 			data set with no connector name will be used for
 			any connectors not explicitly specified.
 
+	drtm=		[EFI,EARLY]
+			Format: { "off" | "auto" | "enforce" }
+			Control the EFI stub Dynamic Root of Trust for
+			Measurement (DRTM) launch policy.
+			off: do not attempt a DRTM launch.
+			auto: attempt a DRTM launch when supported, but fall
+			back to a normal boot if preparation or launch fails.
+			enforce: require a DRTM launch and refuse to fall back
+			to a normal boot if preparation or launch fails.
+			The default is selected by the EFI_STUB_DRTM_DEFAULT_*
+			configuration options.
+
 	dscc4.setup=	[NET]
 
 	dt_cpu_ftrs=	[PPC,EARLY]
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 3d6fb3ca2806ca..f77fa1ae716843 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -75,6 +75,36 @@ config EFI_GENERIC_STUB
 config EFI_STUB_IMAGE_INFO
 	bool
 
+config EFI_STUB_DRTM
+	bool
+
+choice
+	prompt "Default DRTM launch policy"
+	depends on EFI_STUB_DRTM
+	default EFI_STUB_DRTM_DEFAULT_OFF
+	help
+	  Select the DRTM policy used when no drtm= option is present on the
+	  kernel command line. The command-line option overrides this default.
+
+config EFI_STUB_DRTM_DEFAULT_OFF
+	bool "Off"
+	help
+	  Do not attempt a DRTM launch unless it is requested explicitly.
+
+config EFI_STUB_DRTM_DEFAULT_AUTO
+	bool "Automatic with fallback"
+	help
+	  Attempt a DRTM launch when the firmware supports it, but fall back to
+	  normal boot if preparation or a returnable launch attempt fails.
+
+config EFI_STUB_DRTM_DEFAULT_ENFORCE
+	bool "Enforce"
+	help
+	  Require a DRTM launch and refuse normal-boot fallback if preparation
+	  or a returnable launch attempt fails.
+
+endchoice
+
 config EFI_ZBOOT
 	bool "Enable the generic EFI decompressor"
 	depends on EFI_GENERIC_STUB && !ARM
diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
index 83fade2b0d3b84..5b356c4be78975 100644
--- a/drivers/firmware/efi/libstub/efi-stub-entry.c
+++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
@@ -67,6 +67,10 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
 	if (status != EFI_SUCCESS)
 		return status;
 
+	status = efi_drtm_prepare();
+	if (status != EFI_SUCCESS)
+		return status;
+
 	efi_info("Booting Linux Kernel...\n");
 
 	status = handle_kernel_image(&image_addr, &image_size,
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index f27f2e1f001997..2dd4a5ac916000 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -27,6 +27,37 @@ static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA);
 
 int efi_mem_encrypt;
 
+#ifdef CONFIG_EFI_STUB_DRTM
+enum efi_drtm_policy efi_drtm_policy =
+	IS_ENABLED(CONFIG_EFI_STUB_DRTM_DEFAULT_ENFORCE) ? EFI_DRTM_ENFORCE :
+	IS_ENABLED(CONFIG_EFI_STUB_DRTM_DEFAULT_AUTO) ? EFI_DRTM_AUTO :
+	EFI_DRTM_OFF;
+
+static void efi_drtm_parse_options(char *options)
+{
+	char *keyword;
+
+	while (options) {
+		keyword = options;
+		while (*options && *options != ',')
+			options++;
+		if (*options)
+			*options++ = '\0';
+		else
+			options = NULL;
+
+		if (!strcmp(keyword, "off"))
+			efi_drtm_policy = EFI_DRTM_OFF;
+		else if (!strcmp(keyword, "auto"))
+			efi_drtm_policy = EFI_DRTM_AUTO;
+		else if (!strcmp(keyword, "enforce"))
+			efi_drtm_policy = EFI_DRTM_ENFORCE;
+	}
+}
+#else
+static void efi_drtm_parse_options(char *options) {}
+#endif
+
 bool __pure __efi_soft_reserve_enabled(void)
 {
 	return !efi_nosoftreserve;
@@ -89,6 +120,9 @@ efi_status_t efi_parse_options(char const *cmdline)
 				efi_mem_encrypt = 1;
 			else if (parse_option_str(val, "off"))
 				efi_mem_encrypt = -1;
+		} else if (IS_ENABLED(CONFIG_EFI_STUB_DRTM) &&
+			   !strcmp(param, "drtm") && val) {
+			efi_drtm_parse_options(val);
 		} else if (!strcmp(param, "efi") && val) {
 			efi_nochunk = parse_option_str(val, "nochunk");
 			efi_novamap |= parse_option_str(val, "novamap");
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index da01d6005a62af..f3a6aefdc052ca 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -1078,6 +1078,42 @@ efi_status_t check_platform_features(void);
 
 void *get_efi_config_table(efi_guid_t guid);
 
+enum efi_drtm_policy {
+	EFI_DRTM_OFF,
+	EFI_DRTM_AUTO,
+	EFI_DRTM_ENFORCE,
+};
+
+#ifdef CONFIG_EFI_STUB_DRTM
+extern enum efi_drtm_policy efi_drtm_policy;
+efi_status_t efi_drtm_prepare(void);
+unsigned long efi_drtm_get_extra_size(void);
+efi_status_t efi_drtm_prepare_launch(unsigned long image_base,
+				     unsigned long fdt_addr);
+void efi_drtm_launch(void);
+#else
+enum {efi_drtm_policy = EFI_DRTM_OFF};
+static inline efi_status_t efi_drtm_prepare(void)
+{
+	return EFI_SUCCESS;
+}
+
+static inline unsigned long efi_drtm_get_extra_size(void)
+{
+	return 0;
+}
+
+static inline efi_status_t
+efi_drtm_prepare_launch(unsigned long image_base, unsigned long fdt_addr)
+{
+	return EFI_SUCCESS;
+}
+
+static inline void efi_drtm_launch(void)
+{
+}
+#endif
+
 /* NOTE: These functions do not print a trailing newline after the string */
 void efi_char16_puts(efi_char16_t *);
 void efi_puts(const char *str);
diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
index 5b2dd709d7b151..15bb331f2dc56c 100644
--- a/drivers/firmware/efi/libstub/fdt.c
+++ b/drivers/firmware/efi/libstub/fdt.c
@@ -223,6 +223,7 @@ static
 efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
 					    efi_loaded_image_t *image,
 					    unsigned long *new_fdt_addr,
+					    unsigned long kernel_addr,
 					    char *cmdline_ptr)
 {
 	unsigned long desc_size;
@@ -289,6 +290,10 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
 		goto fail_free_new_fdt;
 	}
 
+	status = efi_drtm_prepare_launch(kernel_addr, *new_fdt_addr);
+	if (status != EFI_SUCCESS)
+		goto fail_free_new_fdt;
+
 	priv.new_fdt_addr = (void *)*new_fdt_addr;
 
 	status = efi_exit_boot_services(handle, &priv, exit_boot_func);
@@ -350,7 +355,7 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image,
 	efi_status_t status;
 
 	status = allocate_new_fdt_and_exit_boot(handle, image, &fdt_addr,
-						cmdline_ptr);
+						kernel_addr, cmdline_ptr);
 	if (status != EFI_SUCCESS) {
 		efi_err("Failed to update FDT and exit boot services\n");
 		return status;
@@ -359,6 +364,7 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image,
 	if (IS_ENABLED(CONFIG_ARM))
 		efi_handle_post_ebs_state();
 
+	efi_drtm_launch();
 	efi_enter_kernel(kernel_addr, fdt_addr, fdt_totalsize((void *)fdt_addr));
 	/* not reached */
 }
diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
index 960a542881d875..6ca231ad593b20 100644
--- a/drivers/firmware/efi/libstub/zboot.c
+++ b/drivers/firmware/efi/libstub/zboot.c
@@ -35,7 +35,7 @@ asmlinkage efi_status_t __efiapi
 efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
 {
 	char *cmdline_ptr __free(efi_pool) = NULL;
-	unsigned long image_base, alloc_size;
+	unsigned long image_base, image_size, alloc_size;
 	efi_loaded_image_t *image;
 	efi_status_t status;
 
@@ -52,12 +52,17 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
 	if (status != EFI_SUCCESS)
 		return status;
 
-	efi_info("Decompressing Linux Kernel...\n");
-
-	status = efi_zboot_decompress_init(&alloc_size);
+	status = efi_drtm_prepare();
 	if (status != EFI_SUCCESS)
 		return status;
 
+	efi_info("Decompressing Linux Kernel...\n");
+
+	status = efi_zboot_decompress_init(&image_size);
+	if (status != EFI_SUCCESS)
+		return status;
+	alloc_size = image_size + efi_drtm_get_extra_size();
+
 	 // If the architecture has a preferred address for the image,
 	 // try that first.
 	image_base = alloc_preferred_address(alloc_size);
@@ -92,8 +97,12 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
 	}
 
 	// Decompress the payload into the newly allocated buffer
-	status = efi_zboot_decompress((void *)image_base, alloc_size);
+	status = efi_zboot_decompress((void *)image_base, image_size);
 	if (status == EFI_SUCCESS) {
+		/*
+		 * Have to sync the entire allocation because the sync also
+		 * remaps and changes the permissions.
+		 */
 		efi_cache_sync_image(image_base, alloc_size);
 		status =
 			efi_stub_common(handle, image, image_base, cmdline_ptr);
-- 
2.43.0



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

* [PATCH 09/16] efi/libstub: Have efi_kaslr_relocate_kernel() handle extra_size
  2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
                   ` (7 preceding siblings ...)
  2026-09-24 13:53 ` [PATCH 08/16] efi/libstub: Add generic arch callbacks for DRTM Jason Gunthorpe
@ 2026-09-24 13:53 ` Jason Gunthorpe
  2026-09-24 13:53 ` [PATCH 10/16] efi: Add a __efi_data_handoff section annotation Jason Gunthorpe
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

There are three possibilities here, each a little different:
- relocating for kaslr, just request extra_size like the zboot flow does
  when allocating from EFI
- in place, attempt to allocate from EFI precisely after Image to
  confirm nothing weird is there, failing that
- like any other error with the in place EFI location allocate
  non-randomly with extra_size included

Remove the callers' assignments of reserve_size since
efi_kaslr_relocate_kernel() now does it.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/firmware/efi/libstub/arm64-stub.c |  1 -
 drivers/firmware/efi/libstub/kaslr.c      | 72 +++++++++++++++++++----
 drivers/firmware/efi/libstub/riscv-stub.c |  1 -
 3 files changed, 62 insertions(+), 12 deletions(-)

diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index 1d3fc8ac13efa7..1aa169464e529e 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -38,7 +38,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 	info = efi_get_image_info((unsigned long)_text);
 	kernel_codesize = le64_to_cpu(info->code_size);
 	kernel_memsize = kernel_size + (_end - _edata);
-	*reserve_size = kernel_memsize;
 	*image_addr = (unsigned long)_text;
 
 	return efi_kaslr_relocate_kernel(image_addr, reserve_addr, reserve_size,
diff --git a/drivers/firmware/efi/libstub/kaslr.c b/drivers/firmware/efi/libstub/kaslr.c
index 4bc963e999eb97..e419f3800af517 100644
--- a/drivers/firmware/efi/libstub/kaslr.c
+++ b/drivers/firmware/efi/libstub/kaslr.c
@@ -83,11 +83,47 @@ static bool check_image_region(u64 base, u64 size)
 	return ret;
 }
 
+/*
+ * The PE loader owns only kernel_memsize of the image.  Try to own the
+ * requested tail separately at the exact adjacent address instead of
+ * relocating the complete region.
+ */
+static efi_status_t allocate_image_tail(unsigned long image_addr,
+					unsigned long kernel_memsize,
+					unsigned long extra_size,
+					unsigned long *reserve_addr,
+					unsigned long *reserve_size)
+{
+	efi_physical_addr_t tail_addr;
+	efi_status_t status;
+
+	/*
+	 * Since we intend to use efi_free() for reserve_addr it should be
+	 * aligned to the higher alignment since efi_free() includes rounding.
+	 * For ARM64 the kernel image is already aligned up to EFI_ALLOC_ALIGN
+	 * by the linker.
+	 */
+	tail_addr = image_addr + kernel_memsize;
+	if (!IS_ALIGNED(tail_addr, EFI_ALLOC_ALIGN))
+		return EFI_OUT_OF_RESOURCES;
+
+	extra_size = round_up(extra_size, EFI_ALLOC_ALIGN);
+	status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
+			     EFI_LOADER_CODE, extra_size / EFI_PAGE_SIZE,
+			     &tail_addr);
+	if (status != EFI_SUCCESS)
+		return status;
+
+	*reserve_addr = tail_addr;
+	*reserve_size = extra_size;
+	return EFI_SUCCESS;
+}
+
 /**
  * efi_kaslr_relocate_kernel() - Relocate the kernel (random if KASLR enabled)
  * @image_addr: Pointer to the current kernel location
- * @reserve_addr:	Pointer to the relocated kernel location
- * @reserve_size:	Size of the relocated kernel
+ * @reserve_addr:	Pointer to any allocated memory
+ * @reserve_size:	Size that was allocated
  * @kernel_size:	Size of the text + data
  * @kernel_codesize:	Size of the text
  * @kernel_memsize:	Size of the text + data + bss
@@ -109,6 +145,9 @@ efi_status_t efi_kaslr_relocate_kernel(unsigned long *image_addr,
 {
 	efi_status_t status;
 	u64 min_kimg_align = efi_get_kimg_min_align();
+	unsigned long extra_size = efi_drtm_get_extra_size();
+
+	*reserve_size = kernel_memsize + extra_size;
 
 	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) {
 		/*
@@ -125,16 +164,29 @@ efi_status_t efi_kaslr_relocate_kernel(unsigned long *image_addr,
 	}
 
 	if (status != EFI_SUCCESS) {
-		if (!check_image_region(*image_addr, kernel_memsize)) {
+		bool image_region_ok =
+			check_image_region(*image_addr, kernel_memsize);
+
+		if (!image_region_ok) {
 			efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n");
 		} else if (IS_ALIGNED(*image_addr, min_kimg_align) &&
-			   (unsigned long)_end < EFI_ALLOC_LIMIT) {
-			/*
-			 * Just execute from wherever we were loaded by the
-			 * UEFI PE/COFF loader if the placement is suitable.
-			 */
-			*reserve_size = 0;
-			return EFI_SUCCESS;
+			   (unsigned long)_end + extra_size < EFI_ALLOC_LIMIT) {
+			if (!extra_size) {
+				/*
+				 * Just execute from wherever we were loaded by
+				 * the UEFI PE/COFF loader if the placement is
+				 * suitable.
+				 */
+				*reserve_size = 0;
+				return EFI_SUCCESS;
+			}
+
+			status = allocate_image_tail(*image_addr,
+						     kernel_memsize, extra_size,
+						     reserve_addr,
+						     reserve_size);
+			if (status == EFI_SUCCESS)
+				return EFI_SUCCESS;
 		}
 
 		status = efi_allocate_pages_aligned(*reserve_size, reserve_addr,
diff --git a/drivers/firmware/efi/libstub/riscv-stub.c b/drivers/firmware/efi/libstub/riscv-stub.c
index 725b634c517919..a88b2d275e5bb0 100644
--- a/drivers/firmware/efi/libstub/riscv-stub.c
+++ b/drivers/firmware/efi/libstub/riscv-stub.c
@@ -37,7 +37,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 	kernel_codesize = __init_text_end - _start;
 	kernel_memsize = kernel_size + (_end - _edata);
 	*image_addr = (unsigned long)_start;
-	*reserve_size = kernel_memsize;
 
 	status = efi_kaslr_relocate_kernel(image_addr,
 					   reserve_addr, reserve_size,
-- 
2.43.0



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

* [PATCH 10/16] efi: Add a __efi_data_handoff section annotation
  2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
                   ` (8 preceding siblings ...)
  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 ` 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
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

For a clean DRTM measurement, data written by the stub in the image must
not fall within the measured range. __efi_data_handoff can be used to mark
this data so it is placed outside the measured .data or .init.data
section, and also ensure it is force allocated and not part of .bss.

For DRTM data marked this way will need eventual hardening when the kernel
consumes it. For example sysfb_primary_display eventually leads to a blind
ioremap. Later series will look at hardening these flows.

The arch-agnostic sysfb_primary_display is the first user. The embedded
stub writes it.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/firmware/efi/efi-init.c |  2 +-
 include/linux/efi.h             | 12 ++++++++++++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c
index 6103b1a082d247..b00c4c03ca810a 100644
--- a/drivers/firmware/efi/efi-init.c
+++ b/drivers/firmware/efi/efi-init.c
@@ -61,7 +61,7 @@ extern __weak const efi_config_table_type_t efi_arch_tables[];
  * it even without EFI, everything else can get them from here.
  */
 #if !defined(CONFIG_X86) && (defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_FIRMWARE_EDID))
-struct sysfb_display_info sysfb_primary_display __section(".data");
+struct sysfb_display_info sysfb_primary_display __efi_data_handoff;
 EXPORT_SYMBOL_GPL(sysfb_primary_display);
 #endif
 
diff --git a/include/linux/efi.h b/include/linux/efi.h
index aa15ff88539bdf..a77bb604b1d1fd 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -29,6 +29,18 @@
 
 struct screen_info;
 
+/*
+ * Data the stub wants to pass to the kernel must not land in .bss so it doesn't
+ * get zero'd during early boot, and when DRTM is enabled must not land in the
+ * measured sections. The offset of such data can be passed to both EFI stubs
+ * using a mechanism like struct efi_image_info.
+ */
+#ifdef CONFIG_EFI_STUB_DRTM
+#define __efi_data_handoff	__section(".unmeasured.data")
+#else
+#define __efi_data_handoff	__section(".data")
+#endif
+
 #define EFI_SUCCESS		0
 #define EFI_LOAD_ERROR		( 1 | (1UL << (BITS_PER_LONG-1)))
 #define EFI_INVALID_PARAMETER	( 2 | (1UL << (BITS_PER_LONG-1)))
-- 
2.43.0



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

* [PATCH 11/16] efi/libstub: Put the stub's writable data in unique sections for DRTM
  2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
                   ` (9 preceding siblings ...)
  2026-09-24 13:53 ` [PATCH 10/16] efi: Add a __efi_data_handoff section annotation Jason Gunthorpe
@ 2026-09-24 13:53 ` Jason Gunthorpe
  2026-09-24 13:53 ` [PATCH 12/16] arm64: drtm: Add macro definitions for DEN0113 Jason Gunthorpe
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

Currently the EFI stub's .bss and .data are both placed in .init.data,
which allows them to be discarded after boot, but places them within the
region of memory we need to measure as part of a DRTM launch.

If the EFI stub modifies the measured data before the measurement, then we
can no longer get a predictable measurement.

Give them unique section names; the arch's linker script has to put
these sections outside the measured range.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 drivers/firmware/efi/libstub/Makefile  | 10 ++++++++++
 drivers/firmware/efi/libstub/zboot.lds |  4 ++--
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 77a2b2d74f3f62..3f1921e6c334d1 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -142,6 +142,16 @@ STUBCOPY_FLAGS-$(CONFIG_ARM64)	+= --prefix-alloc-sections=.init \
 				   --prefix-symbols=__efistub_
 STUBCOPY_RELOC-$(CONFIG_ARM64)	:= R_AARCH64_ABS
 
+# Give writable stub state a dedicated section namespace.  objcopy applies
+# section renames before section prefixes, irrespective of their command line
+# ordering, so these become .init.efidata and .init.efibss.
+#
+# The names must stay outside the .init.data.* namespace.  INIT_DATA collects
+# *(.init.data .init.data.*) into a measured kernel output section that the
+# arm64 linker script emits first.
+STUBCOPY_FLAGS-$(CONFIG_EFI_STUB_DRTM) += --rename-section .data=.efidata \
+					   --rename-section .bss=.efibss,load,alloc
+
 # For RISC-V, we don't need anything special other than arm64. Keep all the
 # symbols in .init section and make sure that no absolute symbols references
 # exist.
diff --git a/drivers/firmware/efi/libstub/zboot.lds b/drivers/firmware/efi/libstub/zboot.lds
index c7c2f4dd144301..5320a05498758d 100644
--- a/drivers/firmware/efi/libstub/zboot.lds
+++ b/drivers/firmware/efi/libstub/zboot.lds
@@ -38,13 +38,13 @@ SECTIONS
 
 	.data : ALIGN(4096) {
 		_data = .;
-		*(.data* .init.data*)
+		*(.data* .init.data* .init.efidata*)
 		_edata = ALIGN(512);
 		. = _edata;
 	}
 
 	.bss : {
-		*(.bss* .init.bss*)
+		*(.bss* .init.bss* .init.efibss*)
 		_end = ALIGN(512);
 		. = _end;
 	}
-- 
2.43.0



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

* [PATCH 12/16] arm64: drtm: Add macro definitions for DEN0113
  2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
                   ` (10 preceding siblings ...)
  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 ` Jason Gunthorpe
  2026-09-25  0:29   ` Jonathan Cameron
  2026-09-24 13:53 ` [PATCH 13/16] arm64: drtm: Update the linker script for EFI_STUB_DRTM Jason Gunthorpe
                   ` (3 subsequent siblings)
  15 siblings, 1 reply; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

Taken from rev 1.4b of the spec, following the SMCC register layout and
constant names.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 arch/arm64/include/asm/drtm.h | 196 ++++++++++++++++++++++++++++++++++
 1 file changed, 196 insertions(+)
 create mode 100644 arch/arm64/include/asm/drtm.h

diff --git a/arch/arm64/include/asm/drtm.h b/arch/arm64/include/asm/drtm.h
new file mode 100644
index 00000000000000..d6dd04a4ebcea5
--- /dev/null
+++ b/arch/arm64/include/asm/drtm.h
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES
+ *
+ * Definitions from ARM DEN 0113 "DRTM Architecture for Arm"
+ */
+#ifndef __ASM_DRTM_H
+#define __ASM_DRTM_H
+
+#include <linux/arm-smccc.h>
+#include <linux/bits.h>
+
+/* Offset 0x02 is reserved by DEN0113. */
+#define ARM_DRTM_SMC_FN_BASE                                      \
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \
+			   ARM_SMCCC_OWNER_STANDARD, 0x110)
+#define ARM_DRTM_SMC_VERSION			(ARM_DRTM_SMC_FN_BASE + 0x00)
+#define ARM_DRTM_SMC_FEATURES			(ARM_DRTM_SMC_FN_BASE + 0x01)
+#define ARM_DRTM_SMC_UNPROTECT_MEMORY		(ARM_DRTM_SMC_FN_BASE + 0x03)
+#define ARM_DRTM_SMC_DYNAMIC_LAUNCH		(ARM_DRTM_SMC_FN_BASE + 0x04)
+#define ARM_DRTM_SMC_CLOSE_LOCALITY		(ARM_DRTM_SMC_FN_BASE + 0x05)
+#define ARM_DRTM_SMC_GET_ERROR			(ARM_DRTM_SMC_FN_BASE + 0x06)
+#define ARM_DRTM_SMC_SET_ERROR			(ARM_DRTM_SMC_FN_BASE + 0x07)
+#define ARM_DRTM_SMC_SET_TCB_HASH		(ARM_DRTM_SMC_FN_BASE + 0x08)
+#define ARM_DRTM_SMC_LOCK_TCB_HASHES		(ARM_DRTM_SMC_FN_BASE + 0x09)
+#define ARM_DRTM_SMC_ENABLE_SECURE_INTERRUPTS	(ARM_DRTM_SMC_FN_BASE + 0x0a)
+
+#define ARM_DRTM_FEATURE_SELECTOR	BIT_U64(63)
+#define ARM_DRTM_FEATURE_TPM		0x01
+#define ARM_DRTM_FEATURE_MIN_MEMORY	0x02
+#define ARM_DRTM_FEATURE_DMA_PROTECTION	0x03
+#define ARM_DRTM_FEATURE_BOOT_PE	0x04
+#define ARM_DRTM_FEATURE_TCB_HASH	0x05
+#define ARM_DRTM_FEATURE_IMAGE_AUTH	0x06
+
+#define ARM_DRTM_VERSION_MAJOR_MASK	GENMASK_U32(30, 16)
+#define ARM_DRTM_VERSION_MINOR_MASK	GENMASK_U32(15, 0)
+#define ARM_DRTM_VERSION_MAJOR		1
+#define ARM_DRTM_VERSION_MIN_MINOR	1
+
+#define ARM_DRTM_TPM_ALG_MASK		GENMASK_U64(15, 0)
+#define ARM_DRTM_TPM_HASHING		BIT_U64(32)
+#define ARM_DRTM_PCR_SCHEMA_MASK	GENMASK_U64(36, 33)
+#define ARM_DRTM_PCR_SCHEMA_DEFAULT	BIT_U64(33)
+#define ARM_DRTM_PCR_SCHEMA_AUTHORITIES	BIT_U64(34)
+
+#define ARM_DRTM_DLME_DATA_PAGES_MASK	GENMASK_U64(31, 0)
+#define ARM_DRTM_NW_DCE_PAGES_MASK	GENMASK_U64(63, 32)
+#define ARM_DRTM_PAGE_SIZE		4096
+
+#define ARM_DRTM_DMA_PROTECTION_MASK	GENMASK_U64(7, 0)
+#define ARM_DRTM_DMA_PROTECTION_COMPLETE BIT_U64(0)
+#define ARM_DRTM_DMA_PROTECTION_REGION	BIT_U64(1)
+#define ARM_DRTM_MAX_REGIONS_MASK	GENMASK_U64(23, 8)
+#define ARM_DRTM_TCB_HASH_COUNT_MASK	GENMASK_U64(7, 0)
+#define ARM_DRTM_IMAGE_AUTH_SUPPORTED	BIT_U64(0)
+
+#define ARM_DRTM_LAUNCH_HASH_FIRMWARE	0
+#define ARM_DRTM_LAUNCH_HASH_TPM	BIT_U32(0)
+#define ARM_DRTM_LAUNCH_PCR_DEFAULT	0
+#define ARM_DRTM_LAUNCH_PCR_AUTHORITIES	BIT_U32(1)
+#define ARM_DRTM_LAUNCH_DMA_COMPLETE	0
+#define ARM_DRTM_LAUNCH_DMA_REGION	BIT_U32(3)
+#define ARM_DRTM_LAUNCH_NO_AUTH		0
+#define ARM_DRTM_LAUNCH_AUTH		BIT_U32(6)
+#define ARM_DRTM_LAUNCH_KEEP_SECURE_IRQS 0
+#define ARM_DRTM_LAUNCH_DISABLE_SECURE_IRQS BIT_U32(7)
+
+#define ARM_DRTM_SUCCESS		0
+#define ARM_DRTM_NOT_SUPPORTED		-1
+#define ARM_DRTM_INVALID_PARAMETERS	-2
+#define ARM_DRTM_DENIED			-3
+#define ARM_DRTM_NOT_FOUND		-4
+#define ARM_DRTM_INTERNAL_ERROR		-5
+#define ARM_DRTM_MEM_PROTECT_INVALID	-6
+#define ARM_DRTM_OUT_OF_RESOURCES	-8
+#define ARM_DRTM_INVALID_DATA		-9
+#define ARM_DRTM_SECONDARY_PE_NOT_OFF	-10
+#define ARM_DRTM_ALREADY_CLOSED		-11
+#define ARM_DRTM_TPM_ERROR		-12
+
+/* Algorthim IDs are defined by TCG, in the kernel they are TPM_ALG_* */
+
+#define ARM_DRTM_PARAMETERS_REVISION	2
+
+#ifndef __ASSEMBLY__
+
+#include <linux/bitfield.h>
+#include <linux/build_bug.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+
+struct arm_drtm_parameters {
+	__le16 revision;
+	__le16 reserved;
+	__le32 launch_features;
+	__le64 dlme_region_address;
+	__le64 dlme_region_size;
+	__le64 dlme_image_start;
+	__le64 dlme_entry_point_offset;
+	__le64 dlme_image_size;
+	__le64 dlme_data_offset;
+	__le64 nw_dce_region_address;
+	__le64 nw_dce_region_size;
+	__le64 protection_table_address;
+	__le64 protection_table_size;
+};
+static_assert(sizeof(struct arm_drtm_parameters) == 88);
+
+static inline s32 arm_drtm_version(u16 *major, u16 *minor)
+{
+	struct arm_smccc_res res;
+	u32 version;
+
+	arm_smccc_1_1_smc(ARM_DRTM_SMC_VERSION, 0, 0, 0, 0, 0, 0, 0,
+			  &res);
+	version = res.a0;
+	/*
+	 * For this command only the output is specified as w0 a 32 bit value.
+	 * All others use x0 a 64 bit value. The -ve error and version are
+	 * overlayed together with the 32 bit sign bit telling them apart.
+	 */
+	if (version & BIT(31))
+		return version;
+
+	*major = FIELD_GET(ARM_DRTM_VERSION_MAJOR_MASK, version);
+	*minor = FIELD_GET(ARM_DRTM_VERSION_MINOR_MASK, version);
+	return ARM_DRTM_SUCCESS;
+}
+
+static inline s64 arm_drtm_features(u64 function_or_feature, u64 *value)
+{
+	struct arm_smccc_res res;
+	s64 status;
+
+	arm_smccc_1_1_smc(ARM_DRTM_SMC_FEATURES, function_or_feature,
+			  0, 0, 0, 0, 0, 0, &res);
+	status = res.a0;
+	if (status >= 0 && value)
+		*value = res.a1;
+	return status;
+}
+
+static inline s64 arm_drtm_unprotect_memory(void)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_smc(ARM_DRTM_SMC_UNPROTECT_MEMORY, 0, 0, 0, 0, 0, 0, 0,
+			  &res);
+	return res.a0;
+}
+
+static inline s64
+arm_drtm_dynamic_launch(struct arm_drtm_parameters *params_addr)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_smc(ARM_DRTM_SMC_DYNAMIC_LAUNCH,
+			  (unsigned long)params_addr, 0, 0, 0, 0, 0, 0, &res);
+	return res.a0;
+}
+
+static inline s64 arm_drtm_close_locality(u32 locality)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_smc(ARM_DRTM_SMC_CLOSE_LOCALITY, locality,
+			  0, 0, 0, 0, 0, 0, &res);
+	return res.a0;
+}
+
+static inline s64 arm_drtm_get_error(s64 *error_code)
+{
+	struct arm_smccc_res res;
+	s64 status;
+
+	arm_smccc_1_1_smc(ARM_DRTM_SMC_GET_ERROR, 0, 0, 0, 0, 0, 0, 0,
+			  &res);
+	status = res.a0;
+	if (status != ARM_DRTM_SUCCESS)
+		return status;
+
+	*error_code = res.a1;
+	return ARM_DRTM_SUCCESS;
+}
+
+static inline s64 arm_drtm_enable_secure_interrupts(void)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_smc(ARM_DRTM_SMC_ENABLE_SECURE_INTERRUPTS,
+			  0, 0, 0, 0, 0, 0, 0, &res);
+	return res.a0;
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_DRTM_H */
-- 
2.43.0



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

* [PATCH 13/16] arm64: drtm: Update the linker script for EFI_STUB_DRTM
  2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
                   ` (11 preceding siblings ...)
  2026-09-24 13:53 ` [PATCH 12/16] arm64: drtm: Add macro definitions for DEN0113 Jason Gunthorpe
@ 2026-09-24 13:53 ` Jason Gunthorpe
  2026-09-24 13:53 ` [PATCH 14/16] arm64: drtm: Add drtm_entry point to head.S Jason Gunthorpe
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

Implement the link layout that CONFIG_EFI_STUB_DRTM requires. This maps
vmlinux into the Dynamic Launch Measured Environment (DLME) defined by the
spec.

Broadly, Image fits into the spec defined DLME region memory layout in
this order:
 - Program headers and padding up to _stext. EFI can write to these while
   loading the stub so they do not have a stable measurement.
 - All the boot-time immutable data, including .text, .data, .init
   and so on (measured)
 - Data written by the EFI stub
 - .bss, padding and other 0'd data up to _end
 - The "DLME Data" written by the launch process. This is a datastructure
   the post launch kernel will parse to get trusted information about th
   launch.

New linker symbols are added to mark these areas and their offsets are
placed into the efi_image_info so both stubs can get them.

The spec's design of the DLME was intended to fit a typical OS image like
this, with two areas that are unmeasured and an inner measured region.

Linux zeroes the unmeasured area of .bss/etc after the DRTM launch so it
also reaches a known value. The DLME data is written by the launch and is
trusted. The EFI stub data is either ignored or will have to be sanitized.

Add a section for the unmeasured data before the PECOFF padding. This is
an allocated section so it is zero'd in the image and is only 64 bytes in
my builds. There is a high chance it gets absorbed into the padding
region.

The post-launch kernel will have to reserve the "DLME Data" before
starting the allocator since it falls outside the linker map. This will
happen in the first series to consume this data.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 arch/arm64/include/asm/image.h  |  8 +++++
 arch/arm64/kernel/vmlinux.lds.S | 64 ++++++++++++++++++++++++++++++++-
 2 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/image.h b/arch/arm64/include/asm/image.h
index 4a220c71f76c6a..a4af9a94037bfb 100644
--- a/arch/arm64/include/asm/image.h
+++ b/arch/arm64/include/asm/image.h
@@ -5,7 +5,11 @@
 
 #define ARM64_IMAGE_MAGIC	"ARM\x64"
 
+#ifdef CONFIG_ARM64_DRTM
+#define EFI_IMAGE_INFO_SIZE	40
+#else
 #define EFI_IMAGE_INFO_SIZE	8
+#endif
 
 #define ARM64_IMAGE_FLAG_BE_SHIFT		0
 #define ARM64_IMAGE_FLAG_PAGE_SIZE_SHIFT	(ARM64_IMAGE_FLAG_BE_SHIFT + 1)
@@ -62,6 +66,10 @@ struct arm64_image_header {
  */
 struct efi_image_info {
 	__le64 code_size;
+#ifdef CONFIG_ARM64_DRTM
+	__le64 drtm_measured_start;
+	__le64 dlme_measured_size;
+#endif
 };
 static_assert(sizeof(struct efi_image_info) == EFI_IMAGE_INFO_SIZE);
 
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 8305b47995954b..18d9717fb26741 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -190,10 +190,24 @@ SECTIONS
 
 	.head.text : {
 		_text = .;
+#ifdef CONFIG_ARM64_DRTM
+		/* DEN0113 R314010: The DLME region must start at a 4KB aligned address. */
+		ASSERT((_text & (SZ_4K - 1)) == 0,
+		       "DLME region is not 4 KiB aligned")
+#endif
 		HEAD_TEXT
 	}
 	.text : ALIGN(SEGMENT_ALIGN) {	/* Real text segment		*/
 		_stext = .;		/* Text and read-only data	*/
+#ifdef CONFIG_ARM64_DRTM
+		__drtm_measured_start = _stext;
+		/*
+		 * DEN0113 R314020: The DLME image must start at a 4KB aligned
+		 * address. This happens always because SEGMENT_ALIGN is big.
+		 */
+		ASSERT((__drtm_measured_start & (SZ_4K - 1)) == 0,
+		       "DLME measured start is not 4 KiB aligned")
+#endif
 			IRQENTRY_TEXT
 			SOFTIRQENTRY_TEXT
 			ENTRY_TEXT
@@ -285,6 +299,11 @@ SECTIONS
 		EFI_IMAGE_INFO(
 			/* code_size */
 			EFI_IMAGE_INFO_OFFSET(__inittext_end);
+#ifdef CONFIG_ARM64_DRTM
+			EFI_IMAGE_INFO_OFFSET(__drtm_measured_start);
+			/* dlme_measured_size */
+			EFI_IMAGE_INFO_ENTRY(__drtm_measured_end - __drtm_measured_start);
+#endif
 		)
 	}
 	.exit.data : {
@@ -348,6 +367,44 @@ SECTIONS
 		__mmuoff_data_end = .;
 	}
 
+	/*
+	 * DRTM layout for DEN0113 as it relates to the link layout, refer
+	 * to Figure 8 in 1.4b. In that language:
+	 *  "Free Space 1" is the PE header and padding between _text and
+	 *        __drtm_measured_start (_stext)
+	 *  "DLME Image" is from __drtm_measured_start to __drtm_measured_end
+	 *  "Free Space 2" is kernel efi data/bss/etc till __drtm_dlme_start
+	 *  "DLME Data" is a memory sized "Minimum Size of DLME data"
+	 *        and is retained after boot for use by the kernel
+	 *
+	 * Thus, the DRTM_PARAMETERS follow from that:
+	 *   DLME Region Address = _text's PA ie the start of Image
+	 *   DLME Region Size = DLME Data Offset + "Minimum Size of DLME data"
+	 *   DLME Image Start Offset = __drtm_measured_start - _text
+	 *   DLME Image Size = __drtm_measured_end - __drtm_measured_start
+	 *   DLME Data Offset = __drtm_dlme_start - _text
+	 *   Normal World DCE region address = PA of __drtm_dlme_start +
+	 *                                  "Minimum Size of DLME data"
+	 *
+	 * The EFI stub will place any optional "Normal World DCE" region
+	 * immediately after the "DLME data". It is only used internally by the
+	 * FW during the launch and has no effect on the link layout.
+	 */
+#ifdef CONFIG_ARM64_DRTM
+	__drtm_measured_end = .;
+
+	/*
+	 * Writable EFI stub state. When DRTM is being used the stub's mutable
+	 * data cannot reside in the normal .init.data because that section
+	 * will be measured.
+	 */
+	.unmeasured.data : {
+		*(.unmeasured.data)
+		*(.init.efidata .init.efidata.*)
+		*(.init.efibss .init.efibss.*)
+	}
+#endif
+
 	PECOFF_EDATA_PADDING
 	__pecoff_data_rawsize = ABSOLUTE(. - __initdata_begin);
 	_edata = .;
@@ -370,10 +427,15 @@ SECTIONS
 
 	. += SZ_4K;		/* stack for the early C runtime */
 	early_init_stack = .;
-
 	. = ALIGN(SEGMENT_ALIGN);
 	__pecoff_data_size = ABSOLUTE(. - __initdata_begin);
 	_end = .;
+#ifdef CONFIG_ARM64_DRTM
+	/* DEN0113 R314030: The DLME data must start at a 4KB aligned address. */
+	__drtm_dlme_start = .;
+	ASSERT((__drtm_dlme_start & (SZ_4K - 1)) == 0,
+	       "DLME data is not 4 KiB aligned")
+#endif
 	__pi__end = .;
 
 	STABS_DEBUG
-- 
2.43.0



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

* [PATCH 14/16] arm64: drtm: Add drtm_entry point to head.S
  2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
                   ` (12 preceding siblings ...)
  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 ` 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
  15 siblings, 0 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

The DRTM launch defined by DEN0113 cannot use primary_entry because the
spec defines a different launch protocol. drtm_entry is a small trampoline
that validates the DRTM provided data matches the location expected from
the link layout, acquires the DTB through an EFI stub writable handoff
struct and then jumps to primary_entry.

Add arch/arm64/kernel/drtm.c, as later patches and series will need more
kernel side functions.

Passing the fdt address like this will require security hardening in
future series.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 arch/arm64/include/asm/drtm.h   | 19 ++++++++
 arch/arm64/include/asm/image.h  |  2 +
 arch/arm64/kernel/Makefile      |  1 +
 arch/arm64/kernel/drtm.c        | 10 ++++
 arch/arm64/kernel/head.S        | 83 +++++++++++++++++++++++++++++++++
 arch/arm64/kernel/vmlinux.lds.S |  8 ++++
 6 files changed, 123 insertions(+)
 create mode 100644 arch/arm64/kernel/drtm.c

diff --git a/arch/arm64/include/asm/drtm.h b/arch/arm64/include/asm/drtm.h
index d6dd04a4ebcea5..6c9ded836cb03c 100644
--- a/arch/arm64/include/asm/drtm.h
+++ b/arch/arm64/include/asm/drtm.h
@@ -82,6 +82,9 @@
 
 #define ARM_DRTM_PARAMETERS_REVISION	2
 
+#define ARM64_DRTM_HANDOFF_FDT_ADDR_OFFSET	0
+#define ARM64_DRTM_HANDOFF_ENABLED_OFFSET	8
+
 #ifndef __ASSEMBLY__
 
 #include <linux/bitfield.h>
@@ -192,5 +195,21 @@ static inline s64 arm_drtm_enable_secure_interrupts(void)
 	return res.a0;
 }
 
+/*
+ * Since we cannot pass a parameter through the launch to drtm_entry any
+ * additional data is written by the stub here.
+ */
+struct arm64_drtm_handoff {
+	__le64 fdt_addr;
+	u8 drtm_enabled;
+};
+
+static_assert(offsetof(struct arm64_drtm_handoff, fdt_addr) ==
+	      ARM64_DRTM_HANDOFF_FDT_ADDR_OFFSET);
+static_assert(offsetof(struct arm64_drtm_handoff, drtm_enabled) ==
+	      ARM64_DRTM_HANDOFF_ENABLED_OFFSET);
+
+extern struct arm64_drtm_handoff arm64_drtm_handoff;
+
 #endif /* !__ASSEMBLY__ */
 #endif /* __ASM_DRTM_H */
diff --git a/arch/arm64/include/asm/image.h b/arch/arm64/include/asm/image.h
index a4af9a94037bfb..bdf4b655f72b1d 100644
--- a/arch/arm64/include/asm/image.h
+++ b/arch/arm64/include/asm/image.h
@@ -69,6 +69,8 @@ struct efi_image_info {
 #ifdef CONFIG_ARM64_DRTM
 	__le64 drtm_measured_start;
 	__le64 dlme_measured_size;
+	__le64 drtm_entry;
+	__le64 arm64_drtm_handoff;
 #endif
 };
 static_assert(sizeof(struct efi_image_info) == EFI_IMAGE_INFO_SIZE);
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index d2690c3ec52885..bd9a4c5179173f 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_HAVE_STATIC_CALL)		+= static_call.o
 obj-$(CONFIG_CPU_PM)			+= sleep.o suspend.o
 obj-$(CONFIG_KGDB)			+= kgdb.o
 obj-$(CONFIG_EFI)			+= efi.o efi-rt-wrapper.o
+obj-$(CONFIG_ARM64_DRTM)		+= drtm.o
 obj-$(CONFIG_PCI)			+= pci.o
 obj-$(CONFIG_ARMV8_DEPRECATED)		+= armv8_deprecated.o
 obj-$(CONFIG_ACPI)			+= acpi.o
diff --git a/arch/arm64/kernel/drtm.c b/arch/arm64/kernel/drtm.c
new file mode 100644
index 00000000000000..14493948a27f0d
--- /dev/null
+++ b/arch/arm64/kernel/drtm.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES
+ *
+ * Support functions for ARM DEN 0113 "DRTM Architecture for Arm"
+ */
+#include <linux/efi.h>
+
+#include <asm/drtm.h>
+
+struct arm64_drtm_handoff arm64_drtm_handoff __efi_data_handoff;
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 87a822e5c4ca83..6ffe5b4537c7d9 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -21,6 +21,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/cache.h>
 #include <asm/cputype.h>
+#include <asm/drtm.h>
 #include <asm/el2_setup.h>
 #include <asm/elf.h>
 #include <asm/image.h>
@@ -35,6 +36,7 @@
 #include <asm/stacktrace/frame.h>
 #include <asm/thread_info.h>
 #include <asm/virt.h>
+#include <uapi/linux/psci.h>
 
 #include "efi-header.S"
 
@@ -131,6 +133,87 @@ SYM_CODE_START(primary_entry)
 SYM_CODE_END(primary_entry)
 
 	__INIT
+#ifdef CONFIG_ARM64_DRTM
+/*
+ * Entry point used by a DRTM launch. Verify that information provided by the
+ * EFI stub matches expectations. We rely on an untrusted-write/trusted-verify
+ * approach so this doesn't have to deal with writing to cache-off memory. Per
+ * DEN0113 R45380, the launch supplies:
+ *
+ *   x0 = physical base of the DLME region
+ *   x1 = offset of thee DLME Data, which is several tables written by
+ *        the launch to pass trusted information to the post launch kernel
+ *
+ * These values must match the link layout in vmlinux.lds.S or the launch is
+ * invalid. The EFI stub will get them from the efi_image_info and pass them
+ * into arm_drtm_parameters.
+ *
+ * DEN0113 R45450-R45470 specify the remaining entry state as the PSCI CPU_ON
+ * initial state: AArch64 at the highest Non-secure EL, little-endian, with the
+ * MMU and D-cache disabled and Non-secure asynchronous/debug exceptions
+ * masked.
+ *
+ * Per DEN0113 R45220 the launch cleans and invalidates the whole "DLME region"
+ * which is everything from _text till past __drtm_dlme_start before
+ * it measures the image. Thus the handoff data written into the region by the
+ * EFI stub is safely readable here with the MMU off.
+ */
+SYM_CODE_START(drtm_entry)
+	/* Verify that x0 is the runtime physical address of _text */
+	adr_l	x2, _text
+	cmp	x0, x2
+	b.ne	.Ldrtm_bad_entry
+
+	/* x0 + x1 must be the runtime physical start of the DLME data */
+	add	x3, x0, x1
+	adr_l	x4, __drtm_dlme_start
+	cmp	x3, x4
+	b.ne	.Ldrtm_bad_entry
+
+	/* Stub must set drtm_enabled */
+	adr_l	x4, arm64_drtm_handoff
+	ldrb	w2, [x4, #ARM64_DRTM_HANDOFF_ENABLED_OFFSET]
+	cbz	x2, .Ldrtm_bad_entry
+
+	/* primary_entry(handoff->fdt_addr, 0, 0, 0) */
+	ldr	x0, [x4, #ARM64_DRTM_HANDOFF_FDT_ADDR_OFFSET]
+	mov	x1, xzr
+	mov	x2, xzr
+	mov	x3, xzr
+	b	primary_entry
+
+	/*
+	 * Can't continue, launch is corrupted, spec says the DLME can call
+	 * SET_ERROR which should forward the error to the next boot for
+	 * display.
+	 */
+.Ldrtm_bad_entry:
+	ldr	w0, =ARM_DRTM_SMC_SET_ERROR
+	/* Error ID = Vendor-specific Error, DRTM Phase = DLME */
+	mov	x1, #((0xff << 3) | 5)
+	mov	x2, xzr
+	mov	x3, xzr
+	mov	x4, xzr
+	mov	x5, xzr
+	mov	x6, xzr
+	mov	x7, xzr
+	smc	#0
+	/* Cold-reset the machine as required after reporting a DLME error */
+	ldr	w0, =PSCI_0_2_FN_SYSTEM_RESET
+	mov	x1, xzr
+	mov	x2, xzr
+	mov	x3, xzr
+	mov	x4, xzr
+	mov	x5, xzr
+	mov	x6, xzr
+	mov	x7, xzr
+	smc	#0
+	/* FW is really broken, just hang. */
+1:	wfe
+	b	1b
+SYM_CODE_END(drtm_entry)
+#endif
+
 SYM_CODE_START_LOCAL(record_mmu_state)
 	mrs	x19, CurrentEL
 	cmp	x19, #CurrentEL_EL2
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 18d9717fb26741..dc8ab58c933009 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -303,6 +303,8 @@ SECTIONS
 			EFI_IMAGE_INFO_OFFSET(__drtm_measured_start);
 			/* dlme_measured_size */
 			EFI_IMAGE_INFO_ENTRY(__drtm_measured_end - __drtm_measured_start);
+			EFI_IMAGE_INFO_OFFSET(drtm_entry);
+			EFI_IMAGE_INFO_OFFSET(arm64_drtm_handoff);
 #endif
 		)
 	}
@@ -381,6 +383,8 @@ SECTIONS
 	 *   DLME Region Address = _text's PA ie the start of Image
 	 *   DLME Region Size = DLME Data Offset + "Minimum Size of DLME data"
 	 *   DLME Image Start Offset = __drtm_measured_start - _text
+	 *   DLME Entry Point Offset = drtm_entry - __drtm_measured_start
+	 *                             (in .init.text)
 	 *   DLME Image Size = __drtm_measured_end - __drtm_measured_start
 	 *   DLME Data Offset = __drtm_dlme_start - _text
 	 *   Normal World DCE region address = PA of __drtm_dlme_start +
@@ -467,6 +471,10 @@ ASSERT(__hyp_idmap_text_end - __hyp_idmap_text_start <= PAGE_SIZE,
 	"HYP init code too big")
 ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K,
 	"ID map text too big or misaligned")
+#ifdef CONFIG_ARM64_DRTM
+ASSERT(drtm_entry >= __drtm_measured_start && drtm_entry < __drtm_measured_end,
+	"DRTM entry is outside the measured image")
+#endif
 #ifdef CONFIG_HIBERNATION
 ASSERT(__hibernate_exit_text_end - __hibernate_exit_text_start <= SZ_4K,
        "Hibernate exit text is bigger than 4 KiB")
-- 
2.43.0



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

* [PATCH 15/16] arm64: drtm: Call UNPROTECT_MEMORY
  2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
                   ` (13 preceding siblings ...)
  2026-09-24 13:53 ` [PATCH 14/16] arm64: drtm: Add drtm_entry point to head.S Jason Gunthorpe
@ 2026-09-24 13:53 ` Jason Gunthorpe
  2026-09-24 13:53 ` [PATCH 16/16] efi/arm64: Implement ARM64 DRTM in the stub Jason Gunthorpe
  15 siblings, 0 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

The stub always requests ARM_DRTM_LAUNCH_DMA_COMPLETE. On a system
with an SMMU the COMPLETE option is sanely implemented using the SMMU
global abort register. DMA_COMPLETE should be mostly a no-op. It
seems to be designed for the region protection mode that Linux does
not use.

However, the FW can still do something interesting under it and we
should call it. Choose late_initcall as we know the SMMU drivers are
loaded by then. If some platform does actually block DMA beyond the
SMMU, then this would result in a noisy failure of built-in driver
DMA, not a silent security gap.

The platforms I'm aware of are OK with this placement, and it is a
reasonable place to start.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 arch/arm64/kernel/drtm.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/arch/arm64/kernel/drtm.c b/arch/arm64/kernel/drtm.c
index 14493948a27f0d..3d1af2d34c987e 100644
--- a/arch/arm64/kernel/drtm.c
+++ b/arch/arm64/kernel/drtm.c
@@ -3,8 +3,47 @@
  *
  * Support functions for ARM DEN 0113 "DRTM Architecture for Arm"
  */
+#include <linux/bug.h>
 #include <linux/efi.h>
+#include <linux/init.h>
+#include <linux/printk.h>
 
 #include <asm/drtm.h>
 
 struct arm64_drtm_handoff arm64_drtm_handoff __efi_data_handoff;
+
+static int __init arm64_drtm_unprotect_memory(void)
+{
+	s64 status;
+
+	if (!arm64_drtm_handoff.drtm_enabled)
+		return 0;
+
+	/*
+	 * Currently Linux can only fully support a DRTM implementation that
+	 * relies only the SMMU. This should be called directly after attaching
+	 * a driver to every SMMU but before binding any drivers that want to
+	 * use devices attached to the SMMU. Our boot flow does not have a way
+	 * to do that, so for now call it here.
+	 *
+	 * For SMMU based implementations their UNPROTECT_MEMORY is probably a
+	 * NOP since touching the SMMU here is forbidden, but they may still do
+	 * something interesting so be sure to call it at least.
+	 *
+	 * The stub excludes the most likely case of non-SMMU by only using
+	 * ARM_DRTM_LAUNCH_DMA_COMPLETE, which is defined as:
+	 *    Complete DMA protection is hardware-based enforcement at the SMMU
+	 *    that blocks all DMA from Non- secure devices."
+	 *
+	 * For now if people have such systems they cannot include built-in
+	 * drivers for any DMA devices, those have to be modules to be ordered
+	 * after this.
+	 */
+	status = arm_drtm_unprotect_memory();
+	WARN(status != ARM_DRTM_SUCCESS,
+	     "DRTM: failed to unprotect memory (x0=%lld)", status);
+	if (status == ARM_DRTM_SUCCESS)
+		pr_info("DRTM: launch completed\n");
+	return 0;
+}
+late_initcall_sync(arm64_drtm_unprotect_memory);
-- 
2.43.0



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

* [PATCH 16/16] efi/arm64: Implement ARM64 DRTM in the stub
  2026-09-24 13:53 [PATCH 00/16] arm64: DRTM, boot portion Jason Gunthorpe
                   ` (14 preceding siblings ...)
  2026-09-24 13:53 ` [PATCH 15/16] arm64: drtm: Call UNPROTECT_MEMORY Jason Gunthorpe
@ 2026-09-24 13:53 ` Jason Gunthorpe
  2026-09-25 18:37   ` Jonathan Cameron
  15 siblings, 1 reply; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 13:53 UTC (permalink / raw)
  To: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon
  Cc: Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

Provide an implementation of the CONFIG_EFI_STUB_DRTM protocol for ARM64
DEN0113 >= v1.1.

First, it queries the FW for support and collects all the
information. This is needed to compute the extra_size, which comes
from FW reporting how much memory it needs during the launch for the
DLME Data and DCE-owned data. The generic stub ensures there is
trailing memory after Image for this.

Then the DRTM_PARAMETERS launch structure is computed using the
offsets in the efi_info.

Finally, the stub does ExitBootServices and calls the actual launch.

The feature discovery process is deliberately fairly verbose to help
debug any FW weirdness in the field. Enable it with efi=debug

It looks something like:

 EFI stub: DRTM: interface version 1.4
 EFI stub: DEBUG: DRTM: TPM algorithm 0xc, TPM hashing unavailable, PCR schemas 0x1
 EFI stub: DEBUG: DRTM: minimum DLME data 73728 bytes, Normal-world DCE 0 bytes
 EFI stub: Decompressing Linux Kernel...
 EFI stub: Generating empty DTB
 EFI stub: Exiting boot services...
 EFI stub: DEBUG: DRTM: will launch, selected launch features 0x0
 [    0.000000] Booting Linux on physical CPU 0x0000000000 [0x000f0510]

Eventually the launch'd kernel is going to require built in crypto
libraries that match what the FW is using so it can validate some of the
information left behind during early boot. Refuse to launch if these are
not built in and build in the most common ones from the ARM64_DRTM
kconfig.

One nit, if the platform does not support SMC then using drtm=auto may
crash on the SMC op. As far as I can tell there is no way to discover SMC
support through EFI. Learning it from the ACPI FADT is doable and costs
about 250 lines of code.

Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
 arch/arm64/Kconfig                        |  16 +
 drivers/firmware/efi/libstub/Makefile     |   1 +
 drivers/firmware/efi/libstub/arm64-drtm.c | 414 ++++++++++++++++++++++
 3 files changed, 431 insertions(+)
 create mode 100644 drivers/firmware/efi/libstub/arm64-drtm.c

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 4a752835ce1116..30244bc2d57696 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2543,6 +2543,22 @@ config EFI
 	  allow the kernel to be booted as an EFI application. This
 	  is only useful on systems that have UEFI firmware.
 
+config ARM64_DRTM
+	bool "Arm Dynamic Root of Trust for Measurement support"
+	depends on EFI
+	select CRYPTO
+	select CRYPTO_SHA256
+	select CRYPTO_SHA512
+	select EFI_STUB_DRTM
+	help
+	  Support launching Linux as a Dynamically Launched Measured
+	  Environment (DLME) using Arm's DEN0113 DRTM specification. Requires
+	  booting through the EFI stub. The drtm= kernel command line option
+	  enables or disables the launch at boot.
+
+	  If unsure, say N. This option is EXPERIMENTAL and does not yet provide
+	  security.
+
 config COMPRESSED_INSTALL
 	bool "Install compressed image by default"
 	help
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 3f1921e6c334d1..f0958b4df16592 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -83,6 +83,7 @@ lib-$(CONFIG_EFI_GENERIC_STUB)	+= efi-stub.o string.o intrinsics.o systable.o \
 
 lib-$(CONFIG_ARM)		+= arm32-stub.o
 lib-$(CONFIG_ARM64)		+= kaslr.o arm64.o arm64-stub.o smbios.o
+lib-$(CONFIG_ARM64_DRTM)	+= arm64-drtm.o
 lib-$(CONFIG_X86)		+= x86-stub.o smbios.o
 lib-$(CONFIG_X86_64)		+= x86-5lvl.o
 lib-$(CONFIG_RISCV)		+= kaslr.o riscv.o riscv-stub.o
diff --git a/drivers/firmware/efi/libstub/arm64-drtm.c b/drivers/firmware/efi/libstub/arm64-drtm.c
new file mode 100644
index 00000000000000..12ddf7c2dd056a
--- /dev/null
+++ b/drivers/firmware/efi/libstub/arm64-drtm.c
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES
+ *
+ * EFI Stub implementation for ARM DEN 0113 "DRTM Architecture for Arm"
+ *
+ * This code runs on the untrusted side of the boot in the ACPI stub. Nothing it
+ * does should impact the integrity of the post-launch world and it does not
+ * need to take special security precautions.
+ */
+#include <linux/bitfield.h>
+#include <linux/efi.h>
+#include <linux/kconfig.h>
+#include <linux/overflow.h>
+#include <linux/sizes.h>
+#include <linux/tpm_command.h>
+#include <linux/unaligned.h>
+
+#include <uapi/linux/psci.h>
+
+#include <asm/cputype.h>
+#include <asm/drtm.h>
+#include <asm/image.h>
+
+#include "efistub.h"
+
+struct efi_drtm_config {
+	u32 launch_features;
+	unsigned long dlme_data_size;
+	unsigned long nw_dce_size;
+	struct arm_drtm_parameters *params_addr;
+};
+static struct efi_drtm_config drtm_cfg;
+
+/* True if SMCCC 1.0 or later is available. */
+static bool efi_arm64_psci_smccc_compatible(void)
+{
+	struct arm_smccc_res res;
+	s32 status;
+
+	arm_smccc_1_1_smc(PSCI_0_2_FN_PSCI_VERSION, &res);
+	if ((s32)res.a0 < 0)
+		return false;
+
+	if (PSCI_VERSION_MAJOR(res.a0) < 1)
+		return false;
+
+	arm_smccc_1_1_smc(PSCI_1_0_FN_PSCI_FEATURES, ARM_SMCCC_VERSION_FUNC_ID,
+			  &res);
+	status = (s32)res.a0;
+	if (status == PSCI_RET_NOT_SUPPORTED) {
+		/*
+		 * SMCCC_VERSION was introduced by SMCCC 1.1, so firmware that
+		 * does not advertise that function through PSCI_FEATURES is
+		 * using the valid SMCCC 1.0 baseline.
+		 */
+		return true;
+	} else if (status < 0) {
+		return false;
+	} else {
+		u32 version;
+
+		arm_smccc_1_1_smc(ARM_SMCCC_VERSION_FUNC_ID, &res);
+		version = res.a0;
+		if ((version >> 16) != 1 || version < ARM_SMCCC_VERSION_1_1)
+			return false;
+	}
+	return true;
+}
+
+static bool efi_drtm_query_feature(u64 feature, u64 *value)
+{
+	s64 status;
+
+	status = arm_drtm_features(ARM_DRTM_FEATURE_SELECTOR | feature, value);
+	/*
+	 * v1.4b Section 3.3.1 says:
+	 *   A return value of greater than 0 means the feature ID is
+	 *   implemented, and there are other feature-specific
+	 *   feature or capability bits available in other return value
+	 *   registers.
+	 * And for FEATURE_SELECTOR all defined features return data in other
+	 * registers, so 0 is not an allowed return.
+	 */
+	if (status < 1) {
+		efi_err("DRTM: feature %llx query failed (x0=%lld)\n", feature,
+			status);
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * For the kernel to boot it must have the matching hash algorithm built in to
+ * be able to validate the TCB hashes. Assume the TPM hash algorithm is the one
+ * that TCB_HASH_TABLE will be using.
+ */
+static bool efi_drtm_hash_algorithm_supported(u16 algorithm)
+{
+	switch (algorithm) {
+	case TPM_ALG_SHA256:
+		return IS_BUILTIN(CONFIG_CRYPTO_SHA256);
+	case TPM_ALG_SHA384:
+	case TPM_ALG_SHA512:
+		return IS_BUILTIN(CONFIG_CRYPTO_SHA512);
+	default:
+		return false;
+	}
+}
+
+static bool efi_drtm_probe_tpm(void)
+{
+	u16 algorithm;
+	u8 schemas;
+	u64 value;
+
+	if (!efi_drtm_query_feature(ARM_DRTM_FEATURE_TPM, &value))
+		return false;
+	algorithm = FIELD_GET(ARM_DRTM_TPM_ALG_MASK, value);
+	schemas = FIELD_GET(ARM_DRTM_PCR_SCHEMA_MASK, value);
+
+	if (!efi_drtm_hash_algorithm_supported(algorithm)) {
+		efi_err("DRTM: firmware hash algorithm 0x%x is unavailable (feature 0x%llx)\n",
+			algorithm, value);
+		return false;
+	}
+
+	if (!(value & ARM_DRTM_PCR_SCHEMA_DEFAULT)) {
+		efi_err("DRTM: default PCR schema is unavailable (feature 0x%llx)\n",
+			value);
+		return false;
+	}
+
+	efi_debug(
+		"DRTM: TPM algorithm 0x%x, TPM hashing %s, PCR schemas 0x%x\n",
+		algorithm,
+		value & ARM_DRTM_TPM_HASHING ? "available" : "unavailable",
+		schemas);
+	return true;
+}
+
+static bool efi_drtm_probe_memory(void)
+{
+	u64 value;
+
+	if (!efi_drtm_query_feature(ARM_DRTM_FEATURE_MIN_MEMORY, &value))
+		return false;
+
+	drtm_cfg.dlme_data_size =
+		FIELD_GET(ARM_DRTM_DLME_DATA_PAGES_MASK, value) *
+		ARM_DRTM_PAGE_SIZE;
+	drtm_cfg.nw_dce_size = FIELD_GET(ARM_DRTM_NW_DCE_PAGES_MASK, value) *
+			       ARM_DRTM_PAGE_SIZE;
+
+	efi_debug(
+		"DRTM: minimum DLME data %lu bytes, Normal-world DCE %lu bytes\n",
+		drtm_cfg.dlme_data_size, drtm_cfg.nw_dce_size);
+	return true;
+}
+
+static bool efi_drtm_probe_dma(void)
+{
+	u64 value;
+
+	if (!efi_drtm_query_feature(ARM_DRTM_FEATURE_DMA_PROTECTION, &value))
+		return false;
+
+	if (!(value & ARM_DRTM_DMA_PROTECTION_COMPLETE)) {
+		efi_err("DRTM: complete DMA protection is unavailable (feature 0x%llx)\n",
+			value);
+		return false;
+	}
+	return true;
+}
+
+/* Sanity check nothing has gone wrong */
+static bool efi_drtm_probe_boot_pe(void)
+{
+	u64 current_pe = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
+	u64 boot_pe;
+
+	if (!efi_drtm_query_feature(ARM_DRTM_FEATURE_BOOT_PE, &boot_pe))
+		return false;
+
+	if ((boot_pe & MPIDR_HWID_BITMASK) != current_pe) {
+		efi_err("DRTM: boot PE 0x%llx does not match current PE 0x%llx\n",
+			boot_pe, current_pe);
+		return false;
+	}
+
+	return true;
+}
+
+static void efi_drtm_report_previous_error(void)
+{
+	s64 error_code;
+	s64 status;
+
+	status = arm_drtm_features(ARM_DRTM_SMC_GET_ERROR, NULL);
+	if (status != ARM_DRTM_SUCCESS) {
+		efi_debug("DRTM: GET_ERROR is unavailable (x0=%lld)\n", status);
+		return;
+	}
+
+	status = arm_drtm_get_error(&error_code);
+	if (status != ARM_DRTM_SUCCESS) {
+		efi_warn("DRTM: failed to read previous error (x0=%lld)\n",
+			 status);
+		return;
+	}
+
+	if (error_code) {
+		efi_warn(
+			"DRTM: firmware reports previous launch error 0x%llx\n",
+			error_code);
+		if (efi_drtm_policy != EFI_DRTM_ENFORCE)
+			efi_drtm_policy = EFI_DRTM_OFF;
+	}
+}
+
+static efi_status_t efi_drtm_failure(void)
+{
+	if (efi_drtm_policy == EFI_DRTM_AUTO) {
+		efi_warn("DRTM: preparation failed, continuing without DRTM\n");
+		efi_drtm_policy = EFI_DRTM_OFF;
+		return EFI_SUCCESS;
+	}
+
+	efi_err("DRTM: enforced preparation failed\n");
+	return EFI_UNSUPPORTED;
+}
+
+efi_status_t efi_drtm_prepare(void)
+{
+	s64 feature_status;
+	u16 major, minor;
+	s32 status;
+
+	if (efi_drtm_policy == EFI_DRTM_OFF)
+		return EFI_SUCCESS;
+
+	if (!efi_arm64_psci_smccc_compatible())
+		return efi_drtm_failure();
+
+	/* VERSION must be the first DRTM call. */
+	status = arm_drtm_version(&major, &minor);
+	if (status != ARM_DRTM_SUCCESS) {
+		efi_err("DRTM: failed to read interface version (x0=%d)\n",
+			status);
+		return efi_drtm_failure();
+	}
+	if (major != ARM_DRTM_VERSION_MAJOR ||
+	    minor < ARM_DRTM_VERSION_MIN_MINOR) {
+		efi_err("DRTM: unsupported interface version %u.%u\n", major,
+			minor);
+		return efi_drtm_failure();
+	}
+	efi_info("DRTM: interface version %u.%u\n", major, minor);
+
+	efi_drtm_report_previous_error();
+	if (efi_drtm_policy == EFI_DRTM_OFF)
+		return EFI_SUCCESS;
+
+	feature_status = arm_drtm_features(ARM_DRTM_SMC_DYNAMIC_LAUNCH, NULL);
+	if (feature_status != ARM_DRTM_SUCCESS) {
+		efi_err("DRTM: dynamic launch is unavailable (x0=%lld)\n",
+			feature_status);
+		return efi_drtm_failure();
+	}
+
+	if (!efi_drtm_probe_tpm() || !efi_drtm_probe_memory() ||
+	    !efi_drtm_probe_dma() || !efi_drtm_probe_boot_pe())
+		return efi_drtm_failure();
+
+	drtm_cfg.launch_features =
+		ARM_DRTM_LAUNCH_HASH_FIRMWARE | ARM_DRTM_LAUNCH_PCR_DEFAULT |
+		ARM_DRTM_LAUNCH_DMA_COMPLETE | ARM_DRTM_LAUNCH_NO_AUTH |
+		ARM_DRTM_LAUNCH_KEEP_SECURE_IRQS;
+
+	return EFI_SUCCESS;
+}
+
+unsigned long efi_drtm_get_extra_size(void)
+{
+	/*
+	 * DEN0113 Table 6, feature 0x2 reports both minimum sizes in 4 KiB
+	 * pages.  The linker places the DLME data at the 4 KiB-aligned end of
+	 * the static Image as required by R314030.  The DLME region must
+	 * include all of that data (R45200), and an optional Normal-world DCE
+	 * follows it at another 4 KiB-aligned address as required by R312080.
+	 * A final page holds the 4 KiB-aligned DRTM_PARAMETERS required by
+	 * R312010.  Only the first area is part of the DLME region.
+	 */
+	if (efi_drtm_policy == EFI_DRTM_OFF)
+		return 0;
+	return drtm_cfg.dlme_data_size + drtm_cfg.nw_dce_size +
+	       ARM_DRTM_PAGE_SIZE;
+}
+
+efi_status_t efi_drtm_prepare_launch(unsigned long image_base,
+				     unsigned long fdt_addr)
+{
+	const struct arm64_image_header *header = (const void *)image_base;
+	const struct efi_image_info *info = efi_get_image_info(image_base);
+	struct arm64_drtm_handoff *handoff =
+		efi_get_image_symbol(image_base, arm64_drtm_handoff);
+	struct arm_drtm_parameters *params;
+	unsigned long measured_offset;
+	unsigned long measured_size;
+	unsigned long image_size;
+	unsigned long dlme_start;
+	unsigned long dlme_end;
+	unsigned long dce_end;
+	unsigned long entry;
+
+	if (efi_drtm_policy == EFI_DRTM_OFF)
+		return EFI_SUCCESS;
+
+	image_size = le64_to_cpu(header->image_size);
+	measured_offset = le64_to_cpu(info->drtm_measured_start);
+	measured_size = le64_to_cpu(info->dlme_measured_size);
+	entry = le64_to_cpu(info->drtm_entry);
+	dlme_start = image_base + image_size;
+	dlme_end = dlme_start + drtm_cfg.dlme_data_size;
+	dce_end = dlme_end + drtm_cfg.nw_dce_size;
+
+	/* Quick checks something didn't go wrong during image construction */
+	if (entry < measured_offset ||
+	    entry - measured_offset >= measured_size ||
+	    !IS_ALIGNED(image_base, ARM_DRTM_PAGE_SIZE) ||
+	    !IS_ALIGNED(image_size, ARM_DRTM_PAGE_SIZE) ||
+	    !IS_ALIGNED(measured_offset, ARM_DRTM_PAGE_SIZE) ||
+	    !IS_ALIGNED(dlme_start, ARM_DRTM_PAGE_SIZE) ||
+	    !IS_ALIGNED(dlme_end, ARM_DRTM_PAGE_SIZE) ||
+	    !IS_ALIGNED(dce_end, ARM_DRTM_PAGE_SIZE)) {
+		efi_err("DRTM: final Image layout is invalid\n");
+		return efi_drtm_failure();
+	}
+
+	/*
+	 * See arch/arm64/kernel/vmlinux.lds.S for the DRTM Memory layout. After
+	 * the DLME we choose to place the Normal World DCE region followed by
+	 * the aligned DRTM_PARAMETERS structure.
+	 */
+	memset((void *)dlme_start, 0, efi_drtm_get_extra_size());
+	params = (void *)dce_end;
+	params->revision = cpu_to_le16(ARM_DRTM_PARAMETERS_REVISION);
+	params->launch_features = cpu_to_le32(drtm_cfg.launch_features);
+	params->dlme_region_address = cpu_to_le64(image_base);
+	params->dlme_region_size = cpu_to_le64(dlme_end - image_base);
+	params->dlme_image_start = cpu_to_le64(measured_offset);
+	params->dlme_entry_point_offset = cpu_to_le64(entry - measured_offset);
+	params->dlme_image_size = cpu_to_le64(measured_size);
+	params->dlme_data_offset = cpu_to_le64(image_size);
+	if (drtm_cfg.nw_dce_size) {
+		params->nw_dce_region_address = cpu_to_le64(dlme_end);
+		params->nw_dce_region_size = cpu_to_le64(drtm_cfg.nw_dce_size);
+	}
+
+	/*
+	 * The DLME Data contains its own size in a trusted header, so the
+	 * handoff doesn't need to include extra_size. The DCE Data is only
+	 * temporary so the kernel also does not need to know about it.
+	*/
+	handoff->fdt_addr = cpu_to_le64(fdt_addr);
+	handoff->drtm_enabled = 1;
+
+	efi_debug("DRTM: will launch, selected launch features 0x%x\n",
+		  drtm_cfg.launch_features);
+
+	drtm_cfg.params_addr = params;
+	return EFI_SUCCESS;
+}
+
+static void efi_drtm_fallback(void)
+{
+	struct arm_drtm_parameters *params = drtm_cfg.params_addr;
+	unsigned long image_base = le64_to_cpu(params->dlme_region_address);
+	struct arm64_drtm_handoff *handoff =
+		efi_get_image_symbol(image_base, arm64_drtm_handoff);
+
+	handoff->drtm_enabled = 0;
+}
+
+void efi_drtm_launch(void)
+{
+
+	if (efi_drtm_policy == EFI_DRTM_OFF)
+		return;
+
+	/*
+	 * No cache maintenance is required before the launch. DEN0113 R42130
+	 * requires the DRTM_PARAMETERS to be accessible as Normal Write-Back
+	 * Cacheable, Inner Shareable memory, so the DCE reads them coherently
+	 * with the writes made above.  R45220 then has the DCE clean and
+	 * invalidate the whole DLME region to the Point of Coherency before it
+	 * measures the DLME image, which covers both the Image itself and the
+	 * handoff struct placed in the DLME region. Thus once we jump into the
+	 * kernel with MMU and caches off the CPU will see everything the stub
+	 * wrote.
+	 */
+	arm_drtm_dynamic_launch(drtm_cfg.params_addr);
+
+	/*
+	 * DEN0113 section 3.4 returns from DYNAMIC_LAUNCH only on error. Boot
+	 * services and their diagnostics are no longer available, so hang.
+	 */
+	if (efi_drtm_policy == EFI_DRTM_ENFORCE) {
+		for (;;)
+			asm volatile("wfe");
+	}
+
+	efi_drtm_fallback();
+}
-- 
2.43.0



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

* Re: [PATCH 01/16] efi/libstub: Fix error unwind freeing fdt in allocate_new_fdt_and_exit_boot()
  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
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Cameron @ 2026-09-24 22:42 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon,
	Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

On Thu, 24 Sep 2026 10:53:04 -0300
Jason Gunthorpe <jgg@nvidia.com> wrote:

> Sashiko says fdt_addr can point to either an allocated fdt or the fdt from
> get_fdt() which is memory owned by FW.
> 
> Only the allocated fdt should be freed on the error unwind path. Use a
> dedicated variable for the allocation's size so that the free does not get
> confused.
> 
> Fixes: 4fc8e738ff3e ("efi: libstub: remove DT dependency from generic stub")
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
> ---
>  drivers/firmware/efi/libstub/fdt.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
> index 23b3543d3041b0..5b2dd709d7b151 100644
> --- a/drivers/firmware/efi/libstub/fdt.c
> +++ b/drivers/firmware/efi/libstub/fdt.c
> @@ -229,6 +229,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
>  	u32 desc_ver;
>  	efi_status_t status;
>  	struct exit_boot_struct priv;
> +	unsigned long fdt_size_allocated = 0;
>  	unsigned long fdt_addr = 0;
>  	unsigned long fdt_size = 0;
>  
> @@ -257,6 +258,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
>  			efi_err("Failed to load device tree!\n");
>  			goto fail;
>  		}
> +		fdt_size_allocated = fdt_size;
Hmm. I argued with myself for a while on this.  Which one of fdt_size and fdt_size_allocate
is the appropriate one to pass to the call?  In the end I didn't get a good answer so
oh I guess this is as good as the other way around.

Bug looks real to me and this fixes it I think. Give I know this code very little
take this tag with a pinch of salt.

Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>

>  	}
>  
>  	if (fdt_addr) {
> @@ -334,7 +336,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
>  	efi_free(MAX_FDT_SIZE, *new_fdt_addr);
>  
>  fail:
> -	efi_free(fdt_size, fdt_addr);
> +	efi_free(fdt_size_allocated, fdt_addr);
>  	if (!efi_novamap)
>  		efi_bs_call(free_pool, priv.runtime_map);
>  



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

* Re: [PATCH 03/16] efi/libstub: Free cmdline_ptr in efi_pe_entry
  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
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Cameron @ 2026-09-24 22:49 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon,
	Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

On Thu, 24 Sep 2026 10:53:06 -0300
Jason Gunthorpe <jgg@nvidia.com> wrote:

> Sashiko points out that efi_handle_cmdline() allocates this memory and
> hands it over to the caller. If efi_pe_entry() ever returns it should be
> freed. Add a __free annotation.
> 
> Fixes: 42c8ea3dca09 ("efi: libstub: Factor out EFI stub entrypoint into separate file")
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
> ---
>  drivers/firmware/efi/libstub/efi-stub-entry.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
> index aa85e910fe595e..83fade2b0d3b84 100644
> --- a/drivers/firmware/efi/libstub/efi-stub-entry.c
> +++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
> @@ -40,7 +40,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
>  	unsigned long image_addr;
>  	unsigned long image_size = 0;
>  	/* addr/point and size pairs for memory management*/
> -	char *cmdline_ptr = NULL;
> +	char *cmdline_ptr __free(efi_pool) = NULL;

Can we move this down to just above the call to efi_handle_cmdline that
does the constructor side of this?

I see none of the efi stuff follow those guidance note that went in cleanup.h.

Ah well, not my problem :)

J

>  	efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
>  	unsigned long reserve_addr = 0;
>  	unsigned long reserve_size = 0;



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

* Re: [PATCH 04/16] vmlinux.lds: Move DATA_LE32() from arm64 to the common linker script
  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
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Cameron @ 2026-09-24 22:53 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon,
	Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai, Will Deacon

On Thu, 24 Sep 2026 10:53:07 -0300
Jason Gunthorpe <jgg@nvidia.com> wrote:

> Other arches may want to use this to get consistent fixed endian output.

You will have to grab it quickly!
https://lore.kernel.org/all/20260918145217.1669-10-will@kernel.org/#Z31arch:arm64:kernel:image.h
drops that definition as part of ripping out arm64 big endian support.

+CC Will for awareness.

> 
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
> ---
>  arch/arm64/kernel/image.h         | 14 --------------
>  include/asm-generic/vmlinux.lds.h | 15 +++++++++++++++
>  2 files changed, 15 insertions(+), 14 deletions(-)
> 
> diff --git a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h
> index 7bc3ba89790191..1bff6b061b6cab 100644
> --- a/arch/arm64/kernel/image.h
> +++ b/arch/arm64/kernel/image.h
> @@ -14,26 +14,12 @@
>  #include <asm/image.h>
>  
>  /*
> - * There aren't any ELF relocations we can use to endian-swap values known only
> - * at link time (e.g. the subtraction of two symbol addresses), so we must get
> - * the linker to endian-swap certain values before emitting them.
> - *
>   * Note that, in order for this to work when building the ELF64 PIE executable
>   * (for KASLR), these values should not be referenced via R_AARCH64_ABS64
>   * relocations, since these are fixed up at runtime rather than at build time
>   * when PIE is in effect. So we need to split them up in 32-bit high and low
>   * words.
>   */
> -#ifdef CONFIG_CPU_BIG_ENDIAN
> -#define DATA_LE32(data)				\
> -	((((data) & 0x000000ff) << 24) |	\
> -	 (((data) & 0x0000ff00) << 8)  |	\
> -	 (((data) & 0x00ff0000) >> 8)  |	\
> -	 (((data) & 0xff000000) >> 24))
> -#else
> -#define DATA_LE32(data) ((data) & 0xffffffff)
> -#endif
> -
>  #define DEFINE_IMAGE_LE64(sym, data)				\
>  	sym##_lo32 = DATA_LE32((data) & 0xffffffff);		\
>  	sym##_hi32 = DATA_LE32((data) >> 32)
> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
> index b2988aa12f6645..1786a8e4323b9f 100644
> --- a/include/asm-generic/vmlinux.lds.h
> +++ b/include/asm-generic/vmlinux.lds.h
> @@ -56,6 +56,21 @@
>  #define LOAD_OFFSET 0
>  #endif
>  
> +/*
> + * There aren't any ELF relocations we can use to endian-swap values known only
> + * at link time (e.g. the subtraction of two symbol addresses), so we must get
> + * the linker to endian-swap certain values before emitting them.
> + */
> +#ifdef CONFIG_CPU_BIG_ENDIAN
> +#define DATA_LE32(data)				\
> +	((((data) & 0x000000ff) << 24) |	\
> +	 (((data) & 0x0000ff00) << 8)  |	\
> +	 (((data) & 0x00ff0000) >> 8)  |	\
> +	 (((data) & 0xff000000) >> 24))
> +#else
> +#define DATA_LE32(data) ((data) & 0xffffffff)
> +#endif
> +
>  /*
>   * Only some architectures want to have the .notes segment visible in
>   * a separate PT_NOTE ELF Program Header. When this happens, it needs



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

* Re: [PATCH 07/16] efi/zboot: Lift efi_cache_sync_image() from efi_zboot_decompress()
  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
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Cameron @ 2026-09-24 22:57 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon,
	Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

On Thu, 24 Sep 2026 10:53:10 -0300
Jason Gunthorpe <jgg@nvidia.com> wrote:

> The two decompressors duplicate this call and the next patch needs to
> change the argument. Hoist it up to remove the duplication.
> 
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>

> diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
> index 4b76f74c56dae0..960a542881d875 100644
> --- a/drivers/firmware/efi/libstub/zboot.c
> +++ b/drivers/firmware/efi/libstub/zboot.c
> @@ -92,9 +92,12 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
>  	}
>  
>  	// Decompress the payload into the newly allocated buffer
> -	status = efi_zboot_decompress((void *)image_base, alloc_size) ?:
> -	         efi_stub_common(handle, image, image_base, cmdline_ptr);
> -
> +	status = efi_zboot_decompress((void *)image_base, alloc_size);
> +	if (status == EFI_SUCCESS) {
> +		efi_cache_sync_image(image_base, alloc_size);
> +		status =
> +			efi_stub_common(handle, image, image_base, cmdline_ptr);

Just go one character longer!

> +	}
>  	efi_free(alloc_size, image_base);
>  	return status;
>  }



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

* Re: [PATCH 01/16] efi/libstub: Fix error unwind freeing fdt in allocate_new_fdt_and_exit_boot()
  2026-09-24 22:42   ` Jonathan Cameron
@ 2026-09-24 23:44     ` Jason Gunthorpe
  0 siblings, 0 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 23:44 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon,
	Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

On Thu, Sep 24, 2026 at 03:42:27PM -0700, Jonathan Cameron wrote:
> On Thu, 24 Sep 2026 10:53:04 -0300
> Jason Gunthorpe <jgg@nvidia.com> wrote:
> 
> > Sashiko says fdt_addr can point to either an allocated fdt or the fdt from
> > get_fdt() which is memory owned by FW.
> > 
> > Only the allocated fdt should be freed on the error unwind path. Use a
> > dedicated variable for the allocation's size so that the free does not get
> > confused.
> > 
> > Fixes: 4fc8e738ff3e ("efi: libstub: remove DT dependency from generic stub")
> > Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
> > ---
> >  drivers/firmware/efi/libstub/fdt.c | 4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
> > index 23b3543d3041b0..5b2dd709d7b151 100644
> > --- a/drivers/firmware/efi/libstub/fdt.c
> > +++ b/drivers/firmware/efi/libstub/fdt.c
> > @@ -229,6 +229,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
> >  	u32 desc_ver;
> >  	efi_status_t status;
> >  	struct exit_boot_struct priv;
> > +	unsigned long fdt_size_allocated = 0;
> >  	unsigned long fdt_addr = 0;
> >  	unsigned long fdt_size = 0;
> >  
> > @@ -257,6 +258,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
> >  			efi_err("Failed to load device tree!\n");
> >  			goto fail;
> >  		}
> > +		fdt_size_allocated = fdt_size;
> Hmm. I argued with myself for a while on this.  Which one of fdt_size and fdt_size_allocate
> is the appropriate one to pass to the call?  In the end I didn't get a good answer so
> oh I guess this is as good as the other way around.

Huh. Functionally it does not matter, but looking at it again I will
change it to pass fdt_size_allocated since that chases down to the
actual allocation. Makes more sense to me like that.

@@ -253,13 +253,13 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
                if (strstr(cmdline_ptr, "dtb="))
                        efi_err("Ignoring DTB from command line.\n");
        } else {
-               status = efi_load_dtb(image, &fdt_addr, &fdt_size);
+               status = efi_load_dtb(image, &fdt_addr, &fdt_size_allocated);
 
                if (status != EFI_SUCCESS && status != EFI_NOT_READY) {
                        efi_err("Failed to load device tree!\n");
                        goto fail;
                }
-               fdt_size_allocated = fdt_size;
+               fdt_size = fdt_size_allocated;
        }

Thanks,
Jason


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

* Re: [PATCH 04/16] vmlinux.lds: Move DATA_LE32() from arm64 to the common linker script
  2026-09-24 22:53   ` Jonathan Cameron
@ 2026-09-24 23:50     ` Jason Gunthorpe
  2026-09-25 13:30       ` Ard Biesheuvel
  0 siblings, 1 reply; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 23:50 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon,
	Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

On Thu, Sep 24, 2026 at 03:53:07PM -0700, Jonathan Cameron wrote:
> On Thu, 24 Sep 2026 10:53:07 -0300
> Jason Gunthorpe <jgg@nvidia.com> wrote:
> 
> > Other arches may want to use this to get consistent fixed endian output.
> 
> You will have to grab it quickly!
> https://lore.kernel.org/all/20260918145217.1669-10-will@kernel.org/#Z31arch:arm64:kernel:image.h
> drops that definition as part of ripping out arm64 big endian support.

Ah, well easy conflict resolution then :)

When I was doing this I was really doubting why it had to be endian
specific, this is mostly a cargo cult from the other stuff that was
already working that way..

I'm personally skeptical any arch could have either EFI stub a
different endianess than the vmlinux, it seems like nonsense on alot
of levels.

So, I will remove the fixed endian pieces from here? Does anyone think
otherwise?

Thanks,
Jason


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

* Re: [PATCH 07/16] efi/zboot: Lift efi_cache_sync_image() from efi_zboot_decompress()
  2026-09-24 22:57   ` Jonathan Cameron
@ 2026-09-24 23:53     ` Jason Gunthorpe
  0 siblings, 0 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-24 23:53 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon,
	Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

On Thu, Sep 24, 2026 at 03:57:21PM -0700, Jonathan Cameron wrote:
> On Thu, 24 Sep 2026 10:53:10 -0300
> Jason Gunthorpe <jgg@nvidia.com> wrote:
> 
> > The two decompressors duplicate this call and the next patch needs to
> > change the argument. Hoist it up to remove the duplication.
> > 
> > Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
> 
> > diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
> > index 4b76f74c56dae0..960a542881d875 100644
> > --- a/drivers/firmware/efi/libstub/zboot.c
> > +++ b/drivers/firmware/efi/libstub/zboot.c
> > @@ -92,9 +92,12 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
> >  	}
> >  
> >  	// Decompress the payload into the newly allocated buffer
> > -	status = efi_zboot_decompress((void *)image_base, alloc_size) ?:
> > -	         efi_stub_common(handle, image, image_base, cmdline_ptr);
> > -
> > +	status = efi_zboot_decompress((void *)image_base, alloc_size);
> > +	if (status == EFI_SUCCESS) {
> > +		efi_cache_sync_image(image_base, alloc_size);
> > +		status =
> > +			efi_stub_common(handle, image, image_base, cmdline_ptr);
> 
> Just go one character longer!

OK! You have good eyes to notice that! I use clang-format and stopped
caring! The flexible 80 unless you need it unless you are in the wrong
subsystem scares me!

Thanks,
Jason


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

* Re: [PATCH 12/16] arm64: drtm: Add macro definitions for DEN0113
  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
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Cameron @ 2026-09-25  0:29 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon,
	Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai,
	Suzuki K Poulose

On Thu, 24 Sep 2026 10:53:15 -0300
Jason Gunthorpe <jgg@nvidia.com> wrote:

> Taken from rev 1.4b of the spec, following the SMCC register layout and
> constant names.
> 
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
> ---
>  arch/arm64/include/asm/drtm.h | 196 ++++++++++++++++++++++++++++++++++
>  1 file changed, 196 insertions(+)
>  create mode 100644 arch/arm64/include/asm/drtm.h
> 
> diff --git a/arch/arm64/include/asm/drtm.h b/arch/arm64/include/asm/drtm.h
> new file mode 100644
> index 00000000000000..d6dd04a4ebcea5
> --- /dev/null
> +++ b/arch/arm64/include/asm/drtm.h
> @@ -0,0 +1,196 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES
> + *
> + * Definitions from ARM DEN 0113 "DRTM Architecture for Arm"
> + */
> +#ifndef __ASM_DRTM_H
> +#define __ASM_DRTM_H
> +
> +#include <linux/arm-smccc.h>
> +#include <linux/bits.h>
> +
> +/* Offset 0x02 is reserved by DEN0113. */
> +#define ARM_DRTM_SMC_FN_BASE                                      \
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \
> +			   ARM_SMCCC_OWNER_STANDARD, 0x110)

Another wrapper for the same thing. Now which patch set did I last
moan about this in...  RMM 2.0 firmware series.
https://lore.kernel.org/all/d7ccaf22-5bde-4344-8bf0-a5a17dcac0f3@arm.com/

This one at least does it via base and sum.  But that then separates it from
the spec?   That is sort of the case anyway because the spec has the full
number.  0xC400_0110 so I guess not too bad.

> +#define ARM_DRTM_SMC_VERSION			(ARM_DRTM_SMC_FN_BASE + 0x00)



> +#define ARM_DRTM_FEATURE_SELECTOR	BIT_U64(63)
> +#define ARM_DRTM_FEATURE_TPM		0x01
> +#define ARM_DRTM_FEATURE_MIN_MEMORY	0x02
> +#define ARM_DRTM_FEATURE_DMA_PROTECTION	0x03
> +#define ARM_DRTM_FEATURE_BOOT_PE	0x04
> +#define ARM_DRTM_FEATURE_TCB_HASH	0x05
> +#define ARM_DRTM_FEATURE_IMAGE_AUTH	0x06

Nice to have a mask for the 8 bits of the feature field.
Also nice to keep order the same as the SMC defines which would put this after
version.  That also puts it next to the values returned for each feature.



> +
> +#define ARM_DRTM_TPM_ALG_MASK		GENMASK_U64(15, 0)
> +#define ARM_DRTM_TPM_HASHING		BIT_U64(32)
> +#define ARM_DRTM_PCR_SCHEMA_MASK	GENMASK_U64(36, 33)
> +#define ARM_DRTM_PCR_SCHEMA_DEFAULT	BIT_U64(33)
> +#define ARM_DRTM_PCR_SCHEMA_AUTHORITIES	BIT_U64(34)

Ah.  Always love a field made up of a bunch of bits. Hard to define
cleanly.   Do you actually need the PCR_SCHEMA_MASK?  Might be easier
to just not have it?  I think you only use it for a print. Maybe
build the bits we understand from the two specific bits?

Alternatively you could use the spec style definition and have 
#define ARM_DRTM_PCR_SCHEMA_DEFAULT BIT(0)
#define ARM_DRTM_PCR_SCHEMA_AUTHORITIES BIT(1)
or similar and have to check them via a FIELD_GET(FIELD_GET())



> +
> +#define ARM_DRTM_DLME_DATA_PAGES_MASK	GENMASK_U64(31, 0)
> +#define ARM_DRTM_NW_DCE_PAGES_MASK	GENMASK_U64(63, 32)
> +#define ARM_DRTM_PAGE_SIZE		4096
> +
> +#define ARM_DRTM_DMA_PROTECTION_MASK	GENMASK_U64(7, 0)
> +#define ARM_DRTM_DMA_PROTECTION_COMPLETE BIT_U64(0)
> +#define ARM_DRTM_DMA_PROTECTION_REGION	BIT_U64(1)

Ah. They are at it again. Fields within fields.
Maybe could use some white space to make it somewhat obvious
that is going on?  Indent the subfield a bit more?


> +#define ARM_DRTM_MAX_REGIONS_MASK	GENMASK_U64(23, 8)

blank line here probably just to make it obvious going to a
different u64.

> +#define ARM_DRTM_TCB_HASH_COUNT_MASK	GENMASK_U64(7, 0)

Same here.  I vaguely wonder if it is worth adding something
reflecting the relevant feature ID to each of these defines
so we know what the are referring to?

> +#define ARM_DRTM_IMAGE_AUTH_SUPPORTED	BIT_U64(0)
> +

Maybe a comment for next lot to where to find them in the spec
- took me a while.  Table 9 DTRM_Parameters, line for
LAUNCH_FEATURES if anyone is following along.

> +#define ARM_DRTM_LAUNCH_HASH_FIRMWARE	0
> +#define ARM_DRTM_LAUNCH_HASH_TPM	BIT_U32(0)

I'd rather see them as fields and field value pairs but
can see that is going to get a bit verbose.

> +#define ARM_DRTM_LAUNCH_PCR_DEFAULT	0
> +#define ARM_DRTM_LAUNCH_PCR_AUTHORITIES	BIT_U32(1)
> +#define ARM_DRTM_LAUNCH_DMA_COMPLETE	0
> +#define ARM_DRTM_LAUNCH_DMA_REGION	BIT_U32(3)
> +#define ARM_DRTM_LAUNCH_NO_AUTH		0
> +#define ARM_DRTM_LAUNCH_AUTH		BIT_U32(6)
> +#define ARM_DRTM_LAUNCH_KEEP_SECURE_IRQS 0
> +#define ARM_DRTM_LAUNCH_DISABLE_SECURE_IRQS BIT_U32(7)
> +
> +#define ARM_DRTM_SUCCESS		0
> +#define ARM_DRTM_NOT_SUPPORTED		-1
> +#define ARM_DRTM_INVALID_PARAMETERS	-2
> +#define ARM_DRTM_DENIED			-3
> +#define ARM_DRTM_NOT_FOUND		-4
> +#define ARM_DRTM_INTERNAL_ERROR		-5
> +#define ARM_DRTM_MEM_PROTECT_INVALID	-6

Hmm. the spec I pulled from arm.com has COPROCESSOR_ERROR for -7. Maybe
include it?

> +#define ARM_DRTM_OUT_OF_RESOURCES	-8
> +#define ARM_DRTM_INVALID_DATA		-9
> +#define ARM_DRTM_SECONDARY_PE_NOT_OFF	-10
> +#define ARM_DRTM_ALREADY_CLOSED		-11
> +#define ARM_DRTM_TPM_ERROR		-12
> +
> +/* Algorthim IDs are defined by TCG, in the kernel they are TPM_ALG_* */
> +
> +#define ARM_DRTM_PARAMETERS_REVISION	2
> +
> +#ifndef __ASSEMBLY__
> +
> +#include <linux/bitfield.h>
> +#include <linux/build_bug.h>
> +#include <linux/stddef.h>
> +#include <linux/types.h>

> +
> +static inline s64 arm_drtm_features(u64 function_or_feature, u64 *value)
> +{
> +	struct arm_smccc_res res;
> +	s64 status;
> +
> +	arm_smccc_1_1_smc(ARM_DRTM_SMC_FEATURES, function_or_feature,
> +			  0, 0, 0, 0, 0, 0, &res);
> +	status = res.a0;
> +	if (status >= 0 && value)
> +		*value = res.a1;
If status == 0, is res.a1 useful?
You have a helpful comment at the call site in the final patch but none
the less I have read the spec section a couple of times and have no idea.

> +	return status;
> +}

Thanks,

Jonathan




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

* Re: [PATCH 03/16] efi/libstub: Free cmdline_ptr in efi_pe_entry
  2026-09-24 22:49   ` Jonathan Cameron
@ 2026-09-25 12:59     ` Jason Gunthorpe
  2026-09-25 13:20       ` Ard Biesheuvel
  0 siblings, 1 reply; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-25 12:59 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon,
	Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

On Thu, Sep 24, 2026 at 03:49:02PM -0700, Jonathan Cameron wrote:
> On Thu, 24 Sep 2026 10:53:06 -0300
> Jason Gunthorpe <jgg@nvidia.com> wrote:
> 
> > Sashiko points out that efi_handle_cmdline() allocates this memory and
> > hands it over to the caller. If efi_pe_entry() ever returns it should be
> > freed. Add a __free annotation.
> > 
> > Fixes: 42c8ea3dca09 ("efi: libstub: Factor out EFI stub entrypoint into separate file")
> > Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
> > ---
> >  drivers/firmware/efi/libstub/efi-stub-entry.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
> > index aa85e910fe595e..83fade2b0d3b84 100644
> > --- a/drivers/firmware/efi/libstub/efi-stub-entry.c
> > +++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
> > @@ -40,7 +40,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
> >  	unsigned long image_addr;
> >  	unsigned long image_size = 0;
> >  	/* addr/point and size pairs for memory management*/
> > -	char *cmdline_ptr = NULL;
> > +	char *cmdline_ptr __free(efi_pool) = NULL;
> 
> Can we move this down to just above the call to efi_handle_cmdline that
> does the constructor side of this?
> 
> I see none of the efi stuff follow those guidance note that went in
> cleanup.h.

Yeah, I stuck with what was there.. It looks kind of weird that way:

	char *cmdline_ptr __free(efi_pool) = NULL;
	status = efi_handle_cmdline(image, &cmdline_ptr);
	if (status != EFI_SUCCESS)
		return status;

Jason


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

* Re: [PATCH 03/16] efi/libstub: Free cmdline_ptr in efi_pe_entry
  2026-09-25 12:59     ` Jason Gunthorpe
@ 2026-09-25 13:20       ` Ard Biesheuvel
  0 siblings, 0 replies; 31+ messages in thread
From: Ard Biesheuvel @ 2026-09-25 13:20 UTC (permalink / raw)
  To: Jason Gunthorpe, Jonathan Cameron
  Cc: Alexandre Ghiti, Albert Ou, Arnd Bergmann, Catalin Marinas,
	Jonathan Corbet, David Sterba, Ilias Apalodimas, linux-arch,
	linux-arm-kernel, linux-doc, linux-efi, linux-riscv, Mark Rutland,
	Palmer Dabbelt, Paul Walmsley, Randy Dunlap, Simon Glass,
	Shuah Khan, Nick Terrell, Will Deacon, Alexandre Ghiti,
	Conor Dooley, linux-integrity, Palmer Dabbelt, patches,
	Ross Philipson, Sami Tolvanen, Song Shuai



On Fri, 25 Sep 2026, at 14:59, Jason Gunthorpe wrote:
> On Thu, Sep 24, 2026 at 03:49:02PM -0700, Jonathan Cameron wrote:
>> On Thu, 24 Sep 2026 10:53:06 -0300
>> Jason Gunthorpe <jgg@nvidia.com> wrote:
>> 
>> > Sashiko points out that efi_handle_cmdline() allocates this memory and
>> > hands it over to the caller. If efi_pe_entry() ever returns it should be
>> > freed. Add a __free annotation.
>> > 
>> > Fixes: 42c8ea3dca09 ("efi: libstub: Factor out EFI stub entrypoint into separate file")
>> > Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
>> > ---
>> >  drivers/firmware/efi/libstub/efi-stub-entry.c | 2 +-
>> >  1 file changed, 1 insertion(+), 1 deletion(-)
>> > 
>> > diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
>> > index aa85e910fe595e..83fade2b0d3b84 100644
>> > --- a/drivers/firmware/efi/libstub/efi-stub-entry.c
>> > +++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
>> > @@ -40,7 +40,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
>> >  	unsigned long image_addr;
>> >  	unsigned long image_size = 0;
>> >  	/* addr/point and size pairs for memory management*/
>> > -	char *cmdline_ptr = NULL;
>> > +	char *cmdline_ptr __free(efi_pool) = NULL;
>> 
>> Can we move this down to just above the call to efi_handle_cmdline that
>> does the constructor side of this?
>> 
>> I see none of the efi stuff follow those guidance note that went in
>> cleanup.h.
>

My bad. Patches welcome.


> Yeah, I stuck with what was there.. It looks kind of weird that way:
>
> 	char *cmdline_ptr __free(efi_pool) = NULL;
> 	status = efi_handle_cmdline(image, &cmdline_ptr);
> 	if (status != EFI_SUCCESS)
> 		return status;
>

That looks fine, no?


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

* Re: [PATCH 04/16] vmlinux.lds: Move DATA_LE32() from arm64 to the common linker script
  2026-09-24 23:50     ` Jason Gunthorpe
@ 2026-09-25 13:30       ` Ard Biesheuvel
  0 siblings, 0 replies; 31+ messages in thread
From: Ard Biesheuvel @ 2026-09-25 13:30 UTC (permalink / raw)
  To: Jason Gunthorpe, Jonathan Cameron
  Cc: Alexandre Ghiti, Albert Ou, Arnd Bergmann, Catalin Marinas,
	Jonathan Corbet, David Sterba, Ilias Apalodimas, linux-arch,
	linux-arm-kernel, linux-doc, linux-efi, linux-riscv, Mark Rutland,
	Palmer Dabbelt, Paul Walmsley, Randy Dunlap, Simon Glass,
	Shuah Khan, Nick Terrell, Will Deacon, Alexandre Ghiti,
	Conor Dooley, linux-integrity, Palmer Dabbelt, patches,
	Ross Philipson, Sami Tolvanen, Song Shuai



On Fri, 25 Sep 2026, at 01:50, Jason Gunthorpe wrote:
> On Thu, Sep 24, 2026 at 03:53:07PM -0700, Jonathan Cameron wrote:
>> On Thu, 24 Sep 2026 10:53:07 -0300
>> Jason Gunthorpe <jgg@nvidia.com> wrote:
>> 
>> > Other arches may want to use this to get consistent fixed endian output.
>> 
>> You will have to grab it quickly!
>> https://lore.kernel.org/all/20260918145217.1669-10-will@kernel.org/#Z31arch:arm64:kernel:image.h
>> drops that definition as part of ripping out arm64 big endian support.
>
> Ah, well easy conflict resolution then :)
>
> When I was doing this I was really doubting why it had to be endian
> specific, this is mostly a cargo cult from the other stuff that was
> already working that way..
>
> I'm personally skeptical any arch could have either EFI stub a
> different endianess than the vmlinux, it seems like nonsense on alot
> of levels.
>
> So, I will remove the fixed endian pieces from here? Does anyone think
> otherwise?
>

Booting a BE kernel from EFI has never worked so no need to start caring
about it now.



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

* Re: [PATCH 16/16] efi/arm64: Implement ARM64 DRTM in the stub
  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
  0 siblings, 1 reply; 31+ messages in thread
From: Jonathan Cameron @ 2026-09-25 18:37 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon,
	Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

On Thu, 24 Sep 2026 10:53:19 -0300
Jason Gunthorpe <jgg@nvidia.com> wrote:

> Provide an implementation of the CONFIG_EFI_STUB_DRTM protocol for ARM64
> DEN0113 >= v1.1.
> 
> First, it queries the FW for support and collects all the
> information. This is needed to compute the extra_size, which comes
> from FW reporting how much memory it needs during the launch for the
> DLME Data and DCE-owned data. The generic stub ensures there is
> trailing memory after Image for this.
> 
> Then the DRTM_PARAMETERS launch structure is computed using the
> offsets in the efi_info.
> 
> Finally, the stub does ExitBootServices and calls the actual launch.
ARM_DRTM_FEATURE_DMA_PROTECTION> 
> The feature discovery process is deliberately fairly verbose to help
> debug any FW weirdness in the field. Enable it with efi=debug
> 
> It looks something like:
> 
>  EFI stub: DRTM: interface version 1.4
>  EFI stub: DEBUG: DRTM: TPM algorithm 0xc, TPM hashing unavailable, PCR schemas 0x1
>  EFI stub: DEBUG: DRTM: minimum DLME data 73728 bytes, Normal-world DCE 0 bytes
>  EFI stub: Decompressing Linux Kernel...
>  EFI stub: Generating empty DTB
>  EFI stub: Exiting boot services...
>  EFI stub: DEBUG: DRTM: will launch, selected launch features 0x0
>  [    0.000000] Booting Linux on physical CPU 0x0000000000 [0x000f0510]
> 
> Eventually the launch'd kernel is going to require built in crypto
> libraries that match what the FW is using so it can validate some of the
> information left behind during early boot. Refuse to launch if these are
> not built in and build in the most common ones from the ARM64_DRTM
> kconfig.
> 
> One nit, if the platform does not support SMC then using drtm=auto may
> crash on the SMC op. As far as I can tell there is no way to discover SMC
> support through EFI. Learning it from the ACPI FADT is doable and costs
> about 250 lines of code.
> 
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
First read though only found some superficial stuff.

Generally looks fine to me.

Jonathan

> diff --git a/drivers/firmware/efi/libstub/arm64-drtm.c b/drivers/firmware/efi/libstub/arm64-drtm.c
> new file mode 100644
> index 00000000000000..12ddf7c2dd056a
> --- /dev/null
> +++ b/drivers/firmware/efi/libstub/arm64-drtm.c



> +
> +static bool efi_drtm_probe_memory(void)
> +{
> +	u64 value;
> +
> +	if (!efi_drtm_query_feature(ARM_DRTM_FEATURE_MIN_MEMORY, &value))
> +		return false;
> +
> +	drtm_cfg.dlme_data_size =
> +		FIELD_GET(ARM_DRTM_DLME_DATA_PAGES_MASK, value) *

> +		ARM_DRTM_PAGE_SIZE;
> +	drtm_cfg.nw_dce_size = FIELD_GET(ARM_DRTM_NW_DCE_PAGES_MASK, value) *
> +			       ARM_DRTM_PAGE_SIZE;
> +
> +	efi_debug(
> +		"DRTM: minimum DLME data %lu bytes, Normal-world DCE %lu bytes\n",

That code formatter loves the silly.  This is definitely not more readable
than a slightly longer line!
I'm reading upwards and got bored now - will assume you'll take a look and tidy
up other such silliness.


> +		drtm_cfg.dlme_data_size, drtm_cfg.nw_dce_size);
> +	return true;
> +}

> +
> +static void efi_drtm_report_previous_error(void)
> +{
> +	s64 error_code;
> +	s64 status;
> +
> +	status = arm_drtm_features(ARM_DRTM_SMC_GET_ERROR, NULL);
> +	if (status != ARM_DRTM_SUCCESS) {
> +		efi_debug("DRTM: GET_ERROR is unavailable (x0=%lld)\n", status);
> +		return;
> +	}
> +
> +	status = arm_drtm_get_error(&error_code);
> +	if (status != ARM_DRTM_SUCCESS) {
> +		efi_warn("DRTM: failed to read previous error (x0=%lld)\n",
> +			 status);
> +		return;
> +	}
> +
> +	if (error_code) {
> +		efi_warn(
> +			"DRTM: firmware reports previous launch error 0x%llx\n",

That code formatter is being silly again.

> +			error_code);
> +		if (efi_drtm_policy != EFI_DRTM_ENFORCE)
> +			efi_drtm_policy = EFI_DRTM_OFF;
> +	}
> +}

> +
> +efi_status_t efi_drtm_prepare(void)
> +{
> +	s64 feature_status;
> +	u16 major, minor;
> +	s32 status;
> +
> +	if (efi_drtm_policy == EFI_DRTM_OFF)
> +		return EFI_SUCCESS;
> +
> +	if (!efi_arm64_psci_smccc_compatible())
> +		return efi_drtm_failure();
> +
> +	/* VERSION must be the first DRTM call. */

Words like 'must' should be backed by a specific spec reference.
I couldn't immediately fine one other than common sense suggesting it should
be called to check we have a version we understand ho to talk to.

> +	status = arm_drtm_version(&major, &minor);
> +	if (status != ARM_DRTM_SUCCESS) {
> +		efi_err("DRTM: failed to read interface version (x0=%d)\n",
> +			status);
> +		return efi_drtm_failure();
> +	}
> +	if (major != ARM_DRTM_VERSION_MAJOR ||
> +	    minor < ARM_DRTM_VERSION_MIN_MINOR) {
> +		efi_err("DRTM: unsupported interface version %u.%u\n", major,
> +			minor);
> +		return efi_drtm_failure();
> +	}
> +	efi_info("DRTM: interface version %u.%u\n", major, minor);
> +
> +	efi_drtm_report_previous_error();
> +	if (efi_drtm_policy == EFI_DRTM_OFF)
> +		return EFI_SUCCESS;
> +
> +	feature_status = arm_drtm_features(ARM_DRTM_SMC_DYNAMIC_LAUNCH, NULL);
> +	if (feature_status != ARM_DRTM_SUCCESS) {
> +		efi_err("DRTM: dynamic launch is unavailable (x0=%lld)\n",
> +			feature_status);
> +		return efi_drtm_failure();
> +	}
> +
> +	if (!efi_drtm_probe_tpm() || !efi_drtm_probe_memory() ||
> +	    !efi_drtm_probe_dma() || !efi_drtm_probe_boot_pe())
> +		return efi_drtm_failure();
> +
> +	drtm_cfg.launch_features =
> +		ARM_DRTM_LAUNCH_HASH_FIRMWARE | ARM_DRTM_LAUNCH_PCR_DEFAULT |
> +		ARM_DRTM_LAUNCH_DMA_COMPLETE | ARM_DRTM_LAUNCH_NO_AUTH |
> +		ARM_DRTM_LAUNCH_KEEP_SECURE_IRQS;
> +
> +	return EFI_SUCCESS;
> +}
> +
> +unsigned long efi_drtm_get_extra_size(void)
> +{
> +	/*
> +	 * DEN0113 Table 6, feature 0x2 reports both minimum sizes in 4 KiB
> +	 * pages.  The linker places the DLME data at the 4 KiB-aligned end of
> +	 * the static Image as required by R314030.  The DLME region must
> +	 * include all of that data (R45200), and an optional Normal-world DCE
> +	 * follows it at another 4 KiB-aligned address as required by R312080.
> +	 * A final page holds the 4 KiB-aligned DRTM_PARAMETERS required by
> +	 * R312010.  Only the first area is part of the DLME region.
> +	 */
> +	if (efi_drtm_policy == EFI_DRTM_OFF)
> +		return 0;
> +	return drtm_cfg.dlme_data_size + drtm_cfg.nw_dce_size +
> +	       ARM_DRTM_PAGE_SIZE;
> +}
> +
> +efi_status_t efi_drtm_prepare_launch(unsigned long image_base,
> +				     unsigned long fdt_addr)
> +{
> +	const struct arm64_image_header *header = (const void *)image_base;
> +	const struct efi_image_info *info = efi_get_image_info(image_base);
> +	struct arm64_drtm_handoff *handoff =
> +		efi_get_image_symbol(image_base, arm64_drtm_handoff);
> +	struct arm_drtm_parameters *params;
> +	unsigned long measured_offset;
> +	unsigned long measured_size;
> +	unsigned long image_size;
> +	unsigned long dlme_start;
> +	unsigned long dlme_end;
> +	unsigned long dce_end;
> +	unsigned long entry;
> +
> +	if (efi_drtm_policy == EFI_DRTM_OFF)
> +		return EFI_SUCCESS;
> +
> +	image_size = le64_to_cpu(header->image_size);
> +	measured_offset = le64_to_cpu(info->drtm_measured_start);
> +	measured_size = le64_to_cpu(info->dlme_measured_size);
> +	entry = le64_to_cpu(info->drtm_entry);
> +	dlme_start = image_base + image_size;
> +	dlme_end = dlme_start + drtm_cfg.dlme_data_size;
> +	dce_end = dlme_end + drtm_cfg.nw_dce_size;
> +
> +	/* Quick checks something didn't go wrong during image construction */
> +	if (entry < measured_offset ||
> +	    entry - measured_offset >= measured_size ||
> +	    !IS_ALIGNED(image_base, ARM_DRTM_PAGE_SIZE) ||
> +	    !IS_ALIGNED(image_size, ARM_DRTM_PAGE_SIZE) ||
> +	    !IS_ALIGNED(measured_offset, ARM_DRTM_PAGE_SIZE) ||
> +	    !IS_ALIGNED(dlme_start, ARM_DRTM_PAGE_SIZE) ||
> +	    !IS_ALIGNED(dlme_end, ARM_DRTM_PAGE_SIZE) ||
> +	    !IS_ALIGNED(dce_end, ARM_DRTM_PAGE_SIZE)) {
> +		efi_err("DRTM: final Image layout is invalid\n");
> +		return efi_drtm_failure();
> +	}
> +
> +	/*
> +	 * See arch/arm64/kernel/vmlinux.lds.S for the DRTM Memory layout. After
> +	 * the DLME we choose to place the Normal World DCE region followed by
> +	 * the aligned DRTM_PARAMETERS structure.
> +	 */
> +	memset((void *)dlme_start, 0, efi_drtm_get_extra_size());

Is that efi_drtm_get_extra_size() adding much?  It is a little irritating to
have to go look in there to figure out that this memset actually covers
the params. If you were to just have the sum visible here that would be
more obvious and align with the comment immediately above the memset.

Maybe it is worth keeping for the big comment in there, but it does
feel like that and what we have here could be combined.

> +	params = (void *)dce_end;
> +	params->revision = cpu_to_le16(ARM_DRTM_PARAMETERS_REVISION);
> +	params->launch_features = cpu_to_le32(drtm_cfg.launch_features);
> +	params->dlme_region_address = cpu_to_le64(image_base);
> +	params->dlme_region_size = cpu_to_le64(dlme_end - image_base);
> +	params->dlme_image_start = cpu_to_le64(measured_offset);
> +	params->dlme_entry_point_offset = cpu_to_le64(entry - measured_offset);
> +	params->dlme_image_size = cpu_to_le64(measured_size);
> +	params->dlme_data_offset = cpu_to_le64(image_size);
> +	if (drtm_cfg.nw_dce_size) {
> +		params->nw_dce_region_address = cpu_to_le64(dlme_end);
> +		params->nw_dce_region_size = cpu_to_le64(drtm_cfg.nw_dce_size);
> +	}
> +
> +	/*
> +	 * The DLME Data contains its own size in a trusted header, so the
> +	 * handoff doesn't need to include extra_size. The DCE Data is only
> +	 * temporary so the kernel also does not need to know about it.
> +	*/
> +	handoff->fdt_addr = cpu_to_le64(fdt_addr);
> +	handoff->drtm_enabled = 1;
> +
> +	efi_debug("DRTM: will launch, selected launch features 0x%x\n",
> +		  drtm_cfg.launch_features);
> +
> +	drtm_cfg.params_addr = params;
> +	return EFI_SUCCESS;
> +}
> +
> +static void efi_drtm_fallback(void)
> +{
> +	struct arm_drtm_parameters *params = drtm_cfg.params_addr;
> +	unsigned long image_base = le64_to_cpu(params->dlme_region_address);
> +	struct arm64_drtm_handoff *handoff =
> +		efi_get_image_symbol(image_base, arm64_drtm_handoff);
> +
> +	handoff->drtm_enabled = 0;
> +}
> +
> +void efi_drtm_launch(void)
> +{
> +

I love trivial. Pointless blank line.

> +	if (efi_drtm_policy == EFI_DRTM_OFF)
> +		return;
> +
> +	/*
> +	 * No cache maintenance is required before the launch. DEN0113 R42130
> +	 * requires the DRTM_PARAMETERS to be accessible as Normal Write-Back
> +	 * Cacheable, Inner Shareable memory, so the DCE reads them coherently
> +	 * with the writes made above.  R45220 then has the DCE clean and
> +	 * invalidate the whole DLME region to the Point of Coherency before it
> +	 * measures the DLME image, which covers both the Image itself and the
> +	 * handoff struct placed in the DLME region. Thus once we jump into the
> +	 * kernel with MMU and caches off the CPU will see everything the stub
> +	 * wrote.
> +	 */
> +	arm_drtm_dynamic_launch(drtm_cfg.params_addr);
> +
> +	/*
> +	 * DEN0113 section 3.4 returns from DYNAMIC_LAUNCH only on error. Boot

I'd use a spec version for references + ideally title of section.
As much as folk may try, sometimes these things move around.

Also tweak the wording.  Failure sure the section doesn't return from anything :)

> +	 * services and their diagnostics are no longer available, so hang.
> +	 */
> +	if (efi_drtm_policy == EFI_DRTM_ENFORCE) {
> +		for (;;)
> +			asm volatile("wfe");
> +	}
> +
> +	efi_drtm_fallback();
> +}



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

* Re: [PATCH 12/16] arm64: drtm: Add macro definitions for DEN0113
  2026-09-25  0:29   ` Jonathan Cameron
@ 2026-09-26 18:27     ` Jason Gunthorpe
  0 siblings, 0 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-26 18:27 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon,
	Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai,
	Suzuki K Poulose

On Thu, Sep 24, 2026 at 05:29:52PM -0700, Jonathan Cameron wrote:
> This one at least does it via base and sum.  But that then separates it from
> the spec?   That is sort of the case anyway because the spec has the full
> number.  0xC400_0110 so I guess not too bad.

I wasn't sure what to do with this since the spec had the full hex and
we have these helper macros.. I made it look more like something else
with the offset style instead of the function call style:

> > +#define ARM_DRTM_SMC_VERSION			(ARM_DRTM_SMC_FN_BASE + 0x00)

IDK, maybe ARM_DRTM_SMC_FN_BASE(0x110) is more connected to the spec,
but I'm used to doing it like this from ioctl land which is very
similar.


> > +#define ARM_DRTM_FEATURE_SELECTOR	BIT_U64(63)
> > +#define ARM_DRTM_FEATURE_TPM		0x01
> > +#define ARM_DRTM_FEATURE_MIN_MEMORY	0x02
> > +#define ARM_DRTM_FEATURE_DMA_PROTECTION	0x03
> > +#define ARM_DRTM_FEATURE_BOOT_PE	0x04
> > +#define ARM_DRTM_FEATURE_TCB_HASH	0x05
> > +#define ARM_DRTM_FEATURE_IMAGE_AUTH	0x06
>
> Nice to have a mask for the 8 bits of the feature field.

OK

> Also nice to keep order the same as the SMC defines which would put this after
> version.  That also puts it next to the values returned for each feature.

I reorganized everything

> > +#define ARM_DRTM_TPM_ALG_MASK		GENMASK_U64(15, 0)
> > +#define ARM_DRTM_TPM_HASHING		BIT_U64(32)
> > +#define ARM_DRTM_PCR_SCHEMA_MASK	GENMASK_U64(36, 33)
> > +#define ARM_DRTM_PCR_SCHEMA_DEFAULT	BIT_U64(33)
> > +#define ARM_DRTM_PCR_SCHEMA_AUTHORITIES	BIT_U64(34)
> 
> Ah.  Always love a field made up of a bunch of bits. Hard to define
> cleanly.   Do you actually need the PCR_SCHEMA_MASK?  

I did it with a field content which gets reused in the launch struct:

/*
 * PCR schema numbers. ARM_DRTM_PCR_SCHEMA_MASK is a bitmap indexed by these,
 * and the Launch Features ARM_DRTM_LAUNCH_PCR_SCHEMA_MASK field holds one.
 */
#define ARM_DRTM_PCR_SCHEMA_DEFAULT		0
#define ARM_DRTM_PCR_SCHEMA_AUTHORITIES		1

/*
 * DMA protection types. ARM_DRTM_DMA_PROTECTION_MASK is a bitmap indexed by
 * these, and the Launch Features ARM_DRTM_LAUNCH_DMA_PROTECTION_MASK field
 * holds one.
 */
#define ARM_DRTM_DMA_PROTECTION_COMPLETE	0
#define ARM_DRTM_DMA_PROTECTION_REGION		1

Have to use BIT() to get the bitmap encoding.

> Same here.  I vaguely wonder if it is worth adding something
> reflecting the relevant feature ID to each of these defines
> so we know what the are referring to?

I added comments and spec references for everything

> > +#define ARM_DRTM_LAUNCH_HASH_FIRMWARE	0
> > +#define ARM_DRTM_LAUNCH_HASH_TPM	BIT_U32(0)
> 
> I'd rather see them as fields and field value pairs but
> can see that is going to get a bit verbose.

I think that would be too verbose in this case, and the usage is very
limited.


> > +static inline s64 arm_drtm_features(u64 function_or_feature, u64 *value)
> > +{
> > +	struct arm_smccc_res res;
> > +	s64 status;
> > +
> > +	arm_smccc_1_1_smc(ARM_DRTM_SMC_FEATURES, function_or_feature,
> > +			  0, 0, 0, 0, 0, 0, &res);
> > +	status = res.a0;
> > +	if (status >= 0 && value)
> > +		*value = res.a1;
> If status == 0, is res.a1 useful?
> You have a helpful comment at the call site in the final patch but none
> the less I have read the spec section a couple of times and have no idea.

I read the spec as 0 is not allowed.

I changed this around to have two wrapper functions, which works a bit
better.

static inline s64 arm_drtm_query_function(u64 function_id)
{
	struct arm_smccc_res res;

	arm_smccc_1_1_smc(ARM_DRTM_SMC_FEATURES, function_id, 0, 0, 0, 0, 0, 0,
			  &res);
	return res.a0;
}

/*
 * v1.4b Section 3.3.1 says:
 *   A return value of greater than 0 means the feature ID is
 *   implemented, and there are other feature-specific
 *   feature or capability bits available in other return value
 *   registers.
 * And for FEATURE_SELECTOR all defined features return data in other
 * registers, so 0 is not an allowed return.
 */
static inline s64 arm_drtm_query_feature(u64 feature, u64 *value)
{
	struct arm_smccc_res res;

	arm_smccc_1_1_smc(ARM_DRTM_SMC_FEATURES,
			  ARM_DRTM_FEATURE_SELECTOR |
				  FIELD_PREP(ARM_DRTM_FEATURE_ID_MASK, feature),
			  0, 0, 0, 0, 0, 0, &res);
	*value = res.a1;
	return res.a0;
}

Thanks,
Jason


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

* Re: [PATCH 16/16] efi/arm64: Implement ARM64 DRTM in the stub
  2026-09-25 18:37   ` Jonathan Cameron
@ 2026-09-26 18:45     ` Jason Gunthorpe
  0 siblings, 0 replies; 31+ messages in thread
From: Jason Gunthorpe @ 2026-09-26 18:45 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Alexandre Ghiti, Albert Ou, Ard Biesheuvel, Arnd Bergmann,
	Catalin Marinas, Jonathan Corbet, David Sterba, Ilias Apalodimas,
	linux-arch, linux-arm-kernel, linux-doc, linux-efi, linux-riscv,
	Mark Rutland, Palmer Dabbelt, Paul Walmsley, Randy Dunlap,
	Simon Glass, Shuah Khan, Nick Terrell, Will Deacon,
	Alexandre Ghiti, Conor Dooley, linux-integrity, Palmer Dabbelt,
	patches, Ross Philipson, Sami Tolvanen, Song Shuai

On Fri, Sep 25, 2026 at 11:37:09AM -0700, Jonathan Cameron wrote:
> > +efi_status_t efi_drtm_prepare(void)
> > +{
> > +	s64 feature_status;
> > +	u16 major, minor;
> > +	s32 status;
> > +
> > +	if (efi_drtm_policy == EFI_DRTM_OFF)
> > +		return EFI_SUCCESS;
> > +
> > +	if (!efi_arm64_psci_smccc_compatible())
> > +		return efi_drtm_failure();
> > +
> > +	/* VERSION must be the first DRTM call. */
> 
> Words like 'must' should be backed by a specific spec reference.
> I couldn't immediately fine one other than common sense suggesting it should
> be called to check we have a version we understand ho to talk to.

	/*
	 * v1.4B section 3.2.1 "DRTM_VERSION usage" explains that a new major
	 * ABI version may "Change behavior of existing functions". Verify the
	 * major version before calling anything so we don't trigger unknown
	 * behavior.
	 */
	status = arm_drtm_version(&major, &minor); 

> > +	/*
> > +	 * See arch/arm64/kernel/vmlinux.lds.S for the DRTM Memory layout. After
> > +	 * the DLME we choose to place the Normal World DCE region followed by
> > +	 * the aligned DRTM_PARAMETERS structure.
> > +	 */
> > +	memset((void *)dlme_start, 0, efi_drtm_get_extra_size());
> 
> Is that efi_drtm_get_extra_size() adding much? 

Yeah, it is the one place we compute the extra amount that was
allocated. How about:

	/*
	 * For robustness zero all the trailing space at the end of the
	 * alocation. This contains the DRTM_PARAMETERS structure too, so
	 * must be done before filling it.
	 */
	memset((void *)dlme_start, 0, efi_drtm_get_extra_size());


> Maybe it is worth keeping for the big comment in there, but it does
> feel like that and what we have here could be combined.

efi_drtm_get_extra_size() is called by the generic EFI code, I can't
remove it.

> > +	/*
> > +	 * DEN0113 section 3.4 returns from DYNAMIC_LAUNCH only on error. Boot
> 
> I'd use a spec version for references + ideally title of section.
> As much as folk may try, sometimes these things move around.

I tightened all of this

Thanks,
Jason


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

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

Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH 05/16] efi/libstub: Add a general way to get symbols from the vmlinux into zboot Jason Gunthorpe
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

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