How to build and link project sharing "system calls" to bootloader as a singleton object?

228 Views Asked by At

I'm trying to build a solution, where there would be two projects: 'bootloader' (starting after reset and doing smth), and 'mainApplication' getting the control from bootloader.

Initially i've just reproduced the example from here: https://visualgdb.com/tutorials/arm/bootloader/

The final part of this tutorial describes "system call" - passing the pointer to some function residing in bootloader to the main application and then making a call to this function from there.

The intention is to pass not a pointer to a function, but say pointer to an object of a class.

Modified example from tutorial looks like this:

Bootloader:



//sys.h

class SysCalls
{
public:
    SysCalls();
    int sum(int, int);
};



//sys.cpp

#include "sys.h"

SysCalls::SysCalls()
{
}

int SysCalls::sum(int a, int b)
{
    return a + b;
}


// main.cpp

#include <sys.h>

...

SysCalls _sys;

void *g_Syscalls[] __attribute__((section(".syscalls"))) = { (void *)&_sys };



Main Application:

//main.cpp

#include <sys.h> // the same header as in bootloader

extern "C" void *g_Syscalls[];

SysCalls *_sys = (SysCalls*) g_Syscalls[0];

int main(void)
{

...

    int sum = _sys->sum(1, 2);
...



I get an linker error:

undefined reference to `SysCalls::sum(int, int)'

which is predictable, but...

Is there any good way to build this, i wonder? some linker config? or should i include sys.cpp to mainApplication also, and make the content not to be included in final binary somehow?

Also, looking forward - if talking about simple staff like shown sum function, which uses only stack, it is only a linker issue, but if i want to create a kind of 'system service', say singleton object with some heap usage, then the question would be - if there is any good way to freeze the part of heap used by this object when transferring control from bootloader, where it was created to main Application, which should use it...

2

There are 2 best solutions below

2
On BEST ANSWER

A pointer to an object with data members instantiated by the bootloader would be invalid in the application unless the bootloader's RAM is permanently assigned rather than being reused by the application. Which itself would require memory partitioning by the linker. The only type of class that would be valid without such memory partitioning is one containing static member functions that do not use static data, and therefore the only benefit of a pointer to a class would be to have a single pointer to a collection if functions (which may not be without merit).

Either way, whilst it may be possible to use some sort of linker configuration to manage your requirement, linker scripts are often arcane and are not portable between toolchain. A simpler solution would be to create a vector table populated with the pointers to your functions, classes, or objects (previous caveats notwithstanding), and use the linker and/or compiler linker directives to locate the table in ROM at a known and reserved location. That same table location can then also be placed in your application link map. Your entry points are then simply provided by accessing that table as an array of pointers, with a known index for each access point.

The vectors need not be pointers to functions, you can interpret them (by casting) as a pointer to any entity. Again precious caveats about object validity in the application context notwithstanding.

4
On

This approach is used by many middleware software components. One of the example is the SoftDevices BT NRF middleware. In the linker scripts it gives some RAM for the static objects and some space for the local stack as well. The "main" program has this RAM excluded from use (the flash area occupied by the SDev is also excluded). It works very well.

It is not the actual bootloader - the bootloader is a separate being having acces to the SDev) as NRF bootloader is OTA capable