Hi Michael,

This looks ok now. I am thinking if we should also remove the tpm_auto_start() 
from
efi_tcg2.c now and select the new Kconfig option. It might be a bit problematic,
since the tpm_auto_start() from EFI onlyruns when you initialize the subsystem.
That subsystem only comes to life when we ask something out of EFI, i.e
read a variable or boot an image etc. So in theory you can have a combination 
where EFI
is compiled in, but TPM_AUTOSTART isn't and you only enable the TPM when 
booting via EFI.
If we select that symbol we initialize it regardless.

Thanks
/Ilias


On Tue Oct 6, 2026 at 6:52 PM EEST, Michael Haener wrote:
> Add CONFIG_TPM_AUTOSTART, which runs the TPM startup and self-test
> sequence from an EVT_LAST_STAGE_INIT handler. This is the same thing the
> 'tpm autostart' command does, but it does not depend on a boot script or
> on the environment.
>
> Today a TPM is only started automatically when either CONFIG_MEASURED_BOOT
> is used (and then only from bootm) or when booting via EFI with
> CONFIG_EFI_TCG2_PROTOCOL. A plain booti/bootm therefore leaves the chip
> uninitialised and the OS has to start it itself, which Linux reports as
> "A TPM error (256) occurred attempting the self test". Boards have worked
> around this by putting 'tpm autostart' into their environment, see
> board/xilinx/zynqmp/zynqmp_kria.env.
>
> The startup is done from an event rather than in the uclass probe:
> nothing probes the TPM on a plain booti/bootm, and the event runs exactly
> once in U-Boot proper without changing what probing a TPM means for the
> existing callers.
>
> Boards that share one binary between variants with and without a TPM
> fitted can enable this safely: when no TPM device is found the startup is
> skipped silently. Other errors are reported as warnings but do not stop
> the boot. Note that the full self-test adds to the boot time.
>
> Signed-off-by: Michael Haener <[email protected]>
> ---
> Changes in v3:
> - Split the tests and the Kria conversion into separate patches
>
> Changes in v2:
> - Move the code to lib/tpm_autostart.c and the option to lib/Kconfig
> - Stay silent only when no TPM device exists (-ENODEV), warn otherwise
> - Use u32 and %#x for the tpm_auto_start() result
> - Mention the boot-time cost of the self-test in the help text
> - Document the option in doc/usage/measured_boot.rst
> - Explain in the commit message why an event is used instead of probe
>
>  doc/usage/measured_boot.rst | 18 ++++++++++++++++++
>  lib/Kconfig                 | 19 +++++++++++++++++++
>  lib/Makefile                |  1 +
>  lib/tpm_autostart.c         | 37 +++++++++++++++++++++++++++++++++++++
>  4 files changed, 75 insertions(+)
>  create mode 100644 lib/tpm_autostart.c
>
> diff --git a/doc/usage/measured_boot.rst b/doc/usage/measured_boot.rst
> index 488dd546f13..d74cfab2594 100644
> --- a/doc/usage/measured_boot.rst
> +++ b/doc/usage/measured_boot.rst
> @@ -55,3 +55,21 @@ Requirements
>  * The operating system must also be configured to use the memory regions
>    specified in the U-Boot device-tree in order to make use of the event
>    log.
> +
> +Starting the TPM without measured boot
> +--------------------------------------
> +
> +Measured boot starts the TPM as a side effect, but only on the boot paths
> +listed above. A plain booti/bootm without CONFIG_MEASURED_BOOT, or a boot
> +which does not go through the EFI subsystem, leaves the chip uninitialised
> +and the operating system has to start it itself. Some kernels report this as
> +an error.
> +
> +CONFIG_TPM_AUTOSTART runs the same startup and self-test sequence as the
> +'tpm autostart' command from an EVT_LAST_STAGE_INIT handler, independently of
> +the boot path, the environment and any boot script. When no TPM device is
> +found the startup is skipped, so a board which shares one binary between
> +variants with and without a TPM fitted can enable it safely.
> +
> +Note that a full self-test can take a noticeable amount of time on a TPMv2,
> +which is added to every boot even when the TPM is not used afterwards.
> diff --git a/lib/Kconfig b/lib/Kconfig
> index ff7655e1496..33ae8037479 100644
> --- a/lib/Kconfig
> +++ b/lib/Kconfig
> @@ -565,6 +565,25 @@ config TPM
>         If you want a fully functional TPM enable all hashing algorithms.
>         If you enabled measured boot all hashing algorithms are selected.
>
> +config TPM_AUTOSTART
> +     bool "Start the TPM during board initialisation"
> +     depends on TPM
> +     select EVENT
> +     help
> +       Run the TPM startup and self-test sequence from an EVT_LAST_STAGE_INIT
> +       handler, which is the same thing the 'tpm autostart' command does.
> +       Without this the chip is still uninitialised when the OS takes over
> +       and the OS has to start it itself, which some kernels report as an
> +       error.
> +
> +       Boards that share one binary between variants with and without a TPM
> +       fitted can enable this safely: when no TPM device is found the
> +       startup is skipped silently.
> +
> +       Note that a full self-test can take a noticeable amount of time on
> +       a TPMv2, so this adds to the boot time of every boot, even when the
> +       TPM is not used afterwards.
> +
>  config SPL_TPM
>       bool "Trusted Platform Module (TPM) Support in SPL"
>       depends on SPL_DM
> diff --git a/lib/Makefile b/lib/Makefile
> index 93a389b10e4..b31861fe4b5 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -59,6 +59,7 @@ obj-$(CONFIG_$(PHASE_)OF_LIVE) += of_live.o
>  obj-$(CONFIG_$(PHASE_)TPM) += tpm-common.o
>  ifeq ($(CONFIG_$(PHASE_)TPM),y)
>  obj-$(CONFIG_TPM) += tpm_api.o
> +obj-$(CONFIG_TPM_AUTOSTART) += tpm_autostart.o
>  obj-$(CONFIG_TPM_V1) += tpm-v1.o
>  obj-$(CONFIG_TPM_V2) += tpm-v2.o
>  obj-$(CONFIG_EFI_TCG2_PROTOCOL) += tpm_tcg2.o
> diff --git a/lib/tpm_autostart.c b/lib/tpm_autostart.c
> new file mode 100644
> index 00000000000..5b43b2aecbb
> --- /dev/null
> +++ b/lib/tpm_autostart.c
> @@ -0,0 +1,37 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Start the TPM during init, so that the OS does not have to do it.
> + *
> + * Copyright (c) 2026 Siemens AG
> + */
> +
> +#define LOG_CATEGORY UCLASS_TPM
> +
> +#include <dm.h>
> +#include <errno.h>
> +#include <event.h>
> +#include <log.h>
> +#include <tpm_api.h>
> +
> +static int tpm_evt_autostart(void)
> +{
> +     struct udevice *dev;
> +     int ret;
> +     u32 rc;
> +
> +     ret = uclass_first_device_err(UCLASS_TPM, &dev);
> +     if (ret) {
> +             /* a board may share one binary between variants without a TPM 
> */
> +             if (ret != -ENODEV)
> +                     log_warning("Cannot init TPM (err=%dE)\n", ret);
> +
> +             return 0;
> +     }
> +
> +     rc = tpm_auto_start(dev);
> +     if (rc)
> +             log_warning("TPM startup failed (rc=%#x)\n", rc);
> +
> +     return 0;
> +}
> +EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, tpm_evt_autostart);

Reply via email to