-
Notifications
You must be signed in to change notification settings - Fork 681
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
bootutil: Add support for devices without erase #2114
base: main
Are you sure you want to change the base?
Changes from all commits
6dd54da
e1a441d
4edb7fc
b96fe4a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -548,7 +548,11 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) | |
/* The image slot is corrupt. There is no way to recover, so erase the | ||
* slot to allow future upgrades. | ||
*/ | ||
#if !defined(CONFIG_MCUBOOT) && defined(__ZEPHYR__) | ||
flash_area_flatten(fa, 0, flash_area_get_size(fa)); | ||
#else | ||
Comment on lines
+551
to
+553
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. think it was mentioned in a previous PR that OS specific code should not be present in here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can fix that although MCUboot has significant problem where we are coupled with Flash Map API which means that this has to be replaced with a function that is implemented for every supported system. I will figure way around. |
||
flash_area_erase(fa, 0, flash_area_get_size(fa)); | ||
#endif | ||
rc = BOOT_EBADIMAGE; | ||
} | ||
break; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1020,7 +1020,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, | |
&boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver); | ||
if (rc < 0 && boot_check_header_erased(state, BOOT_PRIMARY_SLOT)) { | ||
BOOT_LOG_ERR("insufficient version in secondary slot"); | ||
flash_area_erase(fap, 0, flash_area_get_size(fap)); | ||
boot_scramble_slot(fap); | ||
/* Image in the secondary slot does not satisfy version requirement. | ||
* Erase the image and continue booting from the primary slot. | ||
*/ | ||
|
@@ -1040,7 +1040,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, | |
} | ||
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { | ||
if ((slot != BOOT_PRIMARY_SLOT) || ARE_SLOTS_EQUIVALENT()) { | ||
flash_area_erase(fap, 0, flash_area_get_size(fap)); | ||
boot_scramble_slot(fap); | ||
/* Image is invalid, erase it to prevent further unnecessary | ||
* attempts to validate and boot it. | ||
*/ | ||
|
@@ -1081,7 +1081,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, | |
* | ||
* Erase the image and continue booting from the primary slot. | ||
*/ | ||
flash_area_erase(fap, 0, fap->fa_size); | ||
boot_scramble_slot(fap); | ||
fih_rc = FIH_NO_BOOTABLE_IMAGE; | ||
goto out; | ||
} | ||
|
@@ -1174,20 +1174,108 @@ boot_validated_swap_type(struct boot_loader_state *state, | |
} | ||
#endif | ||
|
||
/* Helper macro to avoid compile errors with systems that do not | ||
* provide function to check device type. | ||
* Note: it used to be inline, but somehow compiler would not | ||
* optimize out branches that were impossible when this evaluated to | ||
* just "true". | ||
*/ | ||
#ifdef MCUBOOT_DEV_WITHOUT_ERASE_THEN_NO_ERASE | ||
#define device_requires_erase(fa) (flash_area_erase_required(fa)) | ||
#else | ||
#define device_requires_erase(fa) (true) | ||
#endif | ||
|
||
/** | ||
* Erases a region of flash. | ||
* Erases a region of device that requires erase prior to write; does | ||
* nothing on devices without erase. | ||
* | ||
* @param flash_area The flash_area containing the region to erase. | ||
* @param fap The flash_area containing the region to erase. | ||
* @param off The offset within the flash area to start the | ||
* erase. | ||
* erase. | ||
* @param sz The number of bytes to erase. | ||
* | ||
* @return 0 on success; nonzero on failure. | ||
*/ | ||
int | ||
boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz) | ||
{ | ||
return flash_area_erase(fap, off, sz); | ||
if (device_requires_erase(fap)) { | ||
return flash_area_erase(fap, off, sz); | ||
} | ||
return 0; | ||
} | ||
|
||
/** | ||
* Removes data from specified region either by writing 0x00 in place of | ||
* data or by doing erase, if device has such hardware requirement. | ||
* | ||
* @param fa The flash_area containing the region to erase. | ||
* @param off The offset within the flash area to start the | ||
* erase. | ||
* @param size The number of bytes to erase. | ||
* | ||
* @return 0 on success; nonzero on failure. | ||
*/ | ||
int | ||
boot_scramble_region(const struct flash_area *fa, uint32_t off, uint32_t size) | ||
{ | ||
int ret = 0; | ||
|
||
if (device_requires_erase(fa)) { | ||
return flash_area_erase(fa, off, size); | ||
} else { | ||
uint8_t buf[BOOT_MAX_ALIGN]; | ||
size_t size_done = 0; | ||
|
||
memset(buf, flash_area_erased_val(fa), sizeof(buf)); | ||
|
||
while (size_done < size) { | ||
ret = flash_area_write(fa, size_done + off, buf, sizeof(buf)); | ||
if (ret != 0) { | ||
break; | ||
} | ||
size_done += sizeof(buf); | ||
} | ||
Comment on lines
+1228
to
+1239
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this just assumes max align will not overflow the size but makes no checks to ensure that, it should reduces buffer on final write to ensure it does not overflow There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that was intentional as I have assumes that MCUboot should write at BOOT_MAX_ALIGN pace anyway, but maybe that should be fixed. |
||
} | ||
return ret; | ||
} | ||
|
||
/** | ||
* Remove enough data from slot to mark is as unused | ||
* | ||
* @param fa Pointer to flash area object for slot | ||
* | ||
* @return 0 on success; nonzero on failure. | ||
*/ | ||
int | ||
boot_scramble_slot(const struct flash_area *fa) | ||
{ | ||
size_t size; | ||
|
||
/* Whether device with erase or not, without minimal scramble | ||
* removing deata in entire slot. | ||
*/ | ||
#if !defined(MCUBOOT_MINIMAL_SCRAMBLE) | ||
size = flash_area_get_size(fa); | ||
#else | ||
if (device_requires_erase(fa)) { | ||
int ret = 0; | ||
struct flash_sector header; | ||
|
||
ret = flash_area_get_sector(fa, 0, &header); | ||
size = flash_sector_get_size(&header); | ||
|
||
if (ret != 0) { | ||
return ret; | ||
} | ||
} else { | ||
size = MAX(sizeof(((struct image_header *)0)->ih_magic), | ||
BOOT_MAX_ALIGN); | ||
size = (size + BOOT_MAX_ALIGN - 1) & ~(BOOT_MAX_ALIGN - 1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should do the same for footer data because it might contain swap status or mcuboot flags for swapping images and those should always be cleared There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah right, header and slot trailer are verified separately. |
||
} | ||
#endif | ||
return boot_scramble_region(fa, 0, size); | ||
} | ||
|
||
#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) | ||
|
@@ -2112,8 +2200,7 @@ check_downgrade_prevention(struct boot_loader_state *state) | |
if (rc < 0) { | ||
/* Image in slot 0 prevents downgrade, delete image in slot 1 */ | ||
BOOT_LOG_INF("Image %d in slot 1 erased due to downgrade prevention", BOOT_CURR_IMG(state)); | ||
flash_area_erase(BOOT_IMG(state, 1).area, 0, | ||
flash_area_get_size(BOOT_IMG(state, 1).area)); | ||
boot_scramble_slot(BOOT_IMG(state, 1).area); | ||
} else { | ||
rc = 0; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -832,6 +832,36 @@ endif # BOOT_DECOMPRESSION_SUPPORT | |
|
||
endmenu | ||
|
||
config MCUBOOT_STORAGE_NO_UNNEEDED_ERASE | ||
bool "Erase is performed only on devices that require it by design" | ||
depends on FLASH_HAS_NO_EXPLICIT_ERASE | ||
help | ||
Not all devices require erase before write and, depending on driver, | ||
may emulate erase by write, as a way to scramble data rather then | ||
by hardware requirement. This unfortunately means that code that | ||
does erase before write, when not needed, will write device twice | ||
which not only reduces device life time but also doubles time | ||
of any write operation (one write for erase and one write for actual | ||
write). | ||
When this option is enabled, MCUboot will check for type of device | ||
and will avoid erase where not needed. | ||
|
||
config MCUBOOT_STORAGE_MINIMAL_SCRAMBLE | ||
bool "Do minimal required work to remove data" | ||
help | ||
In some cases MCUboot has to remove data, which usually means make | ||
it non-viable for MCUboot rather then completely destroyed. | ||
For example when MCUboot does not want to bother with broken image | ||
in some slot it will remove it. | ||
The same can be achieved with just removal of header, leaving the | ||
rest of image untouched, as without header MCUboot will not be able | ||
to recognize image in slot as bootable. | ||
Comment on lines
+856
to
+858
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. include footer |
||
When this option is enabled, MCUboot will not attempt to erase | ||
entire slot or image, instead it will just remove enough of | ||
data from slot to not recognize it as image anymore. | ||
Depending on type of device this may be done by erase of minimal | ||
number of pages or overwrite of part of image. | ||
|
||
config MCUBOOT_DEVICE_SETTINGS | ||
# Hidden selector for device-specific settings | ||
bool | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-I+i, *always