Repository: incubator-mynewt-core Updated Branches: refs/heads/develop 4bfe5ef86 -> 7dc1ba022
MYNEWT-520 boot - Allow incompatible image slots Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/7dc1ba02 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/7dc1ba02 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/7dc1ba02 Branch: refs/heads/develop Commit: 7dc1ba022222d441a9b486f963ccb26bbf3f2a78 Parents: 4bfe5ef Author: Christopher Collins <[email protected]> Authored: Wed Dec 21 12:04:17 2016 -0800 Committer: Christopher Collins <[email protected]> Committed: Wed Dec 21 12:07:47 2016 -0800 ---------------------------------------------------------------------- boot/bootutil/src/loader.c | 138 ++++++++++++++++++++++++++-------------- 1 file changed, 92 insertions(+), 46 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7dc1ba02/boot/bootutil/src/loader.c ---------------------------------------------------------------------- diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 4d17291..e4dfc61 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -44,9 +44,9 @@ static struct { struct { struct image_header hdr; struct flash_area *sectors; + int num_sectors; } imgs[BOOT_NUM_SLOTS]; - int num_img_sectors; struct flash_area scratch_sector; uint8_t write_sz; @@ -251,7 +251,15 @@ boot_read_image_headers(void) for (i = 0; i < BOOT_NUM_SLOTS; i++) { rc = boot_read_image_header(i, &boot_data.imgs[i].hdr); if (rc != 0) { - return rc; + /* If at least one header was read successfully, then the boot + * loader can attempt a boot. Failure to read any headers is a + * fatal error. + */ + if (i > 0) { + return 0; + } else { + return rc; + } } } @@ -277,6 +285,28 @@ boot_write_sz(void) return elem_sz; } +static int +boot_slots_compatible(void) +{ + const struct flash_area *sector0; + const struct flash_area *sector1; + int i; + + /* Ensure both image slots have identical sector layouts. */ + if (boot_data.imgs[0].num_sectors != boot_data.imgs[1].num_sectors) { + return 0; + } + for (i = 0; i < boot_data.imgs[0].num_sectors; i++) { + sector0 = boot_data.imgs[0].sectors + i; + sector1 = boot_data.imgs[1].sectors + i; + if (sector0->fa_size != sector1->fa_size) { + return 0; + } + } + + return 1; +} + /** * Determines the sector layout of both image slots and the scratch area. * This information is necessary for calculating the number of bytes to erase @@ -286,13 +316,10 @@ boot_write_sz(void) static int boot_read_sectors(void) { - const struct flash_area *sector0; - const struct flash_area *sector1; const struct flash_area *scratch; int num_sectors_slot0; int num_sectors_slot1; int rc; - int i; num_sectors_slot0 = BOOT_MAX_IMG_SECTORS; rc = flash_area_to_sectors(FLASH_AREA_IMAGE_0, &num_sectors_slot0, @@ -300,6 +327,7 @@ boot_read_sectors(void) if (rc != 0) { return BOOT_EFLASH; } + boot_data.imgs[0].num_sectors = num_sectors_slot0; num_sectors_slot1 = BOOT_MAX_IMG_SECTORS; rc = flash_area_to_sectors(FLASH_AREA_IMAGE_1, &num_sectors_slot1, @@ -307,27 +335,13 @@ boot_read_sectors(void) if (rc != 0) { return BOOT_EFLASH; } + boot_data.imgs[1].num_sectors = num_sectors_slot1; rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &scratch); if (rc != 0) { return BOOT_EFLASH; } boot_data.scratch_sector = *scratch; - boot_data.write_sz = hal_flash_align(scratch->fa_device_id); - - /* Ensure both image slots have identical sector layouts. */ - if (num_sectors_slot0 != num_sectors_slot1) { - return BOOT_EFLASH; - } - for (i = 0; i < num_sectors_slot0; i++) { - sector0 = boot_data.imgs[0].sectors + i; - sector1 = boot_data.imgs[1].sectors + i; - if (sector0->fa_size != sector1->fa_size) { - return BOOT_EFLASH; - } - } - - boot_data.num_img_sectors = num_sectors_slot0; boot_data.write_sz = boot_write_sz(); @@ -842,7 +856,7 @@ boot_copy_image(struct boot_status *bs) int swap_idx; swap_idx = 0; - last_sector_idx = boot_data.num_img_sectors - 1; + last_sector_idx = boot_data.imgs[0].num_sectors - 1; while (last_sector_idx >= 0) { sz = boot_copy_sz(last_sector_idx, &first_sector_idx); if (swap_idx >= bs->idx) { @@ -925,6 +939,53 @@ boot_finalize_revert_swap(void) } /** + * Performs an image swap if one is required. + * + * @param out_swap_type On success, the type of swap performed gets + * written here. + * + * @return 0 on success; nonzero on failure. + */ +static int +boot_swap_if_needed(int *out_swap_type) +{ + struct boot_status bs; + int swap_type; + int rc; + + /* Determine if we rebooted in the middle of an image swap + * operation. + */ + rc = boot_read_status(&bs); + if (rc != 0) { + return rc; + } + + /* If a partial swap was detected, complete it. */ + if (bs.idx != 0 || bs.state != 0) { + rc = boot_copy_image(&bs); + assert(rc == 0); + + /* Extrapolate the type of the partial swap. We need this + * information to know how to mark the swap complete in flash. + */ + swap_type = boot_previous_swap_type(); + } else { + swap_type = boot_validated_swap_type(); + switch (swap_type) { + case BOOT_SWAP_TYPE_TEST: + case BOOT_SWAP_TYPE_REVERT: + rc = boot_copy_image(&bs); + assert(rc == 0); + break; + } + } + + *out_swap_type = swap_type; + return 0; +} + +/** * Prepares the booting process. This function moves images around in flash as * appropriate, and tells you what address to boot from. * @@ -935,7 +996,6 @@ boot_finalize_revert_swap(void) int boot_go(struct boot_rsp *rsp) { - struct boot_status bs; int swap_type; int slot; int rc; @@ -943,7 +1003,7 @@ boot_go(struct boot_rsp *rsp) /* The array of slot sectors are defined here (as opposed to file scope) so * that they don't get allocated for non-boot-loader apps. This is * necessary because the gcc option "-fdata-sections" doesn't seem to have - * any effect for some reason. + * any effect in older gcc versions (e.g., 4.8.4). */ static struct flash_area slot0_sectors[BOOT_MAX_IMG_SECTORS]; static struct flash_area slot1_sectors[BOOT_MAX_IMG_SECTORS]; @@ -962,30 +1022,16 @@ boot_go(struct boot_rsp *rsp) return rc; } - /* Determine if we rebooted in the middle of an image swap operation. */ - rc = boot_read_status(&bs); - if (rc != 0) { - return rc; - } - - /* If a partial swap was detected, complete it. */ - if (bs.idx != 0 || bs.state != 0) { - rc = boot_copy_image(&bs); - assert(rc == 0); - - /* Extrapolate the type of the partial swap. We need this information - * to know how to mark the swap complete in flash. - */ - swap_type = boot_previous_swap_type(); - } else { - swap_type = boot_validated_swap_type(); - switch (swap_type) { - case BOOT_SWAP_TYPE_TEST: - case BOOT_SWAP_TYPE_REVERT: - rc = boot_copy_image(&bs); - assert(rc == 0); - break; + /* If the image slots aren't compatible, no swap is possible. Just boot + * into slot 0. + */ + if (boot_slots_compatible()) { + rc = boot_swap_if_needed(&swap_type); + if (rc != 0) { + return rc; } + } else { + swap_type = BOOT_SWAP_TYPE_NONE; } switch (swap_type) {
