Hi Aidan,
On 2026-05-13T00:26:04, Aidan Garske <[email protected]> wrote:
> tpm: add sandbox TPM SPI emulator
>
> Add a TPM SPI emulator for sandbox testing that implements the TIS
> (TPM Interface Specification) SPI protocol, allowing wolfTPM's SPI
> HAL code to be tested without physical hardware.
>
> drivers/tpm/tpm_spi_sandbox.c (new):
> Emulates a TPM connected via SPI by implementing the TIS register
> set and SPI protocol:
> - SPI protocol state machine: parses 4-byte TIS SPI headers
> (R/W bit, transfer length, register address) and handles data
> phase with immediate ready signaling (no wait states)
> - TIS register emulation: TPM_ACCESS (locality request/grant),
> TPM_STS (command ready, data expect, data available, burst
> count), TPM_INTF_CAPS, TPM_DID_VID (Infineon SLB9670 IDs),
> TPM_RID, and TPM_DATA_FIFO (command/response buffering)
> - TIS state machine: IDLE -> READY -> RECEPTION -> EXECUTION ->
> COMPLETION, with command-ready abort support
> - Generates simple TPM_RC_SUCCESS responses (a full implementation
> would integrate the sandbox TPM2 state machine)
> [...]
>
> drivers/mtd/spi/sandbox.c | 30 +++-
> drivers/tpm/tpm_spi_sandbox.c | 410
> ++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 431 insertions(+), 9 deletions(-)
> diff --git a/drivers/tpm/tpm_spi_sandbox.c b/drivers/tpm/tpm_spi_sandbox.c
> @@ -0,0 +1,410 @@
> + * Generate a simple success response.
> + * A full implementation would call the
> + * sandbox TPM2 state machine here.
> + */
> + priv->rsp_buf[0] = 0x80; /* TPM_ST_NO_SESSIONS */
> + priv->rsp_buf[1] = 0x01;
> + priv->rsp_buf[2] = 0x00; /* Response size: 10 */
> + priv->rsp_buf[3] = 0x00;
> + priv->rsp_buf[4] = 0x00;
> + priv->rsp_buf[5] = 0x0A;
> + priv->rsp_buf[6] = 0x00; /* TPM_RC_SUCCESS */
> + priv->rsp_buf[7] = 0x00;
> + priv->rsp_buf[8] = 0x00;
> + priv->rsp_buf[9] = 0x00;
> + priv->rsp_len = 10;
Every command returns the same canned 10-byte TPM_RC_SUCCESS. Any test
exercising tpm2 get_capability, pcr_read, pcr_extend etc. would either
fail to parse the response or silently accept garbage as success.
As-is, this emulator just lets SPI bytes flow.
Please use lower-case hex.
The real sandbox TPM2 state machine already lives next door in
drivers/tpm/tpm2_tis_sandbox.c with sandbox_common.c. Please wire this
emulator into sandbox_tpm2_fill_buf() and the existing
nvdata/PCR/hierarchy logic so commands actually do what they say.
Otherwise the wolfTPM C unit tests in patch 12 can't meaningfully run
on sandbox.
> diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c
> @@ -571,16 +571,28 @@ int sandbox_spi_get_emul(struct sandbox_state *state,
> + struct udevice *emul;
> + ofnode node = dev_ofnode(slave);
> +
> + /* First check for sandbox,emul phandle property */
> + ret = uclass_get_device_by_phandle(UCLASS_SPI_EMUL, slave,
> + 'sandbox,emul', &emul);
> + if (!ret) {
> + debug("%s: busnum=%u, cs=%u: using phandle emulator\n",
> + __func__, busnum, cs);
> + info->emul = emul;
This is a generic change to sandbox SPI emulation that affects every
existing sandbox SPI user. Please split it into its own patch ahead of
this one, with a commit message justifying the sandbox,emul phandle
convention on its own terms, and ideally a doc update. Bundled with
the TPM emulator, the reasoning gets lost.
> diff --git a/drivers/tpm/tpm_spi_sandbox.c b/drivers/tpm/tpm_spi_sandbox.c
> @@ -0,0 +1,410 @@
> + /*
> + * Handle FIFO writes - the FIFO is at 0x0024 but any address
> + * from 0x0024 up to 0x0F00 can be used for FIFO access when
> + * doing multi-byte transfers (address auto-increments).
> + */
> + if (reg >= TPM_DATA_FIFO_REG && reg < TPM_DID_VID_REG) {
The comment doesn't match up - the TIS FIFO is a single register at
0x0024 and the address does not auto-increment; the host repeats the
same address while burst-count drains. Because the SPI layer does
priv->addr + priv->data_pos for every byte, you treat a 3000-byte
window as FIFO, which masks the issue but is wrong if anything reads
e.g. TPM_INT_ENABLE_REG (0x0008) - one of your #defines, is never
handled. Please hold priv->addr constant for FIFO accesses, and either
implement the other registers you've declared or drop the #defines.
> diff --git a/drivers/tpm/tpm_spi_sandbox.c b/drivers/tpm/tpm_spi_sandbox.c
> @@ -0,0 +1,410 @@
> +static const struct udevice_id sandbox_tpm_spi_slave_ids[] = {
> + { .compatible = 'sandbox,tpm-spi' },
> + { }
> +};
> +
> +U_BOOT_DRIVER(sandbox_tpm_spi) = {
> + .name = 'sandbox_tpm_spi',
> + .id = UCLASS_SPI_GENERIC,
> + .of_match = sandbox_tpm_spi_slave_ids,
> + .probe = sandbox_tpm_spi_slave_probe,
> +};
Why a UCLASS_SPI_GENERIC stub with a sandbox-specific compatible,
rather than reusing tcg,tpm_tis-spi so the existing tpm2_tis_spi.c
driver binds on top of the emulator? That would give actual U-Boot TPM
uclass coverage on sandbox (currently zero for the SPI path) and let
the standard ut dm tpm tests run against this emulator without wolfTPM
in the picture. As written, the slave driver exists only to make the
DT node bind, and the emulator only ever sees raw bytes from wolfTPM's
native HAL, so the U-Boot TPM stack still has no SPI sandbox coverage.
> diff --git a/drivers/tpm/tpm_spi_sandbox.c b/drivers/tpm/tpm_spi_sandbox.c
> @@ -0,0 +1,410 @@
> +/* Maximum buffer sizes */
> +#define TPM_CMD_BUF_SIZE 4096
> +#define TPM_RSP_BUF_SIZE 4096
These 4 KiB buffers live in priv_auto, which is fine, but the existing
sandbox TPM2 emulator caps responses at TPM2_MAX_BUF_SIZE in tpm-v2.h
— please reuse that rather than inventing new sizes, especially since
the goal is to integrate with that state machine.
Regards,
Simon