Add RIOT bootloader to manage firmware slots#6922
Add RIOT bootloader to manage firmware slots#6922kYc0o wants to merge 11 commits intoRIOT-OS:masterfrom
Conversation
d4ed5ba to
9dabe0e
Compare
|
I just added another feature that could increase the security. In #6919 it's proposed a single hash over the firmware, which can allow to send "valid" firmwares, by just changing the version. Now, the hash is done again including the metadata, which will also hash the version. |
eb64f41 to
668ce72
Compare
85e543e to
71b4b54
Compare
|
@kaspar030 for some reason this PR fails with pic32 boards... but I don't understand why, can you check? |
71b4b54 to
8365d4c
Compare
ping @kaspar030 |
|
check your objcopy command lines. They include "--output-target elf32-littlearm --binary-architecture=arm", which certainly fails on mips. |
That line shouldn't also fail on AVR targets? |
Probably. I don't know... Can you reproduce the error locally? |
|
Actually I don't see why Murdock execute such line, since it should only work for valid platforms using correct flags. How can I execute that Murdock command locally? |
Just compile any application for pic32-wildfire. This is not murdock specific. |
/Users/facosta/git/RIOT-OS/RIOT/makefiles/arch/mips.inc.mk:3: *** "Please set $(MIPS_ELF_ROOT) and ensure $(MIPS_ELF_ROOT)/bin is on your PATH". Stop.Well... I need the toolchain... |
Try building in docker. |
|
I'm trying to follow the instructions on the wiki but I have this error: unable to prepare context: unable to evaluate symlinks in Dockerfile path: lstat /Users/facosta/git/RIOT-OS/RIOT/dist/Dockerfile: no such file or directoryIs the wiki updated with the current RIOT repository organisation? |
Looks outdated. If you've got docker installed, "BUILD_IN_DOCKER=1 make all" in any application directory should actually download the correct docker image if it is not locally available. |
|
I have a completely unrelated error: Launching build container using image "riot/riotbuild:latest".
docker run --rm -i -t -u "$(id -u)" \
-v '/Users/facosta/git/RIOT2/RIOT:/data/riotbuild/riotbase' \
-v '/Users/facosta/git/RIOT2/RIOT/cpu:/data/riotbuild/riotcpu' \
-v '/Users/facosta/git/RIOT2/RIOT/boards:/data/riotbuild/riotboard' \
-v '/Users/facosta/git/RIOT2/RIOT/makefiles:/data/riotbuild/riotmake' \
-v '/Users/facosta/git/RIOT2/RIOT:/data/riotbuild/riotproject' \
-v /etc/localtime:/etc/localtime:ro \
-e 'RIOTBASE=/data/riotbuild/riotbase' \
-e 'CCACHE_BASEDIR=/data/riotbuild/riotbase' \
-e 'RIOTCPU=/data/riotbuild/riotcpu' \
-e 'RIOTBOARD=/data/riotbuild/riotboard' \
-e 'RIOTMAKE=/data/riotbuild/riotmake' \
-e 'RIOTPROJECT=/data/riotbuild/riotproject' \
-e 'BOARD=pic32-wifire' \
-w '/data/riotbuild/riotproject/examples/default/' \
'riot/riotbuild:latest' make all
Building application "default" for "pic32-wifire" with MCU "mips_pic32mz".
"make" -C /data/riotbuild/riotbase/core
"make" -C /data/riotbuild/riotbase/drivers
"make" -C /data/riotbuild/riotbase/drivers/saul
"make" -C /data/riotbuild/riotbase/sys
"make" -C /data/riotbuild/riotbase/sys/auto_init
"make" -C /data/riotbuild/riotbase/sys/auto_init/saul
"make" -C /data/riotbuild/riotbase/sys/fmt
"make" -C /data/riotbuild/riotbase/sys/phydat
"make" -C /data/riotbuild/riotbase/sys/ps
"make" -C /data/riotbuild/riotbase/sys/saul_reg
"make" -C /data/riotbuild/riotbase/sys/shell
"make" -C /data/riotbuild/riotbase/sys/shell/commands
"make" -C /data/riotbuild/riotboard/pic32-wifire
"make" -C /data/riotbuild/riotcpu/mips_pic32mz
"make" -C /data/riotbuild/riotcpu/mips32r2_common
"make" -C /data/riotbuild/riotcpu/mips32r2_common/periph
"make" -C /data/riotbuild/riotcpu/mips_pic32_common
"make" -C /data/riotbuild/riotcpu/mips_pic32_common/periph
/data/riotbuild/riotproject/examples/default/bin/pic32-wifire/cpu.a(thread_arch.o): In function `_mips_handle_exception':
/data/riotbuild/riotcpu/mips32r2_common/thread_arch.c:(.text._mips_handle_exception+0x4c): undefined reference to `uart_write'
/data/riotbuild/riotproject/examples/default/bin/pic32-wifire/board.a(wifire.o): In function `board_init':
/data/riotbuild/riotboard/pic32-wifire/wifire.c:(.text.board_init+0x20): undefined reference to `uart_init'
collect2: error: ld returned 1 exit status
/data/riotbuild/riotbase/Makefile.include:316: recipe for target 'all' failed
make: *** [all] Error 1
make: *** [..in-docker-container] Error 2 |
|
For the gnrc_networking example I succeeded to have the same error as Murdock. However, nothing is related to my code. objcopy -O ihex --change-section-lma .lowerbootflashalias-0xA0000000 --change-section-lma .bootflash1-0xA0000000 --change-section-lma .bootflash2-0xA0000000 --change-section-lma .exception_vector-0x80000000 --change-section-lma .text-0x80000000 --change-section-lma .init-0x80000000 --change-section-lma .fini-0x80000000 --change-section-lma .eh_frame-0x80000000 --change-section-lma .gcc_except_table-0x80000000 --change-section-lma .jcr-0x80000000 --change-section-lma .ctors-0x80000000 --change-section-lma .dtors-0x80000000 --change-section-lma .rodata-0x80000000 --change-section-lma .data-0x80000000 --change-section-lma .bss-0x80000000 --change-section-lma .startdata-0x80000000 /data/riotbuild/riotproject/examples/gnrc_networking/bin/pic32-wifire/gnrc_networking.elf /data/riotbuild/riotproject/examples/gnrc_networking/bin/pic32-wifire/gnrc_networking.hex
objcopy: --change-section-lma .gcc_except_table+0xffffffff80000000 never used
objcopy -O binary /data/riotbuild/riotproject/examples/gnrc_networking/bin/pic32-wifire/gnrc_networking.elf /data/riotbuild/riotproject/examples/gnrc_networking/bin/pic32-wifire/gnrc_networking.bin
objcopy: Unable to recognise the format of the input file `/data/riotbuild/riotproject/examples/gnrc_networking/bin/pic32-wifire/gnrc_networking.elf'
/data/riotbuild/riotbase/Makefile.include:316: recipe for target 'all' failed |
|
I think I found the error. |
442d3a5 to
eb4529e
Compare
kaspar030
left a comment
There was a problem hiding this comment.
IMO the functionality of this PR needs to be organized a little better.
-
find better name than "fw-slots"
-
factor out "multi-slot" stuff in seperate files.
-
is it really necessarry to have multiple compiles? Can't the necessary variables be set just at the linking step, or be deduced by e.g., the address of reset handler, or a combination?
-
One linker file should be enough (with parameterized sizes)
Well, I'm open to propositions, I need to describe what this modules does, which is manipulate images on the internal ROM divided by slots.
I don't really get this. Do you mean separate the functions in different files? What's the rationale?
Currently I'm only triggering two compiles (one for the bootloader, one for the application), which each one is linked to the correct addresses according to the slot information. I don't see how to avoid this, or why is harmful/suboptimal.
Well I tried this once in #6450 using gcc to "compile" the linker file using external variables. The method looks fancy but IMHO was a bit ugly and unnecessary, since we're not handling with tons of linker scripts but only 3, one per slot and one for the bootloader. The assumption is that we don't need more than 2 slots, which represent the current image and the update. |
and bootloader images
7d6cd0d to
02235f8
Compare
| * @brief Branch the execution to a specified address, usually used to | ||
| * jump to another RIOT instance. | ||
| */ | ||
| static inline void cortexm_branch_address(uint32_t destination_address) |
There was a problem hiding this comment.
Does this work for you on samr21-xpro? I'm getting a compile error in line 205. Also the jumping seems to hard fault.
There was a problem hiding this comment.
Yeah I had it too, apparently that option is only valid for M3 mcu.
I have a branch with some modifications to work with samr21 but there's something not working with the metadata.
|
Closing in favour of #7457. |
This PR is based on #6919.
Following #6919, this PR aims to use the generated firmware metadata and put it at the beginning of a firmware binary.
A bootloader based on RIOT is now able to read the metadata and to boot the newest version if the application ID is the same, otherwise it will fallback to the slot 1. In addition, an interactive bootloader is available by setting
INTERACTIVE_BOOTLOADER = 1in the bootlaoder's Makefile.The assumption to fallback to slot 1 is because this PR enables a new target that can be flashed directly from any application, by running
make bootloader flash. This will compile the application, the bootloader, and create an ELF file with both images inside, which can be flashed by openocd. By default, the application will take the first slot (while the bootloader will take slot 0), thus I assume that at least slot 1 should be available.In order to use slot 2, the user should implement a mechanism to download a firmware with valid metadata. A firmware of this kind can be generated by doing
make FW_SLOT=2 APPID=[32bit Hex] VERSION=[16bit > 0] firmware-sloton any example or application. This will produce a file of the kindapplication-slot2-APPID-VERSION.binwhich should fit slot 2 allocated space. This file will be located in the bin directory.A following-up PR will propose a way to download such a firmware.
IMPORTANT
This PR will work only on iotlab-m3 platforms, or any stm32f103re mcu based board.
Adding new mcu's requires only to set where the slots begin and end. You can take cpu/stm32f1/include/cpu_conf.h as a example. Also, to write new firmwares, you will need the periph_flashpage feature, which is only available for some CPU's in RIOT.
Besides, the current approach to boot other slots is to move the VTOR location, which is a feature only available on cortex-m3/4 mcu's.
P.S. @haukepetersen for a strange reason the cpu_init does not need to be skipped anymore...Fixed in #6970