* [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0
@ 2026-05-09 0:04 Aidan Garske
2026-05-09 0:04 ` [PATCH v3 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm Aidan Garske
` (12 more replies)
0 siblings, 13 replies; 18+ messages in thread
From: Aidan Garske @ 2026-05-09 0:04 UTC (permalink / raw)
To: u-boot; +Cc: David Garske, Ilias Apalodimas
Hi all,
This is v3 of the wolfTPM TPM 2.0 stack integration for U-Boot.
wolfTPM (https://github.com/wolfSSL/wolfTPM) is a portable, GPLv2 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 backend behind the existing
'tpm2' command, alongside support for QEMU+swtpm, sandbox emulation, and
real Raspberry Pi 4 + Infineon SLB9672 hardware.
Branch (full 14-commit history including the subtree squash + merge):
https://github.com/aidangarske/u-boot wolftpm-v2-patches
Note on the subtree commits omitted from this email thread:
The branch above contains 14 commits; the email series is 12 patches.
Two commits are deliberately not sent to the list:
* "Squashed 'lib/wolftpm/' content from commit 664db130d57"
- the parentless squash commit produced by `git subtree add`.
Its diff is ~3.4MB / ~90k lines and would be rejected by the
mailing list on size.
* "Merge commit 'd42fd7b146...' as 'lib/wolftpm'"
- the corresponding subtree merge commit. Merges have no patch
form and are routinely omitted by `git format-patch`.
Please pull from the branch above (or wolfssl/wolfTPM @ 664db130d57)
to inspect the imported wolfTPM source. Subsequent updates will go
via tools/update-subtree.sh, matching how mbedTLS, lwIP, and
dts/upstream are maintained in tree.
Changes since v2:
- Replaced the lib/wolftpm git submodule with a git subtree import
(squash + merge), matching the convention used for mbedTLS, lwIP,
and dts/upstream. tools/update-subtree.sh is updated to know
about the wolftpm subtree (path lib/wolftpm, upstream
https://github.com/wolfssl/wolfTPM.git).
[feedback: Ilias Apalodimas]
- Reverted the changes to include/linux/byteorder/generic.h. The
redefinition workaround for cpu_to_beXX / beXX_to_cpu now lives
on the wolfTPM side: include/configs/user_settings.h pulls in
<asm/byteorder.h> up front so U-Boot's macros are defined before
wolfTPM's #ifndef-guarded fallbacks in tpm2_packet.h.
[feedback: Ilias Apalodimas]
Testing:
- QEMU arm64 + swtpm Python test framework
(./test/py/test.py --bd qemu_arm64 -k "test_wolftpm and not ut_cmd"):
19 passed, 2 skipped (matching doc/usage/cmd/wolftpm.rst).
- Manual QEMU arm64 + swtpm walkthrough per
doc/usage/cmd/wolftpm.rst section "Building and Running wolfTPM
with U-Boot using QEMU": tpm2 help/info/autostart/startup/
get_capability/pcr_read/pcr_print/caps all return expected output.
- Raspberry Pi 4 + Infineon SLB9672 (real hardware): all wolfTPM
cmd tests pass, including firmware update path.
v2 thread:
https://lore.kernel.org/u-boot/?q=PATCH+v2+tpm+wolfTPM
Aidan Garske (12):
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
dts: add TPM device tree nodes for RPi4, QEMU, and sandbox
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: enable wolfTPM in rpi_4_defconfig
--
2.47.3
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v3 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm 2026-05-09 0:04 [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske @ 2026-05-09 0:04 ` Aidan Garske 2026-05-09 0:04 ` [PATCH v3 02/12] include/hash: add SHA384 hash wrapper declaration for wolfTPM Aidan Garske ` (11 subsequent siblings) 12 siblings, 0 replies; 18+ messages in thread From: Aidan Garske @ 2026-05-09 0:04 UTC (permalink / raw) To: u-boot; +Cc: David Garske, Ilias Apalodimas 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.47.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 02/12] include/hash: add SHA384 hash wrapper declaration for wolfTPM 2026-05-09 0:04 [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske 2026-05-09 0:04 ` [PATCH v3 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm Aidan Garske @ 2026-05-09 0:04 ` Aidan Garske 2026-05-09 0:04 ` [PATCH v3 03/12] spi: add BCM2835/BCM2711 hardware SPI controller driver Aidan Garske ` (10 subsequent siblings) 12 siblings, 0 replies; 18+ messages in thread From: Aidan Garske @ 2026-05-09 0:04 UTC (permalink / raw) To: u-boot; +Cc: David Garske, Ilias Apalodimas 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.47.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 03/12] spi: add BCM2835/BCM2711 hardware SPI controller driver 2026-05-09 0:04 [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske 2026-05-09 0:04 ` [PATCH v3 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm Aidan Garske 2026-05-09 0:04 ` [PATCH v3 02/12] include/hash: add SHA384 hash wrapper declaration for wolfTPM Aidan Garske @ 2026-05-09 0:04 ` Aidan Garske 2026-05-11 8:50 ` Peter Robinson 2026-05-09 0:04 ` [PATCH v3 04/12] dts: add TPM device tree nodes for RPi4, QEMU, and sandbox Aidan Garske ` (9 subsequent siblings) 12 siblings, 1 reply; 18+ messages in thread From: Aidan Garske @ 2026-05-09 0:04 UTC (permalink / raw) To: u-boot; +Cc: David Garske, Ilias Apalodimas From: Aidan <aidan@wolfssl.com> Add a hardware SPI controller driver for the BCM2835/BCM2711 SoC found on Raspberry Pi 3 and Pi 4 boards. The driver implements: - Register-based SPI transfers using the BCM2835 SPI0 peripheral - Software GPIO chip-select control (matching the Linux driver approach) rather than hardware CS, which avoids issues with automatic CS deassertion during multi-byte TPM TIS transactions - Clock divider calculation for configurable SPI speed - SPI mode 0/1/2/3 support via CPOL/CPHA configuration - GPIO pin setup for SPI0 (MISO/MOSI/SCLK as ALT0, CE0/CE1 as output for software CS) - TPM reset via GPIO4/GPIO24 during probe This driver is needed for wolfTPM to communicate with SPI-attached TPM chips (e.g., Infineon SLB9670/9672) on Raspberry Pi hardware. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- drivers/spi/Kconfig | 9 + drivers/spi/Makefile | 1 + drivers/spi/bcm2835_spi.c | 431 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 441 insertions(+) create mode 100644 drivers/spi/bcm2835_spi.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 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..8133a41a0f8 --- /dev/null +++ b/drivers/spi/bcm2835_spi.c @@ -0,0 +1,431 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * BCM2835/BCM2711 SPI controller driver for U-Boot + * + * Copyright (C) 2025 wolfSSL Inc. + * Author: Aidan Garske <aidan@wolfssl.com> + * + * Based on Linux driver by Chris Boot, Martin Sperl, et al. + */ + +#include <dm.h> +#include <errno.h> +#include <log.h> +#include <malloc.h> +#include <spi.h> +#include <asm/io.h> +#include <asm/gpio.h> +#include <dm/device_compat.h> +#include <linux/delay.h> + +/* SPI register offsets */ +#define BCM2835_SPI_CS 0x00 /* Control and Status */ +#define BCM2835_SPI_FIFO 0x04 /* TX and RX FIFOs */ +#define BCM2835_SPI_CLK 0x08 /* Clock Divider */ +#define BCM2835_SPI_DLEN 0x0c /* Data Length */ +#define BCM2835_SPI_LTOH 0x10 /* LoSSI mode TOH */ +#define BCM2835_SPI_DC 0x14 /* DMA DREQ Controls */ + +/* CS register bits */ +#define BCM2835_SPI_CS_LEN_LONG BIT(25) +#define BCM2835_SPI_CS_DMA_LEN BIT(24) +#define BCM2835_SPI_CS_CSPOL2 BIT(23) +#define BCM2835_SPI_CS_CSPOL1 BIT(22) +#define BCM2835_SPI_CS_CSPOL0 BIT(21) +#define BCM2835_SPI_CS_RXF BIT(20) +#define BCM2835_SPI_CS_RXR BIT(19) +#define BCM2835_SPI_CS_TXD BIT(18) +#define BCM2835_SPI_CS_RXD BIT(17) +#define BCM2835_SPI_CS_DONE BIT(16) +#define BCM2835_SPI_CS_LEN BIT(13) +#define BCM2835_SPI_CS_REN BIT(12) +#define BCM2835_SPI_CS_ADCS BIT(11) +#define BCM2835_SPI_CS_INTR BIT(10) +#define BCM2835_SPI_CS_INTD BIT(9) +#define BCM2835_SPI_CS_DMAEN BIT(8) +#define BCM2835_SPI_CS_TA BIT(7) +#define BCM2835_SPI_CS_CSPOL BIT(6) +#define BCM2835_SPI_CS_CLEAR_RX BIT(5) +#define BCM2835_SPI_CS_CLEAR_TX BIT(4) +#define BCM2835_SPI_CS_CPOL BIT(3) +#define BCM2835_SPI_CS_CPHA BIT(2) +#define BCM2835_SPI_CS_CS_10 BIT(1) +#define BCM2835_SPI_CS_CS_01 BIT(0) + +/* Default clock rate - 250 MHz for Pi 4 */ +#define BCM2835_SPI_DEFAULT_CLK 250000000 + +struct bcm2835_spi_priv { + void __iomem *regs; + u32 clk_hz; + u32 cs_reg; /* Cached CS register value */ + u32 speed_hz; + u8 mode; + struct gpio_desc cs_gpio; + int cs_gpio_valid; + int cs_asserted; /* Track if CS should stay asserted between transfers */ +}; + +struct bcm2835_spi_plat { + fdt_addr_t base; + u32 clk_hz; +}; + +static inline u32 bcm2835_spi_readl(struct bcm2835_spi_priv *priv, u32 reg) +{ + return readl(priv->regs + reg); +} + +static inline void bcm2835_spi_writel(struct bcm2835_spi_priv *priv, + u32 reg, u32 val) +{ + writel(val, priv->regs + reg); +} + +static void bcm2835_spi_reset(struct bcm2835_spi_priv *priv) +{ + /* Clear FIFOs and disable SPI */ + bcm2835_spi_writel(priv, BCM2835_SPI_CS, + BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); +} + +/* GPIO base for software CS control */ +static void __iomem *g_gpio_base = (void __iomem *)0xFE200000; + +/* Software CS control - assert (LOW = active) */ +static void bcm2835_spi_cs_assert(int cs_pin) +{ + /* GPCLR0 - clear pin (drive LOW) */ + writel(1 << cs_pin, g_gpio_base + 0x28); +} + +/* Software CS control - deassert (HIGH = inactive) */ +static void bcm2835_spi_cs_deassert(int cs_pin) +{ + /* GPSET0 - set pin (drive HIGH) */ + writel(1 << cs_pin, g_gpio_base + 0x1C); +} + +static int bcm2835_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev_get_parent(dev); + struct bcm2835_spi_priv *priv = dev_get_priv(bus); + const u8 *tx = dout; + u8 *rx = din; + u32 len = bitlen / 8; + u32 cs_reg; + u32 tx_count = 0, rx_count = 0; + int timeout; + int cs = spi_chip_select(dev); /* Get chip select from slave device */ + int cs_pin = (cs == 0) ? 8 : 7; /* CS0=GPIO8, CS1=GPIO7 */ + u32 stat; + + if (bitlen == 0) { + /* Handle CS-only operations (deassert) */ + if (flags & SPI_XFER_END) { + bcm2835_spi_cs_deassert(cs_pin); + priv->cs_asserted = 0; + } + return 0; + } + + if (bitlen % 8) { + dev_err(dev, "Non-byte-aligned transfer not supported\n"); + return -EINVAL; + } + + /* + * SOFTWARE GPIO CHIP SELECT - like Linux driver + * Don't use hardware CS bits - set to 0 (unused) + */ + cs_reg = priv->cs_reg & ~(BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01); + + /* Assert CS at start of transaction (SPI_XFER_BEGIN) */ + if (flags & SPI_XFER_BEGIN) { + bcm2835_spi_cs_assert(cs_pin); + priv->cs_asserted = 1; + udelay(1); /* CS setup time */ + } + + /* Clear FIFOs for new transaction */ + if (flags & SPI_XFER_BEGIN) { + bcm2835_spi_writel(priv, BCM2835_SPI_CS, + cs_reg | BCM2835_SPI_CS_CLEAR_RX | + BCM2835_SPI_CS_CLEAR_TX); + udelay(1); + } + + /* Start transfer with TA=1 (but CS is controlled by GPIO, not hardware) */ + bcm2835_spi_writel(priv, BCM2835_SPI_CS, cs_reg | BCM2835_SPI_CS_TA); + + /* Poll for completion - transfer byte by byte */ + timeout = 100000; + while ((tx_count < len || rx_count < len) && timeout > 0) { + stat = bcm2835_spi_readl(priv, BCM2835_SPI_CS); + + /* TX FIFO not full - send next byte */ + while ((stat & BCM2835_SPI_CS_TXD) && tx_count < len) { + u8 byte = tx ? tx[tx_count] : 0; + + bcm2835_spi_writel(priv, BCM2835_SPI_FIFO, byte); + tx_count++; + stat = bcm2835_spi_readl(priv, BCM2835_SPI_CS); + } + + /* RX FIFO has data - read it */ + while ((stat & BCM2835_SPI_CS_RXD) && rx_count < len) { + u8 byte = bcm2835_spi_readl(priv, BCM2835_SPI_FIFO) & 0xff; + + if (rx) + rx[rx_count] = byte; + rx_count++; + stat = bcm2835_spi_readl(priv, BCM2835_SPI_CS); + } + + timeout--; + } + + /* Wait for DONE */ + timeout = 10000; + while (!(bcm2835_spi_readl(priv, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE) && + timeout > 0) { + udelay(1); + timeout--; + } + + /* Read any remaining RX data from FIFO */ + while (bcm2835_spi_readl(priv, BCM2835_SPI_CS) & BCM2835_SPI_CS_RXD) { + u8 byte = bcm2835_spi_readl(priv, BCM2835_SPI_FIFO) & 0xff; + + if (rx && rx_count < len) + rx[rx_count++] = byte; + } + + /* Clear TA to complete this transfer (doesn't affect GPIO CS) */ + bcm2835_spi_writel(priv, BCM2835_SPI_CS, cs_reg); + + /* + * SOFTWARE GPIO CHIP SELECT control: + * - SPI_XFER_END: deassert CS (GPIO HIGH) + * - No END flag: keep CS asserted for next transfer + */ + if (flags & SPI_XFER_END) { + bcm2835_spi_cs_deassert(cs_pin); + priv->cs_asserted = 0; + } else { + /* Keep CS asserted for next transfer (e.g., wait state polling) */ + priv->cs_asserted = 1; + } + + if (timeout == 0) { + bcm2835_spi_cs_deassert(cs_pin); /* Make sure CS is released */ + return -ETIMEDOUT; + } + + return 0; +} + +static int bcm2835_spi_set_speed(struct udevice *bus, uint speed) +{ + struct bcm2835_spi_priv *priv = dev_get_priv(bus); + u32 cdiv; + + if (speed == 0) + speed = 1000000; /* Default 1 MHz */ + + priv->speed_hz = speed; + + /* Calculate clock divider */ + if (speed >= priv->clk_hz / 2) { + cdiv = 2; /* Fastest possible */ + } else { + cdiv = (priv->clk_hz + speed - 1) / speed; + cdiv += (cdiv & 1); /* Must be even */ + if (cdiv >= 65536) + cdiv = 0; /* Slowest: clk/65536 */ + } + + bcm2835_spi_writel(priv, BCM2835_SPI_CLK, cdiv); + + return 0; +} + +static int bcm2835_spi_set_mode(struct udevice *bus, uint mode) +{ + struct bcm2835_spi_priv *priv = dev_get_priv(bus); + u32 cs_reg = 0; + + priv->mode = mode; + + /* Set clock polarity and phase */ + if (mode & SPI_CPOL) + cs_reg |= BCM2835_SPI_CS_CPOL; + if (mode & SPI_CPHA) + cs_reg |= BCM2835_SPI_CS_CPHA; + + /* CS bits will be set in xfer based on slave's chip select */ + priv->cs_reg = cs_reg; + + return 0; +} + +static int bcm2835_spi_claim_bus(struct udevice *dev) +{ + return 0; +} + +static int bcm2835_spi_release_bus(struct udevice *dev) +{ + return 0; +} + +/* Setup GPIO pins for SPI0 with SOFTWARE chip select */ +static void bcm2835_spi_setup_gpio(void) +{ + u32 val; + + /* + * SPI0 pin configuration: + * GPIO7 (CE1) - OUTPUT (software CS) - GPFSEL0 bits 23:21 = 001 + * GPIO8 (CE0) - OUTPUT (software CS) - GPFSEL0 bits 26:24 = 001 + * GPIO9 (MISO) - ALT0 (SPI) - GPFSEL0 bits 29:27 = 100 + * GPIO10 (MOSI) - ALT0 (SPI) - GPFSEL1 bits 2:0 = 100 + * GPIO11 (SCLK) - ALT0 (SPI) - GPFSEL1 bits 5:3 = 100 + */ + + /* Set GPIO7, GPIO8 to OUTPUT, GPIO9 to ALT0 in GPFSEL0 */ + val = readl(g_gpio_base + 0x00); + val &= ~((7 << 21) | (7 << 24) | (7 << 27)); /* Clear GPIO7,8,9 */ + val |= (1 << 21); /* GPIO7 = OUTPUT (001) */ + val |= (1 << 24); /* GPIO8 = OUTPUT (001) */ + val |= (4 << 27); /* GPIO9 = ALT0 (100) for MISO */ + writel(val, g_gpio_base + 0x00); + + /* Set GPIO10, GPIO11 to ALT0 in GPFSEL1 */ + val = readl(g_gpio_base + 0x04); + val &= ~((7 << 0) | (7 << 3)); /* Clear GPIO10,11 */ + val |= (4 << 0); /* GPIO10 = ALT0 (100) for MOSI */ + val |= (4 << 3); /* GPIO11 = ALT0 (100) for SCLK */ + writel(val, g_gpio_base + 0x04); + + /* Deassert both CS lines (HIGH = inactive) */ + bcm2835_spi_cs_deassert(7); /* CE1 */ + bcm2835_spi_cs_deassert(8); /* CE0 */ +} + +/* TPM Reset via GPIO4 and GPIO24 */ +static void bcm2835_spi_tpm_reset(void) +{ + void __iomem *gpio_base = (void __iomem *)0xFE200000; + u32 val; + + /* Set GPIO4 as output (GPFSEL0, bits 14:12) */ + val = readl(gpio_base + 0x00); /* GPFSEL0 */ + val &= ~(7 << 12); /* Clear bits 14:12 for GPIO4 */ + val |= (1 << 12); /* Set to output */ + writel(val, gpio_base + 0x00); + + /* Set GPIO24 as output (GPFSEL2, bits 14:12) */ + val = readl(gpio_base + 0x08); /* GPFSEL2 */ + val &= ~(7 << 12); /* Clear bits 14:12 for GPIO24 */ + val |= (1 << 12); /* Set to output */ + writel(val, gpio_base + 0x08); + + /* Assert reset on BOTH pins (LOW) */ + writel((1 << 4) | (1 << 24), gpio_base + 0x28); /* GPCLR0 */ + mdelay(100); + + /* Release reset on BOTH pins (HIGH) */ + writel((1 << 4) | (1 << 24), gpio_base + 0x1C); /* GPSET0 */ + mdelay(150); /* Wait for TPM to initialize */ +} + +static int bcm2835_spi_probe(struct udevice *bus) +{ + struct bcm2835_spi_plat *plat = dev_get_plat(bus); + struct bcm2835_spi_priv *priv = dev_get_priv(bus); + int ret; + + priv->regs = (void __iomem *)plat->base; + priv->clk_hz = plat->clk_hz ? plat->clk_hz : BCM2835_SPI_DEFAULT_CLK; + + /* Setup GPIO pins for SPI0 (ALT0 function) */ + bcm2835_spi_setup_gpio(); + + /* Reset TPM before using SPI */ + bcm2835_spi_tpm_reset(); + + /* Try to get CS GPIO from device tree */ + ret = gpio_request_by_name(bus, "cs-gpios", 0, &priv->cs_gpio, + GPIOD_IS_OUT | GPIOD_ACTIVE_LOW); + if (!ret) { + priv->cs_gpio_valid = 1; + /* Deassert CS initially */ + dm_gpio_set_value(&priv->cs_gpio, 1); + } else { + priv->cs_gpio_valid = 0; + } + + /* Reset the SPI controller */ + bcm2835_spi_reset(priv); + + /* Set default speed and mode */ + bcm2835_spi_set_speed(bus, 1000000); /* 1 MHz default */ + bcm2835_spi_set_mode(bus, SPI_MODE_0); + + return 0; +} + +static int bcm2835_spi_of_to_plat(struct udevice *bus) +{ + struct bcm2835_spi_plat *plat = dev_get_plat(bus); + fdt_addr_t addr; + + addr = dev_read_addr(bus); + if (addr == FDT_ADDR_T_NONE) { + dev_err(bus, "Failed to get SPI base address\n"); + return -EINVAL; + } + + /* + * On BCM2711 (Pi 4), the device tree often uses VideoCore bus addresses + * which start with 0x7E. The ARM needs to access these via the ARM + * peripheral base at 0xFE000000. + */ + if ((addr & 0xFF000000) == 0x7E000000) + addr = (addr & 0x00FFFFFF) | 0xFE000000; + + plat->base = addr; + + /* Try to get clock rate from device tree */ + plat->clk_hz = dev_read_u32_default(bus, "clock-frequency", + BCM2835_SPI_DEFAULT_CLK); + + return 0; +} + +static const struct dm_spi_ops bcm2835_spi_ops = { + .claim_bus = bcm2835_spi_claim_bus, + .release_bus = bcm2835_spi_release_bus, + .xfer = bcm2835_spi_xfer, + .set_speed = bcm2835_spi_set_speed, + .set_mode = bcm2835_spi_set_mode, +}; + +static const struct udevice_id bcm2835_spi_ids[] = { + { .compatible = "brcm,bcm2835-spi" }, + { .compatible = "brcm,bcm2711-spi" }, + { } +}; + +U_BOOT_DRIVER(bcm2835_spi) = { + .name = "bcm2835_spi", + .id = UCLASS_SPI, + .of_match = bcm2835_spi_ids, + .ops = &bcm2835_spi_ops, + .of_to_plat = bcm2835_spi_of_to_plat, + .plat_auto = sizeof(struct bcm2835_spi_plat), + .priv_auto = sizeof(struct bcm2835_spi_priv), + .probe = bcm2835_spi_probe, +}; -- 2.47.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v3 03/12] spi: add BCM2835/BCM2711 hardware SPI controller driver 2026-05-09 0:04 ` [PATCH v3 03/12] spi: add BCM2835/BCM2711 hardware SPI controller driver Aidan Garske @ 2026-05-11 8:50 ` Peter Robinson 0 siblings, 0 replies; 18+ messages in thread From: Peter Robinson @ 2026-05-11 8:50 UTC (permalink / raw) To: Aidan Garske; +Cc: u-boot, David Garske, Ilias Apalodimas On Sat, 9 May 2026 at 01:57, Aidan Garske <aidan@wolfssl.com> wrote: > > From: Aidan <aidan@wolfssl.com> > > Add a hardware SPI controller driver for the BCM2835/BCM2711 SoC > found on Raspberry Pi 3 and Pi 4 boards. > > The driver implements: > - Register-based SPI transfers using the BCM2835 SPI0 peripheral > - Software GPIO chip-select control (matching the Linux driver > approach) rather than hardware CS, which avoids issues with > automatic CS deassertion during multi-byte TPM TIS transactions > - Clock divider calculation for configurable SPI speed > - SPI mode 0/1/2/3 support via CPOL/CPHA configuration > - GPIO pin setup for SPI0 (MISO/MOSI/SCLK as ALT0, CE0/CE1 as > output for software CS) > - TPM reset via GPIO4/GPIO24 during probe > > This driver is needed for wolfTPM to communicate with SPI-attached > TPM chips (e.g., Infineon SLB9670/9672) on Raspberry Pi hardware. > > Signed-off-by: Aidan Garske <aidan@wolfssl.com> > --- > drivers/spi/Kconfig | 9 + > drivers/spi/Makefile | 1 + > drivers/spi/bcm2835_spi.c | 431 ++++++++++++++++++++++++++++++++++++++ > 3 files changed, 441 insertions(+) > create mode 100644 drivers/spi/bcm2835_spi.c > > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig > index 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..8133a41a0f8 > --- /dev/null > +++ b/drivers/spi/bcm2835_spi.c > @@ -0,0 +1,431 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * BCM2835/BCM2711 SPI controller driver for U-Boot > + * > + * Copyright (C) 2025 wolfSSL Inc. > + * Author: Aidan Garske <aidan@wolfssl.com> I'm by no means a copyright expert but does wolfSSL own the copyright if it's derived directly from the Linux driver? > + * Based on Linux driver by Chris Boot, Martin Sperl, et al. > + */ > + > +#include <dm.h> > +#include <errno.h> > +#include <log.h> > +#include <malloc.h> > +#include <spi.h> > +#include <asm/io.h> > +#include <asm/gpio.h> > +#include <dm/device_compat.h> > +#include <linux/delay.h> > + > +/* SPI register offsets */ > +#define BCM2835_SPI_CS 0x00 /* Control and Status */ > +#define BCM2835_SPI_FIFO 0x04 /* TX and RX FIFOs */ > +#define BCM2835_SPI_CLK 0x08 /* Clock Divider */ > +#define BCM2835_SPI_DLEN 0x0c /* Data Length */ > +#define BCM2835_SPI_LTOH 0x10 /* LoSSI mode TOH */ > +#define BCM2835_SPI_DC 0x14 /* DMA DREQ Controls */ > + > +/* CS register bits */ > +#define BCM2835_SPI_CS_LEN_LONG BIT(25) > +#define BCM2835_SPI_CS_DMA_LEN BIT(24) > +#define BCM2835_SPI_CS_CSPOL2 BIT(23) > +#define BCM2835_SPI_CS_CSPOL1 BIT(22) > +#define BCM2835_SPI_CS_CSPOL0 BIT(21) > +#define BCM2835_SPI_CS_RXF BIT(20) > +#define BCM2835_SPI_CS_RXR BIT(19) > +#define BCM2835_SPI_CS_TXD BIT(18) > +#define BCM2835_SPI_CS_RXD BIT(17) > +#define BCM2835_SPI_CS_DONE BIT(16) > +#define BCM2835_SPI_CS_LEN BIT(13) > +#define BCM2835_SPI_CS_REN BIT(12) > +#define BCM2835_SPI_CS_ADCS BIT(11) > +#define BCM2835_SPI_CS_INTR BIT(10) > +#define BCM2835_SPI_CS_INTD BIT(9) > +#define BCM2835_SPI_CS_DMAEN BIT(8) > +#define BCM2835_SPI_CS_TA BIT(7) > +#define BCM2835_SPI_CS_CSPOL BIT(6) > +#define BCM2835_SPI_CS_CLEAR_RX BIT(5) > +#define BCM2835_SPI_CS_CLEAR_TX BIT(4) > +#define BCM2835_SPI_CS_CPOL BIT(3) > +#define BCM2835_SPI_CS_CPHA BIT(2) > +#define BCM2835_SPI_CS_CS_10 BIT(1) > +#define BCM2835_SPI_CS_CS_01 BIT(0) > + > +/* Default clock rate - 250 MHz for Pi 4 */ > +#define BCM2835_SPI_DEFAULT_CLK 250000000 > + > +struct bcm2835_spi_priv { > + void __iomem *regs; > + u32 clk_hz; > + u32 cs_reg; /* Cached CS register value */ > + u32 speed_hz; > + u8 mode; > + struct gpio_desc cs_gpio; > + int cs_gpio_valid; > + int cs_asserted; /* Track if CS should stay asserted between transfers */ > +}; > + > +struct bcm2835_spi_plat { > + fdt_addr_t base; > + u32 clk_hz; > +}; > + > +static inline u32 bcm2835_spi_readl(struct bcm2835_spi_priv *priv, u32 reg) > +{ > + return readl(priv->regs + reg); > +} > + > +static inline void bcm2835_spi_writel(struct bcm2835_spi_priv *priv, > + u32 reg, u32 val) > +{ > + writel(val, priv->regs + reg); > +} > + > +static void bcm2835_spi_reset(struct bcm2835_spi_priv *priv) > +{ > + /* Clear FIFOs and disable SPI */ > + bcm2835_spi_writel(priv, BCM2835_SPI_CS, > + BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); > +} > + > +/* GPIO base for software CS control */ > +static void __iomem *g_gpio_base = (void __iomem *)0xFE200000; > + > +/* Software CS control - assert (LOW = active) */ > +static void bcm2835_spi_cs_assert(int cs_pin) > +{ > + /* GPCLR0 - clear pin (drive LOW) */ > + writel(1 << cs_pin, g_gpio_base + 0x28); > +} > + > +/* Software CS control - deassert (HIGH = inactive) */ > +static void bcm2835_spi_cs_deassert(int cs_pin) > +{ > + /* GPSET0 - set pin (drive HIGH) */ > + writel(1 << cs_pin, g_gpio_base + 0x1C); > +} > + > +static int bcm2835_spi_xfer(struct udevice *dev, unsigned int bitlen, > + const void *dout, void *din, unsigned long flags) > +{ > + struct udevice *bus = dev_get_parent(dev); > + struct bcm2835_spi_priv *priv = dev_get_priv(bus); > + const u8 *tx = dout; > + u8 *rx = din; > + u32 len = bitlen / 8; > + u32 cs_reg; > + u32 tx_count = 0, rx_count = 0; > + int timeout; > + int cs = spi_chip_select(dev); /* Get chip select from slave device */ > + int cs_pin = (cs == 0) ? 8 : 7; /* CS0=GPIO8, CS1=GPIO7 */ > + u32 stat; > + > + if (bitlen == 0) { > + /* Handle CS-only operations (deassert) */ > + if (flags & SPI_XFER_END) { > + bcm2835_spi_cs_deassert(cs_pin); > + priv->cs_asserted = 0; > + } > + return 0; > + } > + > + if (bitlen % 8) { > + dev_err(dev, "Non-byte-aligned transfer not supported\n"); > + return -EINVAL; > + } > + > + /* > + * SOFTWARE GPIO CHIP SELECT - like Linux driver > + * Don't use hardware CS bits - set to 0 (unused) > + */ > + cs_reg = priv->cs_reg & ~(BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01); > + > + /* Assert CS at start of transaction (SPI_XFER_BEGIN) */ > + if (flags & SPI_XFER_BEGIN) { > + bcm2835_spi_cs_assert(cs_pin); > + priv->cs_asserted = 1; > + udelay(1); /* CS setup time */ > + } > + > + /* Clear FIFOs for new transaction */ > + if (flags & SPI_XFER_BEGIN) { > + bcm2835_spi_writel(priv, BCM2835_SPI_CS, > + cs_reg | BCM2835_SPI_CS_CLEAR_RX | > + BCM2835_SPI_CS_CLEAR_TX); > + udelay(1); > + } > + > + /* Start transfer with TA=1 (but CS is controlled by GPIO, not hardware) */ > + bcm2835_spi_writel(priv, BCM2835_SPI_CS, cs_reg | BCM2835_SPI_CS_TA); > + > + /* Poll for completion - transfer byte by byte */ > + timeout = 100000; > + while ((tx_count < len || rx_count < len) && timeout > 0) { > + stat = bcm2835_spi_readl(priv, BCM2835_SPI_CS); > + > + /* TX FIFO not full - send next byte */ > + while ((stat & BCM2835_SPI_CS_TXD) && tx_count < len) { > + u8 byte = tx ? tx[tx_count] : 0; > + > + bcm2835_spi_writel(priv, BCM2835_SPI_FIFO, byte); > + tx_count++; > + stat = bcm2835_spi_readl(priv, BCM2835_SPI_CS); > + } > + > + /* RX FIFO has data - read it */ > + while ((stat & BCM2835_SPI_CS_RXD) && rx_count < len) { > + u8 byte = bcm2835_spi_readl(priv, BCM2835_SPI_FIFO) & 0xff; > + > + if (rx) > + rx[rx_count] = byte; > + rx_count++; > + stat = bcm2835_spi_readl(priv, BCM2835_SPI_CS); > + } > + > + timeout--; > + } > + > + /* Wait for DONE */ > + timeout = 10000; > + while (!(bcm2835_spi_readl(priv, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE) && > + timeout > 0) { > + udelay(1); > + timeout--; > + } > + > + /* Read any remaining RX data from FIFO */ > + while (bcm2835_spi_readl(priv, BCM2835_SPI_CS) & BCM2835_SPI_CS_RXD) { > + u8 byte = bcm2835_spi_readl(priv, BCM2835_SPI_FIFO) & 0xff; > + > + if (rx && rx_count < len) > + rx[rx_count++] = byte; > + } > + > + /* Clear TA to complete this transfer (doesn't affect GPIO CS) */ > + bcm2835_spi_writel(priv, BCM2835_SPI_CS, cs_reg); > + > + /* > + * SOFTWARE GPIO CHIP SELECT control: > + * - SPI_XFER_END: deassert CS (GPIO HIGH) > + * - No END flag: keep CS asserted for next transfer > + */ > + if (flags & SPI_XFER_END) { > + bcm2835_spi_cs_deassert(cs_pin); > + priv->cs_asserted = 0; > + } else { > + /* Keep CS asserted for next transfer (e.g., wait state polling) */ > + priv->cs_asserted = 1; > + } > + > + if (timeout == 0) { > + bcm2835_spi_cs_deassert(cs_pin); /* Make sure CS is released */ > + return -ETIMEDOUT; > + } > + > + return 0; > +} > + > +static int bcm2835_spi_set_speed(struct udevice *bus, uint speed) > +{ > + struct bcm2835_spi_priv *priv = dev_get_priv(bus); > + u32 cdiv; > + > + if (speed == 0) > + speed = 1000000; /* Default 1 MHz */ > + > + priv->speed_hz = speed; > + > + /* Calculate clock divider */ > + if (speed >= priv->clk_hz / 2) { > + cdiv = 2; /* Fastest possible */ > + } else { > + cdiv = (priv->clk_hz + speed - 1) / speed; > + cdiv += (cdiv & 1); /* Must be even */ > + if (cdiv >= 65536) > + cdiv = 0; /* Slowest: clk/65536 */ > + } > + > + bcm2835_spi_writel(priv, BCM2835_SPI_CLK, cdiv); > + > + return 0; > +} > + > +static int bcm2835_spi_set_mode(struct udevice *bus, uint mode) > +{ > + struct bcm2835_spi_priv *priv = dev_get_priv(bus); > + u32 cs_reg = 0; > + > + priv->mode = mode; > + > + /* Set clock polarity and phase */ > + if (mode & SPI_CPOL) > + cs_reg |= BCM2835_SPI_CS_CPOL; > + if (mode & SPI_CPHA) > + cs_reg |= BCM2835_SPI_CS_CPHA; > + > + /* CS bits will be set in xfer based on slave's chip select */ > + priv->cs_reg = cs_reg; > + > + return 0; > +} > + > +static int bcm2835_spi_claim_bus(struct udevice *dev) > +{ > + return 0; > +} > + > +static int bcm2835_spi_release_bus(struct udevice *dev) > +{ > + return 0; > +} > + > +/* Setup GPIO pins for SPI0 with SOFTWARE chip select */ > +static void bcm2835_spi_setup_gpio(void) > +{ > + u32 val; > + > + /* > + * SPI0 pin configuration: > + * GPIO7 (CE1) - OUTPUT (software CS) - GPFSEL0 bits 23:21 = 001 > + * GPIO8 (CE0) - OUTPUT (software CS) - GPFSEL0 bits 26:24 = 001 > + * GPIO9 (MISO) - ALT0 (SPI) - GPFSEL0 bits 29:27 = 100 > + * GPIO10 (MOSI) - ALT0 (SPI) - GPFSEL1 bits 2:0 = 100 > + * GPIO11 (SCLK) - ALT0 (SPI) - GPFSEL1 bits 5:3 = 100 > + */ > + > + /* Set GPIO7, GPIO8 to OUTPUT, GPIO9 to ALT0 in GPFSEL0 */ > + val = readl(g_gpio_base + 0x00); > + val &= ~((7 << 21) | (7 << 24) | (7 << 27)); /* Clear GPIO7,8,9 */ > + val |= (1 << 21); /* GPIO7 = OUTPUT (001) */ > + val |= (1 << 24); /* GPIO8 = OUTPUT (001) */ > + val |= (4 << 27); /* GPIO9 = ALT0 (100) for MISO */ > + writel(val, g_gpio_base + 0x00); > + > + /* Set GPIO10, GPIO11 to ALT0 in GPFSEL1 */ > + val = readl(g_gpio_base + 0x04); > + val &= ~((7 << 0) | (7 << 3)); /* Clear GPIO10,11 */ > + val |= (4 << 0); /* GPIO10 = ALT0 (100) for MOSI */ > + val |= (4 << 3); /* GPIO11 = ALT0 (100) for SCLK */ > + writel(val, g_gpio_base + 0x04); > + > + /* Deassert both CS lines (HIGH = inactive) */ > + bcm2835_spi_cs_deassert(7); /* CE1 */ > + bcm2835_spi_cs_deassert(8); /* CE0 */ > +} > + > +/* TPM Reset via GPIO4 and GPIO24 */ > +static void bcm2835_spi_tpm_reset(void) > +{ > + void __iomem *gpio_base = (void __iomem *)0xFE200000; > + u32 val; > + > + /* Set GPIO4 as output (GPFSEL0, bits 14:12) */ > + val = readl(gpio_base + 0x00); /* GPFSEL0 */ > + val &= ~(7 << 12); /* Clear bits 14:12 for GPIO4 */ > + val |= (1 << 12); /* Set to output */ > + writel(val, gpio_base + 0x00); > + > + /* Set GPIO24 as output (GPFSEL2, bits 14:12) */ > + val = readl(gpio_base + 0x08); /* GPFSEL2 */ > + val &= ~(7 << 12); /* Clear bits 14:12 for GPIO24 */ > + val |= (1 << 12); /* Set to output */ > + writel(val, gpio_base + 0x08); > + > + /* Assert reset on BOTH pins (LOW) */ > + writel((1 << 4) | (1 << 24), gpio_base + 0x28); /* GPCLR0 */ > + mdelay(100); > + > + /* Release reset on BOTH pins (HIGH) */ > + writel((1 << 4) | (1 << 24), gpio_base + 0x1C); /* GPSET0 */ > + mdelay(150); /* Wait for TPM to initialize */ > +} > + > +static int bcm2835_spi_probe(struct udevice *bus) > +{ > + struct bcm2835_spi_plat *plat = dev_get_plat(bus); > + struct bcm2835_spi_priv *priv = dev_get_priv(bus); > + int ret; > + > + priv->regs = (void __iomem *)plat->base; > + priv->clk_hz = plat->clk_hz ? plat->clk_hz : BCM2835_SPI_DEFAULT_CLK; > + > + /* Setup GPIO pins for SPI0 (ALT0 function) */ > + bcm2835_spi_setup_gpio(); > + > + /* Reset TPM before using SPI */ > + bcm2835_spi_tpm_reset(); > + > + /* Try to get CS GPIO from device tree */ > + ret = gpio_request_by_name(bus, "cs-gpios", 0, &priv->cs_gpio, > + GPIOD_IS_OUT | GPIOD_ACTIVE_LOW); > + if (!ret) { > + priv->cs_gpio_valid = 1; > + /* Deassert CS initially */ > + dm_gpio_set_value(&priv->cs_gpio, 1); > + } else { > + priv->cs_gpio_valid = 0; > + } > + > + /* Reset the SPI controller */ > + bcm2835_spi_reset(priv); > + > + /* Set default speed and mode */ > + bcm2835_spi_set_speed(bus, 1000000); /* 1 MHz default */ > + bcm2835_spi_set_mode(bus, SPI_MODE_0); > + > + return 0; > +} > + > +static int bcm2835_spi_of_to_plat(struct udevice *bus) > +{ > + struct bcm2835_spi_plat *plat = dev_get_plat(bus); > + fdt_addr_t addr; > + > + addr = dev_read_addr(bus); > + if (addr == FDT_ADDR_T_NONE) { > + dev_err(bus, "Failed to get SPI base address\n"); > + return -EINVAL; > + } > + > + /* > + * On BCM2711 (Pi 4), the device tree often uses VideoCore bus addresses > + * which start with 0x7E. The ARM needs to access these via the ARM > + * peripheral base at 0xFE000000. > + */ > + if ((addr & 0xFF000000) == 0x7E000000) > + addr = (addr & 0x00FFFFFF) | 0xFE000000; > + > + plat->base = addr; > + > + /* Try to get clock rate from device tree */ > + plat->clk_hz = dev_read_u32_default(bus, "clock-frequency", > + BCM2835_SPI_DEFAULT_CLK); > + > + return 0; > +} > + > +static const struct dm_spi_ops bcm2835_spi_ops = { > + .claim_bus = bcm2835_spi_claim_bus, > + .release_bus = bcm2835_spi_release_bus, > + .xfer = bcm2835_spi_xfer, > + .set_speed = bcm2835_spi_set_speed, > + .set_mode = bcm2835_spi_set_mode, > +}; > + > +static const struct udevice_id bcm2835_spi_ids[] = { > + { .compatible = "brcm,bcm2835-spi" }, > + { .compatible = "brcm,bcm2711-spi" }, > + { } > +}; > + > +U_BOOT_DRIVER(bcm2835_spi) = { > + .name = "bcm2835_spi", > + .id = UCLASS_SPI, > + .of_match = bcm2835_spi_ids, > + .ops = &bcm2835_spi_ops, > + .of_to_plat = bcm2835_spi_of_to_plat, > + .plat_auto = sizeof(struct bcm2835_spi_plat), > + .priv_auto = sizeof(struct bcm2835_spi_priv), > + .probe = bcm2835_spi_probe, > +}; > -- > 2.47.3 > ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v3 04/12] dts: add TPM device tree nodes for RPi4, QEMU, and sandbox 2026-05-09 0:04 [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske ` (2 preceding siblings ...) 2026-05-09 0:04 ` [PATCH v3 03/12] spi: add BCM2835/BCM2711 hardware SPI controller driver Aidan Garske @ 2026-05-09 0:04 ` Aidan Garske 2026-05-11 8:26 ` Peter Robinson 2026-05-09 0:04 ` [PATCH v3 05/12] tpm: add wolfTPM build rules and Kconfig Aidan Garske ` (8 subsequent siblings) 12 siblings, 1 reply; 18+ messages in thread From: Aidan Garske @ 2026-05-09 0:04 UTC (permalink / raw) To: u-boot; +Cc: David Garske, Ilias Apalodimas From: Aidan <aidan@wolfssl.com> Add device tree entries for TPM devices across three platforms: bcm2711-rpi-4-b.dts: Add SPI0 node with Infineon SLB9670/9672 TPM on CE1 (GPIO7), matching the standard Linux tpm-slb9670 overlay. Add spi0 alias so wolfTPM finds the bus at index 0. bcm2711-rpi-4-b-u-boot.dtsi (new file): Add soft-SPI (GPIO bit-bang) fallback node for TPM communication. This uses spi-gpio with GPIO11/10/9/7 and provides an alternative to the hardware SPI driver when pinctrl naming differs between U-Boot and Linux device trees. qemu-arm64.dts: Add MMIO-based TPM TIS node at 0x0c000000 for QEMU virt machine with swtpm. This allows wolfTPM testing via QEMU without hardware. sandbox.dtsi: Add sandbox TPM SPI device (sandbox,tpm-spi) on SPI bus CS1 with a phandle reference to a sandbox TPM SPI emulator node. This enables wolfTPM SPI HAL testing in the sandbox environment. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi | 54 ++++++++++++++++++++++++ arch/arm/dts/bcm2711-rpi-4-b.dts | 20 +++++++++ arch/arm/dts/qemu-arm64.dts | 4 ++ arch/sandbox/dts/sandbox.dtsi | 11 +++++ 4 files changed, 89 insertions(+) create mode 100644 arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi diff --git a/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi b/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi new file mode 100644 index 00000000000..c38276abee9 --- /dev/null +++ b/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * U-Boot specific additions for Raspberry Pi 4 Model B + * + * Adds soft SPI support for Infineon SLB9670/9672 TPM HAT + * connected to SPI0 CE1 (GPIO 7) + * + * Uses GPIO bit-banging instead of hardware SPI to avoid + * GPIO chip naming issues (pinctrl-bcm2835 vs pinctrl-bcm2711) + */ + +#include "bcm283x-u-boot.dtsi" +#include <dt-bindings/gpio/gpio.h> + +/ { + aliases { + spi0 = &soft_spi; + }; + + soft_spi: soft-spi { + compatible = "spi-gpio"; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + bootph-all; + + /* + * GPIO pins for SPI0 on Raspberry Pi 4: + * GPIO 11 = SCLK + * GPIO 10 = MOSI + * GPIO 9 = MISO + * GPIO 7 = CE1 (chip select for TPM) + */ + gpio-sck = <&gpio 11 GPIO_ACTIVE_HIGH>; + gpio-mosi = <&gpio 10 GPIO_ACTIVE_HIGH>; + gpio-miso = <&gpio 9 GPIO_ACTIVE_HIGH>; + cs-gpios = <&gpio 7 GPIO_ACTIVE_LOW>; + num-chipselects = <1>; + spi-delay-us = <1>; + + /* Infineon SLB9672 TPM on CS1 */ + tpm@0 { + compatible = "infineon,slb9672", "tcg,tpm-tis-spi"; + reg = <0>; + spi-max-frequency = <10000000>; + status = "okay"; + bootph-all; + }; + }; +}; + +&gpio { + bootph-all; +}; diff --git a/arch/arm/dts/bcm2711-rpi-4-b.dts b/arch/arm/dts/bcm2711-rpi-4-b.dts index 72ce80fbf26..a09276dc279 100644 --- a/arch/arm/dts/bcm2711-rpi-4-b.dts +++ b/arch/arm/dts/bcm2711-rpi-4-b.dts @@ -8,6 +8,11 @@ compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; model = "Raspberry Pi 4 Model B"; + /* Alias hardware SPI as spi0 so wolfTPM finds it at bus 0 */ + aliases { + spi0 = &spi; + }; + chosen { /* 8250 auxiliary UART instead of pl011 */ stdout-path = "serial1:115200n8"; @@ -54,6 +59,21 @@ enable-active-high; gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>; }; + +}; + +/* Hardware SPI with TPM - matches Linux tpm-slb9670 overlay */ +&spi { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&spi0_gpio7>; + + /* Infineon SLB9670/9672 TPM 2.0 on CE1 (GPIO7) */ + tpm@1 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + reg = <1>; /* CE1 */ + spi-max-frequency = <32000000>; + }; }; &ddc0 { diff --git a/arch/arm/dts/qemu-arm64.dts b/arch/arm/dts/qemu-arm64.dts index 95fcf53ed74..e74d036a532 100644 --- a/arch/arm/dts/qemu-arm64.dts +++ b/arch/arm/dts/qemu-arm64.dts @@ -12,4 +12,8 @@ #endif / { + tpm@0c000000 { + compatible = "tcg,tpm-tis-mmio"; + reg = <0x0 0x0c000000 0x0 0x5000>; + }; }; diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index 02b03894eaf..2fdd7f0e942 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -286,6 +286,17 @@ spi-max-frequency = <40000000>; sandbox,filename = "spi.bin"; }; + + tpm_spi: tpm@1 { + reg = <1>; + compatible = "sandbox,tpm-spi"; + spi-max-frequency = <10000000>; + sandbox,emul = <&tpm_spi_emul>; + }; + }; + + tpm_spi_emul: tpm-spi-emul { + compatible = "sandbox,tpm-spi-emul"; }; spl-test { -- 2.47.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v3 04/12] dts: add TPM device tree nodes for RPi4, QEMU, and sandbox 2026-05-09 0:04 ` [PATCH v3 04/12] dts: add TPM device tree nodes for RPi4, QEMU, and sandbox Aidan Garske @ 2026-05-11 8:26 ` Peter Robinson 0 siblings, 0 replies; 18+ messages in thread From: Peter Robinson @ 2026-05-11 8:26 UTC (permalink / raw) To: Aidan Garske; +Cc: u-boot, David Garske, Ilias Apalodimas NAK, The below should be 4 changes for the 4 different devices. Also it pollutes the Linux DT if Linux boots with FW DT, such as used for a SystemReady compliant device, why wouldn't these go upstream? On the RPi4 side of things you should probably use the prior FW with the overlay provided by the config.txt to get the real TPM. Not sure why the DT would need the soft SPI given you disable the driver in the config? On Sat, 9 May 2026 at 01:47, Aidan Garske <aidan@wolfssl.com> wrote: > > From: Aidan <aidan@wolfssl.com> > > Add device tree entries for TPM devices across three platforms: > > bcm2711-rpi-4-b.dts: > Add SPI0 node with Infineon SLB9670/9672 TPM on CE1 (GPIO7), > matching the standard Linux tpm-slb9670 overlay. Add spi0 alias > so wolfTPM finds the bus at index 0. > > bcm2711-rpi-4-b-u-boot.dtsi (new file): > Add soft-SPI (GPIO bit-bang) fallback node for TPM communication. > This uses spi-gpio with GPIO11/10/9/7 and provides an alternative > to the hardware SPI driver when pinctrl naming differs between > U-Boot and Linux device trees. > > qemu-arm64.dts: > Add MMIO-based TPM TIS node at 0x0c000000 for QEMU virt machine > with swtpm. This allows wolfTPM testing via QEMU without hardware. > > sandbox.dtsi: > Add sandbox TPM SPI device (sandbox,tpm-spi) on SPI bus CS1 with > a phandle reference to a sandbox TPM SPI emulator node. This > enables wolfTPM SPI HAL testing in the sandbox environment. > > Signed-off-by: Aidan Garske <aidan@wolfssl.com> > --- > arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi | 54 ++++++++++++++++++++++++ > arch/arm/dts/bcm2711-rpi-4-b.dts | 20 +++++++++ > arch/arm/dts/qemu-arm64.dts | 4 ++ > arch/sandbox/dts/sandbox.dtsi | 11 +++++ > 4 files changed, 89 insertions(+) > create mode 100644 arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi > > diff --git a/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi b/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi > new file mode 100644 > index 00000000000..c38276abee9 > --- /dev/null > +++ b/arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi > @@ -0,0 +1,54 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * U-Boot specific additions for Raspberry Pi 4 Model B > + * > + * Adds soft SPI support for Infineon SLB9670/9672 TPM HAT > + * connected to SPI0 CE1 (GPIO 7) > + * > + * Uses GPIO bit-banging instead of hardware SPI to avoid > + * GPIO chip naming issues (pinctrl-bcm2835 vs pinctrl-bcm2711) > + */ > + > +#include "bcm283x-u-boot.dtsi" > +#include <dt-bindings/gpio/gpio.h> > + > +/ { > + aliases { > + spi0 = &soft_spi; > + }; > + > + soft_spi: soft-spi { > + compatible = "spi-gpio"; > + #address-cells = <1>; > + #size-cells = <0>; > + status = "okay"; > + bootph-all; > + > + /* > + * GPIO pins for SPI0 on Raspberry Pi 4: > + * GPIO 11 = SCLK > + * GPIO 10 = MOSI > + * GPIO 9 = MISO > + * GPIO 7 = CE1 (chip select for TPM) > + */ > + gpio-sck = <&gpio 11 GPIO_ACTIVE_HIGH>; > + gpio-mosi = <&gpio 10 GPIO_ACTIVE_HIGH>; > + gpio-miso = <&gpio 9 GPIO_ACTIVE_HIGH>; > + cs-gpios = <&gpio 7 GPIO_ACTIVE_LOW>; > + num-chipselects = <1>; > + spi-delay-us = <1>; > + > + /* Infineon SLB9672 TPM on CS1 */ > + tpm@0 { > + compatible = "infineon,slb9672", "tcg,tpm-tis-spi"; > + reg = <0>; > + spi-max-frequency = <10000000>; > + status = "okay"; > + bootph-all; > + }; > + }; > +}; > + > +&gpio { > + bootph-all; > +}; > diff --git a/arch/arm/dts/bcm2711-rpi-4-b.dts b/arch/arm/dts/bcm2711-rpi-4-b.dts > index 72ce80fbf26..a09276dc279 100644 > --- a/arch/arm/dts/bcm2711-rpi-4-b.dts > +++ b/arch/arm/dts/bcm2711-rpi-4-b.dts > @@ -8,6 +8,11 @@ > compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; > model = "Raspberry Pi 4 Model B"; > > + /* Alias hardware SPI as spi0 so wolfTPM finds it at bus 0 */ > + aliases { > + spi0 = &spi; > + }; > + > chosen { > /* 8250 auxiliary UART instead of pl011 */ > stdout-path = "serial1:115200n8"; > @@ -54,6 +59,21 @@ > enable-active-high; > gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>; > }; > + > +}; > + > +/* Hardware SPI with TPM - matches Linux tpm-slb9670 overlay */ > +&spi { > + status = "okay"; > + pinctrl-names = "default"; > + pinctrl-0 = <&spi0_gpio7>; > + > + /* Infineon SLB9670/9672 TPM 2.0 on CE1 (GPIO7) */ > + tpm@1 { > + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; > + reg = <1>; /* CE1 */ > + spi-max-frequency = <32000000>; > + }; > }; > > &ddc0 { > diff --git a/arch/arm/dts/qemu-arm64.dts b/arch/arm/dts/qemu-arm64.dts > index 95fcf53ed74..e74d036a532 100644 > --- a/arch/arm/dts/qemu-arm64.dts > +++ b/arch/arm/dts/qemu-arm64.dts > @@ -12,4 +12,8 @@ > #endif > > / { > + tpm@0c000000 { > + compatible = "tcg,tpm-tis-mmio"; > + reg = <0x0 0x0c000000 0x0 0x5000>; > + }; > }; > diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi > index 02b03894eaf..2fdd7f0e942 100644 > --- a/arch/sandbox/dts/sandbox.dtsi > +++ b/arch/sandbox/dts/sandbox.dtsi > @@ -286,6 +286,17 @@ > spi-max-frequency = <40000000>; > sandbox,filename = "spi.bin"; > }; > + > + tpm_spi: tpm@1 { > + reg = <1>; > + compatible = "sandbox,tpm-spi"; > + spi-max-frequency = <10000000>; > + sandbox,emul = <&tpm_spi_emul>; > + }; > + }; > + > + tpm_spi_emul: tpm-spi-emul { > + compatible = "sandbox,tpm-spi-emul"; > }; > > spl-test { > -- > 2.47.3 > ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v3 05/12] tpm: add wolfTPM build rules and Kconfig 2026-05-09 0:04 [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske ` (3 preceding siblings ...) 2026-05-09 0:04 ` [PATCH v3 04/12] dts: add TPM device tree nodes for RPi4, QEMU, and sandbox Aidan Garske @ 2026-05-09 0:04 ` Aidan Garske 2026-05-09 0:04 ` [PATCH v3 06/12] tpm: add wolfTPM headers and SHA384 glue code Aidan Garske ` (7 subsequent siblings) 12 siblings, 0 replies; 18+ messages in thread From: Aidan Garske @ 2026-05-09 0:04 UTC (permalink / raw) To: u-boot; +Cc: David Garske, Ilias Apalodimas 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.47.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 06/12] tpm: add wolfTPM headers and SHA384 glue code 2026-05-09 0:04 [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske ` (4 preceding siblings ...) 2026-05-09 0:04 ` [PATCH v3 05/12] tpm: add wolfTPM build rules and Kconfig Aidan Garske @ 2026-05-09 0:04 ` Aidan Garske 2026-05-09 0:04 ` [PATCH v3 07/12] tpm: add wolfTPM driver helpers and Kconfig options Aidan Garske ` (6 subsequent siblings) 12 siblings, 0 replies; 18+ messages in thread From: Aidan Garske @ 2026-05-09 0:04 UTC (permalink / raw) To: u-boot; +Cc: David Garske, Ilias Apalodimas 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.47.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 07/12] tpm: add wolfTPM driver helpers and Kconfig options 2026-05-09 0:04 [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske ` (5 preceding siblings ...) 2026-05-09 0:04 ` [PATCH v3 06/12] tpm: add wolfTPM headers and SHA384 glue code Aidan Garske @ 2026-05-09 0:04 ` Aidan Garske 2026-05-09 0:04 ` [PATCH v3 08/12] cmd: refactor tpm2 command into frontend/backend architecture Aidan Garske ` (5 subsequent siblings) 12 siblings, 0 replies; 18+ messages in thread From: Aidan Garske @ 2026-05-09 0:04 UTC (permalink / raw) To: u-boot; +Cc: David Garske, Ilias Apalodimas 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.47.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 08/12] cmd: refactor tpm2 command into frontend/backend architecture 2026-05-09 0:04 [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske ` (6 preceding siblings ...) 2026-05-09 0:04 ` [PATCH v3 07/12] tpm: add wolfTPM driver helpers and Kconfig options Aidan Garske @ 2026-05-09 0:04 ` Aidan Garske 2026-05-09 0:04 ` [PATCH v3 09/12] tpm: add sandbox TPM SPI emulator Aidan Garske ` (4 subsequent siblings) 12 siblings, 0 replies; 18+ messages in thread From: Aidan Garske @ 2026-05-09 0:04 UTC (permalink / raw) To: u-boot; +Cc: David Garske, Ilias Apalodimas 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.47.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 09/12] tpm: add sandbox TPM SPI emulator 2026-05-09 0:04 [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske ` (7 preceding siblings ...) 2026-05-09 0:04 ` [PATCH v3 08/12] cmd: refactor tpm2 command into frontend/backend architecture Aidan Garske @ 2026-05-09 0:04 ` Aidan Garske 2026-05-09 0:04 ` [PATCH v3 10/12] test: add wolfTPM C unit tests and Python integration tests Aidan Garske ` (3 subsequent siblings) 12 siblings, 0 replies; 18+ messages in thread From: Aidan Garske @ 2026-05-09 0:04 UTC (permalink / raw) To: u-boot; +Cc: David Garske, Ilias Apalodimas 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.47.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 10/12] test: add wolfTPM C unit tests and Python integration tests 2026-05-09 0:04 [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske ` (8 preceding siblings ...) 2026-05-09 0:04 ` [PATCH v3 09/12] tpm: add sandbox TPM SPI emulator Aidan Garske @ 2026-05-09 0:04 ` Aidan Garske 2026-05-09 0:04 ` [PATCH v3 11/12] doc: add wolfTPM documentation Aidan Garske ` (2 subsequent siblings) 12 siblings, 0 replies; 18+ messages in thread From: Aidan Garske @ 2026-05-09 0:04 UTC (permalink / raw) To: u-boot; +Cc: David Garske, Ilias Apalodimas 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.47.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 11/12] doc: add wolfTPM documentation 2026-05-09 0:04 [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske ` (9 preceding siblings ...) 2026-05-09 0:04 ` [PATCH v3 10/12] test: add wolfTPM C unit tests and Python integration tests Aidan Garske @ 2026-05-09 0:04 ` Aidan Garske 2026-05-09 0:04 ` [PATCH v3 12/12] configs: enable wolfTPM in rpi_4_defconfig Aidan Garske 2026-05-11 9:15 ` [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Peter Robinson 12 siblings, 0 replies; 18+ messages in thread From: Aidan Garske @ 2026-05-09 0:04 UTC (permalink / raw) To: u-boot; +Cc: David Garske, Ilias Apalodimas From: Aidan <aidan@wolfssl.com> Add documentation for wolfTPM integration, commands, and testing. doc/usage/cmd/wolftpm.rst: Comprehensive RST documentation covering: - All wolfTPM tpm2 subcommands with usage and examples - Infineon TPM firmware update step-by-step guide (extract manifest/firmware, load to RAM, perform update, recovery mode) - Build instructions for RPi4 and QEMU targets - Enabling debug output (U-Boot log system + wolfTPM library) - Complete test suite documentation with test coverage table - Python test framework setup (QEMU + swtpm instructions, helper scripts, verified test results) README.wolftpm.md: Quick-start guide with overview, feature comparison vs standard U-Boot TPM, command reference, build instructions, hardware support details, and file listing. README: Add CONFIG_TPM_WOLF reference in the configuration options section alongside existing CONFIG_TPM entries. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- README | 3 + README.wolftpm.md | 154 +++++++++ doc/usage/cmd/wolftpm.rst | 635 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 792 insertions(+) create mode 100644 README.wolftpm.md create mode 100644 doc/usage/cmd/wolftpm.rst diff --git a/README b/README index 20a73bab802..b9bfe14a1c7 100644 --- a/README +++ b/README @@ -361,6 +361,9 @@ The following options need to be configured: CONFIG_TPM Support TPM devices. + CONFIG_TPM_WOLF + Enables support for wolfTPM library. + CONFIG_TPM_TIS_INFINEON Support for Infineon i2c bus TPM devices. Only one device per system is supported at this time. diff --git a/README.wolftpm.md b/README.wolftpm.md new file mode 100644 index 00000000000..cdebe96ecb1 --- /dev/null +++ b/README.wolftpm.md @@ -0,0 +1,154 @@ +# wolfTPM Support for U-Boot + +This fork adds [wolfTPM](https://github.com/wolfSSL/wolfTPM) support to U-Boot, providing full TPM 2.0 command support using wolfTPM APIs and the wolfTPM library. + +## Overview + +wolfTPM is a portable, open-source TPM 2.0 library that provides: + +- **Native TPM 2.0 API** - Direct access to all TPM 2.0 commands +- **Wrapper API** - Simplified interface for common TPM operations +- **Hardware SPI Support** - Direct communication with TPM hardware via SPI +- **Firmware Update** - Support for Infineon SLB9672/SLB9673 firmware updates +- **No External Dependencies** - Standalone implementation without kernel TPM stack + +## Why wolfTPM vs Standard U-Boot TPM? + +| Feature | Standard U-Boot TPM | wolfTPM | +|---------|---------------------|---------| +| API | Basic TPM commands | Full TPM 2.0 + Wrapper API | +| PCR Operations | Basic read/extend | Full PCR management | +| Firmware Update | Not supported | Infineon SLB9672/9673 | +| Capabilities Query | Limited | Comprehensive `caps` command | +| SPI Communication | Via kernel driver | Native wolfTPM TIS layer | +| Library Integration | N/A | wolfSSL ecosystem compatible | + +## Command: `tpm2` + +When wolfTPM is enabled, the `tpm2` command uses wolfTPM APIs instead of the standard implementation. The command interface is compatible with the standard `tpm2` command, with additional wolfTPM-specific features. + +### Basic Commands + +```bash +tpm2 autostart # Initialize TPM, startup, and self-test +tpm2 init # Initialize TPM software stack +tpm2 info # Show TPM device information +tpm2 caps # Show TPM capabilities (wolfTPM enhanced) +tpm2 self_test full # Run full self-test +``` + +### PCR Operations + +```bash +tpm2 pcr_read <pcr> <addr> [algo] # Read PCR value +tpm2 pcr_extend <pcr> <addr> [algo] # Extend PCR with digest +tpm2 pcr_print # Print all PCR values +tpm2 pcr_allocate <algo> <on|off> # Configure PCR banks +``` + +### Security Management + +```bash +tpm2 clear <hierarchy> # Clear TPM +tpm2 change_auth <hierarchy> <new_pw> [old_pw] # Change password +tpm2 dam_reset [password] # Reset DAM counter +tpm2 dam_parameters <tries> <recovery> <lockout> # Set DAM params +``` + +### Firmware Update (Infineon Only) + +```bash +tpm2 firmware_update <manifest_addr> <size> <firmware_addr> <size> +tpm2 firmware_cancel +``` + +## Building + +### For Raspberry Pi 4 + +```bash +git clone https://github.com/aidangarske/u-boot.git +cd u-boot +git checkout rpi4-wolftpm-uboot +git submodule update --init lib/wolftpm + +export CROSS_COMPILE=aarch64-elf- +make rpi_4_defconfig +make -j$(nproc) +``` + +### Configuration Options + +Enable in `menuconfig` or defconfig: + +``` +# Core TPM support +CONFIG_TPM=y +CONFIG_TPM_V2=y + +# wolfTPM (replaces standard tpm2 command) +CONFIG_TPM_WOLF=y +CONFIG_CMD_TPM=y + +# For Infineon hardware +CONFIG_WOLFTPM_SLB9672=y + +# For QEMU/swtpm testing +# CONFIG_WOLFTPM_LINUX_DEV=y +``` + +**Note:** The `tpm2` command frontend (`cmd/tpm-v2.c`) is always compiled. The backend is selected at build time: when `CONFIG_TPM_WOLF` is enabled, `cmd/wolftpm.c` provides the wolfTPM backend; otherwise, `cmd/native_tpm2.c` provides the native U-Boot backend. + +## Hardware Support + +### Tested Hardware + +- Raspberry Pi 4 Model B +- Infineon SLB9670 TPM (LetsTrust HAT) +- Infineon SLB9672 TPM (with firmware update support) + +### SPI Configuration + +The TPM is configured on SPI0 CE1 (GPIO7), matching the standard Raspberry Pi `tpm-slb9670` overlay: + +``` +SPI0 Pins: +- SCLK: GPIO11 (pin 23) +- MOSI: GPIO10 (pin 19) +- MISO: GPIO9 (pin 21) +- CE1: GPIO7 (pin 26) +``` + +## Documentation + +- **Full Guide**: [rpi4-wolftpm-uboot](https://github.com/aidangarske/rpi4-wolftpm-uboot) +- **Firmware Update**: See `doc/usage/cmd/wolftpm.rst` +- **wolfTPM Library**: [github.com/wolfSSL/wolfTPM](https://github.com/wolfSSL/wolfTPM) + +## Files Modified/Added + +``` +cmd/tpm-v2.c # Shared tpm2 command frontend (dispatch table, help) +cmd/native_tpm2.c # Native U-Boot backend (when wolfTPM is OFF) +cmd/wolftpm.c # wolfTPM backend (when wolfTPM is ON) +cmd/tpm2-backend.h # Backend function declarations +lib/wolftpm/ # wolfTPM library (submodule) +lib/wolftpm.c # wolfTPM library glue code +include/configs/user_settings.h # wolfTPM configuration +include/wolftpm.h # wolfTPM header +arch/arm/dts/bcm2711-rpi-4-b.dts # Device tree with SPI/TPM config +configs/rpi_4_defconfig # RPi4 build configuration +drivers/spi/bcm2835_spi.c # BCM2835 SPI driver +doc/usage/cmd/wolftpm.rst # Command documentation +``` + +## License + +- U-Boot: GPL-2.0 +- wolfTPM: GPL-2.0 +- This integration: GPL-2.0 + +## Author + +Aidan Garske <aidan@wolfssl.com> +wolfSSL Inc. diff --git a/doc/usage/cmd/wolftpm.rst b/doc/usage/cmd/wolftpm.rst new file mode 100644 index 00000000000..85e6be544bb --- /dev/null +++ b/doc/usage/cmd/wolftpm.rst @@ -0,0 +1,635 @@ +wolfTPM Support For Das U-Boot +============================== + +wolfTPM provides experimental support for U-Boot with the following key features: + +- Utilizes SOFT SPI driver in U-Boot for TPM communication +- Implements TPM 2.0 driver functionality through its internal TIS layer +- Provides native API access to all TPM 2.0 commands +- Includes wrapper API for common TPM 2.0 operations +- Supports two integration paths: + - ``__linux__``: Uses existing tpm interface via tpm2_linux.c + - ``__UBOOT__``: Direct SPI communication through tpm_io_uboot.c + +wolfTPM U-Boot Commands +---------------------- + +The following commands are available through the ``tpm2`` command (powered by wolfTPM): + +Basic Commands +~~~~~~~~~~~~~~ + +- ``help`` - Show help text +- ``device [num device]`` - Show all devices or set the specified device +- ``info`` - Show information about the TPM +- ``state`` - Show internal state from the TPM (if available) +- ``autostart`` - Initialize the TPM, perform a Startup(clear) and run a full selftest sequence +- ``init`` - Initialize the software stack (must be first command) +- ``startup <mode> [<op>]`` - Issue a TPM2_Startup command + - ``<mode>``: TPM2_SU_CLEAR (reset state) or TPM2_SU_STATE (preserved state) + - ``[<op>]``: optional shutdown with "off" +- ``self_test <type>`` - Test TPM capabilities + - ``<type>``: "full" (all tests) or "continue" (untested tests only) + +PCR Operations +~~~~~~~~~~~~~~ + +- ``pcr_extend <pcr> <digest_addr> [<digest_algo>]`` - Extend PCR with digest +- ``pcr_read <pcr> <digest_addr> [<digest_algo>]`` - Read PCR to memory +- ``pcr_allocate <algorithm> <on/off> [<password>]`` - Reconfig PCR bank algorithm +- ``pcr_setauthpolicy | pcr_setauthvalue <pcr> <key> [<password>]`` - Change PCR access key +- ``pcr_print`` - Print current PCR state + +Security Management +~~~~~~~~~~~~~~~~~~~ + +- ``clear <hierarchy>`` - Issue TPM2_Clear command + - ``<hierarchy>``: TPM2_RH_LOCKOUT or TPM2_RH_PLATFORM +- ``change_auth <hierarchy> <new_pw> [<old_pw>]`` - Change hierarchy password + - ``<hierarchy>``: TPM2_RH_LOCKOUT, TPM2_RH_ENDORSEMENT, TPM2_RH_OWNER, or TPM2_RH_PLATFORM +- ``dam_reset [<password>]`` - Reset internal error counter +- ``dam_parameters <max_tries> <recovery_time> <lockout_recovery> [<password>]`` - Set DAM parameters +- ``caps`` - Show TPM capabilities and info + +Firmware Management +~~~~~~~~~~~~~~~~~~~ + +- ``firmware_update <manifest_addr> <manifest_sz> <firmware_addr> <firmware_sz>`` - Update TPM firmware +- ``firmware_cancel`` - Cancel TPM firmware update + +Infineon TPM Firmware Update Guide +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**WARNING: Firmware updates are risky. A failed update can brick your TPM. +Only proceed if you have a valid reason to update (security patches, new features) +and understand the risks.** + +The firmware update commands are for Infineon SLB9672/SLB9673 TPMs only. The process +requires extracting manifest and firmware data from Infineon's combined ``.BIN`` file. + +**Prerequisites:** + +- Infineon firmware file (e.g., ``TPM20_16.13.17733.0_R1.BIN``) +- wolfTPM's ``ifx_fw_extract`` tool (in ``lib/wolftpm/examples/firmware/``) +- Your TPM's KeyGroupId (shown by ``tpm2 caps`` command) + +**Step 1: Get your TPM's KeyGroupId** + +Run ``tpm2 caps`` to find your TPM's KeyGroupId:: + + U-Boot> tpm2 caps + Mfg IFX (1), Vendor SLB9672, Fw 16.13 (0x4545), FIPS 140-2 1, CC-EAL4 1 + Operational mode: Normal TPM operational mode (0x0) + KeyGroupId 0x5, FwCounter 1255 (255 same) + ... + +In this example, KeyGroupId is ``0x5``. + +**Step 2: Build the extraction tool (on host machine)** + +:: + + cd lib/wolftpm/examples/firmware + gcc -o ifx_fw_extract ifx_fw_extract.c + +**Step 3: List available key groups in firmware file** + +:: + + ./ifx_fw_extract TPM20_16.13.17733.0_R1.BIN + Found group 00000005 + +Verify your TPM's KeyGroupId matches one in the firmware file. + +**Step 4: Extract manifest and firmware data** + +Use your KeyGroupId (0x5 in this example):: + + ./ifx_fw_extract TPM20_16.13.17733.0_R1.BIN 0x5 manifest.bin firmware.bin + Found group 00000005 + Chosen group found: 00000005 + Manifest size is 3229 + Data size is 925539 + Wrote 3229 bytes to manifest.bin + Wrote 925539 bytes to firmware.bin + +**Step 5: Copy files to SD card** + +Copy ``manifest.bin`` and ``firmware.bin`` to your boot partition (FAT):: + + cp manifest.bin firmware.bin /Volumes/bootfs/ # macOS + cp manifest.bin firmware.bin /boot/firmware/ # Linux + +**Step 6: Load files into memory** + +In U-Boot, load the files from SD card into RAM:: + + U-Boot> fatload mmc 0:1 0x10000000 manifest.bin + 3229 bytes read in 32 ms (97.7 KiB/s) + + U-Boot> fatload mmc 0:1 0x10100000 firmware.bin + 925539 bytes read in 86 ms (10.3 MiB/s) + +**Step 7: Perform firmware update (CAUTION!)** + +Convert file sizes to hex: + +- manifest.bin: 3229 bytes = 0xC9D +- firmware.bin: 925539 bytes = 0xE1F63 + +Run the firmware update:: + + U-Boot> tpm2 firmware_update 0x10000000 0xC9D 0x10100000 0xE1F63 + TPM2 Firmware Update + Infineon Firmware Update Tool + Manifest Address: 0x10000000 (size: 3229) + Firmware Address: 0x10100000 (size: 925539) + tpm2 init: rc = 0 (Success) + Mfg IFX (1), Vendor SLB9672, Fw 16.13 (0x4545) + Operational mode: Normal TPM operational mode (0x0) + KeyGroupId 0x5, FwCounter 1255 (255 same) + Firmware Update (normal mode): + Mfg IFX (1), Vendor SLB9672, Fw 16.13 (0x4545) + Operational mode: Normal TPM operational mode (0x0) + KeyGroupId 0x5, FwCounter 1255 (255 same) + tpm2 firmware_update: rc=0 (Success) + +**DO NOT power off or reset during the update!** + +**Step 8: Verify update** + +After the update completes, verify with:: + + U-Boot> tpm2 caps + +The firmware version should show the new version. + +**Recovery Mode:** + +If the TPM enters recovery mode (opMode shows 0x02 or 0x8x), the firmware update +command will automatically use recovery mode. You may need to run the update again +to complete the process. + +Canceling a Firmware Update +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If an update is in progress and needs to be abandoned (opMode 0x01), use:: + + U-Boot> tpm2 firmware_cancel + tpm2 init: rc = 0 (Success) + tpm2 firmware_cancel: rc=0 (Success) + +**IMPORTANT: After running firmware_cancel, you MUST reboot/power cycle the system +before running any other TPM commands.** If you attempt to run commands without +rebooting, you will get ``TPM_RC_REBOOT`` (error 304):: + + U-Boot> tpm2 firmware_update ... + tpm2 init: rc = 304 (TPM_RC_REBOOT) + Infineon firmware update failed 0x130: TPM_RC_REBOOT + +After rebooting, the TPM will return to normal operation and you can retry the +firmware update or continue with normal TPM operations. + +**Note:** If no firmware update is in progress, ``firmware_cancel`` returns +``TPM_RC_COMMAND_CODE`` (0x143), which is expected and harmless:: + + U-Boot> tpm2 firmware_cancel + tpm2 firmware_cancel: rc=323 (TPM_RC_COMMAND_CODE) + +Enabling wolfTPM in U-Boot +-------------------------- + +Enable wolfTPM support in U-Boot by adding these options to your board's defconfig:: + + CONFIG_TPM=y + CONFIG_TPM_V2=y + CONFIG_TPM_WOLF=y + CONFIG_CMD_WOLFTPM=y + + if with __LINUX__: + CONFIG_TPM_LINUX_DEV=y + +Or use ``make menuconfig`` and enable: + +Enabling Debug Output +~~~~~~~~~~~~~~~~~~~~~ + +wolfTPM commands use U-Boot's logging system (``log_debug()``). To enable debug +output, you must first enable the logging subsystem in your board's defconfig:: + + CONFIG_LOG=y + CONFIG_LOG_MAX_LEVEL=7 + CONFIG_LOG_DEFAULT_LEVEL=7 + +Or via ``make menuconfig``: + +- Console → Enable logging support +- Console → Maximum log level to record = 7 +- Console → Default logging level to display = 7 + +Log levels: +- 7 = DEBUG (to show wolfTPM command debug output) + +**Note:** Without ``CONFIG_LOG=y``, the ``log level`` command will not exist +and ``log_debug()`` calls will produce no output. + +wolfTPM Library Debug +^^^^^^^^^^^^^^^^^^^^^ + +For lower-level wolfTPM library debug output (TPM protocol messages), edit +``include/configs/user_settings.h`` and uncomment:: + + #define DEBUG_WOLFTPM /* Basic wolfTPM debug messages */ + #define WOLFTPM_DEBUG_VERBOSE /* Verbose debug messages */ + #define WOLFTPM_DEBUG_IO /* IO-level debug (SPI transfers) */ + +After enabling, rebuild U-Boot:: + + make clean + make -j4 + +Menuconfig Paths +^^^^^^^^^^^^^^^^ + +The following menuconfig paths are useful for wolfTPM: + +- Device Drivers → TPM → TPM 2.0 Support +- Device Drivers → TPM → wolfTPM Support +- Command line interface → Security commands → Enable wolfTPM commands +- Console → Enable logging support (for ``log_debug()`` output) + +Building and Running wolfTPM with U-Boot using QEMU +--------------------------------------------------- + +To build and run wolfTPM with U-Boot using QEMU and a TPM simulator, follow these steps: + +1. Install swtpm:: + + git clone https://github.com/stefanberger/swtpm.git + cd swtpm + ./autogen.sh + make + +2. Build U-Boot:: + + make distclean + export CROSS_COMPILE=aarch64-linux-gnu- + export ARCH=aarch64 + make qemu_arm64_defconfig + make -j4 + +3. Create TPM directory:: + + mkdir -p /tmp/mytpm1 + +4. Start swtpm (in first terminal):: + + swtpm socket --tpm2 --tpmstate dir=/tmp/mytpm1 --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock --log level=20 + +5. Start QEMU (in second terminal):: + + qemu-system-aarch64 -machine virt -nographic -cpu cortex-a57 -bios u-boot.bin -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis-device,tpmdev=tpm0 + +6. Example output:: + + U-Boot 2025.07-rc1-ge15cbf232ddf-dirty (May 06 2025 - 16:25:56 -0700) + ... + => tpm2 help + tpm2 - Issue a TPMv2.x command + Usage: + tpm2 <command> [<arguments>] + ... + => tpm2 info + tpm_tis@0 v2.0: VendorID 0x1014, DeviceID 0x0001, RevisionID 0x01 [open] + => tpm2 startup TPM2_SU_CLEAR + => tpm2 get_capability 0x6 0x20e 0x200 1 + Capabilities read from TPM: + Property 0x6a2e45a9: 0x6c3646a9 + => tpm2 pcr_read 10 0x100000 + PCR #10 sha256 32 byte content (20 known updates): + 20 25 73 0a 00 56 61 6c 75 65 3a 0a 00 23 23 20 + 4f 75 74 20 6f 66 20 6d 65 6d 6f 72 79 0a 00 23 + +7. Example commands:: + + => tpm2 info + tpm_tis@0 v2.0: VendorID 0x1014, DeviceID 0x0001, RevisionID 0x01 [open] + ... + => tpm2 pcr_read 10 0x100000 + PCR #10 sha256 32 byte content (20 known updates): + 20 25 73 0a 00 56 61 6c 75 65 3a 0a 00 23 23 20 + 4f 75 74 20 6f 66 20 6d 65 6d 6f 72 79 0a 00 23 + +8. Exiting the QEMU: + Press Ctrl-A followed by X + +Testing wolfTPM +--------------- + +wolfTPM includes a comprehensive test suite based on the existing TPM2 tests. +The tests are located in: + +- ``test/cmd/wolftpm.c`` - C unit tests (based on ``test/dm/tpm.c`` and ``test/cmd/hash.c``) +- ``test/py/tests/test_wolftpm.py`` - Python integration tests (based on ``test/py/tests/test_tpm2.py``) + +Running C Unit Tests +~~~~~~~~~~~~~~~~~~~~ + +The C unit tests use the U-Boot test framework and can be run in sandbox mode +or on real hardware. To run all wolfTPM tests:: + + # Build sandbox with tests enabled + make sandbox_defconfig + # Enable wolfTPM in menuconfig + make menuconfig + make -j4 + + # Run U-Boot sandbox + ./u-boot -T + + # In U-Boot sandbox, run the unit tests + => ut cmd + +Individual tests can be run by name:: + + => ut cmd cmd_test_wolftpm_autostart + => ut cmd cmd_test_wolftpm_init + => ut cmd cmd_test_wolftpm_self_test + => ut cmd cmd_test_wolftpm_caps + => ut cmd cmd_test_wolftpm_clear + => ut cmd cmd_test_wolftpm_pcr_read + => ut cmd cmd_test_wolftpm_pcr_extend + +Running Tests Manually in QEMU +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can also test wolfTPM commands manually in QEMU: + +1. Start swtpm:: + + mkdir -p /tmp/mytpm + swtpm socket --tpm2 --tpmstate dir=/tmp/mytpm \ + --ctrl type=unixio,path=/tmp/mytpm/swtpm-sock --log level=20 + +2. Start QEMU with TPM:: + + qemu-system-aarch64 -machine virt -cpu cortex-a57 -m 1024 \ + -bios u-boot.bin \ + -chardev socket,id=chrtpm,path=/tmp/mytpm/swtpm-sock \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis-device,tpmdev=tpm0 \ + -nographic + +3. Run wolfTPM commands at the U-Boot prompt:: + + => tpm2 autostart + => tpm2 caps + => tpm2 pcr_read 0 sha256 + => tpm2 pcr_print + => tpm2 self_test full + => tpm2 clear TPM2_RH_LOCKOUT + => tpm2 dam_parameters 3 10 0 + +Test Coverage +~~~~~~~~~~~~~ + +The test suite covers the following wolfTPM functionality: + ++---------------------------+------------------------------------------+ +| Test Name | Description | ++===========================+==========================================+ +| wolftpm_autostart | TPM initialization and startup | ++---------------------------+------------------------------------------+ +| wolftpm_init | TPM device initialization | ++---------------------------+------------------------------------------+ +| wolftpm_self_test | Full TPM self-test | ++---------------------------+------------------------------------------+ +| wolftpm_self_test_continue| Continue incomplete self-tests | ++---------------------------+------------------------------------------+ +| wolftpm_caps | Read TPM capabilities | ++---------------------------+------------------------------------------+ +| wolftpm_clear | Clear TPM state | ++---------------------------+------------------------------------------+ +| wolftpm_pcr_read | Read PCR values | ++---------------------------+------------------------------------------+ +| wolftpm_pcr_extend | Extend PCR with digest | ++---------------------------+------------------------------------------+ +| wolftpm_pcr_print | Print all PCR values | ++---------------------------+------------------------------------------+ +| wolftpm_pcr_allocate | Reconfigure PCR bank algorithm | ++---------------------------+------------------------------------------+ +| wolftpm_dam_reset | Reset DAM counter | ++---------------------------+------------------------------------------+ +| wolftpm_dam_parameters | Set DAM parameters | ++---------------------------+------------------------------------------+ +| wolftpm_change_auth | Change hierarchy password | ++---------------------------+------------------------------------------+ +| wolftpm_info | Display TPM info | ++---------------------------+------------------------------------------+ +| wolftpm_state | Display TPM state | ++---------------------------+------------------------------------------+ +| wolftpm_device | Show/set TPM device | ++---------------------------+------------------------------------------+ +| wolftpm_startup_clear | TPM2_Startup with CLEAR mode | ++---------------------------+------------------------------------------+ +| wolftpm_startup_state | TPM2_Startup with STATE mode | ++---------------------------+------------------------------------------+ +| wolftpm_startup_shutdown | TPM2_Shutdown command | ++---------------------------+------------------------------------------+ +| wolftpm_get_capability | Read TPM capabilities by property | ++---------------------------+------------------------------------------+ + +The following commands are implemented in ``cmd/wolftpm.c`` but do not yet have +test coverage due to special requirements. These have been tested locally on +hardware but dont have test suites due to different build configurations. + ++---------------------------+------------------------------------------+------------------+ +| Command | Description | Notes | ++===========================+==========================================+==================+ +| pcr_setauthpolicy | Set PCR authorization policy | Requires | +| | | wolfCrypt | ++---------------------------+------------------------------------------+------------------+ +| pcr_setauthvalue | Set PCR authorization value | Requires | +| | | wolfCrypt | ++---------------------------+------------------------------------------+------------------+ +| firmware_update | Update TPM firmware (Infineon only) | Requires | +| | | Infineon HW | ++---------------------------+------------------------------------------+------------------+ +| firmware_cancel | Cancel firmware update (Infineon only) | Requires | +| | | Infineon HW | ++---------------------------+------------------------------------------+------------------+ + +**Note:** The ``pcr_setauthpolicy`` and ``pcr_setauthvalue`` commands require +``WOLFTPM2_NO_WOLFCRYPT`` to be undefined (i.e., wolfCrypt must be enabled). +The ``firmware_update`` and ``firmware_cancel`` commands require Infineon +SLB9672/SLB9673 hardware. + +Testing on SLB 9672 on Raspberry Pi 4 Hardware +---------------------------------------------- + +For testing with real TPM hardware (e.g., Infineon SLB9672 TPM HAT on Raspberry Pi): + +1. Build U-Boot for Raspberry Pi:: + + make distclean + export CROSS_COMPILE=aarch64-linux-gnu- + export ARCH=aarch64 + make rpi_arm64_defconfig + make -j$(nproc) + +2. Backup current boot configuration:: + + sudo cp /boot/firmware/config.txt /boot/firmware/config.txt.backup + +3. Copy U-Boot to boot partition:: + + sudo cp u-boot.bin /boot/firmware/ + +4. Edit ``/boot/firmware/config.txt`` and add:: + + # U-Boot for wolfTPM testing + enable_uart=1 + kernel=u-boot.bin + arm_64bit=1 + +5. Connect serial console (recommended) - USB-to-serial adapter on GPIO 14/15 + (pins 8/10) at 115200 baud. + +6. Reboot and test at U-Boot prompt:: + + U-Boot> tpm2 device + U-Boot> tpm2 info + U-Boot> tpm2 autostart + U-Boot> tpm2 caps + U-Boot> tpm2 pcr_read 0 0x1000000 SHA256 + +7. To restore normal Linux boot:: + + sudo cp /boot/firmware/config.txt.backup /boot/firmware/config.txt + sudo reboot + +**Note:** The Raspberry Pi build uses GPIO-based soft SPI for TPM communication. +Standard SPI0 pins are used: GPIO 11 (SCLK), GPIO 10 (MOSI), GPIO 9 (MISO), +GPIO 7 (CE1 for TPM). Adjust ``arch/arm/dts/bcm2711-rpi-4-b-u-boot.dtsi`` if +your TPM HAT uses different GPIO pins. + +Python Test Framework +~~~~~~~~~~~~~~~~~~~~~ + +**Why QEMU+swtpm is required (not sandbox):** + +The native ``test_tpm2.py`` tests run directly in sandbox because the native +TPM backend uses U-Boot's driver model, which has a built-in sandbox TPM +emulator. wolfTPM bypasses driver model entirely and communicates with TPM +hardware directly via its own SPI/MMIO HAL layer. This means there is no +sandbox emulator for wolfTPM to talk to. Instead, wolfTPM Python tests require +QEMU with swtpm (software TPM emulator) which provides a real TPM device +interface that wolfTPM can communicate with via MMIO. + +**Prerequisites:** + +Install swtpm and QEMU:: + + sudo apt-get install -y swtpm qemu-system-aarch64 pytest + +**Running wolfTPM Python Tests with QEMU+swtpm:** + +1. Build U-Boot for QEMU arm64 with wolfTPM and autodetect enabled:: + + make qemu_arm64_defconfig + scripts/config --enable CONFIG_CMD_WOLFTPM --enable CONFIG_TPM_AUTODETECT + make olddefconfig + make -j$(nproc) + +2. Create the test helper scripts in the U-Boot root directory: + + ``u-boot-test-flash`` (no-op for QEMU):: + + #!/bin/bash + exit 0 + + ``u-boot-test-console`` (starts swtpm + QEMU):: + + #!/bin/bash + SWTPM_DIR=/tmp/mytpm + SWTPM_SOCK=${SWTPM_DIR}/swtpm-sock + mkdir -p ${SWTPM_DIR} + if [ ! -S "${SWTPM_SOCK}" ]; then + swtpm socket --tpm2 --tpmstate dir=${SWTPM_DIR} \ + --ctrl type=unixio,path=${SWTPM_SOCK} --log level=0 & + sleep 1 + fi + exec qemu-system-aarch64 -machine virt -nographic -cpu cortex-a57 \ + -bios u-boot.bin \ + -chardev socket,id=chrtpm,path=${SWTPM_SOCK} \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis-device,tpmdev=tpm0 + + ``u-boot-test-reset`` (no-op):: + + #!/bin/bash + exit 0 + + ``u-boot-test-release`` (cleanup):: + + #!/bin/bash + pkill -f "swtpm.*mytpm" 2>/dev/null + exit 0 + + Make them executable:: + + chmod +x u-boot-test-flash u-boot-test-console u-boot-test-reset u-boot-test-release + +3. Run the wolfTPM Python tests:: + + export PATH=".:$PATH" + ./test/py/test.py --bd qemu_arm64 --build-dir . -k "test_wolftpm and not ut_cmd" -v + +**Verified output (QEMU arm64 + swtpm, 19 passed, 2 skipped):** + +:: + + test_wolftpm_autostart PASSED + test_wolftpm_init PASSED + test_wolftpm_self_test_full PASSED + test_wolftpm_self_test_continue PASSED + test_wolftpm_caps PASSED + test_wolftpm_clear PASSED + test_wolftpm_change_auth SKIPPED (requires wolfCrypt) + test_wolftpm_dam_parameters PASSED + test_wolftpm_dam_reset PASSED + test_wolftpm_pcr_read PASSED + test_wolftpm_pcr_extend PASSED + test_wolftpm_pcr_print PASSED + test_wolftpm_info PASSED + test_wolftpm_state PASSED + test_wolftpm_device PASSED + test_wolftpm_startup_clear PASSED + test_wolftpm_startup_state PASSED + test_wolftpm_startup_shutdown PASSED + test_wolftpm_get_capability SKIPPED + test_wolftpm_pcr_allocate PASSED + test_wolftpm_cleanup PASSED + +The native ``test_tpm2.py`` tests can be run directly in sandbox:: + + ./test/py/test.py --bd sandbox --build -k test_tpm2 -v + +Enabling Debug Output +~~~~~~~~~~~~~~~~~~~~~ + +To see debug messages, enable logging before running:: + + # At U-Boot prompt + => log level 7 + +Or enable in defconfig:: + + CONFIG_LOG=y + CONFIG_LOG_MAX_LEVEL=7 + CONFIG_LOG_DEFAULT_LEVEL=7 + +For wolfTPM library-level debug, edit ``include/configs/user_settings.h``:: + + #define DEBUG_WOLFTPM + #define WOLFTPM_DEBUG_IO /* Shows SPI transfer details */ -- 2.47.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 12/12] configs: enable wolfTPM in rpi_4_defconfig 2026-05-09 0:04 [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske ` (10 preceding siblings ...) 2026-05-09 0:04 ` [PATCH v3 11/12] doc: add wolfTPM documentation Aidan Garske @ 2026-05-09 0:04 ` Aidan Garske 2026-05-11 8:22 ` Peter Robinson 2026-05-11 9:15 ` [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Peter Robinson 12 siblings, 1 reply; 18+ messages in thread From: Aidan Garske @ 2026-05-09 0:04 UTC (permalink / raw) To: u-boot; +Cc: David Garske, Ilias Apalodimas From: Aidan <aidan@wolfssl.com> Enable SPI, TPM, and wolfTPM support in the Raspberry Pi 4 default configuration for out-of-the-box TPM 2.0 support with Infineon SLB9670/9672 TPM HATs. SPI support: CONFIG_SPI, CONFIG_DM_SPI, CONFIG_BCM2835_SPI, CONFIG_CMD_SPI Enables the BCM2835 hardware SPI driver. Soft SPI is disabled since the hardware driver is used. TPM and wolfTPM: CONFIG_TPM, CONFIG_TPM_V2, CONFIG_CMD_TPM: core TPM support CONFIG_TPM_WOLF: wolfTPM library integration CONFIG_CMD_WOLFTPM: wolfTPM command backend for tpm2 CONFIG_WOLFTPM_SLB9672: Infineon SLB9672 chip support WOLFTPM_LINUX_DEV disabled: uses native wolfTPM TIS layer with direct SPI communication rather than U-Boot's TPM driver model Logging: CONFIG_LOG with level 7 (DEBUG) to enable log_debug() output from wolfTPM commands. Testing: CONFIG_UNIT_TEST, CONFIG_CONSOLE_RECORD, CONFIG_HEXDUMP for running the wolfTPM C unit test suite. Signed-off-by: Aidan Garske <aidan@wolfssl.com> --- configs/rpi_4_defconfig | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/configs/rpi_4_defconfig b/configs/rpi_4_defconfig index 8362242b97f..22280d9b70e 100644 --- a/configs/rpi_4_defconfig +++ b/configs/rpi_4_defconfig @@ -69,4 +69,31 @@ CONFIG_SYS_WHITE_ON_BLACK=y CONFIG_VIDEO_BCM2835=y CONFIG_CONSOLE_SCROLL_LINES=10 CONFIG_PHYS_TO_BUS=y -# CONFIG_HEXDUMP is not set +# HEXDUMP enabled for unit tests + +# SPI support (hardware SPI - matches Linux tpm-slb9670 overlay) +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_BCM2835_SPI=y +# CONFIG_SOFT_SPI is not set +CONFIG_CMD_SPI=y + +# TPM and wolfTPM support +CONFIG_TPM=y +CONFIG_TPM_V2=y +CONFIG_CMD_TPM=y +CONFIG_TPM_WOLF=y +# CONFIG_WOLFTPM_LINUX_DEV is not set +CONFIG_WOLFTPM_SLB9672=y +CONFIG_CMD_WOLFTPM=y + +# Logging (debug level to see log_debug output) +CONFIG_LOG=y +CONFIG_LOGLEVEL=7 +CONFIG_LOG_MAX_LEVEL=7 +CONFIG_LOG_DEFAULT_LEVEL=7 + +# Unit testing support +CONFIG_UNIT_TEST=y +CONFIG_CONSOLE_RECORD=y +CONFIG_HEXDUMP=y -- 2.47.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v3 12/12] configs: enable wolfTPM in rpi_4_defconfig 2026-05-09 0:04 ` [PATCH v3 12/12] configs: enable wolfTPM in rpi_4_defconfig Aidan Garske @ 2026-05-11 8:22 ` Peter Robinson 0 siblings, 0 replies; 18+ messages in thread From: Peter Robinson @ 2026-05-11 8:22 UTC (permalink / raw) To: Aidan Garske; +Cc: u-boot, David Garske, Ilias Apalodimas Hi Aidan, Firstly you should be copying the maintainers of the components you're changing, I see a bunch of changes to the Raspberry Pi but the maintainers aren't copied. > Enable SPI, TPM, and wolfTPM support in the Raspberry Pi 4 default > configuration for out-of-the-box TPM 2.0 support with Infineon > SLB9670/9672 TPM HATs. > > SPI support: > CONFIG_SPI, CONFIG_DM_SPI, CONFIG_BCM2835_SPI, CONFIG_CMD_SPI > Enables the BCM2835 hardware SPI driver. Soft SPI is disabled > since the hardware driver is used. Why would the would the soft SPI driver be enabled, I don't see it as a default y anywhere. > TPM and wolfTPM: > CONFIG_TPM, CONFIG_TPM_V2, CONFIG_CMD_TPM: core TPM support > CONFIG_TPM_WOLF: wolfTPM library integration > CONFIG_CMD_WOLFTPM: wolfTPM command backend for tpm2 > CONFIG_WOLFTPM_SLB9672: Infineon SLB9672 chip support > WOLFTPM_LINUX_DEV disabled: uses native wolfTPM TIS layer with > direct SPI communication rather than U-Boot's TPM driver model > > Logging: > CONFIG_LOG with level 7 (DEBUG) to enable log_debug() output > from wolfTPM commands. > > Testing: > CONFIG_UNIT_TEST, CONFIG_CONSOLE_RECORD, CONFIG_HEXDUMP for > running the wolfTPM C unit test suite. The above tells me what you're doing, but I can see that from the config changes below, it doesn't tell me *WHY*! So please explain! > Signed-off-by: Aidan Garske <aidan@wolfssl.com> > --- > configs/rpi_4_defconfig | 29 ++++++++++++++++++++++++++++- > 1 file changed, 28 insertions(+), 1 deletion(-) > > diff --git a/configs/rpi_4_defconfig b/configs/rpi_4_defconfig > index 8362242b97f..22280d9b70e 100644 > --- a/configs/rpi_4_defconfig > +++ b/configs/rpi_4_defconfig > @@ -69,4 +69,31 @@ CONFIG_SYS_WHITE_ON_BLACK=y > CONFIG_VIDEO_BCM2835=y > CONFIG_CONSOLE_SCROLL_LINES=10 > CONFIG_PHYS_TO_BUS=y > -# CONFIG_HEXDUMP is not set > +# HEXDUMP enabled for unit tests Would we want this enabled for a default user on a RPi? I'm not sure we do. > +# SPI support (hardware SPI - matches Linux tpm-slb9670 overlay) > +CONFIG_SPI=y > +CONFIG_DM_SPI=y > +CONFIG_BCM2835_SPI=y > +# CONFIG_SOFT_SPI is not set > +CONFIG_CMD_SPI=y What does the below bring for the average RPi user? Why would I want it as the maintainer? > +# TPM and wolfTPM support > +CONFIG_TPM=y > +CONFIG_TPM_V2=y > +CONFIG_CMD_TPM=y > +CONFIG_TPM_WOLF=y > +# CONFIG_WOLFTPM_LINUX_DEV is not set > +CONFIG_WOLFTPM_SLB9672=y > +CONFIG_CMD_WOLFTPM=y For the below an absolute NAK, This config isn't what the average user would want. The config isn't your play ground. > +# Logging (debug level to see log_debug output) > +CONFIG_LOG=y > +CONFIG_LOGLEVEL=7 > +CONFIG_LOG_MAX_LEVEL=7 > +CONFIG_LOG_DEFAULT_LEVEL=7 > + > +# Unit testing support > +CONFIG_UNIT_TEST=y > +CONFIG_CONSOLE_RECORD=y > +CONFIG_HEXDUMP=y > -- > 2.47.3 > ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 2026-05-09 0:04 [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske ` (11 preceding siblings ...) 2026-05-09 0:04 ` [PATCH v3 12/12] configs: enable wolfTPM in rpi_4_defconfig Aidan Garske @ 2026-05-11 9:15 ` Peter Robinson 2026-05-11 10:09 ` Peter Robinson 12 siblings, 1 reply; 18+ messages in thread From: Peter Robinson @ 2026-05-11 9:15 UTC (permalink / raw) To: Aidan Garske; +Cc: u-boot, David Garske, Ilias Apalodimas Hi Aidan, > This is v3 of the wolfTPM TPM 2.0 stack integration for U-Boot. > > wolfTPM (https://github.com/wolfSSL/wolfTPM) is a portable, GPLv2 TPM 2.0 I go to the github link and it says GPL-3.0 license so which is it? IANAL but I'm not sure if the GPLv3 is compatible with GPLv2 in the context of U-Boot because it would make the whole output a GPLv3 application > 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 backend behind the existing > 'tpm2' command, alongside support for QEMU+swtpm, sandbox emulation, and > real Raspberry Pi 4 + Infineon SLB9672 hardware. So that provides the technical detail, but what value does it provide to U-Boot? We already have a relatively complete TPM stack, do people do firmware updates in the early boot process, why else would someone choose to use this over the existing implementation? One part of what I want to know in a cover letter is what value this provides to the project, what are the pros/cons etc, like what maintenance looks like. Peter > Branch (full 14-commit history including the subtree squash + merge): > https://github.com/aidangarske/u-boot wolftpm-v2-patches > > Note on the subtree commits omitted from this email thread: > The branch above contains 14 commits; the email series is 12 patches. > Two commits are deliberately not sent to the list: > > * "Squashed 'lib/wolftpm/' content from commit 664db130d57" > - the parentless squash commit produced by `git subtree add`. > Its diff is ~3.4MB / ~90k lines and would be rejected by the > mailing list on size. > * "Merge commit 'd42fd7b146...' as 'lib/wolftpm'" > - the corresponding subtree merge commit. Merges have no patch > form and are routinely omitted by `git format-patch`. > > Please pull from the branch above (or wolfssl/wolfTPM @ 664db130d57) > to inspect the imported wolfTPM source. Subsequent updates will go > via tools/update-subtree.sh, matching how mbedTLS, lwIP, and > dts/upstream are maintained in tree. > > Changes since v2: > - Replaced the lib/wolftpm git submodule with a git subtree import > (squash + merge), matching the convention used for mbedTLS, lwIP, > and dts/upstream. tools/update-subtree.sh is updated to know > about the wolftpm subtree (path lib/wolftpm, upstream > https://github.com/wolfssl/wolfTPM.git). > [feedback: Ilias Apalodimas] > - Reverted the changes to include/linux/byteorder/generic.h. The > redefinition workaround for cpu_to_beXX / beXX_to_cpu now lives > on the wolfTPM side: include/configs/user_settings.h pulls in > <asm/byteorder.h> up front so U-Boot's macros are defined before > wolfTPM's #ifndef-guarded fallbacks in tpm2_packet.h. > [feedback: Ilias Apalodimas] > > Testing: > - QEMU arm64 + swtpm Python test framework > (./test/py/test.py --bd qemu_arm64 -k "test_wolftpm and not ut_cmd"): > 19 passed, 2 skipped (matching doc/usage/cmd/wolftpm.rst). > - Manual QEMU arm64 + swtpm walkthrough per > doc/usage/cmd/wolftpm.rst section "Building and Running wolfTPM > with U-Boot using QEMU": tpm2 help/info/autostart/startup/ > get_capability/pcr_read/pcr_print/caps all return expected output. > - Raspberry Pi 4 + Infineon SLB9672 (real hardware): all wolfTPM > cmd tests pass, including firmware update path. > > v2 thread: > https://lore.kernel.org/u-boot/?q=PATCH+v2+tpm+wolfTPM > > Aidan Garske (12): > 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 > dts: add TPM device tree nodes for RPi4, QEMU, and sandbox > 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: enable wolfTPM in rpi_4_defconfig > > -- > 2.47.3 > ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 2026-05-11 9:15 ` [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Peter Robinson @ 2026-05-11 10:09 ` Peter Robinson 0 siblings, 0 replies; 18+ messages in thread From: Peter Robinson @ 2026-05-11 10:09 UTC (permalink / raw) To: Aidan Garske; +Cc: u-boot, David Garske, Ilias Apalodimas On Mon, 11 May 2026 at 10:15, Peter Robinson <pbrobinson@gmail.com> wrote: > > Hi Aidan, > > > This is v3 of the wolfTPM TPM 2.0 stack integration for U-Boot. > > > > wolfTPM (https://github.com/wolfSSL/wolfTPM) is a portable, GPLv2 TPM 2.0 > > I go to the github link and it says GPL-3.0 license so which is it? > > IANAL but I'm not sure if the GPLv3 is compatible with GPLv2 in the > context of U-Boot because it would make the whole output a GPLv3 > application In fact the majority of U-Boot code, like Linux, is GPLv2 only, not later which makes this directly incompatible with U-Boot. > > 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 backend behind the existing > > 'tpm2' command, alongside support for QEMU+swtpm, sandbox emulation, and > > real Raspberry Pi 4 + Infineon SLB9672 hardware. > > So that provides the technical detail, but what value does it provide > to U-Boot? We already have a relatively complete TPM stack, do people > do firmware updates in the early boot process, why else would someone > choose to use this over the existing implementation? > > One part of what I want to know in a cover letter is what value this > provides to the project, what are the pros/cons etc, like what > maintenance looks like. > > Peter > > > Branch (full 14-commit history including the subtree squash + merge): > > https://github.com/aidangarske/u-boot wolftpm-v2-patches > > > > Note on the subtree commits omitted from this email thread: > > The branch above contains 14 commits; the email series is 12 patches. > > Two commits are deliberately not sent to the list: > > > > * "Squashed 'lib/wolftpm/' content from commit 664db130d57" > > - the parentless squash commit produced by `git subtree add`. > > Its diff is ~3.4MB / ~90k lines and would be rejected by the > > mailing list on size. > > * "Merge commit 'd42fd7b146...' as 'lib/wolftpm'" > > - the corresponding subtree merge commit. Merges have no patch > > form and are routinely omitted by `git format-patch`. > > > > Please pull from the branch above (or wolfssl/wolfTPM @ 664db130d57) > > to inspect the imported wolfTPM source. Subsequent updates will go > > via tools/update-subtree.sh, matching how mbedTLS, lwIP, and > > dts/upstream are maintained in tree. > > > > Changes since v2: > > - Replaced the lib/wolftpm git submodule with a git subtree import > > (squash + merge), matching the convention used for mbedTLS, lwIP, > > and dts/upstream. tools/update-subtree.sh is updated to know > > about the wolftpm subtree (path lib/wolftpm, upstream > > https://github.com/wolfssl/wolfTPM.git). > > [feedback: Ilias Apalodimas] > > - Reverted the changes to include/linux/byteorder/generic.h. The > > redefinition workaround for cpu_to_beXX / beXX_to_cpu now lives > > on the wolfTPM side: include/configs/user_settings.h pulls in > > <asm/byteorder.h> up front so U-Boot's macros are defined before > > wolfTPM's #ifndef-guarded fallbacks in tpm2_packet.h. > > [feedback: Ilias Apalodimas] > > > > Testing: > > - QEMU arm64 + swtpm Python test framework > > (./test/py/test.py --bd qemu_arm64 -k "test_wolftpm and not ut_cmd"): > > 19 passed, 2 skipped (matching doc/usage/cmd/wolftpm.rst). > > - Manual QEMU arm64 + swtpm walkthrough per > > doc/usage/cmd/wolftpm.rst section "Building and Running wolfTPM > > with U-Boot using QEMU": tpm2 help/info/autostart/startup/ > > get_capability/pcr_read/pcr_print/caps all return expected output. > > - Raspberry Pi 4 + Infineon SLB9672 (real hardware): all wolfTPM > > cmd tests pass, including firmware update path. > > > > v2 thread: > > https://lore.kernel.org/u-boot/?q=PATCH+v2+tpm+wolfTPM > > > > Aidan Garske (12): > > 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 While I understand why you would put the above patch in it should in fact be sent on it's own as a standalone patch because it's really nothing to with this series. > > dts: add TPM device tree nodes for RPi4, QEMU, and sandbox > > 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: enable wolfTPM in rpi_4_defconfig > > > > -- > > 2.47.3 > > ^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2026-05-11 10:09 UTC | newest] Thread overview: 18+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-05-09 0:04 [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Aidan Garske 2026-05-09 0:04 ` [PATCH v3 01/12] tpm: export tpm_show_device, tpm_set_device, and get_tpm Aidan Garske 2026-05-09 0:04 ` [PATCH v3 02/12] include/hash: add SHA384 hash wrapper declaration for wolfTPM Aidan Garske 2026-05-09 0:04 ` [PATCH v3 03/12] spi: add BCM2835/BCM2711 hardware SPI controller driver Aidan Garske 2026-05-11 8:50 ` Peter Robinson 2026-05-09 0:04 ` [PATCH v3 04/12] dts: add TPM device tree nodes for RPi4, QEMU, and sandbox Aidan Garske 2026-05-11 8:26 ` Peter Robinson 2026-05-09 0:04 ` [PATCH v3 05/12] tpm: add wolfTPM build rules and Kconfig Aidan Garske 2026-05-09 0:04 ` [PATCH v3 06/12] tpm: add wolfTPM headers and SHA384 glue code Aidan Garske 2026-05-09 0:04 ` [PATCH v3 07/12] tpm: add wolfTPM driver helpers and Kconfig options Aidan Garske 2026-05-09 0:04 ` [PATCH v3 08/12] cmd: refactor tpm2 command into frontend/backend architecture Aidan Garske 2026-05-09 0:04 ` [PATCH v3 09/12] tpm: add sandbox TPM SPI emulator Aidan Garske 2026-05-09 0:04 ` [PATCH v3 10/12] test: add wolfTPM C unit tests and Python integration tests Aidan Garske 2026-05-09 0:04 ` [PATCH v3 11/12] doc: add wolfTPM documentation Aidan Garske 2026-05-09 0:04 ` [PATCH v3 12/12] configs: enable wolfTPM in rpi_4_defconfig Aidan Garske 2026-05-11 8:22 ` Peter Robinson 2026-05-11 9:15 ` [PATCH v3 00/12] tpm: Add wolfTPM library support for TPM 2.0 Peter Robinson 2026-05-11 10:09 ` Peter Robinson
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.