Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions .github/workflows/wolfhal-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
name: wolfHAL Build Tests

on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]
types: [opened, synchronize, reopened, ready_for_review]
repository_dispatch:
types: [nightly-trigger]

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
# Cross compile hal/tpm_io_wolfhal.c for a bare metal target against the real
# wolfHAL headers. A host build cannot cover this: __linux__ wins the platform
# selection chain in hal/tpm_io.c, so the wolfHAL branch is never reached.
cross-compile:
name: Cross compile (arm-none-eabi)
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout wolfTPM
uses: actions/checkout@v4

- name: Install ARM toolchain
uses: ./.github/actions/apt-retry
with:
packages: gcc-arm-none-eabi

- name: Checkout wolfHAL
uses: actions/checkout@v4
with:
repository: wolfSSL/wolfHAL
ref: main
path: wolfHAL

# wolfTPM does not ship board definitions, so stand in for the board.h an
# application would provide. Doubles as a check that the documented
# contract in hal/README.md is complete and sufficient.
#
# user_settings.h is needed because this is a bare metal build that never
# runs ./configure, so the generated wolftpm/options.h does not exist.
# WOLFTPM_USER_SETTINGS selects this header instead, which is the same
# path a real wolfHAL application takes.
- name: Generate test board.h and user_settings.h
run: |
mkdir -p test-board
cat > test-board/user_settings.h <<'EOF'
#ifndef TEST_USER_SETTINGS_H
#define TEST_USER_SETTINGS_H
/* Build options come from the compiler command line below. */
#endif
EOF
cat > test-board/board.h <<'EOF'
#ifndef TEST_BOARD_H
#define TEST_BOARD_H
#include <wolfHAL/wolfHAL.h>
extern whal_Spi g_spi;
extern whal_Gpio g_gpio;
extern whal_I2c g_i2c;
extern whal_Spi_ComCfg g_spiComCfg;
extern whal_I2c_ComCfg g_i2cComCfg;
#define BOARD_SPI_DEV (&g_spi)
#define BOARD_SPI_COM_CFG (&g_spiComCfg)
#define BOARD_GPIO_DEV (&g_gpio)
#define BOARD_CS_PIN 15
#define BOARD_I2C_DEV (&g_i2c)
#define BOARD_I2C_COM_CFG (&g_i2cComCfg)
#endif
EOF

- name: Build
run: |
set -e
INC="-Itest-board -IwolfHAL -I. -Ihal"
BASE="-mcpu=cortex-m4 -mthumb -Wall -Wextra -Werror
-Wmissing-prototypes -Wconversion -Wno-unused-parameter
-DWOLFTPM_WOLFHAL -DWOLFTPM_EXAMPLE_HAL -DWOLFTPM_USER_SETTINGS
-DWOLFTPM2_NO_WOLFCRYPT -DNO_FILESYSTEM"
build() {
name="$1"; shift
echo "::group::$name"
arm-none-eabi-gcc -c -o /dev/null $BASE $INC "$@" hal/tpm_io.c
echo "::endgroup::"
}
build "SPI, wait state" -DWOLFTPM_CHECK_WAIT_STATE
build "SPI, no wait state"
build "SPI, verbose" -DWOLFTPM_CHECK_WAIT_STATE -DWOLFTPM_DEBUG_VERBOSE -DWOLFTPM_DEBUG_TIMEOUT
build "I2C" -DWOLFTPM_I2C -DWOLFTPM_ADV_IO
build "I2C, verbose" -DWOLFTPM_I2C -DWOLFTPM_ADV_IO -DWOLFTPM_DEBUG_VERBOSE

# The board.h contract is enforced by #error guards. Verify a missing
# entry is reported by name rather than as a confusing undeclared symbol.
- name: Check board.h guards report missing macros
run: |
set -e
mkdir -p bad-board
sed '/BOARD_CS_PIN/d' test-board/board.h > bad-board/board.h
cp test-board/user_settings.h bad-board/
if arm-none-eabi-gcc -fsyntax-only -mcpu=cortex-m4 -mthumb \
-Ibad-board -IwolfHAL -I. -Ihal \
-DWOLFTPM_WOLFHAL -DWOLFTPM_EXAMPLE_HAL -DWOLFTPM_USER_SETTINGS \
-DWOLFTPM2_NO_WOLFCRYPT -DNO_FILESYSTEM -DWOLFTPM_INCLUDE_IO_FILE \
hal/tpm_io_wolfhal.c 2> guard.log; then
echo "FAIL: expected a compile error for the missing macro"
exit 1
fi
grep -q "board.h must define BOARD_CS_PIN" guard.log || {
echo "FAIL: guard did not name BOARD_CS_PIN"; cat guard.log; exit 1; }
echo "PASS: guard named the missing macro"

# Verify --enable-wolfhal wires up, and that enabling it does not disturb an
# ordinary host build. On Linux the wolfHAL branch is not selected, so
# tpm_io_wolfhal.c must compile to an empty translation unit with no wolfHAL
# headers present. This covers the hal/include.am and configure.ac wiring.
autotools:
name: Autotools (--enable-wolfhal)
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout wolfTPM
uses: actions/checkout@v4

- name: Setup wolfSSL
uses: ./.github/actions/setup-wolfssl

- name: Build with --enable-wolfhal (SPI)
run: |
set -e
./autogen.sh
./configure --enable-wolfhal | tee conf.log
grep -q "wolfHAL IO: *yes" conf.log || {
echo "FAIL: config summary did not report wolfHAL as enabled"; exit 1; }
make -j$(nproc)

- name: Build with --enable-wolfhal --enable-i2c
run: |
set -e
make distclean || true
./autogen.sh
./configure --enable-wolfhal --enable-i2c
make -j$(nproc)
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Portable TPM 2.0 project designed for embedded use.
* wolfTPM uses the TPM Interface Specification (TIS) to communicate either over SPI, or using a memory mapped I/O range.
* On Linux, wolfTPM auto-detects between the kernel TPM driver (`/dev/tpmX`) and direct SPI access at runtime - a simple `./configure && make` works with either interface.
* wolfTPM can also use the Linux TPM kernel interface (`/dev/tpmX`) to talk with any physical TPM on SPI, I2C and even LPC bus.
* Platform support for Raspberry Pi (Linux), MMIO, STM32 with CubeMX, Atmel ASF, Xilinx, QNX Infineon TriCore and Barebox.
* Platform support for Raspberry Pi (Linux), MMIO, STM32 with CubeMX, Atmel ASF, Xilinx, QNX, Infineon TriCore, wolfHAL and Barebox.
* The design allows for easy portability to different platforms:
* Native C code designed for embedded use.
* Single IO callback for hardware SPI interface.
Expand Down Expand Up @@ -223,6 +223,7 @@ There are HAL examples in `hal` directory for:
* Infineon TriCore
* Linux
* STM32 CubeMX
* wolfHAL
* Xilinx

We also support an advanced IO option (`--enable-advio`/`WOLFTPM_ADV_IO`), which adds the register and read/write flag as parameter to the IO callback. This is required for I2C support.
Expand Down Expand Up @@ -329,6 +330,9 @@ make install
this flag adds no compile-time macro but disables the auto-enabled swTPM/fwTPM defaults. (default: not set)
--enable-i2c Enable I2C TPM Support (default: disabled, requires advio) - WOLFTPM_I2C
--enable-mmio Enable built-in MMIO callbacks (default: disabled) - WOLFTPM_MMIO
--enable-wolfhal Enable wolfHAL IO callbacks (default: disabled) - WOLFTPM_WOLFHAL
Requires the wolfHAL headers and an application provided board.h.
See hal/README.md for the required BOARD_* definitions.
--enable-checkwaitstate Enable TIS / SPI Check Wait State support (default: depends on chip) - WOLFTPM_CHECK_WAIT_STATE
--enable-smallstack Enable options to reduce stack usage
--enable-tislock Enable Linux Named Semaphore for locking access to SPI device for concurrent access between processes - WOLFTPM_TIS_LOCK
Expand Down
15 changes: 15 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,20 @@ then
fi


# wolfHAL hardware abstraction layer
# Selects hal/tpm_io_wolfhal.c for SPI/I2C. Requires wolfHAL headers and a
# board.h supplying the BOARD_* peripheral definitions.
AC_ARG_ENABLE([wolfhal],
[AS_HELP_STRING([--enable-wolfhal],[Enable wolfHAL IO callbacks (default: disabled)])],
[ ENABLED_WOLFHAL=$enableval ],
[ ENABLED_WOLFHAL=no ]
)
if test "x$ENABLED_WOLFHAL" = "xyes"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_WOLFHAL"
fi


# TIS / SPI Check Wait State support
# Required for all but Infineon only
if test "x$ENABLED_CHECKWAITSTATE" = "xyes" || test "x$ENABLED_AUTODETECT" = "xyes" || test "x$ENABLED_INFINEON" = "xno"
Expand Down Expand Up @@ -1171,6 +1185,7 @@ fi
echo " * WINAPI: $ENABLED_WINAPI"
echo " * TIS/SPI Check Wait State: $ENABLED_CHECKWAITSTATE"
echo " * HAL Reset (nRST GPIO): $ENABLED_HAL_RESET"
echo " * wolfHAL IO: $ENABLED_WOLFHAL"

echo " * Infineon SLB967X $ENABLED_INFINEON"
echo " * STM ST33: $ENABLED_ST"
Expand Down
67 changes: 67 additions & 0 deletions hal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,75 @@ If using a HAL IO callback it is registered on library initialization using:
| Microchip | `tpm_io_microchip.c` | `WOLFTPM_MICROCHIP_HARMONY` |
| QNX | `tpm_io_qnx.c` | `__QNX__` |
| ST Cube HAL | `tpm_io_st.c` | `WOLFSSL_STM32_CUBEMX` |
| wolfHAL | `tpm_io_wolfhal.c` | `WOLFTPM_WOLFHAL` |
| Xilinx | `tpm_io_xilinx.c` | `__XILINX__` |

## wolfHAL

Enabled with `WOLFTPM_WOLFHAL` or `--enable-wolfhal`. Requires the wolfHAL
headers on the include path.

This HAL is placed last in the platform selection chain, so it is only used
when no other platform macro is defined. Building for an STM32 target with the
CubeMX headers present, for example, selects `tpm_io_st.c` instead.

### Board definitions

wolfTPM does not ship board definitions. `tpm_io_wolfhal.c` includes
`"board.h"`, which the application provides on its include path. A wolfHAL
project already has one, so in most cases only the TPM specific entries below
need adding to it.

For SPI:

| Macro | Type | Description |
| ----- | ---- | ----------- |
| `BOARD_SPI_DEV` | `whal_Spi*` | SPI instance the TPM is connected to |
| `BOARD_SPI_COM_CFG` | `whal_Spi_ComCfg*` | SPI session parameters |
| `BOARD_GPIO_DEV` | `whal_Gpio*` | GPIO instance driving chip select |
| `BOARD_CS_PIN` | pin number | Chip select pin, driven active low |

For I2C (also requires `WOLFTPM_ADV_IO`, which `--enable-i2c` sets):

| Macro | Type | Description |
| ----- | ---- | ----------- |
| `BOARD_I2C_DEV` | `whal_I2c*` | I2C instance the TPM is connected to |
| `BOARD_I2C_COM_CFG` | `whal_I2c_ComCfg*` | I2C session parameters, including the TPM target address |

The TPM target address goes in the `addr` field of `BOARD_I2C_COM_CFG`, not in
a wolfTPM macro. Most TPM 2.0 I2C parts use `0x2e`.

A TPM 2.0 I2C part takes roughly 80us to wake and NAKs until it is ready, so
each transfer is retried up to `TPM_I2C_TRIES` times (default 10). Define
`TPM_I2C_TRIES` to override.

A missing entry is reported at compile time, naming the macro required. Only
the macros needed by the selected bus are checked.

Example additions to an existing wolfHAL `board.h`:

```c
/* TPM on SPI1, chip select on PA15 */
extern whal_Spi_ComCfg g_tpmSpiComCfg;
#define BOARD_SPI_COM_CFG (&g_tpmSpiComCfg)
#define BOARD_CS_PIN 15
```

For I2C, where the session config carries the TPM address:

```c
/* board.c */
whal_I2c_ComCfg g_tpmI2cComCfg = {
.freq = 400000, /* Hz */
.addr = 0x2e, /* TPM target address */
.addrSz = 7, /* bits */
};

/* board.h */
extern whal_I2c_ComCfg g_tpmI2cComCfg;
#define BOARD_I2C_COM_CFG (&g_tpmI2cComCfg)
```

## HAL IO Callback Function

Here are the prototypes for the HAL callback function:
Expand Down
1 change: 1 addition & 0 deletions hal/include.am
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ src_libwolftpm_la_SOURCES += \
hal/tpm_io_st.c \
hal/tpm_io_qnx.c \
hal/tpm_io_uboot.c \
hal/tpm_io_wolfhal.c \
hal/tpm_io_xilinx.c
endif
endif
Expand Down
6 changes: 6 additions & 0 deletions hal/tpm_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@
#include "hal/tpm_io_espressif.c"
#elif defined(WOLFSSL_ZEPHYR)
#include "hal/tpm_io_zephyr.c"
#elif defined(WOLFTPM_WOLFHAL)
#include "hal/tpm_io_wolfhal.c"
#endif

#if !defined(WOLFTPM_I2C) && !defined(WOLFTPM_MMIO) && !defined(WOLFTPM_FWTPM_HAL)
Expand Down Expand Up @@ -107,6 +109,8 @@ static int TPM2_IoCb_SPI(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf,
ret = TPM2_IoCb_Microchip_SPI(ctx, txBuf, rxBuf, xferSz, userCtx);
#elif defined(WOLFSSL_ESPIDF)
ret = TPM2_IoCb_Espressif_SPI(ctx, txBuf, rxBuf, xferSz, userCtx);
#elif defined(WOLFTPM_WOLFHAL)
ret = TPM2_IoCb_Wolfhal_SPI(ctx, txBuf, rxBuf, xferSz, userCtx);
#else

/* TODO: Add your platform here for HW SPI interface */
Expand Down Expand Up @@ -167,6 +171,8 @@ int TPM2_IoCb(TPM2_CTX* ctx, INT32 isRead, UINT32 addr,
ret = TPM2_IoCb_MicrochipHarmony_I2C(ctx, isRead, addr, buf, size, userCtx);
#elif defined(WOLFSSL_ZEPHYR)
ret = TPM2_IoCb_Zephyr_I2C(ctx, isRead, addr, buf, size, userCtx);
#elif defined(WOLFTPM_WOLFHAL)
ret = TPM2_IoCb_Wolfhal_I2C(ctx, isRead, addr, buf, size, userCtx);
#else
/* TODO: Add your platform here for HW I2C interface */
printf("Add your platform here for HW I2C interface\n");
Expand Down
6 changes: 6 additions & 0 deletions hal/tpm_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ WOLFTPM_LOCAL int TPM2_IoCb_MicrochipHarmony_I2C(TPM2_CTX* ctx, int isRead, word
#elif defined(WOLFSSL_ZEPHYR)
WOLFTPM_LOCAL int TPM2_IoCb_Zephyr_I2C(TPM2_CTX* ctx, int isRead, word32 addr,
byte* buf, word16 size, void* userCtx);
#elif defined(WOLFTPM_WOLFHAL)
WOLFTPM_LOCAL int TPM2_IoCb_Wolfhal_I2C(TPM2_CTX* ctx, int isRead, word32 addr,
byte* buf, word16 size, void* userCtx);
#endif /* __linux__ */

#else /* SPI */
Expand Down Expand Up @@ -129,6 +132,9 @@ WOLFTPM_LOCAL int TPM2_IoCb_Infineon_TriCore_SPI(TPM2_CTX* ctx, const byte* txBu
#elif defined(WOLFTPM_MICROCHIP_HARMONY)
WOLFTPM_LOCAL int TPM2_IoCb_Microchip_SPI(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf,
word16 xferSz, void* userCtx);
#elif defined(WOLFTPM_WOLFHAL)
WOLFTPM_LOCAL int TPM2_IoCb_Wolfhal_SPI(TPM2_CTX* ctx, const byte* txBuf,
byte* rxBuf, word16 xferSz, void* userCtx);
#endif

#endif /* WOLFTPM_I2C */
Expand Down
Loading
Loading