cancel
Showing results for 
Search instead for 
Did you mean: 

HardFault in NetxDuo crypto_libraries in External Memory

Zainulabedeen
Associate III

Hey all,

For reference I am enabling the https server using NetxDuo Stack for firmware update in my device.

Initially we were using Internal Flash but now we are interested in External Flash particularly SDRAM. I was able to boot the application code from SDRAM, however i am facing a problem, whenever i call a rest API like GET request a hardfault occurs where the stack traces shows it is originated over _nx_crypto_sha256_update() function in the nx_crypto_sha2.c file over the use the memcpy(). The strange thing is everything works with no hardfault when application work in Internal Flash.

Furthermore, I am able to run RTOS on SDRAM and i can ping my IP on ethernet as well.

Kindly someone help me out for this, i will be grateful.

Also if i should report this behavior somewhere else?

Thanks

1 ACCEPTED SOLUTION

Accepted Solutions

Ok, I am able to solve this issue  by making the SDRAM region as cachable as well as bufferable through MPU.

 

I have one question why can i call MPU_Config in application in External Flash but not in SDRAM ?

 

Thanks

View solution in original post

6 REPLIES 6

Perhaps show a register dump and code at the Fault

What memory addresses is the memcpy() acting on? Is it aligned?

An effective Hard Fault dump of registers, stack and opcodes will help get some action, as would a minimally buildable project illustrating the failure.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

The memcpy at the entry or exit?

https://github.com/STMicroelectronics/stm32-mw-netxduo/blob/db332daede217a6536daf69c6ea474c223c909b0/crypto_libraries/src/nx_crypto_sha2.c#L189

How are you allocating the memory being used to store structures?

The memcpy's are typically acting on the context's buffer when the inputs are feed in blocks other than 64 byte multiples. Perhaps instrument the calling to see the flow dynamics prior to the hard fault failure. Perhaps you can use that to extract a minimally failing test case?

Check alignment of context buffer. Is that also in SDRAM ?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Here is the stack that is being shown when i do GET request:

 
 

Zainulabedeen_2-1757087831461.jpeg

Here is the mapping of the address to show the line number from where the error is triggering from:

using the arm-none-eabi-addr2line  I have mapped these address to the line number 

0xc070156e   Function : HardFault_Handler,  File:  stm32h7xx_it.c Line: 94

0xc070093e   Function : memcpy, File: ?,  Line: ??

Zainulabedeen_3-1757089325753.png

0xc0719e96  Function : _nx_crypto_sha256_update function, File: nx_crypto_sha2.c, Line: 268

 

> What memory addresses is the memcpy() acting on? Is it aligned?

Is there a better way to debug this ? and how to check if the memcpy() memory address is aligned ?

> The memcpy at the entry or exit?

Based on the line number, it is most probably the exit one.

> How are you allocating the memory being used to store structures?

Seems like this is being called by NetxDuo and is passed as a pointer are you saying I should track whether it is dynamically created ?

> Check alignment of context buffer. Is that also in SDRAM ?

I think it is aligned and not in SDRAM.

 

More Context

I tried running the same application by booting from External Flash as well and it worked fine there with no problem.

If booting the application from SDRAM, the https won't work because of this HardFault however the http still work with REST APIs. Only this crypto related file cause Hardfault in that case.

Also for the case of SDRAM, i removed the systemInit() function from the application startup script as it was causing error and the MPU configuration is disabled in application as it was already enabled and working in bootloader:

Here is my bootloader MPU configuration:

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      = 0x0;
    MPU_InitStruct.Size             = MPU_REGION_SIZE_4GB;
    MPU_InitStruct.SubRegionDisable = 0x87;
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_DISABLE;
    MPU_InitStruct.IsShareable      = MPU_ACCESS_SHAREABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /** Initializes and configures the Region and the memory to be protected
     */
    MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    MPU_InitStruct.BaseAddress      = 0x24000000;
    MPU_InitStruct.Size             = MPU_REGION_SIZE_128KB;
    MPU_InitStruct.SubRegionDisable = 0x0;
    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;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /** Initializes and configures the Region and the memory to be protected
     */
    MPU_InitStruct.Number       = MPU_REGION_NUMBER2;
    MPU_InitStruct.Size         = MPU_REGION_SIZE_256B;
    MPU_InitStruct.IsCacheable  = MPU_ACCESS_NOT_CACHEABLE;
    MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /* Region 4: External Flash (OCTOSPI, 0x90080000  - 0x907FFFFF) now with Full Access (readable & writable)
     * This area is removed from Region 0 to apply the desired access rights here.
     */
    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress      = 0x90000000;
    MPU_InitStruct.Size             = MPU_REGION_SIZE_8MB;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; // Read/Write access
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number           = MPU_REGION_NUMBER4;
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE; // If XIP (code execution) is desired; otherwise MPU_INSTRUCTION_ACCESS_DISABLE
    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /* Configure the MPU attributes for SDRAM */
    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress      = 0xC0000000;          // Start address of SDRAM Bank 1
    MPU_InitStruct.Size             = MPU_REGION_SIZE_8MB; // SDRAM size
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE; // Currently MPU_ACCESS_CACHEABLE causes incorrect data
    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number           = MPU_REGION_NUMBER3; // MPU region number
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /* Enables the MPU */
    HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

Thanks a lot.

 

The "better" way is to instrument the code, perhaps put in sanity checks where you check the address range and alignment (with a mask), AND dump actionable data and registers from the fault.

The line number might help it you have the source to hand which the app was built from, but the MCU executes THUMB code, not C code.

Get some viable diagnostics coming out of an available serial port so you can observe dynamic behaviour in a less invasive way, and that you don't have to dig through structures manually. ie automate, so you might refine your ability to catch errant values prior to in faulting, when they are first seen to be wrong.

Adapt something like this to capture and report faulting condition without a debugger. The debugger can help determine source and line info, which otherwise you'll need to fish out of the .MAP or .LST files.

https://github.com/cturvey/RandomNinjaChef/blob/main/KeilHardFault.c

The line number suggests it's the exit memcpy, so check upstream to see how that code is passing blocks of data to the SHA2 update routine, and the integrity of the context passed in.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Ok, I am able to solve this issue  by making the SDRAM region as cachable as well as bufferable through MPU.

 

I have one question why can i call MPU_Config in application in External Flash but not in SDRAM ?

 

Thanks

>>I have one question why can i call MPU_Config in application in External Flash but not in SDRAM ?

I don't know, how exactly does it fail? Does it Fault, if so show register dump from fault to establish WHAT the MCU is objecting too.

Are you using the SDRAM for stack?

Changing how the MCU handles a specific memory, whilst running from that memory, strikes me as a recipe for issues. Bring the external memories up once, and then don't change them a second time, or the clocking, as this can be disruptive.

 

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..