public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE ***
@ 2026-03-16 18:14 David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm David Garske
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw)
  To: u-boot; +Cc: David Garske

*** BLURB HERE ***

Aidan (12):
  tpm: export tpm_show_device, tpm_set_device, and get_tpm
  include: add byteorder macro guards and SHA384 hash wrapper
  spi: add BCM2835/BCM2711 hardware SPI controller driver
  dts: add TPM device tree nodes for RPi4, QEMU, and sandbox
  tpm: add wolfTPM library as git submodule
  tpm: add wolfTPM headers and SHA384 glue code
  tpm: add wolfTPM driver helpers and Kconfig options
  cmd: refactor tpm2 command into frontend/backend architecture
  tpm: add sandbox TPM SPI emulator
  test: add wolfTPM C unit tests and Python integration tests
  doc: add wolfTPM documentation
  configs: enable wolfTPM in rpi_4_defconfig

 .gitmodules                              |    3 +
 README                                   |    3 +
 README.wolftpm.md                        |  154 +++
 arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi |   54 +
 arch/arm/dts/bcm2711-rpi-4-b.dts         |   20 +
 arch/arm/dts/qemu-arm64.dts              |    4 +
 arch/sandbox/dts/sandbox.dtsi            |   11 +
 cmd/Kconfig                              |   11 +
 cmd/Makefile                             |   10 +-
 cmd/native_tpm2.c                        |  516 ++++++++++
 cmd/tpm-common.c                         |    4 +-
 cmd/tpm-v2.c                             |  559 ++---------
 cmd/tpm2-backend.h                       |   66 ++
 cmd/wolftpm.c                            | 1170 ++++++++++++++++++++++
 configs/rpi_4_defconfig                  |   29 +-
 doc/usage/cmd/wolftpm.rst                |  635 ++++++++++++
 drivers/mtd/spi/sandbox.c                |   30 +-
 drivers/spi/Kconfig                      |    9 +
 drivers/spi/Makefile                     |    1 +
 drivers/spi/bcm2835_spi.c                |  431 ++++++++
 drivers/tpm/Kconfig                      |   44 +
 drivers/tpm/Makefile                     |    9 +
 drivers/tpm/tpm_spi_sandbox.c            |  410 ++++++++
 drivers/tpm/wolftpm_common.c             |  137 +++
 include/configs/user_settings.h          |  118 +++
 include/hash.h                           |   18 +
 include/linux/byteorder/generic.h        |   31 +-
 include/tpm-common.h                     |   22 +
 include/wolftpm.h                        |   34 +
 lib/Kconfig                              |   13 +
 lib/Makefile                             |   18 +
 lib/wolftpm                              |    1 +
 lib/wolftpm.c                            |   56 ++
 test/cmd/Makefile                        |    1 +
 test/cmd/wolftpm.c                       |  364 +++++++
 test/py/tests/test_wolftpm.py            |  375 +++++++
 36 files changed, 4861 insertions(+), 510 deletions(-)
 create mode 100644 .gitmodules
 create mode 100644 README.wolftpm.md
 create mode 100644 arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi
 create mode 100644 cmd/native_tpm2.c
 create mode 100644 cmd/tpm2-backend.h
 create mode 100644 cmd/wolftpm.c
 create mode 100644 doc/usage/cmd/wolftpm.rst
 create mode 100644 drivers/spi/bcm2835_spi.c
 create mode 100644 drivers/tpm/tpm_spi_sandbox.c
 create mode 100644 drivers/tpm/wolftpm_common.c
 create mode 100644 include/configs/user_settings.h
 create mode 100644 include/wolftpm.h
 create mode 160000 lib/wolftpm
 create mode 100644 lib/wolftpm.c
 create mode 100644 test/cmd/wolftpm.c
 create mode 100644 test/py/tests/test_wolftpm.py

-- 
2.43.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm
  2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske
@ 2026-03-16 18:14 ` David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 02/12] include: add byteorder macro guards and SHA384 hash wrapper David Garske
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw)
  To: u-boot; +Cc: Aidan

From: Aidan <aidan@wolfssl.com>

Remove static scope from tpm_show_device(), tpm_set_device(), and
get_tpm() in cmd/tpm-common.c so they can be called from other
translation units. Add corresponding declarations to
include/tpm-common.h.

wolfTPM's command backend needs these functions for device enumeration
and selection when operating through U-Boot's driver model.

Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
 cmd/tpm-common.c     |  4 ++--
 include/tpm-common.h | 22 ++++++++++++++++++++++
 2 files changed, 24 insertions(+), 2 deletions(-)

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/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 */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 02/12] include: add byteorder macro guards and SHA384 hash wrapper
  2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm David Garske
@ 2026-03-16 18:14 ` David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 03/12] spi: add BCM2835/BCM2711 hardware SPI controller driver David Garske
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw)
  To: u-boot; +Cc: Aidan

From: Aidan <aidan@wolfssl.com>

Add #ifndef guards around cpu_to_beXX / beXX_to_cpu macro definitions
in include/linux/byteorder/generic.h. wolfTPM, wolfCrypt, and U-Boot
all define these macros; the guards prevent redefinition warnings when
wolfTPM headers are included alongside U-Boot headers.

Add #include <linux/types.h> to include/hash.h so that basic types
(u8, u32, etc.) are available to all includers.

Add a wc_Sha384Hash() wrapper declaration in include/hash.h, gated
by WOLFTPM2_NO_WOLFCRYPT. When wolfTPM is built without wolfCrypt,
this wrapper provides SHA-384 hashing via U-Boot's hash subsystem,
which is needed for Infineon TPM firmware update manifest validation.

Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
 include/hash.h                    | 18 ++++++++++++++++++
 include/linux/byteorder/generic.h | 31 +++++++++++++++++++++++++------
 2 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/include/hash.h b/include/hash.h
index 8b3f79ec473..26043c43a9c 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,20 @@ 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
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 03/12] spi: add BCM2835/BCM2711 hardware SPI controller driver
  2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 02/12] include: add byteorder macro guards and SHA384 hash wrapper David Garske
@ 2026-03-16 18:14 ` David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 04/12] dts: add TPM device tree nodes for RPi4, QEMU, and sandbox David Garske
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw)
  To: u-boot; +Cc: Aidan

From: Aidan <aidan@wolfssl.com>

Add a hardware SPI controller driver for the BCM2835/BCM2711 SoC
found on Raspberry Pi 3 and Pi 4 boards.

The driver implements:
- Register-based SPI transfers using the BCM2835 SPI0 peripheral
- Software GPIO chip-select control (matching the Linux driver
  approach) rather than hardware CS, which avoids issues with
  automatic CS deassertion during multi-byte TPM TIS transactions
- Clock divider calculation for configurable SPI speed
- SPI mode 0/1/2/3 support via CPOL/CPHA configuration
- GPIO pin setup for SPI0 (MISO/MOSI/SCLK as ALT0, CE0/CE1 as
  output for software CS)
- TPM reset via GPIO4/GPIO24 during probe

This driver is needed for wolfTPM to communicate with SPI-attached
TPM chips (e.g., Infineon SLB9670/9672) on Raspberry Pi hardware.

Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
 drivers/spi/Kconfig       |   9 +
 drivers/spi/Makefile      |   1 +
 drivers/spi/bcm2835_spi.c | 431 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 441 insertions(+)
 create mode 100644 drivers/spi/bcm2835_spi.c

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..8133a41a0f8
--- /dev/null
+++ b/drivers/spi/bcm2835_spi.c
@@ -0,0 +1,431 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * BCM2835/BCM2711 SPI controller driver for U-Boot
+ *
+ * Copyright (C) 2025 wolfSSL Inc.
+ * Author: Aidan Garske <aidan@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) {
+		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,
+};
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 04/12] dts: add TPM device tree nodes for RPi4, QEMU, and sandbox
  2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske
                   ` (2 preceding siblings ...)
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 03/12] spi: add BCM2835/BCM2711 hardware SPI controller driver David Garske
@ 2026-03-16 18:14 ` David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 05/12] tpm: add wolfTPM library as git submodule David Garske
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw)
  To: u-boot; +Cc: Aidan

From: Aidan <aidan@wolfssl.com>

Add device tree entries for TPM devices across three platforms:

bcm2711-rpi-4-b.dts:
  Add SPI0 node with Infineon SLB9670/9672 TPM on CE1 (GPIO7),
  matching the standard Linux tpm-slb9670 overlay. Add spi0 alias
  so wolfTPM finds the bus at index 0.

bcm2711-rpi-4-b-u-boot.dtsi (new file):
  Add soft-SPI (GPIO bit-bang) fallback node for TPM communication.
  This uses spi-gpio with GPIO11/10/9/7 and provides an alternative
  to the hardware SPI driver when pinctrl naming differs between
  U-Boot and Linux device trees.

qemu-arm64.dts:
  Add MMIO-based TPM TIS node at 0x0c000000 for QEMU virt machine
  with swtpm. This allows wolfTPM testing via QEMU without hardware.

sandbox.dtsi:
  Add sandbox TPM SPI device (sandbox,tpm-spi) on SPI bus CS1 with
  a phandle reference to a sandbox TPM SPI emulator node. This
  enables wolfTPM SPI HAL testing in the sandbox environment.

Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
 arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi | 54 ++++++++++++++++++++++++
 arch/arm/dts/bcm2711-rpi-4-b.dts         | 20 +++++++++
 arch/arm/dts/qemu-arm64.dts              |  4 ++
 arch/sandbox/dts/sandbox.dtsi            | 11 +++++
 4 files changed, 89 insertions(+)
 create mode 100644 arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi

diff --git a/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi b/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi
new file mode 100644
index 00000000000..c38276abee9
--- /dev/null
+++ b/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * U-Boot specific additions for Raspberry Pi 4 Model B
+ *
+ * Adds soft SPI support for Infineon SLB9670/9672 TPM HAT
+ * connected to SPI0 CE1 (GPIO 7)
+ *
+ * Uses GPIO bit-banging instead of hardware SPI to avoid
+ * GPIO chip naming issues (pinctrl-bcm2835 vs pinctrl-bcm2711)
+ */
+
+#include "bcm283x-u-boot.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	aliases {
+		spi0 = &soft_spi;
+	};
+
+	soft_spi: soft-spi {
+		compatible = "spi-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "okay";
+		bootph-all;
+
+		/*
+		 * GPIO pins for SPI0 on Raspberry Pi 4:
+		 * GPIO 11 = SCLK
+		 * GPIO 10 = MOSI
+		 * GPIO 9  = MISO
+		 * GPIO 7  = CE1 (chip select for TPM)
+		 */
+		gpio-sck = <&gpio 11 GPIO_ACTIVE_HIGH>;
+		gpio-mosi = <&gpio 10 GPIO_ACTIVE_HIGH>;
+		gpio-miso = <&gpio 9 GPIO_ACTIVE_HIGH>;
+		cs-gpios = <&gpio 7 GPIO_ACTIVE_LOW>;
+		num-chipselects = <1>;
+		spi-delay-us = <1>;
+
+		/* Infineon SLB9672 TPM on CS1 */
+		tpm@0 {
+			compatible = "infineon,slb9672", "tcg,tpm-tis-spi";
+			reg = <0>;
+			spi-max-frequency = <10000000>;
+			status = "okay";
+			bootph-all;
+		};
+	};
+};
+
+&gpio {
+	bootph-all;
+};
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@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@0c000000 {
+		compatible = "tcg,tpm-tis-mmio";
+		reg = <0x0 0x0c000000 0x0 0x5000>;
+	};
 };
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@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 {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 05/12] tpm: add wolfTPM library as git submodule
  2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske
                   ` (3 preceding siblings ...)
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 04/12] dts: add TPM device tree nodes for RPi4, QEMU, and sandbox David Garske
@ 2026-03-16 18:14 ` David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 06/12] tpm: add wolfTPM headers and SHA384 glue code David Garske
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw)
  To: u-boot; +Cc: Aidan

From: Aidan <aidan@wolfssl.com>

Add wolfTPM (https://github.com/wolfSSL/wolfTPM) as a git submodule
at lib/wolftpm. wolfTPM is a portable, open-source TPM 2.0 stack
licensed under GPLv2, providing native API access to all TPM 2.0
commands and a wrapper API for common operations.

The build system additions:

.gitmodules:
  Registers the wolfTPM submodule pointing to the upstream repo.

lib/Kconfig:
  Adds CONFIG_TPM_WOLF option under library routines, which selects
  SHA1 and implies DM_RNG.

lib/Makefile:
  When CONFIG_TPM_WOLF and CONFIG_TPM_V2 are both enabled, compiles
  wolfTPM core source files (tpm2.c, tpm2_packet.c, tpm2_tis.c,
  tpm2_wrap.c, tpm2_param_enc.c) and the HAL layer (tpm_io.c).
  Sets -I include paths and -DWOLFTPM_USER_SETTINGS.

Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
 .gitmodules  |  3 +++
 lib/Kconfig  | 13 +++++++++++++
 lib/Makefile | 18 ++++++++++++++++++
 lib/wolftpm  |  1 +
 4 files changed, 35 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 lib/wolftpm

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000000..3f95a7c3eb9
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "lib/wolftpm"]
+	path = lib/wolftpm
+	url = https://github.com/wolfssl/wolfTPM.git
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..76025cc77d8 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 += -I$(srctree)/lib/wolftpm \
+             -I$(srctree)/include/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..664db130d57
--- /dev/null
+++ b/lib/wolftpm
@@ -0,0 +1 @@
+Subproject commit 664db130d57bfa18a3254a0ddc126da1beeb9895
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 06/12] tpm: add wolfTPM headers and SHA384 glue code
  2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske
                   ` (4 preceding siblings ...)
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 05/12] tpm: add wolfTPM library as git submodule David Garske
@ 2026-03-16 18:14 ` David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 07/12] tpm: add wolfTPM driver helpers and Kconfig options David Garske
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw)
  To: u-boot; +Cc: Aidan

From: Aidan <aidan@wolfssl.com>

Add the wolfTPM integration headers and hash wrapper needed to bridge
wolfTPM with U-Boot's subsystems.

include/wolftpm.h:
  Public header exposing TPM2_PCRs_Print(), TPM2_Init_Device(), and
  Infineon firmware update helpers (TPM2_IFX_FwData_Cb,
  TPM2_IFX_GetOpModeStr, TPM2_IFX_PrintInfo). Includes the core
  wolfTPM headers (tpm2.h, tpm2_wrap.h, tpm2_packet.h).

include/configs/user_settings.h:
  wolfTPM compile-time configuration. Selects TPM chip type
  (SLB9672/SLB9673 for real hardware, WOLFTPM_AUTODETECT for
  swtpm/QEMU), communication mode (native SPI TIS layer for real
  hardware, WOLFTPM_LINUX_DEV for U-Boot driver model), timeout
  tuning, and feature flags (WOLFTPM2_NO_WOLFCRYPT,
  WOLFTPM2_NO_HEAP, WOLFTPM_CHECK_WAIT_STATE).

lib/wolftpm.c:
  Provides wc_Sha384Hash() implementation when wolfCrypt is disabled
  (WOLFTPM2_NO_WOLFCRYPT). Uses U-Boot's hash_lookup_algo("sha384")
  to compute SHA-384 digests, which is required for Infineon TPM
  firmware update manifest validation.

Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
 include/configs/user_settings.h | 118 ++++++++++++++++++++++++++++++++
 include/wolftpm.h               |  34 +++++++++
 lib/wolftpm.c                   |  56 +++++++++++++++
 3 files changed, 208 insertions(+)
 create mode 100644 include/configs/user_settings.h
 create mode 100644 include/wolftpm.h
 create mode 100644 lib/wolftpm.c

diff --git a/include/configs/user_settings.h b/include/configs/user_settings.h
new file mode 100644
index 00000000000..e62be7a8f30
--- /dev/null
+++ b/include/configs/user_settings.h
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * wolfTPM build configuration for U-Boot
+ *
+ * Copyright (C) 2025 wolfSSL Inc.
+ * Author: Aidan Garske <aidan@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 __cplusplus
+}
+#endif
+
+#endif /* USER_SETTINGS_H */
diff --git a/include/wolftpm.h b/include/wolftpm.h
new file mode 100644
index 00000000000..a3cd9d0d2dd
--- /dev/null
+++ b/include/wolftpm.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * wolfTPM integration header for U-Boot
+ *
+ * Copyright (C) 2025 wolfSSL Inc.
+ * Author: Aidan Garske <aidan@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/wolftpm.c b/lib/wolftpm.c
new file mode 100644
index 00000000000..49e35401236
--- /dev/null
+++ b/lib/wolftpm.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * wolfTPM wrapper layer for U-Boot
+ *
+ * Copyright (C) 2025 wolfSSL Inc.
+ * Author: Aidan Garske <aidan@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 */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 07/12] tpm: add wolfTPM driver helpers and Kconfig options
  2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske
                   ` (5 preceding siblings ...)
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 06/12] tpm: add wolfTPM headers and SHA384 glue code David Garske
@ 2026-03-16 18:14 ` David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 08/12] cmd: refactor tpm2 command into frontend/backend architecture David Garske
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw)
  To: u-boot; +Cc: Aidan

From: Aidan <aidan@wolfssl.com>

Add wolfTPM helper functions and configuration options to the TPM
driver subsystem.

drivers/tpm/wolftpm_common.c:
  Shared helper functions used by the wolfTPM command backend:
  - TPM2_IFX_FwData_Cb(): firmware data callback for Infineon
    firmware update streaming
  - TPM2_IFX_GetOpModeStr(): converts Infineon operational mode
    codes to human-readable strings
  - TPM2_IFX_PrintInfo(): prints manufacturer, vendor, firmware
    version, and operational mode from WOLFTPM2_CAPS
  - TPM2_PCRs_Print(): enumerates and prints assigned PCR banks
    and their selected PCR indices
  - TPM2_Init_Device(): initializes wolfTPM with the TPM2_IoCb
    HAL callback

drivers/tpm/Kconfig:
  Adds configuration options under TPM_V2:
  - TPM2_SPI_SANDBOX: sandbox TPM SPI emulator for testing
  - TPM_AUTODETECT: auto-detect TPM chip for swtpm/QEMU
  - WOLFTPM_LINUX_DEV: use U-Boot driver model instead of
    wolfTPM's native TIS layer
  - WOLFTPM_SLB9672/SLB9673: Infineon chip-specific features
  - WOLFTPM_FIRMWARE_UPGRADE: firmware update support

drivers/tpm/Makefile:
  Compiles wolftpm_common.o and sets wolfTPM include paths and
  -DWOLFTPM_USER_SETTINGS when CONFIG_TPM_WOLF is enabled.

Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
 drivers/tpm/Kconfig          |  44 +++++++++++
 drivers/tpm/Makefile         |   9 +++
 drivers/tpm/wolftpm_common.c | 137 +++++++++++++++++++++++++++++++++++
 3 files changed, 190 insertions(+)
 create mode 100644 drivers/tpm/wolftpm_common.c

diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig
index 219ea606b50..a2897a0e040 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,42 @@ 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 TPM_AUTODETECT
+    bool "wolfTPM auto-detect TPM chip (for swtpm/QEMU)"
+    depends on TPM_V2 && TPM_WOLF
+    help
+      Enable wolfTPM chip auto-detection instead of using a specific
+      chip type (SLB9672/SLB9673). Use this for swtpm/QEMU testing
+      where no specific hardware chip is present.
+
+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..bee4193e9fc 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 += -I$(srctree)/lib/wolftpm \
+             -I$(srctree)/include/configs \
+             -DWOLFTPM_USER_SETTINGS
+obj-y += wolftpm_common.o
+endif
diff --git a/drivers/tpm/wolftpm_common.c b/drivers/tpm/wolftpm_common.c
new file mode 100644
index 00000000000..bea36cf0229
--- /dev/null
+++ b/drivers/tpm/wolftpm_common.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * wolfTPM common helper functions for U-Boot
+ *
+ * Copyright (C) 2025 wolfSSL Inc.
+ * Author: Aidan Garske <aidan@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 -- */
+/******************************************************************************/
+
+struct fw_info {
+	byte *manifest_buf;
+	byte *firmware_buf;
+	size_t manifest_bufSz;
+	size_t firmware_bufSz;
+};
+
+int TPM2_IFX_FwData_Cb(uint8_t *data, uint32_t data_req_sz,
+			uint32_t offset, void *cb_ctx)
+{
+	struct fw_info *fwinfo = (struct fw_info *)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)
+		memcpy(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)
+{
+	int rc;
+
+	/* Use TPM2_IoCb callback for packet-level access */
+	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 -- */
+/******************************************************************************/
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 08/12] cmd: refactor tpm2 command into frontend/backend architecture
  2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske
                   ` (6 preceding siblings ...)
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 07/12] tpm: add wolfTPM driver helpers and Kconfig options David Garske
@ 2026-03-16 18:14 ` David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 09/12] tpm: add sandbox TPM SPI emulator David Garske
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw)
  To: u-boot; +Cc: Aidan

From: Aidan <aidan@wolfssl.com>

Split the tpm2 command implementation into a shared frontend and
two selectable backends. This allows wolfTPM to provide its own
TPM2 command implementations while keeping the command table,
dispatcher, and help text shared.

Architecture:

cmd/tpm-v2.c (frontend - always compiled):
  Contains the tpm2_commands[] table, get_tpm2_commands(), the
  do_tpm2() dispatcher, and the U_BOOT_CMD help text. References
  backend functions via cmd/tpm2-backend.h. When CONFIG_TPM_WOLF
  is enabled, additional wolfTPM-only commands (caps, pcr_print,
  firmware_update, firmware_cancel) are added to the table.

cmd/tpm2-backend.h (new):
  Declares all backend function prototypes that both backends must
  implement: do_tpm2_device, do_tpm2_info, do_tpm2_init,
  do_tpm2_startup, do_tpm2_selftest, do_tpm2_clear,
  do_tpm2_pcr_extend, do_tpm2_pcr_read, do_tpm2_get_capability,
  do_tpm2_dam_reset, do_tpm2_dam_parameters, do_tpm2_change_auth,
  do_tpm2_pcr_setauthpolicy, do_tpm2_pcr_setauthvalue,
  do_tpm2_pcr_allocate, plus wolfTPM-only functions.

cmd/native_tpm2.c (new - native backend):
  Contains the original tpm2 command implementations that use
  U-Boot's TPM driver model (tpm_api.h, tpm-v2.h). Compiled when
  CONFIG_TPM_WOLF is not set. Common commands delegate to
  tpm-common.c helpers (do_tpm_device, do_tpm_info, etc.).

cmd/wolftpm.c (new - wolfTPM backend):
  Implements all tpm2 commands using wolfTPM library APIs directly
  (wolfTPM2_Init, wolfTPM2_GetCapabilities, wolfTPM2_ExtendPCR,
  etc.). Includes Infineon-specific firmware update and cancel
  commands. Each command initializes its own WOLFTPM2_DEV instance
  rather than going through U-Boot's driver model.

cmd/Kconfig:
  Adds CMD_WOLFTPM option that selects TPM_WOLF and CMD_TPM_V2,
  providing a single menuconfig toggle for wolfTPM support.

cmd/Makefile:
  Conditionally compiles wolftpm.o (when CONFIG_TPM_WOLF=y) or
  native_tpm2.o (otherwise) alongside the shared tpm-v2.o frontend.
  Sets wolfTPM include paths and -DWOLFTPM_USER_SETTINGS.

The reason for separate backend files rather than a callback-based
approach is that wolfTPM uses fundamentally different types and
initialization patterns (WOLFTPM2_DEV vs struct udevice, direct
library calls vs driver model ops), making runtime dispatch
impractical without heavy abstraction.

Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
 cmd/Kconfig        |   11 +
 cmd/Makefile       |   10 +-
 cmd/native_tpm2.c  |  516 +++++++++++++++++++
 cmd/tpm-v2.c       |  559 +++------------------
 cmd/tpm2-backend.h |   66 +++
 cmd/wolftpm.c      | 1170 ++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 1840 insertions(+), 492 deletions(-)
 create mode 100644 cmd/native_tpm2.c
 create mode 100644 cmd/tpm2-backend.h
 create mode 100644 cmd/wolftpm.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 322ebe600c5..d9360d5237a 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -3202,4 +3202,15 @@ 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 "Use wolfTPM as TPM2 backend"
+	depends on TPM_V2
+	select TPM_WOLF
+	select CMD_TPM_V2
+	help
+	  Use the wolfTPM library as the backend for TPM2 commands instead
+	  of the standard U-Boot TPM2 implementation. wolfTPM offers additional
+	  features including firmware update support for Infineon TPMs and
+	  enhanced capabilities reporting.
+
 endif
diff --git a/cmd/Makefile b/cmd/Makefile
index 4cd13d4fa6e..2b12b26e61f 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -191,9 +191,17 @@ 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
+obj-$(CONFIG_CMD_TPM_V1) += tpm-v1.o
 obj-$(CONFIG_CMD_TPM_V2) += tpm-v2.o
+ifeq ($(CONFIG_TPM_WOLF),y)
+ccflags-y += -I$(srctree)/lib/wolftpm \
+             -I$(srctree)/include/configs \
+             -DWOLFTPM_USER_SETTINGS
+obj-$(CONFIG_CMD_TPM_V2) += wolftpm.o
+else
+obj-$(CONFIG_CMD_TPM_V2) += native_tpm2.o
+endif
 obj-$(CONFIG_CMD_CROS_EC) += cros_ec.o
 obj-$(CONFIG_CMD_UBI) += ubi.o
 obj-$(CONFIG_CMD_UBIFS) += ubifs.o
diff --git a/cmd/native_tpm2.c b/cmd/native_tpm2.c
new file mode 100644
index 00000000000..d8dea956156
--- /dev/null
+++ b/cmd/native_tpm2.c
@@ -0,0 +1,516 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Native TPM2 backend implementation
+ *
+ * Copyright (c) 2018 Bootlin
+ * Author: Miquel Raynal <miquel.raynal@bootlin.com>
+ */
+
+#include <command.h>
+#include <dm.h>
+#include <log.h>
+#include <mapmem.h>
+#include <tpm-common.h>
+#include <tpm-v2.h>
+#include "tpm-user-utils.h"
+
+/* Wrappers for common commands - delegate to tpm-common.c */
+int do_tpm2_device(struct cmd_tbl *cmdtp, int flag, int argc,
+		   char *const argv[])
+{
+	return do_tpm_device(cmdtp, flag, argc, argv);
+}
+
+int do_tpm2_info(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[])
+{
+	return do_tpm_info(cmdtp, flag, argc, argv);
+}
+
+int do_tpm2_state(struct cmd_tbl *cmdtp, int flag, int argc,
+		  char *const argv[])
+{
+	return do_tpm_report_state(cmdtp, flag, argc, argv);
+}
+
+int do_tpm2_init(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[])
+{
+	return do_tpm_init(cmdtp, flag, argc, argv);
+}
+
+int do_tpm2_autostart(struct cmd_tbl *cmdtp, int flag, int argc,
+		      char *const argv[])
+{
+	return do_tpm_autostart(cmdtp, flag, argc, argv);
+}
+
+int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc,
+		    char *const argv[])
+{
+	enum tpm2_startup_types mode;
+	struct udevice *dev;
+	int ret;
+	bool bon = true;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	/* argv[2] is optional to perform a TPM2_CC_SHUTDOWN */
+	if (argc > 3 || (argc == 3 && strcasecmp("off", argv[2])))
+		return CMD_RET_USAGE;
+
+	if (!strcasecmp("TPM2_SU_CLEAR", argv[1])) {
+		mode = TPM2_SU_CLEAR;
+	} else if (!strcasecmp("TPM2_SU_STATE", argv[1])) {
+		mode = TPM2_SU_STATE;
+	} else {
+		printf("Couldn't recognize mode string: %s\n", argv[1]);
+		return CMD_RET_FAILURE;
+	}
+
+	if (argv[2])
+		bon = false;
+
+	return report_return_code(tpm2_startup(dev, bon, mode));
+}
+
+int do_tpm2_selftest(struct cmd_tbl *cmdtp, int flag, int argc,
+		     char *const argv[])
+{
+	enum tpm2_yes_no full_test;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	if (!strcasecmp("full", argv[1])) {
+		full_test = TPMI_YES;
+	} else if (!strcasecmp("continue", argv[1])) {
+		full_test = TPMI_NO;
+	} else {
+		printf("Couldn't recognize test mode: %s\n", argv[1]);
+		return CMD_RET_FAILURE;
+	}
+
+	return report_return_code(tpm2_self_test(dev, full_test));
+}
+
+int do_tpm2_clear(struct cmd_tbl *cmdtp, int flag, int argc,
+		  char *const argv[])
+{
+	u32 handle = 0;
+	const char *pw = (argc < 3) ? NULL : argv[2];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (argc < 2 || argc > 3)
+		return CMD_RET_USAGE;
+
+	if (pw_sz > TPM2_DIGEST_LEN)
+		return -EINVAL;
+
+	if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1]))
+		handle = TPM2_RH_LOCKOUT;
+	else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1]))
+		handle = TPM2_RH_PLATFORM;
+	else
+		return CMD_RET_USAGE;
+
+	return report_return_code(tpm2_clear(dev, handle, pw, pw_sz));
+}
+
+int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, int argc,
+		       char *const argv[])
+{
+	struct udevice *dev;
+	struct tpm_chip_priv *priv;
+	u32 index = simple_strtoul(argv[1], NULL, 0);
+	void *digest = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0);
+	int algo = TPM2_ALG_SHA256;
+	int algo_len;
+	int ret;
+	u32 rc;
+
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+	if (argc == 4) {
+		algo = tpm2_name_to_algorithm(argv[3]);
+		if (algo == TPM2_ALG_INVAL)
+			return CMD_RET_FAILURE;
+	}
+	algo_len = tpm2_algorithm_to_len(algo);
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	priv = dev_get_uclass_priv(dev);
+	if (!priv)
+		return -EINVAL;
+
+	if (index >= priv->pcr_count)
+		return -EINVAL;
+
+	rc = tpm2_pcr_extend(dev, index, algo, digest, algo_len);
+	if (!rc) {
+		printf("PCR #%u extended with %d byte %s digest\n", index,
+		       algo_len, tpm2_algorithm_name(algo));
+		print_byte_string(digest, algo_len);
+	}
+
+	unmap_sysmem(digest);
+
+	return report_return_code(rc);
+}
+
+int do_tpm2_pcr_read(struct cmd_tbl *cmdtp, int flag, int argc,
+		     char *const argv[])
+{
+	enum tpm2_algorithms algo = TPM2_ALG_SHA256;
+	struct udevice *dev;
+	struct tpm_chip_priv *priv;
+	u32 index, rc;
+	int algo_len;
+	unsigned int updates;
+	void *data;
+	int ret;
+
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+	if (argc == 4) {
+		algo = tpm2_name_to_algorithm(argv[3]);
+		if (algo == TPM2_ALG_INVAL)
+			return CMD_RET_FAILURE;
+	}
+	algo_len = tpm2_algorithm_to_len(algo);
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	priv = dev_get_uclass_priv(dev);
+	if (!priv)
+		return -EINVAL;
+
+	index = simple_strtoul(argv[1], NULL, 0);
+	if (index >= priv->pcr_count)
+		return -EINVAL;
+
+	data = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0);
+
+	rc = tpm2_pcr_read(dev, index, priv->pcr_select_min, algo,
+			   data, algo_len, &updates);
+	if (!rc) {
+		printf("PCR #%u %s %d byte content (%u known updates):\n", index,
+		       tpm2_algorithm_name(algo), algo_len, updates);
+		print_byte_string(data, algo_len);
+	}
+
+	unmap_sysmem(data);
+
+	return report_return_code(rc);
+}
+
+int do_tpm2_get_capability(struct cmd_tbl *cmdtp, int flag, int argc,
+			   char *const argv[])
+{
+	u32 capability, property, rc;
+	u8 *data;
+	size_t count;
+	int i, j;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	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);
+
+	rc = tpm2_get_capability(dev, capability, property, data, count);
+	if (rc)
+		goto unmap_data;
+
+	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_data:
+	unmap_sysmem(data);
+
+	return report_return_code(rc);
+}
+
+static u32 select_mask(u32 mask, enum tpm2_algorithms algo, bool select)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) {
+		if (hash_algo_list[i].hash_alg != algo)
+			continue;
+
+		if (select)
+			mask |= hash_algo_list[i].hash_mask;
+		else
+			mask &= ~hash_algo_list[i].hash_mask;
+
+		break;
+	}
+
+	return mask;
+}
+
+static bool
+is_algo_in_pcrs(enum tpm2_algorithms algo, struct tpml_pcr_selection *pcrs)
+{
+	size_t i;
+
+	for (i = 0; i < pcrs->count; i++) {
+		if (algo == pcrs->selection[i].hash)
+			return true;
+	}
+
+	return false;
+}
+
+int do_tpm2_pcr_allocate(struct cmd_tbl *cmdtp, int flag, int argc,
+			 char *const argv[])
+{
+	struct udevice *dev;
+	int ret;
+	enum tpm2_algorithms algo;
+	const char *pw = (argc < 4) ? NULL : argv[3];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+	static struct tpml_pcr_selection pcr = { 0 };
+	u32 pcr_len = 0;
+	bool bon = false;
+	static u32 mask;
+	int i;
+
+	/* argv[1]: algorithm (bank), argv[2]: on/off */
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+
+	if (!strcasecmp("on", argv[2]))
+		bon = true;
+	else if (strcasecmp("off", argv[2]))
+		return CMD_RET_USAGE;
+
+	algo = tpm2_name_to_algorithm(argv[1]);
+	if (algo == TPM2_ALG_INVAL)
+		return CMD_RET_USAGE;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (!pcr.count) {
+		/*
+		 * Get current active algorithms (banks), PCRs and mask via the
+		 * first call
+		 */
+		ret = tpm2_get_pcr_info(dev, &pcr);
+		if (ret)
+			return ret;
+
+		for (i = 0; i < pcr.count; i++) {
+			struct tpms_pcr_selection *sel = &pcr.selection[i];
+			const char *name;
+
+			if (!tpm2_is_active_bank(sel))
+				continue;
+
+			mask = select_mask(mask, sel->hash, true);
+			name = tpm2_algorithm_name(sel->hash);
+			if (name)
+				printf("Active bank[%d]: %s\n", i, name);
+		}
+	}
+
+	if (!is_algo_in_pcrs(algo, &pcr)) {
+		printf("%s is not supported by the tpm device\n", argv[1]);
+		return CMD_RET_USAGE;
+	}
+
+	mask = select_mask(mask, algo, bon);
+	ret = tpm2_pcr_config_algo(dev, mask, &pcr, &pcr_len);
+	if (ret)
+		return ret;
+
+	return report_return_code(tpm2_send_pcr_allocate(dev, pw, pw_sz, &pcr,
+							 pcr_len));
+}
+
+int do_tpm2_dam_reset(struct cmd_tbl *cmdtp, int flag, int argc,
+		      char *const argv[])
+{
+	const char *pw = (argc < 2) ? NULL : argv[1];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (argc > 2)
+		return CMD_RET_USAGE;
+
+	if (pw_sz > TPM2_DIGEST_LEN)
+		return -EINVAL;
+
+	return report_return_code(tpm2_dam_reset(dev, pw, pw_sz));
+}
+
+int do_tpm2_dam_parameters(struct cmd_tbl *cmdtp, int flag, int argc,
+			   char *const argv[])
+{
+	const char *pw = (argc < 5) ? NULL : argv[4];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+	/*
+	 * No Dictionary Attack Mitigation (DAM) means:
+	 * maxtries = 0xFFFFFFFF, recovery_time = 1, lockout_recovery = 0
+	 */
+	unsigned long int max_tries;
+	unsigned long int recovery_time;
+	unsigned long int lockout_recovery;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (argc < 4 || argc > 5)
+		return CMD_RET_USAGE;
+
+	if (pw_sz > TPM2_DIGEST_LEN)
+		return -EINVAL;
+
+	if (strict_strtoul(argv[1], 0, &max_tries))
+		return CMD_RET_USAGE;
+
+	if (strict_strtoul(argv[2], 0, &recovery_time))
+		return CMD_RET_USAGE;
+
+	if (strict_strtoul(argv[3], 0, &lockout_recovery))
+		return CMD_RET_USAGE;
+
+	log(LOGC_NONE, LOGL_INFO, "Changing dictionary attack parameters:\n");
+	log(LOGC_NONE, LOGL_INFO, "- maxTries: %lu", max_tries);
+	log(LOGC_NONE, LOGL_INFO, "- recoveryTime: %lu\n", recovery_time);
+	log(LOGC_NONE, LOGL_INFO, "- lockoutRecovery: %lu\n", lockout_recovery);
+
+	return report_return_code(tpm2_dam_parameters(dev, pw, pw_sz, max_tries,
+						      recovery_time,
+						      lockout_recovery));
+}
+
+int do_tpm2_change_auth(struct cmd_tbl *cmdtp, int flag, int argc,
+			char *const argv[])
+{
+	u32 handle;
+	const char *newpw = argv[2];
+	const char *oldpw = (argc == 3) ? NULL : argv[3];
+	const ssize_t newpw_sz = strlen(newpw);
+	const ssize_t oldpw_sz = oldpw ? strlen(oldpw) : 0;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+
+	if (newpw_sz > TPM2_DIGEST_LEN || oldpw_sz > TPM2_DIGEST_LEN)
+		return -EINVAL;
+
+	if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1]))
+		handle = TPM2_RH_LOCKOUT;
+	else if (!strcasecmp("TPM2_RH_ENDORSEMENT", argv[1]))
+		handle = TPM2_RH_ENDORSEMENT;
+	else if (!strcasecmp("TPM2_RH_OWNER", argv[1]))
+		handle = TPM2_RH_OWNER;
+	else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1]))
+		handle = TPM2_RH_PLATFORM;
+	else
+		return CMD_RET_USAGE;
+
+	return report_return_code(tpm2_change_auth(dev, handle, newpw, newpw_sz,
+						   oldpw, oldpw_sz));
+}
+
+int do_tpm2_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag, int argc,
+			      char *const argv[])
+{
+	u32 index = simple_strtoul(argv[1], NULL, 0);
+	char *key = argv[2];
+	const char *pw = (argc < 4) ? NULL : argv[3];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (strlen(key) != TPM2_DIGEST_LEN)
+		return -EINVAL;
+
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+
+	return report_return_code(tpm2_pcr_setauthpolicy(dev, pw, pw_sz, index,
+							 key));
+}
+
+int do_tpm2_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
+			     int argc, char *const argv[])
+{
+	u32 index = simple_strtoul(argv[1], NULL, 0);
+	char *key = argv[2];
+	const ssize_t key_sz = strlen(key);
+	const char *pw = (argc < 4) ? NULL : argv[3];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (strlen(key) != TPM2_DIGEST_LEN)
+		return -EINVAL;
+
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+
+	return report_return_code(tpm2_pcr_setauthvalue(dev, pw, pw_sz, index,
+							key, key_sz));
+}
diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c
index 847b2691581..a131a81d1a4 100644
--- a/cmd/tpm-v2.c
+++ b/cmd/tpm-v2.c
@@ -1,507 +1,51 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
+ * TPM2 command frontend - command table, dispatcher, and help text
+ *
+ * The actual command implementations are provided by the backend:
+ *   - native_tpm2.c: U-Boot native TPM2 APIs (driver model)
+ *   - wolftpm.c: wolfTPM library APIs
+ *
  * Copyright (c) 2018 Bootlin
  * Author: Miquel Raynal <miquel.raynal@bootlin.com>
  */
 
 #include <command.h>
-#include <dm.h>
-#include <log.h>
-#include <mapmem.h>
 #include <tpm-common.h>
-#include <tpm-v2.h>
-#include "tpm-user-utils.h"
-
-static int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc,
-			   char *const argv[])
-{
-	enum tpm2_startup_types mode;
-	struct udevice *dev;
-	int ret;
-	bool bon = true;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	/* argv[2] is optional to perform a TPM2_CC_SHUTDOWN */
-	if (argc > 3 || (argc == 3 && strcasecmp("off", argv[2])))
-		return CMD_RET_USAGE;
-
-	if (!strcasecmp("TPM2_SU_CLEAR", argv[1])) {
-		mode = TPM2_SU_CLEAR;
-	} else if (!strcasecmp("TPM2_SU_STATE", argv[1])) {
-		mode = TPM2_SU_STATE;
-	} else {
-		printf("Couldn't recognize mode string: %s\n", argv[1]);
-		return CMD_RET_FAILURE;
-	}
-
-	if (argv[2])
-		bon = false;
-
-	return report_return_code(tpm2_startup(dev, bon, mode));
-}
-
-static int do_tpm2_self_test(struct cmd_tbl *cmdtp, int flag, int argc,
-			     char *const argv[])
-{
-	enum tpm2_yes_no full_test;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-	if (argc != 2)
-		return CMD_RET_USAGE;
-
-	if (!strcasecmp("full", argv[1])) {
-		full_test = TPMI_YES;
-	} else if (!strcasecmp("continue", argv[1])) {
-		full_test = TPMI_NO;
-	} else {
-		printf("Couldn't recognize test mode: %s\n", argv[1]);
-		return CMD_RET_FAILURE;
-	}
-
-	return report_return_code(tpm2_self_test(dev, full_test));
-}
-
-static int do_tpm2_clear(struct cmd_tbl *cmdtp, int flag, int argc,
-			 char *const argv[])
-{
-	u32 handle = 0;
-	const char *pw = (argc < 3) ? NULL : argv[2];
-	const ssize_t pw_sz = pw ? strlen(pw) : 0;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (argc < 2 || argc > 3)
-		return CMD_RET_USAGE;
-
-	if (pw_sz > TPM2_DIGEST_LEN)
-		return -EINVAL;
-
-	if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1]))
-		handle = TPM2_RH_LOCKOUT;
-	else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1]))
-		handle = TPM2_RH_PLATFORM;
-	else
-		return CMD_RET_USAGE;
-
-	return report_return_code(tpm2_clear(dev, handle, pw, pw_sz));
-}
-
-static int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, int argc,
-			      char *const argv[])
-{
-	struct udevice *dev;
-	struct tpm_chip_priv *priv;
-	u32 index = simple_strtoul(argv[1], NULL, 0);
-	void *digest = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0);
-	int algo = TPM2_ALG_SHA256;
-	int algo_len;
-	int ret;
-	u32 rc;
-
-	if (argc < 3 || argc > 4)
-		return CMD_RET_USAGE;
-	if (argc == 4) {
-		algo = tpm2_name_to_algorithm(argv[3]);
-		if (algo == TPM2_ALG_INVAL)
-			return CMD_RET_FAILURE;
-	}
-	algo_len = tpm2_algorithm_to_len(algo);
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	priv = dev_get_uclass_priv(dev);
-	if (!priv)
-		return -EINVAL;
-
-	if (index >= priv->pcr_count)
-		return -EINVAL;
-
-	rc = tpm2_pcr_extend(dev, index, algo, digest, algo_len);
-	if (!rc) {
-		printf("PCR #%u extended with %d byte %s digest\n", index,
-		       algo_len, tpm2_algorithm_name(algo));
-		print_byte_string(digest, algo_len);
-	}
-
-	unmap_sysmem(digest);
-
-	return report_return_code(rc);
-}
-
-static int do_tpm_pcr_read(struct cmd_tbl *cmdtp, int flag, int argc,
-			   char *const argv[])
-{
-	enum tpm2_algorithms algo = TPM2_ALG_SHA256;
-	struct udevice *dev;
-	struct tpm_chip_priv *priv;
-	u32 index, rc;
-	int algo_len;
-	unsigned int updates;
-	void *data;
-	int ret;
-
-	if (argc < 3 || argc > 4)
-		return CMD_RET_USAGE;
-	if (argc == 4) {
-		algo = tpm2_name_to_algorithm(argv[3]);
-		if (algo == TPM2_ALG_INVAL)
-			return CMD_RET_FAILURE;
-	}
-	algo_len = tpm2_algorithm_to_len(algo);
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	priv = dev_get_uclass_priv(dev);
-	if (!priv)
-		return -EINVAL;
-
-	index = simple_strtoul(argv[1], NULL, 0);
-	if (index >= priv->pcr_count)
-		return -EINVAL;
-
-	data = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0);
-
-	rc = tpm2_pcr_read(dev, index, priv->pcr_select_min, algo,
-			   data, algo_len, &updates);
-	if (!rc) {
-		printf("PCR #%u %s %d byte content (%u known updates):\n", index,
-		       tpm2_algorithm_name(algo), algo_len, updates);
-		print_byte_string(data, algo_len);
-	}
-
-	unmap_sysmem(data);
-
-	return report_return_code(rc);
-}
-
-static int do_tpm_get_capability(struct cmd_tbl *cmdtp, int flag, int argc,
-				 char *const argv[])
-{
-	u32 capability, property, rc;
-	u8 *data;
-	size_t count;
-	int i, j;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	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);
-
-	rc = tpm2_get_capability(dev, capability, property, data, count);
-	if (rc)
-		goto unmap_data;
-
-	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_data:
-	unmap_sysmem(data);
-
-	return report_return_code(rc);
-}
-
-static u32 select_mask(u32 mask, enum tpm2_algorithms algo, bool select)
-{
-	size_t i;
-
-	for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) {
-		if (hash_algo_list[i].hash_alg != algo)
-			continue;
-
-		if (select)
-			mask |= hash_algo_list[i].hash_mask;
-		else
-			mask &= ~hash_algo_list[i].hash_mask;
-
-		break;
-	}
-
-	return mask;
-}
-
-static bool
-is_algo_in_pcrs(enum tpm2_algorithms algo, struct tpml_pcr_selection *pcrs)
-{
-	size_t i;
-
-	for (i = 0; i < pcrs->count; i++) {
-		if (algo == pcrs->selection[i].hash)
-			return true;
-	}
-
-	return false;
-}
-
-static int do_tpm2_pcrallocate(struct cmd_tbl *cmdtp, int flag, int argc,
-			       char *const argv[])
-{
-	struct udevice *dev;
-	int ret;
-	enum tpm2_algorithms algo;
-	const char *pw = (argc < 4) ? NULL : argv[3];
-	const ssize_t pw_sz = pw ? strlen(pw) : 0;
-	static struct tpml_pcr_selection pcr = { 0 };
-	u32 pcr_len = 0;
-	bool bon = false;
-	static u32 mask;
-	int i;
-
-	/* argv[1]: algorithm (bank), argv[2]: on/off */
-	if (argc < 3 || argc > 4)
-		return CMD_RET_USAGE;
-
-	if (!strcasecmp("on", argv[2]))
-		bon = true;
-	else if (strcasecmp("off", argv[2]))
-		return CMD_RET_USAGE;
-
-	algo = tpm2_name_to_algorithm(argv[1]);
-	if (algo == TPM2_ALG_INVAL)
-		return CMD_RET_USAGE;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (!pcr.count) {
-		/*
-		 * Get current active algorithms (banks), PCRs and mask via the
-		 * first call
-		 */
-		ret = tpm2_get_pcr_info(dev, &pcr);
-		if (ret)
-			return ret;
-
-		for (i = 0; i < pcr.count; i++) {
-			struct tpms_pcr_selection *sel = &pcr.selection[i];
-			const char *name;
-
-			if (!tpm2_is_active_bank(sel))
-				continue;
-
-			mask = select_mask(mask, sel->hash, true);
-			name = tpm2_algorithm_name(sel->hash);
-			if (name)
-				printf("Active bank[%d]: %s\n", i, name);
-		}
-	}
-
-	if (!is_algo_in_pcrs(algo, &pcr)) {
-		printf("%s is not supported by the tpm device\n", argv[1]);
-		return CMD_RET_USAGE;
-	}
-
-	mask = select_mask(mask, algo, bon);
-	ret = tpm2_pcr_config_algo(dev, mask, &pcr, &pcr_len);
-	if (ret)
-		return ret;
-
-	return report_return_code(tpm2_send_pcr_allocate(dev, pw, pw_sz, &pcr,
-							 pcr_len));
-}
-
-static int do_tpm_dam_reset(struct cmd_tbl *cmdtp, int flag, int argc,
-			    char *const argv[])
-{
-	const char *pw = (argc < 2) ? NULL : argv[1];
-	const ssize_t pw_sz = pw ? strlen(pw) : 0;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (argc > 2)
-		return CMD_RET_USAGE;
-
-	if (pw_sz > TPM2_DIGEST_LEN)
-		return -EINVAL;
-
-	return report_return_code(tpm2_dam_reset(dev, pw, pw_sz));
-}
-
-static int do_tpm_dam_parameters(struct cmd_tbl *cmdtp, int flag, int argc,
-				 char *const argv[])
-{
-	const char *pw = (argc < 5) ? NULL : argv[4];
-	const ssize_t pw_sz = pw ? strlen(pw) : 0;
-	/*
-	 * No Dictionary Attack Mitigation (DAM) means:
-	 * maxtries = 0xFFFFFFFF, recovery_time = 1, lockout_recovery = 0
-	 */
-	unsigned long int max_tries;
-	unsigned long int recovery_time;
-	unsigned long int lockout_recovery;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (argc < 4 || argc > 5)
-		return CMD_RET_USAGE;
-
-	if (pw_sz > TPM2_DIGEST_LEN)
-		return -EINVAL;
-
-	if (strict_strtoul(argv[1], 0, &max_tries))
-		return CMD_RET_USAGE;
-
-	if (strict_strtoul(argv[2], 0, &recovery_time))
-		return CMD_RET_USAGE;
-
-	if (strict_strtoul(argv[3], 0, &lockout_recovery))
-		return CMD_RET_USAGE;
-
-	log(LOGC_NONE, LOGL_INFO, "Changing dictionary attack parameters:\n");
-	log(LOGC_NONE, LOGL_INFO, "- maxTries: %lu", max_tries);
-	log(LOGC_NONE, LOGL_INFO, "- recoveryTime: %lu\n", recovery_time);
-	log(LOGC_NONE, LOGL_INFO, "- lockoutRecovery: %lu\n", lockout_recovery);
-
-	return report_return_code(tpm2_dam_parameters(dev, pw, pw_sz, max_tries,
-						      recovery_time,
-						      lockout_recovery));
-}
-
-static int do_tpm_change_auth(struct cmd_tbl *cmdtp, int flag, int argc,
-			      char *const argv[])
-{
-	u32 handle;
-	const char *newpw = argv[2];
-	const char *oldpw = (argc == 3) ? NULL : argv[3];
-	const ssize_t newpw_sz = strlen(newpw);
-	const ssize_t oldpw_sz = oldpw ? strlen(oldpw) : 0;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (argc < 3 || argc > 4)
-		return CMD_RET_USAGE;
-
-	if (newpw_sz > TPM2_DIGEST_LEN || oldpw_sz > TPM2_DIGEST_LEN)
-		return -EINVAL;
-
-	if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1]))
-		handle = TPM2_RH_LOCKOUT;
-	else if (!strcasecmp("TPM2_RH_ENDORSEMENT", argv[1]))
-		handle = TPM2_RH_ENDORSEMENT;
-	else if (!strcasecmp("TPM2_RH_OWNER", argv[1]))
-		handle = TPM2_RH_OWNER;
-	else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1]))
-		handle = TPM2_RH_PLATFORM;
-	else
-		return CMD_RET_USAGE;
-
-	return report_return_code(tpm2_change_auth(dev, handle, newpw, newpw_sz,
-						   oldpw, oldpw_sz));
-}
-
-static int do_tpm_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag, int argc,
-				    char *const argv[])
-{
-	u32 index = simple_strtoul(argv[1], NULL, 0);
-	char *key = argv[2];
-	const char *pw = (argc < 4) ? NULL : argv[3];
-	const ssize_t pw_sz = pw ? strlen(pw) : 0;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (strlen(key) != TPM2_DIGEST_LEN)
-		return -EINVAL;
-
-	if (argc < 3 || argc > 4)
-		return CMD_RET_USAGE;
-
-	return report_return_code(tpm2_pcr_setauthpolicy(dev, pw, pw_sz, index,
-							 key));
-}
-
-static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
-				   int argc, char *const argv[])
-{
-	u32 index = simple_strtoul(argv[1], NULL, 0);
-	char *key = argv[2];
-	const ssize_t key_sz = strlen(key);
-	const char *pw = (argc < 4) ? NULL : argv[3];
-	const ssize_t pw_sz = pw ? strlen(pw) : 0;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (strlen(key) != TPM2_DIGEST_LEN)
-		return -EINVAL;
-
-	if (argc < 3 || argc > 4)
-		return CMD_RET_USAGE;
-
-	return report_return_code(tpm2_pcr_setauthvalue(dev, pw, pw_sz, index,
-							key, key_sz));
-}
+#include "tpm2-backend.h"
 
 static struct cmd_tbl tpm2_commands[] = {
-	U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""),
-	U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""),
-	U_BOOT_CMD_MKENT(state, 0, 1, do_tpm_report_state, "", ""),
-	U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""),
+	U_BOOT_CMD_MKENT(device, 0, 1, do_tpm2_device, "", ""),
+	U_BOOT_CMD_MKENT(info, 0, 1, do_tpm2_info, "", ""),
+	U_BOOT_CMD_MKENT(state, 0, 1, do_tpm2_state, "", ""),
+	U_BOOT_CMD_MKENT(init, 0, 1, do_tpm2_init, "", ""),
+	U_BOOT_CMD_MKENT(autostart, 0, 1, do_tpm2_autostart, "", ""),
 	U_BOOT_CMD_MKENT(startup, 0, 1, do_tpm2_startup, "", ""),
-	U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_self_test, "", ""),
+	U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_selftest, "", ""),
 	U_BOOT_CMD_MKENT(clear, 0, 1, do_tpm2_clear, "", ""),
 	U_BOOT_CMD_MKENT(pcr_extend, 0, 1, do_tpm2_pcr_extend, "", ""),
-	U_BOOT_CMD_MKENT(pcr_read, 0, 1, do_tpm_pcr_read, "", ""),
-	U_BOOT_CMD_MKENT(get_capability, 0, 1, do_tpm_get_capability, "", ""),
-	U_BOOT_CMD_MKENT(dam_reset, 0, 1, do_tpm_dam_reset, "", ""),
-	U_BOOT_CMD_MKENT(dam_parameters, 0, 1, do_tpm_dam_parameters, "", ""),
-	U_BOOT_CMD_MKENT(change_auth, 0, 1, do_tpm_change_auth, "", ""),
-	U_BOOT_CMD_MKENT(autostart, 0, 1, do_tpm_autostart, "", ""),
+	U_BOOT_CMD_MKENT(pcr_read, 0, 1, do_tpm2_pcr_read, "", ""),
+	U_BOOT_CMD_MKENT(get_capability, 0, 1, do_tpm2_get_capability, "", ""),
+	U_BOOT_CMD_MKENT(dam_reset, 0, 1, do_tpm2_dam_reset, "", ""),
+	U_BOOT_CMD_MKENT(dam_parameters, 0, 1, do_tpm2_dam_parameters, "", ""),
+	U_BOOT_CMD_MKENT(change_auth, 0, 1, do_tpm2_change_auth, "", ""),
 	U_BOOT_CMD_MKENT(pcr_setauthpolicy, 0, 1,
-			 do_tpm_pcr_setauthpolicy, "", ""),
+			 do_tpm2_pcr_setauthpolicy, "", ""),
 	U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1,
-			 do_tpm_pcr_setauthvalue, "", ""),
-	U_BOOT_CMD_MKENT(pcr_allocate, 0, 1, do_tpm2_pcrallocate, "", ""),
+			 do_tpm2_pcr_setauthvalue, "", ""),
+	U_BOOT_CMD_MKENT(pcr_allocate, 0, 1, do_tpm2_pcr_allocate, "", ""),
+#ifdef CONFIG_TPM_WOLF
+	U_BOOT_CMD_MKENT(caps, 0, 1, do_tpm2_caps, "", ""),
+	U_BOOT_CMD_MKENT(pcr_print, 0, 1, do_tpm2_pcr_print, "", ""),
+#ifdef WOLFTPM_FIRMWARE_UPGRADE
+#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
+	U_BOOT_CMD_MKENT(firmware_update, 0, 1,
+			 do_tpm2_firmware_update, "", ""),
+	U_BOOT_CMD_MKENT(firmware_cancel, 0, 1,
+			 do_tpm2_firmware_cancel, "", ""),
+#endif /* WOLFTPM_SLB9672 || WOLFTPM_SLB9673 */
+#endif /* WOLFTPM_FIRMWARE_UPGRADE */
+#endif /* CONFIG_TPM_WOLF */
 };
 
 struct cmd_tbl *get_tpm2_commands(unsigned int *size)
@@ -511,7 +55,22 @@ struct cmd_tbl *get_tpm2_commands(unsigned int *size)
 	return tpm2_commands;
 }
 
-U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
+static int do_tpm2(struct cmd_tbl *cmdtp, int flag, int argc,
+		   char *const argv[])
+{
+	struct cmd_tbl *cmd;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	cmd = find_cmd_tbl(argv[1], tpm2_commands, ARRAY_SIZE(tpm2_commands));
+	if (!cmd)
+		return CMD_RET_USAGE;
+
+	return cmd->cmd(cmdtp, flag, argc - 1, argv + 1);
+}
+
+U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm2, "Issue a TPMv2.x command",
 "<command> [<arguments>]\n"
 "\n"
 "device [num device]\n"
@@ -521,7 +80,7 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
 "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"
+"    Initialize 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"
@@ -573,6 +132,10 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
 "    <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"
@@ -596,4 +159,18 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
 "        * off - Clear all available PCRs associated with the specified\n"
 "                algorithm (bank)\n"
 "    <password>: optional password\n"
+#ifdef CONFIG_TPM_WOLF
+"caps\n"
+"    Show TPM capabilities and info\n"
+"pcr_print\n"
+"    Prints the current PCR state\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 /* WOLFTPM_SLB9672 || WOLFTPM_SLB9673 */
+#endif /* WOLFTPM_FIRMWARE_UPGRADE */
+#endif /* CONFIG_TPM_WOLF */
 );
diff --git a/cmd/tpm2-backend.h b/cmd/tpm2-backend.h
new file mode 100644
index 00000000000..39e9a3a6b7b
--- /dev/null
+++ b/cmd/tpm2-backend.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * TPM2 backend function declarations
+ *
+ * Each backend (native_tpm2.c or wolftpm.c) implements these functions.
+ * The frontend (tpm-v2.c) references them in the command table.
+ */
+
+#ifndef __TPM2_BACKEND_H
+#define __TPM2_BACKEND_H
+
+#include <command.h>
+
+/* Common TPM2 command handlers - both backends must implement these */
+int do_tpm2_device(struct cmd_tbl *cmdtp, int flag, int argc,
+		   char *const argv[]);
+int do_tpm2_info(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[]);
+int do_tpm2_state(struct cmd_tbl *cmdtp, int flag, int argc,
+		  char *const argv[]);
+int do_tpm2_init(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[]);
+int do_tpm2_autostart(struct cmd_tbl *cmdtp, int flag, int argc,
+		      char *const argv[]);
+int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc,
+		    char *const argv[]);
+int do_tpm2_selftest(struct cmd_tbl *cmdtp, int flag, int argc,
+		     char *const argv[]);
+int do_tpm2_clear(struct cmd_tbl *cmdtp, int flag, int argc,
+		  char *const argv[]);
+int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, int argc,
+		       char *const argv[]);
+int do_tpm2_pcr_read(struct cmd_tbl *cmdtp, int flag, int argc,
+		     char *const argv[]);
+int do_tpm2_get_capability(struct cmd_tbl *cmdtp, int flag, int argc,
+			   char *const argv[]);
+int do_tpm2_dam_reset(struct cmd_tbl *cmdtp, int flag, int argc,
+		      char *const argv[]);
+int do_tpm2_dam_parameters(struct cmd_tbl *cmdtp, int flag, int argc,
+			   char *const argv[]);
+int do_tpm2_change_auth(struct cmd_tbl *cmdtp, int flag, int argc,
+			char *const argv[]);
+int do_tpm2_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag, int argc,
+			      char *const argv[]);
+int do_tpm2_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag, int argc,
+			     char *const argv[]);
+int do_tpm2_pcr_allocate(struct cmd_tbl *cmdtp, int flag, int argc,
+			 char *const argv[]);
+
+/* wolfTPM-only command handlers */
+#ifdef CONFIG_TPM_WOLF
+int do_tpm2_caps(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[]);
+int do_tpm2_pcr_print(struct cmd_tbl *cmdtp, int flag, int argc,
+		      char *const argv[]);
+#ifdef WOLFTPM_FIRMWARE_UPGRADE
+#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
+int do_tpm2_firmware_update(struct cmd_tbl *cmdtp, int flag, int argc,
+			    char *const argv[]);
+int do_tpm2_firmware_cancel(struct cmd_tbl *cmdtp, int flag, int argc,
+			    char *const argv[]);
+#endif /* WOLFTPM_SLB9672 || WOLFTPM_SLB9673 */
+#endif /* WOLFTPM_FIRMWARE_UPGRADE */
+#endif /* CONFIG_TPM_WOLF */
+
+#endif /* __TPM2_BACKEND_H */
diff --git a/cmd/wolftpm.c b/cmd/wolftpm.c
new file mode 100644
index 00000000000..06ea8d47c8a
--- /dev/null
+++ b/cmd/wolftpm.c
@@ -0,0 +1,1170 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TPM2 command implementation using wolfTPM library
+ *
+ * Copyright (C) 2025 wolfSSL Inc.
+ * Author: Aidan Garske <aidan@wolfssl.com>
+ */
+
+#define LOG_CATEGORY UCLASS_BOOTSTD
+
+#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)
+struct fw_info {
+	byte *manifest_buf;
+	byte *firmware_buf;
+	size_t manifest_bufSz;
+	size_t firmware_bufSz;
+};
+#endif
+#endif
+
+/******************************************************************************/
+/* --- BEGIN Common Commands -- */
+/******************************************************************************/
+
+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) {
+		rc = wolfTPM2_GetCapabilities(&dev, &caps);
+		if (!rc) {
+			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;
+}
+
+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) {
+		rc = wolfTPM2_GetCapabilities(&dev, &caps);
+		if (!rc) {
+			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;
+}
+
+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) {
+		rc = wolfTPM2_GetCapabilities(&dev, &caps);
+		if (!rc) {
+			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;
+}
+
+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);
+}
+
+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)
+		return rc;
+
+	/* 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;
+	if (rc != TPM_RC_SUCCESS) {
+		log_debug("wolfTPM2_Reset failed 0x%x: %s\n", rc,
+			TPM2_GetRCString(rc));
+		return rc;
+	}
+
+	/* 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 -- */
+/******************************************************************************/
+
+int do_tpm2_get_capability(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) {
+		memcpy(data, &out.capabilityData.data, sizeof(out.capabilityData.data));
+
+		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;
+}
+
+int do_tpm2_caps(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)
+		return rc;
+
+	rc = wolfTPM2_GetCapabilities(&dev, &caps);
+	if (rc != TPM_RC_SUCCESS)
+		goto cleanup;
+
+	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 */
+	rc = wolfTPM2_GetHandles(PERSISTENT_FIRST, NULL);
+	if (rc >= TPM_RC_SUCCESS)
+		log_debug("Found %d persistent handles\n", rc);
+
+	/* Print the available PCR's */
+	rc = TPM2_PCRs_Print();
+
+cleanup:
+	/* 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;
+}
+
+#ifdef WOLFTPM_FIRMWARE_UPGRADE
+#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
+int do_tpm2_firmware_update(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+	WOLFTPM2_CAPS caps;
+	struct fw_info 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)
+		goto fw_cleanup;
+
+	rc = wolfTPM2_GetCapabilities(&dev, &caps);
+	if (rc != TPM_RC_SUCCESS)
+		goto fw_cleanup;
+
+	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))
+		recovery = 1;
+
+	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 {
+		/* 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)
+			goto fw_cleanup;
+		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)
+		TPM2_IFX_PrintInfo(&caps);
+
+fw_cleanup:
+	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;
+}
+
+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;
+		memcpy(cmd, &val16, sizeof(val16));
+		val16 = 0;
+		memcpy(&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 */
+
+int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	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;
+}
+
+int do_tpm2_selftest(struct cmd_tbl *cmdtp, int flag,
+	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;
+}
+
+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;
+}
+
+int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	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;
+}
+
+int do_tpm2_pcr_read(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	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;
+}
+
+int do_tpm2_pcr_allocate(struct cmd_tbl *cmdtp, int flag,
+	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);
+	} else if (!strcmp(argv[2], "off")) {
+		/* Clear all PCRs for this algorithm */
+		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]);
+		memcpy(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;
+}
+
+/*
+ * Without wolfCrypt, parameter encryption is not available.
+ * 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);
+		memcpy(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;
+	memcpy(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;
+}
+
+int do_tpm2_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	return TPM2_PCR_SetAuth(argc, argv, YES);
+}
+
+int do_tpm2_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	return TPM2_PCR_SetAuth(argc, argv, NO);
+}
+
+int do_tpm2_change_auth(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	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;
+		memcpy(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;
+	memcpy(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;
+}
+#else /* WOLFTPM2_NO_WOLFCRYPT */
+int do_tpm2_change_auth(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	printf("wolfCrypt support required for change_auth\n");
+	return CMD_RET_FAILURE;
+}
+
+int do_tpm2_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	printf("wolfCrypt support required for pcr_setauthpolicy\n");
+	return CMD_RET_FAILURE;
+}
+
+int do_tpm2_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	printf("wolfCrypt support required for pcr_setauthvalue\n");
+	return CMD_RET_FAILURE;
+}
+#endif /* !WOLFTPM2_NO_WOLFCRYPT */
+
+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;
+}
+
+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;
+			memcpy(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;
+}
+
+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;
+			memcpy(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;
+}
+
+#endif /* !WOLFTPM2_NO_WRAPPER */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 09/12] tpm: add sandbox TPM SPI emulator
  2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske
                   ` (7 preceding siblings ...)
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 08/12] cmd: refactor tpm2 command into frontend/backend architecture David Garske
@ 2026-03-16 18:14 ` David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 10/12] test: add wolfTPM C unit tests and Python integration tests David Garske
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw)
  To: u-boot; +Cc: Aidan

From: Aidan <aidan@wolfssl.com>

Add a TPM SPI emulator for sandbox testing that implements the TIS
(TPM Interface Specification) SPI protocol, allowing wolfTPM's SPI
HAL code to be tested without physical hardware.

drivers/tpm/tpm_spi_sandbox.c (new):
  Emulates a TPM connected via SPI by implementing the TIS register
  set and SPI protocol:
  - SPI protocol state machine: parses 4-byte TIS SPI headers
    (R/W bit, transfer length, register address) and handles data
    phase with immediate ready signaling (no wait states)
  - TIS register emulation: TPM_ACCESS (locality request/grant),
    TPM_STS (command ready, data expect, data available, burst
    count), TPM_INTF_CAPS, TPM_DID_VID (Infineon SLB9670 IDs),
    TPM_RID, and TPM_DATA_FIFO (command/response buffering)
  - TIS state machine: IDLE -> READY -> RECEPTION -> EXECUTION ->
    COMPLETION, with command-ready abort support
  - Generates simple TPM_RC_SUCCESS responses (a full implementation
    would integrate the sandbox TPM2 state machine)
  - Registers as UCLASS_SPI_EMUL with compatible "sandbox,tpm-spi-emul"
  - Also registers a SPI slave driver (UCLASS_SPI_GENERIC) with
    compatible "sandbox,tpm-spi" for the DTS device node

drivers/mtd/spi/sandbox.c:
  Modify sandbox_spi_get_emul() to check for a "sandbox,emul"
  phandle property on SPI slave devices before falling back to the
  default SPI flash emulation binding. This allows non-flash SPI
  devices (like the TPM emulator) to specify their own emulator
  via device tree phandle.

Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
 drivers/mtd/spi/sandbox.c     |  30 ++-
 drivers/tpm/tpm_spi_sandbox.c | 410 ++++++++++++++++++++++++++++++++++
 2 files changed, 431 insertions(+), 9 deletions(-)
 create mode 100644 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/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
@@ -0,0 +1,410 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Sandbox TPM SPI Emulator
+ *
+ * Copyright (c) 2025 wolfSSL Inc.
+ * Author: Aidan Garske <aidan@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,
+};
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 10/12] test: add wolfTPM C unit tests and Python integration tests
  2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske
                   ` (8 preceding siblings ...)
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 09/12] tpm: add sandbox TPM SPI emulator David Garske
@ 2026-03-16 18:14 ` David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 11/12] doc: add wolfTPM documentation David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 12/12] configs: enable wolfTPM in rpi_4_defconfig David Garske
  11 siblings, 0 replies; 13+ messages in thread
From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw)
  To: u-boot; +Cc: Aidan

From: Aidan <aidan@wolfssl.com>

Add comprehensive test suites for wolfTPM commands, modeled after
the existing TPM2 test infrastructure.

test/cmd/wolftpm.c (C unit tests):
  18 tests using U-Boot's unit test framework (CMD_TEST macro):
  - autostart, init, info, state, device: basic lifecycle
  - self_test (full and continue): TPM self-test verification
  - startup_clear, startup_state: TPM2_Startup modes
  - get_capability: read TPM properties
  - caps: wolfTPM-enhanced capabilities display
  - clear: TPM state reset via LOCKOUT hierarchy
  - pcr_read, pcr_extend, pcr_print: PCR operations
  - pcr_allocate: PCR bank reconfiguration
  - dam_reset, dam_parameters: dictionary attack mitigation
  - change_auth: hierarchy password change (requires wolfCrypt)
  - cleanup: reset TPM state after tests
  Run with: ut cmd cmd_test_wolftpm_*

test/cmd/Makefile:
  Adds wolftpm.o when CONFIG_TPM_WOLF is enabled.

test/py/tests/test_wolftpm.py (Python integration tests):
  21 tests using pytest with the U-Boot test framework:
  - Requires QEMU + swtpm (not sandbox) because wolfTPM bypasses
    U-Boot's driver model and communicates directly with TPM
    hardware via its own SPI/MMIO HAL
  - Tests mirror the C tests but run end-to-end through the U-Boot
    console, checking return codes via 'echo $?'
  - Includes force_init() helper for TPM reinitialization after
    test failures
  - Skippable via env__wolftpm_device_test_skip config
  - Verified: 19 passed, 2 skipped (change_auth requires wolfCrypt,
    get_capability may skip on some platforms)

Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
 test/cmd/Makefile             |   1 +
 test/cmd/wolftpm.c            | 364 +++++++++++++++++++++++++++++++++
 test/py/tests/test_wolftpm.py | 375 ++++++++++++++++++++++++++++++++++
 3 files changed, 740 insertions(+)
 create mode 100644 test/cmd/wolftpm.c
 create mode 100644 test/py/tests/test_wolftpm.py

diff --git a/test/cmd/Makefile b/test/cmd/Makefile
index 8c9f112782d..6e346dfa4bf 100644
--- a/test/cmd/Makefile
+++ b/test/cmd/Makefile
@@ -48,3 +48,4 @@ obj-$(CONFIG_CMD_SPAWN) += spawn.o
 ifdef CONFIG_CMD_ZIP
 obj-$(CONFIG_CMD_UNZIP) += unzip.o
 endif
+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@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..b862fa06c5b
--- /dev/null
+++ b/test/py/tests/test_wolftpm.py
@@ -0,0 +1,375 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (C) 2025 wolfSSL Inc.
+# Author: Aidan Garske <aidan@wolfssl.com>
+#
+# Based on test_tpm2.py by Miquel Raynal <miquel.raynal@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('tpm2 autostart')
+    if force or 'Error' not in output:
+        ubman.run_command('echo --- start of init ---')
+        ubman.run_command('tpm2 clear TPM2_RH_LOCKOUT')
+        output = ubman.run_command('echo $?')
+        if not output.endswith('0'):
+            ubman.run_command('tpm2 clear TPM2_RH_PLATFORM')
+        ubman.run_command('echo --- end of init ---')
+
+
+@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('tpm2 autostart')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@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('tpm2 init')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@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('tpm2 autostart')
+    ubman.run_command('tpm2 self_test full')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@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('tpm2 autostart')
+    ubman.run_command('tpm2 self_test continue')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@pytest.mark.buildconfigspec('tpm_wolf')
+def test_wolftpm_caps(ubman):
+    """Test wolfTPM caps command.
+
+    Display TPM capabilities and vendor information.
+    """
+    force_init(ubman)
+    ubman.run_command('tpm2 caps')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@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('tpm2 autostart')
+    ubman.run_command('tpm2 clear TPM2_RH_LOCKOUT')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+    ubman.run_command('tpm2 clear TPM2_RH_PLATFORM')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@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'
+    # Note: change_auth requires wolfCrypt (WOLFTPM2_NO_WOLFCRYPT must not be set)
+    ubman.run_command('tpm2 change_auth TPM2_RH_LOCKOUT unicorn')
+    output = ubman.run_command('echo $?')
+    if not output.endswith('0'):
+        # wolfCrypt not available, skip password test
+        pytest.skip('change_auth requires wolfCrypt support')
+
+    # Clear with new password to verify
+    ubman.run_command('tpm2 clear TPM2_RH_LOCKOUT unicorn')
+    output = ubman.run_command('echo $?')
+    ubman.run_command('tpm2 clear TPM2_RH_PLATFORM')
+    assert output.endswith('0')
+
+
+@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('tpm2 dam_parameters 3 10 0')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@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('tpm2 dam_reset')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@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)
+
+    ram = utils.find_ram_base(ubman)
+
+    # Read PCR 0 with SHA256
+    read_pcr = ubman.run_command('tpm2 pcr_read 0 0x%x SHA256' % ram)
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@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('tpm2 pcr_read 16 0x%x SHA256' % ram)
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+    # Extend PCR 16 with zeroed memory
+    ubman.run_command('tpm2 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('tpm2 pcr_read 16 0x%x SHA256' % ram)
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@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('tpm2 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
+
+
+@pytest.mark.buildconfigspec('tpm_wolf')
+def test_wolftpm_info(ubman):
+    """Test wolfTPM info command.
+
+    Display TPM device information.
+    """
+    force_init(ubman)
+
+    ubman.run_command('tpm2 info')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@pytest.mark.buildconfigspec('tpm_wolf')
+def test_wolftpm_state(ubman):
+    """Test wolfTPM state command.
+
+    Display TPM internal state.
+    """
+    force_init(ubman)
+
+    ubman.run_command('tpm2 state')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@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('tpm2 device')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@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('tpm2 init')
+    ubman.run_command('tpm2 startup TPM2_SU_CLEAR')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@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('tpm2 autostart')
+    # Shutdown with STATE
+    ubman.run_command('tpm2 startup TPM2_SU_STATE off')
+    # Re-init
+    ubman.run_command('tpm2 init')
+    # Startup with STATE - may return already started
+    ubman.run_command('tpm2 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
+
+
+@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('tpm2 autostart')
+    ubman.run_command('tpm2 startup TPM2_SU_CLEAR off')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@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('tpm2 get_capability 0x6 0x20e 0x%x 1' % ram)
+    output = ubman.run_command('echo $?')
+    # May fail on some platforms if RAM address is not accessible
+    if not output.endswith('0'):
+        pytest.skip('get_capability failed (RAM address may not be accessible)')
+
+
+@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('tpm2 pcr_allocate SHA256 on')
+    output = ubman.run_command('echo $?')
+    assert output.endswith('0')
+
+
+@pytest.mark.buildconfigspec('tpm_wolf')
+def test_wolftpm_cleanup(ubman):
+    """Cleanup test - ensure TPM is cleared after tests."""
+    force_init(ubman, True)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 11/12] doc: add wolfTPM documentation
  2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske
                   ` (9 preceding siblings ...)
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 10/12] test: add wolfTPM C unit tests and Python integration tests David Garske
@ 2026-03-16 18:14 ` David Garske
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 12/12] configs: enable wolfTPM in rpi_4_defconfig David Garske
  11 siblings, 0 replies; 13+ messages in thread
From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw)
  To: u-boot; +Cc: Aidan

From: Aidan <aidan@wolfssl.com>

Add documentation for wolfTPM integration, commands, and testing.

doc/usage/cmd/wolftpm.rst:
  Comprehensive RST documentation covering:
  - All wolfTPM tpm2 subcommands with usage and examples
  - Infineon TPM firmware update step-by-step guide (extract
    manifest/firmware, load to RAM, perform update, recovery mode)
  - Build instructions for RPi4 and QEMU targets
  - Enabling debug output (U-Boot log system + wolfTPM library)
  - Complete test suite documentation with test coverage table
  - Python test framework setup (QEMU + swtpm instructions,
    helper scripts, verified test results)

README.wolftpm.md:
  Quick-start guide with overview, feature comparison vs standard
  U-Boot TPM, command reference, build instructions, hardware
  support details, and file listing.

README:
  Add CONFIG_TPM_WOLF reference in the configuration options
  section alongside existing CONFIG_TPM entries.

Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
 README                    |   3 +
 README.wolftpm.md         | 154 +++++++++
 doc/usage/cmd/wolftpm.rst | 635 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 792 insertions(+)
 create mode 100644 README.wolftpm.md
 create mode 100644 doc/usage/cmd/wolftpm.rst

diff --git a/README b/README
index 20a73bab802..b9bfe14a1c7 100644
--- a/README
+++ b/README
@@ -361,6 +361,9 @@ The following options need to be configured:
 		CONFIG_TPM
 		Support TPM devices.
 
+		CONFIG_TPM_WOLF
+		Enables support for wolfTPM library.
+
 		CONFIG_TPM_TIS_INFINEON
 		Support for Infineon i2c bus TPM devices. Only one device
 		per system is supported at this time.
diff --git a/README.wolftpm.md b/README.wolftpm.md
new file mode 100644
index 00000000000..cdebe96ecb1
--- /dev/null
+++ b/README.wolftpm.md
@@ -0,0 +1,154 @@
+# wolfTPM Support for U-Boot
+
+This fork adds [wolfTPM](https://github.com/wolfSSL/wolfTPM) support to U-Boot, providing full TPM 2.0 command support using wolfTPM APIs and the wolfTPM library.
+
+## Overview
+
+wolfTPM is a portable, open-source TPM 2.0 library that provides:
+
+- **Native TPM 2.0 API** - Direct access to all TPM 2.0 commands
+- **Wrapper API** - Simplified interface for common TPM operations
+- **Hardware SPI Support** - Direct communication with TPM hardware via SPI
+- **Firmware Update** - Support for Infineon SLB9672/SLB9673 firmware updates
+- **No External Dependencies** - Standalone implementation without kernel TPM stack
+
+## Why wolfTPM vs Standard U-Boot TPM?
+
+| Feature | Standard U-Boot TPM | wolfTPM |
+|---------|---------------------|---------|
+| API | Basic TPM commands | Full TPM 2.0 + Wrapper API |
+| PCR Operations | Basic read/extend | Full PCR management |
+| Firmware Update | Not supported | Infineon SLB9672/9673 |
+| Capabilities Query | Limited | Comprehensive `caps` command |
+| SPI Communication | Via kernel driver | Native wolfTPM TIS layer |
+| Library Integration | N/A | wolfSSL ecosystem compatible |
+
+## Command: `tpm2`
+
+When wolfTPM is enabled, the `tpm2` command uses wolfTPM APIs instead of the standard implementation. The command interface is compatible with the standard `tpm2` command, with additional wolfTPM-specific features.
+
+### Basic Commands
+
+```bash
+tpm2 autostart          # Initialize TPM, startup, and self-test
+tpm2 init               # Initialize TPM software stack
+tpm2 info               # Show TPM device information
+tpm2 caps               # Show TPM capabilities (wolfTPM enhanced)
+tpm2 self_test full     # Run full self-test
+```
+
+### PCR Operations
+
+```bash
+tpm2 pcr_read <pcr> <addr> [algo]      # Read PCR value
+tpm2 pcr_extend <pcr> <addr> [algo]    # Extend PCR with digest
+tpm2 pcr_print                          # Print all PCR values
+tpm2 pcr_allocate <algo> <on|off>       # Configure PCR banks
+```
+
+### Security Management
+
+```bash
+tpm2 clear <hierarchy>                           # Clear TPM
+tpm2 change_auth <hierarchy> <new_pw> [old_pw]   # Change password
+tpm2 dam_reset [password]                        # Reset DAM counter
+tpm2 dam_parameters <tries> <recovery> <lockout> # Set DAM params
+```
+
+### Firmware Update (Infineon Only)
+
+```bash
+tpm2 firmware_update <manifest_addr> <size> <firmware_addr> <size>
+tpm2 firmware_cancel
+```
+
+## Building
+
+### For Raspberry Pi 4
+
+```bash
+git clone https://github.com/aidangarske/u-boot.git
+cd u-boot
+git checkout rpi4-wolftpm-uboot
+git submodule update --init lib/wolftpm
+
+export CROSS_COMPILE=aarch64-elf-
+make rpi_4_defconfig
+make -j$(nproc)
+```
+
+### Configuration Options
+
+Enable in `menuconfig` or defconfig:
+
+```
+# Core TPM support
+CONFIG_TPM=y
+CONFIG_TPM_V2=y
+
+# wolfTPM (replaces standard tpm2 command)
+CONFIG_TPM_WOLF=y
+CONFIG_CMD_TPM=y
+
+# For Infineon hardware
+CONFIG_WOLFTPM_SLB9672=y
+
+# For QEMU/swtpm testing
+# CONFIG_WOLFTPM_LINUX_DEV=y
+```
+
+**Note:** The `tpm2` command frontend (`cmd/tpm-v2.c`) is always compiled. The backend is selected at build time: when `CONFIG_TPM_WOLF` is enabled, `cmd/wolftpm.c` provides the wolfTPM backend; otherwise, `cmd/native_tpm2.c` provides the native U-Boot backend.
+
+## Hardware Support
+
+### Tested Hardware
+
+- Raspberry Pi 4 Model B
+- Infineon SLB9670 TPM (LetsTrust HAT)
+- Infineon SLB9672 TPM (with firmware update support)
+
+### SPI Configuration
+
+The TPM is configured on SPI0 CE1 (GPIO7), matching the standard Raspberry Pi `tpm-slb9670` overlay:
+
+```
+SPI0 Pins:
+- SCLK: GPIO11 (pin 23)
+- MOSI: GPIO10 (pin 19)
+- MISO: GPIO9  (pin 21)
+- CE1:  GPIO7  (pin 26)
+```
+
+## Documentation
+
+- **Full Guide**: [rpi4-wolftpm-uboot](https://github.com/aidangarske/rpi4-wolftpm-uboot)
+- **Firmware Update**: See `doc/usage/cmd/wolftpm.rst`
+- **wolfTPM Library**: [github.com/wolfSSL/wolfTPM](https://github.com/wolfSSL/wolfTPM)
+
+## Files Modified/Added
+
+```
+cmd/tpm-v2.c                     # Shared tpm2 command frontend (dispatch table, help)
+cmd/native_tpm2.c                # Native U-Boot backend (when wolfTPM is OFF)
+cmd/wolftpm.c                    # wolfTPM backend (when wolfTPM is ON)
+cmd/tpm2-backend.h               # Backend function declarations
+lib/wolftpm/                     # wolfTPM library (submodule)
+lib/wolftpm.c                    # wolfTPM library glue code
+include/configs/user_settings.h  # wolfTPM configuration
+include/wolftpm.h                # wolfTPM header
+arch/arm/dts/bcm2711-rpi-4-b.dts # Device tree with SPI/TPM config
+configs/rpi_4_defconfig          # RPi4 build configuration
+drivers/spi/bcm2835_spi.c        # BCM2835 SPI driver
+doc/usage/cmd/wolftpm.rst        # Command documentation
+```
+
+## License
+
+- U-Boot: GPL-2.0
+- wolfTPM: GPL-2.0
+- This integration: GPL-2.0
+
+## Author
+
+Aidan Garske <aidan@wolfssl.com>
+wolfSSL Inc.
diff --git a/doc/usage/cmd/wolftpm.rst b/doc/usage/cmd/wolftpm.rst
new file mode 100644
index 00000000000..85e6be544bb
--- /dev/null
+++ b/doc/usage/cmd/wolftpm.rst
@@ -0,0 +1,635 @@
+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@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@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
+
+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 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::
+
+     => tpm2 autostart
+     => tpm2 caps
+     => tpm2 pcr_read 0 sha256
+     => tpm2 pcr_print
+     => tpm2 self_test full
+     => tpm2 clear TPM2_RH_LOCKOUT
+     => tpm2 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        |
++---------------------------+------------------------------------------+
+
+The following commands are implemented in ``cmd/wolftpm.c`` but do not yet have
+test coverage due to special requirements. These have been tested locally on 
+hardware but dont have test suites due to different build configurations.
+
++---------------------------+------------------------------------------+------------------+
+| 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.
+
+Testing on SLB 9672 on Raspberry Pi 4 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.
+
+Python Test Framework
+~~~~~~~~~~~~~~~~~~~~~
+
+**Why QEMU+swtpm is required (not sandbox):**
+
+The native ``test_tpm2.py`` tests run directly in sandbox because the native
+TPM backend uses U-Boot's driver model, which has a built-in sandbox TPM
+emulator. wolfTPM bypasses driver model entirely and communicates with TPM
+hardware directly via its own SPI/MMIO HAL layer. This means there is no
+sandbox emulator for wolfTPM to talk to. Instead, wolfTPM Python tests require
+QEMU with swtpm (software TPM emulator) which provides a real TPM device
+interface that wolfTPM can communicate with via MMIO.
+
+**Prerequisites:**
+
+Install swtpm and QEMU::
+
+    sudo apt-get install -y swtpm qemu-system-aarch64 pytest
+
+**Running wolfTPM Python Tests with QEMU+swtpm:**
+
+1. Build U-Boot for QEMU arm64 with wolfTPM and autodetect enabled::
+
+     make qemu_arm64_defconfig
+     scripts/config --enable CONFIG_CMD_WOLFTPM --enable CONFIG_TPM_AUTODETECT
+     make olddefconfig
+     make -j$(nproc)
+
+2. Create the test helper scripts in the U-Boot root directory:
+
+   ``u-boot-test-flash`` (no-op for QEMU)::
+
+     #!/bin/bash
+     exit 0
+
+   ``u-boot-test-console`` (starts swtpm + QEMU)::
+
+     #!/bin/bash
+     SWTPM_DIR=/tmp/mytpm
+     SWTPM_SOCK=${SWTPM_DIR}/swtpm-sock
+     mkdir -p ${SWTPM_DIR}
+     if [ ! -S "${SWTPM_SOCK}" ]; then
+         swtpm socket --tpm2 --tpmstate dir=${SWTPM_DIR} \
+             --ctrl type=unixio,path=${SWTPM_SOCK} --log level=0 &
+         sleep 1
+     fi
+     exec qemu-system-aarch64 -machine virt -nographic -cpu cortex-a57 \
+         -bios u-boot.bin \
+         -chardev socket,id=chrtpm,path=${SWTPM_SOCK} \
+         -tpmdev emulator,id=tpm0,chardev=chrtpm \
+         -device tpm-tis-device,tpmdev=tpm0
+
+   ``u-boot-test-reset`` (no-op)::
+
+     #!/bin/bash
+     exit 0
+
+   ``u-boot-test-release`` (cleanup)::
+
+     #!/bin/bash
+     pkill -f "swtpm.*mytpm" 2>/dev/null
+     exit 0
+
+   Make them executable::
+
+     chmod +x u-boot-test-flash u-boot-test-console u-boot-test-reset u-boot-test-release
+
+3. Run the wolfTPM Python tests::
+
+     export PATH=".:$PATH"
+     ./test/py/test.py --bd qemu_arm64 --build-dir . -k "test_wolftpm and not ut_cmd" -v
+
+**Verified output (QEMU arm64 + swtpm, 19 passed, 2 skipped):**
+
+::
+
+    test_wolftpm_autostart PASSED
+    test_wolftpm_init PASSED
+    test_wolftpm_self_test_full PASSED
+    test_wolftpm_self_test_continue PASSED
+    test_wolftpm_caps PASSED
+    test_wolftpm_clear PASSED
+    test_wolftpm_change_auth SKIPPED (requires wolfCrypt)
+    test_wolftpm_dam_parameters PASSED
+    test_wolftpm_dam_reset PASSED
+    test_wolftpm_pcr_read PASSED
+    test_wolftpm_pcr_extend PASSED
+    test_wolftpm_pcr_print PASSED
+    test_wolftpm_info PASSED
+    test_wolftpm_state PASSED
+    test_wolftpm_device PASSED
+    test_wolftpm_startup_clear PASSED
+    test_wolftpm_startup_state PASSED
+    test_wolftpm_startup_shutdown PASSED
+    test_wolftpm_get_capability SKIPPED
+    test_wolftpm_pcr_allocate PASSED
+    test_wolftpm_cleanup PASSED
+
+The native ``test_tpm2.py`` tests can be run directly in sandbox::
+
+    ./test/py/test.py --bd sandbox --build -k test_tpm2 -v
+
+Enabling Debug Output
+~~~~~~~~~~~~~~~~~~~~~
+
+To see 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 debug, edit ``include/configs/user_settings.h``::
+
+    #define DEBUG_WOLFTPM
+    #define WOLFTPM_DEBUG_IO    /* Shows SPI transfer details */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 12/12] configs: enable wolfTPM in rpi_4_defconfig
  2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske
                   ` (10 preceding siblings ...)
  2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 11/12] doc: add wolfTPM documentation David Garske
@ 2026-03-16 18:14 ` David Garske
  11 siblings, 0 replies; 13+ messages in thread
From: David Garske @ 2026-03-16 18:14 UTC (permalink / raw)
  To: u-boot; +Cc: Aidan

From: Aidan <aidan@wolfssl.com>

Enable SPI, TPM, and wolfTPM support in the Raspberry Pi 4 default
configuration for out-of-the-box TPM 2.0 support with Infineon
SLB9670/9672 TPM HATs.

SPI support:
  CONFIG_SPI, CONFIG_DM_SPI, CONFIG_BCM2835_SPI, CONFIG_CMD_SPI
  Enables the BCM2835 hardware SPI driver. Soft SPI is disabled
  since the hardware driver is used.

TPM and wolfTPM:
  CONFIG_TPM, CONFIG_TPM_V2, CONFIG_CMD_TPM: core TPM support
  CONFIG_TPM_WOLF: wolfTPM library integration
  CONFIG_CMD_WOLFTPM: wolfTPM command backend for tpm2
  CONFIG_WOLFTPM_SLB9672: Infineon SLB9672 chip support
  WOLFTPM_LINUX_DEV disabled: uses native wolfTPM TIS layer with
  direct SPI communication rather than U-Boot's TPM driver model

Logging:
  CONFIG_LOG with level 7 (DEBUG) to enable log_debug() output
  from wolfTPM commands.

Testing:
  CONFIG_UNIT_TEST, CONFIG_CONSOLE_RECORD, CONFIG_HEXDUMP for
  running the wolfTPM C unit test suite.

Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
 configs/rpi_4_defconfig | 29 ++++++++++++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)

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
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2026-03-16 18:26 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-16 18:14 [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 00/12] *** SUBJECT HERE *** David Garske
2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm David Garske
2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 02/12] include: add byteorder macro guards and SHA384 hash wrapper David Garske
2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 03/12] spi: add BCM2835/BCM2711 hardware SPI controller driver David Garske
2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 04/12] dts: add TPM device tree nodes for RPi4, QEMU, and sandbox David Garske
2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 05/12] tpm: add wolfTPM library as git submodule David Garske
2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 06/12] tpm: add wolfTPM headers and SHA384 glue code David Garske
2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 07/12] tpm: add wolfTPM driver helpers and Kconfig options David Garske
2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 08/12] cmd: refactor tpm2 command into frontend/backend architecture David Garske
2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 09/12] tpm: add sandbox TPM SPI emulator David Garske
2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 10/12] test: add wolfTPM C unit tests and Python integration tests David Garske
2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 11/12] doc: add wolfTPM documentation David Garske
2026-03-16 18:14 ` [[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 12/12] configs: enable wolfTPM in rpi_4_defconfig David Garske

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox