diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 3f774b664..e45603bbd 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,112 @@ 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_LOGICAL_SECTOR_VALIDATION) +/* Validation can only run once all flash areas are open and pointers to + * flash area objects are stored in state. + */ +static int +boot_validate_logical_sectors(const struct boot_loader_state *state, int faid, const struct flash_area *fa) +{ + uint32_t num_sectors = BOOT_MAX_IMG_SECTORS; + size_t slot_size; + size_t slot_off; + size_t sect_off = 0; + int rc; + int final_rc = 0; + + assert(fa != NULL); + assert(faid != 0); + + slot_off = flash_area_get_off(fa); + slot_size = flash_area_get_size(fa); + + + /* Go till all validations are complete or we face issue that does not allow + * to proceede with further tests. + */ + BOOT_LOG_INF("boot_validate_logical_sectors: validating flash area %p", fa); + BOOT_LOG_INF("boot_validate_logical_sectors: MCUBOOT_LOGICAL_SECTOR_SIZE == 0x%x", + MCUBOOT_LOGICAL_SECTOR_SIZE); + BOOT_LOG_INF("boot_validate_logical_sectors: slot offset == 0x%x", slot_off); + if (slot_size != 0) { + BOOT_LOG_INF("boot_validate_logical_sectors: slot size == 0x%x", slot_size); + } else { + BOOT_LOG_ERR("boot_validate_logical_sectors: 0 size slot"); + return BOOT_EFLASH; + } + + BOOT_LOG_INF("boot_validate_logical_sectors: max %d logical sectors", + slot_size / MCUBOOT_LOGICAL_SECTOR_SIZE); + + if (slot_off % MCUBOOT_LOGICAL_SECTOR_SIZE) { + BOOT_LOG_ERR("boot_validate_logical_sectors: area offset not aligned"); + final_rc = BOOT_EFLASH; + } + + if (slot_size % MCUBOOT_LOGICAL_SECTOR_SIZE) { + BOOT_LOG_ERR("boot_validate_logical_sectors: area size not aligned"); + final_rc = BOOT_EFLASH; + } + + /* Check all hardware specific pages against erase pages of a device */ + for (size_t i = 0; i < num_sectors; i++) { + struct flash_sector fas; + + MCUBOOT_WATCHDOG_FEED(); + + BOOT_LOG_INF("boot_validate_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_validate_logical_sectors: query err %d", rc); + final_rc = BOOT_EFLASH; + continue; + } + + + if (flash_sector_get_off(&fas) % MCUBOOT_LOGICAL_SECTOR_SIZE) { + BOOT_LOG_ERR("boot_validate_logical_sectors: misaligned offset"); + final_rc = BOOT_EFLASH; + } + + sect_off += flash_sector_get_size(&fas); + } + + BOOT_LOG_INF("boot_validate_logical_sectors: done %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_PRIMARY_SLOT)); + out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).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_SECONDARY_SLOT)); + out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).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 +803,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_PRIMARY_SLOT).sectors = sectors->primary[image_index]; #if BOOT_NUM_SLOTS > 1 @@ -709,6 +819,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 +845,29 @@ boot_read_sectors(struct boot_loader_state *state, struct boot_sector_buffer *se BOOT_WRITE_SZ(state) = boot_write_sz(state); +#if defined(MCUBOOT_LOGICAL_SECTOR_VALIDATION) + BOOT_LOG_INF("boot_read_sectors: validate image %d slots", image_index); + BOOT_LOG_INF("boot_read_sectors: BOOT_PRIMARY_SLOT"); + if (boot_validate_logical_sectors(state, FLASH_AREA_IMAGE_PRIMARY(image_index), + BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)) != 0) { + rc = BOOT_EFLASH; + } + + BOOT_LOG_INF("boot_read_sectors: BOOT_SECONDARY_SLOT"); + if(boot_validate_logical_sectors(state, FLASH_AREA_IMAGE_SECONDARY(image_index), + BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT)) != 0) { + rc = BOOT_EFLASH_SEC; + } + +#if MCUBOOT_SWAP_USING_SCRATCH + BOOT_LOG_INF("boot_read_sectors: SCRATCH"); + if(boot_validate_logical_sectors(state, 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 c0a285bbe..f60ef6ccc 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -245,14 +245,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 @@ -515,6 +519,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 @@ -554,6 +559,25 @@ 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) +{ + 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) +{ + 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 37adc5faf..8a28ee9f7 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -651,6 +651,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, @@ -681,6 +682,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 */ /* @@ -2159,10 +2161,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; @@ -2422,6 +2426,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) { @@ -2487,6 +2492,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 7c18a0329..d75cceb3b 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1112,6 +1112,26 @@ 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 if MCUBOOT_LOGICAL_SECTOR_SIZE != 0 + +config MCUBOOT_LOGICAL_SECTOR_VALIDATION + bool "Validate logical sector layout" + default true if MCUBOOT_LOGICAL_SECTOR_SIZE != 0 + 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 @@ -1119,7 +1139,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_LOGICAL_SECTOR_VALIDATION # 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 c5afb632b..9d456465b 100644 --- a/boot/zephyr/flash_map_extended.c +++ b/boot/zephyr/flash_map_extended.c @@ -65,8 +65,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) { @@ -156,10 +154,26 @@ 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_LOGICAL_SECTOR_VALIDATION) 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) { @@ -172,19 +186,6 @@ 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) { @@ -205,3 +206,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 095620846..518a4c8b9 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -357,6 +357,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_LOGICAL_SECTOR_VALIDATION) +#define MCUBOOT_LOGICAL_SECTOR_VALIDATION 1 +#endif + #if defined(CONFIG_BOOT_MAX_IMG_SECTORS_AUTO) && defined(MIN_SECTOR_COUNT) #define MCUBOOT_MAX_IMG_SECTORS MIN_SECTOR_COUNT