Skip to content

Commit 66d22f4

Browse files
committed
Add optional TPM nRST reset HAL and document ST33-on-Pi wiring
1 parent d8993ae commit 66d22f4

8 files changed

Lines changed: 181 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: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,29 @@ 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;
249+
#if defined(__linux__)
250+
ret = TPM2_IoCb_Linux_Reset(ctx, userCtx);
251+
#else
252+
/* No reset HAL for this OS - return NOT_COMPILED_IN so callers can tell it
253+
* apart from a genuine reset failure (TPM_RC_FAILURE) on a supported OS. */
254+
(void)ctx;
255+
(void)userCtx;
256+
ret = NOT_COMPILED_IN;
257+
#ifdef DEBUG_WOLFTPM
258+
printf("TPM reset HAL not implemented for this platform\n");
259+
#endif
260+
#endif
261+
return ret;
262+
}
263+
#endif /* WOLFTPM_HAL_RESET */
264+
242265
#endif /* !(WOLFTPM_LINUX_DEV || WOLFTPM_SWTPM || WOLFTPM_WINAPI) */
243266

244267
/******************************************************************************/

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: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@
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+
#include <time.h> /* nanosleep (usleep is undefined for >= 1s) */
71+
#endif
6772

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

0 commit comments

Comments
 (0)