diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 4fc9e82792..f9c6078841 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -56,6 +56,7 @@ BOOT_LOG_MODULE_DECLARE(mcuboot); /* Currently only used by imgmgr */ int boot_current_slot; +#if !defined(MCUBOOT_LOGICAL_SECTOR_SIZE) || MCUBOOT_LOGICAL_SECTOR_SIZE == 0 #if (!defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)) || \ defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) /* Used for holding static buffers in multiple functions to work around issues @@ -63,6 +64,7 @@ defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) */ static struct boot_sector_buffer sector_buffers; #endif +#endif /* !defined(MCUBOOT_LOGICAL_SECTOR_SIZE) || MCUBOOT_LOGICAL_SECTOR_SIZE == 0 */ /** * @brief Determine if the data at two memory addresses is equal @@ -625,6 +627,7 @@ boot_erase_region(const struct flash_area *fa, uint32_t off, uint32_t size, bool #if (!defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)) || \ defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) +#if !defined(MCUBOOT_LOGICAL_SECTOR_SIZE) || MCUBOOT_LOGICAL_SECTOR_SIZE == 0 int boot_initialize_area(struct boot_loader_state *state, int flash_area) { @@ -665,6 +668,139 @@ boot_initialize_area(struct boot_loader_state *state, int flash_area) return 0; } +#else /* defined(MCUBOOT_LOGICAL_SECTOR_SIZE) && MCUBOOT_LOGICAL_SECTOR_SIZE != 0 */ +#if defined(MCUBOOT_VERIFY_LOGICAL_SECTORS) +/* Validation can only run once all flash areas are open and pointers to + * flash area objects are stored in state. + */ +static int +boot_verify_logical_sectors(int faid, const struct flash_area *fa) +{ + uint32_t slot_size; + uint32_t slot_off; + uint32_t sect_off = 0; + int rc; + int final_rc = 0; + bool device_with_erase; + uint32_t wbs; + + assert(fa != NULL); + assert(faid != 0); + + slot_off = (uint32_t)flash_area_get_off(fa); + slot_size = (uint32_t)flash_area_get_size(fa); + + wbs = flash_area_align(fa); + + device_with_erase = device_requires_erase(fa); + /* Go till all verifications are complete or we face issue that does not allow + * to precede with further tests. + */ + BOOT_LOG_INF("boot_verify_logical_sectors: verify flash area %p", fa); + BOOT_LOG_INF("boot_verify_logical_sectors: MCUBOOT_LOGICAL_SECTOR_SIZE == 0x%x", + MCUBOOT_LOGICAL_SECTOR_SIZE); + BOOT_LOG_INF("boot_verify_logical_sectors: slot offset == 0x%x", slot_off); + if (slot_size != 0) { + BOOT_LOG_INF("boot_verify_logical_sectors: slot size == 0x%x", slot_size); + } else { + BOOT_LOG_ERR("boot_verify_logical_sectors: 0 size slot"); + return BOOT_EFLASH; + } + BOOT_LOG_INF("boot_verify_logical_sectors: write block size %u", wbs); + BOOT_LOG_INF("boot_verify_logical_sectors: device with%s erase", + device_with_erase ? "" : "out"); + + /* We are expecting slot size to be multiple of logical sector size. + * Note though that we do not check alignment of the slot to logical sector. + * as it does not matter, only alignment of slot to a real erase page + * matters. + */ + if (slot_size % MCUBOOT_LOGICAL_SECTOR_SIZE) { + BOOT_LOG_ERR("boot_verify_logical_sectors: area size not aligned"); + final_rc = BOOT_EFLASH; + } + + BOOT_LOG_INF("boot_verify_logical_sectors: max %d logical sectors", + slot_size / MCUBOOT_LOGICAL_SECTOR_SIZE); + + if (device_with_erase) { + size_t total_scanned = 0; + + /* Check all logical sectors pages against erase pages of a device */ + while (total_scanned < slot_size) { + struct flash_sector fas; + + MCUBOOT_WATCHDOG_FEED(); + + BOOT_LOG_INF("boot_verify_logical_sectors: page 0x%x:0x%x ", slot_off, sect_off); + rc = flash_area_get_sector(fa, sect_off, &fas); + if (rc < 0) { + BOOT_LOG_ERR("boot_verify_logical_sectors: query err %d", rc); + final_rc = BOOT_EFLASH; + continue; + } + + /* Jumping by logical sector size should align us with real erase page + * each time. + */ + if (sect_off != flash_sector_get_off(&fas)) { + BOOT_LOG_ERR("boot_verify_logical_sectors: misaligned offset (0x%x)", + (uint32_t)flash_sector_get_off(&fas)); + final_rc = BOOT_EFLASH; + } + + /* Jumping by logical sector size */ + sect_off += MCUBOOT_LOGICAL_SECTOR_SIZE; + total_scanned += MCUBOOT_LOGICAL_SECTOR_SIZE; + } + } else { + /* Devices with no-explicit erase require alignment to write block size */ + + if (MCUBOOT_LOGICAL_SECTOR_SIZE % wbs) { + BOOT_LOG_ERR("boot_verify_logical_sectors: sector size not aligned to write block"); + final_rc = BOOT_EFLASH; + } + + if (slot_off % wbs) { + BOOT_LOG_ERR("boot_verify_logical_sectors: slot not aligned to write block"); + final_rc = BOOT_EFLASH; + } + } + + BOOT_LOG_INF("boot_verify_logical_sectors: completed (%d)", final_rc); + + return final_rc; +} +#endif /* MCUBOOT_LOGICAL_SECTOR_VALIDATION */ + +static int +boot_initialize_area(struct boot_loader_state *state, int flash_area) +{ + size_t area_size; + uint32_t *out_num_sectors; + + if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) { + area_size = flash_area_get_size(BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)); + out_num_sectors = &BOOT_IMG(state, BOOT_SLOT_PRIMARY).num_sectors; + } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) { + area_size = flash_area_get_size(BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY)); + out_num_sectors = &BOOT_IMG(state, BOOT_SLOT_SECONDARY).num_sectors; +#if MCUBOOT_SWAP_USING_SCRATCH + } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) { + area_size = flash_area_get_size(state->scratch.area); + out_num_sectors = &state->scratch.num_sectors; +#endif + } else { + return BOOT_EFLASH; + } + + *out_num_sectors = area_size / MCUBOOT_LOGICAL_SECTOR_SIZE; + + return 0; +} + +#endif /* defined(MCUBOOT_LOGICAL_SECTOR_SIZE) && MCUBOOT_LOGICAL_SECTOR_SIZE != 0 */ + static uint32_t boot_write_sz(struct boot_loader_state *state) { @@ -694,12 +830,13 @@ boot_read_sectors(struct boot_loader_state *state, struct boot_sector_buffer *se uint8_t image_index; int rc; + image_index = BOOT_CURR_IMG(state); + +#if !defined(MCUBOOT_LOGICAL_SECTOR_SIZE) || MCUBOOT_LOGICAL_SECTOR_SIZE == 0 if (sectors == NULL) { sectors = §or_buffers; } - image_index = BOOT_CURR_IMG(state); - BOOT_IMG(state, BOOT_SLOT_PRIMARY).sectors = sectors->primary[image_index]; #if BOOT_NUM_SLOTS > 1 @@ -709,6 +846,9 @@ boot_read_sectors(struct boot_loader_state *state, struct boot_sector_buffer *se state->scratch.sectors = sectors->scratch; #endif #endif +#else + (void)sectors; +#endif /* !defined(MCUBOOT_LOGICAL_SECTOR_SIZE) || MCUBOOT_LOGICAL_SECTOR_SIZE == 0 */ rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index)); if (rc != 0) { @@ -732,6 +872,28 @@ boot_read_sectors(struct boot_loader_state *state, struct boot_sector_buffer *se BOOT_WRITE_SZ(state) = boot_write_sz(state); +#if defined(MCUBOOT_VERIFY_LOGICAL_SECTORS) + BOOT_LOG_INF("boot_read_sectors: verify image %d slots", image_index); + BOOT_LOG_INF("boot_read_sectors: BOOT_SLOT_PRIMARY"); + if (boot_verify_logical_sectors(FLASH_AREA_IMAGE_PRIMARY(image_index), + BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)) != 0) { + rc = BOOT_EFLASH; + } + + BOOT_LOG_INF("boot_read_sectors: BOOT_SLOT_SECONDARY"); + if (boot_verify_logical_sectors(FLASH_AREA_IMAGE_SECONDARY(image_index), + BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY)) != 0) { + rc = BOOT_EFLASH_SEC; + } + +#if MCUBOOT_SWAP_USING_SCRATCH + BOOT_LOG_INF("boot_read_sectors: SCRATCH"); + if (boot_verify_logical_sectors(FLASH_AREA_IMAGE_SCRATCH, state->scratch.area) != 0) { + rc = BOOT_EFLASH; + } +#endif /* MCUBOOT_SWAP_USING_SCRATCH */ +#endif /* defined(MCUBOOT_LOGICAL_SECTOR_VALIDATION) */ + return 0; } #endif diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 784baf7e70..43ef29e077 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -240,14 +240,18 @@ struct boot_loader_state { struct { struct image_header hdr; const struct flash_area *area; +#if !defined(MCUBOOT_LOGICAL_SECTOR_SIZE) || MCUBOOT_LOGICAL_SECTOR_SIZE == 0 boot_sector_t *sectors; +#endif uint32_t num_sectors; } imgs[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS]; #if MCUBOOT_SWAP_USING_SCRATCH struct { const struct flash_area *area; +#if !defined(MCUBOOT_LOGICAL_SECTOR_SIZE) || MCUBOOT_LOGICAL_SECTOR_SIZE == 0 boot_sector_t *sectors; +#endif uint32_t num_sectors; } scratch; #endif @@ -510,6 +514,7 @@ boot_img_slot_off(struct boot_loader_state *state, size_t slot) return flash_area_get_off(BOOT_IMG_AREA(state, slot)); } +#if !defined(MCUBOOT_LOGICAL_SECTOR_SIZE) || MCUBOOT_LOGICAL_SECTOR_SIZE == 0 #ifndef MCUBOOT_USE_FLASH_AREA_GET_SECTORS static inline size_t @@ -549,6 +554,32 @@ boot_img_sector_off(const struct boot_loader_state *state, size_t slot, } #endif /* !defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */ +#else +static inline size_t +boot_img_sector_size(const struct boot_loader_state *state, + size_t slot, size_t sector) +{ + (void)state; + (void)slot; + (void)sector; + + return MCUBOOT_LOGICAL_SECTOR_SIZE; +} + +/* + * Offset of the sector from the beginning of the image, NOT the flash + * device. + */ +static inline uint32_t +boot_img_sector_off(const struct boot_loader_state *state, size_t slot, + size_t sector) +{ + (void)state; + (void)slot; + + return MCUBOOT_LOGICAL_SECTOR_SIZE * sector; +} +#endif #ifdef MCUBOOT_RAM_LOAD # ifdef __BOOTSIM__ diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 9769428b4d..16450f2448 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -702,6 +702,7 @@ boot_image_check(struct boot_loader_state *state, struct image_header *hdr, } #if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) +#if !defined(MCUBOOT_LOGICAL_SECTOR_SIZE) || MCUBOOT_LOGICAL_SECTOR_SIZE == 0 static fih_ret split_image_check(struct image_header *app_hdr, const struct flash_area *app_fap, @@ -732,6 +733,7 @@ split_image_check(struct image_header *app_hdr, out: FIH_RET(fih_rc); } +#endif /* !defined(MCUBOOT_LOGICAL_SECTOR_SIZE) || MCUBOOT_LOGICAL_SECTOR_SIZE == 0 */ #endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */ /* @@ -2210,10 +2212,12 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) BOOT_LOG_DBG("context_boot_go"); +#if !defined(MCUBOOT_LOGICAL_SECTOR_SIZE) || MCUBOOT_LOGICAL_SECTOR_SIZE == 0 #if defined(__BOOTSIM__) struct boot_sector_buffer sector_buf; sectors = §or_buf; #endif +#endif /* !defined(MCUBOOT_LOGICAL_SECTOR_SIZE) || MCUBOOT_LOGICAL_SECTOR_SIZE == 0 */ has_upgrade = false; @@ -2473,6 +2477,7 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) FIH_RET(fih_rc); } +#if !defined(MCUBOOT_LOGICAL_SECTOR_SIZE) || MCUBOOT_LOGICAL_SECTOR_SIZE == 0 fih_ret split_go(int loader_slot, int split_slot, void **entry) { @@ -2538,6 +2543,7 @@ split_go(int loader_slot, int split_slot, void **entry) FIH_RET(fih_rc); } +#endif /* !defined(MCUBOOT_LOGICAL_SECTOR_SIZE) || MCUBOOT_LOGICAL_SECTOR_SIZE == 0 */ #else /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */ diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 467b848dc2..74b1c8ffd9 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1263,6 +1263,27 @@ config BOOT_FIH_PROFILE_DEFAULT_HIGH endmenu +config MCUBOOT_LOGICAL_SECTOR_SIZE + int "Size of a logical sector" + default 0 + help + Set to 0 to use hardware sectors. Any other value here should be + aligned to hardware sectors in size and alignment. + +config MCUBOOT_LOGICAL_SECTOR_SIZE_SET + bool + default y + depends on MCUBOOT_LOGICAL_SECTOR_SIZE != 0 + +config MCUBOOT_VERIFY_LOGICAL_SECTORS + bool "Validate logical sector layout" + default y + depends on MCUBOOT_LOGICAL_SECTOR_SIZE_SET + help + Validation of logical sector size against hardware constrains. + Should be used to validate compile-time configuration against run-time + system. + config MCUBOOT_DEVICE_SETTINGS # Hidden selector for device-specific settings bool @@ -1270,7 +1291,8 @@ config MCUBOOT_DEVICE_SETTINGS # CPU options select MCUBOOT_DEVICE_CPU_CORTEX_M0 if CPU_CORTEX_M0 # Enable flash page layout if available - select FLASH_PAGE_LAYOUT if FLASH_HAS_PAGE_LAYOUT + select FLASH_PAGE_LAYOUT if FLASH_HAS_PAGE_LAYOUT && !MCUBOOT_LOGICAL_SECTOR_SIZE_SET + select FLASH_PAGE_LAYOUT if FLASH_HAS_PAGE_LAYOUT && MCUBOOT_VERIFY_LOGICAL_SECTORS # Enable flash_map module as flash I/O back-end select FLASH_MAP diff --git a/boot/zephyr/flash_map_extended.c b/boot/zephyr/flash_map_extended.c index e73dc07164..5cf95de2ed 100644 --- a/boot/zephyr/flash_map_extended.c +++ b/boot/zephyr/flash_map_extended.c @@ -70,8 +70,6 @@ BOOT_LOG_MODULE_DECLARE(mcuboot); #error "FLASH_DEVICE_ID could not be determined" #endif -static const struct device *flash_dev = DEVICE_DT_GET(FLASH_DEVICE_NODE); - int flash_device_base(uint8_t fd_id, uintptr_t *ret) { if (fd_id != FLASH_DEVICE_ID) { @@ -161,10 +159,28 @@ int flash_area_id_from_direct_image(int image_id) } #endif +uint8_t flash_area_get_device_id(const struct flash_area *fa) +{ + (void)fa; + + return FLASH_DEVICE_ID; +} + +#define ERASED_VAL 0xff +__weak uint8_t flash_area_erased_val(const struct flash_area *fap) +{ + (void)fap; + + return ERASED_VAL; +} + +#if (defined(CONFIG_MCUBOOT_LOGICAL_SECTOR_SIZE) && CONFIG_MCUBOOT_LOGICAL_SECTOR_SIZE == 0) || \ + defined(CONFIG_MCUBOOT_VERIFY_LOGICAL_SECTORS) int flash_area_sector_from_off(off_t off, struct flash_sector *sector) { int rc; struct flash_pages_info page; + static const struct device *flash_dev = DEVICE_DT_GET(FLASH_DEVICE_NODE); rc = flash_get_page_info_by_offs(flash_dev, off, &page); if (rc) { @@ -177,26 +193,13 @@ int flash_area_sector_from_off(off_t off, struct flash_sector *sector) return rc; } -uint8_t flash_area_get_device_id(const struct flash_area *fa) -{ - (void)fa; - return FLASH_DEVICE_ID; -} - -#define ERASED_VAL 0xff -__weak uint8_t flash_area_erased_val(const struct flash_area *fap) -{ - (void)fap; - return ERASED_VAL; -} - int flash_area_get_sector(const struct flash_area *fap, off_t off, struct flash_sector *fsp) { struct flash_pages_info fpi; int rc; - if (off < 0 || (size_t) off >= fap->fa_size) { + if (off < 0 || (size_t)off >= fap->fa_size) { return -ERANGE; } @@ -210,3 +213,27 @@ int flash_area_get_sector(const struct flash_area *fap, off_t off, return rc; } +#else +int flash_area_sector_from_off(off_t off, struct flash_sector *sector) +{ + sector->fs_off = off & ~(CONFIG_MCUBOOT_LOGICAL_SECTOR_SIZE - 1); + sector->fs_size = CONFIG_MCUBOOT_LOGICAL_SECTOR_SIZE; + + return 0; +} + +int flash_area_get_sector(const struct flash_area *fap, off_t off, + struct flash_sector *fsp) +{ + if (off < 0 || (size_t)off >= flash_area_get_size(fap)) { + BOOT_LOG_ERR("flash_area_get_sector: off %ld out of area %p", + (long)off, fap); + return -ERANGE; + } + + fsp->fs_off = off & ~(CONFIG_MCUBOOT_LOGICAL_SECTOR_SIZE - 1); + fsp->fs_size = CONFIG_MCUBOOT_LOGICAL_SECTOR_SIZE; + + return 0; +} +#endif diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index b35a11f97e..321555dbac 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -399,6 +399,27 @@ # endif #endif +/* If set to non-0 it will use logical sectors rather than querying + * device for sector sizes. This slightly reduces code and RAM usage. + * Note that the logical sector size has to be multiple of erase + * sector size that is biggest for of all devices in the system. + */ +#if defined(CONFIG_MCUBOOT_LOGICAL_SECTOR_SIZE) +#define MCUBOOT_LOGICAL_SECTOR_SIZE CONFIG_MCUBOOT_LOGICAL_SECTOR_SIZE +#endif + +/* Enable to validate compile time logical sector setup vs the real device layout. + * This increases the size of bootloader, but is useful to check whether + * selected logical sector size can be used with provided partitions + * and devices they are placed on. + * Once layout is tested, this option should be disabled for production + * devices, as it is pointless to re-validate non-changing setup on + * every MCUboot run. + */ +#if defined(CONFIG_MCUBOOT_VERIFY_LOGICAL_SECTORS) +#define MCUBOOT_VERIFY_LOGICAL_SECTORS 1 +#endif + #if defined(CONFIG_BOOT_MAX_IMG_SECTORS_AUTO) && defined(MIN_SECTOR_COUNT) #define MCUBOOT_MAX_IMG_SECTORS MIN_SECTOR_COUNT diff --git a/sim/Cargo.toml b/sim/Cargo.toml index 6d2262d90b..1492bab9c9 100644 --- a/sim/Cargo.toml +++ b/sim/Cargo.toml @@ -34,6 +34,7 @@ direct-xip = ["mcuboot-sys/direct-xip"] downgrade-prevention = ["mcuboot-sys/downgrade-prevention"] max-align-32 = ["mcuboot-sys/max-align-32"] hw-rollback-protection = ["mcuboot-sys/hw-rollback-protection"] +logical-sectors-4k= ["mcuboot-sys/logical-sectors-4k"] [dependencies] byteorder = "1.4" diff --git a/sim/mcuboot-sys/Cargo.toml b/sim/mcuboot-sys/Cargo.toml index f2eb706342..a0059f6522 100644 --- a/sim/mcuboot-sys/Cargo.toml +++ b/sim/mcuboot-sys/Cargo.toml @@ -93,6 +93,9 @@ downgrade-prevention = [] # Support images with 32-byte maximum write alignment value. max-align-32 = [] +# Use logical sectors +logical-sectors-4k = [] + # Enable hardware rollback protection hw-rollback-protection = [] diff --git a/sim/mcuboot-sys/build.rs b/sim/mcuboot-sys/build.rs index b2595689b7..df61d9e8f8 100644 --- a/sim/mcuboot-sys/build.rs +++ b/sim/mcuboot-sys/build.rs @@ -39,6 +39,7 @@ fn main() { let direct_xip = env::var("CARGO_FEATURE_DIRECT_XIP").is_ok(); let max_align_32 = env::var("CARGO_FEATURE_MAX_ALIGN_32").is_ok(); let hw_rollback_protection = env::var("CARGO_FEATURE_HW_ROLLBACK_PROTECTION").is_ok(); + let logical_sectors_4k = env::var("CARGO_FEATURE_LOGICAL_SECTORS_4K").is_ok(); let mut conf = CachedBuild::new(); conf.conf.define("__BOOTSIM__", None); @@ -53,6 +54,10 @@ fn main() { conf.conf.define("MCUBOOT_BOOT_MAX_ALIGN", Some("8")); } + if logical_sectors_4k { + conf.conf.define("MCUBOOT_LOGICAL_SECTOR_SIZE", Some("4096")); + } + conf.conf.define("MCUBOOT_IMAGE_NUMBER", Some(if multiimage { "2" } else { "1" })); if downgrade_prevention && !overwrite_only {