Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Support image sources other than flash #2031

Closed
wants to merge 4 commits into from

Conversation

edersondisouza
Copy link
Contributor

MCUboot assumes that the images being booted live on a flash (or will be loaded to it, in case of serial support). However, some devices may end up loading an image from a different source, such as an I2C/eSPI storage, using some appropriate protocol. In these cases, usually the image is then loaded directly to RAM.

This PR adds support for such scenarios, currently only on Zephyr port. It expects Zephyr CONFIG_FLASH_MAP_CUSTOM_BACKEND is used to provide Flash Map API to access the image in the non-flash device (but doesn't mandate it). This allows for an integration that is less intrusive on MCUboot code.

It uses single loader to load an image from a set of "sources". The single loader loops through available sources and the first one to succeed signature/validation boots. To access the images, weak functions flash_map_id_get_next() and flash_map_id_get_current() are used. Default implementation keeps current behaviour for single loader, i.e. just loads from FLASH_AREA_IMAGE_PRIMARY(0).

It is expected applications will reimplement these functions, allowing them to define a priority of different sources. As these different storage media may be ready only, MCUboot won't attempt to update them to record last source to succeed or so, it's application responsibility to define the correct priority of sources on every boot.

This PR also moves RAM loading code to its own file, so it's available for single loaders, as well as provide one example of such device, using I2C and Aardvark.

Note that this approach of "pretending devices are all flash" was chosen because I believe it's simpler to integrate. An alternative approach would be to rename all flash_* API to something like storage_, and have the current flash be an implementation of that. Not sure this path would be viable, as using and expecting flash idiosyncrasies is widespread on MCUboot code.

Please review - comments and suggestions on how to better achieve this are highly appreciated =D

Note that this patch depends on zephyrproject-rtos/zephyr#76856. Still a draft, and suggestions here and there will probably reshape this proposal a bit.

RAM loading code is currently under bootutil/loader.c, and it's not
accessible for different loaders, such as the single loaders. Future
patches will make use of the RAM loading code outside the
bootutil/loader.c context, and this patch prepares for that by making it
standalone on boot/bootutil/src/ram_load.c

Signed-off-by: Ederson de Souza <[email protected]>
Now that RAM load code is not dependent on bootutil/loader.c, it can be
used independently of !SINGLE_APPLICATION_SLOT configurations. Move the
related Kconfigs accordingly, so that applications configured to use
single loader can do RAM loading.

Signed-off-by: Ederson de Souza <[email protected]>
MCUboot assumes that the images being booted live on a flash (or will be
loaded to it, in case of serial support). However, some devices may end
up loading an image from a different source, such as an I2C/eSPI storage,
using some appropriate protocol. In these cases, usually the image is
then loaded directly to RAM.

This patch adds support for such scenarios, currently only on Zephyr
port. It expects Zephyr CONFIG_FLASH_MAP_CUSTOM_BACKEND is used to
provide Flash Map API to access the image in the non-flash device (but
doesn't mandate it). This allows for an integration that is less intrusive
on MCUboot code.

It uses single loader to load an image from a set of "sources". The
single loader loops through available sources and the first one to
succeed signature/validation boots. To access the images, weak functions
flash_map_id_get_next() and flash_map_id_get_current() are used. Default
implementation keeps current behaviour for single loader, i.e. just
loads from FLASH_AREA_IMAGE_PRIMARY(0).

It is expected applications will reimplement these functions, allowing
them to define a priority of different sources. As these different
storage media may be ready only, MCUboot won't attempt to update them to
record last source to succeed or so, it's application responsibility to
define the correct priority of sources on every boot.

Signed-off-by: Ederson de Souza <[email protected]>
A sample for non-flash-source on MEC17 EVB. It provides implementation
for Zephyr flash_area_open_custom(), so the right flash map
implementation is used, and MCUboot flash_map_id_get_next() and
flash_map_id_get_current() to prioritize sources. It should show what is
expected from an application to be able to use non-flash sources for
images.

For the I2C device simulation, an Aardvark I2C host adapter is needed,
and a script is provided to make the image loadable via I2C. An
implementation for an "Aardvark driver" on top of I2C is also provided.
Finally, a sample application to be loaded is also available.

For more details on how to build and test the samples, check the
provided README.md.

Signed-off-by: Ederson de Souza <[email protected]>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just do a proper Zephyr Flash Driver for this thing and use Flash API with it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is an example, in sdk-nrf, how virtual flash driver to transport data over IPC is implemented: nrfconnect/sdk-nrf#13917 . Device with such definition can easily be assigned partitions or directly used with Flash API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it - did a test locally, and things were simple enough. Thanks for the input!

@edersondisouza
Copy link
Contributor Author

Guess this RFC has two parts: one about loading from non-flash sources and another about being able to chose the image to run in runtime. The first part can be dropped following @de-nordic comments, but the second use case still makes sense. I guess I'll go with a new RFC for the second part, as there was a lot related to the first part on this one.

@de-nordic
Copy link
Collaborator

de-nordic commented Aug 22, 2024

Guess this RFC has two parts: one about loading from non-flash sources and another about being able to chose the image to run in runtime. The first part can be dropped following @de-nordic comments, but the second use case still makes sense. I guess I'll go with a new RFC for the second part, as there was a lot related to the first part on this one.

Sure, I was only commenting on the Flash part.

I do not know how you plan to implement the drivers, but consider using DTS phandles to point to other devices as one of possible solutions.
This way you can have generic driver to serve class of devices, for example uart:

uart_flash_emu {
   compatible = "zephyr,generic-flash-uart-bridge";
   status = "okay";
   device = <&uart0>;
   size = 
   write-block-size =
   ... // other parameters for protocol, frame size, etc; things that do not touch UART configuration
   partitions {
        compatible = "fixed-partitions";
        ...
   };
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants