[PATCH v4 3/6] tpm: allocate tpm event log if missing
Ilias Apalodimas
ilias.apalodimas at linaro.org
Wed Jul 1 13:51:57 CEST 2026
Hi Ludwig,
On Mon, 29 Jun 2026 at 11:02, Ludwig Nussel <ludwig.nussel at siemens.com> wrote:
>
> With EFI U-Boot always allocates a buffer for the TPM event log. If
> a previous bootloader stage started an event log, U-Boot would copy
> the entries to that allocated buffer.
>
> Without EFI U-Boot wants to reuse the event log memory from a
> previous bootloader stage instead. If U-Boot is first component to
> start the event log, e.g. when used in qemu there would be no memory
> allocated for the event log.
>
> So allocate memory in tcg2_log_prepare_buffer() if no event log was
> found and no buffer was allocated already.
> Also copy the address of the event log into the device tree for the
> kernel so the event log is accessible from Linux userspace too.
>
> Signed-off-by: Ludwig Nussel <ludwig.nussel at siemens.com>
>
[...]
>
> boot/bootm.c | 18 +++---
> boot/image-fdt.c | 69 +++++++++++++++++++++++
> include/tpm-common.h | 2 +
> include/tpm_tcg2.h | 9 +--
> lib/Kconfig | 1 +
> lib/tpm_tcg2.c | 130 ++++++++++++++++++++++++++++++++++---------
> 6 files changed, 188 insertions(+), 41 deletions(-)
>
> diff --git a/boot/bootm.c b/boot/bootm.c
> index 4836d6b2d41..701ec010e01 100644
> --- a/boot/bootm.c
> +++ b/boot/bootm.c
> @@ -921,23 +921,19 @@ int bootm_measure(struct bootm_headers *images)
> return ret;
>
> if (IS_ENABLED(CONFIG_MEASURED_BOOT)) {
> - struct tcg2_event_log elog;
> struct udevice *dev;
> void *initrd_buf;
> void *image_buf;
> const char *s;
> u32 rd_len;
> - bool ign;
>
> - elog.log_size = 0;
> - ign = IS_ENABLED(CONFIG_MEASURE_IGNORE_LOG);
> - ret = tcg2_measurement_init(&dev, &elog, ign);
> - if (ret)
> + ret = tcg2_measurement_init(&dev, NULL);
> + if (ret && ret != -EEXIST)
> return ret;
>
> image_buf = map_sysmem(images->os.image_start,
> images->os.image_len);
> - ret = tcg2_measure_data(dev, &elog, 8, images->os.image_len,
> + ret = tcg2_measure_data(dev, NULL, 8, images->os.image_len,
> image_buf, EV_COMPACT_HASH,
> strlen("linux") + 1, (u8 *)"linux");
> if (ret)
> @@ -945,14 +941,14 @@ int bootm_measure(struct bootm_headers *images)
>
> rd_len = images->rd_end - images->rd_start;
> initrd_buf = map_sysmem(images->rd_start, rd_len);
> - ret = tcg2_measure_data(dev, &elog, 9, rd_len, initrd_buf,
> + ret = tcg2_measure_data(dev, NULL, 9, rd_len, initrd_buf,
> EV_COMPACT_HASH, strlen("initrd") + 1,
> (u8 *)"initrd");
> if (ret)
> goto unmap_initrd;
>
> if (IS_ENABLED(CONFIG_MEASURE_DEVICETREE)) {
> - ret = tcg2_measure_data(dev, &elog, 1, images->ft_len,
> + ret = tcg2_measure_data(dev, NULL, 1, images->ft_len,
> (u8 *)images->ft_addr,
> EV_TABLE_OF_DEVICES,
> strlen("dts") + 1,
> @@ -964,7 +960,7 @@ int bootm_measure(struct bootm_headers *images)
> s = env_get("bootargs");
> if (!s)
> s = "";
> - ret = tcg2_measure_data(dev, &elog, 1, strlen(s) + 1, (u8 *)s,
> + ret = tcg2_measure_data(dev, NULL, 1, strlen(s) + 1, (u8 *)s,
> EV_PLATFORM_CONFIG_FLAGS,
> strlen(s) + 1, (u8 *)s);
>
> @@ -973,7 +969,7 @@ unmap_initrd:
>
> unmap_image:
> unmap_sysmem(image_buf);
> - tcg2_measurement_term(dev, &elog, ret != 0);
> + tcg2_measurement_term(dev, NULL, ret != 0);
> }
>
> return ret;
> diff --git a/boot/image-fdt.c b/boot/image-fdt.c
> index a3a4fb8b558..478158294ed 100644
> --- a/boot/image-fdt.c
> +++ b/boot/image-fdt.c
> @@ -24,6 +24,8 @@
> #include <asm/io.h>
> #include <dm/ofnode.h>
> #include <tee/optee.h>
> +#include <tpm_tcg2.h>
> +#include <dm/device.h>
>
> DECLARE_GLOBAL_DATA_PTR;
>
> @@ -589,6 +591,68 @@ __weak int arch_fixup_fdt(void *blob)
> return 0;
> }
>
> +static int copy_tpm_event_log(void *blob)
> +{
> + int rc;
> + struct udevice *dev;
> + ofnode node;
> + char path[256];
> + int off;
> + struct tcg2_event_log *log;
> +
> + if (!IS_ENABLED(CONFIG_MEASURED_BOOT))
> + return 0;
> +
> + rc = tcg2_platform_get_tpm2(&dev);
> + if (rc)
> + return rc;
> +
> + log = tcg2_platform_get_dev_log(dev);
> +
> + if (!log || !log->allocated) {
> + log_debug("tpm event log not allocated\n");
> + return -ENOENT;
> + }
> +
> + node = dev_ofnode(dev);
> + if (!ofnode_valid(node)) {
> + log_err("tpm %p has no device tree representation\n", dev);
> + return -ENOENT;
> + }
> +
> + rc = ofnode_get_path(node, path, sizeof(path));
> + if (rc)
> + return rc;
> +
> + off = fdt_path_offset(blob, path);
> + if (off < 0) {
> + log_warning("kernel device tree lacks %s\n", path);
> + return 0;
> + }
> +
> + if (fdt_getprop(blob, off, "linux,sml-base", NULL)) {
> + log_warning("kernel dt already defines an event log address at %s\n", path);
> + return 0;
> + }
> +
> + fdt64_t base = cpu_to_fdt64((u64)virt_to_phys(log->log));
> +
> + rc = fdt_find_and_setprop(blob, path, "linux,sml-base", &base, sizeof(base), 1);
> + if (rc) {
> + log_err("failed to set sml-base: %d\n", rc);
> + return rc;
> + }
> +
> + fdt32_t size = cpu_to_fdt32((u32)log->log_size);
> +
> + rc = fdt_find_and_setprop(blob, path, "linux,sml-size", &size, sizeof(size), 1);
> + if (rc) {
> + log_err("failed to set sml-size: %d\n", rc);
> + return rc;
> + }
> + return 0;
> +}
> +
> int image_setup_libfdt(struct bootm_headers *images, void *blob, bool lmb)
> {
> ulong *initrd_start = &images->initrd_start;
> @@ -631,6 +695,11 @@ int image_setup_libfdt(struct bootm_headers *images, void *blob, bool lmb)
> goto err;
> }
>
> + fdt_ret = copy_tpm_event_log(blob);
> + if (fdt_ret && fdt_ret != -ENOENT && fdt_ret != -ENODEV) {
> + log_warning("Failed to copy TPM event log: %d\n", fdt_ret);
> + }
> +
> /* Store name of configuration node as u-boot,bootconf in /chosen node */
> if (images->fit_uname_cfg)
> fdt_find_and_setprop(blob, "/chosen", "u-boot,bootconf",
> diff --git a/include/tpm-common.h b/include/tpm-common.h
> index bfb84a931d1..3be69e7f392 100644
> --- a/include/tpm-common.h
> +++ b/include/tpm-common.h
> @@ -10,6 +10,7 @@
> #include <command.h>
>
> struct udevice;
> +struct tcg2_event_log;
>
> enum tpm_duration {
> TPM_SHORT = 0,
> @@ -83,6 +84,7 @@ struct tpm_chip_priv {
> u32 active_banks[TPM2_NUM_PCR_BANKS];
> #endif
> bool plat_hier_disabled;
> + struct tcg2_event_log *log;
> };
>
> /**
> diff --git a/include/tpm_tcg2.h b/include/tpm_tcg2.h
> index eb6afe49e77..db3f6f486e9 100644
> --- a/include/tpm_tcg2.h
> +++ b/include/tpm_tcg2.h
> @@ -162,12 +162,14 @@ struct tcg_efi_spec_id_event {
> * @log_position: Current entry position
> * @log_size: Log space available
> * @found: Boolean indicating if an existing log was discovered
> + * @allocated: Boolean indicating that the log was allocated by u-boot
> */
> struct tcg2_event_log {
> u8 *log;
> u32 log_position;
> u32 log_size;
> bool found;
> + bool allocated;
> };
>
> /**
> @@ -291,13 +293,10 @@ int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog,
> * memory region, in which case any existing log
> * discovered will be copied to the specified memory
> * region.
> - * @ignore_existing_log Boolean to indicate whether or not to ignore an
> - * existing platform log in memory
> *
> * Return: zero on success, negative errno otherwise
> */
> -int tcg2_measurement_init(struct udevice **dev, struct tcg2_event_log *elog,
> - bool ignore_existing_log);
> +int tcg2_measurement_init(struct udevice **dev, struct tcg2_event_log *elog);
>
> /**
> * Stop measurements and record separator events.
> @@ -345,4 +344,6 @@ void tcg2_platform_startup_error(struct udevice *dev, int rc);
> */
> u32 tcg2_algorithm_to_mask(enum tpm2_algorithms);
>
> +struct tcg2_event_log *tcg2_platform_get_dev_log(struct udevice *dev);
> +
> #endif /* __TPM_TCG_V2_H */
> diff --git a/lib/Kconfig b/lib/Kconfig
> index cf13ac1bdad..170621ae266 100644
> --- a/lib/Kconfig
> +++ b/lib/Kconfig
> @@ -493,6 +493,7 @@ config TPM
> bool "Trusted Platform Module (TPM) Support"
> depends on DM
> imply DM_RNG
> + imply DEVRES
> select SHA1
> help
> This enables support for TPMs which can be used to provide security
> diff --git a/lib/tpm_tcg2.c b/lib/tpm_tcg2.c
> index d41228f75a9..2270b038cf5 100644
> --- a/lib/tpm_tcg2.c
> +++ b/lib/tpm_tcg2.c
> @@ -21,6 +21,7 @@
> #include <linux/unaligned/le_byteshift.h>
> #include "tpm-utils.h"
> #include <bloblist.h>
> +#include <dm/devres.h>
>
> int tcg2_get_pcr_info(struct udevice *dev, u32 *supported_bank, u32 *active_bank,
> u32 *bank_num)
> @@ -212,6 +213,9 @@ static int tcg2_log_append_check(struct tcg2_event_log *elog, u32 pcr_index,
> u32 event_size;
> u8 *log;
>
> + if (!elog || !elog->log_size)
> + return 0;
> +
This is not needed, you always call it after setting up the eventlog.
> event_size = size + tcg2_event_get_size(digest_list);
> if (elog->log_position + event_size > elog->log_size) {
> printf("%s: log too large: %u + %u > %u\n", __func__,
> @@ -553,6 +557,9 @@ int tcg2_measure_data(struct udevice *dev, struct tcg2_event_log *elog,
> if (rc)
> return rc;
>
> + if (!elog)
> + elog = tcg2_platform_get_dev_log(dev);
> +
I still don't like this. However, I think I can live with it, because
we can just change the EFI code in the future do fill in the priv->log
and get rid of the argument overall. We can then just look at
priv->log and allocate one if it's NULL.
> return tcg2_log_append_check(elog, pcr_index, event_type, &digest_list,
> event_size, event);
> }
> @@ -560,15 +567,32 @@ int tcg2_measure_data(struct udevice *dev, struct tcg2_event_log *elog,
> int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog,
> bool ignore_existing_log)
> {
> - struct tcg2_event_log log;
> + struct tcg2_event_log log = {};
> int rc;
> u32 log_active = 0;
>
> - elog->log_position = 0;
> - elog->found = false;
> + if (elog) {
> + elog->log_position = 0;
> + elog->found = false;
> + elog->allocated = false;
> + } else if (tcg2_platform_get_dev_log(dev)) {
> + return -EEXIST;
> + }
>
> rc = tcg2_platform_get_log(dev, (void **)&log.log, &log.log_size);
We now have tcg2_platform_get_log(), tcg2_platform_get_dev_log() and
it's getting a bit confusing.
tcg2_platform_get_log() is already looking at the handover protocol,
the DT and reserved memory nodes to figure out if it needs to use one
of these or bail out.
I think it would make sense to rename tcg2_platform_get_log() to
tcg2_upsert_eventlog of tcg2_find_create_eventlog() and fold in the
memory allocation in there. Since the memory location won't change
across various bootm commands either, we won't be calling
copy_tpm_event_log() each time. And on top of that we can probably get
rid of the -EEXIST checks, since we will know that the first booted
image has also created the eventlog for us. While at it we can also
remove the __weak argument from that function. That was added back
when reading the eventlog from previous loaders wasn't well
standardized. It now is so we don't need platforms overriding that
part
[...]
Thanks
/Ilias
More information about the U-Boot
mailing list