Skip to main content
stenasc
Associate III
June 20, 2016
Question

basic bootloader for M0

  • June 20, 2016
  • 43 replies
  • 5513 views
Posted on June 20, 2016 at 23:21

Hello Forum,

I've been reading on the forums about custom bootloaders stored in flash and I was wondering if there was another possibility (possibly because I want to avoid messing with stack pointers, reset vectors etc.)

In my main app, I have a bootloader function, that copies the new app stored in external flash to processor flash. This bootloader function contains a number of inline functions to read from external flash and copy to processor flash. Checking the .map file, this bootloader function looks to be all located in one place.

My thought process is to copy this bootloader function into RAM at say 0x20000100 and then jump to that address as shown below

void CopyLoaderToRam(void)

{

 //   uint32_t *Ram = (uint32_t *)RAM_ADDR;

    char *Ram = (char *)RAM_ADDR;///////////// Byte Alignment test

    typedef  void (*pFunction)(void);

    pFunction RunCode;

 ptr_bootloader_fn = &bootloader;    // Find the address of the bootloader function.  

   

//    memcpy(Ram, (void *)ptr_bootloader_fn, LOADER_FLASH_SIZE); // Copy bootloader into ram

   

    

      char *boot_byte;

      boot_byte = (char *)&bootloader;

      int i;

      for (i=0; i<= 4*LOADER_FLASH_SIZE; i++)

          {

                Ram[i] = *(boot_byte+i);    

                }

             

    RunCode = (pFunction)Ram[1];       // ResetHandler (PC in second vector)

     

    RunCode();

}

Well the first issue is it doesnt seem to work as I get a hard fault.My fears are that I am overwriting some necessary data in Ram or some alignment issue. I'm not sure. 

However, is it even technically feasible in the first place and if not, why? If it is a non-starter, I would rather know at this stage. Device is a STM32F051.

Kind Regards

Bob
    This topic has been closed for replies.

    43 replies

    Tesla DeLorean
    Guru
    June 20, 2016
    Posted on June 20, 2016 at 23:34

    It is faulting because in this context you are loading a byte and jumping to whatever that is.

    You'd really want the vector table at the base of RAM, as you can remap that, whereas you can't redefine the address of the vector table as you could with the M3/M4 designs. Assume therefore that SCB->VTOR = ZERO, always.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    stenasc
    stenascAuthor
    Associate III
    June 20, 2016
    Posted on June 21, 2016 at 00:22

    Hi Clive,

    Appreciate you getting back. How can I execute the code stored at that location in Ram, which is really what is required?

    In this context, do I need to move the vector table to the base of RAM? My aim is for the bootloader to overwrite the existing app code with the new firmware.

    Bob

    Tesla DeLorean
    Guru
    June 20, 2016
    Posted on June 21, 2016 at 01:21

    For a self contained function...

    void CopyLoaderToRam(void)
    {
    char *Ram = (char *)RAM_ADDR;// You want this word aligned
    typedef void (*pFunction)(void);
    pFunction RunCode;
    memcpy(Ram, (void *)&bootloader, LOADER_FLASH_SIZE); // Copy bootloader into ram
    RunCode = (pFunction)&Ram[1]; // *ADDRESS* of the second byte, ie ODD to indicate 16-bit Thumb
    RunCode();
    }

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    stenasc
    stenascAuthor
    Associate III
    June 21, 2016
    Posted on June 22, 2016 at 01:54

    Thanks for that Clive. However tried it and it hard faulted.  One thing that did confuse me is whether I should copy from address

    0x0800b600 to ram of from 0x0800b601. Printing the pointer address of bootloader function gives me the latter and it is from 0x0800b601 that I copy from. However, the map file below gives two values. Which is correct?

    Regards

    Bob

        Base Addr    Size         Type   Attr      Idx    E Section Name        Object

        0x0800b600   0x000000d0   Code   RO         1297    i.bootloader        loader.o

        Symbol Name                              Value     Ov Type        Size  Object(Section)

        bootloader                               0x0800b601   Thumb Code   204  loader.o(i.bootloader)

    Tesla DeLorean
    Guru
    June 22, 2016
    Posted on June 22, 2016 at 02:36

    The memory is going to be at 0x0800B600, the PC sets to 0x0800B601 and the core flags that as being Thumb code pulling the instruction word from 0x0800B600

    You should be able to run the function in its normal location. The function should not call external dependencies. These in the M0 case might include basic MATH functions, like division. Review the code. Start with a function that just returns a value.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    stenasc
    stenascAuthor
    Associate III
    June 26, 2016
    Posted on June 26, 2016 at 22:57

    Hi Clive,

    Apologies, only getting back to this now. Still no joy, I tried as you said to just return a value, but still get a hard fault.

    int8_t bootloader()

    {

    return 8;

    }

    void CopyLoaderToRam(void)

    {

        

        uint32_t *Ram = (uint32_t *)RAM_ADDR;// You want this word aligned

        typedef  int8_t (*pFunction)(void);

        pFunction RunCode;

       

        memcpy(Ram, (void *)&bootloader, LOADER_FLASH_SIZE); // Copy bootloader into ram

                      

        RunCode = (pFunction)&Ram[1]; // *ADDRESS* of the second byte, ie ODD to indicate 16-bit Thumb

        

        int8_t test_boot;

       test_boot = RunCode();

          printf(''Bootloader returns %d'', test_boot);

    }

    I also tried other snippets of code that I found while browsing the forum (below) but it does not work. I can see the code is copied to the location in RAM ok, so I'm really stuck on this one. There must be something quite fundamental that I've missed.

    Appreciate any help.

    Bob

        uint32_t *Ram = (uint32_t *)RAM_ADDR;// You want this word aligned

    typedef  int8_t (*pFunction)(void);

    uint32_t JumpAddress = *(__IO uint32_t*) (RAM_ADDR + 4);

    pFunction Jump_To_Boot = (pFunction)JumpAddress;

    memcpy(Ram, (void *)&bootloader, LOADER_FLASH_SIZE); // Copy bootloader into ram

    __set_MSP(*(__IO uint32_t*)RAM_ADDR);

        int8_t test_boot;

       test_boot = Jump_To_Boot();

          printf(''Bootloader returns %d'', test_boot);

    }

    Tesla DeLorean
    Guru
    June 26, 2016
    Posted on June 26, 2016 at 23:16

    uint32_t *Ram = (uint32_t *)RAM_ADDR;// NO, NO, Not uint32_t, uint8_t

    &Ram[1] for the 32-bit word case is +4 bytes, &Ram[1] for the 8-bit case is +1 bytes, you want the latter.

    You'd want to ensure &bootloader is the EVEN address, I'd build a list of hex bytes rather than copy a subroutine in-situ

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Tesla DeLorean
    Guru
    June 26, 2016
    Posted on June 26, 2016 at 23:36

    #define SRAM_ADDR 0x20000F00
    typedef int (*pFunction)(void);
    int RamCode(void)
    {
    static const uint16_t Code[] = { 0x4800, 0x4770, 0x007B, 0x0000 }; // payload
    uint8_t *Buffer = (uint8_t *)SRAM_ADDR;
    pFunction RunCode;
    memcpy(Buffer, Code, sizeof(Code)); // Copy code
    RunCode = (pFunction)&Buffer[1]; // +1 for Thumb code
    return(RunCode()); // sourcer32@gmail.com
    }

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    stenasc
    stenascAuthor
    Associate III
    June 28, 2016
    Posted on June 29, 2016 at 00:39

    Hi Clive,

    Thank you. Yes that works, but it is slightly different than copying a function into Ram and executing it. Even though the function only returns a value, I still get a hardfault. Really stuck here. Have you an example of actually copying a simple function into Ram?

    Bob

    Bob

    Tesla DeLorean
    Guru
    June 28, 2016
    Posted on June 29, 2016 at 01:06

    It's not going to be *that* different, I'd have to code something specific as that's not how I solve this kind of problem, and I'm not using M0's

    Use a debugger to understand the fault.

    Make sure the base address of the function into the memcpy() is EVEN, as is the destination address.

    Make sure it copies the entire function and any literals it references.

    Make sure it doesn't have any external references, relative address references only work when they all remain in scope.

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