* [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0
@ 2026-05-13 0:26 Aidan Garske
2026-05-13 0:26 ` [PATCH v4 01/14] tpm: export tpm_show_device, tpm_set_device, and get_tpm Aidan Garske
` (15 more replies)
0 siblings, 16 replies; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot; +Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske
Hi all,
This is v4 of the wolfTPM TPM 2.0 stack integration for U-Boot.
What this series does
---------------------
wolfTPM (https://github.com/wolfSSL/wolfTPM) is a portable TPM 2.0
library that provides a full TPM 2.0 command set, an SPI/MMIO HAL,
and firmware-update support for Infineon SLB9672/SLB9673 hardware.
This series wires it into U-Boot as an *optional* alternative
backend behind the existing 'tpm2' command, plus the supporting
infrastructure to make it run on QEMU+swtpm, sandbox, and real
Raspberry Pi 4 + Infineon SLB9672 hardware.
Why a second TPM backend
------------------------
U-Boot already has a working TPM 2.0 stack and Peter Robinson asked
in v3 review what value this brings. The honest answer is:
1. Firmware update support for Infineon SLB9672/SLB9673. The
existing U-Boot TPM 2.0 stack has no firmware-update command;
wolfTPM provides the manifest+image flashing flow used by
Infineon's recovery / security-patch tooling. This is the
primary "why now" reason for boards shipping Infineon TPM HATs
where the field-updatable firmware is part of the supported
lifecycle.
2. Optional native SPI HAL. The wolfTPM library can talk to a TPM
via either (a) U-Boot's existing TPM driver model (the
WOLFTPM_LINUX_DEV path; this is what QEMU+swtpm uses in this
series) or (b) its own SPI HAL bypassing driver model. Path (b)
is what lets the BCM2835/BCM2711 driver in patch 3 talk straight
to the Infineon HAT on a stock Pi 4 without needing the broader
TPM uclass machinery.
3. Backend selection is a Kconfig switch; CONFIG_TPM_WOLF is
default-off and 'tpm2' continues to dispatch to the existing
backend unless the user opts in. No defconfig in tree turns
this on today except the new rpi_4_wolftpm one this series adds.
Maintenance
-----------
wolfTPM is imported as a git subtree under lib/wolftpm (mirroring
how lib/mbedtls, lib/lwip and dts/upstream are maintained in tree),
and tools/update-subtree.sh knows about it. Updates flow through
the standard `git subtree pull` path, not as separate patches.
Note on license: github.com/wolfSSL/wolfTPM currently shows GPL-3.0
in its repo badge. wolfSSL is working on a GPLv2-compatible release
for upstreaming purposes; this series is being sent now to get
review on the integration shape, with the understanding that the
license question is being addressed separately by wolfSSL before
this is appropriate to merge. I will follow up on the list when
that's resolved.
Changes since v3
----------------
Addressing review from Peter Robinson on v3:
- SPI driver copyright attribution fixed to credit the original
Linux kernel authors (Chris Boot, Stephen Warren, Martin Sperl)
the U-Boot driver is ported from. The driver is still in this
series rather than split off, because nothing else in the tree
uses it yet and decoupling it would just create a "blocked on"
dependency chain; if reviewers prefer it split, happy to do that
in v5.
- rpi_4_defconfig is no longer modified. v3 added CONFIG_LOG /
LOGLEVEL=7 / UNIT_TEST / CONSOLE_RECORD / HEXDUMP to it - that
was wrong, it's not what the average RPi user wants. Instead,
v4 adds a *new* rpi_4_wolftpm_defconfig that enables only the
bits a wolfTPM user actually needs (SPI + TPM + wolfTPM). No
debug / unit-test pollution. Users who don't want wolfTPM
continue to use rpi_4_defconfig untouched.
- The TPM device-tree node for the SLB9670/9672 on RPi 4 has been
moved out of bcm2711-rpi-4-b.dts (which is Linux-derived and
should match upstream) and into bcm2711-rpi-4-b-u-boot.dtsi
(which is the U-Boot convention for U-Boot-only DT additions).
This means SystemReady firmware-provided FDTs and the upstream
Linux DT are no longer polluted by this series.
- DT changes are now split into three per-device commits (RPi4,
QEMU arm64, sandbox) instead of one combined commit.
- Commit messages rewritten to explain *why* the change is being
made, not just *what* configs are set.
Branch
------
Full 16-commit history (including the subtree squash + merge that
aren't sent to the list because they're too large / are a merge):
https://github.com/aidangarske/u-boot wolftpm-v4-patches
Or pull the wolfTPM source straight from
https://github.com/wolfssl/wolfTPM @ 664db130d57.
Testing
-------
- QEMU arm64 + swtpm Python test framework
./test/py/test.py --bd qemu_arm64 \
-k "test_wolftpm and not ut_cmd"
matches v3: 19 passed, 2 skipped. (The 2 skipped are
test_wolftpm_change_auth, which requires wolfCrypt, and
test_wolftpm_get_capability.)
- rpi_4_defconfig (unmodified vanilla path) still builds clean.
- rpi_4_wolftpm_defconfig builds clean, TPM node is present in
the compiled bcm2711-rpi-4-b.dtb at /soc/spi@7e204000/tpm@1
with compatible "infineon,slb9670", "tcg,tpm_tis-spi".
- Real Raspberry Pi 4 + Infineon SLB9672 hardware: tpm2 autostart
/ info / get_capability / pcr_read / pcr_extend / caps / clear
all return expected output; firmware-update path verified.
v3 thread:
https://lore.kernel.org/u-boot/?q=PATCH+v3+tpm+wolfTPM
Aidan Garske (14):
tpm: export tpm_show_device, tpm_set_device, and get_tpm
include/hash: add SHA384 hash wrapper declaration for wolfTPM
spi: add BCM2835/BCM2711 hardware SPI controller driver
arm: dts: bcm2711-rpi-4-b: add Infineon SLB9670/9672 TPM in U-Boot dtsi
arm: dts: qemu-arm64: add TPM TIS MMIO node
sandbox: dts: add TPM SPI emulator node
tpm: add wolfTPM build rules and Kconfig
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: add rpi_4_wolftpm_defconfig
--
2.47.3
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v4 01/14] tpm: export tpm_show_device, tpm_set_device, and get_tpm
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
@ 2026-05-13 0:26 ` Aidan Garske
2026-05-15 13:06 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 02/14] include/hash: add SHA384 hash wrapper declaration for wolfTPM Aidan Garske
` (14 subsequent siblings)
15 siblings, 1 reply; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot; +Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske, 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.49.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 02/14] include/hash: add SHA384 hash wrapper declaration for wolfTPM
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
2026-05-13 0:26 ` [PATCH v4 01/14] tpm: export tpm_show_device, tpm_set_device, and get_tpm Aidan Garske
@ 2026-05-13 0:26 ` Aidan Garske
2026-05-13 0:26 ` [PATCH v4 03/14] spi: add BCM2835/BCM2711 hardware SPI controller driver Aidan Garske
` (13 subsequent siblings)
15 siblings, 0 replies; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot; +Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske, Aidan
From: Aidan <aidan@wolfssl.com>
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 ++++++++++++++++++
1 file changed, 18 insertions(+)
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
--
2.49.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 03/14] spi: add BCM2835/BCM2711 hardware SPI controller driver
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
2026-05-13 0:26 ` [PATCH v4 01/14] tpm: export tpm_show_device, tpm_set_device, and get_tpm Aidan Garske
2026-05-13 0:26 ` [PATCH v4 02/14] include/hash: add SHA384 hash wrapper declaration for wolfTPM Aidan Garske
@ 2026-05-13 0:26 ` Aidan Garske
2026-05-15 13:07 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 04/14] arm: dts: bcm2711-rpi-4-b: add Infineon SLB9670/9672 TPM in U-Boot dtsi Aidan Garske
` (12 subsequent siblings)
15 siblings, 1 reply; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot
Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske, Aidan,
Jagan Teki, Sean Anderson, Patrick Delaunay, Tien Fong Chee,
Ralph Siemsen, Boon Khai Ng, Patrice Chotard
From: Aidan <aidan@wolfssl.com>
The BCM2835/BCM2711 SoC on Raspberry Pi 3/4 has no in-tree U-Boot
driver for its hardware SPI0 controller; existing U-Boot work with
SPI peripherals on these boards has to fall back to GPIO bit-banging
via spi-gpio. That fallback is functional but slow (a few hundred
kHz versus the 32 MHz the controller supports), and for protocols
like the Infineon SLB9670 / SLB9672 TPM 2.0 TIS interface it makes
early-boot operations (startup, self-test, PCR extend) noticeably
sluggish.
Port the Linux kernel driver drivers/spi/spi-bcm2835.c into U-Boot
so existing device-tree nodes using the "brcm,bcm2835-spi" /
"brcm,bcm2711-spi" compatible work out of the box. The port keeps
the same register layout and software-GPIO chip-select scheme the
Linux driver already uses, which is necessary to work around the
BCM2835 SPI block's CS auto-deassert behaviour - that behaviour
corrupts multi-byte TPM TIS transactions when hardware CS is left
enabled.
Notable deltas from the Linux driver:
- DMA, interrupt and slave-mode paths are removed; the U-Boot
xfer is a synchronous polled loop, which is appropriate for the
pre-OS context.
- U-Boot driver-model glue replaces the Linux spi_controller
bookkeeping.
- VideoCore 0x7E000000 peripheral addresses present in the BCM2711
device tree are translated to the ARM-visible 0xFE000000 base.
The first user is the wolfTPM integration on rpi_4_wolftpm_defconfig
with an Infineon SLB9672 TPM HAT, but the driver is not TPM-specific
and any DM_SPI consumer (SPI-NOR flash, SPI EEPROM, etc.) will work
the same way.
Copyright on the ported portions remains with the original Linux
authors (Chris Boot, Stephen Warren, Martin Sperl).
Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
drivers/spi/Kconfig | 9 +
drivers/spi/Makefile | 1 +
drivers/spi/bcm2835_spi.c | 440 ++++++++++++++++++++++++++++++++++++++
3 files changed, 450 insertions(+)
create mode 100644 drivers/spi/bcm2835_spi.c
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 63d61ccf8ed..02ee2b2e6a0 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -116,6 +116,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..b6ac35d37a3
--- /dev/null
+++ b/drivers/spi/bcm2835_spi.c
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Broadcom BCM2835/BCM2711 SPI Controllers
+ *
+ * Copyright (C) 2012 Chris Boot
+ * Copyright (C) 2013 Stephen Warren
+ * Copyright (C) 2015 Martin Sperl
+ * Copyright (C) 2026 wolfSSL Inc.
+ *
+ * Ported from the Linux kernel driver drivers/spi/spi-bcm2835.c
+ * (GPL-2.0+) and re-architected for U-Boot's driver model:
+ * hardware chip-select is replaced with software-GPIO chip-select
+ * (which the Linux driver also does, to work around the CS
+ * auto-deassert behaviour of the BCM2835 SPI block during
+ * multi-byte TPM TIS transactions); DMA and interrupt support is
+ * removed; the transfer loop is a synchronous poll suitable for
+ * the U-Boot context.
+ */
+
+#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.49.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 04/14] arm: dts: bcm2711-rpi-4-b: add Infineon SLB9670/9672 TPM in U-Boot dtsi
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
` (2 preceding siblings ...)
2026-05-13 0:26 ` [PATCH v4 03/14] spi: add BCM2835/BCM2711 hardware SPI controller driver Aidan Garske
@ 2026-05-13 0:26 ` Aidan Garske
2026-05-15 13:08 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 05/14] arm: dts: qemu-arm64: add TPM TIS MMIO node Aidan Garske
` (11 subsequent siblings)
15 siblings, 1 reply; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot; +Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske, Aidan
From: Aidan <aidan@wolfssl.com>
Add a TPM 2.0 device-tree node on SPI0 CE1 for the Infineon
SLB9670 / SLB9672 TPM HAT. The pinout matches the standard Linux
tpm-slb9670 overlay, so a board configured for U-Boot with this
addition behaves the same as a Linux kernel using that overlay.
The node is placed in bcm2711-rpi-4-b-u-boot.dtsi (the U-Boot-only
DT augmentation file) rather than in bcm2711-rpi-4-b.dts. This
keeps the upstream-Linux-derived .dts unchanged, so SystemReady
firmware-provided FDTs and the upstream Linux device tree continue
to match what kernel.org ships - which addresses the concern raised
in v3 review about polluting the Linux DT path.
A spi0 alias is added pointing at the BCM2711 SPI controller, so
that wolfTPM's SPI HAL (which addresses the bus by number) finds
the TPM at bus 0 CS 1.
Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi | 39 ++++++++++++++++++++++++
1 file changed, 39 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..11174e62131
--- /dev/null
+++ b/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * U-Boot-only additions for Raspberry Pi 4 Model B
+ *
+ * Adds a TPM 2.0 device tree node on SPI0 CE1 for the Infineon
+ * SLB9670 / SLB9672 TPM HAT (electrically identical pinout to
+ * the Linux tpm-slb9670 overlay).
+ *
+ * The node lives in *-u-boot.dtsi rather than in bcm2711-rpi-4-b.dts
+ * so it is only visible to U-Boot's bundled FDT and never pollutes
+ * the upstream Linux DT or a SystemReady firmware-provided FDT.
+ */
+
+#include "bcm283x-u-boot.dtsi"
+
+/ {
+ aliases {
+ spi0 = &spi;
+ };
+};
+
+&gpio {
+ bootph-all;
+};
+
+&spi {
+ status = "okay";
+ bootph-all;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_gpio7>;
+
+ /* Infineon SLB9670 / SLB9672 TPM 2.0 on CE1 (GPIO7) */
+ tpm@1 {
+ compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
+ reg = <1>;
+ spi-max-frequency = <32000000>;
+ bootph-all;
+ };
+};
--
2.49.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 05/14] arm: dts: qemu-arm64: add TPM TIS MMIO node
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
` (3 preceding siblings ...)
2026-05-13 0:26 ` [PATCH v4 04/14] arm: dts: bcm2711-rpi-4-b: add Infineon SLB9670/9672 TPM in U-Boot dtsi Aidan Garske
@ 2026-05-13 0:26 ` Aidan Garske
2026-05-15 13:09 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 06/14] sandbox: dts: add TPM SPI emulator node Aidan Garske
` (10 subsequent siblings)
15 siblings, 1 reply; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot; +Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske, Aidan
From: Aidan <aidan@wolfssl.com>
Add a TPM 2.0 TIS MMIO node at the address QEMU's virt machine
exposes when started with -device tpm-tis-device. This lets the
in-tree QEMU+swtpm test path (used by the wolfTPM Python test
suite, and similarly usable by anyone bringing up the existing
TPM 2.0 stack against swtpm) work without having to inject a DT
overlay at runtime.
Address 0x0c000000 / size 0x5000 matches QEMU's virt machine TPM
TIS region.
Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
arch/arm/dts/qemu-arm64.dts | 4 ++++
1 file changed, 4 insertions(+)
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>;
+ };
};
--
2.49.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 06/14] sandbox: dts: add TPM SPI emulator node
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
` (4 preceding siblings ...)
2026-05-13 0:26 ` [PATCH v4 05/14] arm: dts: qemu-arm64: add TPM TIS MMIO node Aidan Garske
@ 2026-05-13 0:26 ` Aidan Garske
2026-05-15 13:11 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 07/14] tpm: add wolfTPM build rules and Kconfig Aidan Garske
` (9 subsequent siblings)
15 siblings, 1 reply; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot
Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske, Aidan,
Simon Glass, Heiko Schocher, Marek Vasut, Mattijs Korpershoek
From: Aidan <aidan@wolfssl.com>
Add a "sandbox,tpm-spi" slave on the existing sandbox SPI bus and
a matching "sandbox,tpm-spi-emul" emulator node, so the sandbox
unit-test target can exercise SPI-attached TPM code paths without
real hardware.
The slave device sits on CS 1 (CS 0 is the SPI-NOR flash emulator
that other sandbox tests use), and the slave's sandbox,emul
phandle points at the emulator node added at the root of the
sandbox device tree.
Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
arch/sandbox/dts/sandbox.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
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.49.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 07/14] tpm: add wolfTPM build rules and Kconfig
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
` (5 preceding siblings ...)
2026-05-13 0:26 ` [PATCH v4 06/14] sandbox: dts: add TPM SPI emulator node Aidan Garske
@ 2026-05-13 0:26 ` Aidan Garske
2026-05-13 0:26 ` [PATCH v4 08/14] tpm: add wolfTPM headers and SHA384 glue code Aidan Garske
` (8 subsequent siblings)
15 siblings, 0 replies; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot
Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske, Aidan,
Heinrich Schuchardt, Heiko Schocher, Christoph Niedermaier,
Stefan Roese, Simon Glass, Marek Vasut, Sean Edmond,
Jerome Forissier
From: Aidan <aidan@wolfssl.com>
Hook the wolfTPM source tree (imported as a subtree at lib/wolftpm/ in
the preceding commits) into the U-Boot build and add upstream-pull
support to tools/update-subtree.sh, matching how mbedtls, dts, and lwip
are maintained.
lib/Kconfig:
Adds CONFIG_TPM_WOLF under library routines, depending on DM,
implying DM_RNG, and selecting SHA1.
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 so wolfTPM picks
up include/configs/user_settings.h.
tools/update-subtree.sh:
Registers the wolftpm subtree (path lib/wolftpm, upstream
https://github.com/wolfssl/wolfTPM.git) so the existing pull/pick
workflow can be used for future wolfTPM updates.
Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
lib/Kconfig | 13 +++++++++++++
lib/Makefile | 17 +++++++++++++++++
tools/update-subtree.sh | 7 ++++++-
3 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/lib/Kconfig b/lib/Kconfig
index 931d5206936..b7dc422e94c 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 is a
+ portable, open-source TPM 2.0 stack licensed under GPLv2. Enabling
+ this option allows U-Boot to interact with the TPM via wolfTPM,
+ including firmware updates, PCR extend, and other TPM 2.0
+ operations. The wolfTPM source tree lives under lib/wolftpm/ as
+ a subtree (see tools/update-subtree.sh).
+
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..0753e33d69e 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -64,6 +64,23 @@ obj-$(CONFIG_EFI_TCG2_PROTOCOL) += tpm_tcg2.o
obj-$(CONFIG_MEASURED_BOOT) += tpm_tcg2.o
endif
+# wolfTPM (TPM 2.0 stack, including firmware update support)
+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/tools/update-subtree.sh b/tools/update-subtree.sh
index 536b3318573..c5963e6a3ae 100755
--- a/tools/update-subtree.sh
+++ b/tools/update-subtree.sh
@@ -17,7 +17,7 @@ set -e
print_usage() {
echo "usage: $0 <op> <subtree-name> <ref>"
echo " <op> pull or pick"
- echo " <subtree-name> mbedtls or dts or lwip"
+ echo " <subtree-name> mbedtls or dts or lwip or wolftpm"
echo " <ref> release tag [pull] or commit id [pick]"
}
@@ -47,6 +47,11 @@ set_params() {
repo_url=https://git.savannah.gnu.org/git/lwip.git
remote_name="lwip_upstream"
;;
+ wolftpm)
+ path=lib/wolftpm
+ repo_url=https://github.com/wolfssl/wolfTPM.git
+ remote_name="wolftpm_upstream"
+ ;;
*)
echo "Invalid subtree name: $subtree_name"
print_usage
--
2.49.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 08/14] tpm: add wolfTPM headers and SHA384 glue code
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
` (6 preceding siblings ...)
2026-05-13 0:26 ` [PATCH v4 07/14] tpm: add wolfTPM build rules and Kconfig Aidan Garske
@ 2026-05-13 0:26 ` Aidan Garske
2026-05-13 0:26 ` [PATCH v4 09/14] tpm: add wolfTPM driver helpers and Kconfig options Aidan Garske
` (7 subsequent siblings)
15 siblings, 0 replies; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot; +Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske, 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).
user_settings.h pulls in <asm/byteorder.h> up front so U-Boot's
cpu_to_beXX / beXX_to_cpu macros are defined before wolfTPM's
tpm2_packet.h, whose fallback definitions are #ifndef-guarded.
This keeps the workaround on the wolfTPM side rather than
modifying linux/byteorder/generic.h.
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 | 123 ++++++++++++++++++++++++++++++++
include/wolftpm.h | 34 +++++++++
lib/wolftpm.c | 56 +++++++++++++++
3 files changed, 213 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..6afd6ddc520
--- /dev/null
+++ b/include/configs/user_settings.h
@@ -0,0 +1,123 @@
+/* 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
+
+/* Define U-Boot's byte-order macros first so wolfTPM's #ifndef-guarded
+ * fallbacks in tpm2_packet.h don't redefine them.
+ */
+#include <asm/byteorder.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.49.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 09/14] tpm: add wolfTPM driver helpers and Kconfig options
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
` (7 preceding siblings ...)
2026-05-13 0:26 ` [PATCH v4 08/14] tpm: add wolfTPM headers and SHA384 glue code Aidan Garske
@ 2026-05-13 0:26 ` Aidan Garske
2026-05-13 0:26 ` [PATCH v4 10/14] cmd: refactor tpm2 command into frontend/backend architecture Aidan Garske
` (6 subsequent siblings)
15 siblings, 0 replies; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot; +Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske, 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.49.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 10/14] cmd: refactor tpm2 command into frontend/backend architecture
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
` (8 preceding siblings ...)
2026-05-13 0:26 ` [PATCH v4 09/14] tpm: add wolfTPM driver helpers and Kconfig options Aidan Garske
@ 2026-05-13 0:26 ` Aidan Garske
2026-05-15 14:11 ` Simon Glass
2026-05-15 14:15 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 11/14] tpm: add sandbox TPM SPI emulator Aidan Garske
` (5 subsequent siblings)
15 siblings, 2 replies; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot
Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske, Aidan,
Kory Maincent (TI.com), Michael Trimarchi, Mikhail Kshevetskiy,
Jerome Forissier, Sean Edmond, Heinrich Schuchardt,
Heiko Schocher, Dinesh Maniyam, Mattijs Korpershoek, Michal Simek,
Brian Sune, Simon Glass, Andrew Goodbody
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 b71ac554c0b..fe9b3819eaa 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -3194,4 +3194,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.49.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 11/14] tpm: add sandbox TPM SPI emulator
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
` (9 preceding siblings ...)
2026-05-13 0:26 ` [PATCH v4 10/14] cmd: refactor tpm2 command into frontend/backend architecture Aidan Garske
@ 2026-05-13 0:26 ` Aidan Garske
2026-05-15 13:24 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 12/14] test: add wolfTPM C unit tests and Python integration tests Aidan Garske
` (4 subsequent siblings)
15 siblings, 1 reply; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot
Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske, Aidan,
Jagan Teki, Vignesh R, Tudor Ambarus, Simon Glass
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.49.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 12/14] test: add wolfTPM C unit tests and Python integration tests
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
` (10 preceding siblings ...)
2026-05-13 0:26 ` [PATCH v4 11/14] tpm: add sandbox TPM SPI emulator Aidan Garske
@ 2026-05-13 0:26 ` Aidan Garske
2026-05-15 14:15 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 13/14] doc: add wolfTPM documentation Aidan Garske
` (3 subsequent siblings)
15 siblings, 1 reply; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot
Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske, Aidan,
Heinrich Schuchardt, Bin Meng, Simon Glass, Dinesh Maniyam
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 2476068aee6..08fbc31a06a 100644
--- a/test/cmd/Makefile
+++ b/test/cmd/Makefile
@@ -45,3 +45,4 @@ endif
obj-$(CONFIG_ARM_FFA_TRANSPORT) += armffa.o
endif
obj-$(CONFIG_CMD_SPAWN) += spawn.o
+obj-$(CONFIG_TPM_WOLF) += wolftpm.o
diff --git a/test/cmd/wolftpm.c b/test/cmd/wolftpm.c
new file mode 100644
index 00000000000..b2e6f82a098
--- /dev/null
+++ b/test/cmd/wolftpm.c
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Tests for wolfTPM commands
+ *
+ * Copyright (C) 2025 wolfSSL Inc.
+ * Author: Aidan Garske <aidan@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.49.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 13/14] doc: add wolfTPM documentation
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
` (11 preceding siblings ...)
2026-05-13 0:26 ` [PATCH v4 12/14] test: add wolfTPM C unit tests and Python integration tests Aidan Garske
@ 2026-05-13 0:26 ` Aidan Garske
2026-05-13 0:26 ` [PATCH v4 14/14] configs: add rpi_4_wolftpm_defconfig Aidan Garske
` (2 subsequent siblings)
15 siblings, 0 replies; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot
Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske, Aidan,
Marek Vasut, Jerome Forissier, Philip Molloy
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 | 685 ++++++++++++++++++++++++++++++++++++++
3 files changed, 842 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..f16f8d8b0f4
--- /dev/null
+++ b/doc/usage/cmd/wolftpm.rst
@@ -0,0 +1,685 @@
+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 4), use the dedicated ``rpi_4_wolftpm_defconfig`` added by this
+series. It enables the BCM2835/BCM2711 hardware SPI driver, the wolfTPM
+backend, and the Infineon SLB9672 chip-specific bits, and leaves the stock
+``rpi_4_defconfig`` untouched for users who do not want wolfTPM.
+
+1. Build U-Boot for Raspberry Pi 4::
+
+ make distclean
+ export CROSS_COMPILE=aarch64-linux-gnu-
+ export ARCH=arm
+ make rpi_4_wolftpm_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
+ dtparam=spi=on
+
+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
+
+No extra build steps are required: ``rpi_4_wolftpm_defconfig`` already
+enables everything ``tpm2 <subcommand>`` needs at runtime - SPI / DM_SPI /
+BCM2835_SPI (hardware SPI controller), TPM / TPM_V2 / CMD_TPM (TPM uclass
+and frontend), CMD_WOLFTPM / TPM_WOLF / WOLFTPM_SLB9672 (wolfTPM backend and
+the Infineon chip-specific bits), plus the rest of the vanilla
+``rpi_4_defconfig`` boot stack (USB, MMC, video, etc.). ``make
+rpi_4_wolftpm_defconfig && make`` and you are done; nothing in this
+section needs to be added by hand.
+
+The TPM device-tree node lives in
+``arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi`` rather than in the Linux-derived
+``bcm2711-rpi-4-b.dts``, so it is visible to U-Boot's bundled FDT but never
+pollutes the upstream Linux DT or a SystemReady firmware-provided FDT. It
+targets standard SPI0 pins matching the Linux ``tpm-slb9670`` overlay:
+GPIO 11 (SCLK), GPIO 10 (MOSI), GPIO 9 (MISO), GPIO 7 (CE1). If your TPM
+HAT wires the chip-select to a different GPIO, edit the ``reg = <1>;`` /
+``pinctrl-0`` entries in the ``-u-boot.dtsi``.
+
+Running the C unit tests on real hardware
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``rpi_4_wolftpm_defconfig`` does **not** enable the unit-test framework, since
+that is developer/CI configuration and not what a typical board user wants
+shipped. To run ``ut cmd wolftpm`` directly on Raspberry Pi 4 (the same way
+QEMU+swtpm runs it from the Python framework), you need to turn on two extra
+Kconfig knobs **before** building:
+
+- ``CONFIG_UNIT_TEST=y`` - registers the ``ut`` command and pulls in the
+ ``ut_lib`` / ``ut_log`` / ``ut_unicode`` / ``ut_env`` test groups. Without
+ it the ``ut`` shell command does not exist.
+- ``CONFIG_HEXDUMP=y`` - the wolfTPM tests' diagnostic output uses
+ ``print_hex_dump``.
+
+Either edit ``configs/rpi_4_wolftpm_defconfig`` locally to add those two
+lines, or set them via ``menuconfig`` after running ``make
+rpi_4_wolftpm_defconfig``::
+
+ make rpi_4_wolftpm_defconfig
+ scripts/config --enable CONFIG_UNIT_TEST --enable CONFIG_HEXDUMP
+ make -j$(nproc)
+
+Then on the Pi, at the U-Boot prompt::
+
+ U-Boot> ut cmd wolftpm
+ ...
+ Tests run: 18, 4495 ms, average: 214 ms, failures: 0
+
+(Tested on Raspberry Pi 4 Model B + Infineon SLB9672 HAT, May 2026.)
+The full ``ut cmd`` run also includes 3 generic command tests for 21 total.
+
+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.49.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v4 14/14] configs: add rpi_4_wolftpm_defconfig
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
` (12 preceding siblings ...)
2026-05-13 0:26 ` [PATCH v4 13/14] doc: add wolfTPM documentation Aidan Garske
@ 2026-05-13 0:26 ` Aidan Garske
2026-05-15 11:31 ` Matthias Brugger
2026-05-13 6:35 ` [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Ilias Apalodimas
2026-05-13 16:36 ` Peter Robinson
15 siblings, 1 reply; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 0:26 UTC (permalink / raw)
To: u-boot
Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske, Aidan,
Matthias Brugger, Marek Vasut
From: Aidan <aidan@wolfssl.com>
Add a new defconfig variant for Raspberry Pi 4 that enables the
wolfTPM stack and the hardware SPI driver out of the box, so users
with an Infineon SLB9670 / SLB9672 TPM HAT can build a working
U-Boot in a single 'make rpi_4_wolftpm_defconfig && make' step.
This is a separate defconfig rather than a modification to
rpi_4_defconfig because the average RPi 4 user does not have a
TPM attached and should not pay for SPI + TPM + wolfTPM code size
by default - that was the concern raised against v3's modification
of rpi_4_defconfig.
Compared to rpi_4_defconfig this enables:
- CONFIG_SPI / CONFIG_DM_SPI / CONFIG_BCM2835_SPI / CONFIG_CMD_SPI
The hardware SPI controller driver added earlier in this series,
plus the spi command for diagnostics.
- CONFIG_TPM / CONFIG_TPM_V2 / CONFIG_CMD_TPM
The core TPM 2.0 stack and 'tpm2' command.
- CONFIG_TPM_WOLF / CONFIG_CMD_WOLFTPM / CONFIG_WOLFTPM_SLB9672
wolfTPM as the active TPM backend, with SLB9672 firmware-update
support enabled. CONFIG_WOLFTPM_LINUX_DEV is left off so
wolfTPM uses its native SPI HAL (the Linux-dev path is the
QEMU+swtpm path, not the bare-metal RPi path).
No debug / unit-test config (LOG, LOGLEVEL, UNIT_TEST,
CONSOLE_RECORD, HEXDUMP) is enabled - those belong in a developer's
local .config, not in a defconfig shipped in tree.
Signed-off-by: Aidan Garske <aidan@wolfssl.com>
---
configs/rpi_4_wolftpm_defconfig | 81 +++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
create mode 100644 configs/rpi_4_wolftpm_defconfig
diff --git a/configs/rpi_4_wolftpm_defconfig b/configs/rpi_4_wolftpm_defconfig
new file mode 100644
index 00000000000..4301d2a3e93
--- /dev/null
+++ b/configs/rpi_4_wolftpm_defconfig
@@ -0,0 +1,81 @@
+CONFIG_ARM=y
+CONFIG_ARCH_BCM283X=y
+CONFIG_TEXT_BASE=0x00080000
+CONFIG_TARGET_RPI_4=y
+CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
+CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x7fffe30
+CONFIG_ENV_SIZE=0x4000
+CONFIG_DEFAULT_DEVICE_TREE="bcm2711-rpi-4-b"
+CONFIG_OF_LIBFDT_OVERLAY=y
+CONFIG_DM_RESET=y
+CONFIG_SYS_LOAD_ADDR=0x1000000
+CONFIG_PCI=y
+CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
+CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
+CONFIG_BOOTSTD_DEFAULTS=y
+CONFIG_OF_BOARD_SETUP=y
+CONFIG_FDT_SIMPLEFB=y
+CONFIG_USE_PREBOOT=y
+CONFIG_PREBOOT="pci enum; usb start;"
+CONFIG_SYS_PBSIZE=1049
+# CONFIG_DISPLAY_CPUINFO is not set
+# CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_MISC_INIT_R=y
+CONFIG_SYS_PROMPT="U-Boot> "
+CONFIG_CMD_NVEDIT_EFI=y
+CONFIG_CMD_DFU=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_PCI=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_EFIDEBUG=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_FS_UUID=y
+CONFIG_CMD_WOLFTPM=y
+CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
+CONFIG_ENV_RELOC_GD_ENV_ADDR=y
+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_TFTP_TSIZE=y
+CONFIG_DM_DMA=y
+CONFIG_DFU_MMC=y
+CONFIG_SYS_DFU_DATA_BUF_SIZE=0x100000
+CONFIG_SYS_DFU_MAX_FILE_SIZE=0x200000
+CONFIG_BCM2835_GPIO=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_SDMA=y
+CONFIG_MMC_SDHCI_BCM2835=y
+CONFIG_BCMGENET=y
+CONFIG_PCI_BRCMSTB=y
+CONFIG_DM_RNG=y
+CONFIG_PINCTRL=y
+# CONFIG_PINCTRL_GENERIC is not set
+CONFIG_RNG_IPROC200=y
+# CONFIG_REQUIRE_SERIAL_CONSOLE is not set
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_BCM2835_SPI=y
+CONFIG_SYSINFO=y
+CONFIG_SYSINFO_SMBIOS=y
+# CONFIG_WOLFTPM_LINUX_DEV is not set
+CONFIG_WOLFTPM_SLB9672=y
+CONFIG_USB=y
+CONFIG_DM_USB_GADGET=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_PCI=y
+CONFIG_USB_KEYBOARD=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_MANUFACTURER="FSL"
+CONFIG_USB_GADGET_VENDOR_NUM=0x0525
+CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5
+CONFIG_USB_GADGET_DWC2_OTG=y
+CONFIG_USB_GADGET_DOWNLOAD=y
+CONFIG_VIDEO=y
+# CONFIG_VIDEO_BPP8 is not set
+# CONFIG_VIDEO_BPP16 is not set
+CONFIG_SYS_WHITE_ON_BLACK=y
+CONFIG_VIDEO_BCM2835=y
+CONFIG_CONSOLE_SCROLL_LINES=10
+CONFIG_PHYS_TO_BUS=y
+CONFIG_TPM=y
+# CONFIG_HEXDUMP is not set
--
2.49.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
` (13 preceding siblings ...)
2026-05-13 0:26 ` [PATCH v4 14/14] configs: add rpi_4_wolftpm_defconfig Aidan Garske
@ 2026-05-13 6:35 ` Ilias Apalodimas
2026-05-13 14:34 ` Tom Rini
2026-05-13 16:36 ` Peter Robinson
15 siblings, 1 reply; 30+ messages in thread
From: Ilias Apalodimas @ 2026-05-13 6:35 UTC (permalink / raw)
To: Aidan Garske, Tom Rini; +Cc: u-boot, Peter Robinson, David Garske
Hi Aidan
On Wed, 13 May 2026 at 03:26, Aidan Garske <aidan@wolfssl.com> wrote:
>
> Hi all,
Thanks for all the efforts. Unfortunaltely I don't think we can pick
any of these up. WolfTPM is listed as GPLv3, which is incompatible
with U-Boot [0]. Tom am I misunderstanding any of this?
>
> This is v4 of the wolfTPM TPM 2.0 stack integration for U-Boot.
>
> What this series does
> ---------------------
>
> wolfTPM (https://github.com/wolfSSL/wolfTPM) is a portable TPM 2.0
> library that provides a full TPM 2.0 command set, an SPI/MMIO HAL,
> and firmware-update support for Infineon SLB9672/SLB9673 hardware.
> This series wires it into U-Boot as an *optional* alternative
> backend behind the existing 'tpm2' command, plus the supporting
> infrastructure to make it run on QEMU+swtpm, sandbox, and real
> Raspberry Pi 4 + Infineon SLB9672 hardware.
>
> Why a second TPM backend
> ------------------------
>
> U-Boot already has a working TPM 2.0 stack and Peter Robinson asked
> in v3 review what value this brings. The honest answer is:
>
> 1. Firmware update support for Infineon SLB9672/SLB9673. The
> existing U-Boot TPM 2.0 stack has no firmware-update command;
> wolfTPM provides the manifest+image flashing flow used by
> Infineon's recovery / security-patch tooling. This is the
> primary "why now" reason for boards shipping Infineon TPM HATs
> where the field-updatable firmware is part of the supported
> lifecycle.
>
> 2. Optional native SPI HAL. The wolfTPM library can talk to a TPM
> via either (a) U-Boot's existing TPM driver model (the
> WOLFTPM_LINUX_DEV path; this is what QEMU+swtpm uses in this
> series) or (b) its own SPI HAL bypassing driver model. Path (b)
> is what lets the BCM2835/BCM2711 driver in patch 3 talk straight
> to the Infineon HAT on a stock Pi 4 without needing the broader
> TPM uclass machinery.
>
> 3. Backend selection is a Kconfig switch; CONFIG_TPM_WOLF is
> default-off and 'tpm2' continues to dispatch to the existing
> backend unless the user opts in. No defconfig in tree turns
> this on today except the new rpi_4_wolftpm one this series adds.
>
> Maintenance
> -----------
>
> wolfTPM is imported as a git subtree under lib/wolftpm (mirroring
> how lib/mbedtls, lib/lwip and dts/upstream are maintained in tree),
> and tools/update-subtree.sh knows about it. Updates flow through
> the standard `git subtree pull` path, not as separate patches.
>
> Note on license: github.com/wolfSSL/wolfTPM currently shows GPL-3.0
> in its repo badge. wolfSSL is working on a GPLv2-compatible release
> for upstreaming purposes; this series is being sent now to get
> review on the integration shape, with the understanding that the
> license question is being addressed separately by wolfSSL before
> this is appropriate to merge. I will follow up on the list when
> that's resolved.
>
> Changes since v3
> ----------------
>
> Addressing review from Peter Robinson on v3:
>
> - SPI driver copyright attribution fixed to credit the original
> Linux kernel authors (Chris Boot, Stephen Warren, Martin Sperl)
> the U-Boot driver is ported from. The driver is still in this
> series rather than split off, because nothing else in the tree
> uses it yet and decoupling it would just create a "blocked on"
> dependency chain; if reviewers prefer it split, happy to do that
> in v5.
> - rpi_4_defconfig is no longer modified. v3 added CONFIG_LOG /
> LOGLEVEL=7 / UNIT_TEST / CONSOLE_RECORD / HEXDUMP to it - that
> was wrong, it's not what the average RPi user wants. Instead,
> v4 adds a *new* rpi_4_wolftpm_defconfig that enables only the
> bits a wolfTPM user actually needs (SPI + TPM + wolfTPM). No
> debug / unit-test pollution. Users who don't want wolfTPM
> continue to use rpi_4_defconfig untouched.
> - The TPM device-tree node for the SLB9670/9672 on RPi 4 has been
> moved out of bcm2711-rpi-4-b.dts (which is Linux-derived and
> should match upstream) and into bcm2711-rpi-4-b-u-boot.dtsi
> (which is the U-Boot convention for U-Boot-only DT additions).
> This means SystemReady firmware-provided FDTs and the upstream
> Linux DT are no longer polluted by this series.
> - DT changes are now split into three per-device commits (RPi4,
> QEMU arm64, sandbox) instead of one combined commit.
> - Commit messages rewritten to explain *why* the change is being
> made, not just *what* configs are set.
>
[...]
[0] https://github.com/wolfSSL/wolfTPM/blob/master/LICENSE
Thanks
/Ilias
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0
2026-05-13 6:35 ` [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Ilias Apalodimas
@ 2026-05-13 14:34 ` Tom Rini
2026-05-13 16:04 ` Aidan Garske
0 siblings, 1 reply; 30+ messages in thread
From: Tom Rini @ 2026-05-13 14:34 UTC (permalink / raw)
To: Ilias Apalodimas; +Cc: Aidan Garske, u-boot, Peter Robinson, David Garske
[-- Attachment #1: Type: text/plain, Size: 569 bytes --]
On Wed, May 13, 2026 at 09:35:44AM +0300, Ilias Apalodimas wrote:
> Hi Aidan
>
> On Wed, 13 May 2026 at 03:26, Aidan Garske <aidan@wolfssl.com> wrote:
> >
> > Hi all,
>
> Thanks for all the efforts. Unfortunaltely I don't think we can pick
> any of these up. WolfTPM is listed as GPLv3, which is incompatible
> with U-Boot [0]. Tom am I misunderstanding any of this?
Yes, as I understand it as well (and Peter raised this question on v3
yesterday too), this is GPLv3 and not GPLv2 (older wolfSSL used to be
v2) and so no, isn't compatible.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0
2026-05-13 14:34 ` Tom Rini
@ 2026-05-13 16:04 ` Aidan Garske
0 siblings, 0 replies; 30+ messages in thread
From: Aidan Garske @ 2026-05-13 16:04 UTC (permalink / raw)
To: Tom Rini, Ilias Apalodimas, Peter Robinson; +Cc: u-boot, David Garske
Hi all,
Yes we have moved all our libraries to GPLv3. We have made exceptions for some open source projects to allow GPLv2 see here: https://github.com/wolfSSL/wolfssl/blob/master/LICENSING#L8. We are willing to do this for wolfTPM and DENX/U-Boot.
Thanks,
Aidan
> On May 13, 2026, at 7:34 AM, Tom Rini <trini@konsulko.com> wrote:
>
> On Wed, May 13, 2026 at 09:35:44AM +0300, Ilias Apalodimas wrote:
>> Hi Aidan
>>
>> On Wed, 13 May 2026 at 03:26, Aidan Garske <aidan@wolfssl.com> wrote:
>>>
>>> Hi all,
>>
>> Thanks for all the efforts. Unfortunaltely I don't think we can pick
>> any of these up. WolfTPM is listed as GPLv3, which is incompatible
>> with U-Boot [0]. Tom am I misunderstanding any of this?
>
> Yes, as I understand it as well (and Peter raised this question on v3
> yesterday too), this is GPLv3 and not GPLv2 (older wolfSSL used to be
> v2) and so no, isn't compatible.
>
> --
> Tom
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
` (14 preceding siblings ...)
2026-05-13 6:35 ` [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Ilias Apalodimas
@ 2026-05-13 16:36 ` Peter Robinson
15 siblings, 0 replies; 30+ messages in thread
From: Peter Robinson @ 2026-05-13 16:36 UTC (permalink / raw)
To: Aidan Garske; +Cc: u-boot, Ilias Apalodimas, Tom Rini, David Garske
Hi Aidan,
> This is v4 of the wolfTPM TPM 2.0 stack integration for U-Boot.
>
> What this series does
> ---------------------
>
> wolfTPM (https://github.com/wolfSSL/wolfTPM) is a portable TPM 2.0
> library that provides a full TPM 2.0 command set, an SPI/MMIO HAL,
> and firmware-update support for Infineon SLB9672/SLB9673 hardware.
> This series wires it into U-Boot as an *optional* alternative
> backend behind the existing 'tpm2' command, plus the supporting
> infrastructure to make it run on QEMU+swtpm, sandbox, and real
> Raspberry Pi 4 + Infineon SLB9672 hardware.
>
> Why a second TPM backend
> ------------------------
>
> U-Boot already has a working TPM 2.0 stack and Peter Robinson asked
> in v3 review what value this brings. The honest answer is:
>
> 1. Firmware update support for Infineon SLB9672/SLB9673. The
> existing U-Boot TPM 2.0 stack has no firmware-update command;
> wolfTPM provides the manifest+image flashing flow used by
> Infineon's recovery / security-patch tooling. This is the
> primary "why now" reason for boards shipping Infineon TPM HATs
> where the field-updatable firmware is part of the supported
> lifecycle.
>
> 2. Optional native SPI HAL. The wolfTPM library can talk to a TPM
> via either (a) U-Boot's existing TPM driver model (the
> WOLFTPM_LINUX_DEV path; this is what QEMU+swtpm uses in this
> series) or (b) its own SPI HAL bypassing driver model. Path (b)
> is what lets the BCM2835/BCM2711 driver in patch 3 talk straight
> to the Infineon HAT on a stock Pi 4 without needing the broader
> TPM uclass machinery.
I don't see what value a HAL provides here, I'm not sure we want to
bypass the driver model. What value does "Not needing the broader
TPM uclass machinery" provide? It's removing one layer, just for the
TPM pieces, and replacing it with another.
It adds a support burden on U-Boot maintainers, potentially having to
debug two different paths when issues are reported as well as the
extra maintenance burden, to achieve basically the same thing. It also
adds a layer of confusion for users.
> 3. Backend selection is a Kconfig switch; CONFIG_TPM_WOLF is
> default-off and 'tpm2' continues to dispatch to the existing
> backend unless the user opts in. No defconfig in tree turns
> this on today except the new rpi_4_wolftpm one this series adds.
That's not a feature, it's an implementation detail.
> Maintenance
> -----------
>
> wolfTPM is imported as a git subtree under lib/wolftpm (mirroring
> how lib/mbedtls, lib/lwip and dts/upstream are maintained in tree),
> and tools/update-subtree.sh knows about it. Updates flow through
> the standard `git subtree pull` path, not as separate patches.
That's the technical details, it doesn't describe who takes the added
burden, CVEs, etc
> Note on license: github.com/wolfSSL/wolfTPM currently shows GPL-3.0
> in its repo badge. wolfSSL is working on a GPLv2-compatible release
> for upstreaming purposes; this series is being sent now to get
> review on the integration shape, with the understanding that the
> license question is being addressed separately by wolfSSL before
> this is appropriate to merge. I will follow up on the list when
> that's resolved.
From my experience license exceptions, as you mentioned in your
followup email, are a complete pain in the butt, to add to it we're
linking in mbedtls, libdtc, LWIP and there's likely license issues
there too, note I haven't looked, which might be affected because
firmware pieces all link together in a single binary.
> Changes since v3
> ----------------
>
> Addressing review from Peter Robinson on v3:
>
> - SPI driver copyright attribution fixed to credit the original
> Linux kernel authors (Chris Boot, Stephen Warren, Martin Sperl)
> the U-Boot driver is ported from. The driver is still in this
> series rather than split off, because nothing else in the tree
> uses it yet and decoupling it would just create a "blocked on"
> dependency chain; if reviewers prefer it split, happy to do that
> in v5.
Please split it out to it's own series, It can be tested with the
standard TPM2 stack using a RPi SLB9672 module. Please see
doc/CONTRIBUTE.rst about patch series for explicit details on this.
> - rpi_4_defconfig is no longer modified. v3 added CONFIG_LOG /
> LOGLEVEL=7 / UNIT_TEST / CONSOLE_RECORD / HEXDUMP to it - that
> was wrong, it's not what the average RPi user wants. Instead,
> v4 adds a *new* rpi_4_wolftpm_defconfig that enables only the
> bits a wolfTPM user actually needs (SPI + TPM + wolfTPM). No
> debug / unit-test pollution. Users who don't want wolfTPM
> continue to use rpi_4_defconfig untouched.
It should probably be a rpi_arm64_defconfig derived option, and I am
not enamored, as the Raspberry Pi maintainer, having another option to
maintain and test for regressions. Please at least look at using an
#include at the very least.
> - The TPM device-tree node for the SLB9670/9672 on RPi 4 has been
> moved out of bcm2711-rpi-4-b.dts (which is Linux-derived and
> should match upstream) and into bcm2711-rpi-4-b-u-boot.dtsi
> (which is the U-Boot convention for U-Boot-only DT additions).
> This means SystemReady firmware-provided FDTs and the upstream
> Linux DT are no longer polluted by this series.
That statement is incorrect. The bcm2711-rpi-4-b-u-boot.dtsi additions
still end up in the DT that is provided to the OS via FW DT.
> - DT changes are now split into three per-device commits (RPi4,
> QEMU arm64, sandbox) instead of one combined commit.
> - Commit messages rewritten to explain *why* the change is being
> made, not just *what* configs are set.
Overall I am quite conflicted on this, I don't see largely what the
value is vs the extra maintenance effort.
I think we might be better off looking at what pieces need to land to
make maintaining this out of tree straight forward and easy for users
that wish to use the alternative option that wolfTPM provides. ATM I
don't know what that would look like, it's just a thought I am
expressing.
Regards,
Peter
> Branch
> ------
>
> Full 16-commit history (including the subtree squash + merge that
> aren't sent to the list because they're too large / are a merge):
> https://github.com/aidangarske/u-boot wolftpm-v4-patches
>
> Or pull the wolfTPM source straight from
> https://github.com/wolfssl/wolfTPM @ 664db130d57.
>
> Testing
> -------
>
> - QEMU arm64 + swtpm Python test framework
> ./test/py/test.py --bd qemu_arm64 \
> -k "test_wolftpm and not ut_cmd"
> matches v3: 19 passed, 2 skipped. (The 2 skipped are
> test_wolftpm_change_auth, which requires wolfCrypt, and
> test_wolftpm_get_capability.)
> - rpi_4_defconfig (unmodified vanilla path) still builds clean.
> - rpi_4_wolftpm_defconfig builds clean, TPM node is present in
> the compiled bcm2711-rpi-4-b.dtb at /soc/spi@7e204000/tpm@1
> with compatible "infineon,slb9670", "tcg,tpm_tis-spi".
> - Real Raspberry Pi 4 + Infineon SLB9672 hardware: tpm2 autostart
> / info / get_capability / pcr_read / pcr_extend / caps / clear
> all return expected output; firmware-update path verified.
>
> v3 thread:
> https://lore.kernel.org/u-boot/?q=PATCH+v3+tpm+wolfTPM
>
> Aidan Garske (14):
> tpm: export tpm_show_device, tpm_set_device, and get_tpm
> include/hash: add SHA384 hash wrapper declaration for wolfTPM
> spi: add BCM2835/BCM2711 hardware SPI controller driver
> arm: dts: bcm2711-rpi-4-b: add Infineon SLB9670/9672 TPM in U-Boot dtsi
> arm: dts: qemu-arm64: add TPM TIS MMIO node
> sandbox: dts: add TPM SPI emulator node
> tpm: add wolfTPM build rules and Kconfig
> 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: add rpi_4_wolftpm_defconfig
>
> --
> 2.47.3
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 14/14] configs: add rpi_4_wolftpm_defconfig
2026-05-13 0:26 ` [PATCH v4 14/14] configs: add rpi_4_wolftpm_defconfig Aidan Garske
@ 2026-05-15 11:31 ` Matthias Brugger
0 siblings, 0 replies; 30+ messages in thread
From: Matthias Brugger @ 2026-05-15 11:31 UTC (permalink / raw)
To: Aidan Garske, u-boot
Cc: Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske,
Marek Vasut
On 13/05/2026 02:26, Aidan Garske wrote:
> From: Aidan <aidan@wolfssl.com>
>
> Add a new defconfig variant for Raspberry Pi 4 that enables the
> wolfTPM stack and the hardware SPI driver out of the box, so users
> with an Infineon SLB9670 / SLB9672 TPM HAT can build a working
> U-Boot in a single 'make rpi_4_wolftpm_defconfig && make' step.
>
> This is a separate defconfig rather than a modification to
> rpi_4_defconfig because the average RPi 4 user does not have a
> TPM attached and should not pay for SPI + TPM + wolfTPM code size
> by default - that was the concern raised against v3's modification
> of rpi_4_defconfig.
>
> Compared to rpi_4_defconfig this enables:
> - CONFIG_SPI / CONFIG_DM_SPI / CONFIG_BCM2835_SPI / CONFIG_CMD_SPI
> The hardware SPI controller driver added earlier in this series,
> plus the spi command for diagnostics.
> - CONFIG_TPM / CONFIG_TPM_V2 / CONFIG_CMD_TPM
> The core TPM 2.0 stack and 'tpm2' command.
> - CONFIG_TPM_WOLF / CONFIG_CMD_WOLFTPM / CONFIG_WOLFTPM_SLB9672
> wolfTPM as the active TPM backend, with SLB9672 firmware-update
> support enabled. CONFIG_WOLFTPM_LINUX_DEV is left off so
> wolfTPM uses its native SPI HAL (the Linux-dev path is the
> QEMU+swtpm path, not the bare-metal RPi path).
>
> No debug / unit-test config (LOG, LOGLEVEL, UNIT_TEST,
> CONSOLE_RECORD, HEXDUMP) is enabled - those belong in a developer's
> local .config, not in a defconfig shipped in tree.
>
> Signed-off-by: Aidan Garske <aidan@wolfssl.com>
Peter what is your view on that. Shall we add config options for specific hats?
I'm inclined to do so, but I wonder if we can have some kind of config overlay
instead of a fresh new config. (I'm not aware that U-Boot allows for something
like this right now).
Regards,
Matthias
> ---
> configs/rpi_4_wolftpm_defconfig | 81 +++++++++++++++++++++++++++++++++
> 1 file changed, 81 insertions(+)
> create mode 100644 configs/rpi_4_wolftpm_defconfig
>
> diff --git a/configs/rpi_4_wolftpm_defconfig b/configs/rpi_4_wolftpm_defconfig
> new file mode 100644
> index 00000000000..4301d2a3e93
> --- /dev/null
> +++ b/configs/rpi_4_wolftpm_defconfig
> @@ -0,0 +1,81 @@
> +CONFIG_ARM=y
> +CONFIG_ARCH_BCM283X=y
> +CONFIG_TEXT_BASE=0x00080000
> +CONFIG_TARGET_RPI_4=y
> +CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
> +CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x7fffe30
> +CONFIG_ENV_SIZE=0x4000
> +CONFIG_DEFAULT_DEVICE_TREE="bcm2711-rpi-4-b"
> +CONFIG_OF_LIBFDT_OVERLAY=y
> +CONFIG_DM_RESET=y
> +CONFIG_SYS_LOAD_ADDR=0x1000000
> +CONFIG_PCI=y
> +CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
> +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
> +CONFIG_BOOTSTD_DEFAULTS=y
> +CONFIG_OF_BOARD_SETUP=y
> +CONFIG_FDT_SIMPLEFB=y
> +CONFIG_USE_PREBOOT=y
> +CONFIG_PREBOOT="pci enum; usb start;"
> +CONFIG_SYS_PBSIZE=1049
> +# CONFIG_DISPLAY_CPUINFO is not set
> +# CONFIG_DISPLAY_BOARDINFO is not set
> +CONFIG_MISC_INIT_R=y
> +CONFIG_SYS_PROMPT="U-Boot> "
> +CONFIG_CMD_NVEDIT_EFI=y
> +CONFIG_CMD_DFU=y
> +CONFIG_CMD_GPIO=y
> +CONFIG_CMD_MMC=y
> +CONFIG_CMD_PCI=y
> +CONFIG_CMD_SPI=y
> +CONFIG_CMD_USB=y
> +CONFIG_CMD_EFIDEBUG=y
> +CONFIG_CMD_TPM=y
> +CONFIG_CMD_FS_UUID=y
> +CONFIG_CMD_WOLFTPM=y
> +CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
> +CONFIG_ENV_RELOC_GD_ENV_ADDR=y
> +CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
> +CONFIG_TFTP_TSIZE=y
> +CONFIG_DM_DMA=y
> +CONFIG_DFU_MMC=y
> +CONFIG_SYS_DFU_DATA_BUF_SIZE=0x100000
> +CONFIG_SYS_DFU_MAX_FILE_SIZE=0x200000
> +CONFIG_BCM2835_GPIO=y
> +CONFIG_MMC_SDHCI=y
> +CONFIG_MMC_SDHCI_SDMA=y
> +CONFIG_MMC_SDHCI_BCM2835=y
> +CONFIG_BCMGENET=y
> +CONFIG_PCI_BRCMSTB=y
> +CONFIG_DM_RNG=y
> +CONFIG_PINCTRL=y
> +# CONFIG_PINCTRL_GENERIC is not set
> +CONFIG_RNG_IPROC200=y
> +# CONFIG_REQUIRE_SERIAL_CONSOLE is not set
> +CONFIG_SPI=y
> +CONFIG_DM_SPI=y
> +CONFIG_BCM2835_SPI=y
> +CONFIG_SYSINFO=y
> +CONFIG_SYSINFO_SMBIOS=y
> +# CONFIG_WOLFTPM_LINUX_DEV is not set
> +CONFIG_WOLFTPM_SLB9672=y
> +CONFIG_USB=y
> +CONFIG_DM_USB_GADGET=y
> +CONFIG_USB_XHCI_HCD=y
> +CONFIG_USB_XHCI_PCI=y
> +CONFIG_USB_KEYBOARD=y
> +CONFIG_USB_GADGET=y
> +CONFIG_USB_GADGET_MANUFACTURER="FSL"
> +CONFIG_USB_GADGET_VENDOR_NUM=0x0525
> +CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5
> +CONFIG_USB_GADGET_DWC2_OTG=y
> +CONFIG_USB_GADGET_DOWNLOAD=y
> +CONFIG_VIDEO=y
> +# CONFIG_VIDEO_BPP8 is not set
> +# CONFIG_VIDEO_BPP16 is not set
> +CONFIG_SYS_WHITE_ON_BLACK=y
> +CONFIG_VIDEO_BCM2835=y
> +CONFIG_CONSOLE_SCROLL_LINES=10
> +CONFIG_PHYS_TO_BUS=y
> +CONFIG_TPM=y
> +# CONFIG_HEXDUMP is not set
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 01/14] tpm: export tpm_show_device, tpm_set_device, and get_tpm
2026-05-13 0:26 ` [PATCH v4 01/14] tpm: export tpm_show_device, tpm_set_device, and get_tpm Aidan Garske
@ 2026-05-15 13:06 ` Simon Glass
0 siblings, 0 replies; 30+ messages in thread
From: Simon Glass @ 2026-05-15 13:06 UTC (permalink / raw)
To: aidan; +Cc: u-boot, Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske
Hi Aidan,
On 2026-05-13T00:26:04, Aidan Garske <aidan@wolfssl.com> wrote:
> tpm: export tpm_show_device, tpm_set_device, and get_tpm
>
> 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
> @@ -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)
These three helpers live in cmd/ and operate on a static tpm_dev
private to the command layer. Promoting them so a backend in lib/ or
drivers/ can call into cmd/ is the wrong direction. If the wolfTPM
backend genuinely needs shared 'currently selected TPM' state, please
move that state and these helpers into the TPM uclass and have
cmd/tpm-common.c call into them, not the other way round.
> diff --git a/include/tpm-common.h b/include/tpm-common.h
> @@ -337,4 +337,26 @@ enum tpm_version tpm_get_version(struct udevice *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);
The kerneldoc is wrong. tpm_set_device() and get_tpm() return
CMD_RET_FAILURE (1, positive), not -ve. tpm_show_device() ignores
per-device errors and unconditionally returns 0. Either document
accurately, or make tpm_show_device() propagate the failure from
tpm_get_desc().
If these become public API, please also fix the return convention to
use proper negative errnos (CMD_RET_* is a command-layer thing) and
rename get_tpm() - tpm_get_device() or similar. get_tpm() is too
generic for a global symbol.
Also, @devp is undocumented. Please add an entry for it, and note that
the function selects device 0 the first time it is called.
Regards,
Simon
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 03/14] spi: add BCM2835/BCM2711 hardware SPI controller driver
2026-05-13 0:26 ` [PATCH v4 03/14] spi: add BCM2835/BCM2711 hardware SPI controller driver Aidan Garske
@ 2026-05-15 13:07 ` Simon Glass
2026-05-15 15:13 ` Peter Robinson
0 siblings, 1 reply; 30+ messages in thread
From: Simon Glass @ 2026-05-15 13:07 UTC (permalink / raw)
To: aidan
Cc: u-boot, Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske,
Jagan Teki, Sean Anderson, Patrick Delaunay, Tien Fong Chee,
Ralph Siemsen, Boon Khai Ng, Patrice Chotard
Hi Aidan,
On 2026-05-13T00:26:04, Aidan Garske <aidan@wolfssl.com> wrote:
> spi: add BCM2835/BCM2711 hardware SPI controller driver
>
> The BCM2835/BCM2711 SoC on Raspberry Pi 3/4 has no in-tree U-Boot
> driver for its hardware SPI0 controller; existing U-Boot work with
> SPI peripherals on these boards has to fall back to GPIO bit-banging
> via spi-gpio. That fallback is functional but slow (a few hundred
> kHz versus the 32 MHz the controller supports), and for protocols
> like the Infineon SLB9670 / SLB9672 TPM 2.0 TIS interface it makes
> early-boot operations (startup, self-test, PCR extend) noticeably
> sluggish.
>
> Port the Linux kernel driver drivers/spi/spi-bcm2835.c into U-Boot
> so existing device-tree nodes using the 'brcm,bcm2835-spi' /
> 'brcm,bcm2711-spi' compatible work out of the box. The port keeps
> the same register layout and software-GPIO chip-select scheme the
> Linux driver already uses, which is necessary to work around the
> BCM2835 SPI block's CS auto-deassert behaviour - that behaviour
> corrupts multi-byte TPM TIS transactions when hardware CS is left
> enabled.
>
> [...]
>
> drivers/spi/Kconfig | 9 +
> drivers/spi/Makefile | 1 +
> drivers/spi/bcm2835_spi.c | 440 ++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 450 insertions(+)
> diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> @@ -0,0 +1,440 @@
> +/* 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) */
The GPIO base should come from the devicetree and more generally,
access to it should be via a GPIO driver. Please use lower-case hex.
This should not be in a generic SPI controller driver, and it
contradicts the commit message claim that the driver is not
TPM-specific. Any board that probes this driver currently pulses GPIO4
and GPIO24 low for 100 ms - what if something is wired to those pins?
TPM reset belongs in the TPM driver (perhaps with a gpio-reset in the
DT node for the TPM).
> diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> @@ -0,0 +1,440 @@
> +/* GPIO base for software CS control */
> +static void __iomem *g_gpio_base = (void __iomem *)0xFE200000;
This is BCM2711-only, so BCM2835 (Pi 3, which the Kconfig help and
commit subject both advertise) has its GPIO block at 0x3f200000, so
the driver will silently corrupt unrelated memory there. Anyway,
U-Boot already has pinctrl (pinctrl-bcm283x.c) and GPIO
(bcm2835_gpio.c) drivers for this SoC; please go through those.
> diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> @@ -0,0 +1,440 @@
> + /* 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;
> + }
priv->cs_gpio and priv->cs_gpio_valid are written here but never read
- bcm2835_spi_xfer() instead does
int cs_pin = (cs == 0) ? 8 : 7;
and pokes GPSET0/GPCLR0 directly, ignoring the DT. Either honour
cs-gpios via dm_gpio_set_value() (the normal U-Boot pattern, which
DM_SPI_GPIO already handles generically), or drop the cs_gpio request
and document that the driver hardcodes the Pi SPI0 CE0/CE1 pin
assignment. As written it's half of each.
> diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> @@ -0,0 +1,440 @@
> +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 */
> +};
cs_asserted is assigned in three places in xfer() but never read.
Please remove it (and the comment that promises behaviour it does not
implement).
> diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> @@ -0,0 +1,440 @@
> +/* Default clock rate - 250 MHz for Pi 4 */
> +#define BCM2835_SPI_DEFAULT_CLK 250000000
This is the SPI core/source clock, not a default transfer rate - the
default transfer speed is 1 MHz below. The name is confusing. More
importantly, on BCM2835 vs BCM2711 vs different VPU clock settings
this number is not constant; please pull it from the clk uclass (or
from clock-frequency in DT, which you already read, with no hard-coded
fallback).
> diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> @@ -0,0 +1,440 @@
> +static inline void bcm2835_spi_writel(struct bcm2835_spi_priv *priv,
> + u32 reg, u32 val)
> +{
> + writel(val, priv->regs + reg);
> +}
Please check indent for tab-alignment. Patman or checkpatch will flag these.
> diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> @@ -0,0 +1,440 @@
> + /* Poll for completion - transfer byte by byte */
> + timeout = 100000;
> + while ((tx_count < len || rx_count < len) && timeout > 0) {
The 100000 and 10000 timeouts are bare loop counters, not time bounds
so at 1 MHz a 4 KB transfer takes ~32 ms and the loop body has no
fixed cost, so these mean nothing except 'don't hang forever'. Please
convert to get_timer() / timer_get_us(), the way other DM_SPI drivers
do, so the timeout is independent of CPU speed and transfer length.
> diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> @@ -0,0 +1,440 @@
> +config BCM2835_SPI
> + bool "BCM2835/BCM2711 SPI driver"
> + depends on ARCH_BCM283X
Given the hard-coded 0xfe200000 GPIO base and the BCM2711-only fix-up
in of_to_plat(), the BCM2835 half of this option is not actually
supported. Either fix the driver to derive the GPIO base from DT /
from the existing bcm2835_gpio driver and exercise it on a Pi 3, or
narrow the Kconfig text and commit subject to say BCM2711 only.
Regards,
Simon
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 04/14] arm: dts: bcm2711-rpi-4-b: add Infineon SLB9670/9672 TPM in U-Boot dtsi
2026-05-13 0:26 ` [PATCH v4 04/14] arm: dts: bcm2711-rpi-4-b: add Infineon SLB9670/9672 TPM in U-Boot dtsi Aidan Garske
@ 2026-05-15 13:08 ` Simon Glass
0 siblings, 0 replies; 30+ messages in thread
From: Simon Glass @ 2026-05-15 13:08 UTC (permalink / raw)
To: aidan; +Cc: u-boot, Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske
Hi Aidan,
On 2026-05-13T00:26:04, Aidan Garske <aidan@wolfssl.com> wrote:
> arm: dts: bcm2711-rpi-4-b: add Infineon SLB9670/9672 TPM in U-Boot dtsi
>
> Add a TPM 2.0 device-tree node on SPI0 CE1 for the Infineon
> SLB9670 / SLB9672 TPM HAT. The pinout matches the standard Linux
> tpm-slb9670 overlay, so a board configured for U-Boot with this
> addition behaves the same as a Linux kernel using that overlay.
>
> The node is placed in bcm2711-rpi-4-b-u-boot.dtsi (the U-Boot-only
> DT augmentation file) rather than in bcm2711-rpi-4-b.dts. This
> keeps the upstream-Linux-derived .dts unchanged, so SystemReady
> firmware-provided FDTs and the upstream Linux device tree continue
> to match what kernel.org ships - which addresses the concern raised
> in v3 review about polluting the Linux DT path.
>
> A spi0 alias is added pointing at the BCM2711 SPI controller, so
> that wolfTPM's SPI HAL (which addresses the bus by number) finds
> the TPM at bus 0 CS 1.
>
> Signed-off-by: Aidan Garske <aidan@wolfssl.com>
>
> arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi | 39 ++++++++++++++++++++++++++++++++
> 1 file changed, 39 insertions(+)
> diff --git a/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi b/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi
> @@ -0,0 +1,39 @@
> +#include 'bcm283x-u-boot.dtsi'
> +
> +/ {
> + aliases {
> + spi0 = &spi;
> + };
> +};
> +
> +&gpio {
> + bootph-all;
> +};
bcm283x-u-boot.dtsi (included a few lines above) already adds
bootph-all to &gpio, so you shouldn't need this.
> diff --git a/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi b/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi
> @@ -0,0 +1,39 @@
> + /* Infineon SLB9670 / SLB9672 TPM 2.0 on CE1 (GPIO7) */
> + tpm@1 {
> + compatible = 'infineon,slb9670', 'tcg,tpm_tis-spi';
> + reg = <1>;
> + spi-max-frequency = <32000000>;
> + bootph-all;
> + };
Just to note - drivers/tpm/tpm2_tis_spi.c already binds to
tcg,tpm_tis-spi, so this node is not wolfTPM-specific; the in-tree
TPM2 stack will probe it too. Combined with Peter's request to split
the BCM2835 SPI driver out, one option is a small standalone series
that lands patch 3 plus this DT node and lets the existing TPM2 stack
drive the SLB9670 on a Pi 4, independent of the wolfTPM question.
Anyway, please adjust the commit message, since it under-sells what it
enables.
Regards,
Simon
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 05/14] arm: dts: qemu-arm64: add TPM TIS MMIO node
2026-05-13 0:26 ` [PATCH v4 05/14] arm: dts: qemu-arm64: add TPM TIS MMIO node Aidan Garske
@ 2026-05-15 13:09 ` Simon Glass
0 siblings, 0 replies; 30+ messages in thread
From: Simon Glass @ 2026-05-15 13:09 UTC (permalink / raw)
To: aidan; +Cc: u-boot, Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske
Hi Aidan,
On 2026-05-13T00:26:04, Aidan Garske <aidan@wolfssl.com> wrote:
> arm: dts: qemu-arm64: add TPM TIS MMIO node
>
> Add a TPM 2.0 TIS MMIO node at the address QEMU's virt machine
> exposes when started with -device tpm-tis-device. This lets the
> in-tree QEMU+swtpm test path (used by the wolfTPM Python test
> suite, and similarly usable by anyone bringing up the existing
> TPM 2.0 stack against swtpm) work without having to inject a DT
> overlay at runtime.
>
> Address 0x0c000000 / size 0x5000 matches QEMU's virt machine TPM
> TIS region.
>
> Signed-off-by: Aidan Garske <aidan@wolfssl.com>
>
> arch/arm/dts/qemu-arm64.dts | 4 ++++
> 1 file changed, 4 insertions(+)
> diff --git a/arch/arm/dts/qemu-arm64.dts b/arch/arm/dts/qemu-arm64.dts
> @@ -12,4 +12,8 @@
> / {
> + tpm@0c000000 {
> + compatible = 'tcg,tpm-tis-mmio';
> + reg = <0x0 0x0c000000 0x0 0x5000>;
> + };
> };
I don't think this addition takes effect at runtime. qemu_arm64 sets
imply OF_HAS_PRIOR_STAGE and board_fdt_blob_setup() returns the DTB
QEMU loaded into RAM, so U-Boot uses QEMU's generated DT, not the
compiled-in qemu-arm64.dtb. OF_OMIT_DTB defaults to y when
OF_HAS_PRIOR_STAGE is set, so the compiled DT isn't even bundled into
u-boot.bin. See doc/develop/devicetree/dt_qemu.rst
When QEMU is started with -device tpm-tis-device it already adds a tpm
node at the same 0x0c000000 region, so the existing TPM 2.0 stack
picks it up without any change here. Have you confirmed that removing
this hunk actually breaks the test path? If not, please drop the
patch; if it does help in some specific path (e.g. -dtb u-boot.dtb),
the commit message should call that out.
See also this patch where a similar thing came up (due to a QEMU
maintainer refusing to support DT additions, U-Boot needs to do the
overlay itself).
https://patchwork.ozlabs.org/project/uboot/patch/20260507140624.v3.1.5f8ce2dc2b00328d29e64be2684b10d9f52c6a7b@changeid/
I also found the context re QEMU expectations (basically Tianocore).
https://patchwork.ozlabs.org/project/uboot/patch/20240911062511.494855-23-patrick.rudolph@9elements.com/
Also, the reg property uses four cells but the root node doesn't
declare #address-cells/#size-cells, so the defaults (2/1) apply and
the cell count is wrong. Per
dts/upstream/Bindings/tpm/tcg,tpm-tis-mmio.yaml the compatible needs a
vendor-specific string first with tcg,tpm-tis-mmio as the fallback -
tcg,tpm-tis-mmio alone fails the schema. If the node really is needed,
please match what QEMU emits (or pick a sensible vendor prefix) and
wrap it in a parent that sets the address/size cells.
Regards,
Simon
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 06/14] sandbox: dts: add TPM SPI emulator node
2026-05-13 0:26 ` [PATCH v4 06/14] sandbox: dts: add TPM SPI emulator node Aidan Garske
@ 2026-05-15 13:11 ` Simon Glass
0 siblings, 0 replies; 30+ messages in thread
From: Simon Glass @ 2026-05-15 13:11 UTC (permalink / raw)
To: aidan
Cc: u-boot, Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske,
Simon Glass, Heiko Schocher, Marek Vasut, Mattijs Korpershoek
Hi Aidan,
On 2026-05-13T00:26:04, Aidan Garske <aidan@wolfssl.com> wrote:
> sandbox: dts: add TPM SPI emulator node
>
> Add a 'sandbox,tpm-spi' slave on the existing sandbox SPI bus and
> a matching 'sandbox,tpm-spi-emul' emulator node, so the sandbox
> unit-test target can exercise SPI-attached TPM code paths without
> real hardware.
>
> The slave device sits on CS 1 (CS 0 is the SPI-NOR flash emulator
> that other sandbox tests use), and the slave's sandbox,emul
> phandle points at the emulator node added at the root of the
> sandbox device tree.
>
> Signed-off-by: Aidan Garske <aidan@wolfssl.com>
>
> arch/sandbox/dts/sandbox.dtsi | 11 +++++++++++
> 1 file changed, 11 insertions(+)
Reviewed-by: Simon Glass <sjg@chromium.org>
> diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi
> @@ -286,6 +286,17 @@
> + tpm_spi: tpm@1 {
> + reg = <1>;
> + compatible = 'sandbox,tpm-spi';
> + spi-max-frequency = <10000000>;
> + sandbox,emul = <&tpm_spi_emul>;
> + };
Just to check - is there a reason this is in sandbox.dtsi rather than
test.dts? Only the C unit tests in patch 12 exercise this emulator,
and test-only nodes normally live in test.dts. The existing sandbox
TPM nodes in sandbox.dtsi are arguably an exception rather than the
rule. It's fine to have the node in both, though.
Regards,
Simon
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 11/14] tpm: add sandbox TPM SPI emulator
2026-05-13 0:26 ` [PATCH v4 11/14] tpm: add sandbox TPM SPI emulator Aidan Garske
@ 2026-05-15 13:24 ` Simon Glass
0 siblings, 0 replies; 30+ messages in thread
From: Simon Glass @ 2026-05-15 13:24 UTC (permalink / raw)
To: aidan
Cc: u-boot, Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske,
Jagan Teki, Vignesh R, Tudor Ambarus, Simon Glass
Hi Aidan,
On 2026-05-13T00:26:04, Aidan Garske <aidan@wolfssl.com> wrote:
> tpm: add sandbox TPM SPI emulator
>
> 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)
> [...]
>
> drivers/mtd/spi/sandbox.c | 30 +++-
> drivers/tpm/tpm_spi_sandbox.c | 410 ++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 431 insertions(+), 9 deletions(-)
> diff --git a/drivers/tpm/tpm_spi_sandbox.c b/drivers/tpm/tpm_spi_sandbox.c
> @@ -0,0 +1,410 @@
> + * 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;
Every command returns the same canned 10-byte TPM_RC_SUCCESS. Any test
exercising tpm2 get_capability, pcr_read, pcr_extend etc. would either
fail to parse the response or silently accept garbage as success.
As-is, this emulator just lets SPI bytes flow.
Please use lower-case hex.
The real sandbox TPM2 state machine already lives next door in
drivers/tpm/tpm2_tis_sandbox.c with sandbox_common.c. Please wire this
emulator into sandbox_tpm2_fill_buf() and the existing
nvdata/PCR/hierarchy logic so commands actually do what they say.
Otherwise the wolfTPM C unit tests in patch 12 can't meaningfully run
on sandbox.
> diff --git 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,
> + 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;
This is a generic change to sandbox SPI emulation that affects every
existing sandbox SPI user. Please split it into its own patch ahead of
this one, with a commit message justifying the sandbox,emul phandle
convention on its own terms, and ideally a doc update. Bundled with
the TPM emulator, the reasoning gets lost.
> diff --git a/drivers/tpm/tpm_spi_sandbox.c b/drivers/tpm/tpm_spi_sandbox.c
> @@ -0,0 +1,410 @@
> + /*
> + * 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) {
The comment doesn't match up - the TIS FIFO is a single register at
0x0024 and the address does not auto-increment; the host repeats the
same address while burst-count drains. Because the SPI layer does
priv->addr + priv->data_pos for every byte, you treat a 3000-byte
window as FIFO, which masks the issue but is wrong if anything reads
e.g. TPM_INT_ENABLE_REG (0x0008) - one of your #defines, is never
handled. Please hold priv->addr constant for FIFO accesses, and either
implement the other registers you've declared or drop the #defines.
> diff --git a/drivers/tpm/tpm_spi_sandbox.c b/drivers/tpm/tpm_spi_sandbox.c
> @@ -0,0 +1,410 @@
> +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,
> +};
Why a UCLASS_SPI_GENERIC stub with a sandbox-specific compatible,
rather than reusing tcg,tpm_tis-spi so the existing tpm2_tis_spi.c
driver binds on top of the emulator? That would give actual U-Boot TPM
uclass coverage on sandbox (currently zero for the SPI path) and let
the standard ut dm tpm tests run against this emulator without wolfTPM
in the picture. As written, the slave driver exists only to make the
DT node bind, and the emulator only ever sees raw bytes from wolfTPM's
native HAL, so the U-Boot TPM stack still has no SPI sandbox coverage.
> diff --git a/drivers/tpm/tpm_spi_sandbox.c b/drivers/tpm/tpm_spi_sandbox.c
> @@ -0,0 +1,410 @@
> +/* Maximum buffer sizes */
> +#define TPM_CMD_BUF_SIZE 4096
> +#define TPM_RSP_BUF_SIZE 4096
These 4 KiB buffers live in priv_auto, which is fine, but the existing
sandbox TPM2 emulator caps responses at TPM2_MAX_BUF_SIZE in tpm-v2.h
— please reuse that rather than inventing new sizes, especially since
the goal is to integrate with that state machine.
Regards,
Simon
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 10/14] cmd: refactor tpm2 command into frontend/backend architecture
2026-05-13 0:26 ` [PATCH v4 10/14] cmd: refactor tpm2 command into frontend/backend architecture Aidan Garske
@ 2026-05-15 14:11 ` Simon Glass
2026-05-15 14:15 ` Simon Glass
1 sibling, 0 replies; 30+ messages in thread
From: Simon Glass @ 2026-05-15 14:11 UTC (permalink / raw)
To: Aidan Garske
Cc: u-boot, Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske,
Kory Maincent (TI.com), Michael Trimarchi, Mikhail Kshevetskiy,
Jerome Forissier, Sean Edmond, Heinrich Schuchardt,
Heiko Schocher, Dinesh Maniyam, Mattijs Korpershoek, Michal Simek,
Brian Sune, Andrew Goodbody
Hi Aidan,
On Tue, 12 May 2026 at 18:26, Aidan Garske <aidan@wolfssl.com> wrote:
>
> 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
This commit should be split so that the refactor is first and the Wolf
stuff later.
Regards,
Simon
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 10/14] cmd: refactor tpm2 command into frontend/backend architecture
2026-05-13 0:26 ` [PATCH v4 10/14] cmd: refactor tpm2 command into frontend/backend architecture Aidan Garske
2026-05-15 14:11 ` Simon Glass
@ 2026-05-15 14:15 ` Simon Glass
1 sibling, 0 replies; 30+ messages in thread
From: Simon Glass @ 2026-05-15 14:15 UTC (permalink / raw)
To: aidan
Cc: u-boot, Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske,
Kory Maincent (TI.com), Michael Trimarchi, Mikhail Kshevetskiy,
Jerome Forissier, Sean Edmond, Heinrich Schuchardt,
Heiko Schocher, Dinesh Maniyam, Mattijs Korpershoek, Michal Simek,
Brian Sune, Simon Glass, Andrew Goodbody
Hi Aidan,
On 2026-05-13T00:26:04, Aidan Garske <aidan@wolfssl.com> wrote:
> cmd: refactor tpm2 command into frontend/backend architecture
>
> 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,
> [...]
>
> 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(-)
> diff --git a/cmd/wolftpm.c b/cmd/wolftpm.c
> @@ -0,0 +1,1170 @@
> +#define LOG_CATEGORY UCLASS_BOOTSTD
wolftpm.c has nothing to do with the bootstd uclass. Should be
UCLASS_TPM (or LOGC_NONE). Likely applies to other files in this
series too.
> diff --git a/cmd/wolftpm.c b/cmd/wolftpm.c
> @@ -0,0 +1,1170 @@
> + /* 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));
> + }
> + }
Both branches do the same thing - continue is meant to be incremental,
not full. The native backend passes TPMI_YES/TPMI_NO to
tpm2_self_test() to distinguish. Please call the appropriate wolfTPM
API for the incremental case, or collapse the branches and document
that there's no difference.
> diff --git a/cmd/wolftpm.c b/cmd/wolftpm.c
> @@ -0,0 +1,1170 @@
> + 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;
Most wolfTPM handlers return the raw TPM2 return code directly to the
shell. The native backend funnels everything through
report_return_code() which maps non-zero rc to CMD_RET_FAILURE and
prints a useful diagnostic. Returning a raw TPM_RC from a cmd_tbl
handler is not what the shell expects - please use
report_return_code() so the two backends behave the same from the
user's perspective.
> diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c
> @@ -511,7 +55,22 @@ struct cmd_tbl *get_tpm2_commands(unsigned int *size)
> +#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 */
The supposedly-shared frontend now contains four levels of
backend-specific #ifdef in both the table and the help text. The
shared-command-table argument for splitting the file is weaker than it
looks. Worse, the inner #if defined(WOLFTPM_SLB9672)... tests a symbol
from a wolfTPM-private header, not a Kconfig - so tpm-v2.c now needs
the wolfTPM header search path even though it otherwise has nothing to
do with wolfTPM. A Kconfig (e.g. CONFIG_TPM_WOLF_FW_UPGRADE) would be
much cleaner.
> diff --git a/cmd/wolftpm.c b/cmd/wolftpm.c
> @@ -0,0 +1,1170 @@
> +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;
The shared help text still advertises 'device [num device]' but this
implementation rejects any argument. Either implement device switching
or trim the help text when CONFIG_TPM_WOLF is set - quietly diverging
from the documented interface is worse than either.
> diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c
> @@ -521,7 +80,7 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
> '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"
> @@ -573,6 +132,10 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
> "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"
These are independent improvements - please split into their own
patches so they can be picked up even if the wolfTPM bits don't land.
> diff --git a/cmd/wolftpm.c b/cmd/wolftpm.c
> @@ -0,0 +1,1170 @@
> +#include <wolftpm/tpm2.h>
> +#include <wolftpm/tpm2_wrap.h>
> +#include <wolftpm/tpm2_packet.h>
> +#include <wolftpm.h>
> +
> +#include <stdio.h>
> +#include <hash.h>
Include ordering is also upside-down: U-Boot convention is <command.h>
and core headers first, then driver/library headers. The file also
uses camelCase locals
(doStartup/fullTest/pcrIndex/digestLen/manifest_bufSz) and
uint8_t/uint16_t/uint32_t throughout; U-Boot style is snake_case and
u8/u16/u32. Please run patman / checkpatch and adjust.
Regards,
Simon
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 12/14] test: add wolfTPM C unit tests and Python integration tests
2026-05-13 0:26 ` [PATCH v4 12/14] test: add wolfTPM C unit tests and Python integration tests Aidan Garske
@ 2026-05-15 14:15 ` Simon Glass
0 siblings, 0 replies; 30+ messages in thread
From: Simon Glass @ 2026-05-15 14:15 UTC (permalink / raw)
To: Aidan Garske
Cc: u-boot, Peter Robinson, Ilias Apalodimas, Tom Rini, David Garske,
Heinrich Schuchardt, Bin Meng, Dinesh Maniyam
Hi Aidan,
On Tue, 12 May 2026 at 18:27, Aidan Garske <aidan@wolfssl.com> wrote:
>
> 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
Thank you for writing tests here. For the cmd tests it is a good idea
to check the console output - see the UTF_CONSOLE flag and things like
ut_assert_nextline()
Regards,
Simon
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v4 03/14] spi: add BCM2835/BCM2711 hardware SPI controller driver
2026-05-15 13:07 ` Simon Glass
@ 2026-05-15 15:13 ` Peter Robinson
0 siblings, 0 replies; 30+ messages in thread
From: Peter Robinson @ 2026-05-15 15:13 UTC (permalink / raw)
To: Simon Glass
Cc: aidan, u-boot, Ilias Apalodimas, Tom Rini, David Garske,
Jagan Teki, Sean Anderson, Patrick Delaunay, Tien Fong Chee,
Ralph Siemsen, Boon Khai Ng, Patrice Chotard
On Fri, 15 May 2026 at 14:07, Simon Glass <sjg@chromium.org> wrote:
>
> Hi Aidan,
>
> On 2026-05-13T00:26:04, Aidan Garske <aidan@wolfssl.com> wrote:
> > spi: add BCM2835/BCM2711 hardware SPI controller driver
> >
> > The BCM2835/BCM2711 SoC on Raspberry Pi 3/4 has no in-tree U-Boot
> > driver for its hardware SPI0 controller; existing U-Boot work with
> > SPI peripherals on these boards has to fall back to GPIO bit-banging
> > via spi-gpio. That fallback is functional but slow (a few hundred
> > kHz versus the 32 MHz the controller supports), and for protocols
> > like the Infineon SLB9670 / SLB9672 TPM 2.0 TIS interface it makes
> > early-boot operations (startup, self-test, PCR extend) noticeably
> > sluggish.
> >
> > Port the Linux kernel driver drivers/spi/spi-bcm2835.c into U-Boot
> > so existing device-tree nodes using the 'brcm,bcm2835-spi' /
> > 'brcm,bcm2711-spi' compatible work out of the box. The port keeps
> > the same register layout and software-GPIO chip-select scheme the
> > Linux driver already uses, which is necessary to work around the
> > BCM2835 SPI block's CS auto-deassert behaviour - that behaviour
> > corrupts multi-byte TPM TIS transactions when hardware CS is left
> > enabled.
> >
> > [...]
> >
> > drivers/spi/Kconfig | 9 +
> > drivers/spi/Makefile | 1 +
> > drivers/spi/bcm2835_spi.c | 440 ++++++++++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 450 insertions(+)
>
> > diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> > @@ -0,0 +1,440 @@
> > +/* 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) */
>
> The GPIO base should come from the devicetree and more generally,
> access to it should be via a GPIO driver. Please use lower-case hex.
>
> This should not be in a generic SPI controller driver, and it
> contradicts the commit message claim that the driver is not
> TPM-specific. Any board that probes this driver currently pulses GPIO4
> and GPIO24 low for 100 ms - what if something is wired to those pins?
> TPM reset belongs in the TPM driver (perhaps with a gpio-reset in the
> DT node for the TPM).
>
> > diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> > @@ -0,0 +1,440 @@
> > +/* GPIO base for software CS control */
> > +static void __iomem *g_gpio_base = (void __iomem *)0xFE200000;
>
> This is BCM2711-only, so BCM2835 (Pi 3, which the Kconfig help and
> commit subject both advertise) has its GPIO block at 0x3f200000, so
> the driver will silently corrupt unrelated memory there. Anyway,
> U-Boot already has pinctrl (pinctrl-bcm283x.c) and GPIO
> (bcm2835_gpio.c) drivers for this SoC; please go through those.
>
> > diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> > @@ -0,0 +1,440 @@
> > + /* 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;
> > + }
>
> priv->cs_gpio and priv->cs_gpio_valid are written here but never read
> - bcm2835_spi_xfer() instead does
>
> int cs_pin = (cs == 0) ? 8 : 7;
>
> and pokes GPSET0/GPCLR0 directly, ignoring the DT. Either honour
> cs-gpios via dm_gpio_set_value() (the normal U-Boot pattern, which
> DM_SPI_GPIO already handles generically), or drop the cs_gpio request
> and document that the driver hardcodes the Pi SPI0 CE0/CE1 pin
> assignment. As written it's half of each.
>
> > diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> > @@ -0,0 +1,440 @@
> > +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 */
> > +};
>
> cs_asserted is assigned in three places in xfer() but never read.
> Please remove it (and the comment that promises behaviour it does not
> implement).
>
> > diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> > @@ -0,0 +1,440 @@
> > +/* Default clock rate - 250 MHz for Pi 4 */
> > +#define BCM2835_SPI_DEFAULT_CLK 250000000
>
> This is the SPI core/source clock, not a default transfer rate - the
> default transfer speed is 1 MHz below. The name is confusing. More
> importantly, on BCM2835 vs BCM2711 vs different VPU clock settings
> this number is not constant; please pull it from the clk uclass (or
> from clock-frequency in DT, which you already read, with no hard-coded
> fallback).
>
> > diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> > @@ -0,0 +1,440 @@
> > +static inline void bcm2835_spi_writel(struct bcm2835_spi_priv *priv,
> > + u32 reg, u32 val)
> > +{
> > + writel(val, priv->regs + reg);
> > +}
>
> Please check indent for tab-alignment. Patman or checkpatch will flag these.
>
> > diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> > @@ -0,0 +1,440 @@
> > + /* Poll for completion - transfer byte by byte */
> > + timeout = 100000;
> > + while ((tx_count < len || rx_count < len) && timeout > 0) {
>
> The 100000 and 10000 timeouts are bare loop counters, not time bounds
> so at 1 MHz a 4 KB transfer takes ~32 ms and the loop body has no
> fixed cost, so these mean nothing except 'don't hang forever'. Please
> convert to get_timer() / timer_get_us(), the way other DM_SPI drivers
> do, so the timeout is independent of CPU speed and transfer length.
>
> > diff --git a/drivers/spi/bcm2835_spi.c b/drivers/spi/bcm2835_spi.c
> > @@ -0,0 +1,440 @@
> > +config BCM2835_SPI
> > + bool "BCM2835/BCM2711 SPI driver"
> > + depends on ARCH_BCM283X
>
> Given the hard-coded 0xfe200000 GPIO base and the BCM2711-only fix-up
> in of_to_plat(), the BCM2835 half of this option is not actually
> supported. Either fix the driver to derive the GPIO base from DT /
> from the existing bcm2835_gpio driver and exercise it on a Pi 3, or
> narrow the Kconfig text and commit subject to say BCM2711 only.
This needs to support all, if it's an option people will try to use it
and get a bad experience.
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2026-05-15 15:13 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-13 0:26 [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske
2026-05-13 0:26 ` [PATCH v4 01/14] tpm: export tpm_show_device, tpm_set_device, and get_tpm Aidan Garske
2026-05-15 13:06 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 02/14] include/hash: add SHA384 hash wrapper declaration for wolfTPM Aidan Garske
2026-05-13 0:26 ` [PATCH v4 03/14] spi: add BCM2835/BCM2711 hardware SPI controller driver Aidan Garske
2026-05-15 13:07 ` Simon Glass
2026-05-15 15:13 ` Peter Robinson
2026-05-13 0:26 ` [PATCH v4 04/14] arm: dts: bcm2711-rpi-4-b: add Infineon SLB9670/9672 TPM in U-Boot dtsi Aidan Garske
2026-05-15 13:08 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 05/14] arm: dts: qemu-arm64: add TPM TIS MMIO node Aidan Garske
2026-05-15 13:09 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 06/14] sandbox: dts: add TPM SPI emulator node Aidan Garske
2026-05-15 13:11 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 07/14] tpm: add wolfTPM build rules and Kconfig Aidan Garske
2026-05-13 0:26 ` [PATCH v4 08/14] tpm: add wolfTPM headers and SHA384 glue code Aidan Garske
2026-05-13 0:26 ` [PATCH v4 09/14] tpm: add wolfTPM driver helpers and Kconfig options Aidan Garske
2026-05-13 0:26 ` [PATCH v4 10/14] cmd: refactor tpm2 command into frontend/backend architecture Aidan Garske
2026-05-15 14:11 ` Simon Glass
2026-05-15 14:15 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 11/14] tpm: add sandbox TPM SPI emulator Aidan Garske
2026-05-15 13:24 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 12/14] test: add wolfTPM C unit tests and Python integration tests Aidan Garske
2026-05-15 14:15 ` Simon Glass
2026-05-13 0:26 ` [PATCH v4 13/14] doc: add wolfTPM documentation Aidan Garske
2026-05-13 0:26 ` [PATCH v4 14/14] configs: add rpi_4_wolftpm_defconfig Aidan Garske
2026-05-15 11:31 ` Matthias Brugger
2026-05-13 6:35 ` [PATCH v4 00/14] tpm: Add wolfTPM library support for TPM 2.0 Ilias Apalodimas
2026-05-13 14:34 ` Tom Rini
2026-05-13 16:04 ` Aidan Garske
2026-05-13 16:36 ` Peter Robinson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox