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

Multi flash #359

Merged
merged 10 commits into from
Dec 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 27 additions & 13 deletions boot/bootutil/src/bootutil_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,11 @@ struct boot_loader_state {
size_t num_sectors;
} imgs[BOOT_NUM_SLOTS];

const struct flash_area *scratch_area;
struct {
const struct flash_area *area;
boot_sector_t *sectors;
size_t num_sectors;
} scratch;

uint8_t write_sz;
};
Expand Down Expand Up @@ -198,7 +202,7 @@ int boot_read_enc_key(uint8_t slot, uint8_t *enckey);

/* These are macros so they can be used as lvalues. */
#define BOOT_IMG_AREA(state, slot) ((state)->imgs[(slot)].area)
#define BOOT_SCRATCH_AREA(state) ((state)->scratch_area)
#define BOOT_SCRATCH_AREA(state) ((state)->scratch.area)
#define BOOT_WRITE_SZ(state) ((state)->write_sz)

static inline struct image_header*
Expand All @@ -213,6 +217,12 @@ boot_img_num_sectors(struct boot_loader_state *state, size_t slot)
return state->imgs[slot].num_sectors;
}

static inline size_t
boot_scratch_num_sectors(struct boot_loader_state *state)
{
return state->scratch.num_sectors;
}

/*
* Offset of the slot from the beginning of the flash device.
*/
Expand All @@ -224,7 +234,7 @@ boot_img_slot_off(struct boot_loader_state *state, size_t slot)

static inline size_t boot_scratch_area_size(struct boot_loader_state *state)
{
return state->scratch_area->fa_size;
return BOOT_SCRATCH_AREA(state)->fa_size;
}

#ifndef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
Expand Down Expand Up @@ -252,27 +262,26 @@ static inline int
boot_initialize_area(struct boot_loader_state *state, int flash_area)
{
int num_sectors = BOOT_MAX_IMG_SECTORS;
size_t slot;
int rc;

switch (flash_area) {
case FLASH_AREA_IMAGE_0:
slot = 0;
rc = flash_area_to_sectors(flash_area, &num_sectors, state->imgs[0].sectors);
state->imgs[0].num_sectors = (size_t)num_sectors;
break;
case FLASH_AREA_IMAGE_1:
slot = 1;
rc = flash_area_to_sectors(flash_area, &num_sectors, state->imgs[1].sectors);
state->imgs[1].num_sectors = (size_t)num_sectors;
break;
case FLASH_AREA_IMAGE_SCRATCH:
rc = flash_area_to_sectors(flash_area, &num_sectors, state->scratch.sectors);
state->scratch.num_sectors = (size_t)num_sectors;
break;
default:
return BOOT_EFLASH;
}

rc = flash_area_to_sectors(flash_area, &num_sectors,
state->imgs[slot].sectors);
if (rc != 0) {
return rc;
}
state->imgs[slot].num_sectors = (size_t)num_sectors;
return 0;
return rc;
}

#else /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
Expand Down Expand Up @@ -311,6 +320,11 @@ boot_initialize_area(struct boot_loader_state *state, int flash_area)
out_sectors = state->imgs[1].sectors;
out_num_sectors = &state->imgs[1].num_sectors;
break;
case FLASH_AREA_IMAGE_SCRATCH:
num_sectors = BOOT_MAX_IMG_SECTORS;
out_sectors = state->scratch.sectors;
out_num_sectors = &state->scratch.num_sectors;
break;
default:
return -1;
}
Expand Down
126 changes: 105 additions & 21 deletions boot/bootutil/src/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,40 +316,92 @@ boot_write_sz(void)
* We need to use the bigger of those 2 values.
*/
elem_sz = flash_area_align(boot_data.imgs[0].area);
align = flash_area_align(boot_data.scratch_area);
align = flash_area_align(boot_data.scratch.area);
if (align > elem_sz) {
elem_sz = align;
}

return elem_sz;
}

/*
* Slots are compatible when all sectors that store upto to size of the image
* round up to sector size, in both slot's are able to fit in the scratch
* area, and have sizes that are a multiple of each other (powers of two
* presumably!).
*/
static int
boot_slots_compatible(void)
{
size_t num_sectors_0 = boot_img_num_sectors(&boot_data, 0);
size_t num_sectors_1 = boot_img_num_sectors(&boot_data, 1);
size_t size_0, size_1;
size_t i;
size_t num_sectors_0;
size_t num_sectors_1;
size_t sz0, sz1;
size_t slot0_sz, slot1_sz;
size_t scratch_sz;
size_t i, j;
int8_t smaller;

num_sectors_0 = boot_img_num_sectors(&boot_data, 0);
num_sectors_1 = boot_img_num_sectors(&boot_data, 1);
if (num_sectors_0 > BOOT_MAX_IMG_SECTORS || num_sectors_1 > BOOT_MAX_IMG_SECTORS) {
BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
return 0;
}

/* Ensure both image slots have identical sector layouts. */
if (num_sectors_0 != num_sectors_1) {
BOOT_LOG_WRN("Cannot upgrade: number of sectors differ between slots");
return 0;
}
scratch_sz = boot_scratch_area_size(&boot_data);

for (i = 0; i < num_sectors_0; i++) {
size_0 = boot_img_sector_size(&boot_data, 0, i);
size_1 = boot_img_sector_size(&boot_data, 1, i);
if (size_0 != size_1) {
BOOT_LOG_WRN("Cannot upgrade: an incompatible sector was found");
return 0;
/*
* The following loop scans all sectors in a linear fashion, assuring that
* for each possible sector in each slot, it is able to fit in the other
* slot's sector or sectors. Slot's should be compatible as long as any
* number of a slot's sectors are able to fit into another, which only
* excludes cases where sector sizes are not a multiple of each other.
*/
i = sz0 = slot0_sz = 0;
j = sz1 = slot1_sz = 0;
smaller = 0;
while (i < num_sectors_0 || j < num_sectors_1) {
if (sz0 == sz1) {
sz0 += boot_img_sector_size(&boot_data, 0, i);
sz1 += boot_img_sector_size(&boot_data, 1, j);
i++;
j++;
} else if (sz0 < sz1) {
sz0 += boot_img_sector_size(&boot_data, 0, i);
/* guarantee that multiple sectors of slot1 fit into slot0 */
if (smaller == 2) {
BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
return 0;
}
smaller = 1;
i++;
} else {
sz1 += boot_img_sector_size(&boot_data, 1, j);
nvlsianpu marked this conversation as resolved.
Show resolved Hide resolved
/* guarantee that multiple sectors of slot0 fit into slot1 */
if (smaller == 1) {
BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
return 0;
}
smaller = 2;
j++;
}
if (sz0 == sz1) {
slot0_sz += sz0;
slot1_sz += sz1;
/* scratch has to fit each swap operation to the size of the larger
* sector among slot0 and slot1
*/
if (sz0 > scratch_sz || sz1 > scratch_sz) {
BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside scratch");
return 0;
}
smaller = sz0 = sz1 = 0;
}
}

if (i != num_sectors_0 || j != num_sectors_1 || slot0_sz != slot1_sz) {
BOOT_LOG_WRN("Cannot upgrade: slots are not compatible");
return 0;
nvlsianpu marked this conversation as resolved.
Show resolved Hide resolved
}

return 1;
Expand All @@ -376,6 +428,11 @@ boot_read_sectors(void)
return BOOT_EFLASH;
}

rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_SCRATCH);
if (rc != 0) {
return BOOT_EFLASH;
}

BOOT_WRITE_SZ(&boot_data) = boot_write_sz();

return 0;
Expand Down Expand Up @@ -735,6 +792,11 @@ boot_copy_sz(int last_sector_idx, int *out_first_sector_idx)
scratch_sz = boot_scratch_area_size(&boot_data);
for (i = last_sector_idx; i >= 0; i--) {
new_sz = sz + boot_img_sector_size(&boot_data, 0, i);
/*
* slot1 is not being checked here, because `boot_slots_compatible`
* already provides assurance that the copy size will be compatible
* with slot0 and scratch.
*/
if (new_sz > scratch_sz) {
break;
}
Expand Down Expand Up @@ -951,8 +1013,8 @@ boot_swap_sectors(int idx, uint32_t sz, struct boot_status *bs)
copy_sz = sz;
trailer_sz = boot_slots_trailer_sz(BOOT_WRITE_SZ(&boot_data));

/* sz in this function is always is always sized on a multiple of the
* sector size. The check against the start offset of the last sector
/* sz in this function is always sized on a multiple of the sector size.
* The check against the start offset of the last sector
* is to determine if we're swapping the last sector. The last sector
* needs special handling because it's where the trailer lives. If we're
* copying it, we need to use scratch to write the trailer temporarily.
Expand Down Expand Up @@ -1193,6 +1255,7 @@ boot_copy_image(struct boot_status *bs)
uint32_t sz;
int first_sector_idx;
int last_sector_idx;
int last_idx_slot1;
uint32_t swap_idx;
struct image_header *hdr;
#ifdef MCUBOOT_ENC_IMAGES
Expand All @@ -1202,6 +1265,8 @@ boot_copy_image(struct boot_status *bs)
#endif
uint32_t size;
uint32_t copy_size;
uint32_t slot0_size;
uint32_t slot1_size;
int rc;

/* FIXME: just do this if asked by user? */
Expand Down Expand Up @@ -1294,14 +1359,31 @@ boot_copy_image(struct boot_status *bs)
#endif
}

size = 0;
slot0_size = 0;
slot1_size = 0;
last_sector_idx = 0;
last_idx_slot1 = 0;

/*
* Knowing the size of the largest image between both slots, here we
* find what is the last sector in slot0 that needs swapping. Since we
* already know that both slots are compatible, slot1's last sector is
* not really required after this check is finished.
*/
while (1) {
nvlsianpu marked this conversation as resolved.
Show resolved Hide resolved
size += boot_img_sector_size(&boot_data, 0, last_sector_idx);
if (size >= copy_size) {
if (slot0_size < copy_size || slot0_size < slot1_size) {
slot0_size += boot_img_sector_size(&boot_data, 0, last_sector_idx);
}
if (slot1_size < copy_size || slot1_size < slot0_size) {
slot1_size += boot_img_sector_size(&boot_data, 1, last_idx_slot1);
}
if (slot0_size >= copy_size &&
slot1_size >= copy_size &&
slot0_size == slot1_size) {
break;
}
last_sector_idx++;
last_idx_slot1++;
}

swap_idx = 0;
Expand Down Expand Up @@ -1463,8 +1545,10 @@ boot_go(struct boot_rsp *rsp)
*/
static boot_sector_t slot0_sectors[BOOT_MAX_IMG_SECTORS];
static boot_sector_t slot1_sectors[BOOT_MAX_IMG_SECTORS];
static boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
boot_data.imgs[0].sectors = slot0_sectors;
boot_data.imgs[1].sectors = slot1_sectors;
boot_data.scratch.sectors = scratch_sectors;

#ifdef MCUBOOT_ENC_IMAGES
/* FIXME: remove this after RAM is cleared by sim */
Expand Down
9 changes: 4 additions & 5 deletions sim/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions sim/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ validate-slot0 = ["mcuboot-sys/validate-slot0"]
enc-rsa = ["mcuboot-sys/enc-rsa"]
enc-kw = ["mcuboot-sys/enc-kw"]

[build-dependencies]
gcc = "0.3.54"

[dependencies]
libc = "0.2.0"
rand = "0.3.0"
Expand Down
2 changes: 1 addition & 1 deletion sim/mcuboot-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ enc-rsa = []
enc-kw = []

[build-dependencies]
gcc = "0.3.54"
cc = "1.0.25"

[dependencies]
lazy_static = "1.0"
Expand Down
5 changes: 3 additions & 2 deletions sim/mcuboot-sys/build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Build mcuboot as a library, based on the requested features.

extern crate gcc;
extern crate cc;

use std::env;
use std::fs;
Expand All @@ -16,8 +16,9 @@ fn main() {
let enc_rsa = env::var("CARGO_FEATURE_ENC_RSA").is_ok();
let enc_kw = env::var("CARGO_FEATURE_ENC_KW").is_ok();

let mut conf = gcc::Build::new();
let mut conf = cc::Build::new();
conf.define("__BOOTSIM__", None);
conf.define("MCUBOOT_HAVE_LOGGING", None);
conf.define("MCUBOOT_USE_FLASH_AREA_GET_SECTORS", None);
conf.define("MCUBOOT_HAVE_ASSERT_H", None);
conf.define("MCUBOOT_MAX_IMG_SECTORS", Some("128"));
Expand Down
Loading