Passing information from bootloader to Zephyr


Daniel Thompson <daniel.thompson@...>
 

On 24/07/17 19:03, Marti Bolivar wrote:
On 24 July 2017 at 13:50, Daniel Thompson <daniel.thompson@... <mailto:daniel.thompson@...>> wrote:
On 24/07/17 17:34, Erwan Gouriou wrote:
On 24 July 2017 at 18:03, Daniel Thompson
<daniel.thompson@... <mailto:daniel.thompson@...>
<mailto:daniel.thompson@...
<mailto:daniel.thompson@...>>> wrote:
On 24/07/17 16:47, Marti Bolivar wrote:
It's likely future work, but it seems inevitable
we'll have to
define exactly the state of the device that mcuboot
provides to the
chainloaded image. Having a place to put formal
definitions
will
simplify this work.
I especially want to highlight this part: ^^
Erwan, I noticed while looking at a recent PR [1] that
the STM32
UARTs have a status = "disabled" property in DTS (not
introduced
in this change, was already there).
But in fact, when Zephyr is chain-loaded by mcuboot, at
least
one of the UARTs is not disabled, since mcuboot uses it
to log
and doesn't disable it before jumping to the next
image. Further
the clocks are reconfigured from their reset defaults,
the PLL
is on, etc.
It seems like this will inevitably cause problems as
the Zephyr
DTS continues to get more sophisticated (not just for
STM32).
Am I missing something here?
The enabled property doesn't describe whether the peripheral is
active or not at bootloader handover. It is more like
whether that
peripheral is connected to something useful. DT describes the
hardware, including the board, so if a UART is not pinned out
somewhere in the board design it should not be enabled in
the DT.
And if connected to HW, should it be enabled and clocked?
Linux uses mix of Kconfig/dt. Kconfig for compilation/dt for
activation.
I'd describe it that Linux uses *drivers* for activation. For
example, it is the driver that makes the appropriate calls (usually
via clock framework, etc) to enable and clock its peripheral.
So KConfig controls whether the driver is includes a driver or not
(driver not compiled -> no activation).
Similar, in Linux, DT is just a data structure and doesn't really
*do* anything. However by describing hardware it does enable the
kernel to probe for drivers whose hardware cannot be automatically
detected (no hardware detected -> no activation).
Do we want the same in Zephyr and keep these 2 levels of
configuration?
Another option would be to add a property in device tree to
declare activation at boot.
Currently zephyr has the two layers of separation although the
mechanism is different, although in my opinion, the driver is still
ending up doing all the activation.
DT support is realized as a pre-processor that enriches the
configuration space by defining CONFIG_ symbols with special names.
For example
CONFIG_UART_STM32_PORT_2_NAME,
CONFIG_UART_STM32_PORT_2_BASE_ADDRESS, etc.
KConfig controls both whether the driver as a whole is enabled *and*
whether that driver should enable port 2. The driver then uses the
symbols provided by DT to fill out a DEVICE[_AND_API]_INIT() macro.
The main difference versus Linux is that, on Zephyr, KConfig can
control whether or not port 2 is enabled. Thus if hardware is
omitted from the DT you will discover this at build time. This is
good for code size (an application that doesn't use UART2 doesn't
need to change the DT just to eliminate the overhead) but appears
also makes the status field in DT pretty much redundant anyway.
Sorry, I'm not following how this is relevant to the questions about the bootloader/Zephyr boundary. Am I missing something?
Not sure. ;-)

Mostly it is illustrating that the DT status of a peripheral is (pretty much) unrelated to the mcuboot protocols to hand over peripherals.

Another minor point is that while it is reasonable for mcuboot to expect zephyr drivers to be able to handle peripherals that mcuboot has already activated, it is unlikely that a zephyr application will know how to *deactivate* peripherals that it doesn't need (since to keep application code size down all knowledge of such peripheral ends up being compiled out). This is a minor point, mostly because I can't think of many peripherals that mcuboot would need and that zephyr leaves idle. Nevertheless if they do exist, they risk wasting power of mcuboot does not declock/depower them during a boot.


Daniel.


Marti Bolivar <marti.bolivar@...>
 



On 24 July 2017 at 13:50, Daniel Thompson <daniel.thompson@...> wrote:
On 24/07/17 17:34, Erwan Gouriou wrote:



On 24 July 2017 at 18:03, Daniel Thompson <daniel.thompson@... <mailto:daniel.thompson@linaro.org>> wrote:

    On 24/07/17 16:47, Marti Bolivar wrote:

             It's likely future work, but it seems inevitable we'll have to
             define exactly the state of the device that mcuboot
        provides to the
             chainloaded image. Having a place to put formal definitions
        will
             simplify this work.


        I especially want to highlight this part: ^^

        Erwan, I noticed while looking at a recent PR [1] that the STM32
        UARTs have a status = "disabled" property in DTS (not introduced
        in this change, was already there).

        But in fact, when Zephyr is chain-loaded by mcuboot, at least
        one of the UARTs is not disabled, since mcuboot uses it to log
        and doesn't disable it before jumping to the next image. Further
        the clocks are reconfigured from their reset defaults, the PLL
        is on, etc.

        It seems like this will inevitably cause problems as the Zephyr
        DTS continues to get more sophisticated (not just for STM32).

        Am I missing something here?


    The enabled property doesn't describe whether the peripheral is
    active or not at bootloader handover. It is more like whether that
    peripheral is connected to something useful. DT describes the
    hardware, including the board, so if a UART is not pinned out
    somewhere in the board design it should not be enabled in the DT.

And if connected to HW, should it be enabled and clocked?
Linux uses mix of Kconfig/dt. Kconfig for compilation/dt for activation.

I'd describe it that Linux uses *drivers* for activation. For example, it is the driver that makes the appropriate calls (usually via clock framework, etc) to enable and clock its peripheral.

So KConfig controls whether the driver is includes a driver or not (driver not compiled -> no activation).

Similar, in Linux, DT is just a data structure and doesn't really *do* anything. However by describing hardware it does enable the kernel to probe for drivers whose hardware cannot be automatically detected (no hardware detected -> no activation).


Do we want the same in Zephyr and keep these 2 levels of configuration?
Another option would be to add a property in device tree to declare activation at boot.

Currently zephyr has the two layers of separation although the mechanism is different, although in my opinion, the driver is still ending up doing all the activation.

DT support is realized as a pre-processor that enriches the configuration space by defining CONFIG_ symbols with special names. For example
CONFIG_UART_STM32_PORT_2_NAME,
CONFIG_UART_STM32_PORT_2_BASE_ADDRESS, etc.

KConfig controls both whether the driver as a whole is enabled *and* whether that driver should enable port 2. The driver then uses the symbols provided by DT to fill out a DEVICE[_AND_API]_INIT() macro.

The main difference versus Linux is that, on Zephyr, KConfig can control whether or not port 2 is enabled. Thus if hardware is omitted from the DT you will discover this at build time. This is good for code size (an application that doesn't use UART2 doesn't need to change the DT just to eliminate the overhead) but appears also makes the status field in DT pretty much redundant anyway.


Sorry, I'm not following how this is relevant to the questions about the bootloader/Zephyr boundary. Am I missing something? If this is a Zephyr internals discussion, could you please move it to another (zephyr-devel only) thread?

Thanks.

Marti
 

Daniel.


Daniel Thompson <daniel.thompson@...>
 

On 24/07/17 17:34, Erwan Gouriou wrote:
On 24 July 2017 at 18:03, Daniel Thompson <daniel.thompson@... <mailto:daniel.thompson@...>> wrote:
On 24/07/17 16:47, Marti Bolivar wrote:
It's likely future work, but it seems inevitable we'll have to
define exactly the state of the device that mcuboot
provides to the
chainloaded image. Having a place to put formal definitions
will
simplify this work.
I especially want to highlight this part: ^^
Erwan, I noticed while looking at a recent PR [1] that the STM32
UARTs have a status = "disabled" property in DTS (not introduced
in this change, was already there).
But in fact, when Zephyr is chain-loaded by mcuboot, at least
one of the UARTs is not disabled, since mcuboot uses it to log
and doesn't disable it before jumping to the next image. Further
the clocks are reconfigured from their reset defaults, the PLL
is on, etc.
It seems like this will inevitably cause problems as the Zephyr
DTS continues to get more sophisticated (not just for STM32).
Am I missing something here?
The enabled property doesn't describe whether the peripheral is
active or not at bootloader handover. It is more like whether that
peripheral is connected to something useful. DT describes the
hardware, including the board, so if a UART is not pinned out
somewhere in the board design it should not be enabled in the DT.
And if connected to HW, should it be enabled and clocked?
Linux uses mix of Kconfig/dt. Kconfig for compilation/dt for activation.
I'd describe it that Linux uses *drivers* for activation. For example, it is the driver that makes the appropriate calls (usually via clock framework, etc) to enable and clock its peripheral.

So KConfig controls whether the driver is includes a driver or not (driver not compiled -> no activation).

Similar, in Linux, DT is just a data structure and doesn't really *do* anything. However by describing hardware it does enable the kernel to probe for drivers whose hardware cannot be automatically detected (no hardware detected -> no activation).


Do we want the same in Zephyr and keep these 2 levels of configuration?
Another option would be to add a property in device tree to declare activation at boot.
Currently zephyr has the two layers of separation although the mechanism is different, although in my opinion, the driver is still ending up doing all the activation.

DT support is realized as a pre-processor that enriches the configuration space by defining CONFIG_ symbols with special names. For example
CONFIG_UART_STM32_PORT_2_NAME,
CONFIG_UART_STM32_PORT_2_BASE_ADDRESS, etc.

KConfig controls both whether the driver as a whole is enabled *and* whether that driver should enable port 2. The driver then uses the symbols provided by DT to fill out a DEVICE[_AND_API]_INIT() macro.

The main difference versus Linux is that, on Zephyr, KConfig can control whether or not port 2 is enabled. Thus if hardware is omitted from the DT you will discover this at build time. This is good for code size (an application that doesn't use UART2 doesn't need to change the DT just to eliminate the overhead) but appears also makes the status field in DT pretty much redundant anyway.


Daniel.


Marti Bolivar <marti.bolivar@...>
 



On 24 July 2017 at 12:34, Erwan Gouriou <erwan.gouriou@...> wrote:


On 24 July 2017 at 18:03, Daniel Thompson <daniel.thompson@...> wrote:
On 24/07/17 16:47, Marti Bolivar wrote:
    It's likely future work, but it seems inevitable we'll have to
    define exactly the state of the device that mcuboot provides to the
    chainloaded image. Having a place to put formal definitions will
    simplify this work.


I especially want to highlight this part: ^^

Erwan, I noticed while looking at a recent PR [1] that the STM32 UARTs have a status = "disabled" property in DTS (not introduced in this change, was already there).

But in fact, when Zephyr is chain-loaded by mcuboot, at least one of the UARTs is not disabled, since mcuboot uses it to log and doesn't disable it before jumping to the next image. Further the clocks are reconfigured from their reset defaults, the PLL is on, etc.

It seems like this will inevitably cause problems as the Zephyr DTS continues to get more sophisticated (not just for STM32).

Am I missing something here?

The enabled property doesn't describe whether the peripheral is active or not at bootloader handover. It is more like whether that peripheral is connected to something useful. DT describes the hardware, including the board, so if a UART is not pinned out somewhere in the board design it should not be enabled in the DT.
And if connected to HW, should it be enabled and clocked?
Linux uses mix of Kconfig/dt. Kconfig for compilation/dt for activation. Do we want the same in Zephyr and keep these 2 levels of configuration?
Another option would be to add a property in device tree to declare activation at boot.
Andy.G you may already have thought about this?
Sorry if I have gone off topic.

A little bit :), perhaps.

This thread is about clocks, peripherals, etc. which mcuboot may use and what should happen to them before control is passed to Zephyr; please note that this thread is also posted to the mcuboot developer list. The above seem like they may be unrelated as they sound like Zephyr internals.
 


Also, are you reviewing the SoC DT include file or the board description?

The patch you linked to seems to be mostly SoC include files. It is normal for all peripherals to be disabled in SoC include files. It is only when the pinout for the board is decided that we know what peripherals should actually be enabled (and what pinmux settings to use for them).


Daniel.




Thanks,
Marti

[1] https://github.com/zephyrproject-rtos/zephyr/pull/888



_______________________________________________
Zephyr-devel mailing list
Zephyr-devel@...ct.org
https://lists.zephyrproject.org/mailman/listinfo/zephyr-devel





Erwan Gouriou
 



On 24 July 2017 at 18:03, Daniel Thompson <daniel.thompson@...> wrote:
On 24/07/17 16:47, Marti Bolivar wrote:
    It's likely future work, but it seems inevitable we'll have to
    define exactly the state of the device that mcuboot provides to the
    chainloaded image. Having a place to put formal definitions will
    simplify this work.


I especially want to highlight this part: ^^

Erwan, I noticed while looking at a recent PR [1] that the STM32 UARTs have a status = "disabled" property in DTS (not introduced in this change, was already there).

But in fact, when Zephyr is chain-loaded by mcuboot, at least one of the UARTs is not disabled, since mcuboot uses it to log and doesn't disable it before jumping to the next image. Further the clocks are reconfigured from their reset defaults, the PLL is on, etc.

It seems like this will inevitably cause problems as the Zephyr DTS continues to get more sophisticated (not just for STM32).

Am I missing something here?

The enabled property doesn't describe whether the peripheral is active or not at bootloader handover. It is more like whether that peripheral is connected to something useful. DT describes the hardware, including the board, so if a UART is not pinned out somewhere in the board design it should not be enabled in the DT.
And if connected to HW, should it be enabled and clocked?
Linux uses mix of Kconfig/dt. Kconfig for compilation/dt for activation. Do we want the same in Zephyr and keep these 2 levels of configuration?
Another option would be to add a property in device tree to declare activation at boot.
Andy.G you may already have thought about this?
Sorry if I have gone off topic.


Also, are you reviewing the SoC DT include file or the board description?

The patch you linked to seems to be mostly SoC include files. It is normal for all peripherals to be disabled in SoC include files. It is only when the pinout for the board is decided that we know what peripherals should actually be enabled (and what pinmux settings to use for them).


Daniel.




Thanks,
Marti

[1] https://github.com/zephyrproject-rtos/zephyr/pull/888



_______________________________________________
Zephyr-devel mailing list
Zephyr-devel@...ct.org
https://lists.zephyrproject.org/mailman/listinfo/zephyr-devel




Marti Bolivar <marti.bolivar@...>
 



On 24 July 2017 at 12:03, Daniel Thompson <daniel.thompson@...> wrote:
On 24/07/17 16:47, Marti Bolivar wrote:
    It's likely future work, but it seems inevitable we'll have to
    define exactly the state of the device that mcuboot provides to the
    chainloaded image. Having a place to put formal definitions will
    simplify this work.


I especially want to highlight this part: ^^

Erwan, I noticed while looking at a recent PR [1] that the STM32 UARTs have a status = "disabled" property in DTS (not introduced in this change, was already there).

But in fact, when Zephyr is chain-loaded by mcuboot, at least one of the UARTs is not disabled, since mcuboot uses it to log and doesn't disable it before jumping to the next image. Further the clocks are reconfigured from their reset defaults, the PLL is on, etc.

It seems like this will inevitably cause problems as the Zephyr DTS continues to get more sophisticated (not just for STM32).

Am I missing something here?

The enabled property doesn't describe whether the peripheral is active or not at bootloader handover. It is more like whether that peripheral is connected to something useful. DT describes the hardware, including the board, so if a UART is not pinned out somewhere in the board design it should not be enabled in the DT.

Also, are you reviewing the SoC DT include file or the board description?

The patch you linked to seems to be mostly SoC include files. It is normal for all peripherals to be disabled in SoC include files. It is only when the pinout for the board is decided that we know what peripherals should actually be enabled (and what pinmux settings to use for them).

OK, so it sounds like these DT changes aren't expressing expectations about the state of the peripheral.

But based on David's response, it does seem like it matters to Zephyr what state the peripherals are in when the bootloader hands over control, and that's not currently managed as it should be.

Should we just let this sit until it causes concrete problems? Any ideas from the Zephyr devs on how they'd like to see this managed (noting that this thread is cross-posted to dev-mcuboot)?

Thanks,
Marti
 



Daniel.




Thanks,
Marti

[1] https://github.com/zephyrproject-rtos/zephyr/pull/888



_______________________________________________
Zephyr-devel mailing list
Zephyr-devel@...ct.org
https://lists.zephyrproject.org/mailman/listinfo/zephyr-devel




Daniel Thompson <daniel.thompson@...>
 

On 24/07/17 16:47, Marti Bolivar wrote:
It's likely future work, but it seems inevitable we'll have to
define exactly the state of the device that mcuboot provides to the
chainloaded image. Having a place to put formal definitions will
simplify this work.
I especially want to highlight this part: ^^
Erwan, I noticed while looking at a recent PR [1] that the STM32 UARTs have a status = "disabled" property in DTS (not introduced in this change, was already there).
But in fact, when Zephyr is chain-loaded by mcuboot, at least one of the UARTs is not disabled, since mcuboot uses it to log and doesn't disable it before jumping to the next image. Further the clocks are reconfigured from their reset defaults, the PLL is on, etc.
It seems like this will inevitably cause problems as the Zephyr DTS continues to get more sophisticated (not just for STM32).
Am I missing something here?
The enabled property doesn't describe whether the peripheral is active or not at bootloader handover. It is more like whether that peripheral is connected to something useful. DT describes the hardware, including the board, so if a UART is not pinned out somewhere in the board design it should not be enabled in the DT.

Also, are you reviewing the SoC DT include file or the board description?

The patch you linked to seems to be mostly SoC include files. It is normal for all peripherals to be disabled in SoC include files. It is only when the pinout for the board is decided that we know what peripherals should actually be enabled (and what pinmux settings to use for them).


Daniel.



Thanks,
Marti
[1] https://github.com/zephyrproject-rtos/zephyr/pull/888
_______________________________________________
Zephyr-devel mailing list
Zephyr-devel@...
https://lists.zephyrproject.org/mailman/listinfo/zephyr-devel


David Brown
 

On Mon, Jul 24, 2017 at 11:47:47AM -0400, Marti Bolivar wrote:
It's likely future work, but it seems inevitable we'll have to define
exactly the state of the device that mcuboot provides to the chainloaded
image. Having a place to put formal definitions will simplify this work.

I especially want to highlight this part: ^^

Erwan, I noticed while looking at a recent PR [1] that the STM32 UARTs have a 
status = "disabled" property in DTS (not introduced in this change, was already
there).

But in fact, when Zephyr is chain-loaded by mcuboot, at least one of the UARTs
is not disabled, since mcuboot uses it to log and doesn't disable it before
jumping to the next image. Further the clocks are reconfigured from their reset
defaults, the PLL is on, etc.

It seems like this will inevitably cause problems as the Zephyr DTS continues
to get more sophisticated (not just for STM32).

Am I missing something here?
I don't think so. Part of the definition of the bootloader needs to
be to describe what state it leaves things in. For most
compatibility, it would seem best to leave things in as close to reset
state as possible. Ideally, that would shut down any clocks, etc.

Unfortunately, when booting apps that do use the serial port, turning
off the clock like this will usually result in gibberish coming over
the serial port. This probably doesn't hurt much, but can be
annoying.

The Mynewt approach has been to not use the serial port in the
bootloader. We could consider the uart use to be a debugging feature,
and recommend it be turned off for production.

Otherwise, we would want to add code to disable any clocks that were
started. I'm not sure there is an easy way to do this in the mcuboot
code without introducing target-specific code.

David


Marti Bolivar <marti.bolivar@...>
 

Hi,

David's threads didn't get much response, but while looking at some STM32 rework in Zephyr, I thought it was worth another try.

On 28 June 2017 at 13:29, Marti Bolivar <marti.bolivar@...> wrote:


In general I also think that we need to start thinking about other issues related to passing control from mcuboot to Zephyr. Beyond just setting up the stack and jumping to the entry point, mcuboot on Zephyr also locks IRQs and disables the system clock. However, those aren't the only hardware resources it uses, and it isn't always "clean" about putting them back into their reset state.

For example, Zephyr mcuboot currently leaves the STM32 clock tree configured to use the PLL, it leaves devices powered on, clocked, and configured (e.g. UART), etc. The story is similar on other targets.

Leaving this vaguely defined is undesirable, especially for power management.

It's likely future work, but it seems inevitable we'll have to define exactly the state of the device that mcuboot provides to the chainloaded image. Having a place to put formal definitions will simplify this work.

I especially want to highlight this part: ^^

Erwan, I noticed while looking at a recent PR [1] that the STM32 UARTs have a status = "disabled" property in DTS (not introduced in this change, was already there).

But in fact, when Zephyr is chain-loaded by mcuboot, at least one of the UARTs is not disabled, since mcuboot uses it to log and doesn't disable it before jumping to the next image. Further the clocks are reconfigured from their reset defaults, the PLL is on, etc.

It seems like this will inevitably cause problems as the Zephyr DTS continues to get more sophisticated (not just for STM32).

Am I missing something here?

Thanks,
Marti


 


Marti Bolivar <marti.bolivar@...>
 

Hi David,

Thanks for putting this together.

On 28 June 2017 at 11:59, David Brown <david.brown@...> wrote:
Background
==========

On larger platforms, there will generally be a protocol for passing
information from the bootloader to the operating system that it is
booting.  There are various standards for this, from BIOS, UEFI, to
the more simplistic approach used on many ARM targets of passing a
pointer to a flattened device tree in a register.

Now that we are approaching a 1.0 release of mcuboot, it would be nice
to also have a way for the bootloader to pass information to the
running application.  This will likely be a fairly simple method,
given the memory constraints of the devices typically used by Zephyr.


+1 to simplicity. It's also of course worth noting that we can do this slightly differently across arches if necessary, though it'd be nice to avoid that.
 
It is important to note that the bootloader and application will
generally be built separately, and generally, the bootloader will not
be upgraded, but only the application.  This is why it is necessary
for a possibly upgraded application to know about the bootloader
present in a particular device.

At this time, most of this information is needed by over-the-air
updating, since this effectively has to communicate back to the
bootloader in order to be able to use the new image.  Currently, we're
thinking of:

 - Version information about the bootloader.
 - Information about how to perform an upgrade.
 - Information about the flash device itself, specifically the
   bootloader's ideas of the partitions it cares about.

This is a great list. I'd like to get into some additional details, if possible.

First, I think the application needs to be able to find out how the bootloader was configured, not just its version.

For example, applications may want to know whether the bootloader was configured to swap image data, or if it was built for "overwrite only", or if it's a "split loader", or perhaps some other future boot strategy. You might imagine deploying "canary" builds only to devices which support rollback and not ones which always overwrite old images, for instance. As another example, applications may want to know which signature checking algorithms the bootloader supports, to e.g. determine which of multiple equivalent images signed with different algorithms is appropriate for the current bootloader.

Both of these examples assume deploying different bootloader configurations on the same device. It may not be reasonable to permit this, but I think it's worth considering, especially since saying "that can't happen" forces each application to track its own expectations of the bootloader's configuration, which has its own issues.

Second, I'm not sure if the combination of "how to perform an upgrade" and "ideas of the partitions it cares about" implies the application can signal to the bootloader the results of a given boot, but this seems necessary.

For example, if the bootloader is configured to swap, then when a "test" swapped application boots, it needs to decide to either mark itself as OK or request a revert from mcuboot on the next reset. (More on this topic below).

Third, we may want to consider how to access the public keys trusted by mcuboot from the application, and perhaps other key management. This can be left to a future extension, but it may help point the way on the functions vs. data debate.

Right now, mcuboot supports an array of public keys it trusts when checking a key signature. If these keys are ever compromised, device manufacturers are likely to at least ship future devices with different keys in the bootloader. If they want to continue to upgrade old devices, this means the application must convey the supported keys to the source of firmware updates at runtime. Thinking forward to key revocation is another reason why we will likely want this.
 

Proposal
========

https://github.com/runtimeco/mcuboot/pull/61 has current work on this,
although it is quite tentative.  The idea is to pass a pair of
registers from the bootloader to the application.  One register will
have a magic value, and the other a pointer to a structure (likely in
flash).

Passing a pointer to flash simplifies the design because it will not
be necessary to reserve a section of RAM that the application needs to
avoid using for another purpose.

The structure contains an additional magic value, a version field, and
currently, a function pointer.  Additional queries are made by calling
this function with specific commands.

There is additional complexity because of the function pointer, with
some pros and cons.  Pros:

 - It is fairly easy to add new commands, and even deprecate
   commands.

 - It allows data that must be computed at run time rather than just
   being compile-time constant data.

and some cons as well:

 - It could be considered risky to have the application call into
   code in the bootloader.

 - The code has to be carefully written to not use RAM data, which
   will have been overwritten by the application.

The other option would be to define a larger structure, and place the
current data within this structure.  Pros:

 - No risk of running code in the bootloader.

Cons:

 - Versioning becomes more complicated, and the logic to handle
   various versions must make it into every application.

 - Complex data (e.g. a representation of the partitions) needs to be
   determined at compile time so it can be placed in a ROM data
   structure.

It would also be possible to place this structure in RAM, if we can
define an area for this purpose.  Because mcuboot has a goal to work
with more than just Zephyr, this may impose additional constraints on
every OS that wishes to use mcuboot.


Function pointers are also nice from a flash usage perspective, since mcuboot and the RTOS it chain-loads are likely going to have similar routines operating on this information.

 
Zephyr Details
==============
Supporting this in Zephyr involves adding a small amount of assembly
to system startup to detect if the register contains the magic value,
and if so, stashing away the pointer in the other register.  Once this
is stored, the rest of the use can be done at a library level or by an
application.

In addition, the MPU/MMU may need to be configured to allow reading
and/or execution from the area of flash containing the bootloader.

Questions
=========

 - What do people think of this proposal?

I think we need to define at least Zephyr's relationship to its bootloader, so I'm really glad about this proposal.
 

 - Preferences for: ROM+callback, ROM only, or RAM only

ROM+callback seems best (less duplication of code across RTOSes, lower resource usage on the device) if it is possible.
 

 - How formally should we define this proposal?  Is a de-facto
   implementation by mcuboot sufficient at this time?

I think this should be defined formally. Whenever there's protocol versioning, there needs to be a spec.

In general I also think that we need to start thinking about other issues related to passing control from mcuboot to Zephyr. Beyond just setting up the stack and jumping to the entry point, mcuboot on Zephyr also locks IRQs and disables the system clock. However, those aren't the only hardware resources it uses, and it isn't always "clean" about putting them back into their reset state.

For example, Zephyr mcuboot currently leaves the STM32 clock tree configured to use the PLL, it leaves devices powered on, clocked, and configured (e.g. UART), etc. The story is similar on other targets.

Leaving this vaguely defined is undesirable, especially for power management.

It's likely future work, but it seems inevitable we'll have to define exactly the state of the device that mcuboot provides to the chainloaded image. Having a place to put formal definitions will simplify this work.
 

 - Thoughts on future data that may need to be passed?

Please see above.

Thanks,
Marti
 

Thanks,
David Brown
_______________________________________________
Zephyr-devel mailing list
Zephyr-devel@...ct.org
https://lists.zephyrproject.org/mailman/listinfo/zephyr-devel


David Brown
 

Background
==========

On larger platforms, there will generally be a protocol for passing
information from the bootloader to the operating system that it is
booting. There are various standards for this, from BIOS, UEFI, to
the more simplistic approach used on many ARM targets of passing a
pointer to a flattened device tree in a register.

Now that we are approaching a 1.0 release of mcuboot, it would be nice
to also have a way for the bootloader to pass information to the
running application. This will likely be a fairly simple method,
given the memory constraints of the devices typically used by Zephyr.

It is important to note that the bootloader and application will
generally be built separately, and generally, the bootloader will not
be upgraded, but only the application. This is why it is necessary
for a possibly upgraded application to know about the bootloader
present in a particular device.

At this time, most of this information is needed by over-the-air
updating, since this effectively has to communicate back to the
bootloader in order to be able to use the new image. Currently, we're
thinking of:

- Version information about the bootloader.
- Information about how to perform an upgrade.
- Information about the flash device itself, specifically the
bootloader's ideas of the partitions it cares about.

Proposal
========

https://github.com/runtimeco/mcuboot/pull/61 has current work on this,
although it is quite tentative. The idea is to pass a pair of
registers from the bootloader to the application. One register will
have a magic value, and the other a pointer to a structure (likely in
flash).

Passing a pointer to flash simplifies the design because it will not
be necessary to reserve a section of RAM that the application needs to
avoid using for another purpose.

The structure contains an additional magic value, a version field, and
currently, a function pointer. Additional queries are made by calling
this function with specific commands.

There is additional complexity because of the function pointer, with
some pros and cons. Pros:

- It is fairly easy to add new commands, and even deprecate
commands.

- It allows data that must be computed at run time rather than just
being compile-time constant data.

and some cons as well:

- It could be considered risky to have the application call into
code in the bootloader.

- The code has to be carefully written to not use RAM data, which
will have been overwritten by the application.

The other option would be to define a larger structure, and place the
current data within this structure. Pros:

- No risk of running code in the bootloader.

Cons:

- Versioning becomes more complicated, and the logic to handle
various versions must make it into every application.

- Complex data (e.g. a representation of the partitions) needs to be
determined at compile time so it can be placed in a ROM data
structure.

It would also be possible to place this structure in RAM, if we can
define an area for this purpose. Because mcuboot has a goal to work
with more than just Zephyr, this may impose additional constraints on
every OS that wishes to use mcuboot.

Zephyr Details
==============
Supporting this in Zephyr involves adding a small amount of assembly
to system startup to detect if the register contains the magic value,
and if so, stashing away the pointer in the other register. Once this
is stored, the rest of the use can be done at a library level or by an
application.

In addition, the MPU/MMU may need to be configured to allow reading
and/or execution from the area of flash containing the bootloader.

Questions
=========

- What do people think of this proposal?

- Preferences for: ROM+callback, ROM only, or RAM only

- How formally should we define this proposal? Is a de-facto
implementation by mcuboot sufficient at this time?

- Thoughts on future data that may need to be passed?

Thanks,
David Brown