Skip to content

Commit c631dab

Browse files
committed
Add optional TPM nRST reset HAL and document ST33-on-Pi wiring
1 parent 68c9bd1 commit c631dab

8 files changed

Lines changed: 167 additions & 4 deletions

File tree

.github/workflows/make-test-swtpm.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ jobs:
9999
# STMicro ST33KTPM2
100100
- name: st33ktpm2 firmware
101101
wolftpm_config: --enable-st33 --enable-firmware --disable-fwtpm
102+
# HAL nRST reset control (compile-only, no GPIO hardware in CI)
103+
- name: hal-reset
104+
wolftpm_config: --enable-st33 --enable-hal-reset --disable-fwtpm
105+
test_command: "true"
102106
# SPDM + Nuvoton (compile-only, no hardware in CI)
103107
- name: spdm-nuvoton
104108
wolfssl_config: --enable-wolftpm --enable-ecc --enable-sha384 --enable-aesgcm --enable-hkdf --enable-sp

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,8 @@ make
401401

402402
Note: The `--enable-firmware` option enables firmware upgrade support for ST33 TPMs. This adds the `st33_fw_update` example tool for performing firmware updates.
403403

404+
Raspberry Pi wiring: ST33KTPM2X SPI is on `/dev/spidev0.0` with `nRST` (active low) on GPIO24 (pin 18); Nuvoton uses GPIO4. Optionally drive nRST from code with `--enable-hal-reset` and `TPM2_IoCb_Reset()` (see `hal/README.md`).
405+
404406
### Building Microchip ATTPM20
405407

406408
Build wolfTPM:

configure.ac

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,32 @@ then
474474
AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_ST33"
475475
fi
476476

477+
# Optional TPM hardware reset (nRST) HAL control via Linux GPIO char device.
478+
# Accepts an optional GPIO line number (default ST33 GPIO24 / Pi pin 18, Nuvoton GPIO4).
479+
AC_ARG_ENABLE([hal-reset],
480+
[AS_HELP_STRING([--enable-hal-reset@<:@=LINE@:>@],[Enable TPM nRST reset HAL (optional GPIO line; default ST33 GPIO24, Nuvoton GPIO4) (default: disabled)])],
481+
[ ENABLED_HAL_RESET=$enableval ],
482+
[ ENABLED_HAL_RESET=no ]
483+
)
484+
if test "x$ENABLED_HAL_RESET" != "xno"
485+
then
486+
# The reset HAL implementation (hal/tpm_io.c) only builds for the SPI/I2C
487+
# example HAL, not the native kernel (/dev/tpm0) or swtpm transports, so
488+
# reject those combinations rather than report "yes" with no callable API.
489+
# Note swtpm is the default on Linux x86_64/aarch64, so the hardware reset
490+
# HAL requires explicitly selecting a hardware interface (--enable-spi/-i2c).
491+
if test "x$ENABLED_DEVTPM" = "xyes" || test "x$ENABLED_SWTPM" = "xyes" || test "x$ENABLED_SWTPM" = "xuart"
492+
then
493+
AC_MSG_ERROR([--enable-hal-reset needs the SPI/I2C hardware HAL; it is not available with the swtpm simulator (default on Linux x86_64/aarch64) or --enable-devtpm. Select a hardware interface, e.g. --enable-spi or --enable-i2c.])
494+
fi
495+
AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_HAL_RESET"
496+
case "x$ENABLED_HAL_RESET" in
497+
xyes) ;;
498+
*) AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_RESET_LINE=$ENABLED_HAL_RESET" ;;
499+
esac
500+
ENABLED_HAL_RESET=yes
501+
fi
502+
477503
# Microchip ATTPM20
478504
AC_ARG_ENABLE([mchp],,
479505
[ ENABLED_MCHP=$enableval ],
@@ -1132,6 +1158,7 @@ if test "x$ENABLED_SWTPM" = "xyes"; then
11321158
fi
11331159
echo " * WINAPI: $ENABLED_WINAPI"
11341160
echo " * TIS/SPI Check Wait State: $ENABLED_CHECKWAITSTATE"
1161+
echo " * HAL Reset (nRST GPIO): $ENABLED_HAL_RESET"
11351162

11361163
echo " * Infineon SLB967X $ENABLED_INFINEON"
11371164
echo " * STM ST33: $ENABLED_ST"

examples/spdm/README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,17 @@ effect. The reset pin must be connected and controllable by the host.
9898
to a host-controllable GPIO. Without reset pin control, SPDM mode changes
9999
cannot be applied and recovery from SPDM-only mode is not possible.
100100

101-
### Raspberry Pi Example (GPIO 4)
101+
The reset line is board specific. On a Raspberry Pi, Nuvoton uses GPIO4 and the
102+
ST33KTPM uses GPIO24 (pin 18); confirm your wiring before toggling.
102103

103104
```bash
104-
# Assert reset low, wait, release high, wait for TPM startup
105+
# Assert reset low, release high, wait for TPM startup (Nuvoton GPIO4 shown)
105106
gpioset gpiochip0 4=0 && sleep 0.1 && gpioset gpiochip0 4=1 && sleep 2
107+
# ST33: use line 24 instead of 4
106108
```
107109

108-
Other platforms will use their own GPIO control mechanism. The key requirement
109-
is toggling the TPM reset line (active low) with sufficient hold time.
110+
wolfTPM can also drive this from code: build with `--enable-hal-reset` and call
111+
`TPM2_IoCb_Reset()` (default line: ST33 GPIO24, Nuvoton GPIO4). See `hal/README.md`.
110112

111113
## Automated Test Suite
112114

hal/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ int TPM2_IoCb(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf,
5959
* `WOLFTPM_CHECK_WAIT_STATE`: Enables check of the wait state during a SPI transaction. Most TPM 2.0 chips require this and typically only require 0-2 wait cycles depending on the command. Only the Infineon TPM's guarantee no wait states.
6060
* `WOLFTPM_ADV_IO`: Enables advanced IO callback mode that includes TIS register and read/write flag. This is requires for I2C, but can be used with SPI also.
6161
* `WOLFTPM_DEBUG_IO`: Enable logging of the IO (if using the example HAL).
62+
* `WOLFTPM_HAL_RESET`: Optional TPM hardware reset (nRST) control in the example HAL (`--enable-hal-reset`). On Linux, `TPM2_IoCb_Reset(&dev->ctx, userCtx)` pulses nRST (active low) via the GPIO char device (raw GPIO v2 uAPI, no libgpiod).
63+
64+
## TPM reset (nRST) HAL macros (when `WOLFTPM_HAL_RESET` is set)
65+
66+
* `WOLFTPM_RESET_GPIOCHIP`: GPIO char device. Default: `/dev/gpiochip0`
67+
* `WOLFTPM_RESET_LINE`: GPIO line wired to nRST. Default: ST33 = `24` (GPIO24, Pi pin 18), Nuvoton = `4` (GPIO4). Also settable via `--enable-hal-reset=<line>`.
68+
* `WOLFTPM_RESET_HOLD_US` / `WOLFTPM_RESET_SETTLE_US`: reset hold / post-reset settle time (us). Defaults: `300000` / `1000000`.
6269

6370
## Additional Compiler macros
6471

hal/tpm_io.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,26 @@ int TPM2_IoCb(TPM2_CTX* ctx, const BYTE* txBuf, BYTE* rxBuf,
239239
}
240240

241241
#endif /* WOLFTPM_ADV_IO */
242+
243+
#ifdef WOLFTPM_HAL_RESET
244+
/* Pulse the TPM hardware reset (nRST) line to reset the TPM. Dispatches to the
245+
* platform implementation. Returns TPM_RC_SUCCESS on success. */
246+
int TPM2_IoCb_Reset(TPM2_CTX* ctx, void* userCtx)
247+
{
248+
int ret = TPM_RC_FAILURE;
249+
#if defined(__linux__)
250+
ret = TPM2_IoCb_Linux_Reset(ctx, userCtx);
251+
#else
252+
(void)ctx;
253+
(void)userCtx;
254+
#ifdef DEBUG_WOLFTPM
255+
printf("TPM reset HAL not implemented for this platform\n");
256+
#endif
257+
#endif
258+
return ret;
259+
}
260+
#endif /* WOLFTPM_HAL_RESET */
261+
242262
#endif /* !(WOLFTPM_LINUX_DEV || WOLFTPM_SWTPM || WOLFTPM_WINAPI) */
243263

244264
/******************************************************************************/

hal/tpm_io.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,15 @@ WOLFTPM_LOCAL int TPM2_IoCb_FwTPM(TPM2_CTX* ctx, int isRead, word32 addr,
145145
byte* buf, word16 size, void* userCtx);
146146
#endif
147147

148+
#ifdef WOLFTPM_HAL_RESET
149+
/* Optional TPM hardware reset (nRST) control. Pulses the reset line to reset
150+
* the TPM. Enable with --enable-hal-reset (-DWOLFTPM_HAL_RESET). */
151+
WOLFTPM_API int TPM2_IoCb_Reset(TPM2_CTX* ctx, void* userCtx);
152+
#if defined(__linux__)
153+
WOLFTPM_LOCAL int TPM2_IoCb_Linux_Reset(TPM2_CTX* ctx, void* userCtx);
154+
#endif
155+
#endif
156+
148157
#endif /* WOLFTPM_EXAMPLE_HAL */
149158
#endif /* !(WOLFTPM_LINUX_DEV || WOLFTPM_SWTPM || WOLFTPM_WINAPI) */
150159

hal/tpm_io_linux.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@
6464
#include <fcntl.h>
6565
#include <unistd.h>
6666
#include <errno.h>
67+
#ifdef WOLFTPM_HAL_RESET
68+
/* GPIO character-device uAPI for optional nRST control */
69+
#include <linux/gpio.h>
70+
#endif
6771

6872
#ifdef WOLFTPM_I2C
6973
/* I2C - (Only tested with SLB9673 and ST33 I2C) */
@@ -415,6 +419,94 @@
415419
return ret;
416420
}
417421
#endif /* WOLFTPM_I2C */
422+
423+
#ifdef WOLFTPM_HAL_RESET
424+
/* Pulse the TPM nRST (active low) via the Linux GPIO char device (raw GPIO
425+
* v2 uAPI, no libgpiod). Default line: Raspberry Pi ST33 = GPIO24 (pin 18),
426+
* Nuvoton = GPIO4; override with WOLFTPM_RESET_GPIOCHIP / WOLFTPM_RESET_LINE. */
427+
#ifndef WOLFTPM_RESET_GPIOCHIP
428+
#define WOLFTPM_RESET_GPIOCHIP "/dev/gpiochip0"
429+
#endif
430+
#ifndef WOLFTPM_RESET_LINE
431+
#if defined(WOLFTPM_NUVOTON)
432+
#define WOLFTPM_RESET_LINE 4
433+
#else
434+
#define WOLFTPM_RESET_LINE 24
435+
#endif
436+
#endif
437+
#ifndef WOLFTPM_RESET_HOLD_US
438+
#define WOLFTPM_RESET_HOLD_US 300000 /* reset asserted 300ms */
439+
#endif
440+
#ifndef WOLFTPM_RESET_SETTLE_US
441+
#define WOLFTPM_RESET_SETTLE_US 1000000 /* TPM boot settle 1s */
442+
#endif
443+
444+
int TPM2_IoCb_Linux_Reset(TPM2_CTX* ctx, void* userCtx)
445+
{
446+
int ret = TPM_RC_FAILURE;
447+
int chipFd, reqFd;
448+
struct gpio_v2_line_request req;
449+
struct gpio_v2_line_values vals;
450+
451+
(void)ctx;
452+
(void)userCtx;
453+
454+
chipFd = open(WOLFTPM_RESET_GPIOCHIP, O_RDONLY);
455+
if (chipFd < 0) {
456+
#ifdef DEBUG_WOLFTPM
457+
printf("TPM Reset: open %s failed (errno %d)\n",
458+
WOLFTPM_RESET_GPIOCHIP, errno);
459+
#endif
460+
return TPM_RC_FAILURE;
461+
}
462+
463+
/* Acquire the line as an output driven low (assert reset) */
464+
XMEMSET(&req, 0, sizeof(req));
465+
req.offsets[0] = (unsigned int)WOLFTPM_RESET_LINE;
466+
req.num_lines = 1;
467+
req.config.flags = GPIO_V2_LINE_FLAG_OUTPUT;
468+
req.config.num_attrs = 1;
469+
req.config.attrs[0].attr.id = GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES;
470+
req.config.attrs[0].attr.values = 0; /* drive low (assert reset) */
471+
req.config.attrs[0].mask = 1; /* applies to line index 0 */
472+
XMEMCPY(req.consumer, "wolfTPM-reset", sizeof("wolfTPM-reset"));
473+
474+
if (ioctl(chipFd, GPIO_V2_GET_LINE_IOCTL, &req) < 0 || req.fd < 0) {
475+
#ifdef DEBUG_WOLFTPM
476+
printf("TPM Reset: GET_LINE ioctl failed (errno %d)\n", errno);
477+
#endif
478+
close(chipFd);
479+
return TPM_RC_FAILURE;
480+
}
481+
close(chipFd);
482+
reqFd = req.fd;
483+
484+
/* Hold reset asserted, then release (drive high) and let the TPM boot */
485+
usleep(WOLFTPM_RESET_HOLD_US);
486+
487+
XMEMSET(&vals, 0, sizeof(vals));
488+
vals.mask = 1;
489+
vals.bits = 1; /* drive high = release reset */
490+
if (ioctl(reqFd, GPIO_V2_LINE_SET_VALUES_IOCTL, &vals) < 0) {
491+
#ifdef DEBUG_WOLFTPM
492+
printf("TPM Reset: SET_VALUES ioctl failed (errno %d)\n", errno);
493+
#endif
494+
}
495+
else {
496+
ret = TPM_RC_SUCCESS;
497+
#ifdef DEBUG_WOLFTPM
498+
printf("TPM Reset: pulsed nRST on %s line %d\n",
499+
WOLFTPM_RESET_GPIOCHIP, (int)WOLFTPM_RESET_LINE);
500+
#endif
501+
}
502+
503+
usleep(WOLFTPM_RESET_SETTLE_US);
504+
close(reqFd);
505+
506+
return ret;
507+
}
508+
#endif /* WOLFTPM_HAL_RESET */
509+
418510
#endif /* __linux__ */
419511
#endif /* !(WOLFTPM_LINUX_DEV || WOLFTPM_SWTPM || WOLFTPM_WINAPI) */
420512
#endif /* WOLFTPM_INCLUDE_IO_FILE */

0 commit comments

Comments
 (0)