diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 319ce688e..890460d89 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 @@ -431,6 +433,7 @@ boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size) #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) { @@ -471,6 +474,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) { @@ -500,12 +636,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 @@ -515,6 +652,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) { @@ -538,6 +678,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 14c56cd21..cd7a449da 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -221,7 +221,9 @@ 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; #if defined(MCUBOOT_SWAP_USING_OFFSET) uint16_t unprotected_tlv_size; @@ -231,7 +233,9 @@ struct boot_loader_state { #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 @@ -469,6 +473,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 @@ -508,6 +513,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 02827f153..24c591c2d 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -460,6 +460,7 @@ boot_write_status(const struct boot_loader_state *state, struct boot_status *bs) #endif /* !MCUBOOT_DIRECT_XIP */ #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, @@ -490,6 +491,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 */ #if defined(MCUBOOT_DIRECT_XIP) @@ -1695,10 +1697,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; @@ -1958,6 +1962,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) { @@ -2023,6 +2028,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 828bcb71e..a6ae63805 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1264,6 +1264,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 @@ -1271,7 +1292,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 5b152fde4..19ecd1255 100644 --- a/boot/zephyr/flash_map_extended.c +++ b/boot/zephyr/flash_map_extended.c @@ -71,8 +71,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) { @@ -162,10 +160,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) { @@ -178,26 +194,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; } @@ -211,3 +214,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 d4be9d412..a8b0721ca 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 f7d3505a5..7fe5eda16 100644 --- a/sim/Cargo.toml +++ b/sim/Cargo.toml @@ -35,6 +35,7 @@ downgrade-prevention = ["mcuboot-sys/downgrade-prevention"] max-align-32 = ["mcuboot-sys/max-align-32"] hw-rollback-protection = ["mcuboot-sys/hw-rollback-protection"] check-load-addr = ["mcuboot-sys/check-load-addr"] +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 b3e46082f..b7d7f20b4 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 5276fbeb7..c58df7408 100644 --- a/sim/mcuboot-sys/build.rs +++ b/sim/mcuboot-sys/build.rs @@ -40,6 +40,7 @@ fn main() { 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 check_load_addr = env::var("CARGO_FEATURE_CHECK_LOAD_ADDR").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); @@ -54,6 +55,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 {