[PATCH] tpm: Add wolfTPM library support for TPM 2.0
Aidan Garske
aidan at wolfssl.com
Wed Mar 4 21:52:26 CET 2026
Hi Ilias!
I'm reviewing your feedback and need clarification on exactly what you
want. We have the cmd/wolftpm.c and cmd/tpm-v2.The C files are basically
duplicates of each other and it seems like you want to avoid maintaining 2
sets of the same functions, which is totally understandable. My question:
1. For these two files I think the best approach is to migrate
the wolftpm.c to tpm-v2.c and directly use the ifdef macros to choose
between the wolftpm or tpm2 APIs based on what was compiled in. This gives
us unified functions that should be easier to maintain than 2
separate files. If that sounds good I will make those changes; otherwise,
let me know what you are thinking.
thanks you,
Aidan
------------------------------------
Aidan Garske
Engineering Intern, wolfSSL
+1 (916) 337-1246
-------------------------------------
On Mon, Mar 2, 2026 at 11:52 PM Ilias Apalodimas <
ilias.apalodimas at linaro.org> wrote:
> Hi David,
> Aplogies for the late reply, a ew comments below.
>
> On Wed Jan 28, 2026 at 7:11 PM EET, David Garske wrote:
> > From: Aidan Garske <aidan at wolfssl.com>
> >
> > Add wolfTPM library integration to U-Boot, providing an alternative
> > TPM 2.0 implementation with native API access and enhanced features.
> >
> > wolfTPM is a portable, open-source TPM 2.0 library that provides:
> > - Native TPM 2.0 API with direct access to all TPM 2.0 commands
> > - Wrapper API for simplified common TPM operations
> > - Direct SPI communication via internal TIS layer
> > - Firmware update support for Infineon SLB9672/SLB9673 TPMs
> >
> > The standard tpm2 commands (init, startup, self_test, pcr_read,
> > pcr_extend, clear, etc.) work with any TPM 2.0 compliant module.
> > Firmware update functionality is specific to Infineon SLB9672/SLB9673
> > TPMs only.
> >
> > Key components added:
> > - cmd/wolftpm.c: TPM2 command implementation using wolfTPM APIs
> > - lib/wolftpm: wolfTPM library as git submodule
> > - drivers/spi/bcm2835_spi.c: BCM2835 SPI driver for Raspberry Pi 4
> > - drivers/tpm/tpm_spi_sandbox.c: TPM SPI sandbox driver for testing
> > - drivers/tpm/wolftpm_common.c: Common wolfTPM driver functions
> > - include/configs/user_settings.h: wolfTPM build configuration
> >
> > Configuration options:
> > - CONFIG_TPM_WOLF: Enable wolfTPM support (mutually exclusive with
> > CONFIG_CMD_TPM_V2)
> > - CONFIG_WOLFTPM_SLB9672: Enable Infineon SLB9672/SLB9673 firmware
> > update support
> > - CONFIG_BCM2835_SPI: Enable BCM2835 SPI driver
> >
> > Device tree updates for Raspberry Pi 4, QEMU arm64, and sandbox
> > environments to support TPM over SPI.
> >
> > Tested on Raspberry Pi 4 Model B with Infineon SLB9670 (LetsTrust HAT)
> > and SLB9672 TPMs.
> >
> > Signed-off-by: Aidan Garske <aidan at wolfssl.com>
> > ---
> > .gitmodules | 3 +
> > README | 3 +
> > README.wolftpm.md | 149 +++
> > arch/arm/dts/bcm2711-rpi-4-b.dts | 20 +
> > arch/arm/dts/qemu-arm64.dts | 4 +
> > arch/sandbox/dts/sandbox.dtsi | 11 +
> > cmd/Kconfig | 16 +
> > cmd/Makefile | 11 +-
> > cmd/tpm-common.c | 4 +-
> > cmd/wolftpm.c | 1443 +++++++++++++++++++++++++++++
> > configs/rpi_4_defconfig | 29 +-
> > doc/usage/cmd/wolftpm.rst | 694 ++++++++++++++
> > drivers/mtd/spi/sandbox.c | 30 +-
> > drivers/spi/Kconfig | 9 +
> > drivers/spi/Makefile | 1 +
> > drivers/spi/bcm2835_spi.c | 429 +++++++++
> > drivers/tpm/Kconfig | 36 +
> > drivers/tpm/Makefile | 9 +
> > drivers/tpm/tpm_spi_sandbox.c | 410 ++++++++
> > drivers/tpm/wolftpm_common.c | 135 +++
> > include/configs/user_settings.h | 118 +++
> > include/hash.h | 17 +
> > include/linux/byteorder/generic.h | 31 +-
> > include/tpm-common.h | 22 +
> > include/wolftpm.h | 33 +
> > lib/Kconfig | 13 +
> > lib/Makefile | 18 +
> > lib/wolftpm | 1 +
> > lib/wolftpm.c | 56 ++
> > scripts/check-local-export | 9 +
> > test/cmd/Makefile | 1 +
> > test/cmd/wolftpm.c | 364 ++++++++
> > test/py/tests/test_wolftpm.py | 373 ++++++++
> > 33 files changed, 4483 insertions(+), 19 deletions(-)
>
> This need to be broken down to a series of patches, that we can review.
> Having everything in a
> single patch is not reviewable.
>
> >
> > + CONFIG_TPM_WOLF
> > + Enables support for wolfTPM library.
> > +
>
> I think I've asked this before, but is wolfTPM GPLv2?
>
> This needs to be it's own patch. e.g Add TPM into rpi4
> > diff --git a/arch/arm/dts/bcm2711-rpi-4-b.dts
> b/arch/arm/dts/bcm2711-rpi-4-b.dts
> > index 72ce80fbf26..a09276dc279 100644
> > --- a/arch/arm/dts/bcm2711-rpi-4-b.dts
> > +++ b/arch/arm/dts/bcm2711-rpi-4-b.dts
> > @@ -8,6 +8,11 @@
> > compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
> > model = "Raspberry Pi 4 Model B";
> >
> > + /* Alias hardware SPI as spi0 so wolfTPM finds it at bus 0 */
> > + aliases {
> > + spi0 = &spi;
> > + };
> > +
> > chosen {
> > /* 8250 auxiliary UART instead of pl011 */
> > stdout-path = "serial1:115200n8";
> > @@ -54,6 +59,21 @@
> > enable-active-high;
> > gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>;
> > };
> > +
> > +};
> > +
> > +/* Hardware SPI with TPM - matches Linux tpm-slb9670 overlay */
> > +&spi {
> > + status = "okay";
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&spi0_gpio7>;
> > +
> > + /* Infineon SLB9670/9672 TPM 2.0 on CE1 (GPIO7) */
> > + tpm at 1 {
> > + compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
> > + reg = <1>; /* CE1 */
> > + spi-max-frequency = <32000000>;
> > + };
> > };
> >
> > &ddc0 {
> > diff --git a/arch/arm/dts/qemu-arm64.dts b/arch/arm/dts/qemu-arm64.dts
> > index 95fcf53ed74..e74d036a532 100644
> > --- a/arch/arm/dts/qemu-arm64.dts
> > +++ b/arch/arm/dts/qemu-arm64.dts
> > @@ -12,4 +12,8 @@
> > #endif
> >
> > / {
> > + tpm at 0c000000 {
> > + compatible = "tcg,tpm-tis-mmio";
> > + reg = <0x0 0x0c000000 0x0 0x5000>;
> > + };
>
> Same here for the sandbox
>
> > };
> > diff --git a/arch/sandbox/dts/sandbox.dtsi
> b/arch/sandbox/dts/sandbox.dtsi
> > index 02b03894eaf..2fdd7f0e942 100644
> > --- a/arch/sandbox/dts/sandbox.dtsi
> > +++ b/arch/sandbox/dts/sandbox.dtsi
> > @@ -286,6 +286,17 @@
> > spi-max-frequency = <40000000>;
> > sandbox,filename = "spi.bin";
> > };
> > +
> > + tpm_spi: tpm at 1 {
> > + reg = <1>;
> > + compatible = "sandbox,tpm-spi";
> > + spi-max-frequency = <10000000>;
> > + sandbox,emul = <&tpm_spi_emul>;
> > + };
> > + };
> > +
> > + tpm_spi_emul: tpm-spi-emul {
> > + compatible = "sandbox,tpm-spi-emul";
> > };
> >
> > spl-test {
> > diff --git a/cmd/Kconfig b/cmd/Kconfig
> > index cc4dd5a3163..3a4be20268e 100644
> > --- a/cmd/Kconfig
> > +++ b/cmd/Kconfig
> > @@ -2814,6 +2814,9 @@ config CMD_TPM
> > command requires a suitable TPM on your board and the correct
> driver
> > must be enabled.
> >
> > + Note: For TPM2, do not enable both CMD_TPM and CMD_WOLFTPM as
> they
> > + both provide the tpm2 command.
> > +
> > if CMD_TPM
> >
> > config CMD_TPM_TEST
> > @@ -3194,4 +3197,17 @@ config CMD_SPAWN_NUM_JOBS
> > When a jobs exits, its identifier is available to be re-used by
> the next
> > spawn command.
> >
> > +config CMD_WOLFTPM
> > + bool "Enable wolfTPM tpm2 command (replaces standard tpm2)"
> > + depends on TPM && TPM_V2
> > + select TPM_WOLF
> > + help
> > + This provides the 'tpm2' command using the wolfTPM library
> instead
> > + of the standard U-Boot TPM2 implementation. wolfTPM offers
> additional
> > + features including firmware update support for Infineon TPMs and
> > + enhanced capabilities reporting.
> > +
> > + Note: Do not enable both CMD_TPM and CMD_WOLFTPM as they both
> > + provide the tpm2 command.
> > +
> > endif
> > diff --git a/cmd/Makefile b/cmd/Makefile
> > index 4cd13d4fa6e..9c622e3d717 100644
> > --- a/cmd/Makefile
> > +++ b/cmd/Makefile
> > @@ -191,9 +191,18 @@ obj-$(CONFIG_CMD_TIMER) += timer.o
> > obj-$(CONFIG_CMD_TRACE) += trace.o
> > obj-$(CONFIG_HUSH_PARSER) += test.o
> > obj-$(CONFIG_CMD_TPM) += tpm-common.o
> > -obj-$(CONFIG_CMD_TPM_V1) += tpm-v1.o
> > obj-$(CONFIG_CMD_TPM_TEST) += tpm_test.o
> > +ifeq ($(CONFIG_TPM_WOLF),y)
> > +ifeq ($(CONFIG_TPM_V2),y)
> > +ccflags-y += -Ilib/wolftpm \
> > + -Iinclude/configs \
> > + -DWOLFTPM_USER_SETTINGS
> > +obj-$(CONFIG_TPM_WOLF) += wolftpm.o
> > +endif
> > +else
> > +obj-$(CONFIG_CMD_TPM_V1) += tpm-v1.o
>
> So WolfTPM doesn't support V1? If that's the case the if selection should
> be giarded
> by a TPMv2 config option and allow the user to select wolf vs existing
>
> > obj-$(CONFIG_CMD_TPM_V2) += tpm-v2.o
> > +endif
> > obj-$(CONFIG_CMD_CROS_EC) += cros_ec.o
> > obj-$(CONFIG_CMD_UBI) += ubi.o
> > obj-$(CONFIG_CMD_UBIFS) += ubifs.o
>
> This needs to be on its own patch explaining why staic is added etc
>
> > diff --git a/cmd/tpm-common.c b/cmd/tpm-common.c
> > index 1cd57f901b6..30e99e10758 100644
> > --- a/cmd/tpm-common.c
> > +++ b/cmd/tpm-common.c
> > @@ -234,7 +234,7 @@ int type_string_write_vars(const char *type_str, u8
> *data,
> > return 0;
> > }
> >
> > -static int tpm_show_device(void)
> > +int tpm_show_device(void)
> > {
> > struct udevice *dev;
> > char buf[80];
> > @@ -253,7 +253,7 @@ static int tpm_show_device(void)
> > return 0;
> > }
> >
> > -static int tpm_set_device(unsigned long num)
> > +int tpm_set_device(unsigned long num)
> > {
> > struct udevice *dev;
> > unsigned long n = 0;
> > diff --git a/cmd/wolftpm.c b/cmd/wolftpm.c
> > new file mode 100644
> > index 00000000000..cafd790cfaa
>
> Same for teh code below.
>
> > --- /dev/null
> > +++ b/cmd/wolftpm.c
> > @@ -0,0 +1,1443 @@
> > +/* wolftpm.c
> > +*
> > +* SPDX-License-Identifier: GPL-2.0+
> > +*
> > +* (C) Copyright 2025
> > +* Aidan Garske <aidan at wolfssl.com>
> > +*/
> > +
> > +#define LOG_CATEGORY UCLASS_BOOTSTD
> > +
> > +#ifdef HAVE_CONFIG_H
> > + #include <config.h>
> > +#endif
> > +
> > +#include <wolftpm/tpm2.h>
> > +#include <wolftpm/tpm2_wrap.h>
> > +#include <wolftpm/tpm2_packet.h>
> > +#include <wolftpm.h>
> > +
> > +#include <stdio.h>
> > +#include <hash.h>
> > +#ifndef WOLFTPM2_NO_WRAPPER
> > +
> > +#include <hal/tpm_io.h>
> > +#include <examples/wrap/wrap_test.h>
> > +
> > +/* U-boot specific includes */
> > +#include <command.h>
> > +#include <tpm-common.h>
> > +#include <vsprintf.h>
> > +#include <mapmem.h>
> > +#include <errno.h>
> > +#include <log.h>
> > +#include <string.h>
> > +
> > +
> > +/* Firmware update info structure for Infineon TPM */
> > +#ifdef WOLFTPM_FIRMWARE_UPGRADE
> > +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
> > +typedef struct {
> > + byte* manifest_buf;
> > + byte* firmware_buf;
> > + size_t manifest_bufSz;
> > + size_t firmware_bufSz;
> > +} fw_info_t;
> > +#endif
> > +#endif
> > +
> >
> +/******************************************************************************/
> > +/* --- BEGIN Common Commands -- */
> >
> +/******************************************************************************/
> > +
> > +#ifdef WOLFTPM_LINUX_DEV
> > +/* Use U-Boot's TPM device model for device/info/state when in Linux
> dev mode */
> > +static int do_tpm2_device(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + int rc;
> > + unsigned long num;
> > +
> > + /* Expected 1-2 arg: command + [num device] */
> > + if (argc < 1 || argc > 2) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + if (argc == 2) {
> > + num = dectoul(argv[1], NULL);
> > + rc = tpm_set_device(num);
> > + if (rc)
> > + log_debug("Couldn't set TPM %lu (rc = %d)\n", num, rc);
> > + } else {
> > + rc = tpm_show_device();
> > + }
> > +
> > + log_debug("tpm device: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> > +static int do_tpm2_info(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + int rc;
> > + char buf[80];
> > + struct udevice *dev;
> > +
> > + if (argc != 1) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + rc = get_tpm(&dev);
> > + if (rc == 0) {
>
> We usually do if (!rc)
>
> > + /* Get the current TPM's description
> > + * tpm_get_desc returns the number of bytes written on success
> */
> > + rc = tpm_get_desc(dev, buf, sizeof(buf));
> > + if (rc < 0) {
> > + log_debug("Couldn't get TPM info (%d)\n", rc);
> > + rc = CMD_RET_FAILURE;
> > + }
> > + else {
> > + log_debug("%s\n", buf);
> > + rc = 0; /* Success - return 0, not byte count */
> > + }
> > + }
> > +
> > + log_debug("tpm2 info: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> > +static int do_tpm2_state(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + int rc;
> > + char buf[80];
> > + struct udevice *dev;
> > +
> > + if (argc != 1) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + rc = get_tpm(&dev);
> > + if (rc == 0) {
>
> Same here
>
> > + /* Get the current TPM's state
> > + * tpm_report_state may return -ENOSYS if not implemented by
> driver */
> > + rc = tpm_report_state(dev, buf, sizeof(buf));
> > + if (rc == -ENOSYS) {
>
> > + log_debug("TPM state reporting not supported by driver\n");
> > + rc = 0; /* Not an error, just not supported */
> > + }
>
> The coding style is } else if etc. Also I'd switch those ifs around
> if (rc < 0 ) {
> .....
> } else {
> if (rc == -ENOSYS)
> .....
> }
>
> > + else if (rc < 0) {
> > + log_debug("Couldn't get TPM state (%d)\n", rc);
> > + rc = CMD_RET_FAILURE;
> > + }
> > + else {
> > + log_debug("%s\n", buf);
> > + rc = 0; /* Success - return 0, not byte count */
> > + }
> > + }
> > +
> > + log_debug("tpm2 state: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> > +#else /* !WOLFTPM_LINUX_DEV - Native SPI mode implementations */
>
> Instead of having ifdefs, I'd prefer having the wolftpm implementation
> split to
> its own file. We can then if needeed have a tpm2_common.c if the 2
> implementations
> share code.
>
> > +
> > +static int do_tpm2_device(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + WOLFTPM2_DEV dev;
> > + WOLFTPM2_CAPS caps;
> > + int rc;
> > +
> > + /* Expected 1 arg only in native SPI mode (no device switching) */
> > + if (argc != 1) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Try to initialize and get device info */
> > + rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
> > + if (rc == 0) {
>
> if(!rc)
>
> > + rc = wolfTPM2_GetCapabilities(&dev, &caps);
> > + if (rc == 0) {
> > + printf("TPM Device 0: %s (%s) FW=%d.%d\n",
> > + caps.mfgStr, caps.vendorStr,
> > + caps.fwVerMajor, caps.fwVerMinor);
> > + }
> > + wolfTPM2_Cleanup(&dev);
> > + }
> > +
> > + if (rc != 0) {
> > + printf("No TPM device found (rc=%d: %s)\n", rc,
> TPM2_GetRCString(rc));
> > + return CMD_RET_FAILURE;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int do_tpm2_info(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + WOLFTPM2_DEV dev;
> > + WOLFTPM2_CAPS caps;
> > + int rc;
> > +
> > + if (argc != 1) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
> > + if (rc == 0) {
>
> Same here
>
> > + if (rc == 0) {
> > + printf("TPM 2.0: %s (%s)\n", caps.mfgStr, caps.vendorStr);
> > + printf(" Firmware: %d.%d (0x%08X)\n",
> > + caps.fwVerMajor, caps.fwVerMinor, caps.fwVerVendor);
> > + printf(" Type: 0x%08X\n", caps.tpmType);
> > + }
> > + wolfTPM2_Cleanup(&dev);
> > + }
> > +
> > + if (rc != 0) {
> > + printf("Couldn't get TPM info (rc=%d: %s)\n", rc,
> TPM2_GetRCString(rc));
> > + return CMD_RET_FAILURE;
> > + }
> > +
> > + log_debug("tpm2 info: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
> > + return 0;
> > +}
> > +
> > +static int do_tpm2_state(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + WOLFTPM2_DEV dev;
> > + WOLFTPM2_CAPS caps;
> > + int rc;
> > +
> > + if (argc != 1) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
> > + if (rc == 0) {
> > + rc = wolfTPM2_GetCapabilities(&dev, &caps);
> > + if (rc == 0) {
> > + printf("TPM State:\n");
> > + printf(" Manufacturer: %s\n", caps.mfgStr);
> > + printf(" Vendor: %s\n", caps.vendorStr);
> > + printf(" Firmware: %d.%d\n", caps.fwVerMajor,
> caps.fwVerMinor);
> > +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
> > + printf(" Mode: Infineon SLB967x (Native SPI)\n");
> > + printf(" OpMode: %d\n", caps.opMode);
> > +#else
> > + printf(" Mode: Native wolfTPM SPI\n");
> > +#endif
> > + }
> > + wolfTPM2_Cleanup(&dev);
> > + }
> > +
> > + if (rc != 0) {
> > + printf("Couldn't get TPM state (rc=%d: %s)\n", rc,
> TPM2_GetRCString(rc));
> > + return CMD_RET_FAILURE;
> > + }
> > +
> > + log_debug("tpm2 state: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
> > + return 0;
> > +}
> > +
> > +#endif /* WOLFTPM_LINUX_DEV */
> > +
> > +static int do_tpm2_init(struct cmd_tbl *cmdtp, int flag, int argc,
> > + char *const argv[])
> > +{
> > + WOLFTPM2_DEV dev;
> > +
> > + if (argc != 1) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + return TPM2_Init_Device(&dev, NULL);
> > +}
> > +
> > +
> > +static int do_tpm2_autostart(struct cmd_tbl *cmdtp, int flag, int argc,
> > + char *const argv[])
> > +{
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > +
> > + if (argc != 1) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc == TPM_RC_SUCCESS) {
> > + /* Perform a startup clear
> > + * doStartup=1: Just starts up the TPM */
> > + rc = wolfTPM2_Reset(&dev, 0, 1);
> > + /* TPM_RC_INITIALIZE means already started - treat as success */
> > + if (rc == TPM_RC_INITIALIZE) {
> > + rc = TPM_RC_SUCCESS;
> > + } else if (rc != TPM_RC_SUCCESS) {
> > + log_debug("wolfTPM2_Reset failed 0x%x: %s\n", rc,
> > + TPM2_GetRCString(rc));
> > + }
> > + }
> > + if (rc == TPM_RC_SUCCESS) {
> > + /* Perform a full self test */
> > + rc = wolfTPM2_SelfTest(&dev);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("wolfTPM2_SelfTest failed 0x%x: %s\n", rc,
> > + TPM2_GetRCString(rc));
> > + }
> > + }
> > +
> > + log_debug("tpm2 autostart: rc = %d (%s)\n", rc,
> TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> >
> +/******************************************************************************/
> > +/* --- END Common Commands -- */
> >
> +/******************************************************************************/
> > +
> > +
> >
> +/******************************************************************************/
> > +/* --- START TPM 2.0 Commands -- */
> >
> +/******************************************************************************/
> > +
> > +static int do_tpm2_wrapper_getcapsargs(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + GetCapability_In in;
> > + GetCapability_Out out;
> > + u32 capability, property, rc;
> > + u8 *data;
> > + size_t count;
> > + int i, j;
> > +
> > + if (argc != 5)
> > + return CMD_RET_USAGE;
> > +
> > + capability = simple_strtoul(argv[1], NULL, 0);
> > + property = simple_strtoul(argv[2], NULL, 0);
> > + data = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0);
> > + count = simple_strtoul(argv[4], NULL, 0);
> > +
> > + memset(&in, 0, sizeof(in));
> > + memset(&out, 0, sizeof(out));
> > + in.capability = capability;
> > + in.property = property;
> > + in.propertyCount = count;
> > + rc = TPM2_GetCapability(&in, &out);
> > + if (rc == 0) {
> > + XMEMCPY(data, &out.capabilityData.data,
> sizeof(out.capabilityData.data));
>
> We don't want to carry extra internal implementation details. Is this just
> a memcpy?
>
> > +
> > + printf("Capabilities read from TPM:\n");
> > + for (i = 0; i < count; i++) {
> > + printf("Property 0x");
> > + for (j = 0; j < 4; j++)
> > + printf("%02x", data[(i * 8) + j + sizeof(u32)]);
> > + printf(": 0x");
> > + for (j = 4; j < 8; j++)
> > + printf("%02x", data[(i * 8) + j + sizeof(u32)]);
> > + printf("\n");
> > + }
> > + }
> > +
> > + unmap_sysmem(data);
> > +
> > + log_debug("tpm2 get_capability: rc = %d (%s)\n", rc,
> TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> > +static int do_tpm2_wrapper_capsargs(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > + WOLFTPM2_CAPS caps;
> > +
> > + if (argc != 1) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc == TPM_RC_SUCCESS) {
> > + rc = wolfTPM2_GetCapabilities(&dev, &caps);
> > + }
>
> You don't need {} here. Also if the first result isn't TPM_RC_SUCCESS all
> of the followjng
> ifs will fail. Should't we just fail early?
>
> > + if (rc == TPM_RC_SUCCESS) {
> > + log_debug("Mfg %s (%d), Vendor %s, Fw %u.%u (0x%x), "
> > + "FIPS 140-2 %d, CC-EAL4 %d\n",
> > + caps.mfgStr, caps.mfg, caps.vendorStr, caps.fwVerMajor,
> > + caps.fwVerMinor, caps.fwVerVendor, caps.fips140_2,
> caps.cc_eal4);
> > +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
> > + log_debug("Operational mode: %s (0x%x)\n",
> > + TPM2_IFX_GetOpModeStr(caps.opMode), caps.opMode);
> > + log_debug("KeyGroupId 0x%x, FwCounter %d (%d same)\n",
> > + caps.keyGroupId, caps.fwCounter, caps.fwCounterSame);
> > +#endif
> > + }
> > +
> > + /* List the active persistent handles */
> > + if (rc == TPM_RC_SUCCESS) {
> > + rc = wolfTPM2_GetHandles(PERSISTENT_FIRST, NULL);
> > + if (rc >= TPM_RC_SUCCESS) {
> > + log_debug("Found %d persistent handles\n", rc);
> > + }
> > + }
> > +
> > + /* Print the available PCR's */
> > + if (rc == TPM_RC_SUCCESS) {
> > + rc = TPM2_PCRs_Print();
> > + }
> > +
> > + /* Only doShutdown=1: Just shut down the TPM */
> > + wolfTPM2_Reset(&dev, 1, 0);
> > +
> > + wolfTPM2_Cleanup(&dev);
> > +
> > + log_debug("tpm2 caps: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
>
> The upgrade functionality should be a patch of its own
>
> > +#ifdef WOLFTPM_FIRMWARE_UPGRADE
> > +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
> > +static int do_tpm2_firmware_update(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > + WOLFTPM2_CAPS caps;
> > + fw_info_t fwinfo;
> > + ulong manifest_addr, firmware_addr;
> > + size_t manifest_sz, firmware_sz;
> > + uint8_t manifest_hash[TPM_SHA384_DIGEST_SIZE];
> > + int recovery = 0;
> > +
> > + memset(&fwinfo, 0, sizeof(fwinfo));
> > +
> > + /* Need 5 args: command + 4 arguments */
> > + if (argc != 5) {
> > + log_debug("Error: Expected 5 arguments but got %d\n", argc);
> > + return CMD_RET_USAGE;
> > + }
> > + printf("TPM2 Firmware Update\n");
> > +
> > + /* Convert all arguments from strings to numbers */
> > + manifest_addr = simple_strtoul(argv[1], NULL, 0);
> > + manifest_sz = simple_strtoul(argv[2], NULL, 0);
> > + firmware_addr = simple_strtoul(argv[3], NULL, 0);
> > + firmware_sz = simple_strtoul(argv[4], NULL, 0);
> > +
> > + /* Map the memory addresses */
> > + fwinfo.manifest_buf = map_sysmem(manifest_addr, manifest_sz);
> > + fwinfo.firmware_buf = map_sysmem(firmware_addr, firmware_sz);
> > + fwinfo.manifest_bufSz = manifest_sz;
> > + fwinfo.firmware_bufSz = firmware_sz;
> > +
> > + if (fwinfo.manifest_buf == NULL || fwinfo.firmware_buf == NULL) {
> > + log_debug("Error: Invalid memory addresses\n");
> > + return CMD_RET_FAILURE;
> > + }
> > +
> > + printf("Infineon Firmware Update Tool\n");
> > + printf("\tManifest Address: 0x%lx (size: %zu)\n",
> > + manifest_addr, manifest_sz);
> > + printf("\tFirmware Address: 0x%lx (size: %zu)\n",
> > + firmware_addr, firmware_sz);
> > +
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc == TPM_RC_SUCCESS) {
> > + rc = wolfTPM2_GetCapabilities(&dev, &caps);
> > + }
> > +
> > + if (rc == TPM_RC_SUCCESS) {
> > + TPM2_IFX_PrintInfo(&caps);
> > + if (caps.keyGroupId == 0) {
> > + log_debug("Error getting key group id from TPM!\n");
> > + }
> > + if (caps.opMode == 0x02 || (caps.opMode & 0x80)) {
> > + /* if opmode == 2 or 0x8x then we need to use recovery mode
> */
> > + recovery = 1;
> > + }
> > + }
> > +
> > + if (rc == TPM_RC_SUCCESS) {
> > + if (recovery) {
> > + printf("Firmware Update (recovery mode):\n");
> > + rc = wolfTPM2_FirmwareUpgradeRecover(&dev,
> > + fwinfo.manifest_buf, (uint32_t)fwinfo.manifest_bufSz,
> > + TPM2_IFX_FwData_Cb, &fwinfo);
> > + }
> > + else {
>
> On the entire patch take a look at the coding style and run checkpatch.pl
> please.
> It's usually
> if () {
> ....
> } else {
> ....
> }
>
> > + /* Normal mode - hash with wc_Sha384Hash */
> > + printf("Firmware Update (normal mode):\n");
> > + rc = wc_Sha384Hash(fwinfo.manifest_buf,
> > + (uint32_t)fwinfo.manifest_bufSz, manifest_hash);
> > + if (rc == TPM_RC_SUCCESS) {
> > + rc = wolfTPM2_FirmwareUpgradeHash(&dev, TPM_ALG_SHA384,
> > + manifest_hash, (uint32_t)sizeof(manifest_hash),
> > + fwinfo.manifest_buf,
> (uint32_t)fwinfo.manifest_bufSz,
> > + TPM2_IFX_FwData_Cb, &fwinfo);
> > + }
> > + }
> > + }
> > + if (rc == TPM_RC_SUCCESS) {
> > + TPM2_IFX_PrintInfo(&caps);
> > + }
> > +
> > + if (fwinfo.manifest_buf)
> > + unmap_sysmem(fwinfo.manifest_buf);
> > + if (fwinfo.firmware_buf)
> > + unmap_sysmem(fwinfo.firmware_buf);
> > +
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("Infineon firmware update failed 0x%x: %s\n",
> > + rc, TPM2_GetRCString(rc));
> > + }
> > +
> > + wolfTPM2_Cleanup(&dev);
> > +
> > + log_debug("tpm2 firmware_update: rc=%d (%s)\n", rc,
> TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> > +static int do_tpm2_firmware_cancel(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > + uint8_t cmd[TPM2_HEADER_SIZE + 2];
> > + uint16_t val16;
> > +
> > + if (argc != 1) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc == TPM_RC_SUCCESS) {
> > + /* Setup command size in header */
> > + val16 = TPM2_HEADER_SIZE + 2;
> > + XMEMCPY(cmd, &val16, sizeof(val16));
> > + val16 = 0;
> > + XMEMCPY(&cmd[TPM2_HEADER_SIZE], &val16, sizeof(val16));
> > +
> > + rc =
> TPM2_IFX_FieldUpgradeCommand(TPM_CC_FieldUpgradeAbandonVendor,
> > + cmd, sizeof(cmd));
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("Firmware abandon failed 0x%x: %s\n",
> > + rc, TPM2_GetRCString(rc));
> > + }
> > + }
> > +
> > + wolfTPM2_Cleanup(&dev);
> > +
> > + log_debug("tpm2 firmware_cancel: rc=%d (%s)\n", rc,
> TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +#endif /* WOLFTPM_SLB9672 || WOLFTPM_SLB9673 */
> > +#endif /* WOLFTPM_FIRMWARE_UPGRADE */
> > +
>
> > +static int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
>
> Why can't we reuse the existing functions and just replace tthe TPM calls
> with
> wolfTPM here? Opencoding the startup sequence twice seems unecessary.
>
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > + Startup_In startupIn;
> > + Shutdown_In shutdownIn;
> > + int doStartup = YES;
> > +
> > + /* startup TPM2_SU_CLEAR|TPM2_SU_STATE [off] */
> > + if (argc < 2 || argc > 3)
> > + return CMD_RET_USAGE;
> > + /* Check if shutdown requested */
> > + if (argc == 3) {
> > + if (strcmp(argv[2], "off") != 0)
> > + return CMD_RET_USAGE;
> > + doStartup = NO; /* shutdown */
> > + }
> > + printf("TPM2 Startup\n");
> > +
> > + memset(&startupIn, 0, sizeof(startupIn));
> > + memset(&shutdownIn, 0, sizeof(shutdownIn));
> > +
> > + /* Init the TPM2 device */
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc != TPM_RC_SUCCESS) return rc;
> > +
> > + if (!strcmp(argv[1], "TPM2_SU_CLEAR")) {
> > + if (doStartup == YES) {
> > + startupIn.startupType = TPM_SU_CLEAR;
> > + } else {
> > + shutdownIn.shutdownType = TPM_SU_CLEAR;
> > + }
> > + } else if (!strcmp(argv[1], "TPM2_SU_STATE")) {
> > + if (doStartup == YES) {
> > + startupIn.startupType = TPM_SU_STATE;
> > + } else {
> > + shutdownIn.shutdownType = TPM_SU_STATE;
> > + }
> > + } else {
> > + log_debug("Couldn't recognize mode string: %s\n", argv[1]);
> > + wolfTPM2_Cleanup(&dev);
> > + return CMD_RET_FAILURE;
> > + }
> > +
> > + /* startup */
> > + if (doStartup == YES) {
> > + rc = TPM2_Startup(&startupIn);
> > + /* TPM_RC_INITIALIZE = Already started */
> > + if (rc != TPM_RC_SUCCESS && rc != TPM_RC_INITIALIZE) {
> > + log_debug("TPM2 Startup: Result = 0x%x (%s)\n", rc,
> > + TPM2_GetRCString(rc));
> > + }
> > + /* shutdown */
> > + } else {
> > + rc = TPM2_Shutdown(&shutdownIn);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("TPM2 Shutdown: Result = 0x%x (%s)\n", rc,
> > + TPM2_GetRCString(rc));
> > + }
> > + }
> > +
> > + wolfTPM2_Cleanup(&dev);
> > +
> > + if (rc >= 0)
> > + rc = 0;
> > +
> > + log_debug("tpm2 startup (%s): rc = %d (%s)\n",
> > + doStartup ? "startup" : "shutdown", rc, TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> o
> > +static int do_tpm2_selftest(struct cmd_tbl *cmdtp, int flag,
>
> Same here
>
> > + int argc, char *const argv[])
> > +{
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > + TPMI_YES_NO fullTest = YES;
> > +
> > + /* Need 2 arg: command + type */
> > + if (argc != 2) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc == TPM_RC_SUCCESS) {
> > + if (!strcmp(argv[1], "full")) {
> > + fullTest = YES;
> > + } else if (!strcmp(argv[1], "continue")) {
> > + fullTest = NO;
> > + } else {
> > + log_debug("Couldn't recognize test mode: %s\n", argv[1]);
> > + wolfTPM2_Cleanup(&dev);
> > + return CMD_RET_FAILURE;
> > + }
> > +
> > + /* full test */
> > + if (fullTest == YES) {
> > + rc = wolfTPM2_SelfTest(&dev);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("TPM2 Self Test: Result = 0x%x (%s)\n", rc,
> > + TPM2_GetRCString(rc));
> > + }
> > + /* continue test */
> > + } else {
> > + rc = wolfTPM2_SelfTest(&dev);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("TPM2 Self Test: Result = 0x%x (%s)\n", rc,
> > + TPM2_GetRCString(rc));
> > + }
> > + }
> > + }
> > +
> > + wolfTPM2_Cleanup(&dev);
> > +
> > + log_debug("tpm2 selftest (%s): rc = %d (%s)\n",
> > + fullTest ? "full" : "continue", rc, TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> > +static int do_tpm2_clear(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > + Clear_In clearIn;
> > + TPMI_RH_CLEAR handle;
> > +
> > + /* Need 2 arg: command + type */
> > + if (argc != 2) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1])) {
> > + handle = TPM_RH_LOCKOUT;
> > + } else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1])) {
> > + handle = TPM_RH_PLATFORM;
> > + } else {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc == TPM_RC_SUCCESS) {
> > + /* Set up clear */
> > + memset(&clearIn, 0, sizeof(clearIn));
> > + clearIn.authHandle = handle;
> > +
> > + rc = TPM2_Clear(&clearIn);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("TPM2 Clear: Result = 0x%x (%s)\n", rc,
> > + TPM2_GetRCString(rc));
> > + }
> > + }
> > +
> > + wolfTPM2_Cleanup(&dev);
> > +
> > + log_debug("tpm2 clear (%s): rc = %d (%s)\n",
> > + handle == TPM_RH_LOCKOUT ? "TPM2_RH_LOCKOUT" :
> "TPM2_RH_PLATFORM",
> > + rc, TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> > +static int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
>
> And here
>
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > + uint32_t pcrIndex;
> > + int algo = TPM_ALG_SHA256;
> > + int digestLen;
> > + void *digest;
> > + ulong digest_addr;
> > +
> > + /* Need 3-4 args: command + pcr + digest_addr + [algo] */
> > + if (argc < 3 || argc > 4) {
> > + return CMD_RET_USAGE;
> > + }
> > + printf("TPM2 PCR Extend\n");
> > +
> > + pcrIndex = simple_strtoul(argv[1], NULL, 0);
> > + digest_addr = simple_strtoul(argv[2], NULL, 0);
> > +
> > + /* Optional algorithm */
> > + if (argc == 4) {
> > + algo = TPM2_GetAlgId(argv[3]);
> > + if (algo < 0) {
> > + log_debug("Couldn't recognize algorithm: %s\n", argv[3]);
> > + return CMD_RET_FAILURE;
> > + }
> > + log_debug("Using algorithm: %s\n", TPM2_GetAlgName(algo));
> > + }
> > +
> > + /* Get digest length based on algorithm */
> > + digestLen = TPM2_GetHashDigestSize(algo);
> > + if (digestLen <= 0) {
> > + log_debug("Invalid algorithm digest length\n");
> > + return CMD_RET_FAILURE;
> > + }
> > +
> > + /* Map digest from memory address */
> > + digest = map_sysmem(digest_addr, digestLen);
> > + if (digest == NULL) {
> > + log_debug("Error: Invalid digest memory address\n");
> > + return CMD_RET_FAILURE;
> > + }
> > +
> > + log_debug("TPM2 PCR Extend: PCR %u with %s digest\n",
> > + (unsigned int)pcrIndex, TPM2_GetAlgName(algo));
> > +
> > + /* Init the TPM2 device */
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc != TPM_RC_SUCCESS) {
> > + unmap_sysmem(digest);
> > + return rc;
> > + }
> > +
> > + /* Extend the PCR */
> > + rc = wolfTPM2_ExtendPCR(&dev, pcrIndex, algo, digest, digestLen);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("TPM2_PCR_Extend failed 0x%x: %s\n", rc,
> > + TPM2_GetRCString(rc));
> > + }
> > +
> > + unmap_sysmem(digest);
> > + wolfTPM2_Cleanup(&dev);
> > +
> > + log_debug("tpm2 pcr_extend: rc = %d (%s)\n", rc,
> TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> > +static int do_tpm2_pcr_read(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
>
> And here
>
> > +{
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > + uint32_t pcrIndex;
> > + int algo = TPM_ALG_SHA256;
> > + void *digest;
> > + ulong digest_addr;
> > + int digestLen;
> > +
> > + /* Need 3-4 args: command + pcr + digest_addr + [algo] */
> > + if (argc < 3 || argc > 4) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + pcrIndex = simple_strtoul(argv[1], NULL, 0);
> > + digest_addr = simple_strtoul(argv[2], NULL, 0);
> > +
> > + /* Optional algorithm */
> > + if (argc == 4) {
> > + algo = TPM2_GetAlgId(argv[3]);
> > + if (algo < 0) {
> > + log_debug("Couldn't recognize algorithm: %s\n", argv[3]);
> > + return CMD_RET_FAILURE;
> > + }
> > + log_debug("Using algorithm: %s\n", TPM2_GetAlgName(algo));
> > + }
> > +
> > + /* Get digest length based on algorithm */
> > + digestLen = TPM2_GetHashDigestSize(algo);
> > + if (digestLen <= 0) {
> > + log_debug("Invalid algorithm digest length\n");
> > + return CMD_RET_FAILURE;
> > + }
> > +
> > + /* Map digest from memory address */
> > + digest = map_sysmem(digest_addr, digestLen);
> > + if (digest == NULL) {
> > + log_debug("Error: Invalid digest memory address\n");
> > + return CMD_RET_FAILURE;
> > + }
> > +
> > + log_debug("TPM2 PCR Read: PCR %u to %s digest\n",
> > + (unsigned int)pcrIndex, TPM2_GetAlgName(algo));
> > +
> > + /* Init the TPM2 device */
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc != TPM_RC_SUCCESS) {
> > + unmap_sysmem(digest);
> > + return rc;
> > + }
> > +
> > + /* Read the PCR */
> > + rc = wolfTPM2_ReadPCR(&dev, pcrIndex, algo, digest, &digestLen);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("TPM2_PCR_Read failed 0x%x: %s\n", rc,
> > + TPM2_GetRCString(rc));
> > + }
> > +
> > + unmap_sysmem(digest);
> > + wolfTPM2_Cleanup(&dev);
> > +
> > + log_debug("tpm2 pcr_read: rc = %d (%s)\n", rc,
> TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> > +static int do_tpm2_pcr_allocate(struct cmd_tbl *cmdtp, int flag,
>
> And here
>
> > + int argc, char *const argv[])
> > +{
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > + PCR_Allocate_In in;
> > + PCR_Allocate_Out out;
> > + TPM2B_AUTH auth;
> > +
> > + /* Need 3-4 args: command + algorithm + on/off + [password] */
> > + if (argc < 3 || argc > 4) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc != TPM_RC_SUCCESS) return rc;
> > +
> > + /* Setup PCR Allocation command */
> > + memset(&in, 0, sizeof(in));
> > + in.authHandle = TPM_RH_PLATFORM;
> > +
> > + /* Single PCR bank allocation */
> > + in.pcrAllocation.count = 1; /* Change only one bank */
> > + in.pcrAllocation.pcrSelections[0].hash = TPM2_GetAlgId(argv[1]);
> > + in.pcrAllocation.pcrSelections[0].sizeofSelect = PCR_SELECT_MAX;
> > +
> > + /* Set all PCRs for this algorithm */
> > + if (!strcmp(argv[2], "on")) {
> > + memset(in.pcrAllocation.pcrSelections[0].pcrSelect, 0xFF,
> > + PCR_SELECT_MAX);
> > + }
> > + /* Clear all PCRs for this algorithm */
> > + else if (!strcmp(argv[2], "off")) {
> > + memset(in.pcrAllocation.pcrSelections[0].pcrSelect, 0x00,
> > + PCR_SELECT_MAX);
> > + }
> > + else {
> > + log_debug("Couldn't recognize allocate mode: %s\n", argv[2]);
> > + wolfTPM2_Cleanup(&dev);
> > + return CMD_RET_USAGE;
> > + }
> > + log_debug("Attempting to set %s bank to %s\n",
> > + TPM2_GetAlgName(in.pcrAllocation.pcrSelections[0].hash),
> > + argv[2]);
> > +
> > + /* Set auth password if provided */
> > + if (argc == 4) {
> > + memset(&auth, 0, sizeof(auth));
> > + auth.size = strlen(argv[3]);
> > + XMEMCPY(auth.buffer, argv[3], auth.size);
> > + rc = wolfTPM2_SetAuth(&dev, 0, TPM_RH_PLATFORM, &auth, 0, NULL);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("wolfTPM2_SetAuth failed 0x%x: %s\n", rc,
> > + TPM2_GetRCString(rc));
> > + wolfTPM2_Cleanup(&dev);
> > + return rc;
> > + }
> > + }
> > +
> > + /* Allocate the PCR */
> > + rc = TPM2_PCR_Allocate(&in, &out);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("TPM2_PCR_Allocate failed 0x%x: %s\n", rc,
> > + TPM2_GetRCString(rc));
> > + }
> > +
> > + /* Print current PCR state */
> > + printf("\n\tNOTE: A TPM restart is required for changes to take
> effect\n");
> > + printf("\nCurrent PCR state:\n");
> > + TPM2_PCRs_Print();
> > +
> > + wolfTPM2_Cleanup(&dev);
> > +
> > + printf("Allocation Success: %s\n",
> > + out.allocationSuccess ? "YES" : "NO");
> > + log_debug("tpm2 pcr_allocate %s (%s): rc = %d (%s)\n",
> > + TPM2_GetAlgName(in.pcrAllocation.pcrSelections[0].hash),
> > + argv[2], rc, TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> > +/* We dont have parameter encryption enabled when WOLFTPM2_NO_WOLFCRYPT
> > +* is defined. If the session isn't used then the new password is not
> > +* encrypted in transit over the bus: "a session is required to protect
> > +* the new platform auth" */
> > +#ifndef WOLFTPM2_NO_WOLFCRYPT
> > +static int TPM2_PCR_SetAuth(int argc, char *const argv[],
> > + int isPolicy)
> > +{
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > + WOLFTPM2_SESSION session;
> > + TPM2B_AUTH auth;
> > + const char *pw = (argc < 4) ? NULL : argv[3];
> > + const char *key = argv[2];
> > + const ssize_t key_sz = strlen(key);
> > + u32 pcrIndex = simple_strtoul(argv[1], NULL, 0);
> > +
> > + /* Need 3-4 args: command + pcr + auth + [platform_auth] */
> > + if (argc < 3 || argc > 4) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Init the TPM2 device for value/policy */
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc != TPM_RC_SUCCESS) return rc;
> > +
> > + /* Start the session */
> > + rc = wolfTPM2_StartSession(&dev, &session, NULL, NULL,
> > + isPolicy ? TPM_SE_POLICY : TPM_SE_HMAC, TPM_ALG_NULL);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("wolfTPM2_StartSession failed 0x%x: %s\n", rc,
> > + TPM2_GetRCString(rc));
> > + wolfTPM2_Cleanup(&dev);
> > + return rc;
> > + }
> > +
> > + /* Set the platform auth if provided */
> > + if (pw) {
> > + TPM2B_AUTH platformAuth;
> > + memset(&platformAuth, 0, sizeof(platformAuth));
> > + platformAuth.size = strlen(pw);
> > + XMEMCPY(platformAuth.buffer, pw, platformAuth.size);
> > + rc = wolfTPM2_SetAuth(&dev, 0, TPM_RH_PLATFORM,
> > + &platformAuth, 0, NULL);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("wolfTPM2_SetAuth failed 0x%x: %s\n", rc,
> > + TPM2_GetRCString(rc));
> > + wolfTPM2_UnloadHandle(&dev, &session.handle);
> > + wolfTPM2_Cleanup(&dev);
> > + return rc;
> > + }
> > + }
> > +
> > + printf("Setting %s auth for PCR %u\n",
> > + isPolicy ? "policy" : "value", pcrIndex);
> > +
> > + /* Set up the auth value/policy */
> > + memset(&auth, 0, sizeof(auth));
> > + auth.size = key_sz;
> > + XMEMCPY(auth.buffer, key, key_sz);
> > +
> > + if (isPolicy) {
> > + /* Use TPM2_PCR_SetAuthPolicy command */
> > + PCR_SetAuthPolicy_In in;
> > + memset(&in, 0, sizeof(in));
> > + in.authHandle = TPM_RH_PLATFORM;
> > + in.authPolicy = auth;
> > + in.hashAlg = TPM_ALG_SHA256; /* Default to SHA256 */
> > + in.pcrNum = pcrIndex;
> > + rc = TPM2_PCR_SetAuthPolicy(&in);
> > + } else {
> > + /* Use TPM2_PCR_SetAuthValue command */
> > + PCR_SetAuthValue_In in;
> > + memset(&in, 0, sizeof(in));
> > + in.pcrHandle = pcrIndex;
> > + in.auth = auth;
> > + rc = TPM2_PCR_SetAuthValue(&in);
> > + }
> > +
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("TPM2_PCR_SetAuth%s failed 0x%x: %s\n",
> > + isPolicy ? "Policy" : "Value",
> > + rc, TPM2_GetRCString(rc));
> > + }
> > +
> > + wolfTPM2_UnloadHandle(&dev, &session.handle);
> > + wolfTPM2_Cleanup(&dev);
> > +
> > + log_debug("tpm2 set_auth %s: rc = %d (%s)\n",
> > + isPolicy ? "Policy" : "Value", rc, TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> > +static int do_tpm2_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + return TPM2_PCR_SetAuth(argc, argv, YES);
> > +}
> > +
> > +static int do_tpm2_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + return TPM2_PCR_SetAuth(argc, argv, NO);
> > +}
> > +
> > +static int do_tpm2_change_auth(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> And here etc.
> Basially what would make sense to me is split those function to the
> tpm2_common.c
> I mentioned above and have wrappers/callback to either the default lib or
> wolfTPM
>
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > + WOLFTPM2_SESSION session;
> > + const char *newpw = argv[2];
> > + const char *oldpw = (argc == 4) ? argv[3] : NULL;
> > + const ssize_t newpw_sz = strlen(newpw);
> > + const ssize_t oldpw_sz = oldpw ? strlen(oldpw) : 0;
> > + HierarchyChangeAuth_In in;
> > + TPM2B_AUTH newAuth;
> > +
> > + /* Need 3-4 args: command + hierarchy + new_pw + [old_pw] */
> > + if (argc < 3 || argc > 4) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc != TPM_RC_SUCCESS) return rc;
> > +
> > + memset(&in, 0, sizeof(in));
> > +
> > + /* Set the handle */
> > + if (!strcmp(argv[1], "TPM2_RH_LOCKOUT"))
> > + in.authHandle = TPM_RH_LOCKOUT;
> > + else if (!strcmp(argv[1], "TPM2_RH_ENDORSEMENT"))
> > + in.authHandle = TPM_RH_ENDORSEMENT;
> > + else if (!strcmp(argv[1], "TPM2_RH_OWNER"))
> > + in.authHandle = TPM_RH_OWNER;
> > + else if (!strcmp(argv[1], "TPM2_RH_PLATFORM"))
> > + in.authHandle = TPM_RH_PLATFORM;
> > + else {
> > + wolfTPM2_Cleanup(&dev);
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Validate password length if provided */
> > + if (newpw_sz > TPM_SHA256_DIGEST_SIZE ||
> > + oldpw_sz > TPM_SHA256_DIGEST_SIZE) {
> > + wolfTPM2_Cleanup(&dev);
> > + return -EINVAL;
> > + }
> > +
> > + /* Start auth session */
> > + rc = wolfTPM2_StartSession(&dev, &session, NULL, NULL,
> > + TPM_SE_HMAC, TPM_ALG_CFB);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("wolfTPM2_StartSession failed 0x%x: %s\n", rc,
> > + TPM2_GetRCString(rc));
> > + wolfTPM2_Cleanup(&dev);
> > + return rc;
> > + }
> > +
> > + /* If old password exists then set it as the current auth */
> > + if (oldpw) {
> > + TPM2B_AUTH oldAuth;
> > + memset(&oldAuth, 0, sizeof(oldAuth));
> > + oldAuth.size = oldpw_sz;
> > + XMEMCPY(oldAuth.buffer, oldpw, oldpw_sz);
> > + rc = wolfTPM2_SetAuthPassword(&dev, 0, &oldAuth);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("wolfTPM2_SetAuthPassword failed 0x%x: %s\n", rc,
> > + TPM2_GetRCString(rc));
> > + wolfTPM2_UnloadHandle(&dev, &session.handle);
> > + wolfTPM2_Cleanup(&dev);
> > + return rc;
> > + }
> > + }
> > +
> > + memset(&newAuth, 0, sizeof(newAuth));
> > + newAuth.size = newpw_sz;
> > + XMEMCPY(newAuth.buffer, newpw, newpw_sz);
> > + in.newAuth = newAuth;
> > +
> > + /* Change the auth based on the hierarchy */
> > + rc = wolfTPM2_ChangeHierarchyAuth(&dev, &session, in.authHandle);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("wolfTPM2_ChangeHierarchyAuth failed 0x%x: %s\n", rc,
> > + TPM2_GetRCString(rc));
> > + } else {
> > + log_debug("Successfully changed auth for %s\n", argv[1]);
> > + }
> > +
> > + wolfTPM2_UnloadHandle(&dev, &session.handle);
> > + wolfTPM2_Cleanup(&dev);
> > +
> > + log_debug("tpm2 change_auth: rc = %d (%s)\n", rc,
> TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +#endif /* !WOLFTPM2_NO_WOLFCRYPT */
> > +
> > +static int do_tpm2_pcr_print(struct cmd_tbl *cmdtp, int flag, int argc,
> char *const argv[])
> > +{
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > +
> > + /* Need 1 arg: command */
> > + if (argc != 1) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc == TPM_RC_SUCCESS) {
> > + /* Print the current PCR state */
> > + TPM2_PCRs_Print();
> > + }
> > + wolfTPM2_Cleanup(&dev);
> > +
> > + log_debug("tpm2 pcr_print: rc = %d (%s)\n", rc,
> TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> > +static int do_tpm2_dam_reset(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > + const char *pw = (argc < 2) ? NULL : argv[1];
> > + const ssize_t pw_sz = pw ? strlen(pw) : 0;
> > + DictionaryAttackLockReset_In in;
> > + TPM2_AUTH_SESSION session[MAX_SESSION_NUM];
> > +
> > + /* Need 1-2 args: command + [password] */
> > + if (argc > 2) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Validate password length if provided */
> > + if (pw && pw_sz > TPM_SHA256_DIGEST_SIZE) {
> > + log_debug("Error: Password too long\n");
> > + return -EINVAL;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc == TPM_RC_SUCCESS) {
> > + /* set lock handle */
> > + memset(&in, 0, sizeof(in));
> > + in.lockHandle = TPM_RH_LOCKOUT;
> > +
> > + /* Setup auth session only if password provided */
> > + memset(session, 0, sizeof(session));
> > + session[0].sessionHandle = TPM_RS_PW;
> > + if (pw) {
> > + session[0].auth.size = pw_sz;
> > + XMEMCPY(session[0].auth.buffer, pw, pw_sz);
> > + }
> > + TPM2_SetSessionAuth(session);
> > +
> > + rc = TPM2_DictionaryAttackLockReset(&in);
> > + log_debug("TPM2_Dam_Reset: Result = 0x%x (%s)\n", rc,
> > + TPM2_GetRCString(rc));
> > + }
> > + wolfTPM2_Cleanup(&dev);
> > +
> > + log_debug("tpm2 dam_reset: rc = %d (%s)\n", rc,
> TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> > +static int do_tpm2_dam_parameters(struct cmd_tbl *cmdtp, int flag,
> > + int argc, char *const argv[])
> > +{
> > + int rc;
> > + WOLFTPM2_DEV dev;
> > + const char *pw = (argc < 5) ? NULL : argv[4];
> > + const ssize_t pw_sz = pw ? strlen(pw) : 0;
> > + DictionaryAttackParameters_In in;
> > + TPM2_AUTH_SESSION session[MAX_SESSION_NUM];
> > +
> > + /* Need 4-5 args: command + max_tries + recovery_time +
> > + * lockout_recovery + [password] */
> > + if (argc < 4 || argc > 5) {
> > + return CMD_RET_USAGE;
> > + }
> > +
> > + /* Validate password length if provided */
> > + if (pw && pw_sz > TPM_SHA256_DIGEST_SIZE) {
> > + log_debug("Error: Password too long\n");
> > + return -EINVAL;
> > + }
> > +
> > + /* Init the TPM2 device */
> > + rc = TPM2_Init_Device(&dev, NULL);
> > + if (rc == TPM_RC_SUCCESS) {
> > + /* Set parameters */
> > + memset(&in, 0, sizeof(in));
> > + in.newMaxTries = simple_strtoul(argv[1], NULL, 0);
> > + in.newRecoveryTime = simple_strtoul(argv[2], NULL, 0);
> > + in.lockoutRecovery = simple_strtoul(argv[3], NULL, 0);
> > +
> > + /* set lock handle */
> > + in.lockHandle = TPM_RH_LOCKOUT;
> > +
> > + /* Setup auth session only if password provided */
> > + memset(session, 0, sizeof(session));
> > + session[0].sessionHandle = TPM_RS_PW;
> > + if (pw) {
> > + session[0].auth.size = pw_sz;
> > + XMEMCPY(session[0].auth.buffer, pw, pw_sz);
> > + }
> > + TPM2_SetSessionAuth(session);
> > +
> > + /* Set DAM parameters */
> > + rc = TPM2_DictionaryAttackParameters(&in);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("TPM2_DictionaryAttackParameters failed 0x%x:
> %s\n", rc,
> > + TPM2_GetRCString(rc));
> > + }
> > +
> > + printf("Changing dictionary attack parameters:\n");
> > + printf(" maxTries: %u\n", in.newMaxTries);
> > + printf(" recoveryTime: %u\n", in.newRecoveryTime);
> > + printf(" lockoutRecovery: %u\n", in.lockoutRecovery);
> > + }
> > + wolfTPM2_Cleanup(&dev);
> > +
> > + log_debug("tpm2 dam_parameters: rc = %d (%s)\n", rc,
> TPM2_GetRCString(rc));
> > +
> > + return rc;
> > +}
> > +
> > +static struct cmd_tbl wolftpm_cmds[] = {
> > + U_BOOT_CMD_MKENT(device, 2, 1, do_tpm2_device, "", ""),
> > + U_BOOT_CMD_MKENT(info, 1, 1, do_tpm2_info, "", ""),
> > + U_BOOT_CMD_MKENT(state, 1, 1, do_tpm2_state, "", ""),
> > + U_BOOT_CMD_MKENT(init, 1, 1, do_tpm2_init, "", ""),
> > + U_BOOT_CMD_MKENT(autostart, 1, 1, do_tpm2_autostart, "", ""),
> > + U_BOOT_CMD_MKENT(startup, 3, 1, do_tpm2_startup, "", ""),
> > + U_BOOT_CMD_MKENT(self_test, 2, 1, do_tpm2_selftest, "", ""),
> > + U_BOOT_CMD_MKENT(clear, 2, 1, do_tpm2_clear, "", ""),
> > + U_BOOT_CMD_MKENT(pcr_extend, 4, 1, do_tpm2_pcr_extend, "", ""),
> > + U_BOOT_CMD_MKENT(pcr_read, 4, 1, do_tpm2_pcr_read, "", ""),
> > + U_BOOT_CMD_MKENT(pcr_allocate, 4, 1, do_tpm2_pcr_allocate, "", ""),
> > + U_BOOT_CMD_MKENT(pcr_print, 1, 1, do_tpm2_pcr_print, "", ""),
> > +#ifndef WOLFTPM2_NO_WOLFCRYPT
> > + U_BOOT_CMD_MKENT(change_auth, 4, 1, do_tpm2_change_auth, "", ""),
> > + U_BOOT_CMD_MKENT(pcr_setauthpolicy, 4, 1,
> do_tpm2_pcr_setauthpolicy, "", ""),
> > + U_BOOT_CMD_MKENT(pcr_setauthvalue, 4, 1, do_tpm2_pcr_setauthvalue,
> "", ""),
> > +#endif
> > + U_BOOT_CMD_MKENT(get_capability, 5, 1, do_tpm2_wrapper_getcapsargs,
> "", ""),
> > + U_BOOT_CMD_MKENT(dam_reset, 2, 1, do_tpm2_dam_reset, "", ""),
> > + U_BOOT_CMD_MKENT(dam_parameters, 5, 1, do_tpm2_dam_parameters, "",
> ""),
> > + U_BOOT_CMD_MKENT(caps, 1, 1, do_tpm2_wrapper_capsargs, "", ""),
> > +#ifdef WOLFTPM_FIRMWARE_UPGRADE
> > +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
> > + U_BOOT_CMD_MKENT(firmware_update, 5, 1, do_tpm2_firmware_update,
> "", ""),
> > + U_BOOT_CMD_MKENT(firmware_cancel, 1, 1, do_tpm2_firmware_cancel,
> "", ""),
> > +#endif
> > +#endif
> > +};
> > +
> > +struct cmd_tbl *get_wolftpm_commands(unsigned int *size)
> > +{
> > + *size = ARRAY_SIZE(wolftpm_cmds);
> > +
> > + return wolftpm_cmds;
> > +}
> > +
> > +static int do_wolftpm(struct cmd_tbl *cmdtp, int flag, int argc,
> > + char *const argv[])
>
> Same for the cmd files. Duplicating isn't ideal, we need to apply fixes
> changes 2x
> every time now.
>
> > +{
> > + struct cmd_tbl *cmd;
> > +
> > + if (argc < 2)
> > + return CMD_RET_USAGE;
> > +
> > + cmd = find_cmd_tbl(argv[1], wolftpm_cmds,
> ARRAY_SIZE(wolftpm_cmds));
> > + if (!cmd)
> > + return CMD_RET_USAGE;
> > +
> > + return cmd->cmd(cmdtp, flag, argc - 1, argv + 1);
> > +}
> > +
> > +U_BOOT_CMD(
> > + tpm2, /* name of cmd - replaces standard tpm2
> when wolfTPM enabled */
> > + CONFIG_SYS_MAXARGS, /* max args */
> > + 1, /* repeatable */
> > + do_wolftpm, /* function */
> > + "Issue a TPMv2.x command (wolfTPM)",
> > + "<command> [<arguments>]\n"
> > + "\n"
> > + "Commands:\n"
> > + "help\n"
> > + " Show this help text\n"
> > + "device [num device]\n"
> > + " Show all devices or set the specified device\n"
> > + "info\n"
> > + " Show information about the TPM.\n"
> > + "state\n"
> > + " Show internal state from the TPM (if available)\n"
> > + "autostart\n"
> > + " Initalize the tpm, perform a Startup(clear) and run a full
> selftest\n"
> > + " sequence\n"
> > + "init\n"
> > + " Initialize the software stack. Always the first command to
> issue.\n"
> > + " 'tpm startup' is the only acceptable command after a 'tpm
> init' has been\n"
> > + " issued\n"
> > + "startup <mode> [<op>]\n"
> > + " Issue a TPM2_Startup command.\n"
> > + " <mode> is one of:\n"
> > + " * TPM2_SU_CLEAR (reset state)\n"
> > + " * TPM2_SU_STATE (preserved state)\n"
> > + " [<op>]: optional shutdown\n"
> > + " * off - To shutdown the TPM\n"
> > + "self_test <type>\n"
> > + " Test the TPM capabilities.\n"
> > + " <type> is one of:\n"
> > + " * full (perform all tests)\n"
> > + " * continue (only check untested tests)\n"
> > + "clear <hierarchy>\n"
> > + " Issue a TPM2_Clear command.\n"
> > + " <hierarchy> is one of:\n"
> > + " * TPM2_RH_LOCKOUT\n"
> > + " * TPM2_RH_PLATFORM\n"
> > + "pcr_extend <pcr> <digest_addr> [<digest_algo>]\n"
> > + " Extend PCR #<pcr> with digest at <digest_addr> with
> digest_algo.\n"
> > + " <pcr>: index of the PCR\n"
> > + " <digest_addr>: address of digest of digest_algo type
> (defaults to SHA256)\n"
> > + " [<digest_algo>]: algorithm to use for digest\n"
> > + "pcr_read <pcr> <digest_addr> [<digest_algo>]\n"
> > + " Read PCR #<pcr> to memory address <digest_addr> with
> <digest_algo>.\n"
> > + " <pcr>: index of the PCR\n"
> > + " <digest_addr>: address of digest of digest_algo type
> (defaults to SHA256)\n"
> > + " [<digest_algo>]: algorithm to use for digest\n"
> > + "pcr_print\n"
> > + " Prints the current PCR state\n"
> > + "caps\n"
> > + " Show TPM capabilities and info\n"
> > + "get_capability <capability> <property> <addr> <count>\n"
> > + " Read and display <count> entries indexed by
> <capability>/<property>.\n"
> > + " Values are 4 bytes long and are written at <addr>.\n"
> > + " <capability>: capability\n"
> > + " <property>: property\n"
> > + " <addr>: address to store <count> entries of 4 bytes\n"
> > + " <count>: number of entries to retrieve\n"
> > + "dam_reset [<password>]\n"
> > + " If the TPM is not in a LOCKOUT state, reset the internal
> error counter.\n"
> > + " [<password>]: optional password\n"
> > + "dam_parameters <max_tries> <recovery_time> <lockout_recovery>
> [<password>]\n"
> > + " If the TPM is not in a LOCKOUT state, sets the DAM
> parameters\n"
> > + " <max_tries>: maximum number of failures before lockout,\n"
> > + " 0 means always locking\n"
> > + " <recovery_time>: time before decrement of the error
> counter,\n"
> > + " 0 means no lockout\n"
> > + " <lockout_recovery>: time of a lockout (before the next
> try),\n"
> > + " 0 means a reboot is needed\n"
> > + " [<password>]: optional password of the LOCKOUT hierarchy\n"
> > + "change_auth <hierarchy> <new_pw> [<old_pw>]\n"
> > + " <hierarchy>: the hierarchy\n"
> > + " * TPM2_RH_LOCKOUT\n"
> > + " * TPM2_RH_ENDORSEMENT\n"
> > + " * TPM2_RH_OWNER\n"
> > + " * TPM2_RH_PLATFORM\n"
> > + " <new_pw>: new password for <hierarchy>\n"
> > + " [<old_pw>]: optional previous password of <hierarchy>\n"
> > + "pcr_setauthpolicy | pcr_setauthvalue <pcr> <key> [<password>]\n"
> > + " Change the <key> to access PCR #<pcr>.\n"
> > + " <pcr>: index of the PCR\n"
> > + " <key>: secret to protect the access of PCR #<pcr>\n"
> > + " [<password>]: optional password of the PLATFORM hierarchy\n"
> > + "pcr_allocate <algorithm> <on/off> [<password>]\n"
> > + " Issue a TPM2_PCR_Allocate Command to reconfig PCR bank
> algorithm.\n"
> > + " <algorithm> is one of:\n"
> > + " * SHA1\n"
> > + " * SHA256\n"
> > + " * SHA384\n"
> > + " * SHA512\n"
> > + " <on|off> is one of:\n"
> > + " * on - Select all available PCRs associated with the
> specified\n"
> > + " algorithm (bank)\n"
> > + " * off - Clear all available PCRs associated with the
> specified\n"
> > + " algorithm (bank)\n"
> > + " [<password>]: optional password\n"
> > +
> > +#ifdef WOLFTPM_FIRMWARE_UPGRADE
> > +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
> > + "firmware_update <manifest_addr> <manifest_sz> <firmware_addr>
> <firmware_sz>\n"
> > + " Update TPM firmware\n"
> > + "firmware_cancel\n"
> > + " Cancel TPM firmware update\n"
> > +#endif
> > +#endif
> > +);
> > +
> > +#endif /* !WOLFTPM2_NO_WRAPPER */
> > +
> >
> +/******************************************************************************/
> > +/* --- END TPM 2.0 Commands -- */
> >
> +/******************************************************************************/
> > diff --git a/configs/rpi_4_defconfig b/configs/rpi_4_defconfig
> > index 8362242b97f..22280d9b70e 100644
> > --- a/configs/rpi_4_defconfig
> > +++ b/configs/rpi_4_defconfig
> > @@ -69,4 +69,31 @@ CONFIG_SYS_WHITE_ON_BLACK=y
> > CONFIG_VIDEO_BCM2835=y
> > CONFIG_CONSOLE_SCROLL_LINES=10
> > CONFIG_PHYS_TO_BUS=y
> > -# CONFIG_HEXDUMP is not set
> > +# HEXDUMP enabled for unit tests
> > +
> > +# SPI support (hardware SPI - matches Linux tpm-slb9670 overlay)
> > +CONFIG_SPI=y
> > +CONFIG_DM_SPI=y
> > +CONFIG_BCM2835_SPI=y
> > +# CONFIG_SOFT_SPI is not set
> > +CONFIG_CMD_SPI=y
> > +
> > +# TPM and wolfTPM support
> > +CONFIG_TPM=y
> > +CONFIG_TPM_V2=y
> > +CONFIG_CMD_TPM=y
> > +CONFIG_TPM_WOLF=y
> > +# CONFIG_WOLFTPM_LINUX_DEV is not set
> > +CONFIG_WOLFTPM_SLB9672=y
> > +CONFIG_CMD_WOLFTPM=y
> > +
> > +# Logging (debug level to see log_debug output)
> > +CONFIG_LOG=y
> > +CONFIG_LOGLEVEL=7
> > +CONFIG_LOG_MAX_LEVEL=7
> > +CONFIG_LOG_DEFAULT_LEVEL=7
> > +
> > +# Unit testing support
> > +CONFIG_UNIT_TEST=y
> > +CONFIG_CONSOLE_RECORD=y
> > +CONFIG_HEXDUMP=y
> > diff --git a/doc/usage/cmd/wolftpm.rst b/doc/usage/cmd/wolftpm.rst
> > new file mode 100644
> > index 00000000000..4b5fb251b35
> > --- /dev/null
> > +++ b/doc/usage/cmd/wolftpm.rst
> > @@ -0,0 +1,694 @@
> > +wolfTPM Support For Das U-Boot
> > +==============================
> > +
> > +wolfTPM provides experimental support for U-Boot with the following key
> features:
> > +
> > +- Utilizes SOFT SPI driver in U-Boot for TPM communication
> > +- Implements TPM 2.0 driver functionality through its internal TIS layer
> > +- Provides native API access to all TPM 2.0 commands
> > +- Includes wrapper API for common TPM 2.0 operations
> > +- Supports two integration paths:
> > + - ``__linux__``: Uses existing tpm interface via tpm2_linux.c
> > + - ``__UBOOT__``: Direct SPI communication through tpm_io_uboot.c
> > +
> > +wolfTPM U-Boot Commands
> > +----------------------
> > +
> > +The following commands are available through the ``tpm2`` command
> (powered by wolfTPM):
> > +
> > +Basic Commands
> > +~~~~~~~~~~~~~~
> > +
> > +- ``help`` - Show help text
> > +- ``device [num device]`` - Show all devices or set the specified device
> > +- ``info`` - Show information about the TPM
> > +- ``state`` - Show internal state from the TPM (if available)
> > +- ``autostart`` - Initialize the TPM, perform a Startup(clear) and run
> a full selftest sequence
> > +- ``init`` - Initialize the software stack (must be first command)
> > +- ``startup <mode> [<op>]`` - Issue a TPM2_Startup command
> > + - ``<mode>``: TPM2_SU_CLEAR (reset state) or TPM2_SU_STATE (preserved
> state)
> > + - ``[<op>]``: optional shutdown with "off"
> > +- ``self_test <type>`` - Test TPM capabilities
> > + - ``<type>``: "full" (all tests) or "continue" (untested tests only)
> > +
> > +PCR Operations
> > +~~~~~~~~~~~~~~
> > +
> > +- ``pcr_extend <pcr> <digest_addr> [<digest_algo>]`` - Extend PCR with
> digest
> > +- ``pcr_read <pcr> <digest_addr> [<digest_algo>]`` - Read PCR to memory
> > +- ``pcr_allocate <algorithm> <on/off> [<password>]`` - Reconfig PCR
> bank algorithm
> > +- ``pcr_setauthpolicy | pcr_setauthvalue <pcr> <key> [<password>]`` -
> Change PCR access key
> > +- ``pcr_print`` - Print current PCR state
> > +
> > +Security Management
> > +~~~~~~~~~~~~~~~~~~~
> > +
> > +- ``clear <hierarchy>`` - Issue TPM2_Clear command
> > + - ``<hierarchy>``: TPM2_RH_LOCKOUT or TPM2_RH_PLATFORM
> > +- ``change_auth <hierarchy> <new_pw> [<old_pw>]`` - Change hierarchy
> password
> > + - ``<hierarchy>``: TPM2_RH_LOCKOUT, TPM2_RH_ENDORSEMENT,
> TPM2_RH_OWNER, or TPM2_RH_PLATFORM
> > +- ``dam_reset [<password>]`` - Reset internal error counter
> > +- ``dam_parameters <max_tries> <recovery_time> <lockout_recovery>
> [<password>]`` - Set DAM parameters
> > +- ``caps`` - Show TPM capabilities and info
> > +
> > +Firmware Management
> > +~~~~~~~~~~~~~~~~~~~
> > +
> > +- ``firmware_update <manifest_addr> <manifest_sz> <firmware_addr>
> <firmware_sz>`` - Update TPM firmware
> > +- ``firmware_cancel`` - Cancel TPM firmware update
> > +
> > +Infineon TPM Firmware Update Guide
> > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > +
> > +**WARNING: Firmware updates are risky. A failed update can brick your
> TPM.
> > +Only proceed if you have a valid reason to update (security patches,
> new features)
> > +and understand the risks.**
> > +
> > +The firmware update commands are for Infineon SLB9672/SLB9673 TPMs
> only. The process
> > +requires extracting manifest and firmware data from Infineon's combined
> ``.BIN`` file.
> > +
> > +**Prerequisites:**
> > +
> > +- Infineon firmware file (e.g., ``TPM20_16.13.17733.0_R1.BIN``)
> > +- wolfTPM's ``ifx_fw_extract`` tool (in
> ``lib/wolftpm/examples/firmware/``)
> > +- Your TPM's KeyGroupId (shown by ``tpm2 caps`` command)
> > +
> > +**Step 1: Get your TPM's KeyGroupId**
> > +
> > +Run ``tpm2 caps`` to find your TPM's KeyGroupId::
> > +
> > + U-Boot> tpm2 caps
> > + Mfg IFX (1), Vendor SLB9672, Fw 16.13 (0x4545), FIPS 140-2 1,
> CC-EAL4 1
> > + Operational mode: Normal TPM operational mode (0x0)
> > + KeyGroupId 0x5, FwCounter 1255 (255 same)
> > + ...
> > +
> > +In this example, KeyGroupId is ``0x5``.
> > +
> > +**Step 2: Build the extraction tool (on host machine)**
> > +
> > +::
> > +
> > + cd lib/wolftpm/examples/firmware
> > + gcc -o ifx_fw_extract ifx_fw_extract.c
> > +
> > +**Step 3: List available key groups in firmware file**
> > +
> > +::
> > +
> > + ./ifx_fw_extract TPM20_16.13.17733.0_R1.BIN
> > + Found group 00000005
> > +
> > +Verify your TPM's KeyGroupId matches one in the firmware file.
> > +
> > +**Step 4: Extract manifest and firmware data**
> > +
> > +Use your KeyGroupId (0x5 in this example)::
> > +
> > + ./ifx_fw_extract TPM20_16.13.17733.0_R1.BIN 0x5 manifest.bin
> firmware.bin
> > + Found group 00000005
> > + Chosen group found: 00000005
> > + Manifest size is 3229
> > + Data size is 925539
> > + Wrote 3229 bytes to manifest.bin
> > + Wrote 925539 bytes to firmware.bin
> > +
> > +**Step 5: Copy files to SD card**
> > +
> > +Copy ``manifest.bin`` and ``firmware.bin`` to your boot partition
> (FAT)::
> > +
> > + cp manifest.bin firmware.bin /Volumes/bootfs/ # macOS
> > + cp manifest.bin firmware.bin /boot/firmware/ # Linux
> > +
> > +**Step 6: Load files into memory**
> > +
> > +In U-Boot, load the files from SD card into RAM::
> > +
> > + U-Boot> fatload mmc 0:1 0x10000000 manifest.bin
> > + 3229 bytes read in 32 ms (97.7 KiB/s)
> > +
> > + U-Boot> fatload mmc 0:1 0x10100000 firmware.bin
> > + 925539 bytes read in 86 ms (10.3 MiB/s)
> > +
> > +**Step 7: Perform firmware update (CAUTION!)**
> > +
> > +Convert file sizes to hex:
> > +
> > +- manifest.bin: 3229 bytes = 0xC9D
> > +- firmware.bin: 925539 bytes = 0xE1F63
> > +
> > +Run the firmware update::
> > +
> > + U-Boot> tpm2 firmware_update 0x10000000 0xC9D 0x10100000 0xE1F63
> > + TPM2 Firmware Update
> > + Infineon Firmware Update Tool
> > + Manifest Address: 0x10000000 (size: 3229)
> > + Firmware Address: 0x10100000 (size: 925539)
> > + tpm2 init: rc = 0 (Success)
> > + Mfg IFX (1), Vendor SLB9672, Fw 16.13 (0x4545)
> > + Operational mode: Normal TPM operational mode (0x0)
> > + KeyGroupId 0x5, FwCounter 1255 (255 same)
> > + Firmware Update (normal mode):
> > + Mfg IFX (1), Vendor SLB9672, Fw 16.13 (0x4545)
> > + Operational mode: Normal TPM operational mode (0x0)
> > + KeyGroupId 0x5, FwCounter 1255 (255 same)
> > + tpm2 firmware_update: rc=0 (Success)
> > +
> > +**DO NOT power off or reset during the update!**
> > +
> > +**Step 8: Verify update**
> > +
> > +After the update completes, verify with::
> > +
> > + U-Boot> tpm2 caps
> > +
> > +The firmware version should show the new version.
> > +
> > +**Recovery Mode:**
> > +
> > +If the TPM enters recovery mode (opMode shows 0x02 or 0x8x), the
> firmware update
> > +command will automatically use recovery mode. You may need to run the
> update again
> > +to complete the process.
> > +
> > +Canceling a Firmware Update
> > +^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > +
> > +If an update is in progress and needs to be abandoned (opMode 0x01),
> use::
> > +
> > + U-Boot> tpm2 firmware_cancel
> > + tpm2 init: rc = 0 (Success)
> > + tpm2 firmware_cancel: rc=0 (Success)
> > +
> > +**IMPORTANT: After running firmware_cancel, you MUST reboot/power cycle
> the system
> > +before running any other TPM commands.** If you attempt to run commands
> without
> > +rebooting, you will get ``TPM_RC_REBOOT`` (error 304)::
> > +
> > + U-Boot> tpm2 firmware_update ...
> > + tpm2 init: rc = 304 (TPM_RC_REBOOT)
> > + Infineon firmware update failed 0x130: TPM_RC_REBOOT
> > +
> > +After rebooting, the TPM will return to normal operation and you can
> retry the
> > +firmware update or continue with normal TPM operations.
> > +
> > +**Note:** If no firmware update is in progress, ``firmware_cancel``
> returns
> > +``TPM_RC_COMMAND_CODE`` (0x143), which is expected and harmless::
> > +
> > + U-Boot> tpm2 firmware_cancel
> > + tpm2 firmware_cancel: rc=323 (TPM_RC_COMMAND_CODE)
> > +
> > +Enabling wolfTPM in U-Boot
> > +--------------------------
> > +
> > +Enable wolfTPM support in U-Boot by adding these options to your
> board's defconfig::
> > +
> > + CONFIG_TPM=y
> > + CONFIG_TPM_V2=y
> > + CONFIG_TPM_WOLF=y
> > + CONFIG_CMD_WOLFTPM=y
> > +
> > + if with __LINUX__:
> > + CONFIG_TPM_LINUX_DEV=y
> > +
> > +Or use ``make menuconfig`` and enable:
> > +
> > +Enabling Debug Output
> > +~~~~~~~~~~~~~~~~~~~~~
> > +
> > +wolfTPM commands use U-Boot's logging system (``log_debug()``). To
> enable debug
> > +output, you must first enable the logging subsystem in your board's
> defconfig::
> > +
> > + CONFIG_LOG=y
> > + CONFIG_LOG_MAX_LEVEL=7
> > + CONFIG_LOG_DEFAULT_LEVEL=7
> > +
> > +Or via ``make menuconfig``:
> > +
> > +- Console → Enable logging support
> > +- Console → Maximum log level to record = 7
> > +- Console → Default logging level to display = 7
> > +
> > +Log levels:
> > +- 7 = DEBUG (to show wolfTPM command debug output)
> > +
> > +**Note:** Without ``CONFIG_LOG=y``, the ``log level`` command will not
> exist
> > +and ``log_debug()`` calls will produce no output.
> > +
> > +wolfTPM Library Debug
> > +^^^^^^^^^^^^^^^^^^^^^
> > +
> > +For lower-level wolfTPM library debug output (TPM protocol messages),
> edit
> > +``include/configs/user_settings.h`` and uncomment::
> > +
> > + #define DEBUG_WOLFTPM /* Basic wolfTPM debug messages */
> > + #define WOLFTPM_DEBUG_VERBOSE /* Verbose debug messages */
> > + #define WOLFTPM_DEBUG_IO /* IO-level debug (SPI transfers) */
> > +
> > +After enabling, rebuild U-Boot::
> > +
> > + make clean
> > + make -j4
> > +
> > +Menuconfig Paths
> > +^^^^^^^^^^^^^^^^
> > +
> > +The following menuconfig paths are useful for wolfTPM:
> > +
> > +- Device Drivers → TPM → TPM 2.0 Support
> > +- Device Drivers → TPM → wolfTPM Support
> > +- Command line interface → Security commands → Enable wolfTPM commands
> > +- Console → Enable logging support (for ``log_debug()`` output)
> > +
> > +Building and Running wolfTPM with U-Boot using QEMU
> > +---------------------------------------------------
> > +
> > +To build and run wolfTPM with U-Boot using QEMU and a TPM simulator,
> follow these steps:
> > +
> > +1. Install swtpm::
> > +
> > + git clone https://github.com/stefanberger/swtpm.git
> > + cd swtpm
> > + ./autogen.sh
> > + make
> > +
> > +2. Build U-Boot::
> > +
> > + make distclean
> > + export CROSS_COMPILE=aarch64-linux-gnu-
> > + export ARCH=aarch64
> > + make qemu_arm64_defconfig
> > + make -j4
> > +
> > +3. Create TPM directory::
> > +
> > + mkdir -p /tmp/mytpm1
> > +
> > +4. Start swtpm (in first terminal)::
> > +
> > + swtpm socket --tpm2 --tpmstate dir=/tmp/mytpm1 --ctrl
> type=unixio,path=/tmp/mytpm1/swtpm-sock --log level=20
> > +
> > +5. Start QEMU (in second terminal)::
> > +
> > + qemu-system-aarch64 -machine virt -nographic -cpu cortex-a57 -bios
> u-boot.bin -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock -tpmdev
> emulator,id=tpm0,chardev=chrtpm -device tpm-tis-device,tpmdev=tpm0
> > +
> > +6. Example output::
> > +
> > + U-Boot 2025.07-rc1-ge15cbf232ddf-dirty (May 06 2025 - 16:25:56
> -0700)
> > + ...
> > + => tpm2 help
> > + tpm2 - Issue a TPMv2.x command
> > + Usage:
> > + tpm2 <command> [<arguments>]
> > + ...
> > + => tpm2 info
> > + tpm_tis at 0 v2.0: VendorID 0x1014, DeviceID 0x0001, RevisionID 0x01
> [open]
> > + => tpm2 startup TPM2_SU_CLEAR
> > + => tpm2 get_capability 0x6 0x20e 0x200 1
> > + Capabilities read from TPM:
> > + Property 0x6a2e45a9: 0x6c3646a9
> > + => tpm2 pcr_read 10 0x100000
> > + PCR #10 sha256 32 byte content (20 known updates):
> > + 20 25 73 0a 00 56 61 6c 75 65 3a 0a 00 23 23 20
> > + 4f 75 74 20 6f 66 20 6d 65 6d 6f 72 79 0a 00 23
> > +
> > +7. Example commands::
> > +
> > + => tpm2 info
> > + tpm_tis at 0 v2.0: VendorID 0x1014, DeviceID 0x0001, RevisionID 0x01
> [open]
> > + ...
> > + => tpm2 pcr_read 10 0x100000
> > + PCR #10 sha256 32 byte content (20 known updates):
> > + 20 25 73 0a 00 56 61 6c 75 65 3a 0a 00 23 23 20
> > + 4f 75 74 20 6f 66 20 6d 65 6d 6f 72 79 0a 00 23
> > +
> > +8. Exiting the QEMU:
> > + Press Ctrl-A followed by X
> > +
>
> The examples are nice!
>
> > +Testing wolfTPM
> > +---------------
> > +
> > +wolfTPM includes a comprehensive test suite based on the existing TPM2
> tests.
> > +The tests are located in:
> > +
> > +- ``test/cmd/wolftpm.c`` - C unit tests (based on ``test/dm/tpm.c`` and
> ``test/cmd/hash.c``)
> > +- ``test/py/tests/test_wolftpm.py`` - Python integration tests (based
> on ``test/py/tests/test_tpm2.py``)
> > +
> > +Running C Unit Tests
> > +~~~~~~~~~~~~~~~~~~~~
> > +
> > +The C unit tests use the U-Boot test framework and can be run in
> sandbox mode
> > +or on real hardware. To run all wolfTPM tests::
> > +
> > + # Build sandbox with tests enabled
> > + make sandbox_defconfig
> > + # Enable wolfTPM in menuconfig
> > + make menuconfig
> > + make -j4
> > +
> > + # Run U-Boot sandbox
> > + ./u-boot -T
> > +
> > + # In U-Boot sandbox, run the unit tests
> > + => ut cmd
> > +
> > +Individual tests can be run by name::
> > +
> > + => ut cmd cmd_test_wolftpm_autostart
> > + => ut cmd cmd_test_wolftpm_init
> > + => ut cmd cmd_test_wolftpm_self_test
> > + => ut cmd cmd_test_wolftpm_caps
> > + => ut cmd cmd_test_wolftpm_clear
> > + => ut cmd cmd_test_wolftpm_pcr_read
> > + => ut cmd cmd_test_wolftpm_pcr_extend
> > +
> > +Running Python Tests
> > +~~~~~~~~~~~~~~~~~~~~
> > +
> > +The Python tests require pytest and can be run against real hardware or
> QEMU
> > +with swtpm. First, ensure swtpm is running (see QEMU instructions
> above).
> > +
> > +To run all wolfTPM Python tests::
> > +
> > + # From the U-Boot root directory
> > + ./test/py/test.py --bd qemu_arm64 -k test_wolftpm
> > +
> > +To run individual Python tests::
> > +
> > + ./test/py/test.py --bd qemu_arm64 -k test_wolftpm_autostart
> > + ./test/py/test.py --bd qemu_arm64 -k test_wolftpm_caps
> > + ./test/py/test.py --bd qemu_arm64 -k test_wolftpm_pcr_read
> > +
> > +To skip wolfTPM tests (e.g., when no TPM hardware is available), set the
> > +environment variable in your board configuration::
> > +
> > + env__wolftpm_device_test_skip = True
> > +
> > +Running Tests Manually in QEMU
> > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > +
> > +You can also test wolfTPM commands manually in QEMU:
> > +
> > +1. Start swtpm::
> > +
> > + mkdir -p /tmp/mytpm
> > + swtpm socket --tpm2 --tpmstate dir=/tmp/mytpm \
> > + --ctrl type=unixio,path=/tmp/mytpm/swtpm-sock --log level=20
> > +
> > +2. Start QEMU with TPM::
> > +
> > + qemu-system-aarch64 -machine virt -cpu cortex-a57 -m 1024 \
> > + -bios u-boot.bin \
> > + -chardev socket,id=chrtpm,path=/tmp/mytpm/swtpm-sock \
> > + -tpmdev emulator,id=tpm0,chardev=chrtpm \
> > + -device tpm-tis-device,tpmdev=tpm0 \
> > + -nographic
> > +
> > +3. Run wolfTPM commands at the U-Boot prompt::
> > +
> > + => wolftpm autostart
> > + => wolftpm caps
> > + => wolftpm pcr_read 0 sha256
> > + => wolftpm pcr_print
> > + => wolftpm self_test full
> > + => wolftpm clear TPM2_RH_LOCKOUT
> > + => wolftpm dam_parameters 3 10 0
> > +
> > +Test Coverage
> > +~~~~~~~~~~~~~
> > +
> > +The test suite covers the following wolfTPM functionality:
> > +
> > ++---------------------------+------------------------------------------+
> > +| Test Name | Description |
> > ++===========================+==========================================+
> > +| wolftpm_autostart | TPM initialization and startup |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_init | TPM device initialization |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_self_test | Full TPM self-test |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_self_test_continue| Continue incomplete self-tests |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_caps | Read TPM capabilities |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_clear | Clear TPM state |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_pcr_read | Read PCR values |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_pcr_extend | Extend PCR with digest |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_pcr_print | Print all PCR values |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_pcr_allocate | Reconfigure PCR bank algorithm |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_dam_reset | Reset DAM counter |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_dam_parameters | Set DAM parameters |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_change_auth | Change hierarchy password |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_info | Display TPM info |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_state | Display TPM state |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_device | Show/set TPM device |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_startup_clear | TPM2_Startup with CLEAR mode |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_startup_state | TPM2_Startup with STATE mode |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_startup_shutdown | TPM2_Shutdown command |
> > ++---------------------------+------------------------------------------+
> > +| wolftpm_get_capability | Read TPM capabilities by property |
> > ++---------------------------+------------------------------------------+
> > +
> > +TODO: Commands Not Yet Tested
> > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > +
> > +The following commands are implemented in ``cmd/wolftpm.c`` but do not
> yet have
> > +test coverage due to special requirements:
> > +
> >
> ++---------------------------+------------------------------------------+------------------+
> > +| Command | Description
> | Notes |
> >
> ++===========================+==========================================+==================+
> > +| pcr_setauthpolicy | Set PCR authorization policy
> | Requires |
> > +| |
> | wolfCrypt |
> >
> ++---------------------------+------------------------------------------+------------------+
> > +| pcr_setauthvalue | Set PCR authorization value
> | Requires |
> > +| |
> | wolfCrypt |
> >
> ++---------------------------+------------------------------------------+------------------+
> > +| firmware_update | Update TPM firmware (Infineon only)
> | Requires |
> > +| |
> | Infineon HW |
> >
> ++---------------------------+------------------------------------------+------------------+
> > +| firmware_cancel | Cancel firmware update (Infineon only)
> | Requires |
> > +| |
> | Infineon HW |
> >
> ++---------------------------+------------------------------------------+------------------+
> > +
> > +**Note:** The ``pcr_setauthpolicy`` and ``pcr_setauthvalue`` commands
> require
> > +``WOLFTPM2_NO_WOLFCRYPT`` to be undefined (i.e., wolfCrypt must be
> enabled).
> > +The ``firmware_update`` and ``firmware_cancel`` commands require
> Infineon
> > +SLB9672/SLB9673 hardware.
> > +
> > +To add tests for these commands:
> > +
> > +1. Add C unit test in ``test/cmd/wolftpm.c``::
> > +
> > + static int cmd_test_wolftpm_<command>(struct unit_test_state *uts)
> > + {
> > + ut_assertok(run_command("wolftpm autostart", 0));
> > + ut_assertok(run_command("wolftpm <command> <args>", 0));
> > + return 0;
> > + }
> > + CMD_TEST(cmd_test_wolftpm_<command>, 0);
> > +
> > +2. Add Python test in ``test/py/tests/test_wolftpm.py``::
> > +
> > + @pytest.mark.buildconfigspec('tpm_wolf')
> > + def test_wolftpm_<command>(ubman):
> > + force_init(ubman)
> > + ubman.run_command('wolftpm <command> <args>')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +TODO: Testing on Raspberry Pi Hardware
> > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > +
> > +For testing with real TPM hardware (e.g., Infineon SLB9672 TPM HAT on
> Raspberry Pi):
> > +
> > +1. Build U-Boot for Raspberry Pi::
> > +
> > + make distclean
> > + export CROSS_COMPILE=aarch64-linux-gnu-
> > + export ARCH=aarch64
> > + make rpi_arm64_defconfig
> > + make -j$(nproc)
> > +
> > +2. Backup current boot configuration::
> > +
> > + sudo cp /boot/firmware/config.txt /boot/firmware/config.txt.backup
> > +
> > +3. Copy U-Boot to boot partition::
> > +
> > + sudo cp u-boot.bin /boot/firmware/
> > +
> > +4. Edit ``/boot/firmware/config.txt`` and add::
> > +
> > + # U-Boot for wolfTPM testing
> > + enable_uart=1
> > + kernel=u-boot.bin
> > + arm_64bit=1
> > +
> > +5. Connect serial console (recommended) - USB-to-serial adapter on GPIO
> 14/15
> > + (pins 8/10) at 115200 baud.
> > +
> > +6. Reboot and test at U-Boot prompt::
> > +
> > + U-Boot> tpm2 device
> > + U-Boot> tpm2 info
> > + U-Boot> tpm2 autostart
> > + U-Boot> tpm2 caps
> > + U-Boot> tpm2 pcr_read 0 0x1000000 SHA256
> > +
> > +7. To restore normal Linux boot::
> > +
> > + sudo cp /boot/firmware/config.txt.backup /boot/firmware/config.txt
> > + sudo reboot
> > +
> > +**Note:** The Raspberry Pi build uses GPIO-based soft SPI for TPM
> communication.
> > +Standard SPI0 pins are used: GPIO 11 (SCLK), GPIO 10 (MOSI), GPIO 9
> (MISO),
> > +GPIO 7 (CE1 for TPM). Adjust
> ``arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi`` if
> > +your TPM HAT uses different GPIO pins.
> > +
> > +TODO: Python Test Framework
> > +~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > +
> > +The Python tests in ``test/py/tests/test_wolftpm.py`` require
> additional setup
> > +for QEMU boards (external ``u-boot-test-flash``,
> ``u-boot-test-console``, etc.
> > +scripts). The C unit tests (``test/cmd/wolftpm.c``) provide equivalent
> coverage
> > +and work directly with ``ut cmd`` in U-Boot.
> > +
> > +**Status:** Python tests need verification with proper QEMU test
> infrastructure
> > +or deprecation in favor of C unit tests which are fully functional.
> > +
> > +Testing wolfTPM SPI Path in Sandbox
> > +-----------------------------------
> > +
> > +The sandbox build includes a TPM SPI emulator that tests the complete
> wolfTPM
> > +SPI communication path without requiring hardware. This validates the
> SPI HAL
> > +code path in ``lib/wolftpm/hal/tpm_io_uboot.c``.
> > +
> > +SPI Code Path
> > +~~~~~~~~~~~~~
> > +
> > +When testing in sandbox, the following code path is exercised::
> > +
> > + wolftpm commands (cmd/wolftpm.c)
> > + ↓
> > + wolfTPM library (lib/wolftpm/)
> > + ↓
> > + SPI HAL (lib/wolftpm/hal/tpm_io_uboot.c)
> > + ↓
> > + U-Boot SPI API (spi_get_bus_and_cs, spi_xfer)
> > + ↓
> > + Sandbox SPI Master (drivers/spi/sandbox_spi.c)
> > + ↓
> > + TPM SPI Emulator (drivers/tpm/tpm_spi_sandbox.c)
> > +
> > +The TPM SPI emulator implements the TPM TIS (Trusted Platform Module
> Interface
> > +Specification) over SPI protocol:
> > +
> > +- 4-byte SPI header: ``[R/W|len-1][0xD4][addr_hi][addr_lo]``
> > +- Wait-state handling with ready byte
> > +- TIS register emulation (ACCESS, STS, FIFO, DID/VID, RID)
> > +- TIS state machine (IDLE → READY → RECEPTION → COMPLETION)
> > +
> > +Building Sandbox with SPI Support
> > +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > +
> > +To build sandbox with TPM SPI emulator support::
> > +
> > + make sandbox_defconfig
> > + make -j$(nproc)
> > +
> > +The following configs are enabled by default in sandbox:
> > +
> > +- ``CONFIG_TPM=y``
> > +- ``CONFIG_TPM_V2=y``
> > +- ``CONFIG_TPM_WOLF=y``
> > +- ``CONFIG_CMD_WOLFTPM=y``
> > +- ``CONFIG_TPM2_SPI_SANDBOX=y``
> > +
> > +Running SPI Tests
> > +~~~~~~~~~~~~~~~~~
> > +
> > +**Important:** The sandbox TPM SPI device requires the ``-D`` flag to
> load the
> > +full device tree. Without this flag, the SPI bus will not be available.
> > +
> > +Run wolfTPM commands via SPI::
> > +
> > + # Build sandbox
> > + make sandbox_defconfig && make -j$(nproc)
> > +
> > + # Run with full device tree
> > + ./u-boot -D
> > +
> > + # At U-Boot prompt, test wolfTPM SPI path
> > + => wolftpm autostart
> > + => wolftpm caps
> > + => wolftpm info
> > + => wolftpm pcr_read 0 0x1000000 SHA256
> > + => wolftpm pcr_print
> > +
> > +Non-interactive testing::
> > +
> > + # Single command
> > + ./u-boot -D -c "wolftpm autostart"
> > +
> > + # Multiple commands
> > + ./u-boot -D -c "wolftpm autostart; wolftpm caps; wolftpm info"
> > +
> > +Expected output::
> > +
> > + TPM SPI initialized: bus 0, cs 1
> > + TPM2: Caps 0x30000697, Did 0x001d, Vid 0x15d1, Rid 0x36
> > + TPM2_Startup pass
> > + wolfTPM2_Reset complete
> > + TPM2_SelfTest pass
> > +
> > +Enabling Debug Output
> > +~~~~~~~~~~~~~~~~~~~~~
> > +
> > +To see SPI-level debug messages, enable logging before running::
> > +
> > + # At U-Boot prompt
> > + => log level 7
> > +
> > +Or enable in defconfig::
> > +
> > + CONFIG_LOG=y
> > + CONFIG_LOG_MAX_LEVEL=7
> > + CONFIG_LOG_DEFAULT_LEVEL=7
> > +
> > +For wolfTPM library-level SPI debug, edit
> ``include/configs/user_settings.h``::
> > +
> > + #define DEBUG_WOLFTPM
> > + #define WOLFTPM_DEBUG_IO /* Shows SPI transfer details */
> > +
> > +Device Tree Configuration
> > +~~~~~~~~~~~~~~~~~~~~~~~~~
> > +
> > +The sandbox SPI TPM is defined in ``arch/sandbox/dts/sandbox.dtsi``::
> > +
> > + &spi0 {
> > + tpm_spi: tpm at 1 {
> > + reg = <1>;
> > + compatible = "sandbox,tpm-spi";
> > + spi-max-frequency = <10000000>;
> > + sandbox,emul = <&tpm_spi_emul>;
> > + };
> > + };
> > +
> > + tpm_spi_emul: tpm-spi-emul {
> > + compatible = "sandbox,tpm-spi-emul";
> > + };
> > +
> > +The emulator driver is in ``drivers/tpm/tpm_spi_sandbox.c``.
> > diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c
> > index e5ebc3479fb..41bd07817aa 100644
> > --- a/drivers/mtd/spi/sandbox.c
> > +++ b/drivers/mtd/spi/sandbox.c
> > @@ -571,16 +571,28 @@ int sandbox_spi_get_emul(struct sandbox_state
> *state,
> >
> > info = &state->spi[busnum][cs];
> > if (!info->emul) {
> > - /* Use the same device tree node as the SPI flash device */
> > - debug("%s: busnum=%u, cs=%u: binding SPI flash emulation:
> ",
> > - __func__, busnum, cs);
> > - ret = sandbox_sf_bind_emul(state, busnum, cs, bus,
> > - dev_ofnode(slave), slave->name);
> > - if (ret) {
> > - debug("failed (err=%d)\n", ret);
> > - return ret;
> > + struct udevice *emul;
> > + ofnode node = dev_ofnode(slave);
> > +
> > + /* First check for sandbox,emul phandle property */
> > + ret = uclass_get_device_by_phandle(UCLASS_SPI_EMUL, slave,
> > + "sandbox,emul", &emul);
> > + if (!ret) {
> > + debug("%s: busnum=%u, cs=%u: using phandle
> emulator\n",
> > + __func__, busnum, cs);
> > + info->emul = emul;
> > + } else {
> > + /* Fall back to SPI flash emulation binding */
> > + debug("%s: busnum=%u, cs=%u: binding SPI flash
> emulation: ",
> > + __func__, busnum, cs);
> > + ret = sandbox_sf_bind_emul(state, busnum, cs, bus,
> > + node, slave->name);
> > + if (ret) {
> > + debug("failed (err=%d)\n", ret);
> > + return ret;
> > + }
> > + debug("OK\n");
> > }
> > - debug("OK\n");
> > }
> > *emulp = info->emul;
> >
> > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> > index 8c6c095a8cf..9625b1e073e 100644
> > --- a/drivers/spi/Kconfig
> > +++ b/drivers/spi/Kconfig
> > @@ -117,6 +117,15 @@ config ATMEL_SPI
> > many AT91 (ARM) chips. This driver can be used to access
> > the SPI Flash, such as AT25DF321.
> >
> > +config BCM2835_SPI
> > + bool "BCM2835/BCM2711 SPI driver"
> > + depends on ARCH_BCM283X
> > + help
> > + Enable the BCM2835/BCM2711 SPI controller driver. This driver
> > + can be used to access SPI devices on Raspberry Pi boards
> > + including Pi 3 and Pi 4. It uses the hardware SPI controller
> > + rather than GPIO bit-banging.
> > +
> > config BCM63XX_HSSPI
> > bool "BCM63XX HSSPI driver"
> > depends on (ARCH_BMIPS || ARCH_BCMBCA)
> > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> > index 0dc2d23e172..47a1c6194b1 100644
> > --- a/drivers/spi/Makefile
> > +++ b/drivers/spi/Makefile
> > @@ -27,6 +27,7 @@ obj-$(CONFIG_APPLE_SPI) += apple_spi.o
> > obj-$(CONFIG_ATH79_SPI) += ath79_spi.o
> > obj-$(CONFIG_ATMEL_QSPI) += atmel-quadspi.o
> > obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o
> > +obj-$(CONFIG_BCM2835_SPI) += bcm2835_spi.o
> > obj-$(CONFIG_BCM63XX_HSSPI) += bcm63xx_hsspi.o
> > obj-$(CONFIG_BCMBCA_HSSPI) += bcmbca_hsspi.o
> > obj-$(CONFIG_BCM63XX_SPI) += bcm63xx_spi.o
> > diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> > new file mode 100644
> > index 00000000000..c44c2a6ed3e
> > --- /dev/null
> > +++ b/drivers/spi/bcm2835_spi.c
>
> This is nice to have, but needs to be in its own patch so the RPI
> maintainers
> can review/ack it
>
> > @@ -0,0 +1,429 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * BCM2835/BCM2711 SPI controller driver for U-Boot
> > + *
> > + * Copyright (C) 2025 wolfSSL Inc.
> > + * Author: Aidan Garske <aidan at wolfssl.com>
> > + *
> > + * Based on Linux driver by Chris Boot, Martin Sperl, et al.
> > + */
> > +
> > +#include <dm.h>
> > +#include <errno.h>
> > +#include <log.h>
> > +#include <malloc.h>
> > +#include <spi.h>
> > +#include <asm/io.h>
> > +#include <asm/gpio.h>
> > +#include <dm/device_compat.h>
> > +#include <linux/delay.h>
> > +
> > +/* SPI register offsets */
> > +#define BCM2835_SPI_CS 0x00 /* Control and Status */
> > +#define BCM2835_SPI_FIFO 0x04 /* TX and RX FIFOs */
> > +#define BCM2835_SPI_CLK 0x08 /* Clock Divider */
> > +#define BCM2835_SPI_DLEN 0x0c /* Data Length */
> > +#define BCM2835_SPI_LTOH 0x10 /* LoSSI mode TOH */
> > +#define BCM2835_SPI_DC 0x14 /* DMA DREQ Controls */
> > +
> > +/* CS register bits */
> > +#define BCM2835_SPI_CS_LEN_LONG BIT(25)
> > +#define BCM2835_SPI_CS_DMA_LEN BIT(24)
> > +#define BCM2835_SPI_CS_CSPOL2 BIT(23)
> > +#define BCM2835_SPI_CS_CSPOL1 BIT(22)
> > +#define BCM2835_SPI_CS_CSPOL0 BIT(21)
> > +#define BCM2835_SPI_CS_RXF BIT(20)
> > +#define BCM2835_SPI_CS_RXR BIT(19)
> > +#define BCM2835_SPI_CS_TXD BIT(18)
> > +#define BCM2835_SPI_CS_RXD BIT(17)
> > +#define BCM2835_SPI_CS_DONE BIT(16)
> > +#define BCM2835_SPI_CS_LEN BIT(13)
> > +#define BCM2835_SPI_CS_REN BIT(12)
> > +#define BCM2835_SPI_CS_ADCS BIT(11)
> > +#define BCM2835_SPI_CS_INTR BIT(10)
> > +#define BCM2835_SPI_CS_INTD BIT(9)
> > +#define BCM2835_SPI_CS_DMAEN BIT(8)
> > +#define BCM2835_SPI_CS_TA BIT(7)
> > +#define BCM2835_SPI_CS_CSPOL BIT(6)
> > +#define BCM2835_SPI_CS_CLEAR_RX BIT(5)
> > +#define BCM2835_SPI_CS_CLEAR_TX BIT(4)
> > +#define BCM2835_SPI_CS_CPOL BIT(3)
> > +#define BCM2835_SPI_CS_CPHA BIT(2)
> > +#define BCM2835_SPI_CS_CS_10 BIT(1)
> > +#define BCM2835_SPI_CS_CS_01 BIT(0)
> > +
> > +/* Default clock rate - 250 MHz for Pi 4 */
> > +#define BCM2835_SPI_DEFAULT_CLK 250000000
> > +
> > +struct bcm2835_spi_priv {
> > + void __iomem *regs;
> > + u32 clk_hz;
> > + u32 cs_reg; /* Cached CS register value */
> > + u32 speed_hz;
> > + u8 mode;
> > + struct gpio_desc cs_gpio;
> > + int cs_gpio_valid;
> > + int cs_asserted; /* Track if CS should stay asserted between
> transfers */
> > +};
> > +
> > +struct bcm2835_spi_plat {
> > + fdt_addr_t base;
> > + u32 clk_hz;
> > +};
> > +
> > +static inline u32 bcm2835_spi_readl(struct bcm2835_spi_priv *priv, u32
> reg)
> > +{
> > + return readl(priv->regs + reg);
> > +}
> > +
> > +static inline void bcm2835_spi_writel(struct bcm2835_spi_priv *priv,
> > + u32 reg, u32 val)
> > +{
> > + writel(val, priv->regs + reg);
> > +}
> > +
> > +static void bcm2835_spi_reset(struct bcm2835_spi_priv *priv)
> > +{
> > + /* Clear FIFOs and disable SPI */
> > + bcm2835_spi_writel(priv, BCM2835_SPI_CS,
> > + BCM2835_SPI_CS_CLEAR_RX |
> BCM2835_SPI_CS_CLEAR_TX);
> > +}
> > +
> > +/* GPIO base for software CS control */
> > +static void __iomem *g_gpio_base = (void __iomem *)0xFE200000;
> > +
> > +/* Software CS control - assert (LOW = active) */
> > +static void bcm2835_spi_cs_assert(int cs_pin)
> > +{
> > + /* GPCLR0 - clear pin (drive LOW) */
> > + writel(1 << cs_pin, g_gpio_base + 0x28);
> > +}
> > +
> > +/* Software CS control - deassert (HIGH = inactive) */
> > +static void bcm2835_spi_cs_deassert(int cs_pin)
> > +{
> > + /* GPSET0 - set pin (drive HIGH) */
> > + writel(1 << cs_pin, g_gpio_base + 0x1C);
> > +}
> > +
> > +static int bcm2835_spi_xfer(struct udevice *dev, unsigned int bitlen,
> > + const void *dout, void *din, unsigned long
> flags)
> > +{
> > + struct udevice *bus = dev_get_parent(dev);
> > + struct bcm2835_spi_priv *priv = dev_get_priv(bus);
> > + const u8 *tx = dout;
> > + u8 *rx = din;
> > + u32 len = bitlen / 8;
> > + u32 cs_reg;
> > + u32 tx_count = 0, rx_count = 0;
> > + int timeout;
> > + int cs = spi_chip_select(dev); /* Get chip select from slave
> device */
> > + int cs_pin = (cs == 0) ? 8 : 7; /* CS0=GPIO8, CS1=GPIO7 */
> > + u32 stat;
> > +
> > + if (bitlen == 0) {
> > + /* Handle CS-only operations (deassert) */
> > + if (flags & SPI_XFER_END) {
> > + bcm2835_spi_cs_deassert(cs_pin);
> > + priv->cs_asserted = 0;
> > + }
> > + return 0;
> > + }
> > +
> > + if (bitlen % 8) {
> > + dev_err(dev, "Non-byte-aligned transfer not supported\n");
> > + return -EINVAL;
> > + }
> > +
> > + /*
> > + * SOFTWARE GPIO CHIP SELECT - like Linux driver
> > + * Don't use hardware CS bits - set to 0 (unused)
> > + */
> > + cs_reg = priv->cs_reg & ~(BCM2835_SPI_CS_CS_10 |
> BCM2835_SPI_CS_CS_01);
> > +
> > + /* Assert CS at start of transaction (SPI_XFER_BEGIN) */
> > + if (flags & SPI_XFER_BEGIN) {
> > + bcm2835_spi_cs_assert(cs_pin);
> > + priv->cs_asserted = 1;
> > + udelay(1); /* CS setup time */
> > + }
> > +
> > + /* Clear FIFOs for new transaction */
> > + if (flags & SPI_XFER_BEGIN) {
> > + bcm2835_spi_writel(priv, BCM2835_SPI_CS,
> > + cs_reg | BCM2835_SPI_CS_CLEAR_RX |
> > + BCM2835_SPI_CS_CLEAR_TX);
> > + udelay(1);
> > + }
> > +
> > + /* Start transfer with TA=1 (but CS is controlled by GPIO, not
> hardware) */
> > + bcm2835_spi_writel(priv, BCM2835_SPI_CS, cs_reg |
> BCM2835_SPI_CS_TA);
> > +
> > + /* Poll for completion - transfer byte by byte */
> > + timeout = 100000;
> > + while ((tx_count < len || rx_count < len) && timeout > 0) {
> > + stat = bcm2835_spi_readl(priv, BCM2835_SPI_CS);
> > +
> > + /* TX FIFO not full - send next byte */
> > + while ((stat & BCM2835_SPI_CS_TXD) && tx_count < len) {
> > + u8 byte = tx ? tx[tx_count] : 0;
> > + bcm2835_spi_writel(priv, BCM2835_SPI_FIFO, byte);
> > + tx_count++;
> > + stat = bcm2835_spi_readl(priv, BCM2835_SPI_CS);
> > + }
> > +
> > + /* RX FIFO has data - read it */
> > + while ((stat & BCM2835_SPI_CS_RXD) && rx_count < len) {
> > + u8 byte = bcm2835_spi_readl(priv, BCM2835_SPI_FIFO) & 0xff;
> > + if (rx)
> > + rx[rx_count] = byte;
> > + rx_count++;
> > + stat = bcm2835_spi_readl(priv, BCM2835_SPI_CS);
> > + }
> > +
> > + timeout--;
> > + }
> > +
> > + /* Wait for DONE */
> > + timeout = 10000;
> > + while (!(bcm2835_spi_readl(priv, BCM2835_SPI_CS) &
> BCM2835_SPI_CS_DONE) &&
> > + timeout > 0) {
> > + udelay(1);
> > + timeout--;
> > + }
> > +
> > + /* Read any remaining RX data from FIFO */
> > + while (bcm2835_spi_readl(priv, BCM2835_SPI_CS) &
> BCM2835_SPI_CS_RXD) {
> > + u8 byte = bcm2835_spi_readl(priv, BCM2835_SPI_FIFO) & 0xff;
> > + if (rx && rx_count < len)
> > + rx[rx_count++] = byte;
> > + }
> > +
> > + /* Clear TA to complete this transfer (doesn't affect GPIO CS) */
> > + bcm2835_spi_writel(priv, BCM2835_SPI_CS, cs_reg);
> > +
> > + /*
> > + * SOFTWARE GPIO CHIP SELECT control:
> > + * - SPI_XFER_END: deassert CS (GPIO HIGH)
> > + * - No END flag: keep CS asserted for next transfer
> > + */
> > + if (flags & SPI_XFER_END) {
> > + bcm2835_spi_cs_deassert(cs_pin);
> > + priv->cs_asserted = 0;
> > + } else {
> > + /* Keep CS asserted for next transfer (e.g., wait state
> polling) */
> > + priv->cs_asserted = 1;
> > + }
> > +
> > + if (timeout == 0) {
> > + bcm2835_spi_cs_deassert(cs_pin); /* Make sure CS is released */
> > + return -ETIMEDOUT;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int bcm2835_spi_set_speed(struct udevice *bus, uint speed)
> > +{
> > + struct bcm2835_spi_priv *priv = dev_get_priv(bus);
> > + u32 cdiv;
> > +
> > + if (speed == 0)
> > + speed = 1000000; /* Default 1 MHz */
> > +
> > + priv->speed_hz = speed;
> > +
> > + /* Calculate clock divider */
> > + if (speed >= priv->clk_hz / 2) {
> > + cdiv = 2; /* Fastest possible */
> > + } else {
> > + cdiv = (priv->clk_hz + speed - 1) / speed;
> > + cdiv += (cdiv & 1); /* Must be even */
> > + if (cdiv >= 65536)
> > + cdiv = 0; /* Slowest: clk/65536 */
> > + }
> > +
> > + bcm2835_spi_writel(priv, BCM2835_SPI_CLK, cdiv);
> > +
> > + return 0;
> > +}
> > +
> > +static int bcm2835_spi_set_mode(struct udevice *bus, uint mode)
> > +{
> > + struct bcm2835_spi_priv *priv = dev_get_priv(bus);
> > + u32 cs_reg = 0;
> > +
> > + priv->mode = mode;
> > +
> > + /* Set clock polarity and phase */
> > + if (mode & SPI_CPOL)
> > + cs_reg |= BCM2835_SPI_CS_CPOL;
> > + if (mode & SPI_CPHA)
> > + cs_reg |= BCM2835_SPI_CS_CPHA;
> > +
> > + /* CS bits will be set in xfer based on slave's chip select */
> > + priv->cs_reg = cs_reg;
> > +
> > + return 0;
> > +}
> > +
> > +static int bcm2835_spi_claim_bus(struct udevice *dev)
> > +{
> > + return 0;
> > +}
> > +
> > +static int bcm2835_spi_release_bus(struct udevice *dev)
> > +{
> > + return 0;
> > +}
> > +
> > +/* Setup GPIO pins for SPI0 with SOFTWARE chip select */
> > +static void bcm2835_spi_setup_gpio(void)
> > +{
> > + u32 val;
> > +
> > + /*
> > + * SPI0 pin configuration:
> > + * GPIO7 (CE1) - OUTPUT (software CS) - GPFSEL0 bits 23:21 = 001
> > + * GPIO8 (CE0) - OUTPUT (software CS) - GPFSEL0 bits 26:24 = 001
> > + * GPIO9 (MISO) - ALT0 (SPI) - GPFSEL0 bits 29:27 = 100
> > + * GPIO10 (MOSI) - ALT0 (SPI) - GPFSEL1 bits 2:0 = 100
> > + * GPIO11 (SCLK) - ALT0 (SPI) - GPFSEL1 bits 5:3 = 100
> > + */
> > +
> > + /* Set GPIO7, GPIO8 to OUTPUT, GPIO9 to ALT0 in GPFSEL0 */
> > + val = readl(g_gpio_base + 0x00);
> > + val &= ~((7 << 21) | (7 << 24) | (7 << 27)); /* Clear GPIO7,8,9 */
> > + val |= (1 << 21); /* GPIO7 = OUTPUT (001) */
> > + val |= (1 << 24); /* GPIO8 = OUTPUT (001) */
> > + val |= (4 << 27); /* GPIO9 = ALT0 (100) for MISO */
> > + writel(val, g_gpio_base + 0x00);
> > +
> > + /* Set GPIO10, GPIO11 to ALT0 in GPFSEL1 */
> > + val = readl(g_gpio_base + 0x04);
> > + val &= ~((7 << 0) | (7 << 3)); /* Clear GPIO10,11 */
> > + val |= (4 << 0); /* GPIO10 = ALT0 (100) for MOSI */
> > + val |= (4 << 3); /* GPIO11 = ALT0 (100) for SCLK */
> > + writel(val, g_gpio_base + 0x04);
> > +
> > + /* Deassert both CS lines (HIGH = inactive) */
> > + bcm2835_spi_cs_deassert(7); /* CE1 */
> > + bcm2835_spi_cs_deassert(8); /* CE0 */
> > +}
> > +
> > +/* TPM Reset via GPIO4 and GPIO24 */
> > +static void bcm2835_spi_tpm_reset(void)
> > +{
> > + void __iomem *gpio_base = (void __iomem *)0xFE200000;
> > + u32 val;
> > +
> > + /* Set GPIO4 as output (GPFSEL0, bits 14:12) */
> > + val = readl(gpio_base + 0x00); /* GPFSEL0 */
> > + val &= ~(7 << 12); /* Clear bits 14:12 for GPIO4 */
> > + val |= (1 << 12); /* Set to output */
> > + writel(val, gpio_base + 0x00);
> > +
> > + /* Set GPIO24 as output (GPFSEL2, bits 14:12) */
> > + val = readl(gpio_base + 0x08); /* GPFSEL2 */
> > + val &= ~(7 << 12); /* Clear bits 14:12 for GPIO24 */
> > + val |= (1 << 12); /* Set to output */
> > + writel(val, gpio_base + 0x08);
> > +
> > + /* Assert reset on BOTH pins (LOW) */
> > + writel((1 << 4) | (1 << 24), gpio_base + 0x28); /* GPCLR0 */
> > + mdelay(100);
> > +
> > + /* Release reset on BOTH pins (HIGH) */
> > + writel((1 << 4) | (1 << 24), gpio_base + 0x1C); /* GPSET0 */
> > + mdelay(150); /* Wait for TPM to initialize */
> > +}
> > +
> > +static int bcm2835_spi_probe(struct udevice *bus)
> > +{
> > + struct bcm2835_spi_plat *plat = dev_get_plat(bus);
> > + struct bcm2835_spi_priv *priv = dev_get_priv(bus);
> > + int ret;
> > +
> > + priv->regs = (void __iomem *)plat->base;
> > + priv->clk_hz = plat->clk_hz ? plat->clk_hz :
> BCM2835_SPI_DEFAULT_CLK;
> > +
> > + /* Setup GPIO pins for SPI0 (ALT0 function) */
> > + bcm2835_spi_setup_gpio();
> > +
> > + /* Reset TPM before using SPI */
> > + bcm2835_spi_tpm_reset();
> > +
> > + /* Try to get CS GPIO from device tree */
> > + ret = gpio_request_by_name(bus, "cs-gpios", 0, &priv->cs_gpio,
> > + GPIOD_IS_OUT | GPIOD_ACTIVE_LOW);
> > + if (ret == 0) {
> > + priv->cs_gpio_valid = 1;
> > + /* Deassert CS initially */
> > + dm_gpio_set_value(&priv->cs_gpio, 1);
> > + } else {
> > + priv->cs_gpio_valid = 0;
> > + }
> > +
> > + /* Reset the SPI controller */
> > + bcm2835_spi_reset(priv);
> > +
> > + /* Set default speed and mode */
> > + bcm2835_spi_set_speed(bus, 1000000); /* 1 MHz default */
> > + bcm2835_spi_set_mode(bus, SPI_MODE_0);
> > +
> > + return 0;
> > +}
> > +
> > +static int bcm2835_spi_of_to_plat(struct udevice *bus)
> > +{
> > + struct bcm2835_spi_plat *plat = dev_get_plat(bus);
> > + fdt_addr_t addr;
> > +
> > + addr = dev_read_addr(bus);
> > + if (addr == FDT_ADDR_T_NONE) {
> > + dev_err(bus, "Failed to get SPI base address\n");
> > + return -EINVAL;
> > + }
> > +
> > + /*
> > + * On BCM2711 (Pi 4), the device tree often uses VideoCore bus
> addresses
> > + * which start with 0x7E. The ARM needs to access these via the ARM
> > + * peripheral base at 0xFE000000.
> > + */
> > + if ((addr & 0xFF000000) == 0x7E000000) {
> > + addr = (addr & 0x00FFFFFF) | 0xFE000000;
> > + }
> > +
> > + plat->base = addr;
> > +
> > + /* Try to get clock rate from device tree */
> > + plat->clk_hz = dev_read_u32_default(bus, "clock-frequency",
> > + BCM2835_SPI_DEFAULT_CLK);
> > +
> > + return 0;
> > +}
> > +
> > +static const struct dm_spi_ops bcm2835_spi_ops = {
> > + .claim_bus = bcm2835_spi_claim_bus,
> > + .release_bus = bcm2835_spi_release_bus,
> > + .xfer = bcm2835_spi_xfer,
> > + .set_speed = bcm2835_spi_set_speed,
> > + .set_mode = bcm2835_spi_set_mode,
> > +};
> > +
> > +static const struct udevice_id bcm2835_spi_ids[] = {
> > + { .compatible = "brcm,bcm2835-spi" },
> > + { .compatible = "brcm,bcm2711-spi" },
> > + { }
> > +};
> > +
> > +U_BOOT_DRIVER(bcm2835_spi) = {
> > + .name = "bcm2835_spi",
> > + .id = UCLASS_SPI,
> > + .of_match = bcm2835_spi_ids,
> > + .ops = &bcm2835_spi_ops,
> > + .of_to_plat = bcm2835_spi_of_to_plat,
> > + .plat_auto = sizeof(struct bcm2835_spi_plat),
> > + .priv_auto = sizeof(struct bcm2835_spi_priv),
> > + .probe = bcm2835_spi_probe,
> > +};
> > diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig
> > index 219ea606b50..d4694946b94 100644
> > --- a/drivers/tpm/Kconfig
> > +++ b/drivers/tpm/Kconfig
> > @@ -158,6 +158,14 @@ config TPM2_TIS_SANDBOX
> > such as basic configuration, PCR extension and PCR read. Extended
> > functionalities are not implemented.
> >
> > +config TPM2_SPI_SANDBOX
> > + bool "Enable sandbox TPM SPI emulator"
> > + depends on TPM_V2 && SANDBOX && DM_SPI
> > + help
> > + This driver emulates a TPM connected via SPI for sandbox testing.
> > + It implements the TPM TIS SPI protocol and can be used to test
> > + wolfTPM SPI HAL code without physical hardware.
> > +
> > config TPM2_TIS_SPI
> > bool "Enable support for TPMv2.x SPI chips"
> > depends on TPM_V2 && DM_SPI
> > @@ -200,6 +208,34 @@ config TPM2_EVENT_LOG_SIZE
> > allocated twice. One for the eventlog it self and one for the
> > configuration table that is required from the TCG2 spec
> >
> > +config WOLFTPM_LINUX_DEV
> > + bool "Use device-level TPM interface (bypass wolfTPM TIS layer)"
> > + depends on TPM_V2 && TPM_WOLF
> > + default y
> > + help
> > + Enable wolfTPM to use the underlying TPM driver instead of its own
> > + TIS (TPM Interface Specification) layer. On U-Boot, this uses the
> > + U-Boot TPM driver model (tpm_xfer). On Linux, this uses /dev/tpm0.
> > + This is the recommended setting for U-Boot.
> > +
> > +config WOLFTPM_SLB9672
> > + bool "Enable support for Infineon SLB9672 TPM"
> > + depends on TPM_V2 && TPM_WOLF
> > + help
> > + Enable support for Infineon SLB9672 TPM features in wolfTPM.
> > +
> > +config WOLFTPM_SLB9673
> > + bool "Enable support for Infineon SLB9673 TPM"
> > + depends on TPM_V2 && TPM_WOLF
> > + help
> > + Enable support for Infineon SLB9673 TPM features in wolfTPM.
> > +
> > +config WOLFTPM_FIRMWARE_UPGRADE
> > + bool "Enable firmware upgrade support for wolfTPM"
> > + depends on TPM_V2 && TPM_WOLF
> > + help
> > + Enable support for Infineon TPM firmware upgrade commands in
> wolfTPM.
> > +
> > endif # TPM_V2
> >
> > endmenu
> > diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile
> > index b83ce703ec0..39de454cacf 100644
> > --- a/drivers/tpm/Makefile
> > +++ b/drivers/tpm/Makefile
> > @@ -10,7 +10,16 @@ obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o
> sandbox_common.o
> >
> > obj-$(CONFIG_$(PHASE_)TPM2_CR50_I2C) += cr50_i2c.o
> > obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o sandbox_common.o
> > +obj-$(CONFIG_TPM2_SPI_SANDBOX) += tpm_spi_sandbox.o
> > obj-$(CONFIG_TPM2_TIS_SPI) += tpm2_tis_core.o tpm2_tis_spi.o
> > obj-$(CONFIG_TPM2_TIS_I2C) += tpm2_tis_core.o tpm2_tis_i2c.o
> > obj-$(CONFIG_TPM2_FTPM_TEE) += tpm2_ftpm_tee.o
> > obj-$(CONFIG_TPM2_MMIO) += tpm2_tis_core.o tpm2_tis_mmio.o
> > +
> > +# wolfTPM helper functions
> > +ifeq ($(CONFIG_TPM_WOLF),y)
> > +ccflags-y += -Ilib/wolftpm \
> > + -Iinclude/configs \
> > + -DWOLFTPM_USER_SETTINGS
> > +obj-y += wolftpm_common.o
> > +endif
> > diff --git a/drivers/tpm/tpm_spi_sandbox.c
> b/drivers/tpm/tpm_spi_sandbox.c
> > new file mode 100644
> > index 00000000000..694c5d721f0
> > --- /dev/null
> > +++ b/drivers/tpm/tpm_spi_sandbox.c
>
> Same for this one
>
> > @@ -0,0 +1,410 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Sandbox TPM SPI Emulator
> > + *
> > + * Copyright (c) 2025 wolfSSL Inc.
> > + * Author: Aidan Garske <aidan at wolfssl.com>
> > + *
> > + * Emulates TPM TIS SPI protocol for testing wolfTPM SPI HAL
> > + * without hardware. Wraps the existing sandbox TPM2 state machine.
> > + */
> > +
> > +#include <dm.h>
> > +#include <log.h>
> > +#include <spi.h>
> > +#include <spi_flash.h>
> > +#include <asm/spi.h>
> > +#include <asm/state.h>
> > +#include <linux/bitops.h>
> > +
> > +/* TIS register addresses (locality 0) */
> > +#define TPM_ACCESS_REG 0x0000
> > +#define TPM_INT_ENABLE_REG 0x0008
> > +#define TPM_INTF_CAPS_REG 0x0014
> > +#define TPM_STS_REG 0x0018
> > +#define TPM_DATA_FIFO_REG 0x0024
> > +#define TPM_DID_VID_REG 0x0F00
> > +#define TPM_RID_REG 0x0F04
> > +
> > +/* TIS access register bits */
> > +#define TPM_ACCESS_VALID 0x80
> > +#define TPM_ACCESS_ACTIVE_LOCALITY 0x20
> > +#define TPM_ACCESS_REQUEST_PENDING 0x04
> > +#define TPM_ACCESS_REQUEST_USE 0x02
> > +
> > +/* TIS status register bits */
> > +#define TPM_STS_VALID 0x80
> > +#define TPM_STS_COMMAND_READY 0x40
> > +#define TPM_STS_GO 0x20
> > +#define TPM_STS_DATA_AVAIL 0x10
> > +#define TPM_STS_DATA_EXPECT 0x08
> > +
> > +/* Interface capabilities */
> > +#define TPM_INTF_CAPS_VALUE 0x30000697 /* Typical Infineon value */
> > +
> > +/* Device/Vendor ID - Infineon SLB9670 */
> > +#define TPM_DID_VID_VALUE 0x001D15D1
> > +
> > +/* Revision ID */
> > +#define TPM_RID_VALUE 0x36
> > +
> > +/* Maximum buffer sizes */
> > +#define TPM_CMD_BUF_SIZE 4096
> > +#define TPM_RSP_BUF_SIZE 4096
> > +#define MAX_SPI_FRAMESIZE 64
> > +
> > +/* TPM TIS SPI protocol states */
> > +enum tpm_spi_state {
> > + TPM_SPI_IDLE,
> > + TPM_SPI_HEADER, /* Receiving 4-byte header */
> > + TPM_SPI_WAIT_STATE, /* Sending wait state bytes */
> > + TPM_SPI_DATA, /* Transfer data */
> > +};
> > +
> > +/* TIS state machine */
> > +enum tpm_tis_state {
> > + TIS_IDLE,
> > + TIS_READY, /* Ready to receive command */
> > + TIS_RECEPTION, /* Receiving command data */
> > + TIS_EXECUTION, /* Executing command */
> > + TIS_COMPLETION, /* Response available */
> > +};
> > +
> > +struct sandbox_tpm_spi {
> > + /* SPI protocol state */
> > + enum tpm_spi_state spi_state;
> > + u8 header[4];
> > + int header_pos;
> > + bool is_read;
> > + u32 addr;
> > + int xfer_len;
> > + int data_pos;
> > +
> > + /* TIS state */
> > + enum tpm_tis_state tis_state;
> > + u8 access_reg;
> > + u32 sts_reg;
> > + u32 intf_caps;
> > +
> > + /* Command/response buffers */
> > + u8 cmd_buf[TPM_CMD_BUF_SIZE];
> > + int cmd_len;
> > + int cmd_pos;
> > + u8 rsp_buf[TPM_RSP_BUF_SIZE];
> > + int rsp_len;
> > + int rsp_pos;
> > +
> > + /* Burst count for status register */
> > + u16 burst_count;
> > +};
> > +
> > +/*
> > + * Parse TIS SPI header
> > + * Format: [R/W|len-1][0xD4][addr_hi][addr_lo]
> > + * Bit 7 of byte 0: 1=read, 0=write
> > + * Bits 5:0 of byte 0: transfer length - 1
> > + */
> > +static void parse_spi_header(struct sandbox_tpm_spi *priv)
> > +{
> > + priv->is_read = (priv->header[0] & 0x80) != 0;
> > + priv->xfer_len = (priv->header[0] & 0x3F) + 1;
> > + priv->addr = (priv->header[2] << 8) | priv->header[3];
> > + priv->data_pos = 0;
> > +}
> > +
> > +/*
> > + * Read from TIS register
> > + */
> > +static u8 tis_reg_read(struct sandbox_tpm_spi *priv, u32 addr)
> > +{
> > + u32 reg = addr & 0x0FFF; /* Mask off locality bits */
> > +
> > + switch (reg) {
> > + case TPM_ACCESS_REG:
> > + return priv->access_reg;
> > +
> > + case TPM_STS_REG:
> > + case TPM_STS_REG + 1:
> > + case TPM_STS_REG + 2:
> > + case TPM_STS_REG + 3: {
> > + int byte_off = reg - TPM_STS_REG;
> > + u32 sts = priv->sts_reg;
> > +
> > + /* Update burst count in status */
> > + sts |= ((u32)priv->burst_count << 8);
> > + return (sts >> (byte_off * 8)) & 0xFF;
> > + }
> > +
> > + case TPM_INTF_CAPS_REG:
> > + case TPM_INTF_CAPS_REG + 1:
> > + case TPM_INTF_CAPS_REG + 2:
> > + case TPM_INTF_CAPS_REG + 3: {
> > + int byte_off = reg - TPM_INTF_CAPS_REG;
> > +
> > + return (priv->intf_caps >> (byte_off * 8)) & 0xFF;
> > + }
> > +
> > + case TPM_DID_VID_REG:
> > + case TPM_DID_VID_REG + 1:
> > + case TPM_DID_VID_REG + 2:
> > + case TPM_DID_VID_REG + 3: {
> > + int byte_off = reg - TPM_DID_VID_REG;
> > +
> > + return (TPM_DID_VID_VALUE >> (byte_off * 8)) & 0xFF;
> > + }
> > +
> > + case TPM_RID_REG:
> > + return TPM_RID_VALUE;
> > +
> > + default:
> > + /*
> > + * Handle FIFO reads - the FIFO can be accessed at any
> address
> > + * from 0x0024 up to 0x0F00 for multi-byte transfers.
> > + */
> > + if (reg >= TPM_DATA_FIFO_REG && reg < TPM_DID_VID_REG) {
> > + if (priv->tis_state == TIS_COMPLETION &&
> > + priv->rsp_pos < priv->rsp_len) {
> > + u8 data = priv->rsp_buf[priv->rsp_pos++];
> > +
> > + /* Update status when all data read */
> > + if (priv->rsp_pos >= priv->rsp_len) {
> > + priv->sts_reg &=
> ~TPM_STS_DATA_AVAIL;
> > + priv->sts_reg |=
> TPM_STS_COMMAND_READY;
> > + priv->tis_state = TIS_READY;
> > + }
> > + return data;
> > + }
> > + return 0xFF;
> > + }
> > + return 0xFF;
> > + }
> > +}
> > +
> > +/*
> > + * Write to TIS register
> > + */
> > +static void tis_reg_write(struct sandbox_tpm_spi *priv, u32 addr, u8
> value)
> > +{
> > + u32 reg = addr & 0x0FFF;
> > +
> > + switch (reg) {
> > + case TPM_ACCESS_REG:
> > + if (value & TPM_ACCESS_REQUEST_USE) {
> > + /* Request locality */
> > + priv->access_reg |= TPM_ACCESS_ACTIVE_LOCALITY;
> > + priv->access_reg |= TPM_ACCESS_VALID;
> > + }
> > + break;
> > +
> > + case TPM_STS_REG:
> > + if (value & TPM_STS_COMMAND_READY) {
> > + /* Abort current command and go to ready state */
> > + priv->tis_state = TIS_READY;
> > + priv->cmd_len = 0;
> > + priv->cmd_pos = 0;
> > + priv->rsp_len = 0;
> > + priv->rsp_pos = 0;
> > + priv->sts_reg = TPM_STS_VALID |
> TPM_STS_COMMAND_READY;
> > + priv->burst_count = MAX_SPI_FRAMESIZE;
> > + }
> > + if (value & TPM_STS_GO) {
> > + /* Execute command */
> > + if (priv->tis_state == TIS_RECEPTION &&
> > + priv->cmd_len > 0) {
> > + /*
> > + * Generate a simple success response.
> > + * A full implementation would call the
> > + * sandbox TPM2 state machine here.
> > + */
> > + priv->rsp_buf[0] = 0x80; /*
> TPM_ST_NO_SESSIONS */
> > + priv->rsp_buf[1] = 0x01;
> > + priv->rsp_buf[2] = 0x00; /* Response
> size: 10 */
> > + priv->rsp_buf[3] = 0x00;
> > + priv->rsp_buf[4] = 0x00;
> > + priv->rsp_buf[5] = 0x0A;
> > + priv->rsp_buf[6] = 0x00; /*
> TPM_RC_SUCCESS */
> > + priv->rsp_buf[7] = 0x00;
> > + priv->rsp_buf[8] = 0x00;
> > + priv->rsp_buf[9] = 0x00;
> > + priv->rsp_len = 10;
> > + priv->rsp_pos = 0;
> > +
> > + priv->tis_state = TIS_COMPLETION;
> > + priv->sts_reg = TPM_STS_VALID |
> > + TPM_STS_DATA_AVAIL;
> > + }
> > + }
> > + break;
> > +
> > + default:
> > + /*
> > + * Handle FIFO writes - the FIFO is at 0x0024 but any
> address
> > + * from 0x0024 up to 0x0F00 can be used for FIFO access
> when
> > + * doing multi-byte transfers (address auto-increments).
> > + */
> > + if (reg >= TPM_DATA_FIFO_REG && reg < TPM_DID_VID_REG) {
> > + if (priv->tis_state == TIS_READY) {
> > + /* Start receiving command */
> > + priv->tis_state = TIS_RECEPTION;
> > + priv->cmd_len = 0;
> > + priv->cmd_pos = 0;
> > + priv->sts_reg = TPM_STS_VALID |
> TPM_STS_DATA_EXPECT;
> > + }
> > + if (priv->tis_state == TIS_RECEPTION) {
> > + if (priv->cmd_len < TPM_CMD_BUF_SIZE) {
> > + priv->cmd_buf[priv->cmd_len++] =
> value;
> > +
> > + /* Check if we have complete
> command */
> > + if (priv->cmd_len >= 6) {
> > + u32 expected_len;
> > +
> > + expected_len =
> (priv->cmd_buf[2] << 24) |
> > +
> (priv->cmd_buf[3] << 16) |
> > +
> (priv->cmd_buf[4] << 8) |
> > +
> priv->cmd_buf[5];
> > + if (priv->cmd_len >=
> expected_len) {
> > + /* Command
> complete */
> > + priv->sts_reg &=
> > +
> ~TPM_STS_DATA_EXPECT;
> > + }
> > + }
> > + }
> > + }
> > + }
> > + break;
> > + }
> > +}
> > +
> > +/*
> > + * SPI emulation transfer callback
> > + */
> > +static int sandbox_tpm_spi_xfer(struct udevice *dev, unsigned int
> bitlen,
> > + const void *dout, void *din, unsigned long
> flags)
> > +{
> > + struct sandbox_tpm_spi *priv = dev_get_priv(dev);
> > + int bytes = bitlen / 8;
> > + const u8 *tx = dout;
> > + u8 *rx = din;
> > + int i;
> > +
> > + /* Handle CS assert - reset state machine */
> > + if (flags & SPI_XFER_BEGIN) {
> > + priv->spi_state = TPM_SPI_HEADER;
> > + priv->header_pos = 0;
> > + }
> > +
> > + for (i = 0; i < bytes; i++) {
> > + u8 tx_byte = tx ? tx[i] : 0;
> > + u8 rx_byte = 0;
> > +
> > + switch (priv->spi_state) {
> > + case TPM_SPI_IDLE:
> > + /* Should not happen during active transfer */
> > + rx_byte = 0xFF;
> > + break;
> > +
> > + case TPM_SPI_HEADER:
> > + /* Receive 4-byte header */
> > + priv->header[priv->header_pos++] = tx_byte;
> > + rx_byte = 0x00;
> > +
> > + if (priv->header_pos >= 4) {
> > + parse_spi_header(priv);
> > + log_debug("TPM SPI: %s len=%d
> addr=0x%04x\n",
> > + priv->is_read ? "read" : "write",
> > + priv->xfer_len, priv->addr);
> > + /* Return wait state in last header byte */
> > + rx_byte = 0x01; /* Ready immediately */
> > + priv->spi_state = TPM_SPI_DATA;
> > + }
> > + break;
> > +
> > + case TPM_SPI_DATA:
> > + if (priv->is_read) {
> > + /* Read from TPM register */
> > + rx_byte = tis_reg_read(priv,
> > + priv->addr +
> priv->data_pos);
> > + } else {
> > + /* Write to TPM register */
> > + tis_reg_write(priv, priv->addr +
> priv->data_pos,
> > + tx_byte);
> > + rx_byte = 0x00;
> > + }
> > + priv->data_pos++;
> > + break;
> > +
> > + default:
> > + rx_byte = 0xFF;
> > + break;
> > + }
> > +
> > + if (rx)
> > + rx[i] = rx_byte;
> > + }
> > +
> > + /* Handle CS deassert - return to idle */
> > + if (flags & SPI_XFER_END)
> > + priv->spi_state = TPM_SPI_IDLE;
> > +
> > + return 0;
> > +}
> > +
> > +static int sandbox_tpm_spi_probe(struct udevice *dev)
> > +{
> > + struct sandbox_tpm_spi *priv = dev_get_priv(dev);
> > +
> > + /* Initialize TIS state */
> > + priv->spi_state = TPM_SPI_IDLE;
> > + priv->tis_state = TIS_IDLE;
> > + priv->access_reg = TPM_ACCESS_VALID;
> > + priv->sts_reg = TPM_STS_VALID;
> > + priv->intf_caps = TPM_INTF_CAPS_VALUE;
> > + priv->burst_count = MAX_SPI_FRAMESIZE;
> > + priv->cmd_len = 0;
> > + priv->rsp_len = 0;
> > +
> > + log_debug("TPM SPI sandbox emulator probed\n");
> > +
> > + return 0;
> > +}
> > +
> > +static const struct dm_spi_emul_ops sandbox_tpm_spi_ops = {
> > + .xfer = sandbox_tpm_spi_xfer,
> > +};
> > +
> > +static const struct udevice_id sandbox_tpm_spi_ids[] = {
> > + { .compatible = "sandbox,tpm-spi-emul" },
> > + { }
> > +};
> > +
> > +U_BOOT_DRIVER(sandbox_tpm_spi_emul) = {
> > + .name = "sandbox_tpm_spi_emul",
> > + .id = UCLASS_SPI_EMUL,
> > + .of_match = sandbox_tpm_spi_ids,
> > + .ops = &sandbox_tpm_spi_ops,
> > + .probe = sandbox_tpm_spi_probe,
> > + .priv_auto = sizeof(struct sandbox_tpm_spi),
> > +};
> > +
> > +/*
> > + * SPI slave driver for TPM device
> > + * This gets probed when a device with "sandbox,tpm-spi" is found in
> DTS.
> > + * The actual SPI transfers are handled by the emulator above.
> > + */
> > +static int sandbox_tpm_spi_slave_probe(struct udevice *dev)
> > +{
> > + log_debug("TPM SPI slave device probed\n");
> > + return 0;
> > +}
> > +
> > +static const struct udevice_id sandbox_tpm_spi_slave_ids[] = {
> > + { .compatible = "sandbox,tpm-spi" },
> > + { }
> > +};
> > +
> > +U_BOOT_DRIVER(sandbox_tpm_spi) = {
> > + .name = "sandbox_tpm_spi",
> > + .id = UCLASS_SPI_GENERIC,
> > + .of_match = sandbox_tpm_spi_slave_ids,
> > + .probe = sandbox_tpm_spi_slave_probe,
> > +};
> > diff --git a/drivers/tpm/wolftpm_common.c b/drivers/tpm/wolftpm_common.c
> > new file mode 100644
> > index 00000000000..6dea24c5c9a
> > --- /dev/null
> > +++ b/drivers/tpm/wolftpm_common.c
> > @@ -0,0 +1,135 @@
> > +/* wolftpm.c
> > +*
> > +* SPDX-License-Identifier: GPL-2.0+
> > +*
> > +* (C) Copyright 2025
> > +* Aidan Garske <aidan at wolfssl.com>
> > +*/
> > +
> > +#define LOG_CATEGORY UCLASS_BOOTSTD
> > +
> > +#include <wolftpm.h>
> > +#include <wolftpm/tpm2.h>
> > +#include <wolftpm/tpm2_wrap.h>
> > +#include <wolftpm/tpm2_packet.h>
> > +#include <hal/tpm_io.h>
> > +#include <stdio.h>
> > +#include <string.h>
> > +#include <log.h>
> > +#include <hash.h>
> > +#include <examples/wrap/wrap_test.h>
> > +
> > +#ifndef WOLFTPM2_NO_WRAPPER
> > +#ifdef WOLFTPM_FIRMWARE_UPGRADE
> > +
> >
> +/******************************************************************************/
> > +/* --- BEGIN helper functions -- */
> >
> +/******************************************************************************/
> > +
> > +typedef struct {
> > + byte* manifest_buf;
> > + byte* firmware_buf;
> > + size_t manifest_bufSz;
> > + size_t firmware_bufSz;
> > +} fw_info_t;
> > +
> > +int TPM2_IFX_FwData_Cb(uint8_t* data, uint32_t data_req_sz,
> > + uint32_t offset, void* cb_ctx)
> > +{
> > + fw_info_t* fwinfo = (fw_info_t*)cb_ctx;
> > + if (offset > fwinfo->firmware_bufSz) {
> > + return BUFFER_E;
> > + }
> > + if (offset + data_req_sz > (uint32_t)fwinfo->firmware_bufSz) {
> > + data_req_sz = (uint32_t)fwinfo->firmware_bufSz - offset;
> > + }
> > + if (data_req_sz > 0) {
> > + XMEMCPY(data, &fwinfo->firmware_buf[offset], data_req_sz);
> > + }
> > + return data_req_sz;
> > +}
> > +
> > +const char* TPM2_IFX_GetOpModeStr(int opMode)
> > +{
> > + const char* opModeStr = "Unknown";
> > + switch (opMode) {
> > + case 0x00:
> > + opModeStr = "Normal TPM operational mode";
> > + break;
> > + case 0x01:
> > + opModeStr = "TPM firmware update mode (abandon possible)";
> > + break;
> > + case 0x02:
> > + opModeStr = "TPM firmware update mode (abandon not
> possible)";
> > + break;
> > + case 0x03:
> > + opModeStr = "After successful update, but before finalize";
> > + break;
> > + case 0x04:
> > + opModeStr = "After finalize or abandon, reboot required";
> > + break;
> > + default:
> > + break;
> > + }
> > + return opModeStr;
> > +}
> > +
> > +void TPM2_IFX_PrintInfo(WOLFTPM2_CAPS* caps)
> > +{
> > + printf("Mfg %s (%d), Vendor %s, Fw %u.%u (0x%x)\n",
> > + caps->mfgStr, caps->mfg, caps->vendorStr, caps->fwVerMajor,
> > + caps->fwVerMinor, caps->fwVerVendor);
> > + printf("Operational mode: %s (0x%x)\n",
> > + TPM2_IFX_GetOpModeStr(caps->opMode), caps->opMode);
> > + printf("KeyGroupId 0x%x, FwCounter %d (%d same)\n",
> > + caps->keyGroupId, caps->fwCounter, caps->fwCounterSame);
> > +}
> > +#endif /* WOLFTPM_FIRMWARE_UPGRADE */
> > +
> > +int TPM2_PCRs_Print(void)
> > +{
> > + int rc;
> > + int pcrCount, pcrIndex;
> > + GetCapability_In capIn;
> > + GetCapability_Out capOut;
> > + TPML_PCR_SELECTION* pcrSel;
> > +
> > + memset(&capIn, 0, sizeof(capIn));
> > + capIn.capability = TPM_CAP_PCRS;
> > + capIn.property = 0;
> > + capIn.propertyCount = 1;
> > + rc = TPM2_GetCapability(&capIn, &capOut);
> > + if (rc != TPM_RC_SUCCESS) {
> > + log_debug("TPM2_GetCapability failed rc=%d (%s)\n", rc,
> TPM2_GetRCString(rc));
> > + return rc;
> > + }
> > + pcrSel = &capOut.capabilityData.data.assignedPCR;
> > + printf("Assigned PCR's:\n");
> > + for (pcrCount=0; pcrCount < (int)pcrSel->count; pcrCount++) {
> > + printf("\t%s: ",
> TPM2_GetAlgName(pcrSel->pcrSelections[pcrCount].hash));
> > + for (pcrIndex=0;
> > + pcrIndex<pcrSel->pcrSelections[pcrCount].sizeofSelect*8;
> > + pcrIndex++) {
> > + if ((pcrSel->pcrSelections[pcrCount].pcrSelect[pcrIndex/8] &
> > + ((1 << (pcrIndex % 8)))) != 0) {
> > + printf(" %d", pcrIndex);
> > + }
> > + }
> > + printf("\n");
> > + }
> > + return TPM_RC_SUCCESS;
> > +}
> > +
> > +int TPM2_Init_Device(WOLFTPM2_DEV* dev, void* userCtx)
> > +{
> > + /* Use TPM2_IoCb callback which calls TPM2_IoCb_Uboot_SPI for
> packet-level access */
> > + int rc = wolfTPM2_Init(dev, TPM2_IoCb, userCtx);
> > + log_debug("tpm2 init: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
> > + return rc;
> > +}
> > +
> > +#endif /* WOLFTPM2_NO_WRAPPER */
> > +
> >
> +/******************************************************************************/
> > +/* --- END helper functions -- */
> >
> +/******************************************************************************/
> > diff --git a/include/configs/user_settings.h
> b/include/configs/user_settings.h
> > new file mode 100644
> > index 00000000000..5aaa27a3d3f
> > --- /dev/null
> > +++ b/include/configs/user_settings.h
> > @@ -0,0 +1,118 @@
> > +/* user_settings.h
> > + *
> > + * SPDX-License-Identifier: GPL-2.0+
> > + *
> > + * (C) Copyright 2025
> > + * Aidan Garske <aidan at wolfssl.com>
> > + */
> > +
> > +#ifndef USER_SETTINGS_H
> > +#define USER_SETTINGS_H
> > +
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +
> >
> +/******************************************************************************/
> > +/* --- BEGIN wolfTPM U-boot Settings -- */
> >
> +/******************************************************************************/
> > +
> > +/*
> =========================================================================
> > + * TPM Chip Configuration
> > + *
> =========================================================================
> > + *
> > + * CONFIG_TPM_AUTODETECT: For swtpm/QEMU testing (no specific chip)
> > + * !CONFIG_TPM_AUTODETECT: For real hardware (SLB9672/SLB9673)
> > + */
> > +#ifdef CONFIG_TPM_AUTODETECT
> > + #define WOLFTPM_AUTODETECT
> > +#else
> > + /* Real hardware - Infineon SLB9672/SLB9673
> > + * Firmware upgrade only supported by these chips */
> > + #define WOLFTPM_FIRMWARE_UPGRADE
> > + #define WOLFTPM_SLB9672
> > + /* #define WOLFTPM_SLB9673 */
> > +#endif
> > +
> > +/* Include delay.h and types.h for
> > + * U-boot time delay and types */
> > +#include <linux/delay.h>
> > +#include <linux/types.h>
> > +#include <stdint.h>
> > +
> > +/* wolfCrypt disabled - pcr_setauthpolicy/pcr_setauthvalue not available
> > + * To enable wolfCrypt, you would need to:
> > + * 1. Uncomment the line below to undefine WOLFTPM2_NO_WOLFCRYPT
> > + * 2. Add wolfCrypt source files to the U-Boot build (lib/Makefile)
> > + * 3. Add wolfCrypt settings for embedded/no-OS use
> > + */
> > +#undef WOLFTPM2_NO_WOLFCRYPT
> > +#define WOLFTPM2_NO_WOLFCRYPT
> > +
> > +/*
> =========================================================================
> > + * TPM Communication Mode Selection (Auto-detected based on chip type)
> > + *
> =========================================================================
> > + *
> > + * For real SPI hardware (SLB9672/SLB9673):
> > + * - Uses wolfTPM's native TIS layer with raw SPI via tpm_io_uboot.c
> > + * - Requires CONFIG_SPI and CONFIG_DM_SPI enabled in U-Boot
> > + *
> > + * For swtpm/QEMU testing (no specific chip defined):
> > + * - Uses WOLFTPM_LINUX_DEV mode with U-Boot's TPM driver (tpm_xfer())
> > + * - Works with MMIO-based TPM via tpm2_tis_mmio.c
> > + */
> > +
> > +#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
> > + /* Real SPI hardware - use native wolfTPM TIS with raw SPI */
> > + /* WOLFTPM_LINUX_DEV is NOT defined */
> > + #define WOLFTPM_EXAMPLE_HAL
> > +
> > + /* SPI bus and chip select for TPM
> > + * Official Raspberry Pi tpm-slb9670 overlay uses CE1 (GPIO7)
> > + * This matches LetsTrust and most Infineon evaluation boards */
> > + #ifndef TPM_SPI_BUS
> > + #define TPM_SPI_BUS 0
> > + #endif
> > + #ifndef TPM_SPI_CS
> > + #define TPM_SPI_CS 1 /* CE1/GPIO7 - official RPi TPM overlay
> setting */
> > + #endif
> > +#else
> > + /* swtpm/QEMU - use U-Boot's TPM driver with MMIO communication
> mode */
> > + #define WOLFTPM_LINUX_DEV
> > +#endif
> > +
> > +#define XSLEEP_MS(ms) udelay(ms * 1000)
> > +
> > +/* Timeout configuration */
> > +#ifdef WOLFTPM_FIRMWARE_UPGRADE
> > + /* Firmware update requires much longer timeout for TPM processing
> */
> > + #define TPM_TIMEOUT_TRIES 2000000
> > +#else
> > + /* Normal operations - reduce from default 1,000,000 to prevent
> long hangs */
> > + #define TPM_TIMEOUT_TRIES 10000
> > +#endif
> > +
> > +/* Add small delay between poll attempts to avoid tight spin loop */
> > +#define XTPM_WAIT() udelay(100)
> > +
> > +/* Do not include API's that use heap(), they are not required */
> > +#define WOLFTPM2_NO_HEAP
> > +
> > +/* Debugging - disabled for clean output */
> > +/* #define DEBUG_WOLFTPM */
> > +/* #define WOLFTPM_DEBUG_VERBOSE */
> > +/* #define WOLFTPM_DEBUG_IO */
> > +/* #define WOLFTPM_DEBUG_TIMEOUT */
> > +
> > +/* SPI Wait state checking - most TPMs use this */
> > +#define WOLFTPM_CHECK_WAIT_STATE
> > +
> >
> +/******************************************************************************/
> > +/* --- END wolfTPM U-boot Settings -- */
> >
> +/******************************************************************************/
> > +
> > +#ifdef __cpluspluss
> > +}
> > +#endif
> > +
> > +#endif /* USER_SETTINGS_H */
> > diff --git a/include/hash.h b/include/hash.h
> > index 8b3f79ec473..242de9f0e84 100644
> > --- a/include/hash.h
> > +++ b/include/hash.h
> > @@ -6,6 +6,8 @@
> > #ifndef _HASH_H
> > #define _HASH_H
> >
> > +#include <linux/types.h>
> > +
> > #ifdef USE_HOSTCC
> > #include <linux/kconfig.h>
> > #endif
> > @@ -163,4 +165,19 @@ int hash_progressive_lookup_algo(const char
> *algo_name,
> > */
> > int hash_parse_string(const char *algo_name, const char *str, uint8_t
> *result);
> >
> > +#ifdef WOLFTPM2_NO_WOLFCRYPT
> > +/**
> > + * wc_Sha384Hash() - Calculate SHA384 hash
> > + * @data: Data to hash
> > + * @len: Length of data
> > + * @hash: Output buffer for hash
> > + *
> > + * This is a wrapper function to provide wolfCrypt-compatible SHA384
> hashing
> > + * when wolfCrypt is not available.
> > + *
> > + * Return: 0 on success, -1 on error
> > + */
> > +int wc_Sha384Hash(const unsigned char* data, unsigned int len, unsigned
> char* hash);
> > +#endif /* WOLFTPM2_NO_WOLFCRYPT */
> > +
> > #endif
> > diff --git a/include/linux/byteorder/generic.h
> b/include/linux/byteorder/generic.h
> > index bee0ff60336..def601eed2b 100644
> > --- a/include/linux/byteorder/generic.h
> > +++ b/include/linux/byteorder/generic.h
> > @@ -89,12 +89,6 @@
> > #define le32_to_cpu __le32_to_cpu
> > #define cpu_to_le16 __cpu_to_le16
> > #define le16_to_cpu __le16_to_cpu
> > -#define cpu_to_be64 __cpu_to_be64
> > -#define be64_to_cpu __be64_to_cpu
> > -#define cpu_to_be32 __cpu_to_be32
> > -#define be32_to_cpu __be32_to_cpu
> > -#define cpu_to_be16 __cpu_to_be16
> > -#define be16_to_cpu __be16_to_cpu
> > #define cpu_to_le64p __cpu_to_le64p
> > #define le64_to_cpup __le64_to_cpup
> > #define cpu_to_le32p __cpu_to_le32p
> > @@ -120,6 +114,31 @@
> > #define cpu_to_be16s __cpu_to_be16s
> > #define be16_to_cpus __be16_to_cpus
> >
> > +/*
> > + * Check if byte-order functions are already defined by the system:
> > + * wolfTPM, wolfCrypt, and U-boot all define these functions, so
> > + * we need to check if they are already defined before defining
> > + * them again.
> > + */
> > +#ifndef cpu_to_be16
> > +#define cpu_to_be16 __cpu_to_be16
> > +#endif
> > +#ifndef cpu_to_be32
> > +#define cpu_to_be32 __cpu_to_be32
> > +#endif
> > +#ifndef cpu_to_be64
> > +#define cpu_to_be64 __cpu_to_be64
> > +#endif
> > +#ifndef be16_to_cpu
> > +#define be16_to_cpu __be16_to_cpu
> > +#endif
> > +#ifndef be32_to_cpu
> > +#define be32_to_cpu __be32_to_cpu
> > +#endif
> > +#ifndef be64_to_cpu
> > +#define be64_to_cpu __be64_to_cpu
> > +#endif
> > +
> > /*
> > * They have to be macros in order to do the constant folding
> > * correctly - if the argument passed into a inline function
> > diff --git a/include/tpm-common.h b/include/tpm-common.h
> > index bfb84a931d1..1ea4463fbbe 100644
> > --- a/include/tpm-common.h
> > +++ b/include/tpm-common.h
> > @@ -337,4 +337,26 @@ enum tpm_version tpm_get_version(struct udevice
> *dev);
> > /* Iterate on all TPM devices */
> > #define for_each_tpm_device(dev) uclass_foreach_dev_probe(UCLASS_TPM,
> (dev))
> >
> > +/**
> > + * tpm_show_device() - Show all TPM devices
> > + *
> > + * Return: 0 on success, -ve on failure
> > + */
> > +int tpm_show_device(void);
> > +
> > +/**
> > + * tpm_set_device() - Set the TPM device to use
> > + *
> > + * @num: The number of the TPM device to use
> > + * Return: 0 on success, -ve on failure
> > + */
> > +int tpm_set_device(unsigned long num);
> > +
> > +/**
> > + * get_tpm() - Get the TPM device
> > + *
> > + * Return: 0 on success, -ve on failure
> > + */
> > +int get_tpm(struct udevice **devp);
> > +
> > #endif /* __TPM_COMMON_H */
> > diff --git a/include/wolftpm.h b/include/wolftpm.h
> > new file mode 100644
> > index 00000000000..dfa8af327f4
> > --- /dev/null
> > +++ b/include/wolftpm.h
> > @@ -0,0 +1,33 @@
> > +/* wolftpm.h
> > +*
> > +* SPDX-License-Identifier: GPL-2.0+
> > +*
> > +* (C) Copyright 2025
> > +* Aidan Garske <aidan at wolfssl.com>
> > +*/
> > +
> > +#ifndef __WOLFTPM_H__
> > +#define __WOLFTPM_H__
> > +
> > +#include <wolftpm/tpm2.h>
> > +#include <wolftpm/tpm2_wrap.h>
> > +#include <wolftpm/tpm2_packet.h>
> > +
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +
> > +#ifdef WOLFTPM_FIRMWARE_UPGRADE
> > +int TPM2_IFX_FwData_Cb(uint8_t* data, uint32_t data_req_sz, uint32_t
> offset, void* cb_ctx);
> > +const char* TPM2_IFX_GetOpModeStr(int opMode);
> > +void TPM2_IFX_PrintInfo(WOLFTPM2_CAPS* caps);
> > +#endif
> > +
> > +int TPM2_PCRs_Print(void);
> > +int TPM2_Init_Device(WOLFTPM2_DEV* dev, void* userCtx);
> > +
> > +#ifdef __cplusplus
> > +}
> > +#endif
> > +
> > +#endif /* __WOLFTPM_H__ */
> > diff --git a/lib/Kconfig b/lib/Kconfig
> > index 931d5206936..24477ea53c9 100644
> > --- a/lib/Kconfig
> > +++ b/lib/Kconfig
> > @@ -500,6 +500,19 @@ 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_WOLF
> > + bool "Enable wolfTPM support"
> > + depends on DM
> > + imply DM_RNG
> > + select SHA1
> > + help
> > + This option enables support for wolfTPM in U-Boot. WolfTPM can
> be
> > + used to update ARM specific platforms. Enabling this
> option allows
> > + U-Boot to interact with the TPM using wolfTPM commands
> such as
> > + firmware updates, PCR extend, and more. It is especially
> useful on
> > + platforms that require support for secure boot and other
> TPM-related
> > + functionality.
> > +
> > config SPL_TPM
> > bool "Trusted Platform Module (TPM) Support in SPL"
> > depends on SPL_DM
> > diff --git a/lib/Makefile b/lib/Makefile
> > index 70667f3728c..ba3a9e85c11 100644
> > --- a/lib/Makefile
> > +++ b/lib/Makefile
> > @@ -55,6 +55,7 @@ obj-$(CONFIG_BITREVERSE) += bitrev.o
> > obj-y += list_sort.o
> > endif
> >
> > +# U-boot TPM
> > obj-$(CONFIG_$(PHASE_)TPM) += tpm-common.o
> > ifeq ($(CONFIG_$(PHASE_)TPM),y)
> > obj-$(CONFIG_TPM) += tpm_api.o
> > @@ -64,6 +65,23 @@ obj-$(CONFIG_EFI_TCG2_PROTOCOL) += tpm_tcg2.o
> > obj-$(CONFIG_MEASURED_BOOT) += tpm_tcg2.o
> > endif
> >
> > +# wolfTPM with TPM 2.0 support (including TPM firmware update)
> > +ifeq ($(CONFIG_TPM_WOLF),y)
> > +ifeq ($(CONFIG_TPM_V2),y)
> > +ccflags-y += -Ilib/wolftpm \
> > + -Iinclude/configs \
> > + -DWOLFTPM_USER_SETTINGS
> > +obj-y += wolftpm/hal/tpm_io.o
> > +obj-$(CONFIG_WOLFTPM_LINUX_DEV) += wolftpm/src/tpm2_linux.o
> > +obj-y += wolftpm/src/tpm2.o
> > +obj-y += wolftpm/src/tpm2_packet.o
> > +obj-y += wolftpm/src/tpm2_tis.o
> > +obj-y += wolftpm/src/tpm2_wrap.o
> > +obj-y += wolftpm/src/tpm2_param_enc.o
> > +obj-y += wolftpm.o
> > +endif
> > +endif
> > +
> > obj-$(CONFIG_$(PHASE_)CRC8) += crc8.o
> > obj-$(CONFIG_$(PHASE_)CRC16) += crc16.o
> > obj-$(CONFIG_$(PHASE_)CRC16) += crc16-ccitt.o
> > diff --git a/lib/wolftpm b/lib/wolftpm
> > new file mode 160000
> > index 00000000000..19559386121
> > --- /dev/null
> > +++ b/lib/wolftpm
> > @@ -0,0 +1 @@
> > +Subproject commit 1955938612159325826329e1f7e6bb0d1e0f799f
> > diff --git a/lib/wolftpm.c b/lib/wolftpm.c
> > new file mode 100644
> > index 00000000000..a2b8a302365
> > --- /dev/null
> > +++ b/lib/wolftpm.c
> > @@ -0,0 +1,56 @@
> > +/* wolftpm.c
> > + *
> > + * SPDX-License-Identifier: GPL-2.0+
> > + *
> > + * (C) Copyright 2025
> > + * Aidan Garske <aidan at wolfssl.com>
> > + */
> > +
> > +/* wolfTPM wrapper layer to expose U-boot API
> > + * when wolfCrypt is not available. This is used by
> > + * the U-boot firmware update command.
> > + */
> > +
> > +#include <configs/user_settings.h>
> > +#include <hash.h>
> > +#include <linux/types.h>
> > +#include <stdint.h>
> > +#include <stdio.h>
> > +#include <string.h>
> > +#include <malloc.h>
> > +#include <mapmem.h>
> > +#include <asm/cache.h>
> > +#include <errno.h>
> > +
> > +/* Add wolfTPM type definitions */
> > +typedef uint8_t byte;
> > +typedef uint32_t word32;
> > +
> > +#ifdef WOLFTPM2_NO_WOLFCRYPT
> > +int wc_Sha384Hash(const byte* data, word32 len, byte* hash)
> > +{
> > + struct hash_algo *algo;
> > + u8 *output;
> > + void *buf;
> > +
> > + if (hash_lookup_algo("sha384", &algo)) {
> > + printf("Unknown hash algorithm 'sha384'\n");
> > + return -1;
> > + }
> > +
> > + output = (u8 *)memalign(ARCH_DMA_MINALIGN,
> > + algo->digest_size);
> > + if (!output) {
> > + return -ENOMEM;
> > + }
> > +
> > + buf = (void *)map_sysmem((ulong)data, len);
> > + algo->hash_func_ws(buf, len, output, algo->chunk_size);
> > + unmap_sysmem(buf);
> > +
> > + memcpy(hash, output, algo->digest_size);
> > +
> > + free(output);
> > + return 0;
> > +}
> > +#endif /* WOLFTPM2_NO_WOLFCRYPT */
> > diff --git a/scripts/check-local-export b/scripts/check-local-export
> > index 6ccc2f46741..ce520772866 100755
> > --- a/scripts/check-local-export
> > +++ b/scripts/check-local-export
> > @@ -5,6 +5,15 @@
> > #
> > # Exit with error if a local exported symbol is found.
> > # EXPORT_SYMBOL should be used for global symbols.
> > +#
> > +# NOTE: This check is skipped on macOS with older bash that lacks
> > +# associative arrays support (bash 4.0+). The check will run properly
> > +# on Linux build systems.
> > +
> > +# Check for bash 4+ (required for associative arrays)
> > +if [[ ${BASH_VERSINFO[0]} -lt 4 ]]; then
> > + exit 0
> > +fi
> >
> > set -e
> >
> > diff --git a/test/cmd/Makefile b/test/cmd/Makefile
> > index 2476068aee6..08fbc31a06a 100644
> > --- a/test/cmd/Makefile
> > +++ b/test/cmd/Makefile
> > @@ -45,3 +45,4 @@ endif
> > obj-$(CONFIG_ARM_FFA_TRANSPORT) += armffa.o
> > endif
> > obj-$(CONFIG_CMD_SPAWN) += spawn.o
> > +obj-$(CONFIG_TPM_WOLF) += wolftpm.o
> > diff --git a/test/cmd/wolftpm.c b/test/cmd/wolftpm.c
> > new file mode 100644
> > index 00000000000..b2e6f82a098
> > --- /dev/null
> > +++ b/test/cmd/wolftpm.c
> > @@ -0,0 +1,364 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Tests for wolfTPM commands
> > + *
> > + * Copyright (C) 2025 wolfSSL Inc.
> > + * Author: Aidan Garske <aidan at wolfssl.com>
> > + *
> > + * Based on test/py/tests/test_tpm2.py and test/dm/tpm.c
> > + *
> > + * Note: These tests verify command success via return code only.
> > + * Console output is not checked since it varies with debug levels.
> > + * Run with: ut cmd
> > + */
> > +
> > +#include <command.h>
> > +#include <dm.h>
> > +#include <dm/test.h>
> > +#include <test/cmd.h>
> > +#include <test/test.h>
> > +#include <test/ut.h>
> > +
> > +/**
> > + * Test wolfTPM autostart command
> > + *
> > + * This initializes the TPM, performs startup and self-test
> > + */
> > +static int cmd_test_wolftpm_autostart(struct unit_test_state *uts)
> > +{
> > + /* Initialize and autostart the TPM */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_autostart, 0);
> > +
> > +/**
> > + * Test wolfTPM init command
> > + */
> > +static int cmd_test_wolftpm_init(struct unit_test_state *uts)
> > +{
> > + ut_assertok(run_command("tpm2 init", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_init, 0);
> > +
> > +/**
> > + * Test wolfTPM info command
> > + *
> > + * Display TPM device information
> > + */
> > +static int cmd_test_wolftpm_info(struct unit_test_state *uts)
> > +{
> > + /* First autostart to ensure TPM is ready */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + /* Get TPM info */
> > + ut_assertok(run_command("tpm2 info", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_info, 0);
> > +
> > +/**
> > + * Test wolfTPM state command
> > + *
> > + * Display TPM internal state
> > + */
> > +static int cmd_test_wolftpm_state(struct unit_test_state *uts)
> > +{
> > + /* First autostart to ensure TPM is ready */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + /* Get TPM state */
> > + ut_assertok(run_command("tpm2 state", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_state, 0);
> > +
> > +/**
> > + * Test wolfTPM device command
> > + *
> > + * Show all TPM devices
> > + */
> > +static int cmd_test_wolftpm_device(struct unit_test_state *uts)
> > +{
> > + /* Show TPM devices - no autostart needed */
> > + ut_assertok(run_command("tpm2 device", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_device, 0);
> > +
> > +/**
> > + * Test wolfTPM self_test command
> > + */
> > +static int cmd_test_wolftpm_self_test(struct unit_test_state *uts)
> > +{
> > + /* First autostart to ensure TPM is ready */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + /* Run full self test */
> > + ut_assertok(run_command("tpm2 self_test full", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_self_test, 0);
> > +
> > +/**
> > + * Test wolfTPM self_test continue command
> > + */
> > +static int cmd_test_wolftpm_self_test_continue(struct unit_test_state
> *uts)
> > +{
> > + /* First autostart to ensure TPM is ready */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + /* Run continue self test */
> > + ut_assertok(run_command("tpm2 self_test continue", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_self_test_continue, 0);
> > +
> > +/**
> > + * Test wolfTPM startup command with TPM2_SU_CLEAR
> > + *
> > + * Issue TPM2_Startup with CLEAR mode (reset state)
> > + */
> > +static int cmd_test_wolftpm_startup_clear(struct unit_test_state *uts)
> > +{
> > + /* First init to prepare TPM */
> > + ut_assertok(run_command("tpm2 init", 0));
> > +
> > + /* Issue startup with CLEAR mode */
> > + ut_assertok(run_command("tpm2 startup TPM2_SU_CLEAR", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_startup_clear, 0);
> > +
> > +/**
> > + * Test wolfTPM startup command with TPM2_SU_STATE
> > + *
> > + * Issue TPM2_Startup with STATE mode (preserved state)
> > + */
> > +static int cmd_test_wolftpm_startup_state(struct unit_test_state *uts)
> > +{
> > + /* First autostart to ensure TPM has state */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + /* Shutdown first to prepare for STATE startup */
> > + run_command("tpm2 startup TPM2_SU_STATE off", 0);
> > +
> > + /* Re-init */
> > + ut_assertok(run_command("tpm2 init", 0));
> > +
> > + /* Issue startup with STATE mode - may return already started */
> > + run_command("tpm2 startup TPM2_SU_STATE", 0);
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_startup_state, 0);
> > +
> > +/**
> > + * Test wolfTPM get_capability command
> > + *
> > + * Read TPM capabilities by property
> > + */
> > +static int cmd_test_wolftpm_get_capability(struct unit_test_state *uts)
> > +{
> > + /* First autostart to ensure TPM is ready */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + /* Get capability - property 0x6 (TPM_CAP_TPM_PROPERTIES), 0x20e
> (PT_MANUFACTURER) */
> > + ut_assertok(run_command("tpm2 get_capability 0x6 0x20e 0x1000000
> 1", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_get_capability, 0);
> > +
> > +/**
> > + * Test wolfTPM caps command (get capabilities)
> > + *
> > + * Display TPM capabilities and vendor info
> > + */
> > +static int cmd_test_wolftpm_caps(struct unit_test_state *uts)
> > +{
> > + /* First autostart to ensure TPM is ready */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + /* Get TPM capabilities */
> > + ut_assertok(run_command("tpm2 caps", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_caps, 0);
> > +
> > +/**
> > + * Test wolfTPM clear command
> > + *
> > + * Reset TPM internal state using LOCKOUT hierarchy
> > + */
> > +static int cmd_test_wolftpm_clear(struct unit_test_state *uts)
> > +{
> > + /* First autostart to ensure TPM is ready */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + /* Clear using LOCKOUT hierarchy */
> > + ut_assertok(run_command("tpm2 clear TPM2_RH_LOCKOUT", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_clear, 0);
> > +
> > +/**
> > + * Test wolfTPM pcr_read command
> > + *
> > + * Read PCR value from a specific index to a memory address
> > + */
> > +static int cmd_test_wolftpm_pcr_read(struct unit_test_state *uts)
> > +{
> > + /* First autostart to ensure TPM is ready */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + /* Read PCR 0 with SHA256 to memory address 0x1000000 */
> > + ut_assertok(run_command("tpm2 pcr_read 0 0x1000000 SHA256", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_pcr_read, 0);
> > +
> > +/**
> > + * Test wolfTPM pcr_extend command
> > + *
> > + * Extend a PCR with a digest value
> > + */
> > +static int cmd_test_wolftpm_pcr_extend(struct unit_test_state *uts)
> > +{
> > + /* First autostart to ensure TPM is ready */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + /* Clear to start fresh */
> > + run_command("tpm2 clear TPM2_RH_LOCKOUT", 0);
> > +
> > + /* Extend PCR 16 (resettable PCR) with digest from memory
> > + * PCR 16-23 are typically available for debug/testing
> > + */
> > + ut_assertok(run_command("tpm2 pcr_extend 16 0x1000000 SHA256", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_pcr_extend, 0);
> > +
> > +/**
> > + * Test wolfTPM pcr_print command
> > + *
> > + * Print all PCR values
> > + */
> > +static int cmd_test_wolftpm_pcr_print(struct unit_test_state *uts)
> > +{
> > + /* First autostart to ensure TPM is ready */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + /* Print all PCRs */
> > + ut_assertok(run_command("tpm2 pcr_print", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_pcr_print, 0);
> > +
> > +/**
> > + * Test wolfTPM pcr_allocate command
> > + *
> > + * Reconfigure PCR bank algorithm. Note: A TPM restart is required
> > + * for changes to take effect, so we just verify the command succeeds.
> > + */
> > +static int cmd_test_wolftpm_pcr_allocate(struct unit_test_state *uts)
> > +{
> > + /* First autostart to ensure TPM is ready */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + /* Allocate SHA256 bank on - this should succeed */
> > + ut_assertok(run_command("tpm2 pcr_allocate SHA256 on", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_pcr_allocate, 0);
> > +
> > +/**
> > + * Test wolfTPM dam_reset command
> > + *
> > + * Reset Dictionary Attack Mitigation counter
> > + */
> > +static int cmd_test_wolftpm_dam_reset(struct unit_test_state *uts)
> > +{
> > + /* First autostart to ensure TPM is ready */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + /* Reset DAM counter */
> > + ut_assertok(run_command("tpm2 dam_reset", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_dam_reset, 0);
> > +
> > +/**
> > + * Test wolfTPM dam_parameters command
> > + *
> > + * Set Dictionary Attack Mitigation parameters
> > + */
> > +static int cmd_test_wolftpm_dam_parameters(struct unit_test_state *uts)
> > +{
> > + /* First autostart to ensure TPM is ready */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > +
> > + /* Set DAM parameters:
> > + * - max_tries: 3
> > + * - recovery_time: 10 seconds
> > + * - lockout_recovery: 0 seconds
> > + */
> > + ut_assertok(run_command("tpm2 dam_parameters 3 10 0", 0));
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_dam_parameters, 0);
> > +
> > +/**
> > + * Test wolfTPM change_auth command
> > + *
> > + * Change hierarchy authorization password
> > + * Note: Requires WOLFTPM2_NO_WOLFCRYPT to NOT be defined
> > + */
> > +static int cmd_test_wolftpm_change_auth(struct unit_test_state *uts)
> > +{
> > + /* First autostart and clear to ensure clean state */
> > + ut_assertok(run_command("tpm2 autostart", 0));
> > + run_command("tpm2 clear TPM2_RH_LOCKOUT", 0);
> > +
> > + /* Change LOCKOUT password to "testpw"
> > + * This may fail if WOLFTPM2_NO_WOLFCRYPT is defined
> > + */
> > + if (run_command("tpm2 change_auth TPM2_RH_LOCKOUT testpw", 0) ==
> 0) {
> > + /* Clear with new password to verify it worked */
> > + ut_assertok(run_command("tpm2 clear TPM2_RH_LOCKOUT
> testpw", 0));
> > + }
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_change_auth, 0);
> > +
> > +/**
> > + * Cleanup test - ensure TPM is cleared after tests
> > + */
> > +static int cmd_test_wolftpm_cleanup(struct unit_test_state *uts)
> > +{
> > + /* Clear TPM to reset any passwords or test state */
> > + run_command("tpm2 autostart", 0);
> > + run_command("tpm2 clear TPM2_RH_LOCKOUT", 0);
> > + run_command("tpm2 clear TPM2_RH_PLATFORM", 0);
> > +
> > + return 0;
> > +}
> > +CMD_TEST(cmd_test_wolftpm_cleanup, 0);
> > diff --git a/test/py/tests/test_wolftpm.py
> b/test/py/tests/test_wolftpm.py
> > new file mode 100644
> > index 00000000000..9d67211f96c
> > --- /dev/null
> > +++ b/test/py/tests/test_wolftpm.py
> > @@ -0,0 +1,373 @@
> > +# SPDX-License-Identifier: GPL-2.0+
> > +# Copyright (C) 2025 wolfSSL Inc.
> > +# Author: Aidan Garske <aidan at wolfssl.com>
> > +#
> > +# Based on test_tpm2.py by Miquel Raynal <miquel.raynal at bootlin.com>
> > +
> > +"""
> > +Test the wolfTPM related commands. These tests require a TPM device
> > +(real hardware or software TPM emulator like swtpm).
> > +
> > +Notes:
> > +* These tests will prove the password mechanism. The TPM chip must be
> cleared of
> > + any password.
> > +* Tests are designed to be similar to test_tpm2.py but use wolfTPM
> wrapper APIs.
> > +
> > +Configuration:
> > +* Set env__wolftpm_device_test_skip to True to skip these tests.
> > +"""
> > +
> > +import os.path
> > +import pytest
> > +import utils
> > +import re
> > +import time
> > +
> > +
> > +def force_init(ubman, force=False):
> > + """Initialize wolfTPM before running tests.
> > +
> > + When a test fails, U-Boot may be reset. Because TPM stack must be
> initialized
> > + after each reboot, we must ensure these lines are always executed
> before
> > + trying any command or they will fail with no reason.
> > + """
> > + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip',
> False)
> > + if skip_test:
> > + pytest.skip('skip wolfTPM device test')
> > + output = ubman.run_command('wolftpm autostart')
> > + if force or 'Error' not in output:
> > + ubman.run_command('echo --- start of init ---')
> > + ubman.run_command('wolftpm clear TPM2_RH_LOCKOUT')
> > + output = ubman.run_command('echo $?')
> > + if not output.endswith('0'):
> > + ubman.run_command('wolftpm clear TPM2_RH_PLATFORM')
> > + ubman.run_command('echo --- end of init ---')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_autostart(ubman):
> > + """Test wolfTPM autostart command.
> > +
> > + Initialize the software stack, perform startup and self-test.
> > + """
> > + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip',
> False)
> > + if skip_test:
> > + pytest.skip('skip wolfTPM device test')
> > + ubman.run_command('wolftpm autostart')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_init(ubman):
> > + """Test wolfTPM init command.
> > +
> > + Initialize the TPM device for communication.
> > + """
> > + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip',
> False)
> > + if skip_test:
> > + pytest.skip('skip wolfTPM device test')
> > + ubman.run_command('wolftpm init')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_self_test_full(ubman):
> > + """Test wolfTPM full self_test command.
> > +
> > + Perform a full TPM self-test to verify all components are
> operational.
> > + """
> > + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip',
> False)
> > + if skip_test:
> > + pytest.skip('skip wolfTPM device test')
> > + ubman.run_command('wolftpm autostart')
> > + ubman.run_command('wolftpm self_test full')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_self_test_continue(ubman):
> > + """Test wolfTPM continue self_test command.
> > +
> > + Ask the TPM to finish any remaining self tests.
> > + """
> > + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip',
> False)
> > + if skip_test:
> > + pytest.skip('skip wolfTPM device test')
> > + ubman.run_command('wolftpm autostart')
> > + ubman.run_command('wolftpm self_test continue')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_caps(ubman):
> > + """Test wolfTPM caps command.
> > +
> > + Display TPM capabilities and vendor information.
> > + """
> > + force_init(ubman)
> > + caps_output = ubman.run_command('wolftpm caps')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > + # Should contain manufacturer info
> > + assert 'Mfg' in caps_output or 'Vendor' in caps_output or 'wolfTPM'
> in caps_output
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_clear(ubman):
> > + """Test wolfTPM clear command.
> > +
> > + Clear the TPM internal state using LOCKOUT hierarchy.
> > + LOCKOUT/PLATFORM hierarchies must not have a password set.
> > + """
> > + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip',
> False)
> > + if skip_test:
> > + pytest.skip('skip wolfTPM device test')
> > + ubman.run_command('wolftpm autostart')
> > + ubman.run_command('wolftpm clear TPM2_RH_LOCKOUT')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > + ubman.run_command('wolftpm clear TPM2_RH_PLATFORM')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_change_auth(ubman):
> > + """Test wolfTPM change_auth command.
> > +
> > + Change the owner/hierarchy password.
> > + """
> > + force_init(ubman)
> > +
> > + # Change LOCKOUT password to 'unicorn'
> > + ubman.run_command('wolftpm change_auth TPM2_RH_LOCKOUT unicorn')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > + # Clear with new password to verify
> > + ubman.run_command('wolftpm clear TPM2_RH_LOCKOUT unicorn')
> > + output = ubman.run_command('echo $?')
> > + ubman.run_command('wolftpm clear TPM2_RH_PLATFORM')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_dam_parameters(ubman):
> > + """Test wolfTPM dam_parameters command.
> > +
> > + Change Dictionary Attack Mitigation parameters:
> > + - Max number of failed authentication before lockout: 3
> > + - Time before failure counter is decremented: 10 sec
> > + - Time after lockout failure before retry: 0 sec
> > + """
> > + force_init(ubman)
> > +
> > + # Set DAM parameters
> > + ubman.run_command('wolftpm dam_parameters 3 10 0')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_dam_reset(ubman):
> > + """Test wolfTPM dam_reset command.
> > +
> > + Reset the Dictionary Attack Mitigation counter.
> > + """
> > + force_init(ubman)
> > +
> > + ubman.run_command('wolftpm dam_reset')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_pcr_read(ubman):
> > + """Test wolfTPM pcr_read command.
> > +
> > + Read PCR value from a specific index.
> > + """
> > + force_init(ubman)
> > +
> > + # Read PCR 0 with SHA256
> > + read_pcr = ubman.run_command('wolftpm pcr_read 0 sha256')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > + # Check for PCR output
> > + assert 'PCR' in read_pcr or 'digest' in read_pcr.lower() or
> 'sha256' in read_pcr.lower()
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_pcr_extend(ubman):
> > + """Test wolfTPM pcr_extend command.
> > +
> > + Extend a PCR with a digest value.
> > + PCR 16-23 are typically available for debug/testing.
> > + """
> > + force_init(ubman)
> > + ram = utils.find_ram_base(ubman)
> > +
> > + # Read PCR 16 first
> > + read_pcr = ubman.run_command('wolftpm pcr_read 16 sha256')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > + # Extend PCR 16 with zeroed memory
> > + ubman.run_command('wolftpm pcr_extend 16 0x%x sha256' % ram)
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > + # Read again to verify it changed
> > + read_pcr_after = ubman.run_command('wolftpm pcr_read 16 sha256')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_pcr_print(ubman):
> > + """Test wolfTPM pcr_print command.
> > +
> > + Print all assigned PCRs.
> > + """
> > + force_init(ubman)
> > +
> > + pcr_output = ubman.run_command('wolftpm pcr_print')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > + # Should contain PCR info
> > + assert 'PCR' in pcr_output or 'Assigned' in pcr_output
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_info(ubman):
> > + """Test wolfTPM info command.
> > +
> > + Display TPM device information.
> > + """
> > + force_init(ubman)
> > +
> > + ubman.run_command('wolftpm info')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_state(ubman):
> > + """Test wolfTPM state command.
> > +
> > + Display TPM internal state.
> > + """
> > + force_init(ubman)
> > +
> > + ubman.run_command('wolftpm state')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_device(ubman):
> > + """Test wolfTPM device command.
> > +
> > + Show all TPM devices.
> > + """
> > + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip',
> False)
> > + if skip_test:
> > + pytest.skip('skip wolfTPM device test')
> > + ubman.run_command('wolftpm device')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_startup_clear(ubman):
> > + """Test wolfTPM startup command with TPM2_SU_CLEAR.
> > +
> > + Issue TPM2_Startup with CLEAR mode (reset state).
> > + """
> > + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip',
> False)
> > + if skip_test:
> > + pytest.skip('skip wolfTPM device test')
> > + ubman.run_command('wolftpm init')
> > + ubman.run_command('wolftpm startup TPM2_SU_CLEAR')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_startup_state(ubman):
> > + """Test wolfTPM startup command with TPM2_SU_STATE.
> > +
> > + Issue TPM2_Startup with STATE mode (preserved state).
> > + """
> > + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip',
> False)
> > + if skip_test:
> > + pytest.skip('skip wolfTPM device test')
> > + # First autostart to have valid state
> > + ubman.run_command('wolftpm autostart')
> > + # Shutdown with STATE
> > + ubman.run_command('wolftpm startup TPM2_SU_STATE off')
> > + # Re-init
> > + ubman.run_command('wolftpm init')
> > + # Startup with STATE - may return already started
> > + ubman.run_command('wolftpm startup TPM2_SU_STATE')
> > + output = ubman.run_command('echo $?')
> > + # May return non-zero if already started, just verify command ran
> > + assert output is not None
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_startup_shutdown(ubman):
> > + """Test wolfTPM startup shutdown command.
> > +
> > + Issue TPM2_Shutdown.
> > + """
> > + skip_test = ubman.config.env.get('env__wolftpm_device_test_skip',
> False)
> > + if skip_test:
> > + pytest.skip('skip wolfTPM device test')
> > + ubman.run_command('wolftpm autostart')
> > + ubman.run_command('wolftpm startup TPM2_SU_CLEAR off')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_get_capability(ubman):
> > + """Test wolfTPM get_capability command.
> > +
> > + Read TPM capabilities by property.
> > + """
> > + force_init(ubman)
> > + ram = utils.find_ram_base(ubman)
> > +
> > + # Get capability - TPM_CAP_TPM_PROPERTIES (0x6), PT_MANUFACTURER
> (0x20e)
> > + ubman.run_command('wolftpm get_capability 0x6 0x20e 0x%x 1' % ram)
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_pcr_allocate(ubman):
> > + """Test wolfTPM pcr_allocate command.
> > +
> > + Reconfigure PCR bank algorithm.
> > + Note: A TPM restart is required for changes to take effect.
> > + """
> > + force_init(ubman)
> > +
> > + # Allocate SHA256 bank on
> > + ubman.run_command('wolftpm pcr_allocate SHA256 on')
> > + output = ubman.run_command('echo $?')
> > + assert output.endswith('0')
> > +
> > +
> > + at pytest.mark.buildconfigspec('tpm_wolf')
> > +def test_wolftpm_cleanup(ubman):
> > + """Cleanup test - ensure TPM is cleared after tests."""
> > + force_init(ubman, True)
>
> Thanks
> /Ilias
>
More information about the U-Boot
mailing list