cancel
Showing results for 
Search instead for 
Did you mean: 

MPU configuration in combination with sbsfu (secure boot and secure firmware upgrade) package.

Denny1
Associate

I'm currently porting an existing project so it can be updated using the sbsfu bootloader project from ST.

My userproject is using the MPU to protect the ethernet tx and rx descriptors from ending up in the d cache. However, if i enable the MPU the FPU stops working. Upon the first floating point operation the processor goes into the hardfault handler. Then the MM Fault stat register contains a 0x20. Which corresponds to the MLSPERR bit :

A MemManage fault occurred during floating-point lazy state preservation.

I'm using the following code to enable the MPU:

void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};
 
  /* Disables the MPU */
  HAL_MPU_Disable();
  /** Initializes and configures the Region and the memory to be protected 
  */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0x30040000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_256B;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
 
  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /** Initializes and configures the Region and the memory to be protected 
  */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER1;
  MPU_InitStruct.BaseAddress = 0x30044000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
 
  HAL_MPU_ConfigRegion(&MPU_InitStruct);
  /* Enables the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
 
}

The bootloader project is based on the 2 image version of the Nucleo-H753ZI sbsfu sample project, and ported to the H743ZI processor which is used in the project i'm working on. For debugging i disabled all of the provided security options.

I really do not want to do the MPU config in the bootloader code if i do not have to, as I would like to be able to change the configuration in later updates. Is it even possible to change the MPU in user code?

1 ACCEPTED SOLUTION

Accepted Solutions
Denny1
Associate

I hope i can help anyone experiencing the same problem. After a long period of debugging we think we found the problem.

The cortex m7 has a lazy state preservation function in the floating point unit. (http://infocenter.arm.com/help/topic/com.arm.doc.dai0298a/DAFGGBJD.html). In the sbsfu bootloader the Application code is started from an interrupt (this is done to ensure user code is started in privileged mode). However, because the user application code never returns, this interrupt never returns.

From here I will have to guess what the real problem is, in my opinion it could be one or a combination of the following:

  • The lazy stacking is never reset (because the interrupt does not return)
  • The stack is relocated (Because the user application is started).
  • The interrupt vector table is relocated.

As the problem was only happening when we enabled the MPU, i think the MPU was preventing the FPU from putting the values currently in the registers in the bootloader stack.

We fixed this by resetting the FPU lazy stacking in the systemInit of the user application code:

/* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
	SCB->CPACR &= ~((3UL << 10*2)|(3UL << 11*2));  /* Disable CP10 & CP11 */
	FPU->FPCCR = 0; //REMOVE THE STACKED VALUES FROM THE BOOTLOADER
	FPU->FPCCR |= FPU_FPCCR_LSPEN_Msk; //RE ENABLE LAZY STACKING
	FPU->FPCCR |= FPU_FPCCR_ASPEN_Msk;
        SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
#endif

Probably it is also possible to reset the FPU in the interrupt where the user application is started, but we didn't try this.

View solution in original post

1 REPLY 1
Denny1
Associate

I hope i can help anyone experiencing the same problem. After a long period of debugging we think we found the problem.

The cortex m7 has a lazy state preservation function in the floating point unit. (http://infocenter.arm.com/help/topic/com.arm.doc.dai0298a/DAFGGBJD.html). In the sbsfu bootloader the Application code is started from an interrupt (this is done to ensure user code is started in privileged mode). However, because the user application code never returns, this interrupt never returns.

From here I will have to guess what the real problem is, in my opinion it could be one or a combination of the following:

  • The lazy stacking is never reset (because the interrupt does not return)
  • The stack is relocated (Because the user application is started).
  • The interrupt vector table is relocated.

As the problem was only happening when we enabled the MPU, i think the MPU was preventing the FPU from putting the values currently in the registers in the bootloader stack.

We fixed this by resetting the FPU lazy stacking in the systemInit of the user application code:

/* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
	SCB->CPACR &= ~((3UL << 10*2)|(3UL << 11*2));  /* Disable CP10 & CP11 */
	FPU->FPCCR = 0; //REMOVE THE STACKED VALUES FROM THE BOOTLOADER
	FPU->FPCCR |= FPU_FPCCR_LSPEN_Msk; //RE ENABLE LAZY STACKING
	FPU->FPCCR |= FPU_FPCCR_ASPEN_Msk;
        SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
#endif

Probably it is also possible to reset the FPU in the interrupt where the user application is started, but we didn't try this.