mcuboot
mcuboot copied to clipboard
Bootloader should provide the version of zephyr, mcuboot and a user defined version to the application
This issue originally was opened in https://github.com/zephyrproject-rtos/zephyr/issues/37160
We are using the MCUBoot based bootloader (/bootloader/mcuboot
) in a Zephyr project.
It seems there is no way for a (Zephyr) application to get the following information from the MCUBoot bootloader:
- The used Zephyr version in the bootloader
- The used MCUBoot version
- A user defined bootloader version (like set in the application with the image tool,
imgtool sign --version $VERSION_FOR_IMGTOOL ...
)
We think that it is important that an application is able to read this information from the bootloader for troubleshooting or special handling of a newer bootloader version.
Did I miss such functionality or is it not existing? And if so, is there a reason for it to be missing?
As a workaround for our test system, I added such functionality by providing this information through the UART log:
# Add Git hash, MCUboot repo commit hash/tag and zephyrproject version to Startup Log Message
sed -i "/BOOT_LOG_INF(\"Starting bootloader/c\ BOOT_LOG_INF(\"Starting bootloader | \" __DATE__ \" \" __TIME__ \" | Version: $GIT_VERSION | MCUboot: $MCUBOOT_GIT_VERSION | Zephyrproject: $ZEPHYR_REVISION\");" mcuboot/boot/zephyr/main.c
How ever this is not be possible on the systems on the field.
I think the way to implement this is by defining fix locations in flash and store the mentioned information there.
The right place most likely would be at the end of the boot_partition
, https://github.com/zephyrproject-rtos/zephyr/blob/main/boards/arm/nrf52840dongle_nrf52840/fstab-debugger.dts#L18.
I have done this on other projects (not Zephyr based) and it worked well.
I think the way to implement this is by defining fix locations in flash and store the mentioned information there.
There are hooks for doing this that are used by TF-M for boot measurements. Perhaps this could be leveraged to get this information into Zephyr.
I'm not sure this should be stored in flash, but in SRAM and passed to the running app from the bootloader.
@d3zd3z Thanks for your input. Do you have any links to those hooks and boot measurements?
A little update:
Because we need a solution now, we went for following:
We have a python script, which generates a little hex file. The hex file will put the needed information to the end of the bootloader_partition
.
Nordic provides a little tool to merge 2 hex files: mergehex
.
We then simply flash that combined hex file to the bootloader_partition
.
The application itself can read the data out again from there:
bootloaderVersionBlock_t *bootloderVersionBlock = (bootloaderVersionBlock_t *)0xF000;
LOG_INF("Version: %d, bootloderVersionBlock.version);
I've added "enhancement" and "someday" to this so we can keep it around, but it sounds like you've found a way to meet your immediate needs.
Hi @caco3, I had similar requirements for my mcuboot-based bootloaders.
There is a relatively new feature called data sharing
(same feature @d3zd3z mentioned above that is used for TF-M measured boots). Essentially, it lets you store TLV-encoded values in a reserved region of RAM that is shared between the bootloader and application. You can see the official MCUboot documentation regarding this feature here.
Although it's for a different platform, you can see how it is implemented in the Mbed-OS port (#1115). I also just added demos of how to use it to the Mbed-OS demo repositories: bootloader demo, application demo.
Basically, in steps:
0.) Reserve the region of RAM using your platform/toolchain (ie: prevent a small area of RAM from being initialized at startup in the application)
1.) Configure MCUboot bootloader and application so that it knows where in RAM the reserved region is (see MCUBOOT_SHARED_DATA_BASE
and MCUBOOT_SHARED_DATA_SIZE
configuration parameters in documentation).
2.) Implement a hook function that MCUboot expects (must be a C symbol if building with C++): boot_save_shared_data
3.) In your boot_save_shared_data
implementation, call boot_add_data_to_shared_area
to add custom data to the shared region
4.) At application startup, read the shared data region TLVs. See an example of how to do this (in C++) here.
Note that it is imperative that you prevent your startup code from "initializing" (ie: RAM zeroing) this reserved section. You will have to refer to your platform/toolchain's documentation for details on how to do this. On Mbed-OS, I simply configure the linker script so that it does not "know" about the small reserved shared data region at the end of RAM.
I hope this helps! Let me know if you have any further questions. I encourage you to join the MCUboot slack channel as well.
@d3zd3z Another thought that comes to mind: MCUboot should have the version in a #define
somewhere. I can't find a place where the MCUboot version is available in code.
@d3zd3z Thank you for sharing your knowledge in such detailed level! @AGlass0fMilk I also didn't find such a define. As a workaround, and since I want to see the version in the log, I patched main() as seen in the first post.
MCUboot should have the version in a
#define
somewhere. I can't find a place where the MCUboot version is available in code.
This is probably worth it's own issue. I'll create an issue for this #1151, which has a checklist for each platform.
@AGlass0fMilk Do you have an example based on zephyr?
@d3zd3z @AGlass0fMilk I found a easy way to get mcuboot version in zephyr. zephyr can generate merge.hex file and it will fill no use space to 0xff, so that when mcuboot boot up, check the tail of mcuboot, if not match it is version, then write version to flash, only once. when application upgrade mcuboot, it will earse mcuboot flash partition, so that is another chance to write it`s version.
that means mcuboot seal version in runtime.
@Cherish-Gww The only comment I would make is that mcuboot should never be updated by the application. Two reasons, 1, if power were lost you would have an unbootable device, and 2. the hardware should be configurable so that mcuboot cannot be modified, otherwise you will be unable to trust the boot process.
I have used a section of linker file that I added at a specified memory location in flash where I set a version number for bootloader. Then I read that address from app firmware. That's work for me.
MCUboot now has a version when built using zephyr: https://github.com/mcu-tools/mcuboot/blob/main/boot/zephyr/VERSION This can be shared with an application using data sharing, see zephyr test here: https://github.com/zephyrproject-rtos/zephyr/tree/main/tests/boot/mcuboot_data_sharing
Therefore this can be closed?
To my understanding, this only covers the MCUBoot version, but not the Zephyr and user defined version. Not sure if the Zephyr version could be found out based on the MUCBoot version (and the GIT history). Since we want traceability, our build process adds the user defined version and the GIT hash to the hex file so we can read it out in the application. Without this addings, I do not see how one could trace the MCUBoot build back to the pipeline/GIT commit..
But why would there be a user version for MCUboot? If you are using MCUboot as-is, then you have the version from it, if you are editing/forking MCUboot then you have your own version scheme which is custom to that.
You could probably use https://docs.zephyrproject.org/latest/services/binary_descriptors/index.html for that
You are right, such information should not be part of MCUboot but the application where it is embedded into (eg. a Zephyr project). And thanks for the link to the Binary Descriptors. Thats exactly what I was looking for. It seems how ever to be fairly new (comming in Zephyr 3.5?)