2024-12-06 12:31 PM
I'm currently using a NUCEO-U5A5ZJ-Q development board and having an issue jumping from the Application code into the Bootloader. Two major issues are the Application is running ThreadX, and the board has the TrustZone enabled.
Through experimentation, I've determined how to successfully jump into the bootloader when the TrustZone is disabled. Effectively, the code to jump into the bootloader must be done BEFORE executing the "MX_ThreadX_Init( )" instruction in main.c. Any attempt to jump into the bootloader after the MX_ThreadX_Init call results in a HardFault during the execution (initialization?) of the bootloader code.
However, now with the TrustZone enabled, I have been unsuccessful at bringing up the bootloader code without a HardFault being generated. The jump into the System Memory bootloader at 0x0BF90000 is successful, but always results in a HardFault due to trying to access a NULL value during the execution (initialization?) of the bootloader code.
Is there any advice you can give me to on how to get this to work?
Some questions I have:
Thank you!
Steve.
-
2024-12-09 01:57 AM
Hello @SDSigma ,
are you attempting to jump from bootloader from secure or non-secure context?
can you share the sequence in which you attempt the jump as this can be related to security constrains.
Regards
2024-12-09 05:06 AM
I have tried to jump to the bootloader from both the main.c in the secure side and also from main.c in the nonsecure side with similar results. The bootloader is entered using either method as I can step through the System Memory Bootloader assembly code within the STM32CubeIDE debugger, however both always end in a HardFault when allowed to run.
The code being used to jump to the bootloader is as follows:
void jump_to_bootloader( void )
{
uint32_t ndx;
void (*SysMemBootJump)( void ); /* Prototype for the jump function */
/* Disable all interrupts */
__disable_irq();
/* Disable Systick timer */
SysTick->CTRL = 0;
/* Set the clock to the default state */
HAL_RCC_DeInit();
/* De-initialize all peripherals */
HAL_DeInit();
/* Clear Interrupt Enable Register & Interrupt Pending Register */
for( ndx = 0; ndx < sizeof(NVIC->ICER) / sizeof(NVIC->ICER[0]); ndx++ )
{
NVIC->ICER[ndx] = 0xFFFFFFFF;
NVIC->ICPR[ndx] = 0xFFFFFFFF;
}
/* Re-enable all interrupts */
__enable_irq();
/* Set up the jump to bootloader address + 4 */
SysMemBootJump = (void (*)(void))(*(uint32_t *)(BOOTLOADER_ADDRESS + 4));
/* Set the main stack pointer to the boot loader stack */
__set_MSP(*(uint32_t *)BOOTLOADER_ADDRESS);
/* Call the function to jump to boot loader location */
SysMemBootJump();
/* Should never get here */
for( ; ; ) { }
}
The two places I've tried calling the function:
// From main.c in the secure project
int main(void)
{
/* SAU/IDAU, FPU and interrupts secure/non-secure allocation setup done */
/* in SystemInit() based on partition_stm32u5a5xx.h file's definitions. */
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the System Power */
SystemPower_Config();
/* GTZC initialisation */
MX_GTZC_S_Init();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SPI2_Init();
/* USER CODE BEGIN 2 */
/* Jump to the bootloader BEFORE initializing the nonsecure code */
jump_to_bootloader();
/* USER CODE END 2 */
/*************** Setup and jump to non-secure *******************************/
NonSecure_Init();
// From main.c on the nonsecure project
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ICACHE_Init();
MX_SPI1_Init();
/* USER CODE BEGIN 2 */
/* Call to jump to bootloader here BEFORE calling the ThreadX init */
jump_to_bootloader();
/* USER CODE END 2 */
MX_ThreadX_Init();
2024-12-10 07:56 AM
Hello @SDSigma ,
"The bootloader is entered using either method as I can step through the System Memory Bootloader assembly code within the STM32CubeIDE debugger"
you are able to jump to bootloader and execute then a hardfault occurs can you give more details about the hardfault and what caused it as this is not related to the jump process if i get you right just note that Products with security using TrustZone isolation - Boot_V3 including the U5 series
a) Boot depending on TrustZone value - Boot_V3_1 (see Figure 11) When TZEN is enabled, some constraints are added to the BL functionalities:
> Boot timing is different from the TZEN disabled use case
> Before jumping to the BL, the SFSP maps all the needed resources by the BL
to the non-secure domain. A jump from the BL (“Go” command) to an application using other resources does not work.
> Some secure option bytes are not accessible as the bootloader is non-secure. Some APIs are added on the SFSP to guarantee that the BL can modify them on open products states (Open, RDP L0).
> Some parts of the SRAM are used by the SFSP and remain on Secure domain when jumping to the BL, so are not accessible by the customer through BL
see section 4.10 of AN2606 for more details.
Regards
2024-12-10 11:39 PM
Hello,
I may be mistaken, but I believe I read in the reference manual that when TZ is active, the bootloader present in the MCU's ROM may no longer be accessible.
For security reasons, the MCU is forced to boot from address SECBOOTADD0 or within the RSS zone. This information also depends on the RDP level, which can prevent access to the RSS.
You can find this information in section 3 of the reference manual RM0456, pages 191 and 192.
2024-12-11 06:14 AM
Thank you to all that have replied to this topic.
Since the software solution looks to be difficult (or maybe not possible), we have instead decided on a hardware/software solution to get the unit into bootloader mode.
Hardware portion:
Software portion:
When the processor resets, the BOOT0 pin will still be high so it will jump into the bootloader.
After a number of seconds, the capacitor will discharge so any subsequent resets will return to normal boots.