Search code examples
craspberry-pi-picozephyr-rtosmcuarm-mpu

Hard fault RP2040 pico Zephyr


I'm using RP2040 under Zephyr and MCUboot. The final goal is to be able to update the firmware using MCUMGR over an UART bus. MCUboot use A/B seamless (dual slot memory) method to provide a safe update algorithm. When device reboot, MCUboot check if a new firmware is available and in this case boot on new firmware. To do this, a swap algorithm place the target firmware in slot 0. As this algorithm manipulate flash, some function has to be mapped inside SRAM to be sure that function doesn't erase his own code. Normally, code is directly executed from flash thanks to Direct-XIP on RP2040. The problem is that SRAM seams to not be executable. When the program enter inside the function located in SRAM and execute the very first instruction this cause a hard fault:

0x2000c144 <flash_range_erase>: push {r4, r5, r6, r7, lr}

Fortunately, Zephyr crash's handler give some informations:

E: ***** HARD FAULT *****
E: r0/a1:  0x0003d000  r1/a2:  0x00002000  r2/a3:  0x00002000
E: r3/a4:  0x00000000 r12/ip:  0x2000c145 r14/lr:  0x100022e5
E:  xpsr:  0x21000000
E: Faulting instruction address (r15/pc): 0x2000c144
E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
E: Current thread: 0x2000c3d0 (unknown)
E: Halting system

Everything seems normal and the address of the pc is correct. I strongly suspect a MPU misconfiguration which crash the program when executing code located in SRAM.

My question is:

Can MPU cause Hardfault ? How can i configure SRAM in Zephyr to execute code from SRAM ?

First, i tried to check if the function same is executable from flash. I removed the macro that indicate to located on flash.

Before:

void __no_inline_not_in_flash_func(flash_range_erase)(uint32_t flash_offs, size_t count) {
...

After:

void flash_range_erase(uint32_t flash_offs, size_t count) {
...

And ... it works ! The functions is executed as expected. I'm quite sure right now that the MPU is unhappy to let me execute code inside SRAM.

I searched informations about how to configure MPU to let me execute code in SRAM and i found this page: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/hardware/arch/arm_cortex_m.html That explain how to configure fixed regions. I added the following lines in my device tree overlay:

&sram0 {
    /delete-property/ compatible ;
    /delete-property/ reg ;
    compatible = "zephyr,memory-region", "mmio-sram";
    zephyr,memory-region = "RAM_EXECUTABLE";
    zephyr,memory-region-mpu = "RAM";
    reg = < 0x20000000 0x10000 >; //Configure SRAM for MCUboot fixed for MPU
    // RAM size has to match with BOOTLOADER_SRAM_SIZE (see menuconfig)
};

But this didn't solve the problem.


Solution

  • It was an issue in flash controller of the RP2040 in Zephyr.

    The flash controller has to disable XiP to run flash operations (r/w). During this process the controller tried to run a function that was not linked in RAM (was in flash).

    To resume, the controller tried to call a function that was in flash after disabling the flash execution. I'll probably post a patch soon.

    More infos on Zephyr's discord here: https://discord.com/channels/720317445772017664/938474761405726800/1060917537405157446

    Note in my question i tried to use the MPU but i had to disable on bootloader configuration.