From 6d652d444fe150090f18b592e673d4f217728bc3 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Wed, 26 Aug 2026 16:47:09 -0600 Subject: [PATCH] Support for AURIX TC4xx host and CSRM cores --- Makefile | 30 +- arch.mk | 203 ++++- config/examples/aurix-tc4xx-csrm-ecc.config | 26 + config/examples/aurix-tc4xx-ecc.config | 26 + .../aurix-tc4xx-fullsys-csrm-ecc.config | 30 + .../examples/aurix-tc4xx-fullsys-ecc.config | 37 + docs/Targets.md | 12 + hal/aurix_tc4xx.c | 793 ++++++++++++++++++ hal/aurix_tc4xx_csrm.c | 23 + lib/wolfHSM | 2 +- test-app/Makefile | 46 + test-app/app_aurix_tc4xx.c | 121 +++ test-app/app_aurix_tc4xx_csrm.c | 22 + .../tc4xx/wolfBoot-wolfHSM-keys.nvminit | 9 + 14 files changed, 1363 insertions(+), 17 deletions(-) create mode 100644 config/examples/aurix-tc4xx-csrm-ecc.config create mode 100644 config/examples/aurix-tc4xx-ecc.config create mode 100644 config/examples/aurix-tc4xx-fullsys-csrm-ecc.config create mode 100644 config/examples/aurix-tc4xx-fullsys-ecc.config create mode 100644 hal/aurix_tc4xx.c create mode 100644 hal/aurix_tc4xx_csrm.c create mode 100644 test-app/app_aurix_tc4xx.c create mode 100644 test-app/app_aurix_tc4xx_csrm.c create mode 100644 tools/scripts/tc4xx/wolfBoot-wolfHSM-keys.nvminit diff --git a/Makefile b/Makefile index f3113710..df53786d 100644 --- a/Makefile +++ b/Makefile @@ -261,7 +261,14 @@ CFLAGS+=$(WOLFPSA_CFLAGS) # Setup default optimizations (for GCC) ifeq ($(USE_GCC_HEADLESS),1) CFLAGS+=-Wall -Wextra -Wno-main -ffreestanding - CFLAGS+=-ffunction-sections -fdata-sections -fomit-frame-pointer + ifneq (,$(filter aurix_tc4xx aurix_tc4xx_csrm,$(TARGET))) + # No -fdata-sections: tricore-elf-gcc 13 emits bare-named data sections + # (.varname, not .bss.varname) that escape the iLLD linker script's + # clear/copy tables, leaving statics uninitialized at boot. + CFLAGS+=-ffunction-sections -fomit-frame-pointer + else + CFLAGS+=-ffunction-sections -fdata-sections -fomit-frame-pointer + endif # Allow unused parameters and functions CFLAGS+=-Wno-unused-parameter -Wno-unused-function # Error on unused variables @@ -587,31 +594,34 @@ endif ifeq ($(WOLFHSM_SERVER),1) _DO_WH_NVMTOOL:=1 endif -# Not every wolfHSM port provisions keys from a pre-built NVM image. A HAL may -# instead install the verification key into the server's key cache at boot (see -# hal_hsm_init_connect on pic32cz), which is the only option on targets whose -# server wipes its NVM partition on startup. Those set WOLFHSM_NVM_IMAGE=0. +# Some wolfHSM ports do not provision keys from a pre-built NVM image. +# Their HAL installs the verification key into the server key cache at boot. +# Set WOLFHSM_NVM_IMAGE=0 for those targets. WOLFHSM_NVM_IMAGE?=1 ifeq ($(WOLFHSM_NVM_IMAGE),0) _DO_WH_NVMTOOL:= endif -# Disable NVM image generation if user-provided keys without explicit USER_NVM_INIT -# (providing USER_NVM_INIT allows users to supply keys and still generate a custom NVM image) +# Disable NVM image generation for user-provided keys unless +# USER_NVM_INIT is set. ifeq ($(_USER_PROVIDED_KEYS),1) ifeq ($(USER_NVM_INIT),) _DO_WH_NVMTOOL:= endif endif ifeq ($(_DO_WH_NVMTOOL),1) +WH_NVM_TOOL_FLAGS ?= --invert-erased-byte +WH_NVM_HEX_ALIGN ?= 8 + whnvmtool: @echo "Building wolfHSM NVM tool" @$(MAKE) -C $(WOLFBOOT_LIB_WOLFHSM)/tools/whnvmtool nvm-image: $(PRIVATE_KEY) whnvmtool @echo "Generating wolfHSM NVM image" - $(Q)$(WOLFBOOT_LIB_WOLFHSM)/tools/whnvmtool/whnvmtool --image=$(WH_NVM_BIN) --size=$(WH_NVM_PART_SIZE) --invert-erased-byte $(NVM_CONFIG) - @echo "Converting NVM image to Intel HEX format" - $(Q)$(OBJCOPY) -I binary -O ihex --change-address $(WH_NVM_BASE_ADDRESS) $(WH_NVM_BIN) $(WH_NVM_HEX) + $(Q)rm -f $(WH_NVM_BIN) $(WH_NVM_HEX) + $(Q)$(WOLFBOOT_LIB_WOLFHSM)/tools/whnvmtool/whnvmtool --image=$(WH_NVM_BIN) --size=$(WH_NVM_PART_SIZE) \ + --hex=$(WH_NVM_HEX) --hex-base=$(WH_NVM_BASE_ADDRESS) --hex-align=$(WH_NVM_HEX_ALIGN) \ + $(WH_NVM_TOOL_FLAGS) $(NVM_CONFIG) @echo "NVM images generated: $(WH_NVM_BIN) and $(WH_NVM_HEX)" endif diff --git a/arch.mk b/arch.mk index 9628e173..f4ec09cd 100644 --- a/arch.mk +++ b/arch.mk @@ -2192,7 +2192,8 @@ endif # # TARGET=aurix_tc3xx: AURIX TC3xx TriCore host # TARGET=aurix_tc3xx_hsm: AURIX TC3xx Cortex-M3 HSM core -# TARGET=aurix_tc4xx: AURIX TC4xx Tricore host (coming soon) +# TARGET=aurix_tc4xx: AURIX TC4xx TriCore host +# TARGET=aurix_tc4xx_csrm: AURIX TC4xx CSRM (TriCore CPU6) # Backwards compatibility migration error for legacy ARCH=AURIX_TC3 ifeq ($(filter clean keysclean,$(MAKECMDGOALS)),) @@ -2387,13 +2388,203 @@ ifeq ($(ARCH), AURIX) $(WOLFHSM_INFINEON_TC3XX)/port/client/tchsm_hh_host.o endif - endif # aurix_tc3xx_hsm + endif # !aurix_tc3xx_hsm endif # TC3xx - # TC4xx specific - ifeq ($(TARGET), aurix_tc4xx) - # Coming soon ;-) - endif + ifneq (,$(filter aurix_tc4xx aurix_tc4xx_csrm,$(TARGET))) + # TC4xx + USE_GCC?=1 + ARCH_FLASH_OFFSET?=0x80000000 + + # wolfHSM TC4xx port root. Expected that wolfBoot is inside as a submodule. + WOLFHSM_INFINEON_TC4XX?=$(abspath ..) + TC4_LLD_DIR?=$(WOLFHSM_INFINEON_TC4XX)/drivers + TC4_WB_DIR?=$(WOLFHSM_INFINEON_TC4XX)/port/wolfboot + + # TC4 derivative device selection from the port device.mk. + include $(WOLFHSM_INFINEON_TC4XX)/device.mk + + CROSS_COMPILE?=tricore-elf- + + CFLAGS += -mcpu=$(DEV_MCPU) -D$(DEV_MACRO) $(DEV_XTAL_DEF) \ + $(DEV_GCC13_CFLAGS) + CFLAGS += -Wall -fno-common -fstrict-volatile-bitfields \ + -ffunction-sections -fno-builtin -std=gnu99 \ + -DPART_BOOT_EXT -DPART_UPDATE_EXT -DPART_SWAP_EXT \ + -DWOLFBOOT_LOADER_MAIN + # Vendor iLLD sources trip some -Wextra diagnostics + CFLAGS += -Wno-missing-field-initializers -Wno-unused-parameter \ + -Wno-unused-variable -Wno-sign-compare -Wno-type-limits + + # iLLD include paths. SSW configuration differs per core. + ifeq ($(TARGET), aurix_tc4xx_csrm) + CFLAGS += -I$(TC4_WB_DIR)/csrm -I$(TC4_WB_DIR)/csrm/Cfg_Ssw + else + CFLAGS += -I$(TC4_WB_DIR) -I$(TC4_WB_DIR)/Cfg_Ssw + endif + + # Linker scripts ship with the port, not in hal/. + ifeq ($(TARGET), aurix_tc4xx_csrm) + LSCRIPT_IN=$(TC4_WB_DIR)/csrm/aurix_tc4xx_csrm.ld + else + LSCRIPT_IN=$(TC4_WB_DIR)/aurix_tc4xx.ld + endif + CFLAGS += \ + -I$(TC4_LLD_DIR) \ + -I$(TC4_LLD_DIR)/Infra/Ssw/TC4xx/Csrm \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Csrm \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Csrm/Cpu/Trap \ + -I$(TC4_LLD_DIR)/Infra \ + -I$(TC4_LLD_DIR)/Infra/Platform \ + -I$(TC4_LLD_DIR)/Infra/Platform/Compilers \ + -I$(TC4_LLD_DIR)/Infra/Sfr \ + -I$(TC4_LLD_DIR)/Infra/Sfr/$(DEV_DERIV) \ + -I$(TC4_LLD_DIR)/Infra/Ssw \ + -I$(TC4_LLD_DIR)/Infra/Ssw/TC4xx \ + -I$(TC4_LLD_DIR)/Infra/Ssw/TC4xx/Tricore \ + -I$(TC4_LLD_DIR)/Service \ + -I$(TC4_LLD_DIR)/Service/CpuGeneric \ + -I$(TC4_LLD_DIR)/Service/CpuGeneric/If \ + -I$(TC4_LLD_DIR)/Service/CpuGeneric/If/Ccu6If \ + -I$(TC4_LLD_DIR)/Service/CpuGeneric/StdIf \ + -I$(TC4_LLD_DIR)/Service/CpuGeneric/SysSe \ + -I$(TC4_LLD_DIR)/Service/CpuGeneric/SysSe/Bsp \ + -I$(TC4_LLD_DIR)/Service/CpuGeneric/SysSe/General \ + -I$(TC4_LLD_DIR)/Service/CpuGeneric/SysSe/Time \ + -I$(TC4_LLD_DIR)/Service/CpuGeneric/_Utilities \ + -I$(TC4_LLD_DIR)/Service/Tricore \ + -I$(TC4_LLD_DIR)/Service/Tricore/Comm \ + -I$(TC4_LLD_DIR)/Service/Tricore/Math \ + -I$(TC4_LLD_DIR)/iLLD \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Ap \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Ap/Std \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Asclin \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Asclin/Asc \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Asclin/Std \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Clock \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Clock/Std \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Egtm \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Egtm/Std \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Geth \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Geth/Std \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Port \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Port/Std \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Src \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Src/Std \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/_Impl \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/_Impl/$(DEV_DERIV) \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/_Lib \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/_Lib/DataHandling \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/_Lib/Timer \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/_PinMap \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/_PinMap/$(DEV_DERIV) \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Cpu \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Cpu/Irq \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Cpu/Std \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Cpu/Trap \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Flash/Std \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Smu \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Smu/Std \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Stm \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Stm/Std \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Vmt \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Vmt/Std \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Wtu \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Wtu/Std \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/_Impl \ + -I$(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/_Impl/$(DEV_DERIV) + + # No TriCore asm in wolfCrypt + MATH_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sp_c32.o + + # wolfHSM support + ifneq ($(filter 1,$(WOLFHSM_CLIENT) $(WOLFHSM_SERVER)),) + # Common wolfHSM port files. + CFLAGS += -I$(WOLFHSM_INFINEON_TC4XX)/port -DWOLFHSM_CFG_DMA \ + -DWOLFHSM_CFG_NO_SYS_TIME + OBJS += $(WOLFHSM_INFINEON_TC4XX)/port/tchsm_hsmhost.o + OBJS += $(WOLFBOOT_LIB_WOLFHSM)/src/wh_transport_mem.o + + # NVM image variables for the server key store. + WH_NVM_BIN ?= whNvmImage.bin + WH_NVM_HEX ?= whNvmImage.hex + WH_NVM_PART_SIZE ?= 0x8000 + WH_NVM_BASE_ADDRESS ?= 0xAE800000 + WH_NVM_TOOL_FLAGS ?= + WH_NVM_HEX_ALIGN ?= 8 + NVM_CONFIG ?= tools/scripts/tc4xx/wolfBoot-wolfHSM-keys.nvminit + endif + + ifeq ($(WOLFHSM_CLIENT),1) + # Client transport bring-up files. + CFLAGS += -I$(WOLFHSM_INFINEON_TC4XX)/port/client + OBJS += $(WOLFHSM_INFINEON_TC4XX)/port/client/tchsm_client.o \ + $(WOLFHSM_INFINEON_TC4XX)/port/client/tchsm_hh_host.o \ + $(WOLFHSM_INFINEON_TC4XX)/port/client/tchsm_spr_apu.o \ + $(WOLFHSM_INFINEON_TC4XX)/port/client/tchsm_dma_client.o \ + $(WOLFHSM_INFINEON_TC4XX)/port/client/tchsm_time.o + endif + + ifeq ($(TARGET), aurix_tc4xx_csrm) + CFLAGS += -msoft-sp-float -msoft-dp-float + LDFLAGS += -msoft-sp-float -msoft-dp-float + # Full-system CSRM wolfBoot target leaves host release to tchsm-server. + ifeq ($(AURIX_TC4_FULLSYS),1) + CFLAGS += -DWOLFBOOT_AURIX_TC4XX_FULLSYS + LSCRIPT_IN=$(TC4_WB_DIR)/csrm/aurix_tc4xx_csrm_fullsys.ld + endif + endif + + LDFLAGS += -mcpu=$(DEV_MCPU) -Wl,--cref -Wl,-Map="wolfboot.map" + + # Remove UCB, BMHD, and other empty but loadable elf sections from wolfBoot.bin + # such that the binary image can be contiguous + OBJCOPY_FLAGS+=-R '.bmhd*' -R '.usercfg*' -R '.csusercfg*' -R '.sdata4' -R '.sdata' -R '.zdata' + + # iLLD startup software and drivers used by the HAL. + TC4_LLD_SRCS := \ + $(wildcard $(TC4_LLD_DIR)/Infra/Platform/Compilers/*.c) \ + $(TC4_LLD_DIR)/Infra/Ssw/TC4xx/Tricore/Ifx_Ssw_Infra.c \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Ap/Std/*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Asclin/Std/*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Clock/Std/*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Port/Std/*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/Src/Std/*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/_Impl/*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/_Impl/$(DEV_DERIV)/*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/_PinMap/IfxAsclin_PinMap*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/CpuGeneric/_PinMap/$(DEV_DERIV)/IfxAsclin_PinMap*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Cpu/Std/*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Stm/Std/*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Wtu/Std/*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/_Impl/*.c) + + ifeq ($(TARGET), aurix_tc4xx_csrm) + # CSRM (CPU6) startup software + trap table + TC4_LLD_SRCS += \ + $(TC4_LLD_DIR)/Infra/Ssw/TC4xx/Csrm/Ifx_Ssw_Tc6.c \ + $(TC4_LLD_DIR)/iLLD/TC4xx/Csrm/Cpu/Trap/IfxCpu_Trap_Cs.c + OBJS += $(TC4_LLD_SRCS:.c=.o) + OBJS += $(TC4_WB_DIR)/csrm/Cfg_Ssw/Ifx_Cfg_Ssw.o \ + $(TC4_WB_DIR)/csrm/Cfg_Ssw/Ifx_Cfg_SswBmhdCs.o \ + $(TC4_WB_DIR)/csrm/tc4_wolfboot_csrm_main.o + else + # Host CPU0 startup software and trap table. + TC4_LLD_SRCS += \ + $(TC4_LLD_DIR)/Infra/Ssw/TC4xx/Tricore/Ifx_Ssw_Tc0.c \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Cpu/Irq/*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Cpu/Trap/*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Smu/Std/*.c) \ + $(wildcard $(TC4_LLD_DIR)/iLLD/TC4xx/Tricore/Vmt/Std/*.c) + OBJS += $(TC4_LLD_SRCS:.c=.o) + OBJS += $(TC4_WB_DIR)/Cfg_Ssw/Ifx_Cfg_Ssw.o \ + $(TC4_WB_DIR)/Cfg_Ssw/Ifx_Cfg_SswBmhd.o \ + $(TC4_WB_DIR)/tc4_wolfboot_main.o + endif + endif # TC4xx endif CFLAGS+=-DARCH_FLASH_OFFSET=$(ARCH_FLASH_OFFSET) diff --git a/config/examples/aurix-tc4xx-csrm-ecc.config b/config/examples/aurix-tc4xx-csrm-ecc.config new file mode 100644 index 00000000..01bba688 --- /dev/null +++ b/config/examples/aurix-tc4xx-csrm-ecc.config @@ -0,0 +1,26 @@ +ARCH?=AURIX +TARGET?=aurix_tc4xx_csrm +SIGN?=ECC256 +HASH?=SHA256 +DEBUG?=0 +NO_ASM?=1 +WOLFBOOT_VERSION?=1 +V?=0 +SPMATH?=1 +RAM_CODE?=1 +EXT_FLASH?=1 +EXT_BOOT=1 +EXT_UPDATE=1 +EXT_SWAP=1 +FLAGS_INVERT=1 +FLASH_MULTI_SECTOR_ERASE=1 +DEBUG_UART=1 +PRINTF_ENABLED=1 +WOLFBOOT_IMG_HASH_ONESHOT=1 + +ARCH_FLASH_OFFSET=0x84000000 +WOLFBOOT_SECTOR_SIZE=0x4000 +WOLFBOOT_PARTITION_SIZE=0x70000 +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x84018000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x84088000 +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x840F8000 diff --git a/config/examples/aurix-tc4xx-ecc.config b/config/examples/aurix-tc4xx-ecc.config new file mode 100644 index 00000000..e75d24ad --- /dev/null +++ b/config/examples/aurix-tc4xx-ecc.config @@ -0,0 +1,26 @@ +ARCH?=AURIX +TARGET?=aurix_tc4xx +SIGN?=ECC256 +HASH?=SHA256 +DEBUG?=0 +NO_ASM?=1 +WOLFBOOT_VERSION?=1 +V?=0 +SPMATH?=1 +RAM_CODE?=1 +EXT_FLASH?=1 +EXT_BOOT=1 +EXT_UPDATE=1 +EXT_SWAP=1 +FLAGS_INVERT=1 +FLASH_MULTI_SECTOR_ERASE=1 +DEBUG_UART=1 +PRINTF_ENABLED=1 +WOLFBOOT_IMG_HASH_ONESHOT=1 + +ARCH_FLASH_OFFSET=0x80000000 +WOLFBOOT_SECTOR_SIZE=0x4000 +WOLFBOOT_PARTITION_SIZE=0x180000 +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80400000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x80580000 +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x80700000 diff --git a/config/examples/aurix-tc4xx-fullsys-csrm-ecc.config b/config/examples/aurix-tc4xx-fullsys-csrm-ecc.config new file mode 100644 index 00000000..33d0655a --- /dev/null +++ b/config/examples/aurix-tc4xx-fullsys-csrm-ecc.config @@ -0,0 +1,30 @@ +ARCH?=AURIX +TARGET?=aurix_tc4xx_csrm +AURIX_TC4_FULLSYS=1 +SIGN?=ECC256 +HASH?=SHA256 +DEBUG?=0 +NO_ASM?=1 +WOLFBOOT_VERSION?=1 +V?=0 +SPMATH?=1 +RAM_CODE?=1 +EXT_FLASH?=1 +EXT_BOOT=1 +EXT_UPDATE=1 +EXT_SWAP=1 +FLAGS_INVERT=1 +FLASH_MULTI_SECTOR_ERASE=1 +DEBUG_UART=1 +PRINTF_ENABLED=1 +WOLFBOOT_IMG_HASH_ONESHOT=1 + +# Full-system CSRM layout. +# Reserve 64 KiB for wolfBoot. +# Use 0x74000 BOOT and UPDATE partitions for the signed server. +ARCH_FLASH_OFFSET=0x84000000 +WOLFBOOT_SECTOR_SIZE=0x4000 +WOLFBOOT_PARTITION_SIZE=0x74000 +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x84010000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x84084000 +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x840F8000 diff --git a/config/examples/aurix-tc4xx-fullsys-ecc.config b/config/examples/aurix-tc4xx-fullsys-ecc.config new file mode 100644 index 00000000..5a281ec7 --- /dev/null +++ b/config/examples/aurix-tc4xx-fullsys-ecc.config @@ -0,0 +1,37 @@ +ARCH?=AURIX +TARGET?=aurix_tc4xx +SIGN?=ECC256 +HASH?=SHA256 +DEBUG?=0 +NO_ASM?=1 +WOLFBOOT_VERSION?=1 +V?=0 +SPMATH?=1 +RAM_CODE?=1 +EXT_FLASH?=1 +EXT_BOOT=1 +EXT_UPDATE=1 +EXT_SWAP=1 +FLAGS_INVERT=1 +FLASH_MULTI_SECTOR_ERASE=1 +DEBUG_UART=1 +PRINTF_ENABLED=1 +WOLFBOOT_IMG_HASH_ONESHOT=1 + +# wolfHSM client mode for the full-system chain. +# Hash and ECC verify are offloaded to tchsm-server. +# Align COMM_DATA_LEN with the server build. +WOLFHSM_CLIENT=1 +WOLFHSM_CFG_COMM_DATA_LEN=8192 + +# Detached self header for server cross-verify. +WOLFBOOT_SELF_HEADER=1 +SELF_HEADER_EXT=1 +WOLFBOOT_PARTITION_SELF_HEADER_ADDRESS=0x80100000 + +ARCH_FLASH_OFFSET=0x80000000 +WOLFBOOT_SECTOR_SIZE=0x4000 +WOLFBOOT_PARTITION_SIZE=0x180000 +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80400000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x80580000 +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x80700000 diff --git a/docs/Targets.md b/docs/Targets.md index 2bd7b408..d0ccc43a 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -10,6 +10,7 @@ This README describes configuration of supported targets. * [Cortex-A72 / Raspberry Pi Compute Module 4](#cortex-a72--raspberry-pi-compute-module-4-bcm2711) * [Cypress PSoC-6](#cypress-psoc-6) * [Infineon AURIX TC3xx](#infineon-aurix-tc3xx) +* [Infineon AURIX TC4xx](#infineon-aurix-tc4xx) * [Intel x86-64 Intel FSP](#intel-x86_64-with-intel-fsp-support) * [Kontron VX3060-S2](#kontron-vx3060-s2) * [Microchip PIC32CK](#microchip-pic32ck) @@ -8681,6 +8682,17 @@ Currently, wolfBoot for TC3xx is distributed as part of the wolfHSM TC3xx platfo For access to the TC3xx platform release or for more information on using wolfBoot and wolfHSM on AURIX devices, contact [facts@wolfssl.com](mailto:facts@wolfssl.com). +## Infineon AURIX TC4xx + +wolfBoot supports the Infineon AURIX TC4xx family and includes a demo application for the TC4D7 AURIX LiteKit-V2.1. It can be configured to run on either the TriCore application cores or the CSRM core. + +Both cores build with `ARCH=AURIX`. `TARGET` selects the core: `aurix_tc4xx` for the TriCore application cores and `aurix_tc4xx_csrm` for the CSRM core. Example configurations are in `config/examples/aurix-tc4xx-*.config`. + +On AURIX TC4xx devices, wolfBoot can also integrate with [wolfHSM](https://www.wolfssl.com/products/wolfhsm/) to offload cryptographic operations and key management to the CSRM core. + +Currently, wolfBoot for TC4xx is distributed as part of the wolfHSM TC4xx platform release bundle, not as a standalone package. This bundle is under NDA and is not publicly available. + +For access to the TC4xx platform release or for more information on using wolfBoot and wolfHSM on AURIX devices, contact [facts@wolfssl.com](mailto:facts@wolfssl.com). ## Vorago VA416x0 diff --git a/hal/aurix_tc4xx.c b/hal/aurix_tc4xx.c new file mode 100644 index 00000000..613f495d --- /dev/null +++ b/hal/aurix_tc4xx.c @@ -0,0 +1,793 @@ +/* aurix_tc4xx.c + * + * Copyright (C) 2014-2026 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfBoot. If not, see . + */ + +/* wolfBoot HAL for the Infineon AURIX TC4xx host and CSRM cores. + */ + +#include +#include + +/* wolfBoot headers */ +#include "hal.h" +#include "image.h" /* for RAMFUNCTION */ +#include "loader.h" /* for wolfBoot_panic */ +#include "printf.h" + +/* iLLD headers */ +#include "Ifx_Types.h" +#include "IfxAsclin.h" +#include "IfxAsclin_PinMap.h" +#include "IfxCpu.h" +#include "IfxWtu.h" +#ifndef TARGET_aurix_tc4xx_csrm +#include "IfxClock.h" +#endif + +#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) + +#include "IfxApApu.h" +#include "IfxApProt.h" +#include "IfxSrc.h" + +/* wolfHSM headers */ +#include "wolfhsm/wh_client.h" +#include "wolfhsm/wh_error.h" +/* wolfHSM AURIX TC4xx port headers */ +#include "tchsm_hsmhost.h" +#include "tchsm_client.h" +#include "tchsm_spr_apu.h" + +/* wolfHSM client ID for the HSM server. + * Align with whnvmtool provisioning. */ +#ifndef WOLFBOOT_WOLFHSM_CLIENT_ID +#error \ + "WOLFBOOT_WOLFHSM_CLIENT_ID is not defined. Set WOLFHSM_CLIENT_ID in your .config or on the make command line." +#endif + +/* HAL symbols exported for wolfBoot wolfHSM client mode. */ +whClientContext hsmClientCtx = {0}; +/* The server hashes host flash by address. */ +const int hsmDevIdHash = WH_DEV_ID_DMA; +const int hsmDevIdPubKey = WH_DEV_ID; +/* Verify public key stored in wolfHSM NVM. */ +const int hsmKeyIdPubKey = 0xFF; +#ifdef EXT_ENCRYPT +#error "AURIX TC4xx does not support firmware encryption with wolfHSM (yet)" +#endif + +_Static_assert(WOLFBOOT_WOLFHSM_CLIENT_ID == TCHSM_HSMHOST_CLIENT_APP0, + "WOLFHSM_CLIENT_ID must match the port's APP0 client ID"); + +#endif /* WOLFBOOT_ENABLE_WOLFHSM_CLIENT */ + +#define TC4_PFLASH_PAGE_SIZE (32u) +#define TC4_PFLASH_BURST_SIZE (512u) +#ifdef TARGET_aurix_tc4xx_csrm +#define TC4_PROG_CHUNK_SIZE TC4_PFLASH_PAGE_SIZE +#else +#define TC4_PROG_CHUNK_SIZE TC4_PFLASH_BURST_SIZE +#endif + +/* Convert between the cached (0x8...) segment used by the wolfBoot + * partition configuration and the non-cached (0xA...) alias the command + * interface requires. */ +#define TC4_FLASH_NC(addr) (((uint32_t)(addr)) | 0x20000000u) + +/* Select FCI based on CPU */ +#ifdef TARGET_aurix_tc4xx_csrm +#define TC4_CMD_BASE (0xF80C0000u) +#else +#define TC4_CMD_BASE (0xF8080000u) +#endif + +#define TC4_CMD_REG(off) ((volatile uint32_t*)(TC4_CMD_BASE | (off))) +#define TC4_CMD_MODE TC4_CMD_REG(0x5554u) /* mode/status cycles */ +#define TC4_CMD_LOAD2X32 TC4_CMD_REG(0x55F4u) /* page assembly, 2x32-bit */ +#define TC4_CMD_ADDR TC4_CMD_REG(0xAA50u) /* command word 1: address */ +#define TC4_CMD_COUNT TC4_CMD_REG(0xAA58u) /* command word 2: count */ +#define TC4_CMD_CODE TC4_CMD_REG(0xAAA8u) /* command code, written twice */ + +#define TC4_MODE_CLEAR_STATUS (0xFAu) +#define TC4_MODE_PF_PAGEMODE (0x50u) +#define TC4_MODE_RESET_READ (0xF0u) + +/* DMU command interface status/error registers (CSCI mirrors HCI at +0x80) */ +#define TC4_DMU_REG(addr) ((volatile uint32_t*)(addr)) +#ifdef TARGET_aurix_tc4xx_csrm +#define TC4_HCI_STATUS TC4_DMU_REG(0xF8040084u) +#define TC4_HCI_ERR TC4_DMU_REG(0xF8040090u) +#define TC4_HCI_CLRERR TC4_DMU_REG(0xF8040094u) +#else +#define TC4_HCI_STATUS TC4_DMU_REG(0xF8040004u) +#define TC4_HCI_ERR TC4_DMU_REG(0xF8040010u) +#define TC4_HCI_CLRERR TC4_DMU_REG(0xF8040014u) +#endif +#define TC4_GP_BKALLOC TC4_DMU_REG(0xF8040A00u) +#define TC4_BKALLOC_CSRMPF (1u << 18) + +/* HCI.STATUS fields */ +#define TC4_STATUS_BANKS_BUSY (0x000F0FFFu) /* per-bank busy + host DF + FSI \ + */ +#define TC4_STATUS_PFPAGE (1u << 25) +#define TC4_STATUS_REQDONE (1u << 31) + +#define TC4_ERR_OPFAIL_MASK \ + (0x00010077u) /* ADER|SQER|PROER|ABER|CLER|PVER|OPER */ +#define TC4_ERR_EVER (1u << 7) +#define TC4_CLRERR_ALL (0xF7u) /* OPER (bit16) has no clear bit */ + +/* Bounded wait limits for flash commands */ +#define TC4_BUSY_SPIN_LIMIT (50000000u) +#define TC4_REQDONE_SPIN_LIMIT (1000000u) + +#define WOLFBOOT_AURIX_RESET_REASON (0x5742) /* "WB" */ + +/* Helper macros for the base address of the page or sector containing addr */ +#define GET_PAGE_ADDR(addr) ((uintptr_t)(addr) & ~(TC4_PFLASH_PAGE_SIZE - 1)) +#define GET_SECTOR_ADDR(addr) ((uintptr_t)(addr) & ~(WOLFBOOT_SECTOR_SIZE - 1)) + +#define TC4_DSYNC() __asm volatile("dsync" ::: "memory") + +/* RAM buffer holding one flash sector for read-modify-write operations */ +static uint32_t sectorBuffer[WOLFBOOT_SECTOR_SIZE / sizeof(uint32_t)]; + +static void RAMFUNCTION flashClearStatus(void) +{ + *TC4_CMD_MODE = TC4_MODE_CLEAR_STATUS; + TC4_DSYNC(); +} + +/* Wait for all host banks idle and for REQDONE (end of sequence status). + * A timeout fails the operation. + * Returns 0 on completion, -1 on timeout. */ +static int RAMFUNCTION flashWaitDone(void) +{ + uint32_t spins; + + spins = TC4_BUSY_SPIN_LIMIT; + while (((*TC4_HCI_STATUS & TC4_STATUS_BANKS_BUSY) != 0u) && + (--spins != 0u)) { + } + if (spins == 0u) { + return -1; + } + + spins = TC4_REQDONE_SPIN_LIMIT; + while (((*TC4_HCI_STATUS & TC4_STATUS_REQDONE) == 0u) && (--spins != 0u)) { + } + if (spins == 0u) { + return -1; + } + + TC4_DSYNC(); + return 0; +} + +/* Read and clear the error flags. Returns the raw error register value. */ +static uint32_t RAMFUNCTION flashGetClearErrors(void) +{ + uint32_t err = *TC4_HCI_ERR; + *TC4_HCI_CLRERR = TC4_CLRERR_ALL; + TC4_DSYNC(); + return err; +} + +/* Issue a flash command and wait for completion. Returns the error flags on + * completion or TC4_ERR_OPFAIL_MASK on timeout. */ +static uint32_t RAMFUNCTION flashCommand(uint32_t address, uint32_t count, + uint32_t code1, uint32_t code2) +{ + flashClearStatus(); + *TC4_CMD_ADDR = TC4_FLASH_NC(address); + *TC4_CMD_COUNT = count; + *TC4_CMD_CODE = code1; + *TC4_CMD_CODE = code2; + TC4_DSYNC(); + + if (flashWaitDone() != 0) { + return TC4_ERR_OPFAIL_MASK; + } + return flashGetClearErrors(); +} + +/* Blank check one page via the hardware erase-verify command. + * Returns 1 if erased, 0 if programmed, -1 on error. */ +static int RAMFUNCTION flashIsPageErased(uint32_t pageAddr) +{ + uint32_t err = flashCommand(pageAddr, 0u, 0x80u, 0x56u); + if ((err & TC4_ERR_OPFAIL_MASK) != 0u) { + return -1; + } + return ((err & TC4_ERR_EVER) != 0u) ? 0 : 1; +} + +/* Erase one 16KB logical sector. Sectors are erased one at a time due to issues + * with multi-sector erases leaving the busy flag set. Returns 0 on success. */ +static int RAMFUNCTION flashEraseSector(uint32_t sectorAddr) +{ + uint32_t err = flashCommand(sectorAddr, 1u, 0x80u, 0x50u); + if ((err & TC4_ERR_OPFAIL_MASK) != 0u) { + return -1; + } + return 0; +} + +/* Program a naturally aligned group of pages (one page or one burst) that + * is already erased. data must hold size bytes; size is either + * TC4_PFLASH_PAGE_SIZE or TC4_PFLASH_BURST_SIZE. Returns 0 on success. */ +static int RAMFUNCTION flashProgramAligned(uint32_t addr, const uint32_t* data, + uint32_t size) +{ + uint32_t i; + uint32_t err; + uint32_t spins; + + /* Enter page mode and wait for the assembly buffer to be ready */ + flashClearStatus(); + *TC4_CMD_MODE = TC4_MODE_PF_PAGEMODE; + TC4_DSYNC(); + spins = TC4_REQDONE_SPIN_LIMIT; + while (((*TC4_HCI_STATUS & TC4_STATUS_PFPAGE) == 0u) && (--spins != 0u)) { + } + if (spins == 0u) { + return -1; + } + + /* Fill the page assembly buffer, two 32-bit words per cycle */ + for (i = 0; i < (size / sizeof(uint32_t)); i += 2u) { + *TC4_CMD_LOAD2X32 = data[i]; + *TC4_CMD_LOAD2X32 = data[i + 1u]; + } + TC4_DSYNC(); + + /* Write Page (0xAA) or Write Burst (0xA6) */ + err = flashCommand(addr, 0u, 0xA0u, + (size == TC4_PFLASH_BURST_SIZE) ? 0xA6u : 0xAAu); + if ((err & TC4_ERR_OPFAIL_MASK) != 0u) { + /* Leave page mode so the interface is not stuck */ + *TC4_CMD_MODE = TC4_MODE_RESET_READ; + TC4_DSYNC(); + return -1; + } + return 0; +} + +/* Read len bytes at address, which must not span an erased page (callers + * blank-check first). Reads go through the non-cached alias so no stale + * cache lines are involved. */ +static void RAMFUNCTION flashRead(uint32_t address, uint8_t* data, uint32_t len) +{ + const volatile uint8_t* src = + (const volatile uint8_t*)TC4_FLASH_NC(address); + uint32_t i; + for (i = 0; i < len; i++) { + data[i] = src[i]; + } +} + +/* Read an entire sector into sectorBuffer, substituting the erased-byte + * value for erased pages so no erased cell is ever read. */ +static void RAMFUNCTION cacheSector(uint32_t sectorAddress) +{ + uint32_t page; + for (page = 0; page < WOLFBOOT_SECTOR_SIZE; page += TC4_PFLASH_PAGE_SIZE) { + uint32_t* dst = sectorBuffer + (page / sizeof(uint32_t)); + int erased = flashIsPageErased(sectorAddress + page); + + if (erased < 0) { + wolfBoot_panic(); + } + else if (erased == 1) { + uint32_t i; + for (i = 0; i < TC4_PFLASH_PAGE_SIZE / sizeof(uint32_t); i++) { + dst[i] = FLASH_WORD_ERASED; + } + } + else { + flashRead(sectorAddress + page, (uint8_t*)dst, + TC4_PFLASH_PAGE_SIZE); + } + } +} + +/* Program sectorBuffer back into an erased sector, chunk by chunk + * (bursts on the host interface, single pages on the CSRM) */ +static void RAMFUNCTION programCachedSector(uint32_t sectorAddress) +{ + uint32_t off; + for (off = 0; off < WOLFBOOT_SECTOR_SIZE; off += TC4_PROG_CHUNK_SIZE) { + if (flashProgramAligned(sectorAddress + off, + sectorBuffer + (off / sizeof(uint32_t)), + TC4_PROG_CHUNK_SIZE) != 0) { + wolfBoot_panic(); + } + } +} + +/* Program unaligned data into erased flash, page by page */ +static int RAMFUNCTION programBytesToErasedFlash(uint32_t address, + const uint8_t* data, int size) +{ + uint32_t pageBuffer[TC4_PFLASH_PAGE_SIZE / sizeof(uint32_t)]; + uint32_t pageAddress = GET_PAGE_ADDR(address); + uint32_t offset = address % TC4_PFLASH_PAGE_SIZE; + + while (size > 0) { + uint32_t toWrite = TC4_PFLASH_PAGE_SIZE - offset; + uint32_t i; + + if (toWrite > (uint32_t)size) { + toWrite = (uint32_t)size; + } + + for (i = 0; i < TC4_PFLASH_PAGE_SIZE / sizeof(uint32_t); i++) { + pageBuffer[i] = FLASH_WORD_ERASED; + } + memcpy((uint8_t*)pageBuffer + offset, data, toWrite); + + if (flashProgramAligned(pageAddress, pageBuffer, + TC4_PFLASH_PAGE_SIZE) != 0) { + return -1; + } + + size -= toWrite; + data += toWrite; + address += toWrite; + pageAddress = GET_PAGE_ADDR(address); + offset = address % TC4_PFLASH_PAGE_SIZE; + } + return 0; +} + +#if defined(DEBUG_UART) || defined(UART_FLASH) + +#define TC4_UART (&MODULE_ASCLIN0) +#define TC4_UART_BAUD (115200u) +#define TC4_UART_FIFO_SIZE (16u) + +int uart_tx(const uint8_t c); +int uart_rx(uint8_t* c); +void uart_init(void); +void uart_write(const char* buf, unsigned int sz); + +void uart_init(void) +{ + Ifx_ASCLIN* u = TC4_UART; + + IfxAsclin_enableModule(u); + IfxAsclin_setClockSource(u, IfxAsclin_ClockSource_noClock); + IfxAsclin_setFrameMode(u, IfxAsclin_FrameMode_initialise); + IfxAsclin_setPrescaler(u, 1); + IfxAsclin_setClockSource(u, IfxAsclin_ClockSource_ascFastClock); + (void)IfxAsclin_setBitTiming( + u, (float32)TC4_UART_BAUD, IfxAsclin_OversamplingFactor_16, + IfxAsclin_SamplePointPosition_8, IfxAsclin_SamplesPerBit_three); + IfxAsclin_setClockSource(u, IfxAsclin_ClockSource_noClock); + + IfxAsclin_enableParity(u, FALSE); + IfxAsclin_setStopBit(u, IfxAsclin_StopBit_1); + IfxAsclin_setShiftDirection(u, IfxAsclin_ShiftDirection_lsbFirst); + IfxAsclin_setDataLength(u, IfxAsclin_DataLength_8); + IfxAsclin_setTxFifoInletWidth(u, IfxAsclin_TxFifoInletWidth_1); + IfxAsclin_setRxFifoOutletWidth(u, IfxAsclin_RxFifoOutletWidth_1); + IfxAsclin_setFrameMode(u, IfxAsclin_FrameMode_asc); + + IfxAsclin_initTxPin(&IfxAsclin0_TX_F_P14_0_OUT, IfxPort_OutputMode_pushPull, + IfxPort_PadDriver_cmosAutomotiveSpeed1); + IfxAsclin_initRxPin(&IfxAsclin0_RXA_F_P14_1_IN, IfxPort_InputMode_pullUp, + IfxPort_PadDriver_cmosAutomotiveSpeed1); + + IfxAsclin_setClockSource(u, IfxAsclin_ClockSource_ascFastClock); + IfxAsclin_disableAllFlags(u); + IfxAsclin_clearAllFlags(u); + IfxAsclin_flushTxFifo(u); + IfxAsclin_enableTxFifoOutlet(u, TRUE); +} + +int uart_tx(const uint8_t c) +{ + Ifx_ASCLIN* u = TC4_UART; + while (IfxAsclin_getTxFifoFillLevel(u) >= TC4_UART_FIFO_SIZE) { + } + IfxAsclin_writeTxData(u, c); + return 1; +} + +int uart_rx(uint8_t* c) +{ + (void)c; + return 0; +} + +void uart_write(const char* buf, unsigned int sz) +{ + while (sz > 0) { + if (*buf == '\n') { + (void)uart_tx('\r'); + } + (void)uart_tx(*buf++); + sz--; + } +} + +/* Block until the TX FIFO has fully drained onto the wire */ +static void uart_flush(void) +{ + Ifx_ASCLIN* u = TC4_UART; + volatile uint32_t i; + + while (IfxAsclin_getTxFifoFillLevel(u) != 0u) { + } + /* Delay in case TC flag is still set from an earlier idle + * period while the last frame sits in the shift reg. */ + for (i = 0; i < 200000u; i++) { + } +} + +#endif /* DEBUG_UART || UART_FLASH */ + +/* + * wolfBoot HAL entry points + */ + +void hal_init(void) +{ +#ifdef TARGET_aurix_tc4xx_csrm + IfxWtu_disableSecurityWatchdog(IfxWtu_getSecurityWatchdogPassword()); + + /* The CSRM PFLASH bank must be allocated to the CSRM or the CSCI + * command writes will fail silently */ + if ((*TC4_GP_BKALLOC & TC4_BKALLOC_CSRMPF) == 0u) { + wolfBoot_panic(); + } +#else + IfxWtu_disableCpuWatchdog(IfxWtu_getCpuWatchdogPassword()); + IfxWtu_disableSystemWatchdog(IfxWtu_getSystemWatchdogPassword()); + + /* Refuse to run if a host PFLASH bank has been reallocated to CSRM. */ + if ((*TC4_GP_BKALLOC & 0xFu) != 0u) { + wolfBoot_panic(); + } +#endif + +#ifdef DEBUG_UART +#ifdef TARGET_aurix_tc4xx_csrm + /* Delay to allow host-side unlock of UART during parallel boot */ + { + volatile uint32_t i; + for (i = 0; i < 100000u; i++) { + } + } +#endif + uart_init(); +#ifdef TARGET_aurix_tc4xx_csrm + wolfBoot_printf("Hello from TC4xx wolfBoot on CSRM: V%d\n", + WOLFBOOT_VERSION); +#else + wolfBoot_printf("Hello from TC4xx wolfBoot on TriCore CPU0: V%d\n", + WOLFBOOT_VERSION); +#endif +#endif +} + +void hal_prepare_boot(void) +{ +#ifdef DEBUG_UART + /* Final print, then drain so the clock switch below cannot corrupt + * in-flight characters */ + wolfBoot_printf("hal_prepare_boot\n"); + uart_flush(); + IfxAsclin_setClockSource(TC4_UART, IfxAsclin_ClockSource_noClock); + IfxAsclin_disableModule(TC4_UART); +#endif + +#ifndef TARGET_aurix_tc4xx_csrm + /* Host cores must return the clock tree to the backup clock and power the + * PLLs down, as the iLLD SSW can't handle already initialized PLLs. */ + (void)IfxClock_switchToBackupClock(&IfxClock_defaultClockConfig); +#endif +} + +void do_boot(const uint32_t* app_offset) +{ + __asm volatile("ji %0" ::"a"(app_offset)); +} + +void RAMFUNCTION arch_reboot(void) +{ + (void)WOLFBOOT_AURIX_RESET_REASON; +#ifdef TARGET_aurix_tc4xx_csrm + /* No reboot impl needed on CSRM yet */ + while (1) { + } +#else + IfxCpu_triggerSwReset(); + while (1) { + } +#endif +} + +/* + * Flash HAL. Addresses arrive in the cached (0x8...) segment from the + * partition configuration. All command sequences convert to the + * non-cached alias internally. + */ + +int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t* data, int size) +{ + int ret = 0; + uint32_t currentAddress = address; + int remainingSize = size; + int bytesWrittenTotal = 0; + + while (remainingSize > 0) { + uint32_t currentSectorAddress = GET_SECTOR_ADDR(currentAddress); + uint32_t offsetInSector = currentAddress - currentSectorAddress; + uint32_t bytesInThisSector = WOLFBOOT_SECTOR_SIZE - offsetInSector; + uint32_t page; + int needsSectorRmw = 0; + + if (bytesInThisSector > (uint32_t)remainingSize) { + bytesInThisSector = remainingSize; + } + + /* If any affected page already has data, read-modify-write the + * whole sector */ + const uint32_t startPage = GET_PAGE_ADDR(currentAddress); + const uint32_t endPage = + GET_PAGE_ADDR(currentAddress + bytesInThisSector - 1); + for (page = startPage; page <= endPage; page += TC4_PFLASH_PAGE_SIZE) { + int erased = flashIsPageErased(page); + if (erased < 0) { + return -1; + } + if (erased == 0) { + needsSectorRmw = 1; + break; + } + } + + if (needsSectorRmw) { + cacheSector(currentSectorAddress); + + ret = hal_flash_erase(currentSectorAddress, WOLFBOOT_SECTOR_SIZE); + if (ret != 0) { + break; + } + + memcpy((uint8_t*)sectorBuffer + offsetInSector, + data + bytesWrittenTotal, bytesInThisSector); + + programCachedSector(currentSectorAddress); + } + else { + ret = programBytesToErasedFlash( + currentAddress, data + bytesWrittenTotal, bytesInThisSector); + if (ret != 0) { + break; + } + } + + bytesWrittenTotal += bytesInThisSector; + currentAddress += bytesInThisSector; + remainingSize -= bytesInThisSector; + } + + return ret; +} + +int RAMFUNCTION hal_flash_erase(uint32_t address, int len) +{ + uint32_t currentSectorAddr; + uint32_t startSectorAddr; + uint32_t endAddress; + uint32_t endSectorAddr; + int ret = 0; + + if (len <= 0) { + return 0; + } + + startSectorAddr = GET_SECTOR_ADDR(address); + endAddress = address + len - 1; + endSectorAddr = GET_SECTOR_ADDR(endAddress); + + for (currentSectorAddr = startSectorAddr; + currentSectorAddr <= endSectorAddr; + currentSectorAddr += WOLFBOOT_SECTOR_SIZE) { + + const int isFirstSector = (currentSectorAddr == startSectorAddr); + const int isLastSector = (currentSectorAddr == endSectorAddr); + const int isPartialStart = isFirstSector && (address > startSectorAddr); + const int isPartialEnd = + isLastSector && + (endAddress < (endSectorAddr + WOLFBOOT_SECTOR_SIZE - 1)); + + if (isPartialStart || isPartialEnd) { + /* Partial sector: read-modify-write with the target range + * filled with the erased value */ + uint32_t eraseStartOffset = + isPartialStart ? (address - currentSectorAddr) : 0; + uint32_t eraseEndOffset = isPartialEnd + ? (endAddress - currentSectorAddr) + : (WOLFBOOT_SECTOR_SIZE - 1); + uint32_t eraseLen = eraseEndOffset - eraseStartOffset + 1; + uint32_t i; + + cacheSector(currentSectorAddr); + + for (i = 0; i < eraseLen; i++) { + ((uint8_t*)sectorBuffer)[eraseStartOffset + i] = + FLASH_BYTE_ERASED; + } + + if (flashEraseSector(currentSectorAddr) != 0) { + ret = -1; + break; + } + + programCachedSector(currentSectorAddr); + } + else { + if (flashEraseSector(currentSectorAddr) != 0) { + ret = -1; + break; + } + } + } + + return ret; +} + +void RAMFUNCTION hal_flash_unlock(void) {} + +void RAMFUNCTION hal_flash_lock(void) {} + +int RAMFUNCTION ext_flash_write(uintptr_t address, const uint8_t* data, int len) +{ + return hal_flash_write((uint32_t)address, data, len); +} + +/* Reads flash, spoofing the erased-byte value for erased pages + * (reading them directly would raise an uncorrectable ECC bus error). + * Returns the number of bytes read, or -1 on error. */ +int RAMFUNCTION ext_flash_read(uintptr_t address, uint8_t* data, int len) +{ + int bytesRead = 0; + + while (bytesRead < len) { + uint32_t pageAddress = GET_PAGE_ADDR(address); + uint32_t offset = address % TC4_PFLASH_PAGE_SIZE; + uint32_t bytesInThisPage = TC4_PFLASH_PAGE_SIZE - offset; + int erased; + + if (bytesInThisPage > (uint32_t)(len - bytesRead)) { + bytesInThisPage = len - bytesRead; + } + + erased = flashIsPageErased(pageAddress); + if (erased < 0) { + return -1; + } + + if (erased == 1) { + uint32_t i; + for (i = 0; i < bytesInThisPage; i++) { + data[bytesRead + i] = FLASH_BYTE_ERASED; + } + } + else { + flashRead(address, data + bytesRead, bytesInThisPage); + } + + address += bytesInThisPage; + bytesRead += bytesInThisPage; + } + + return bytesRead; +} + +int RAMFUNCTION ext_flash_erase(uintptr_t address, int len) +{ + return hal_flash_erase((uint32_t)address, len); +} + +void RAMFUNCTION ext_flash_lock(void) +{ + hal_flash_lock(); +} + +void RAMFUNCTION ext_flash_unlock(void) +{ + hal_flash_unlock(); +} + +#ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT + +/* wolfHSM client connection over the port shared-memory transport. */ + +/* Nonzero hardware setup return code for debugger inspection. */ +volatile int g_tc4_hsmc_hw_rc; + +/* CPU0 hardware setup for HsmHost transport. */ +static int tc4_hsmc_hw_init(void) +{ + { + IfxApApu_ApuConfig apConfig; + IfxApApu_initConfig(&apConfig); + const unsigned long srcTagMask = + (1UL << IfxApProt_TagId_cpu0d) | (1UL << IfxApProt_TagId_cpu0ds) | + (1UL << IfxApProt_TagId_cpu1d) | (1UL << IfxApProt_TagId_cpu1ds) | + (1UL << IfxApProt_TagId_cpucsd) | (1UL << IfxApProt_TagId_cpucsds); + apConfig.wraTagId = srcTagMask; + apConfig.rdaTagId = srcTagMask; + apConfig.wrbTagId = 0U; + apConfig.rdbTagId = 0U; + IfxSrc_configureAccessToSrcs(&apConfig); + } + + /* Probe SR0 to confirm SRC ACCEN writes are enabled. */ + SRC_GPSR4_SR0.U = 0x00006014u; + if (((SRC_GPSR4_SR0.U >> 12) & 0xFu) != 6u) { + return -1; + } + + if (tchsm_SprApu_OpenDspr() != 0u) { + return -2; + } + return 0; +} + +int hal_hsm_init_connect(void) +{ + int rc; + + /* The S2H wake ISR needs interrupts. */ + IfxCpu_enableInterrupts(); + + rc = tc4_hsmc_hw_init(); + if (rc != 0) { + g_tc4_hsmc_hw_rc = rc; + return rc; + } + + tchsm_client_init(TCHSM_HSMHOST_CLIENT_APP0); + + rc = tchsm_client_wait_ready(TCHSM_HSMHOST_CLIENT_APP0, 10000u); + if (rc != WH_ERROR_OK) { + return rc; + } + + rc = wh_Client_Init(&hsmClientCtx, + tchsm_client_get_config(TCHSM_HSMHOST_CLIENT_APP0)); + if (rc != WH_ERROR_OK) { + return rc; + } + return wh_Client_CommInit(&hsmClientCtx, NULL, NULL); +} + +int hal_hsm_disconnect(void) +{ + int rc = wh_Client_CommClose(&hsmClientCtx); + int rc2 = wh_Client_Cleanup(&hsmClientCtx); + return (rc != WH_ERROR_OK) ? rc : rc2; +} + +#endif /* WOLFBOOT_ENABLE_WOLFHSM_CLIENT */ diff --git a/hal/aurix_tc4xx_csrm.c b/hal/aurix_tc4xx_csrm.c new file mode 100644 index 00000000..ee44edae --- /dev/null +++ b/hal/aurix_tc4xx_csrm.c @@ -0,0 +1,23 @@ +/* aurix_tc4xx_csrm.c + * + * Copyright (C) 2014-2026 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfBoot. If not, see . + */ + +/* TC4xx CSRM core (TriCore CPU6). The build defines TARGET_aurix_tc4xx_csrm, + * which selects the CSRM paths inside the shared TC4xx HAL. */ +#include "aurix_tc4xx.c" diff --git a/lib/wolfHSM b/lib/wolfHSM index db9a4e00..86dd6df0 160000 --- a/lib/wolfHSM +++ b/lib/wolfHSM @@ -1 +1 @@ -Subproject commit db9a4e00cadccae36df4564784df4ea030a3ebf6 +Subproject commit 86dd6df04572b5d457da4a86f12750b93cf83bf4 diff --git a/test-app/Makefile b/test-app/Makefile index b4ecffe5..11ef2c18 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -1295,6 +1295,52 @@ ifneq (,$(filter aurix_tc3xx aurix_tc3xx_hsm,$(TARGET))) endif endif +ifneq (,$(filter aurix_tc4xx aurix_tc4xx_csrm,$(TARGET))) + # TC4 startup tables miss some sections emitted by -fdata-sections. + CFLAGS:=$(filter-out -fdata-sections,$(CFLAGS)) + # Flash helpers run from PSPR. + # Limit __WOLFBOOT to objects that define RAMFUNCTION helpers. + ../hal/$(TARGET).o: CFLAGS+=-DRAM_CODE -D__WOLFBOOT + ../test-app/libwolfboot.o: CFLAGS+=-DRAM_CODE -D__WOLFBOOT + ifeq ($(TARGET),aurix_tc4xx_csrm) + # CSRM app uses the shared startup and driver objects. + APP_OBJS += $(TC4_LLD_SRCS:.c=.o) + APP_OBJS += $(TC4_WB_DIR)/csrm/Cfg_Ssw/Ifx_Cfg_Ssw.o + # CSRM app linker script ships with the port. + LSCRIPT_TEMPLATE = $(TC4_WB_DIR)/csrm/tc4cs_app.ld + else + # Host test-app uses patched iLLD startup and drivers from the TC4 port. + # Drop Ifx_Ssw_Tc0.o and replace with patched aurix_tc4xx_ssw_tc0.o below + APP_OBJS += $(filter-out %/Ifx_Ssw_Tc0.o,$(TC4_LLD_SRCS:.c=.o)) + APP_OBJS += $(TC4_WB_DIR)/Cfg_Ssw/Ifx_Cfg_Ssw.o + APP_OBJS += aurix_tc4xx_ssw_tc0.o + # Host app linker script ships with the port. + LSCRIPT_TEMPLATE = $(TC4_WB_DIR)/tc4tc_app.ld + endif + + # TC4 wolfHSM port objects used by the HAL. + ifeq ($(WOLFHSM_CLIENT),1) + APP_OBJS += $(WOLFHSM_INFINEON_TC4XX)/port/tchsm_hsmhost.o \ + $(WOLFHSM_INFINEON_TC4XX)/port/client/tchsm_client.o \ + $(WOLFHSM_INFINEON_TC4XX)/port/client/tchsm_hh_host.o \ + $(WOLFHSM_INFINEON_TC4XX)/port/client/tchsm_spr_apu.o \ + $(WOLFHSM_INFINEON_TC4XX)/port/client/tchsm_dma_client.o \ + $(WOLFHSM_INFINEON_TC4XX)/port/client/tchsm_time.o \ + $(WOLFBOOT_LIB_WOLFHSM)/src/wh_transport_mem.o + endif + +# Build Ifx_Ssw_Tc0.c a second time as aurix_tc4xx_ssw_tc0.o with the +# hypervisor exit compiled out, since wolfBoot already ran it before +# jumping to the app. The new name keeps it from conflicting with the +# bootloader's Ifx_Ssw_Tc0.o, which is built from the same file +aurix_tc4xx_ssw_tc0.o: $(TC4_LLD_DIR)/Infra/Ssw/TC4xx/Tricore/Ifx_Ssw_Tc0.c + @echo "\t[CC-APP] $@" + $(Q)$(CC) $(CFLAGS) -DIFX_CFG_SSW_SKIP_DISABLE_VIRTUALIZATION -c -o $@ $< + +# Default goal for argument-less sub-makes. +.DEFAULT_GOAL := image.bin +endif + # On PPC64 (e5500/e6500) arch.mk turns on PPC32 SHA asm for the bootloader's # image-verify link; strip it from the test-app's wolfCrypt so PPC_ASM alone # controls the app's AES/SHA asm. diff --git a/test-app/app_aurix_tc4xx.c b/test-app/app_aurix_tc4xx.c new file mode 100644 index 00000000..e80ed5ed --- /dev/null +++ b/test-app/app_aurix_tc4xx.c @@ -0,0 +1,121 @@ +/* app_aurix_tc4xx.c + * + * Copyright (C) 2014-2026 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfBoot. If not, see . + */ + +/* wolfBoot test app for AURIX TC4xx. + * Host mode (TARGET=aurix_tc4xx) runs on CPU0. + * CSRM mode (TARGET=aurix_tc4xx_csrm, see app_aurix_tc4xx_csrm.c) runs + * on CPU6. + * Flash helpers run from PSPR. */ + +#if defined(TARGET_aurix_tc4xx) || defined(TARGET_aurix_tc4xx_csrm) + +#include +#include +#include "target.h" +#include "printf.h" +#include "hal.h" +#include "wolfboot/wolfboot.h" +#ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT +#include "wolfhsm/wh_client.h" +/* Defined by the port client glue. */ +extern whClientContext hsmClientCtx; +#endif + +#define BASE_FW_VERSION 1 + +/* Empty _init for the SSW C init hook. */ +void _init(void) {} + +/* Hang on flash HAL faults. */ +void wolfBoot_panic(void) +{ + while (1) { + __asm volatile("nop"); + } +} + +/* Entry after C runtime init. */ +#ifdef TARGET_aurix_tc4xx_csrm +void core6_main(void) +#else +void core0_main(void) +#endif +{ +#ifdef DEBUG_UART + uart_init(); +#endif +#ifdef TARGET_aurix_tc4xx_csrm + wolfBoot_printf("TC4xx CSRM Test Application\n"); +#else + wolfBoot_printf("TC4xx Test Application\n"); +#endif + wolfBoot_printf("Version: %d\n", wolfBoot_current_firmware_version()); + + if (wolfBoot_current_firmware_version() <= BASE_FW_VERSION) { + /* Stage the update from base firmware. */ + wolfBoot_update_trigger(); + } + else { + /* Confirm updated firmware. */ + wolfBoot_success(); + } + +#ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT + /* Full-system echo through the wolfHSM server. */ + { + int rc; + const char echoMsg[] = "wolfHSM echo test"; + char echoResp[sizeof(echoMsg)]; + uint16_t echoRespLen = 0; + + rc = hal_hsm_init_connect(); + if (rc == 0) { + wolfBoot_printf("wolfHSM Echo: sending %d bytes\n", + sizeof(echoMsg)); + rc = wh_Client_Echo(&hsmClientCtx, sizeof(echoMsg), echoMsg, + &echoRespLen, echoResp); + if (rc != 0) { + wolfBoot_printf("wolfHSM Echo test failed: %d\n", rc); + } + else if ((echoRespLen != sizeof(echoMsg)) || + (memcmp(echoResp, echoMsg, sizeof(echoMsg)) != 0)) { + /* The reply must match what was sent, byte for byte. */ + wolfBoot_printf("wolfHSM Echo mismatch: received %d bytes\n", + echoRespLen); + } + else { + wolfBoot_printf("wolfHSM Echo success: received %d bytes\n", + echoRespLen); + } + hal_hsm_disconnect(); + } + else { + wolfBoot_printf("HSM connect failed: %d\n", rc); + } + } +#endif + + /* Main application loop. */ + while (1) { + /* Spin forever. */ + } +} + +#endif /* TARGET_aurix_tc4xx || TARGET_aurix_tc4xx_csrm */ diff --git a/test-app/app_aurix_tc4xx_csrm.c b/test-app/app_aurix_tc4xx_csrm.c new file mode 100644 index 00000000..687f2adc --- /dev/null +++ b/test-app/app_aurix_tc4xx_csrm.c @@ -0,0 +1,22 @@ +/* app_aurix_tc4xx_csrm.c + * + * Copyright (C) 2014-2026 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfBoot. If not, see . + */ + +/* TC4xx CSRM core build of the test application; see app_aurix_tc4xx.c. */ +#include "app_aurix_tc4xx.c" diff --git a/tools/scripts/tc4xx/wolfBoot-wolfHSM-keys.nvminit b/tools/scripts/tc4xx/wolfBoot-wolfHSM-keys.nvminit new file mode 100644 index 00000000..834c0119 --- /dev/null +++ b/tools/scripts/tc4xx/wolfBoot-wolfHSM-keys.nvminit @@ -0,0 +1,9 @@ +# NVM config for whnvmtool. +# +# Key format +# key