Bootloader Interface
Overview
SWUpdate has bindings to various bootloaders in order to store persistent state information across reboots. Currently, the following bootloaders are supported:
The actual (sub)set of bootloaders supported is a compile-time choice. At
run-time, the compile-time set default bootloader interface implementation
is used unless overruled to use another bootloader interface implementation
via the -B
command line switch or a configuration file (via the
bootloader
setting in the globals
section, see
examples/configuration/swupdate.cfg
).
Note that the run-time support for some bootloaders, currently U-Boot and EFI Boot Guard, relies on loading the respective bootloader’s environment modification shared library at run-time. Hence, even if support for a particular bootloader is compiled-in, the according shared library must be present and loadable on the target system at run-time for using this bootloader interface implementation. This allows, e.g., distributions to ship a generic SWUpdate package and downstream integrators to combine this generic package with the appropriate bootloader by just providing its environment modification shared library.
Bootloader Interface Description
The bootloader interface implementations are located in bootloader/
.
Each bootloader has to implement the interface functions as defined in
include/bootloader.h
, more precisely
char *env_get(const char *name);
int env_set(const char *name, const char *value);
int env_unset(const char *name);
int apply_list(const char *filename);
which
retrieve a key’s value from the bootloader environment,
set a key to a value in the bootloader environment,
delete a key-value pair from the bootloader environment, and
apply the key=value
pairs found in a file.
Then, each bootloader interface implementation has to register itself to
SWUpdate at run-time by calling the register_bootloader(const char *name,
bootloader *bl)
function that takes the bootloader’s name and a pointer
to struct bootloader
as in include/bootloader.h
which is filled
with pointers to the respective above mentioned interface functions.
If the bootloader setup fails and hence it cannot be successfully registered,
e.g., because the required shared library for environment modification cannot
be loaded, NULL
is to be returned as pointer to struct bootloader
.
For example, assuming a bootloader named “trunk” and (static) interface
functions implementations do_env_{get,set,unset}()
as well as
do_apply_list()
in a bootloader/trunk.c
file, the following snippet
registers this bootloader to SWUpdate at run-time:
static bootloader trunk = {
.env_get = &do_env_get,
.env_set = &do_env_set,
.env_unset = &do_env_unset,
.apply_list = &do_apply_list
};
__attribute__((constructor))
static void trunk_probe(void)
{
(void)register_bootloader(BOOTLOADER_TRUNK, &trunk);
}
with
#define BOOTLOADER_TRUNK "trunk"
added to include/bootloader.h
as a single central “trunk” bootloader
name definition aiding in maintaining the uniqueness of bootloader names.
This new “trunk” bootloader should also be added to the Suricatta Lua
Module interface specification’s bootloader Table
suricatta.bootloader.bootloaders = { ... }
in
suricatta/suricatta.lua
.
Attention
Take care to uniquely name the bootloader.
See, e.g., bootloader/{uboot,ebg}.c
for examples of a bootloader using
a shared environment modification library and bootloader/{grub,none}.c
for a simpler bootloader support example.
Bootloader Build System Integration
A bootloader support implementation needs to be registered to the kconfig build system.
First, the bootloader support implementation, named “trunk” and implemented
in bootloader/trunk.c
for example, needs to be added to
bootloader/Config.in
in the Bootloader Interfaces
menu as
follows:
...
menu "Bootloader"
menu "Bootloader Interfaces"
...
config BOOTLOADER_TRUNK
bool "TrUnK Bootloader"
help
Support for the TrUnK Bootloader
https://github.com/knurt/trunk
Then, in order to enable the compile-time selection of the “trunk” bootloader
as default, add a section to the Default Bootloader Interface
choice
submenu of the Bootloader
menu as follows:
choice
prompt "Default Bootloader Interface"
help
Default bootloader interface to use if not explicitly
overridden via configuration or command-line option
at run-time.
...
config BOOTLOADER_DEFAULT_TRUNK
bool "TrUnK"
depends on BOOTLOADER_TRUNK
help
Use TrUnK as default bootloader interface.
Finally, bootloader/Makefile
needs to be adapted to build the “trunk”
bootloader support code, given BOOTLOADER_TRUNK
was enabled:
obj-$(CONFIG_BOOTLOADER_TRUNK) += trunk.o
If the “trunk” bootloader, for example, requires loading a shared
environment modification library, then Makefile.flags
needs to be
adapted as well, e.g., as follows:
ifeq ($(CONFIG_BOOTLOADER_TUNK),y)
LDLIBS += dl
endif