user9564464
user9564464

Reputation: 313

Eclipse CDT & STM32: force predefined program memory

I have an uncommon but in my eyes reasonable use case: I have to build two STM32 firmware images: a boot loader and an application (by using the latest Eclipse CDT based IDE from ST Microelectronics, called: "STM32CubeIDE").

Because my constraints are mostly low power consumption and not security, therefore I have only the requirement for data integrity for the DFU (Device Firmware Upgrade) scenario and for this I implemented a CRC32 check over the complete FW images. The tricky part is, that the firmware itself contains its actually size within a C-struct at a fixed offset address 0x200 in the code memory (the benefit for this design is, that not the complete code memory has to be transmitted, but the FW is always protected by the CRC32):

The layout of a firmware is something like this:

<ISR Table> <FW-Header@FixedAddress0x200> <RestFWCode> " + CRC32
  1. FW Header contains FW size
  2. The complete FW size which is used by the booloader to flash the application is the stored FW size (see 1.) + 4 byte of the appended CRC32

For my implementation I need to replace a memory area within the "FW Header" area with the actual FW size (which is only available after the build process).

For this I made a python script which patches the binary "*.bin" file, but it seems, that Eclipse/GDB uses for debugging the ELF-file, which looks for me much more complicated for a custom patch compared to the binary image, since I found no easy way to do this (to replace the actual FW size and append the 4 bytes of the CRC32).

Therefore, I thought the easiest way would be to patch the code memory right after the firmware got loader from the debugger. I tested successfully a command-line tool from ST which can manipulate arbitrary memory even in the code memory (my code memory starts at 0x08000000 + application at offset 0x4000 and FW header at öffset 0x200 -> 0x08004200):

ST-LINK_CLI.exe -c SWD -w32 0x08004200 0xAABBCCDD

(see: https://www.st.com/resource/en/user_manual/cd00262073.pdf)

My Problem is, I don't know how to initiate this simple EXE call right before the debugger got attached to the MCU... I tried the "Debug Configuration"-> "Startup" -> "Run Commands", but without success...

Does anybody know a way how to achieve this?

Upvotes: 0

Views: 701

Answers (2)

abonneville
abonneville

Reputation: 334

I am going to recommend a different workflow to achieve the same image format:

<ISR Table> <FW-Header@FixedAddress0x200> <RestFWCode> " + CRC32

Once in place, your build process will be:

  1. Build FW image to produce a raw binary, without a CRC-32 value
  2. Calculate CRC-32 on the raw binary image, third-party tool
  3. Insert the calculated CRC-32 into linker script, rebuild FW image

Note: For STM32CubeIDE, you will want to have your own *.elf project that includes the STM32CubeMX project as a static library. Otherwise, STM32CubeMX will overwrite your linker script each time it generates new code.

Since each project tends to have a slightly different linker script, I am going to demonstrate using a .test_crc sector. Insert the following into your *.ld linker script:

  .test_crc :
  {
    _image_start = .;
    BYTE( 0x31)
    BYTE( 0x32)
    BYTE( 0x33)
    BYTE( 0x34)
    BYTE( 0x35)
    BYTE( 0x36)
    BYTE( 0x37)
    BYTE( 0x38)
    BYTE( 0x39)

    /* FW Image Header */ 
    LONG( _image_end - _image_start ) /* Size of FW image */
    LONG( _image_start ) /* Base address to load FW image */

    /* Place this at the end of the FW image */
    _image_end = .;
    _IMAGE_CRC = ABSOLUTE(0x0); /* Using CRC-32C (aka zip checksum) */  
    /*LONG( (-_IMAGE_CRC) - 1 ) /* Uncomment to append value, comment to calculate new value  */
  } >FLASH

Add the following as a post-build step in STM32CubeIDE (generates the raw binary image):

arm-none-eabi-objcopy -S -O binary -j .test_crc ${ProjName}.elf ${ProjName}.bin

Now your ready to test/evaluate the process:

  1. Rebuild your project to generate a *.bin file.
  2. Using a third-party tool, calculate a CRC-32 checksum. I use 7-Zip command-line interface to generate the CRC-32C value for the *.bin file
  3. Append the calculated CRC-32C. In the linker script, set the 0x0 in the following _IMAGE_CRC = ABSOLUTE(0x0) to match your calculated value. Uncomment the following:

LONG( (-_IMAGE_CRC) - 1 ) /* Uncomment to append value, comment to calculate new value */

  1. Rebuild your image and run the third-party CRC utility, it should now report 0xFFFFFFFF for a CRC-32C value.

When you are ready to apply this to your actual FW image, do the following:

  1. Change the post-build step to dump the full binary: arm-none-eabi-objcopy -S -O binary ${ProjName}.elf ${ProjName}.bin
  2. Move _image_start = .; in front of your vector table.
  3. Move the following after your vector table:

/* FW Image Header */ LONG( _image_end - _image_start ) /* Size of FW image */ LONG( _image_start ) /* Base address to load FW image */

  1. Move the following to end of the last sector:

/* Place this at the end of the FW image */ _image_end = .; _IMAGE_CRC = ABSOLUTE(0x0); /* Using CRC-32C (aka zip checksum) */
/*LONG( (-_IMAGE_CRC) - 1 ) /* Uncomment to append value, comment to calculate new value */

You may find that you actually do not need the CRC value built into the image, and can just append the CRC value to the *.bin. Then provide the *.bin to your bootloader. The *.bin will still contain the load address and size of FW image, +4 bytes for the appended CRC value.

Upvotes: 1

J_S
J_S

Reputation: 3282

Running a program before starting a debug session can be done using Eclipse's "Launch group" located under Debug Configurations, e.g. top menu -> Run -> Debug Configurations.

enter image description here

However before doing that you should go to project properties -> Builders and add your program invocation there - path to the executable plus its arguments. Make sure it's NOT checked so that it doesn't run when you build your project. Then you can go to the Launch Groups described above and create a group that contains the program you've defined in the project Builders section, then after that your regular debug session which you should already have available on the list.

Upvotes: 1

Related Questions