[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