Skip to main content
NAhme.2
Associate
May 21, 2021
Question

Continuous reset loop with SBSFU on STM32L4R9. Reset always happens right at the moment the secure engine is called.

  • May 21, 2021
  • 12 replies
  • 5567 views

When the Secure Engine Call (inside SE_Init() function) is called in this line:

e_ret_status = (*SE_CallGatePtr)(SE_INIT_ID, peSE_Status, primask_bit, uSystemCoreClock);

(which is between a SE_EnterSecureMode and SE_ExitSecureMode).

The MCU resets at this point, the reset happens continuously (reset loop) always at this line. The code executed until after SE_EnterSecureMode(&primask_bit); is called. I have added TRACE calls to check this.

Here is the problem area:

/* Enter Secure Mode */
 TRACE("\r\n= [SE_Init] SE_EnterSecureMode...");
 SE_EnterSecureMode(&primask_bit);
 
 /* Secure Engine Call */
 TRACE("\r\n= [SE_Init] (*SE_CallGatePtr)..."); //RESET HAPPENS BELOW:
 e_ret_status = (*SE_CallGatePtr)(SE_INIT_ID, peSE_Status, primask_bit, uSystemCoreClock);
 TRACE("\r\n= [SE_Init] (*SE_CallGatePtr) done");
 
 /* Exit Secure Mode */
 TRACE("\r\n= [SE_Init] SE_ExitSecureMode...");
 SE_ExitSecureMode(primask_bit);

I have setup all other paramters correctly for STM32L4R9 following AN5056 section 3 (Porting X-CUBE-SBSFU to another board) and have made appropriate memory mapping changes for Secure Engine, SBSFU, Download Area, Active Image defined flash sections. Also the SE RAM1 sections. As per errata, I have defined SE firewall protected RAM1 to be under maximum 128KB (instead of 192KB) - actually just 4KB.

I have also seen this issue and applied the recommendation, to no success:

https://community.st.com/s/question/0D50X0000ADEGfr/firewall-reset-when-accessing-unprotected-sram1-memory-stm32l4r9

I have no idea what is happening. I'm not even sure it's the firewall spurious reset. I disabled SFU_FWALL_PROTECT_ENABLE define and the same issue persists. Also if it was an actual firewall (or other reset) I would get the TRACE printout telling me that. This is just a inexplicable reset.

0693W00000AP7mlQAD.png

Any help is appreciated. It's a complete showstopper with SBSFU.

This topic has been closed for replies.

12 replies

firmwareguru
Graduate
May 25, 2021

Hi, I have spent much time working with the X-CUBE-SBSFU system.

To start, I would ensure that *all* protections are off. That means the SBSFU should not be allowed to set any option bytes during its initialization.

I routinely use the debugger (STM32CubeIDE + STLINK) to trace through SBSFU and SECoreBin. This can be accomplished by ensuring the protections are off (RDP level 0 is set and remains set) and by loading the symbols from both SECoreBin and SBSFU elf files into the debugger, while only downloading the SBSFU binary to the target (since the SBSFU binary includes the SECoreBin binary).

The reset could be that SE_CallGatePtr is NULL (hard fault).

The best way to find out is really to fire up the debugger and step through the function calls. You do not need to build the applications any differently.

Let us know how that goes.

NAhme.2
NAhme.2Author
Associate
May 26, 2021

Hi!

Thanks for your response!

So I've tried with disabling all the protections RDP, WRP, PCROP, FWALL, TAMPER, DAP, DMA, IWDG, MPU, but the same issue persists. Which leads me to believe it's not any of these protections that are causing reset, but there is another issue.

Not sure why SE_CallGatePtr would be NULL as the macro SET_CALLGATE(); is called inside SE_Init(..). That should be setting up the Callgate function pointer.

I have not modified much in the code other than changing the UART port, and modifying the memory mapping for download/active area and teh SE RAM Region addresses (in mapping_fwimg.ld, and mapping_sbsfu.ld files). These are very straightforward and I've checked 10x to make sure everything correct here.

When I debug, if I put breakpoint at

e_ret_status = (*SE_CallGatePtr)(SE_INIT_ID, peSE_Status, primask_bit, uSystemCoreClock);

then the program runs to that line and stops. If I put breakpoint on next line of code "SE_ExitSecureMode(primask_bit);", the debugger is "lost" and if I pause it goes to 0x1fff355c "break at 0x1fff355c with no debug information available, or outside of program code." If I press the "reset" button to restart debug from main function start, It does not work as debugger is lost. I have to exit and re-enter debugging and same thing repeats. What do I look for now? any ideas?

firmwareguru
Graduate
May 27, 2021

Well it certainly appears that the Program Counter is going off into the weeds.

Can you provide the value, as reported by the debugger, of SE_CallGatePtr before that line is executed? I would expect it to be somewhere in system flash starting at 0x08000000.

On the protections, have you verified that they are not actually enabled in the option bytes on your target? Use STM32CubeProgrammer to go through the option bytes like firewall etc. to ensure they are off or disabled. I am not sure if the latest X-CUBE-SBSFU has a regression script (regression.sh) like the TF-M offering in the project directory, but if it does that could be run to reset the option bytes.

NAhme.2
NAhme.2Author
Associate
May 27, 2021

So the value of SE_CallGatePtr is <optimized out> when I stop program before that line is executed (by breakpoint).

0693W00000AQ6Z4QAL.png 

As for protections, I can see from Option Bytes read through STM32CubeProgrammer that Read Out Protection is AA: Level 0. Also PCROP and Write Protection in Bank 1 are also disabled. These have to be disabled anyway to reprogram/flash device and debug. For firewall specifically I don't see anything in Option Bytes > User Configuration or anywhere else.

For the SE_CallGatePtr being optimized out - could that be an issue? however why does the example project work for the STM32L476G-DISCO board without any issues? As I said I only modified few things and am testing on the STM32L4R9I-DISCO.

Would it help if I sent you a .zip of the SBSFU+SECoreBin projects?

firmwareguru
Graduate
May 28, 2021

The SE_CallGatePtr is set with this function:

#define SET_CALLGATE() \
 SE_ErrorStatus(*SE_CallGatePtr)(SE_FunctionIDTypeDef ID, SE_StatusTypeDef *peSE_Status, \
 ...); /*!< Secure Engine CALLGATE pointer function*/ \
 SE_CallGatePtr = (SE_ErrorStatus(*)(SE_FunctionIDTypeDef, SE_StatusTypeDef *, \
 ...))((uint32_t) SE_CALLGATE_REGION_ROM_START + 1U);

It is fixed to SE_CALLGATE_REGION_ROM_START + 1U. What is the value of SE_CALLGATE_REGION_ROM_START from your linker configuration? Better yet, go into the project .map file and search for it to find the actual value the linker placed it at.

The arguments could also be a problem and source of faulting. peSE_Status is a pointer to 0x2009ffe0. This a region located at the very end of the 384 KB SRAM3 area (0x5FFE0 into 0x60000 total available) of the L4R9 device. It must be pointing to a stack location 32 bytes down from the top. This has to be where SBSFU is operating out of right now.

NAhme.2
NAhme.2Author
Associate
May 28, 2021

So in mapping_export.h:

extern uint32_t __ICFEDIT_SE_CallGate_region_ROM_start__; 
#define SE_CALLGATE_REGION_ROM_START ((uint32_t)& __ICFEDIT_SE_CallGate_region_ROM_start__)

and then in mapping_sbsfu.ld:

VECTOR_SIZE = 0x200;
__ICFEDIT_SE_Code_region_ROM_start__ = 0x08000000 + VECTOR_SIZE;
__ICFEDIT_SE_CallGate_region_ROM_start__ = __ICFEDIT_SE_Code_region_ROM_start__ + 0x4;

So therefore __ICFEDIT_SE_CallGate_region_ROM_start__  should be 0x08000000 + VECTOR_SIZE(0x200) + 0x4 = 0x8000204

in the .map file created by linker this value is confirmed:

0x0000000008000204 __ICFEDIT_SE_CallGate_region_ROM_start__ = (__ICFEDIT_SE_Code_region_ROM_start__ + 0x4)

As for SBSFU SE under firewall I have:

(this is not modified by me, neither is the above).

/* RAM section */
/* SE RAM1 region protected by firewall */
/* SE stack is placed 1st in RAM, stack overflow does not write on other RAM area */
__ICFEDIT_SE_region_RAM_start__ = 0x20000000;
__ICFEDIT_SE_region_RAM_stack_top__ = 0x20000400;
__ICFEDIT_SE_region_RAM_end__ = 0x20000FFF;

But as for SBUSFU RAM Region I am using RAM3:

/* SBSFU RAM region */
__ICFEDIT_SB_region_RAM_start__ = 0x20081000; /*OLD: __ICFEDIT_SE_region_RAM_end__ + 1;*/
__ICFEDIT_SB_region_RAM_end__ = 0x2009FFFF;

So that is because, as per errata, we don't have overlap of the low 18-bits with SE Firewall in RAM1 region. This issue is explained here:

https://community.st.com/s/question/0D50X0000ADEGfr/firewall-reset-when-accessing-unprotected-sram1-memory-stm32l4r9

So what do you recommend here? Is this the issue? SB_region_RAM has a good 128KB as per region defined above.

Jocelyn RICARD
ST Employee
May 29, 2021

Hello,

looking at your description it seems that your board is setup to boot on system bootloader.

Reason I'm telling this is that you get 0x1fff355c address.

So, if this is the case, the remap at address 0 is the system bootloader and not the user flash.

On first interrupt you jump to the VTOR address which I think is not set to user flash but left at 0.

So, you you please look at you boot option bytes?

Also, what happens if you don't use the debugger, is your STM32 booting on SBSFU ?

Best regards

Jocelyn

NAhme.2
NAhme.2Author
Associate
May 29, 2021

Hi Jocelyn,

Yes whether or not using debugger, the STM32 boots SBSFU, as SBSFU (incl. SECoreBin) are programmed to device, no user application. So it's expected the system boots SBSFU. But the problem is described in my first post that it's constantly resetting at the line Secure Engine Call with SECallGate pointer.

This SBSFU code works well for STM32L476 DISCO board, to modify it to run on STM32L4R9 DISCO board, I changed flash mapping, UART for printf, and some project files to change the STM32 defined as STM32L476xx to STM32L4R9xx. No functional code changes were made. I'm not sure what is missing in ST SBSFU documentation that I'm not doing which is causing this issue.

Jocelyn RICARD
ST Employee
May 31, 2021

Hello,

OK, then the issue is very probably related to a test made in the secure engine to check that calling address or data provided is located at the right place.

To figure this out one way is to add the symbols of the secure engine in your SBSFU debug session and go step by step in assembly mode.

This will allow you to find the location of the test that leads to the system reset.

You can also review the content of the se_callgate.c and look for the calls to NVIC_SystemReset.

Best regards

Jocelyn

NAhme.2
NAhme.2Author
Associate
May 31, 2021

Hello Jocelyn,

You are exactly right, over the weekend that exactly what I did. I loaded the .elf symbols from SECoreBin for debugging in the SBSFU project.

And I placed breakpoint for SECallGate function calls and figured out the issue was happening in the SECoreBin project file se_low_level.c in the function:

SE_ErrorStatus SE_LL_Buffer_in_ram(void *pBuff, uint32_t Length)

At the if statement check:

 /* Check if length is positive with no overflow */
 if ((Length != 0U) && (!((0xFFFFFFFFUL - addr_start) < Length))
 && (((addr_start >= SRAM1_BASE) && (addr_end <= 0x20017FFFU)) ||
 ((addr_start >= SRAM2_BASE) && (addr_end <= 0x10007FFFU))))

So this of course is using hard-coded values for SRAM1 and SRAM2 end address checking. Also I was using SRAM3 which the STM32L4R9 has, but not the STM32L476. So I modified this check and this issue is now resolved!.

I wish ST didn't hard-code these values and used #define constant names based on which microcontroller is defined for the project. As a developer I am using ST's software libraries to develop an end product, and really spent way too much time debugging this issue. I see most everywhere else there are no such hard-coded values, so this one was a bit of a surprise.

Nabeel

Jocelyn RICARD
ST Employee
May 31, 2021

Hello Nabeel,

OK thank you for your feedback.

I had a look to other projects and this value is not always hardcoded.

I guess the reason here is that we need to provide the whole RAM and there is no symbol that can be used for this purpose.

Also, even if a symbol could be used, in your case you would still had to modify the code to add this SRAM3.

Anyway, I agree this is frustrating !

Best regards

Jocelyn

NAhme.2
NAhme.2Author
Associate
June 2, 2021

Hi Jocelyn,

So moving on from this issue, is there possibly other hard-coded areas of the firmware?

Now with the first issue resolved, I get the following (All the protections in app_sfu.h are disabled for now during debugging/tesitng):

= [SBOOT] SECURE ENGINE INITIALIZATION SUCCESSFUL
= [SBOOT] STATE: CHECK STATUS ON RESET
          INFO: A Reboot has been triggered by a Software reset!
          INFO: Last execution detected error was: No error. Success.
= [SBOOT] STATE: CHECK NEW FIRMWARE TO DOWNLOAD
= [SBOOT] STATE: CHECK USER FW STATUS
          New Fw to be installed from slot SLOT_DWL_1
= [SBOOT] STATE: INSTALL NEW USER FIRMWARE
          Abnormal error 2 at line 1161 in D:/Robbox/new_project/level/STM32_SBSFU/Project/STM32L4R9_Level/Applications/2_Images/2_Images_SBSFU/SBSFU/App/sfu_fwimg_swap.c - CONTINUE
= [SBOOT] STATE: HANDLE CRITICAL FAILURE
= [EXCPT] DECRYPT FAILURE!
= [SBOOT] STATE: REBOOT STATE MACHINE
========= End of Execution ==========

Abnormal error 2 seems to points to "SFU_IMG_FLASH_WRITE_FAILED" as the return status for the function call "SFU_LL_FLASH_Write(...) in sfu_fwimg_swap.c

Any ideas why this is happening now?

Jocelyn RICARD
ST Employee
June 3, 2021

Hello,

STM32L4R9 can be single or dualbank.

You need to check if the conversion between address and page is adapted to your configuration

Best regards

Jocelyn

NAhme.2
NAhme.2Author
Associate
June 3, 2021

Hi,

can you explain that a little more.

so far I’ve disabled dual-bank operation in the option bytes, and also defined NO_SWAP.

Where do I check/configure what you’re saying?

Jocelyn RICARD
ST Employee
June 3, 2021

Hello,

Depending on the example you used as source to make your porting you may need to adapt what the code located in SBSFU/Target

especially sfu_low_level_flash_int.c

Easiest way to understand what happens is to put a breakpoint on the call to flash write just before the line 1161, and go into to understand where it fails

Best regards

Jocelyn

NAhme.2
NAhme.2Author
Associate
June 3, 2021

Hi Jocelyn,

Thank you for your quick responses!

So when I disable all the protections in app_sfu.h, the above issue on line 1161 disappears (I was wrong in that post when I said protections were disabled, they were all enabled actually).

So now (with app_sfu.h protections disabled) I'm able to send a full image (UserApp.sfb) over YMODEM using TeraTerm. After the full image transfer, it Reboots and beings to install the new image, but doesn't proceed beyond that. So it's stuck installing the update somehow:

= [SBOOT] SECURE ENGINE INITIALIZATION SUCCESSFUL
= [SBOOT] STATE: CHECK STATUS ON RESET
 INFO: A Reboot has been triggered by a Software reset!
 INFO: Last execution detected error was: No error. Success.
= [SBOOT] STATE: CHECK NEW FIRMWARE TO DOWNLOAD
= [SBOOT] STATE: CHECK USER FW STATUS
 New Fw to be installed from slot SLOT_DWL_1
= [SBOOT] STATE: INSTALL NEW USER FIRMWARE
 Image preparation done.
 Installation started ...

So it never proceeds after the "Installation started ..."

I am trying to get this working with all protections disabled, then will solve the issues related to that once I have at least a setup working with protections disabled.

Any clues to the above?

PS: I have adapted SBSFUs STM32l476G-DISCO example for use with my STM32L4R9VGT project.

Nabeel

NAhme.2
NAhme.2Author
Associate
June 3, 2021

The SBSFU is now fully working on STM32L4R9VG. As for the last issue in recent conversation, I had to re-enable dual-bank operation in the Option Bytes (using STM32CubeProgrammer) - which are enabling DB1M, and DBANK. Due to the fact that the SBSFU code I'm using was based on STm32L476G which had code in sfu_low_level_flash_int.c for dual-bank mode erase etc., I also re-enabled dual-bank on STM32L4R9. Or else in single-bank mode only mass erase it used, not bank erase - so this would've required rewriting code in that file, any other possible unforeseen consequences. The issue on pausing at "Installation Started..." had to to with the system hanging in the erase operation awaiting last operation to finish. Also for STM32L4R9 there isn't MPU protection (as far as I've seen) so those protections are disabled in app_sfu.h.

It is now fully working with all other protections enabled.

Jocelyn RICARD
ST Employee
June 4, 2021

Hello,

OK thank you for your feedback.

Just for your information, single bank is normally easier to manage as there is no risk related to firewall vs bank swap. This releases a constraint on the mapping of the slots. If you want to make single bank working, normally only flash service implementation in target directory is needed to be changed.

Best regards

Jocelyn