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);
