From 58baba21e0b291a7968d944ba92e6d15ea211e67 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 23 Oct 2025 21:50:24 +0200 Subject: [PATCH 1/9] Fix STM32H5 update --- hal/stm32_tz.c | 13 +++++++++---- hal/stm32h5.c | 11 +++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/hal/stm32_tz.c b/hal/stm32_tz.c index 4be441bbb4..d16789818f 100644 --- a/hal/stm32_tz.c +++ b/hal/stm32_tz.c @@ -96,6 +96,7 @@ void hal_tz_claim_nonsecure_area(uint32_t address, int len) uint32_t reg; uint32_t end = address + len; uint32_t start_address = address; + uint32_t start_page_n; uint32_t bank = 0; int pos; @@ -103,12 +104,13 @@ void hal_tz_claim_nonsecure_area(uint32_t address, int len) return; if (address < FLASH_BANK2_BASE) { - page_n = (address - ARCH_FLASH_OFFSET) / FLASH_PAGE_SIZE; + start_page_n = (address - ARCH_FLASH_OFFSET) / FLASH_PAGE_SIZE; bank = 0; } else { - page_n = (address - FLASH_BANK2_BASE) / FLASH_PAGE_SIZE; + start_page_n = (address - FLASH_BANK2_BASE) / FLASH_PAGE_SIZE; bank = 1; } + page_n = start_page_n; #ifdef TARGET_stm32h5 /* Take into account current swap configuration */ if ((FLASH_OPTSR_CUR & FLASH_OPTSR_SWAP_BANK) >> 31) @@ -129,13 +131,14 @@ void hal_tz_claim_nonsecure_area(uint32_t address, int len) page_n++; } address = start_address; + page_n = start_page_n; while (address < end) { /* Erase claimed non-secure page, in secure mode */ #ifndef TARGET_stm32h5 reg = FLASH_CR & (~((FLASH_CR_PNB_MASK << FLASH_CR_PNB_SHIFT) | FLASH_CR_PER | FLASH_CR_BKER | FLASH_CR_PG | FLASH_CR_MER1 | FLASH_CR_MER2)); FLASH_CR = reg | ((page_n << FLASH_CR_PNB_SHIFT) | FLASH_CR_PER); #else - reg = FLASH_CR & (~((FLASH_CR_PNB_MASK << FLASH_CR_PNB_SHIFT) | FLASH_CR_SER | FLASH_CR_BER | FLASH_CR_PG | FLASH_CR_MER)); + reg = FLASH_CR & (~((FLASH_CR_PNB_MASK << FLASH_CR_PNB_SHIFT) | FLASH_CR_SER | FLASH_CR_BER | FLASH_CR_PG | FLASH_CR_MER | (1 << 31))); FLASH_CR = reg | ((page_n << FLASH_CR_PNB_SHIFT) | FLASH_CR_SER | (bank << 31)); #endif @@ -162,8 +165,10 @@ void hal_tz_release_nonsecure_area(void) { #ifndef DUALBANK_SWAP int i; - for (i = 0; i < FLASH_SECBB_NREGS; i++) + for (i = 0; i < FLASH_SECBB_NREGS; i++) { + FLASH_SECBB1[i] = 0; FLASH_SECBB2[i] = 0; + } #else uint32_t addr; int bank_swp = 0; diff --git a/hal/stm32h5.c b/hal/stm32h5.c index 3df657d76b..787a20ee82 100644 --- a/hal/stm32h5.c +++ b/hal/stm32h5.c @@ -33,17 +33,20 @@ #if TZ_SECURE() -/* This function assumes that the boot and the update - * partitions are at the same address in the two banks, - * regardless if DUALBANK_SWAP is active or not. - */ static int is_flash_nonsecure(uint32_t address) { +#ifndef DUALBANK_SWAP + if (address >= WOLFBOOT_PARTITION_BOOT_ADDRESS) { + return 1; + } + return 0; +#else uint32_t in_bank_offset = (address & 0x000FFFFF); if (in_bank_offset >= (WOLFBOOT_PARTITION_BOOT_ADDRESS - FLASHMEM_ADDRESS_SPACE)) { return 1; } return 0; +#endif } #endif From fdcd7be322a6f78ecac6ebdd773392ebb0808fed Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 23 Oct 2025 22:41:20 +0200 Subject: [PATCH 2/9] Don't use hardcoded value; add comment --- hal/stm32_tz.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hal/stm32_tz.c b/hal/stm32_tz.c index d16789818f..52b33e160f 100644 --- a/hal/stm32_tz.c +++ b/hal/stm32_tz.c @@ -138,7 +138,7 @@ void hal_tz_claim_nonsecure_area(uint32_t address, int len) reg = FLASH_CR & (~((FLASH_CR_PNB_MASK << FLASH_CR_PNB_SHIFT) | FLASH_CR_PER | FLASH_CR_BKER | FLASH_CR_PG | FLASH_CR_MER1 | FLASH_CR_MER2)); FLASH_CR = reg | ((page_n << FLASH_CR_PNB_SHIFT) | FLASH_CR_PER); #else - reg = FLASH_CR & (~((FLASH_CR_PNB_MASK << FLASH_CR_PNB_SHIFT) | FLASH_CR_SER | FLASH_CR_BER | FLASH_CR_PG | FLASH_CR_MER | (1 << 31))); + reg = FLASH_CR & (~((FLASH_CR_PNB_MASK << FLASH_CR_PNB_SHIFT) | FLASH_CR_SER | FLASH_CR_BER | FLASH_CR_PG | FLASH_CR_MER | FLASH_CR_BKSEL)); FLASH_CR = reg | ((page_n << FLASH_CR_PNB_SHIFT) | FLASH_CR_SER | (bank << 31)); #endif @@ -165,6 +165,7 @@ void hal_tz_release_nonsecure_area(void) { #ifndef DUALBANK_SWAP int i; + /* Set all banks as non-secure */ for (i = 0; i < FLASH_SECBB_NREGS; i++) { FLASH_SECBB1[i] = 0; FLASH_SECBB2[i] = 0; From 70f12a2a5e17655ca40fb3566f1265e8c357e2f9 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Fri, 24 Oct 2025 18:09:03 +0200 Subject: [PATCH 3/9] Update docs --- docs/STM32-TZ.md | 10 +++++----- docs/Targets.md | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/STM32-TZ.md b/docs/STM32-TZ.md index 9e969e9ee5..0f398324d5 100644 --- a/docs/STM32-TZ.md +++ b/docs/STM32-TZ.md @@ -192,7 +192,7 @@ OPTION BYTES BANK: 2 Boot Configuration: - NSBOOTADD : 0x80400 (0x8040000) + NSBOOTADD : 0x80600 (0x8060000) NSBOOT_LOCK : 0xC3 (The SWAP_BANK and NSBOOTADD can still be modified following their individual rules.) SECBOOT_LOCK : 0xC3 (The BOOT_UBE, SWAP_BANK and SECBOOTADD can still be modified following their individual rules.) SECBOOTADD : 0xC0000 (0xC000000) @@ -201,7 +201,7 @@ OPTION BYTES BANK: 3 Bank1 - Flash watermark area definition: SECWM1_STRT : 0x0 (0x8000000) - SECWM1_END : 0x1F (0x803E000) + SECWM1_END : 0x2F (0x805e000) Write sector group protection 1: @@ -210,8 +210,8 @@ OPTION BYTES BANK: 4 Bank2 - Flash watermark area definition: - SECWM2_STRT : 0x0 (0x08100000) - SECWM2_END : 0x1F (0x0813e000) + SECWM2_STRT : 0x2F (0x0815e000) + SECWM2_END : 0x0 (0x08100000) Write sector group protection 2: @@ -251,7 +251,7 @@ OPTION BYTES BANK: 9 ``` STM32_Programmer_CLI -c port=swd -d wolfboot.bin 0x0C000000 -STM32_Programmer_CLI -c port=swd -d test-app/image_v1_signed.bin 0x08040000 +STM32_Programmer_CLI -c port=swd -d test-app/image_v1_signed.bin 0x08060000 ``` - After rebooting, the LED on the board should turn on sequentially: diff --git a/docs/Targets.md b/docs/Targets.md index e0cd31ea2b..5f6b2212b6 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -975,7 +975,7 @@ To initiate an update, sign a new version of the app and upload the v3 to the up on the second bank: ```sh -tools/keytools/sign --ecc256 test-app/image.bin wolfboot_signing_private_key.der 3 +IMAGE_HEADER_SIZE=1024 tools/keytools/sign --ecc256 test-app/image.bin wolfboot_signing_private_key.der 3 STM32_Programmer_CLI -c port=swd -d test-app/image_v3_signed.bin 0x08160000 ``` From fd2c81a1f868e7e8eb65f7deb17e9536d12d5986 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Fri, 24 Oct 2025 18:09:57 +0200 Subject: [PATCH 4/9] Fix H5 erase bug --- hal/stm32h5.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/hal/stm32h5.c b/hal/stm32h5.c index 787a20ee82..179f0659e8 100644 --- a/hal/stm32h5.c +++ b/hal/stm32h5.c @@ -192,6 +192,7 @@ void RAMFUNCTION hal_flash_opt_lock(void) int RAMFUNCTION hal_flash_erase(uint32_t address, int len) { + uint32_t start_address; uint32_t end_address; uint32_t p; @@ -202,8 +203,17 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len) if (address < 0x08000000) return -1; - end_address = address + len - 1; - for (p = address; p < end_address; p += FLASH_PAGE_SIZE) { +#if TZ_SECURE() + start_address = address | FLASH_SECURE_MMAP_BASE; + if (is_flash_nonsecure(address)) { + hal_tz_claim_nonsecure_area(address, len); + } +#else + start_address = address; +#endif + + end_address = start_address + len - 1; + for (p = start_address; p < end_address; p += FLASH_PAGE_SIZE) { uint32_t reg; uint32_t base; uint32_t bnksel = 0; @@ -214,12 +224,6 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len) base = FLASH_BANK2_BASE; bnksel = 1; } -#if TZ_SECURE() - /* When in secure mode, skip erasing non-secure pages: will be erased upon claim */ - if (is_flash_nonsecure(address)) { - return 0; - } -#endif /* Check for swapped banks to invert bnksel */ if ((FLASH_OPTSR_CUR & FLASH_OPTSR_SWAP_BANK) >> 31) bnksel = !bnksel; @@ -231,6 +235,12 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len) } /* If the erase operation is completed, disable the associated bits */ FLASH_CR &= ~FLASH_CR_SER ; + +#if TZ_SECURE() + if (is_flash_nonsecure(address)) { + hal_tz_release_nonsecure_area(); + } +#endif return 0; } From e0e921716104e4c3013cb3d4792d1be7d99910c6 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 24 Oct 2025 09:25:41 -0700 Subject: [PATCH 5/9] Fix some issues with documentation for STM32H5 and include steps to test update using STM32 programmer. --- docs/Targets.md | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/docs/Targets.md b/docs/Targets.md index 5f6b2212b6..d89a980273 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -175,10 +175,10 @@ The example configuration for this scenario is available in [/config/examples/st - User Option Bytes requirement (with STM32CubeProgrammer tool - see below for instructions) ``` -TZEN = 1 System with TrustZone-M enabled -DBANK = 1 Dual bank mode -SECWM1_PSTRT=0x0 SECWM1_PEND=0x7F All 128 pages of internal Flash Bank1 set as secure -SECWM2_PSTRT=0x1 SECWM2_PEND=0x0 No page of internal Flash Bank2 set as secure, hence Bank2 non-secure +TZEN = 1 System with TrustZone-M enabled +DBANK = 1 Dual bank mode +SECWM1_STRT=0x0 SECWM1_END=0x7F All 128 pages of internal Flash Bank1 set as secure +SECWM2_STRT=0x1 SECWM2_END=0x0 No page of internal Flash Bank2 set as secure, hence Bank2 non-secure ``` - NOTE: STM32CubeProgrammer V2.3.0 is required (v2.4.0 has a known bug for STM32L5) @@ -189,7 +189,7 @@ SECWM2_PSTRT=0x1 SECWM2_PEND=0x0 No page of internal Flash Bank2 set as secur 2. `make` 3. Prepare board with option bytes configuration reported above - `STM32_Programmer_CLI -c port=swd mode=hotplug -ob TZEN=1 DBANK=1` - - `STM32_Programmer_CLI -c port=swd mode=hotplug -ob SECWM1_PSTRT=0x0 SECWM1_PEND=0x7F SECWM2_PSTRT=0x1 SECWM2_PEND=0x0` + - `STM32_Programmer_CLI -c port=swd mode=hotplug -ob SECWM1_STRT=0x0 SECWM1_END=0x7F SECWM2_STRT=0x1 SECWM2_END=0x0` 4. flash wolfBoot.bin to 0x0c00 0000 - `STM32_Programmer_CLI -c port=swd -d ./wolfboot.bin 0x0C000000` 5. flash .\test-app\image_v1_signed.bin to 0x0804 0000 @@ -316,10 +316,10 @@ SRAM memories into two parts: - User Option Bytes requirement (with STM32CubeProgrammer tool - see below for instructions) ``` -TZEN = 1 System with TrustZone-M enabled -DBANK = 1 Dual bank mode -SECWM1_PSTRT=0x0 SECWM1_PEND=0x7F All 128 pages of internal Flash Bank1 set as secure -SECWM2_PSTRT=0x1 SECWM2_PEND=0x0 No page of internal Flash Bank2 set as secure, hence Bank2 non-secure +TZEN = 1 System with TrustZone-M enabled +DBANK = 1 Dual bank mode +SECWM1_STRT=0x0 SECWM1_END=0x7F All 128 pages of internal Flash Bank1 set as secure +SECWM2_STRT=0x1 SECWM2_END=0x0 No page of internal Flash Bank2 set as secure, hence Bank2 non-secure ``` - NOTE: STM32CubeProgrammer V2.8.0 or newer is required @@ -330,7 +330,7 @@ SECWM2_PSTRT=0x1 SECWM2_PEND=0x0 No page of internal Flash Bank2 set as secur 2. `make TZEN=1` 3. Prepare board with option bytes configuration reported above - `STM32_Programmer_CLI -c port=swd mode=hotplug -ob TZEN=1 DBANK=1` - - `STM32_Programmer_CLI -c port=swd mode=hotplug -ob SECWM1_PSTRT=0x0 SECWM1_PEND=0x7F SECWM2_PSTRT=0x1 SECWM2_PEND=0x0` + - `STM32_Programmer_CLI -c port=swd mode=hotplug -ob SECWM1_STRT=0x0 SECWM1_END=0x7F SECWM2_STRT=0x1 SECWM2_END=0x0` 4. flash wolfBoot.bin to 0x0c000000 - `STM32_Programmer_CLI -c port=swd -d ./wolfboot.bin 0x0C000000` 5. flash .\test-app\image_v1_signed.bin to 0x08010000 @@ -915,7 +915,7 @@ The example configuration for this scenario is available in [/config/examples/st `STM32_Programmer_CLI -c port=swd -ob TZEN=0xB4` - set the option bytes to enable flash secure protection of first 384KB and remainder as non-secure: -`STM32_Programmer_CLI -c port=swd -ob SECWM1_PSTRT=0x0 SECWM1_PEND=0x2F SECWM2_PSTRT=0x2F SECWM2_PEND=0x0` +`STM32_Programmer_CLI -c port=swd -ob SECWM1_STRT=0x0 SECWM1_END=0x2F SECWM2_STRT=0x2F SECWM2_END=0x0` - flash the wolfboot image to the secure partition: `STM32_Programmer_CLI -c port=swd -d wolfboot.bin 0x0C000000` @@ -925,6 +925,19 @@ The example configuration for this scenario is available in [/config/examples/st For a full list of all the option bytes tested with this configuration, refer to [STM32-TZ.md](/docs/STM32-TZ.md). +You can use the "update" command and XMODEM to send a newly signed update (see docs/flash-OTP.md) or use the steps below using the STM32_Programmer: + +```sh +IMAGE_HEADER_SIZE=1024 tools/keytools/sign --ecc256 test-app/image.bin wolfboot_signing_private_key.der 2 +echo -n "pBOOT" > trigger_magic.bin +./tools/bin-assemble/bin-assemble \ + update.bin \ + 0x0 test-app/image_v2_signed.bin \ + 0x9FFFB trigger_magic.bin +STM32_Programmer_CLI -c port=swd -d update.bin 0x08100000 +``` + + ### Scenario 2: TrustZone Enabled, wolfCrypt as secure engine for NS applications This is similar to Scenario 1, but also includes wolfCrypt in secure mode, and From 177358e88debde95bd50ac1cca4e93131ba11faa Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Wed, 29 Oct 2025 00:06:19 +0100 Subject: [PATCH 6/9] Update H5 app to use new NSC API - Make the update and swap partitions secure and inaccessible from the app except via NSC API - Add a couple of necessary new NSC functions - Update the app to only use NSC API - Fix hal_flash_erase to account for secure addresses - Fix some bugs in xmodem implementation --- .../stm32h5-tz-dualbank-otp-lms.config | 2 +- .../examples/stm32h5-tz-dualbank-otp.config | 2 +- config/examples/stm32h5-tz.config | 4 +- config/examples/stm32h5.config | 4 +- hal/stm32h5.c | 33 ++++----- hal/stm32h5.h | 1 + include/wolfboot/wolfboot.h | 11 ++- src/libwolfboot.c | 27 ++++++- test-app/app_stm32h5.c | 73 +++++++++++-------- 9 files changed, 101 insertions(+), 56 deletions(-) diff --git a/config/examples/stm32h5-tz-dualbank-otp-lms.config b/config/examples/stm32h5-tz-dualbank-otp-lms.config index 7f76f6af3d..7ffe9ccd20 100644 --- a/config/examples/stm32h5-tz-dualbank-otp-lms.config +++ b/config/examples/stm32h5-tz-dualbank-otp-lms.config @@ -21,7 +21,7 @@ DUALBANK_SWAP?=1 WOLFBOOT_PARTITION_SIZE?=0xA0000 WOLFBOOT_SECTOR_SIZE?=0x2000 WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08060000 -WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x08160000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0C160000 WOLFBOOT_PARTITION_SWAP_ADDRESS?=0xFFFFFFFF FLAGS_HOME=0 DISABLE_BACKUP=0 diff --git a/config/examples/stm32h5-tz-dualbank-otp.config b/config/examples/stm32h5-tz-dualbank-otp.config index b09b08fbae..af7421eff7 100644 --- a/config/examples/stm32h5-tz-dualbank-otp.config +++ b/config/examples/stm32h5-tz-dualbank-otp.config @@ -21,7 +21,7 @@ DUALBANK_SWAP?=1 WOLFBOOT_PARTITION_SIZE?=0xA0000 WOLFBOOT_SECTOR_SIZE?=0x2000 WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08060000 -WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x08160000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0C160000 WOLFBOOT_PARTITION_SWAP_ADDRESS?=0xFFFFFFFF FLAGS_HOME=0 DISABLE_BACKUP=0 diff --git a/config/examples/stm32h5-tz.config b/config/examples/stm32h5-tz.config index 66c1bae751..aeb4d6a52d 100644 --- a/config/examples/stm32h5-tz.config +++ b/config/examples/stm32h5-tz.config @@ -21,8 +21,8 @@ DUALBANK_SWAP?=0 WOLFBOOT_PARTITION_SIZE?=0xA0000 WOLFBOOT_SECTOR_SIZE?=0x2000 WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08060000 -WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x08100000 -WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x081A0000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0C100000 +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x0C1A0000 FLAGS_HOME=0 DISABLE_BACKUP=0 WOLFCRYPT_TZ=1 diff --git a/config/examples/stm32h5.config b/config/examples/stm32h5.config index 61a340fd3c..54feaa1495 100644 --- a/config/examples/stm32h5.config +++ b/config/examples/stm32h5.config @@ -21,8 +21,8 @@ DUALBANK_SWAP?=0 WOLFBOOT_PARTITION_SIZE?=0xA0000 WOLFBOOT_SECTOR_SIZE?=0x2000 WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08060000 -WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x08100000 -WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x081A0000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0C100000 +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x0C1A0000 FLAGS_HOME=0 DISABLE_BACKUP=0 IMAGE_HEADER_SIZE?=1024 diff --git a/hal/stm32h5.c b/hal/stm32h5.c index 179f0659e8..fe60a72bf9 100644 --- a/hal/stm32h5.c +++ b/hal/stm32h5.c @@ -32,21 +32,14 @@ #define PLL_SRC_HSE 1 #if TZ_SECURE() - static int is_flash_nonsecure(uint32_t address) { -#ifndef DUALBANK_SWAP - if (address >= WOLFBOOT_PARTITION_BOOT_ADDRESS) { - return 1; - } - return 0; -#else - uint32_t in_bank_offset = (address & 0x000FFFFF); - if (in_bank_offset >= (WOLFBOOT_PARTITION_BOOT_ADDRESS - FLASHMEM_ADDRESS_SPACE)) { + if (address >= WOLFBOOT_PARTITION_BOOT_ADDRESS && + address < WOLFBOOT_PARTITION_BOOT_ADDRESS + + WOLFBOOT_PARTITION_SIZE) { return 1; } return 0; -#endif } #endif @@ -204,9 +197,15 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len) return -1; #if TZ_SECURE() - start_address = address | FLASH_SECURE_MMAP_BASE; - if (is_flash_nonsecure(address)) { - hal_tz_claim_nonsecure_area(address, len); + if (address & FLASH_SECURE_MMAP_BIT) { + /* Get address in non-secure address space */ + start_address = address & ~FLASH_SECURE_MMAP_BIT; + } + else { + if (is_flash_nonsecure(address)) { + hal_tz_claim_nonsecure_area(address, len); + } + start_address = address; } #else start_address = address; @@ -218,8 +217,8 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len) uint32_t base; uint32_t bnksel = 0; base = FLASHMEM_ADDRESS_SPACE; - reg = FLASH_CR & (~((FLASH_CR_PNB_MASK << FLASH_CR_PNB_SHIFT) | FLASH_CR_BER)); - if(p >= (FLASH_BANK2_BASE) && (p <= (FLASH_TOP) )) + reg = FLASH_CR & (~((FLASH_CR_PNB_MASK << FLASH_CR_PNB_SHIFT) | FLASH_CR_SER | FLASH_CR_BER | FLASH_CR_PG | FLASH_CR_MER | FLASH_CR_BKSEL)); + if (p >= FLASH_BANK2_BASE && p <= FLASH_TOP) { base = FLASH_BANK2_BASE; bnksel = 1; @@ -231,13 +230,13 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len) FLASH_CR = reg; ISB(); FLASH_CR |= FLASH_CR_STRT; - hal_flash_wait_complete(0); + hal_flash_wait_complete(bnksel); } /* If the erase operation is completed, disable the associated bits */ FLASH_CR &= ~FLASH_CR_SER ; #if TZ_SECURE() - if (is_flash_nonsecure(address)) { + if (!(address & FLASH_SECURE_MMAP_BIT) && is_flash_nonsecure(address)) { hal_tz_release_nonsecure_area(); } #endif diff --git a/hal/stm32h5.h b/hal/stm32h5.h index 95e203ebf0..d80add0736 100644 --- a/hal/stm32h5.h +++ b/hal/stm32h5.h @@ -49,6 +49,7 @@ #endif #define FLASH_SECURE_MMAP_BASE (0x0C000000) +#define FLASH_SECURE_MMAP_BIT (0x04000000) #define RCC_CR (*(volatile uint32_t *)(RCC_BASE + 0x00)) /* RM0481 - Table 108 */ #define RCC_CR_PLL3RDY (1 << 29) /* RM0481 - Table 108 */ diff --git a/include/wolfboot/wolfboot.h b/include/wolfboot/wolfboot.h index f51b380628..09a14fb273 100644 --- a/include/wolfboot/wolfboot.h +++ b/include/wolfboot/wolfboot.h @@ -420,7 +420,6 @@ int wolfBoot_erase_encrypt_key(void); */ /* Call wolfBoot_success from non-secure application */ - __attribute__((cmse_nonsecure_entry)) void wolfBoot_nsc_success(void); @@ -428,6 +427,16 @@ void wolfBoot_nsc_success(void); __attribute__((cmse_nonsecure_entry)) void wolfBoot_nsc_update_trigger(void); +/* Call wolfBoot_get_image_version from non-secure application */ +__attribute__((cmse_nonsecure_entry)) +uint32_t wolfBoot_nsc_get_image_version(uint8_t part); +#define wolfBoot_nsc_current_firmware_version() wolfBoot_nsc_get_image_version(PART_BOOT) +#define wolfBoot_nsc_update_firmware_version() wolfBoot_nsc_get_image_version(PART_UPDATE) + +/* Call wolfBoot_get_partition_state from non-secure application */ +__attribute__((cmse_nonsecure_entry)) +int wolfBoot_nsc_get_partition_state(uint8_t part, uint8_t *st); + /* Erase one or more sectors in the update partition. * - address: offset within the update partition ('0' corresponds to PARTITION_UPDATE_ADDRESS) * - len: size, in bytes diff --git a/src/libwolfboot.c b/src/libwolfboot.c index 6c08380daf..a94434bca6 100644 --- a/src/libwolfboot.c +++ b/src/libwolfboot.c @@ -2051,25 +2051,48 @@ void wolfBoot_nsc_update_trigger(void) wolfBoot_update_trigger(); } +__attribute__((cmse_nonsecure_entry)) +uint32_t wolfBoot_nsc_get_image_version(uint8_t part) +{ + return wolfBoot_get_image_version(part); +} + +__attribute__((cmse_nonsecure_entry)) +int wolfBoot_nsc_get_partition_state(uint8_t part, uint8_t *st) +{ + return wolfBoot_get_partition_state(part, st); +} + __attribute__((cmse_nonsecure_entry)) int wolfBoot_nsc_erase_update(uint32_t address, uint32_t len) { + int ret; + if (address > WOLFBOOT_PARTITION_SIZE) return -1; if (address + len > WOLFBOOT_PARTITION_SIZE) return -1; - return hal_flash_erase(address + WOLFBOOT_PARTITION_UPDATE_ADDRESS, len); + hal_flash_unlock(); + ret = hal_flash_erase(address + WOLFBOOT_PARTITION_UPDATE_ADDRESS, len); + hal_flash_lock(); + return ret; } __attribute__((cmse_nonsecure_entry)) int wolfBoot_nsc_write_update(uint32_t address, const uint8_t *buf, uint32_t len) { + int ret; + if (address > WOLFBOOT_PARTITION_SIZE) return -1; if (address + len > WOLFBOOT_PARTITION_SIZE) return -1; - return hal_flash_write(address + WOLFBOOT_PARTITION_UPDATE_ADDRESS, buf, len); + + hal_flash_unlock(); + ret = hal_flash_write(address + WOLFBOOT_PARTITION_UPDATE_ADDRESS, buf, len); + hal_flash_lock(); + return ret; } #endif diff --git a/test-app/app_stm32h5.c b/test-app/app_stm32h5.c index f6749c692e..48ce7a96a5 100644 --- a/test-app/app_stm32h5.c +++ b/test-app/app_stm32h5.c @@ -267,21 +267,22 @@ static int cmd_update_xmodem(const char *args) { int ret = -1; uint8_t xpkt[XMODEM_PACKET_SIZE]; - uint32_t dst_flash = (uint32_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS; + uint32_t dst_offset = 0; uint8_t pkt_num = 0, pkt_num_expected=0xFF; uint32_t pkt_size = XMODEM_PACKET_SIZE; + uint32_t t_size = 0; uint32_t update_ver = 0; uint32_t now = jiffies; uint32_t i = 0; uint8_t pkt_num_inv; uint8_t crc, calc_crc; int transfer_started = 0; + int eot_expected = 0; printf("Erasing update partition..."); fflush(stdout); - hal_flash_unlock(); - hal_flash_erase(dst_flash, WOLFBOOT_PARTITION_SIZE); + wolfBoot_nsc_erase_update(dst_offset, WOLFBOOT_PARTITION_SIZE); printf("Done.\r\n"); printf("Waiting for XMODEM transfer...\r\n"); @@ -303,6 +304,8 @@ static int cmd_update_xmodem(const char *args) } } else { now = jiffies; + if (i == 0 && xpkt[0] == XEOT) + break; i += ret; } } @@ -313,6 +316,12 @@ static int cmd_update_xmodem(const char *args) extra_led_on(); break; } + else if (eot_expected) { + ret = 1; + uart_tx(XNAK); + break; + } + if (xpkt[0] != XSOH) { continue; } @@ -335,10 +344,9 @@ static int cmd_update_xmodem(const char *args) crc = xpkt[XMODEM_PACKET_SIZE - 1]; calc_crc = crc8(xpkt, XMODEM_PACKET_SIZE - 1); if (crc == calc_crc) { - uint32_t t_size; /* CRC is valid */ memcpy(xpkt_payload, xpkt + 3, XMODEM_PAYLOAD_SIZE); - ret = hal_flash_write(dst_flash, xpkt_payload, XMODEM_PAYLOAD_SIZE); + ret = wolfBoot_nsc_write_update(dst_offset, xpkt_payload, XMODEM_PAYLOAD_SIZE); if (ret != 0) { xcancel(); printf("Error writing to flash\r\n"); @@ -347,15 +355,16 @@ static int cmd_update_xmodem(const char *args) uart_tx(XACK); pkt_num++; pkt_num_expected++; - dst_flash += XMODEM_PAYLOAD_SIZE; - t_size = *((uint32_t *)(WOLFBOOT_PARTITION_UPDATE_ADDRESS + 4)); - t_size += IMAGE_HEADER_SIZE; - if ((uint32_t)dst_flash >= (WOLFBOOT_PARTITION_UPDATE_ADDRESS + t_size)) { - ret = 0; - extra_led_off(); - break; + dst_offset += XMODEM_PAYLOAD_SIZE; + if (t_size == 0) { + /* At first packet, save expected partition size */ + t_size = *(uint32_t *)(xpkt_payload + 4); + t_size += IMAGE_HEADER_SIZE; } - uart_tx(XACK); + if (dst_offset >= t_size) { + eot_expected = 1; + } + /*uart_tx(XACK);*/ } else { uart_tx(XNAK); } @@ -367,17 +376,22 @@ static int cmd_update_xmodem(const char *args) uart_tx('\r'); printf("End of transfer. ret: %d\r\n", ret); - update_ver = wolfBoot_update_firmware_version(); - if (update_ver != 0) { - printf("New firmware version: 0x%lx\r\n", update_ver); - printf("Triggering update...\r\n"); - wolfBoot_update_trigger(); - printf("Update completed successfully.\r\n"); - } else { - printf("No valid image in update partition\r\n"); + if (ret != 0) { + printf("Transfer failed\r\n"); + } + else { + printf("Transfer succeeded\r\n"); + update_ver = wolfBoot_nsc_update_firmware_version(); + if (update_ver != 0) { + printf("New firmware version: 0x%lx\r\n", update_ver); + printf("Triggering update...\r\n"); + wolfBoot_nsc_update_trigger(); + printf("Update written successfully. Reboot to apply.\r\n"); + } else { + printf("No valid image in update partition\r\n"); + } } - hal_flash_lock(); return ret; } @@ -427,17 +441,17 @@ static int cmd_info(const char *args) uint16_t hdrSz; uint8_t boot_part_state = IMG_STATE_NEW, update_part_state = IMG_STATE_NEW; - cur_fw_version = wolfBoot_current_firmware_version(); - update_fw_version = wolfBoot_update_firmware_version(); + cur_fw_version = wolfBoot_nsc_current_firmware_version(); + update_fw_version = wolfBoot_nsc_update_firmware_version(); - wolfBoot_get_partition_state(PART_BOOT, &boot_part_state); - wolfBoot_get_partition_state(PART_UPDATE, &update_part_state); + wolfBoot_nsc_get_partition_state(PART_BOOT, &boot_part_state); + wolfBoot_nsc_get_partition_state(PART_UPDATE, &update_part_state); printf("\r\n"); printf("System information\r\n"); printf("====================================\r\n"); printf("Flash banks are %sswapped.\r\n", ((FLASH_OPTSR_CUR & (FLASH_OPTSR_SWAP_BANK)) == 0)?"not ":""); - printf("Firmware version : 0x%lx\r\n", wolfBoot_current_firmware_version()); + printf("Firmware version : 0x%lx\r\n", cur_fw_version); printf("Current firmware state: %s\r\n", part_state_name(boot_part_state)); if (update_fw_version != 0) { if (update_part_state == IMG_STATE_UPDATING) @@ -482,7 +496,7 @@ static int cmd_info(const char *args) static int cmd_success(const char *args) { - wolfBoot_success(); + wolfBoot_nsc_success(); printf("update success confirmed.\r\n"); return 0; } @@ -741,14 +755,13 @@ void main(void) int ret; uint32_t app_version; - /* Turn on boot LED */ boot_led_on(); /* Enable SysTick */ systick_enable(); - app_version = wolfBoot_current_firmware_version(); + app_version = wolfBoot_nsc_current_firmware_version(); nvic_irq_setprio(NVIC_USART3_IRQN, 0); nvic_irq_enable(NVIC_USART3_IRQN); From 18134632a70aae97e1c612a6bf2eaddf3655aacd Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Wed, 29 Oct 2025 00:41:52 +0100 Subject: [PATCH 7/9] Fix non-trustzone configs --- config/examples/stm32h5.config | 4 ++-- test-app/app_stm32h5.c | 37 ++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/config/examples/stm32h5.config b/config/examples/stm32h5.config index 54feaa1495..61a340fd3c 100644 --- a/config/examples/stm32h5.config +++ b/config/examples/stm32h5.config @@ -21,8 +21,8 @@ DUALBANK_SWAP?=0 WOLFBOOT_PARTITION_SIZE?=0xA0000 WOLFBOOT_SECTOR_SIZE?=0x2000 WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08060000 -WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0C100000 -WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x0C1A0000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x08100000 +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x081A0000 FLAGS_HOME=0 DISABLE_BACKUP=0 IMAGE_HEADER_SIZE?=1024 diff --git a/test-app/app_stm32h5.c b/test-app/app_stm32h5.c index 48ce7a96a5..7f1e4eb91e 100644 --- a/test-app/app_stm32h5.c +++ b/test-app/app_stm32h5.c @@ -282,7 +282,12 @@ static int cmd_update_xmodem(const char *args) printf("Erasing update partition..."); fflush(stdout); +#ifdef WOLFCRYPT_SECURE_MODE wolfBoot_nsc_erase_update(dst_offset, WOLFBOOT_PARTITION_SIZE); +#else + hal_flash_unlock(); + hal_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS + dst_offset, WOLFBOOT_PARTITION_SIZE); +#endif printf("Done.\r\n"); printf("Waiting for XMODEM transfer...\r\n"); @@ -346,7 +351,11 @@ static int cmd_update_xmodem(const char *args) if (crc == calc_crc) { /* CRC is valid */ memcpy(xpkt_payload, xpkt + 3, XMODEM_PAYLOAD_SIZE); +#ifdef WOLFCRYPT_SECURE_MODE ret = wolfBoot_nsc_write_update(dst_offset, xpkt_payload, XMODEM_PAYLOAD_SIZE); +#else + ret = hal_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS + dst_offset, xpkt_payload, XMODEM_PAYLOAD_SIZE); +#endif if (ret != 0) { xcancel(); printf("Error writing to flash\r\n"); @@ -381,17 +390,29 @@ static int cmd_update_xmodem(const char *args) } else { printf("Transfer succeeded\r\n"); +#ifdef WOLFCRYPT_SECURE_MODE update_ver = wolfBoot_nsc_update_firmware_version(); +#else + update_ver = wolfBoot_update_firmware_version(); +#endif if (update_ver != 0) { printf("New firmware version: 0x%lx\r\n", update_ver); printf("Triggering update...\r\n"); +#ifdef WOLFCRYPT_SECURE_MODE wolfBoot_nsc_update_trigger(); +#else + wolfBoot_update_trigger(); +#endif printf("Update written successfully. Reboot to apply.\r\n"); } else { printf("No valid image in update partition\r\n"); } } +#ifndef WOLFCRYPT_SECURE_MODE + hal_flash_lock(); +#endif + return ret; } @@ -441,11 +462,19 @@ static int cmd_info(const char *args) uint16_t hdrSz; uint8_t boot_part_state = IMG_STATE_NEW, update_part_state = IMG_STATE_NEW; +#ifdef WOLFCRYPT_SECURE_MODE cur_fw_version = wolfBoot_nsc_current_firmware_version(); update_fw_version = wolfBoot_nsc_update_firmware_version(); wolfBoot_nsc_get_partition_state(PART_BOOT, &boot_part_state); wolfBoot_nsc_get_partition_state(PART_UPDATE, &update_part_state); +#else + cur_fw_version = wolfBoot_current_firmware_version(); + update_fw_version = wolfBoot_update_firmware_version(); + + wolfBoot_get_partition_state(PART_BOOT, &boot_part_state); + wolfBoot_get_partition_state(PART_UPDATE, &update_part_state); +#endif printf("\r\n"); printf("System information\r\n"); @@ -496,7 +525,11 @@ static int cmd_info(const char *args) static int cmd_success(const char *args) { +#ifdef WOLFCRYPT_SECURE_MODE wolfBoot_nsc_success(); +#else + wolfBoot_success(); +#endif printf("update success confirmed.\r\n"); return 0; } @@ -761,7 +794,11 @@ void main(void) /* Enable SysTick */ systick_enable(); +#ifdef WOLFCRYPT_SECURE_MODE app_version = wolfBoot_nsc_current_firmware_version(); +#else + app_version = wolfBoot_current_firmware_version(); +#endif nvic_irq_setprio(NVIC_USART3_IRQN, 0); nvic_irq_enable(NVIC_USART3_IRQN); From ea9484f6a4d8c6df3d0a271b2be878350b26731f Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Wed, 29 Oct 2025 15:02:58 +0100 Subject: [PATCH 8/9] Add docs for NSC APIs and update H5 option bytes --- docs/API.md | 32 ++++++++++++++++++++++++++++++++ docs/STM32-TZ.md | 10 ++++++++-- docs/Targets.md | 4 ++-- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/docs/API.md b/docs/API.md index ebc0883de4..99a5586762 100644 --- a/docs/API.md +++ b/docs/API.md @@ -66,3 +66,35 @@ the two images again. For more information about the update process, see [Firmware Update](firmware_update.md) For the image format, see [Firmware Image](firmware_image.md) + +## NSC API + +If you're running wolfBoot on an ARM TrustZone-enabled device (see for example +[STM32-TZ](STM32-TZ.md)) you may wish to run your application in non-secure +mode, while keeping the UPDATE and SWAP partitions in the secure domain. In +order to accomplish this, any operation by the application that requires access +to those partitions needs to be performed via wolfBoot code running in the +secure domain. For this purpose, wolfBoot provides Non-Secure Callable (NSC) +APIs that allow code running in the non-secure domain to call into the secure +domain managed by wolfBoot. + +These APIs are listed below. + +- `void wolfBoot_nsc_success(void)`: wrapper for `wolfBoot_success()` +- `void wolfBoot_nsc_update_trigger(void)`: wrapper for + `wolfBoot_update_trigger()` +- `uint32_t wolfBoot_nsc_get_image_version(uint8_t part)`: wrapper for + `wolfBoot_get_image_version()` +- `uint32_t wolfBoot_nsc_current_firmware_version(void)`: wrapper for + `wolfBoot_current_firmware_version()` +- `uint32_t wolfBoot_nsc_update_firmware_version(void)`: wrapper for + `wolfBoot_update_firmware_version()` +- `int wolfBoot_nsc_get_partition_state(uint8_t part, uint8_t *st)`: wrapper + for `wolfBoot_get_partition_state()` +- `int wolfBoot_nsc_erase_update(uint32_t address, uint32_t len)`: allows the + application to erase the update partition in secure mode. The `address` + parameter is an offset from the beginning of the partition. +- `int wolfBoot_nsc_write_update(uint32_t address, const uint8_t *buf, uint32_t + len)`: allows the application to write to the update partition in secure + mode. The `address` parameter is an offset from the beginning of the + partition. diff --git a/docs/STM32-TZ.md b/docs/STM32-TZ.md index 0f398324d5..57c9a58a00 100644 --- a/docs/STM32-TZ.md +++ b/docs/STM32-TZ.md @@ -55,6 +55,12 @@ image header size must be supplied as an environment variable. For example: IMAGE_HEADER_SIZE=1024 ./tools/keytools/sign --sha256 --ecc256 myapp.bin wolfboot_signing_private_key.der 1 ``` +### NSC API + +wolfBoot provides a few Non-Secure Callable functions to allow a non-secure +application to perform certain operations that must be run from the secure +domain. For more information, see [API](docs/API.md#nsc-api). + ### Example using STM32L552 - Copy the example configuration for STM32-L5 with support for wolfCrypt in @@ -210,8 +216,8 @@ OPTION BYTES BANK: 4 Bank2 - Flash watermark area definition: - SECWM2_STRT : 0x2F (0x0815e000) - SECWM2_END : 0x0 (0x08100000) + SECWM2_STRT : 0x0 (0x08100000) + SECWM2_END : 0x7F (0x081fe0000) Write sector group protection 2: diff --git a/docs/Targets.md b/docs/Targets.md index d89a980273..a3409e91a3 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -915,7 +915,7 @@ The example configuration for this scenario is available in [/config/examples/st `STM32_Programmer_CLI -c port=swd -ob TZEN=0xB4` - set the option bytes to enable flash secure protection of first 384KB and remainder as non-secure: -`STM32_Programmer_CLI -c port=swd -ob SECWM1_STRT=0x0 SECWM1_END=0x2F SECWM2_STRT=0x2F SECWM2_END=0x0` +`STM32_Programmer_CLI -c port=swd -ob SECWM1_STRT=0x0 SECWM1_END=0x2F SECWM2_STRT=0x0 SECWM2_END=0x7F` - flash the wolfboot image to the secure partition: `STM32_Programmer_CLI -c port=swd -d wolfboot.bin 0x0C000000` @@ -934,7 +934,7 @@ echo -n "pBOOT" > trigger_magic.bin update.bin \ 0x0 test-app/image_v2_signed.bin \ 0x9FFFB trigger_magic.bin -STM32_Programmer_CLI -c port=swd -d update.bin 0x08100000 +STM32_Programmer_CLI -c port=swd -d update.bin 0x0C100000 ``` From 70d25f457acc77eb810ab4e5122d79106e37b88d Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Wed, 29 Oct 2025 15:10:53 +0100 Subject: [PATCH 9/9] Fix docs link --- docs/STM32-TZ.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/STM32-TZ.md b/docs/STM32-TZ.md index 57c9a58a00..72cdaaf4e2 100644 --- a/docs/STM32-TZ.md +++ b/docs/STM32-TZ.md @@ -59,7 +59,7 @@ IMAGE_HEADER_SIZE=1024 ./tools/keytools/sign --sha256 --ecc256 myapp.bin wolfboo wolfBoot provides a few Non-Secure Callable functions to allow a non-secure application to perform certain operations that must be run from the secure -domain. For more information, see [API](docs/API.md#nsc-api). +domain. For more information, see [API](API.md#nsc-api). ### Example using STM32L552