Loading M4 afx from /boot

Until recently we have been succesfully launching our M4 firmware from the /boot directory in the form of a bin file, setting the environt variable in uboot

setenv m4boot 'fatload mmc 0 ${loadaddr} m4_0.bin && bootaux ${loadaddr} 0'

However we have outgrown the space available in the m_text memory (TCM) so have moved const variables and strings into m_data2.

This results in an enormous, mostly empty bin file, so we want to load the M4 executable from an axf file.

However

Colibri iMX8X # fatload mmc 0 ${loadaddr} text_ndb.axf
197320 bytes read in 34 ms (5.5 MiB/s)
Colibri iMX8X # bootaux ${loadaddr} 0
Power on aux core 0
Copy image from 0x89000000 to 0x34fe0000
Start M4
bootaux complete

doesn’t work (the result is a device reboot).

fatload appears to work, and loads the file.

I assume the problem is that nothing is actually interpretting the elf format, and placing the data into the correct places in memory, and the raw data in the file is just being placed in memory.

So, first, I am assuming this is possible - is it ? I’ve seen various posts mentioning this approach although it’s not clear if they are working.

I’ve seen bootelf but our uboot doesn’t have this.

Can bootaux intepret and load the elf data ? Should the fatload be given a different address to load the elf data to initially ?

´U-Boot 2020.04-5.5.0-devel+git.ebd108076039 (Oct 26 2021 - 09:33:45 +0000)´

Hi, I’m the Toradex AI Assistant. The Toradex Support team will follow up with you shortly!

Did you like my answer?

:+1: :-1:


Based on the context provided, it seems that your current U-Boot version (2020.04-5.5.0-devel) does not support the bootelf command, which is typically used for loading ELF files. The bootaux command you are using is not designed to interpret ELF files; it is primarily used for booting auxiliary processors with binary images. Therefore, using bootaux with an ELF file without proper ELF handling will likely lead to issues such as device rebooting.

Since your U-Boot version lacks the bootelf command, and bootaux cannot interpret ELF files, you will not be able to load and execute the axf file successfully with the current setup. You may need to explore alternative methods, such as:

  1. Converting the AXF to a BIN File: Consider converting your axf file to a bin file that can be loaded using bootaux. This might involve using a toolchain or utility that can extract the necessary sections from the ELF file and create a binary image.

  2. Updating U-Boot: If possible, update your U-Boot version to one that includes support for ELF loading with the bootelf command.

  3. Custom ELF Loader: Implement a custom ELF loader in U-Boot that can parse the ELF file and load the sections into the correct memory locations.

Without these changes, the current setup will not be able to handle the ELF format correctly.

Please, also check if these links can help you solve your problem:

IMX7D - can't start M4 elf file from U-boot, works from ULINK debugger.

Actually I have found that on a more recent yocto image I had built for other purposes (to include network-manager) bootelf is present in uboot, even though uboot has an identical version !

So I’m a little confused how it got in there :smiley:

How can I ensure bootelf is included in uboot when bitbaking the image ?

Hi @Timo

Do you know the version of the BSP you are using for both projects?
You can use this command to find this.

tdx-info

Hi Allan,

Our official image displays the following
´´´
Software summary

Bootloader: U-Boot
Kernel version: 5.4.129-5.5.0-devel+git.828ec42a6a32 #1 SMP PREEMPT Wed Oct 27 12:15:27 UTC 2021
Kernel command line: root=PARTUUID=88c3949f-02 ro rootwait video=imxdpufb5:off video=imxdpufb6:off video=imxdpufb7:off
Distro name: NAME=“TDX Wayland with XWayland”
Distro version: VERSION_ID=5.5.0-devel-20211115082809-build.0
Distro variant: -
´´´

and my other test device says

´´´
Software summary

Bootloader: U-Boot
Kernel version: 5.4.129-5.5.0-devel+git.828ec42a6a32 #1 SMP PREEMPT Wed Oct 27 12:15:27 UTC 2021
Kernel command line: root=PARTUUID=3a5de508-02 ro rootwait video=imxdpufb5:off video=imxdpufb6:off video=imxdpufb7:off
Distro name: NAME=“TDX Wayland with XWayland”
Distro version: VERSION_ID=5.5.0-devel-20211115082809-build.0
´´´

This second one was bitbaked the same as the first, though maybe a year later, with a modified local.conf to replace connman with network and modemmanager. So I was surprised to find bootelf in uboot.

I have been sidetracked by other things, so I have yet to test bootelf with our axf, but I don’t doubt that it will work fine.

In any case, we have good reason to update our “official” image (for both networkmanager and uboot with bootelf) and that would be to the latest Torizon.

Just as soon as our own software is looking stable :smiley:

Hmmm.

Actually I’m not getting anywhere with bootelf.

Basically I’m using fatload, followed by bootelf :-

Colibri iMX8X # fatload mmc 0:1 ${loadaddr} test_ndb.axf
197320 bytes read in 34 ms (5.5 MiB/s)
Colibri iMX8X # bootelf -s
"Error" handler, esr 0xbf000000
elr: 000000008008bfc4 lr : 0000000080027d50 (reloc)
elr: 00000000ffeeefc4 lr : 00000000ffe8ad50
x0 : 000000001ffe0000 x1 : 0000000089010000
x2 : 0000000000000a00 x3 : 0000000000000040
x4 : 1ffe0c891ffe0c89 x5 : 00000000ffea92c8
x6 : 0000000000000066 x7 : 00000000fd6acd10
x8 : 0000000000000000 x9 : 0000000000000008
x10: 00000000fd68f440 x11: 00000000fd693780
x12: 0000000000000000 x13: 0000000000000200
x14: 0000000000000002 x15: 0000000000000020
x16: 00000000ffe8aae8 x17: 0000000000000000
x18: 00000000fd680d98 x19: 0000000089000000
x20: 0000000089030020 x21: 0000000000000000
x22: 00000000fd6acd20 x23: 0000000000000000
x24: 0000000000000001 x25: 0000000000000028
x26: 0000000000000000 x27: 0000000000000000
x28: 00000000fd68f400 x29: 00000000fd66f270

Code: eb03005f 540001c1 d65f03c0 f8636824 (f8236804)
Resetting CPU ...

### ERROR ### Please RESET the board ###

I have tried various parameters for bootelf,

  • -p
  • ${loadaddr}
  • ${loadaddr} ${loadaddr}
  • -d ${fdt_addr_r} ${loadaddr} ${loadaddr}

but frankly I don’t understand the addresses and parameters.

Well, I suppose that fatload is loading the raw file data into ${loadaddr}.

Then of course bootelf should interpret the data from that address. So it’s not clear how to instruct bootelf how to do that.

I presume that ´bootelf -p´ should actually work - given that the correct addresses are contained within the axf file.

However, I am also supposing that ${loadaddr} is really where the application should be loaded to, since it’s what we use when loading a simple bin.

I should meantion that the bin works, and that I stripped the debug symbols from the axf file…

Any pointers ?

Looking into this a bit deeper, I am thinking that bootelf is not really designed to launch the M4.

Rather bootaux is the tool for this.

Looking at the classic bin file launch method. First

Colibri iMX8X # fatload mmc 0:1 ${loadaddr} test.bin
197320 bytes read in 34 ms (5.5 MiB/s)

is loading test.bin into DDR.
Then

bootaux ${loadaddr}

actually copies the data from the DDR into the TCM at 0x34fe0000 (AP view == 0x1ffe0000 M4 view). Then it starts the M4 at this same address. See nxp site for more details.

To achieve this from an elf file, I guess we would need a special bootelf-aux loader !

Am I right ?

So, my primary problem is how to load and run the M4 with code which is initialising the DDR ram (m_data2).

Has nobody tried to do this before ?!

Currently I’m thinking that it should be possible to split the binary into two files, and load the m_data2 first with fatload directly to the required address…

So, loading the 2 binaries independently doesn’t quite work :frowning:

I’ve split the binaries using objcopy :-

´´´
arm-none-eabi-objcopy -j .ncache -O binary “test” “test_data2.bin”;
arm-none-eabi-objcopy -R .ncache -O binary “test” “test_app.bin”;
´´´

(n.b. I also trest with --strip-debug but the outputs are the same as might be expected)

I can run the app from MCUXpresso, of course.

Then, if I reset the board (without a power cycle) and interrupt U-Boot, I can

fatload mmc 0:1 ${loadaddr} test_app.bin
bootaux ${loadaddr}

and the app still runs.
On the other hand the app does not run if I do the above after power cycle. This is expected - with a reset, the data is left in memory, whereas after a power cycle the memory is cleared, so the app finds nothing there.
This proves that the data2(.ncache) section has been removed from the test_app.bin.

Unfortunately I have not been able to load the test_data2.bin.
After a power cycle

fatload mmc 0:1 ${loadaddr} test_app.bin
fatload mmc 0:1 0x88000000 test_data2.bin
bootaux ${loadaddr}

the app doesn’t run. There are no obvious errors on the U-Boot console.

I use the address 88000000 because that’s the address of the memory region for m_data2 as specified in the linker script

MEMORY
{
  m_interrupts          (RX)  : ORIGIN = 0x1FFE0000, LENGTH = 0x00000A00
  m_text                (RX)  : ORIGIN = 0x1FFE0A00, LENGTH = 0x0001F600
  m_data                (RW)  : ORIGIN = 0x20000000, LENGTH = 0x00020000
  m_data2               (RW)  : ORIGIN = 0x88000000, LENGTH = 0x08000000
}
:
:
  .ncache :
  {
    *(.rodata)               /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)              /* .rodata* sections (constants, strings, etc.) */
    *(NonCacheable)
    . = ALIGN(4);
    __noncachedata_end__ = .;     /* define a global symbol at ncache data end */
  } > m_data2

which, if I understand correctly, corresponds to DDR.

Also, my understanding is that there is some memory address difference between the U-Boot environment and the M4, in that the TCM addresses start from 1ffe0000 as seen from the M4, but this corresponds to 34fe0000 from U-Boot (“AP view”). As shown by bootaux.

However I haven’t found any address distinction for the DDR.

Is it correct that both M4 and U-Boot use the same addresses for the DDR ?

I did try fatload mmc 0:1 48000000 test_data2.bin after reading my way through this but that gave me ** Reading file would overwrite reserved memory **.

So now I’m a bit stuck.

I found the problem.

First I verifyfied that the JTAG programmer was loading the same m_data2 into the same memory address 0x88000000 as the fatload command above, by using fatwrite.

Finally I saw a mention of ‘dcache flush’ in the NXP documentation (AN5317) which allow the program to run correctly once everything is in place (the M4 needs to fetch the data I put into DDR into it’s cache I guess).

So, the summary is

A> No, bootelf will not load and boot an axf/elf file on the M4.
B> Yes, there is no offset between the DDR addresses.
C> It’s always wise to call dcache flush in these situations. see this.
D> The debug symbols don’t end up in the data file, so you don’t need to strip them.

So, having split the code into two files, the following works :-

fatload mmc 0:1 ${loadaddr} test_app.bin
fatload mmc 0:1 0x88000000 test_data2.bin
dcache flush
bootaux ${loadaddr}

This will be fine so long as your data doesn’t exceed 0x01000000 bytes - at least in my case, where loadaddr=0x89000000. I’m not sure that the loadaddr is not fairly arbitrary - it’s only used temporarily.

Hi @Timo

Happy to know you got it to work.

Sorry I was not able to follow with all the updates.