Showing results for 
Search instead for 
Did you mean: 

STiROT_OEMuROT example results in hard fault

Associate II

Dear community,

I have been experimenting with secure boot on the STM32H573I-DK using the latest git checkout of STM32CubeH5 (see

The STiROT and OEMiROT examples run fine out-of-the-box. However, when I try to provision and run the STiROT_OEMuROT example, then the board seems to be in a boot loop. When I insert a "while (1) {};" line after , the boot loop stops. So it seems to be a hard fault when the jump to non secure code is made.

Note that I am using the code as it is checked in with Git: no changes were made to the example code.

Can anyone help me in debugging this code? I have already followed the tutorial on multiple times, line by line.



ST Employee

Hi @jens-vdb 

Can you check if you correctly set the path of STM32CubeProgrammer and that the selected application path is correct in env.bat script ?

According to the Wiki, in which step the issue is seen ?

Best regards





I have verified the correctness of the path of STM32CubeProgrammer. To confirm that, I set it to a non-existent path and then the provisioning script failed. For what it's worth, I'm using Linux. So instead of the *.bat files, I'm using the *.sh files.

The tutorial on fails in step 4. The crash happens after the line "[INF] Jumping to the first image slot" is printed, then the board resets. The following output can be seen on the serial console:

[INF] TAMPER Activated
[INF] Flash operation: Op=0x0, Area=0x0, Address=0x0
[INF] Starting bootloader
[INF] Swap type: none
[INF] verify counter  0 1000000 1000000
[INF] counter  0 : ok
[INF] verify sig key id 0
[INF] checking public key 48 5b
[INF] verifying signature hlen 20
[INF] signature OK
[INF] Swap type: none
[INF] verify counter  1 1000000 1000000
[INF] counter  1 : ok
[INF] verify sig key id 1
[INF] checking public key 46 5b
[INF] verifying signature hlen 20
[INF] signature OK
[INF] Swap type: none
[INF] verify counter  2 1000000 1000000
[INF] counter  2 : ok
[INF] verify sig key id 2
[INF] checking public key 46 5b
[INF] verifying signature hlen 20
[INF] signature OK
[INF] Swap type: none
[INF] verify counter  3 1000000 1000000
[INF] counter  3 : ok
[INF] verify sig key id 3
[INF] checking public key 46 5b
[INF] verifying signature hlen 20
[INF] signature OK
[INF] verify counter  0 1000000 1000000
[INF] counter  0 : ok
[INF] hash ref OK
[INF] verify counter  1 1000000 1000000
[INF] counter  1 : ok
[INF] hash ref OK
[INF] verify counter  2 1000000 1000000
[INF] counter  2 : ok
[INF] hash ref OK
[INF] verify counter  3 1000000 1000000
[INF] counter  3 : ok
[INF] hash ref OK
[INF] Bootloader chainload address offset: 0x1a000
[INF] Jumping to the first image slot
[INF] TAMPER Activated
[INF] Flash operation: Op=0x0, Area=0x0, Address=0x0

I can break that reset cycle by changing the code as described in my original post. If I put the while(1){}-loop from my original post at the beginning of the HardFault handler function in, I am able to break the reset loop (thus confirming that the reset loop is triggered by a hard fault), and I can do some fault analysis according to the Cortex-M33 manual at :

  1. authorize debugging ( with "Level 3 Intrusive Debug";
  2. connect to the device using the STM32CubeProgrammer;
  3. read out the CFSR register: UFSR=0, BFSR=0x92 (BFARVALID, STKERR, PRECISERR), MMFSR=0;
  4. read out the BFAR register: BFAR=0x2009FFFC.

From the linker script of the non-secure application, BFAR indicates the highest word on the stack (0x20050000-0x200A0000). So it looks like the non-secure application cannot access its own stack for some reason.


Note that the STiROT example code works out of the box with the default application selected ( stirot_boot_path_project=Applications/ROT/STiROT_Appli). But the STiROT example does *not* work anymore If I configure it to use the TrustZone application instead:

No output is provided on the serial console, and discovery of the provisioned device indicates that only STiROT init and config are done (ST HDPL1 status):

discovery: target ID.......................:0x484
discovery: SoC ID..........................:0x5b003f  0x3332510a  0x35353537  0x0
discovery: SDA version.....................:2.4.0
discovery: Vendor ID.......................:STMicroelectronics
discovery: PSA lifecycle...................:ST_LIFECYCLE_IROT_PROVISIONED
discovery: PSA auth version................:1.0
discovery: ST HDPL1 status.................:0x3
discovery: ST HDPL2 status.................:0xffffffff
discovery: ST HDPL3 status.................:0xffffffff
discovery: Token Formats...................:0x200
discovery: Certificate Formats.............:0x201
discovery: cryptosystems...................:Ecdsa-P256 SHA256
discovery: ST provisioning integrity status:0xeaeaeaea

 No idea if this STiROT exmaple information is on-topic, but I thought it might be relevant.

Extending on the seemingly inaccessible stack address, could it be that the call to unsecure_sram3 does not behave as expected (if I understand the code correctly, then that function should "unsecure" the memory to be used by the nonsecure application)? I don't really understand why that call is needed anyways, because the SAU does not configure SRAM3 (0x20000000->...) to be secure.

By the way, @CMYL , I have tested the STiROT_Appli_TrustZone I mentioned in my previous post on Windows as well, and also there it does not work.

After some more debugging, I found that there is a difference between:

  • the code for a secure+nonsecure application that is generated by CubeMX
  • the checked-in secure+nonsecure code for the *_TrustZone applications

Importantly, :

In the CubeMX generated code, 0xFFFFFFFF is written to MPCBB_PrivConfig_array. In the *_TrustZone applications, 0 is stored there. 

Changing that part, however, does not fix the problem still.

As an experiment, I tried to use CubeMX for OEMiROT as described on

There it fails in step 8:

  • When I press the black button, the board indeed resets and the blue LED starts blinking;
  • But when I press the blue button, the blue LED stops blinking
    • By using the programmer to read the PC, it points to the infinite loop in the hardfault handler of the secure application.
    • Following the hard fault analysis procedure as I described in a previous post in this thread, the BFAR register is valid and also points to 0x2009FFFC

Hi @CMYL ,

I think I have found a possible solution. However, I cannot explain the problem currently.

To summarize all above posts:

  • Running the TrustZone examples on the STM32H573 DK results in a hard fault;
  • The error seems to be consistent across different examples: BFAR=0x2009FFFC;
  • BFAR is the address of the last word on the stack of the non-secure application.

As one of many attempts to try to find out what is going wrong, I tried to read each memory region by:

  • Provisioning the device with the TrustZone example (;
  • Opening debug (;
  • Reading memory addresses on each 64K stack block address: 0x20050000, 0x20060000, 0x20070000, 0x20080000, 0x20090000 (e.g., ./ -c port=SWD speed=fast ap=1 mode=Hotplug -r32 0x20090000 4).

From this experiment, it looks like the memory region 0x20090000 - 0x200A0000 is not accessible on the device: memory can not be read:

./ -c port=SWD speed=fast ap=1 mode=Hotplug -r32 0x20090000 4
                        STM32CubeProgrammer v2.14.0

ST-LINK SN  : 004E00253431510937393937
Board       : STM32H573I-DK
Voltage     : 3.31V
SWD freq    : 8000 KHz
Connect mode: Hot Plug
Reset mode  : Software reset
Device ID   : 0x484
Revision ID : --
Device name : STM32H5xx
Flash size  : 2 MBytes (default)
Device type : MCU
Device CPU  : Cortex-M33
BL Version  : 0xE4
SFSP Version: v2.5.0
Debug in Low Power mode enabled

Reading 32-bit memory content
  Size          : 4 Bytes
  Address:      : 0x20090000

Error: failed to read the requested memory content

The solution I found is the following:

  • Modify the default linker script of the non-secure application to make the stack end address equal 0x20090000 instead of 0x200A0000:
    • Change: RAM (xrw) : ORIGIN = 0x20050000, LENGTH = 320K
    • To: RAM (xrw) : ORIGIN = 0x20050000, LENGTH = 256K

By doing that, the example works.

But why? Is there something in that memory region that is protected by maybe STiROT?