Search code examples
assemblyarmcortex-m

relocating arm cm3 assembly code from flash to ram


I have a Cortex M3 part with a special type FLASH memory. The part boots up on this FLASH, but I need to run a function to optimize the speed of the FLASH. The only way to do this is by jumping to RAM and performing those functions there (as the function will crash if run on the FLASH it is optimizing).

ARM allows for scatter loading. This is a solution as I can put the function in RAM and run them once I get to main. But I don't want to perform all of the scatter loading with the FLASH unoptimized. So I would like to run the function before main, which means from the reset handler, or from SystemInit (which is called from the reset handler).

I have written some assembly functions which are located in ROM. At boot, I call the Relocate function that I wrote, which then copies the other functions to RAM, and then I jump to them. This is working.

My questions are:

  1. Does this sound crazy? Is there an easier way to accomplish this (without waiting for scatter loading)?
  2. In the .s file, I have functions that I will relocate. To use those relocated functions, I load the PROC label, and then I subtract the offset of (FLASH - RAM). This doesn't feel portable. Is there another way to calculate the correct PROC addresses for the relocated functions? For example:

    foo     PROC
            ...
            ...
            ENDP
    

foo starts out in ROM at 0x24000000, and I need to move it to RAM at 0x8000. Is there a way to declare that foo lives at 0x8000 even though it must be stored in ROM? Or is there a way to declare foo_reloc to live at 0x8000? This also applies for THUMB code as foo might start at 0x24000001 and need to be called at 0x8001.

Thanks, Nachum


Solution

    1. No it's not crazy.
    2. Don't worry about relocation the linker should take care of all that for you.

    Put your flash config function into a separate execution region in your scatter file. Then the only thing you need to do is modify your scatter loading code to setup the execute region for your flash configuration function first, then call it, then continue with the scatter loading of the other regions.

    Use a scatter file like this:

    LR 0x0
    {
        ROM 0x0
        {
          * (+RO)
          * (+RW,+ZI)
        }
    
        RAM 0x18000 0x8000
        {
            foo.o (*)
        }
    }
    

    You should then get an images that starts with something like:

    $a
    !!!main
    __main
        0x00000000:    eb000000    ....    BL       __scatterload ; 0x8
        0x00000004:    eb000028    (...    BL       __rt_entry ; 0xac
    

    You can write your own scatterloader using the "magic" linker symbols such as "Image$$RAM$$Base" to perform the load of RO, RW and ZI by hand (simply set your own "entry" symbol on the linker command line to bypass the default scatter loader), then call __rt_entry.

    Since the Keil tools are really the ARM tools you can look here for more information.

    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.kui0101a/armlink_chdcgbjd.htm