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

Implement swap without using scratch #589

Merged
merged 9 commits into from
Dec 9, 2019
Merged

Conversation

utzig
Copy link
Member

@utzig utzig commented Nov 20, 2019

This implements a swap upgrade that does not use a scratch area. It works by first moving all sectors in the secondary slot up one position, and then looping on moving sector of index X of the primary slot to index X of the secondary slot, followed by moving sector X+1 of the secondary slot to X on the primary slot, for each sector X.

@utzig utzig force-pushed the swap-move branch 6 times, most recently from 4267878 to e60214a Compare November 21, 2019 20:42
@utzig utzig marked this pull request as ready for review November 21, 2019 21:28
@utzig
Copy link
Member Author

utzig commented Nov 22, 2019

Ah, also currently this allows for both overwrite-only and swap-move to be enabled at the same time, which makes overwrite-only the build option. Must also add a test + #errror

@utzig
Copy link
Member Author

utzig commented Nov 22, 2019

Ok, now it's only missing design doc update. I will wait for review issues before I write it down.

@utzig
Copy link
Member Author

utzig commented Nov 22, 2019

Btw, encrypted image swap is currently broken as was found out after merging e84f0ef!

Copy link
Member

@d3zd3z d3zd3z left a comment

Choose a reason for hiding this comment

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

The code largely looks good, other than the one test occasionally causing segfaults.

Maybe we should at least document that the code assumes the header is smaller than the chunk size (which is 1024), and that if someone had a larger vector table, this would have to be increased, or the code changed.

boot/bootutil/src/loader.c Show resolved Hide resolved
boot/bootutil/src/loader.c Show resolved Hide resolved
Copy link
Member

@d3zd3z d3zd3z left a comment

Choose a reason for hiding this comment

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

Just two little questions, otherwise looks good. I'll create an issue for the one orthogonal thing.

boot/bootutil/src/swap_move.c Show resolved Hide resolved
boot/bootutil/src/swap_move.c Show resolved Hide resolved
@utzig utzig force-pushed the swap-move branch 2 times, most recently from fbc4a97 to 5fe73ad Compare November 28, 2019 13:56
boot/bootutil/src/bootutil_priv.h Show resolved Hide resolved
boot/bootutil/src/bootutil_priv.h Outdated Show resolved Hide resolved
boot/bootutil/src/swap_move.c Show resolved Hide resolved
@nvlsianpu
Copy link
Collaborator

cc @hakonfam

boot/bootutil/src/swap_move.c Show resolved Hide resolved
boot/bootutil/src/swap_move.c Show resolved Hide resolved
boot/bootutil/src/swap_move.c Show resolved Hide resolved
Copy link
Contributor

@oyvindronningstad oyvindronningstad left a comment

Choose a reason for hiding this comment

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

Cool feature :)

* a permanent upgrade in case a reset occurs.
*/
void
fixup_revert(const struct boot_loader_state *state, struct boot_status *bs,
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add more explanation for this? E.g. what is the "right" time?

Copy link
Member Author

Choose a reason for hiding this comment

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

It might be a bad wording; maybe it should be called "wrong" instead of "right". The idea is that there is a short period of time during the beginning of a revert where metadata might be lost because status in slot0 must be erased and status in slot1 was already previously erased. If a reset occurs at this time the swap breaks. The fixup... routine just saves temporarily the data in slot1 (and it will be erased again moments later), but it is saved long enough to walk a few extra steps without loosing information.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks, I got what you meant by "right" ;). Your comment gives good context which I think should be added to the function doc comment.

Copy link
Member Author

Choose a reason for hiding this comment

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

I did not copy the previous answer, but hopefully I improved the text with: 29ec1ab

int boot_write_copy_done(const struct flash_area *fap);
int boot_write_image_ok(const struct flash_area *fap);
int boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type,
uint8_t image_num);
int boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size);
int boot_read_swap_size(int image_index, uint32_t *swap_size);
int boot_erase_trailer_sectors(const struct boot_loader_state *state,
Copy link
Contributor

Choose a reason for hiding this comment

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

Personally, I'd like the new swap implementations to have their own (shared) header file. To make it even more decoupled.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done with 5887060. I did not go too far, simply moved new stuff from the PR, but it looks like it would be possible to move more non overwrite-only stuff in there... would rather do later...

@utzig
Copy link
Member Author

utzig commented Nov 29, 2019

@oyvindronningstad I doubt I would be the best person to document this, all function names look self-explanatory to me! 😂

Copy link
Contributor

@oyvindronningstad oyvindronningstad left a comment

Choose a reason for hiding this comment

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

Some guiding questions for writing documentation. They are questions I get from just looking at the header file with no real knowledge of the implementation, hopefully they will make it easier if you want to write docs :).

Also, consider changing the names. E.g. changing boot_ to swap_ would IMO be more descriptive.


#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)

int boot_erase_trailer_sectors(const struct boot_loader_state *state,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why does this need a separate function?


int boot_erase_trailer_sectors(const struct boot_loader_state *state,
const struct flash_area *fap);
int boot_copy_region(struct boot_loader_state *state,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this for copying between different slots or within the same slot?
Does it erase?
Does it have alignment restrictions?

const struct flash_area *fap_src,
const struct flash_area *fap_dst,
uint32_t off_src, uint32_t off_dst, uint32_t sz);
int boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz);
Copy link
Contributor

Choose a reason for hiding this comment

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

Does it have alignment restrictions?

const struct flash_area *fap_dst,
uint32_t off_src, uint32_t off_dst, uint32_t sz);
int boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz);
int boot_status_init(const struct boot_loader_state *state,
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this initialize the structure in flash, or does it read from flash and initialize a RAM copy, or neither?
Which are input and output parameters?

int boot_status_init(const struct boot_loader_state *state,
const struct flash_area *fap,
const struct boot_status *bs);
void boot_perform_swap(struct boot_loader_state *state,
Copy link
Contributor

Choose a reason for hiding this comment

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

What are input and output parameters?
When is this meant to be called? Many times or once only?
Does it resume where it left off if the device resets?

void boot_perform_swap(struct boot_loader_state *state,
struct boot_status *bs,
uint32_t copy_size);
int boot_status_source(struct boot_loader_state *state);
Copy link
Contributor

Choose a reason for hiding this comment

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

What is a 'source' in this context? What are input and output parameters?

struct boot_status *bs,
uint32_t copy_size);
int boot_status_source(struct boot_loader_state *state);
int boot_read_status_bytes(const struct flash_area *fap,
Copy link
Contributor

Choose a reason for hiding this comment

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

What are 'status bytes' and where are they read from? Which parameter (or return value?) contains the status bytes after I've called this?

* See the License for the specific language governing permissions and
* limitations under the License.
*/

Copy link
Contributor

Choose a reason for hiding this comment

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

Top level docs: e.g. Describe the end result of a swap, and maybe a sentence about each method (SCRATCH and MOVE)

@utzig
Copy link
Member Author

utzig commented Dec 3, 2019

@oyvindronningstad I applied a few changes loosely based on your suggestions: renamed functions that are only required by swap upgrade functionality to swap_ (from boot_); moved them to a new swap_misc.c file; added some extra documentation (very basic) to swap_priv.h which does not substitute the required read of the design document. I will write more about how the swap without scratch works in the design document once this PR seems close to done (based on reviews).

@utzig
Copy link
Member Author

utzig commented Dec 3, 2019

@oyvindronningstad Oops, forgot to point the commit, here it is: ba05ddc

Copy link
Member

@d3zd3z d3zd3z left a comment

Choose a reason for hiding this comment

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

I'm happy with these changes (and thanks for adding as new commits, otherwise it would be hard to tell what changed). Once everyone is happy, we can squash.

Copy link
Contributor

@oyvindronningstad oyvindronningstad left a comment

Choose a reason for hiding this comment

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

@utzig Thanks a lot!

One final request: Add top level docs that just point to the relevant design docs.

Signed-off-by: Fabio Utzig <utzig@apache.org>
This moves the functionality that is unique to a scratch based swap
upgrade into a separate file. Later other upgrade strategies can be
added by reimplementing those functions.

Signed-off-by: Fabio Utzig <utzig@apache.org>
@Laczen
Copy link

Laczen commented Dec 7, 2019

@utzig, nice that you are copying my idea for upgrade without scratch area from ZEPboot. The copy is not so good, you should first move up the image in the primary partition, this distributes the flash erases evenly. And it would be nice to mention the idea contributor.

This implements a swap upgrade that does not use a scratch area. It
works by first moving all sectors in the primary slot up one position,
and then looping on moving sector of index X of the secondary slot to
index X of the primary slot, followed by moving sector X+1 of the
primary slot to X on the secondary slot, for each sector X.

The idea behind this implementation was initially suggested by Jehudi
Maes (@Laczen) and implemented on his own bootloader (ZEPboot).

Signed-off-by: Fabio Utzig <utzig@apache.org>
Signed-off-by: Fabio Utzig <utzig@apache.org>
Add cap for swap using move and rename old swap upgrade cap to swap
using scratch. Update sim to allow swapping tests to also run using
move.

Signed-off-by: Fabio Utzig <utzig@apache.org>
Update `make_device` to return a slice of unsupported caps for a test.
This allows skipping tests in devices that are known to be non working
under some build configuration.

The device constructor was updated to return a `Result`, so that the
specific reason for skipping can be returned as a `String`.

Signed-off-by: Fabio Utzig <utzig@apache.org>
Add Mynewt option to enable building a bootloader that uses an
alternative swap algorithm, that first moves up all sectors in slot1 and
then directly swaps between slot0 and slot1.

Signed-off-by: Fabio Utzig <utzig@apache.org>
Signed-off-by: Fabio Utzig <utzig@apache.org>
Add Zephyr option to enable building a bootloader that uses an
alternative swap algorithm, that first moves up all sectors in slot1 and
then directly swaps between slot0 and slot1.

Signed-off-by: Fabio Utzig <utzig@apache.org>
@utzig
Copy link
Member Author

utzig commented Dec 9, 2019

@Laczen Thanks, I've swapped the indexes and now it moves up the primary. 7a7b56fc125eb0d807ccb716ce4fb870c2c66838 was updated to mention the idea.

@utzig
Copy link
Member Author

utzig commented Dec 9, 2019

@nvlsianpu @d3zd3z I added "[EXPERIMENTAL]" to the Zephyr Kconfig (9d94fd3#diff-56e9ade09681f44d80863bfce76a0f2bR130) and would like to leave it there at least until this looks as reliable as the scratch method. Is this OK?

Copy link
Member

@d3zd3z d3zd3z left a comment

Choose a reason for hiding this comment

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

LGTM. Hopefully we can get some good testing, and make this non experimental. But, I think it is good to go in this way.

@utzig utzig merged commit c58842e into mcu-tools:master Dec 9, 2019
@utzig utzig deleted the swap-move branch December 9, 2019 17:30
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.

None yet

5 participants