Skip to content

Add fwTPM example for Xilinx ZCU102 Cortex-R5 (lock-step)#3

Open
dgarske wants to merge 2 commits into
mainfrom
fwtpm_zcu102_r5
Open

Add fwTPM example for Xilinx ZCU102 Cortex-R5 (lock-step)#3
dgarske wants to merge 2 commits into
mainfrom
fwtpm_zcu102_r5

Conversation

@dgarske
Copy link
Copy Markdown
Member

@dgarske dgarske commented May 12, 2026

Summary

Adds two production-class wolfTPM firmware TPM (fwTPM) examples to wolftpm-examples, each demonstrating a different deployment topology. Together they cover the two canonical ways to run wolfTPM as a software TPM 2.0 server inside the same SoC as the application:

  • Single-MCU, isolated: STM32H5 NUCLEO-H563ZI with TrustZone. The fwTPM lives in the secure world; the non-secure application talks to it through a mssim-style framed transport over UART. NSC veneers gate every secure-side call.
  • AMP, dual-cluster: Xilinx ZCU102 with the A53 APU running PetaLinux Linux and the R5 RPU pair running bare-metal in lock-step mode. The fwTPM server runs on the R5; PetaLinux clients reach it over OpenAMP RPMsg loaded via Linux remoteproc. Persistent NV is in QSPI flash. Both TCG TPM 2.0 v1.85 PQC primitives (ML-KEM 512/768/1024, ML-DSA 44/65/87) are enabled.

Architecture

STM32/fwtpm-stm32h5/ — TrustZone-isolated fwTPM

+----------------------------+        +----------------------------+
|  Non-Secure (NSC client)   |        |  Secure (fwTPM server)     |
|  - test_uart_tpm.py harness|        |  - wolfTPM 2.0 fwtpm        |
|  - mssim framed cmds over  | ====>  |  - wolfCrypt SP-32 math    |
|    UART USART3, 115200     |  veneer|  - AES-GCM/CMAC/ECDSA/RSA  |
|                            | <==== NV - 64 KiB internal flash NV |
+----------------------------+        +----------------------------+
                                                   ^
                                                   |
                              +--------------------+
                              |  STM32H563ZI (TZEN=1, dual partition)|
                              +--------------------------------------+
  • TZEN=1, BFB2=1; partition_stm32h563xx.h carves NS/S address space.
  • Secure entry through NSC veneers in fwtpm_nsc.{c,h}; every TPM2 command crosses the secure gate.
  • Persistent NV in 64 KiB of internal flash via the HAL's flash driver — survives reset.
  • HAL clock + IRQ vectors live in the secure-world image; NS sees only the veneer surface.

Xilinx/fwtpm-zcu102-r5/ — AMP fwTPM on R5 lock-step + OpenAMP RPMsg

+----------------------------------------------------+
|  ZCU102 (Zynq UltraScale+ MPSoC)                  |
|                                                    |
|  +-----------------+      OpenAMP RPMsg            |
|  |  APU (A53 x4)   |<-------- IPI mailbox -------+ |
|  |  PetaLinux      |    vrings + buffer pool     | |
|  |  remoteproc-r5  |    in DDR (3EE0_0000)       | |
|  |  rpmsg-char     |                             v |
|  |  fwtpm_pqc_test |              +---------------------+
|  +-----------------+              | RPU (R5 lock-step)  |
|                                   | bare-metal fwTPM    |
|                                   | - wolfTPM 2.0 v1.85 |
|                                   | - wolfCrypt SP-32 + |
|                                   |   ML-KEM + ML-DSA   |
|                                   |   + SHA3/SHAKE      |
|                                   | - GIC + IPI ISR     |
|                                   | - PMU EEMI client   |
|                                   +---------------------+
|                                            ^
|                                            v
|                                    +----------------+
|                                    | QSPI flash NV  |
|                                    | (last 64 KiB)  |
|                                    | persistent     |
|                                    +----------------+
+----------------------------------------------------+

Key design choices, all observable on hardware:

  • Lock-step R5: xlnx,cluster-mode=<1> + xlnx,tcm-mode=<1> combine RPU0+RPU1 into one logical safety-class processor with 256 KiB merged TCM at 0x00000000. Single remoteproc0 instance manages both cores.
  • 1 MiB DDR carveout at 0x3ED00000 (rproc_0_reserved) holds R5 .text + .rodata + .data + .bss + heap + stack + 32 KiB trace ring. RPMsg vrings (16 KiB each) and 256 KiB rpmsg buffer pool sit at 0x3EE00000+, deliberately outside the firmware carveout so APU vring writes never collide with R5 .bss.
  • Custom MPU at boot: Region 0 = 2 GiB Normal-NC over TCM+DDR (libmetal LDREX/STREX needs Normal-typed memory); Region 1 = 256 MiB Device at 0xF0000000 covering the full LPD aperture (GIC400 at 0xF9000000 + IPI at 0xFF300000 + UART/QSPI/CSU at 0xFF000000+). Caches stay off so the trace ring stays APU-coherent without dcache flushes.
  • IRQ-driven rpmsg server: XScuGic + IPI ISR (XPAR_PSU_IPI_1_INT_ID = 65) wakes the R5 from wfi. Server loop drains both vrings via remoteproc_get_notification(RSC_NOTIFY_ID_ANY) then sleeps again. R5 idles near 0% CPU between TPM commands instead of busy-polling.
  • Custom boot.S (no libxilstandalone _boot): vector table at TCM 0x0000_0000 (where the R5 cold-reset vector fetches), TCM-resident reset stub clears stale CP15 MPU state before jumping to DDR _entry, IRQ stub saves caller-saved + lr-4 and dispatches to _irq_dispatch in C.
  • Persistent QSPI NV (opt-in): pmu_eemi.c issues PM_REQUEST_NODE(NODE_QSPI=0x2D) to PMUFW over the RPU0 IPI block before XQspiPsu_LookupConfig, so the controller's clock + power domain are up regardless of whether Linux's spi-zynqmp-qspi driver is enabled in DTS. Build with make elf EXTRA_CFLAGS=-DFWTPM_NV_QSPI. Default build uses the volatile RAM HAL.
  • TCG TPM 2.0 v1.85 PQC: WOLFTPM_V185 + WOLFSSL_HAVE_MLKEM + HAVE_DILITHIUM + SHA3/SHAKE128/256 enabled in user_settings.h; firmware advertises full ML-KEM 512/768/1024 and ML-DSA 44/65/87 via the v1.85 PT_ML_PARAMETER_SETS capability.
  • Custom PetaLinux project (petalinux/): system-user.dtsi with the lock-step rproc + carveouts + IPI mailbox + qspi disabled; openamp.cfg kernel fragment for REMOTEPROC + RPMSG_CHAR + ZYNQMP_IPI_MBOX; recipes-bsp/fwtpm-r5 stages the R5 ELF in /lib/firmware/; recipes-apps/fwtpm-rpmsg-test installs the smoke client. SD root on mmcblk0p4.
  • Linux clients:
    • fwtpm_rpmsg_test.c — raw TPM2 wire-format smoke (Startup / SelfTest / GetRandom / GetCapability / --pqc adds PT_ML_PARAMETER_SETS probe).
    • fwtpm_pqc_test.c + build-pqc-test.sh — wolfTPM2 wrapper round-trip (ML-KEM-768 encap/decap + ML-DSA-65 sign/verify) over an rpmsg TPM2_IoCb. Reproducible cross-build of static aarch64 binary against sibling wolfssl + wolftpm with the right --enable-pqc --disable-fwtpm --disable-autodetect combo to keep the simple 5-arg TPM2HalIoCb typedef active.

Shared design points

Both ports share the same wolfTPM fwTPM core:

  • WOLFCRYPT_ONLY, SINGLE_THREADED, NO_FILESYSTEM, WOLFSSL_USER_IO.
  • 32-bit SP math (WOLFSSL_SP, WOLFSSL_SP_MATH_ALL, WOLFSSL_SP_SMALL, SP_WORD_SIZE=32).
  • Fresh HASH_DRBG seeded from a platform-specific entropy callback (STM32 RNG peripheral on H5; PMU CCNT jitter on R5 — replaceable with PSU CSU TRNG via PMU mailbox in a follow-on).
  • Same wolfTPM src/fwtpm/ layer dispatches TPM2 commands and routes to wolfCrypt for crypto.

Test results

STM32H5 NUCLEO-H563ZI (single-MCU, TZEN=1)

Hardware-verified on NUCLEO-H563ZI with test_uart_tpm.py over USB-UART:

Test Result
TPM2_Startup(SU_CLEAR) OK
TPM2_SelfTest(NO) OK
TPM2_GetRandom(32) OK
TPM2_GetCapability(MANUFACTURER) OK
TZEN=1 + BFB2=1 boot through NSC veneer OK
Persistent NV across reset (flash) OK

ZCU102 R5 lock-step (AMP fwTPM via OpenAMP RPMsg)

Hardware-verified on a stock ZCU102 (XCZU9EG-2FFVB1156I), 2026-05-15, lock-step R5 with custom PetaLinux 2025.2 image:

Test Result
Tier-1 + Tier-2 R5 ELF compiles + links (Vitis 2025.2 BSP) OK
remoteproc start boots R5 ELF; trace ring shows banner OK
MPU enable -> gic_init done -> FWTPM_Init done -> rpmsg ready OK
fwtpm_rpmsg_test baseline 4 cmds (Startup/SelfTest/GetRandom/GetCap) all 4 pass
fwtpm_rpmsg_test --pqc advertises PT_ML_PARAMETER_SETS = 0x3F all 5 pass
ML-KEM 512/768/1024 + ML-DSA 44/65/87 capability bits set OK
IRQ-driven wfi server loop responds to APU rpmsg writes OK
PetaLinux image boots cleanly to login (mmcblk0p4 rootfs) OK
$ /usr/bin/fwtpm_rpmsg_test --pqc
Startup         tag=0x8001 size=10 rc=0x00000000  OK
SelfTest        tag=0x8001 size=10 rc=0x00000000  OK
GetRandom(32)   tag=0x8001 size=44 rc=0x00000000  OK
GetCapability   tag=0x8001 size=27 rc=0x00000000  OK
GetCap(ML)      prop=0x00000131 value=0x0000003f  OK
                 ML-KEM: 512 768 1024
                 ML-DSA: 44 65 87
all 5 tests passed

R5 trace ring (verbatim, sequential):

mpu: disable -> clear regions -> region 0 (2G Normal-NC)
   -> region 1 (256M Device @0xF0000000) -> enable -> enabled
step 0: gic init -> step 0: gic init done
=== wolfTPM fwTPM on ZCU102 R5 (lock-step) ===
step 1..8: NV (RAM) + clock HAL setup OK
step 10: FWTPM_Init done -> fwTPM initialized successfully
step 11: rpmsg init -> rpmsg: A..L (metal_init -> remoteproc_init ->
    set_rsc_table -> create_virtio -> init_vdev -> create_ept wolftpm)
step 12: rpmsg init done -> rpmsg ready, waiting for commands

@dgarske dgarske self-assigned this May 12, 2026
Copilot AI review requested due to automatic review settings May 12, 2026 23:25
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new end-to-end fwTPM example targeting the Xilinx ZCU102 where Linux (A53) loads and communicates with a bare-metal Cortex-R5 lock-step fwTPM instance via Linux remoteproc + OpenAMP RPMsg, along with a PetaLinux project and a Linux-side smoke test.

Changes:

  • Added ZCU102 R5 lock-step bare-metal fwTPM firmware (resource table, MPU setup, RPMsg transport, NV HALs, linker script, build system).
  • Added a self-contained PetaLinux 2025.2 project (DT overlay carveouts/lock-step/IPI mailbox + recipes for firmware staging and smoke test + kernel config fragment).
  • Added host-side helpers and documentation (SD deploy script, READMEs, repo top-level README entry, gitignore updates).

Reviewed changes

Copilot reviewed 46 out of 49 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
Xilinx/fwtpm-zcu102-r5/README.md ZCU102 fwTPM architecture/build/boot documentation for the new example.
Xilinx/fwtpm-zcu102-r5/deploy-to-sdcard.sh Host script to deploy PetaLinux artifacts to an SD card.
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/Makefile Build rules for the R5 bare-metal fwTPM firmware (Tier-1 objects, Tier-2 ELF link).
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/boot.S R5 reset/vector entry and TCM stub for remoteproc reload robustness.
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/lscript.ld Linker script for rproc DDR carveout + TCM vectors + trace/resource sections.
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/mpu_setup.c Minimal ARMv7-R MPU programming for Normal-NC + Device regions.
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/main.c Firmware entry: MPU init, HAL registration, fwTPM init, RPMsg server loop.
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/user_settings.h wolfSSL/wolfTPM build-time configuration for bare-metal R5.
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/fwtpm_clock_zynqmp.c Clock HAL (PMU CCNT) and RNG seed callback.
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/fwtpm_nv_ram.c Volatile RAM-backed NV HAL (V1 fallback).
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/fwtpm_nv_qspi.c QSPI-backed NV HAL skeleton using XQspiPsu.
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/fwtpm_rpmsg.c OpenAMP RPMsg endpoint bridging to FWTPM_ProcessCommand + poll loop.
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/platform_info.c libmetal device registration + remoteproc ops + IPI helpers for OpenAMP.
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/rsc_table.c remoteproc resource table (rpmsg vdev + optional trace ring).
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/bsp_stubs.c Newlib/BSP stubs: _sbrk + outbyte() -> trace buffer ring.
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/zcu102_r5.h Local header for platform HAL APIs used across firmware sources.
Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/include/xparameters.h Hand-rolled minimal platform constants and carveout addresses.
Xilinx/fwtpm-zcu102-r5/petalinux/README.md Instructions for building and validating the included PetaLinux project.
Xilinx/fwtpm-zcu102-r5/petalinux/.gitignore Ignores PetaLinux build outputs/imported hardware, preserves key configs.
Xilinx/fwtpm-zcu102-r5/petalinux/.petalinux/metadata Captures PetaLinux version and project metadata for the committed project.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/attributes PetaLinux project attributes (e.g., defconfig selection).
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/configs/config Committed PetaLinux system configuration used as build input.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/configs/flash_parts.txt Flash layout config for PetaLinux tooling.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/configs/rootfsconfigs/user-rootfsconfig Rootfs config list (user-rootfsconfig) for the project.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/README Meta-user layer README (currently template content).
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/COPYING.MIT MIT license text for the meta-user layer template.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/conf/layer.conf Yocto layer configuration for meta-user (scarthgap compatibility).
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/conf/petalinuxbsp.conf Adds fwtpm-r5 and fwtpm-rpmsg-test packages to IMAGE_INSTALL.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/conf/user-rootfsconfig Meta-user rootfs package listing file.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/recipes-bsp/device-tree/device-tree.bbappend Hooks in system-user.dtsi overlay for the device-tree build.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/recipes-bsp/device-tree/device-tree-sdt.inc SDT include wiring for extra DT include files.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi DT overlay: lock-step cluster mode, carveouts, IPI mailbox, QSPI partition, GEM3 PHY.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/recipes-bsp/fwtpm-r5/fwtpm-r5_0.1.0.bb Recipe to stage the prebuilt R5 ELF into firmware directory for remoteproc.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/recipes-apps/fwtpm-rpmsg-test/fwtpm-rpmsg-test_0.1.0.bb Recipe to build/install the RPMsg smoke-test client.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/recipes-apps/fwtpm-rpmsg-test/files/fwtpm_rpmsg_test.c Source for the smoke-test client (duplicate of linux-client version).
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/recipes-kernel/linux/linux-xlnx_%.bbappend Adds kernel feature fragments (bsp.cfg + openamp.cfg).
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/recipes-kernel/linux/linux-xlnx/bsp.cfg Empty kernel fragment placeholder referenced by bbappend.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/recipes-kernel/linux/linux-xlnx/openamp.cfg Kernel config fragment enabling remoteproc/rpmsg/mailbox.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/recipes-bsp/u-boot/u-boot-xlnx_%.bbappend U-Boot bbappend adding platform-top.h and bsp.cfg.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/recipes-bsp/u-boot/files/platform-top.h U-Boot platform-top config header inclusion shim.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/recipes-bsp/u-boot/files/bsp.cfg U-Boot config selection for platform-top.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/recipes-bsp/u-boot/files/0001-ubifs-distroboot-support.patch U-Boot patch file (currently not wired into bbappend).
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/meta-xilinx-tools/recipes-bsp/uboot-device-tree/uboot-device-tree.bbappend Adds a DT include for the U-Boot device-tree build.
Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/meta-xilinx-tools/recipes-bsp/uboot-device-tree/files/system-user.dtsi Minimal U-Boot DT include overlay file.
Xilinx/fwtpm-zcu102-r5/linux-client/Makefile Standalone build for the A53 Linux smoke-test client.
Xilinx/fwtpm-zcu102-r5/linux-client/fwtpm_rpmsg_test.c Standalone A53 Linux RPMsg smoke-test client source.
README.md Top-level repo README updated to mention the new ZCU102 example.
.gitignore Repo gitignore updated for ZCU102 example build artifacts (BSP/hw/petalinux outputs/client binary).
Comments suppressed due to low confidence (2)

Xilinx/fwtpm-zcu102-r5/README.md:211

  • In the Memory Map table, the QSPI fwtpm-nv partition is listed at 0x07F00000, but system-user.dtsi defines it at 0x07FF0000. This discrepancy can cause readers to partition flash incorrectly and (if the QSPI HAL is enabled) can lead to writes to the wrong offset; please make the address consistent everywhere.
| RPMsg buffer pool | 0x3EE08000   | 256 KiB | shared payload buffers      |
| QSPI fwtpm-nv     | 0x07F00000   | 64 KiB  | persistent NV (R5 owns)     |

Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/fwtpm_nv_qspi.c:253

  • This file uses printf() for QSPI init errors, but the port documentation indicates newlib stdio is not usable on this bare-metal R5 (no _write backend). If printf isn’t wired to outbyte/xil_printf, these diagnostics may hang precisely when flash init fails; prefer xil_printf/outbyte-based logging for error reporting here.

    cfg = XQspiPsu_LookupConfig(XPAR_XQSPIPSU_0_BASEADDR);
    if (cfg == NULL) {
        printf("XQspiPsu LookupConfig failed\n");
        return -1;
    }
    rc = XQspiPsu_CfgInitialize(&g_qspi, cfg, cfg->BaseAddress);
    if (rc != XST_SUCCESS) {
        printf("XQspiPsu CfgInitialize failed: %d\n", rc);
        return rc;

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/main.c Outdated
Comment thread Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/include/xparameters.h Outdated
Comment thread Xilinx/fwtpm-zcu102-r5/README.md
Comment thread Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/fwtpm_nv_qspi.c
Comment thread Xilinx/fwtpm-zcu102-r5/firmware/fwtpm-r5/fwtpm_rpmsg.c
Comment thread Xilinx/fwtpm-zcu102-r5/deploy-to-sdcard.sh Outdated
Comment thread Xilinx/fwtpm-zcu102-r5/petalinux/README.md
Comment thread Xilinx/fwtpm-zcu102-r5/petalinux/project-spec/meta-user/README
Comment thread Xilinx/fwtpm-zcu102-r5/petalinux/.petalinux/metadata
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants