boot_serial: Add unaligned stack buffer writing
Fixes a bug when writing to devices which have memory alignment
requirements with data being using directly from a zcbor-response
whereby the alignment of the buffer data does not meet the
requirements of the flash driver.
Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c
index 2584c06..9a79926 100644
--- a/boot/boot_serial/src/boot_serial.c
+++ b/boot/boot_serial/src/boot_serial.c
@@ -511,7 +511,38 @@
BOOT_LOG_INF("Writing at 0x%x until 0x%x", curr_off, curr_off + img_chunk_len);
/* Write flash aligned chunk, note that img_chunk_len now holds aligned length */
+#if defined(MCUBOOT_SERIAL_UNALIGNED_BUFFER_SIZE) && MCUBOOT_SERIAL_UNALIGNED_BUFFER_SIZE > 0
+ if (flash_area_align(fap) > 1 &&
+ (((size_t)img_chunk) & (flash_area_align(fap) - 1)) != 0) {
+ /* Buffer address incompatible with write address, use buffer to write */
+ uint8_t write_size = MCUBOOT_SERIAL_UNALIGNED_BUFFER_SIZE;
+ uint8_t wbs_aligned[MCUBOOT_SERIAL_UNALIGNED_BUFFER_SIZE];
+
+ while (img_chunk_len >= flash_area_align(fap)) {
+ if (write_size > img_chunk_len) {
+ write_size = img_chunk_len;
+ }
+
+ memset(wbs_aligned, flash_area_erased_val(fap), sizeof(wbs_aligned));
+ memcpy(wbs_aligned, img_chunk, write_size);
+
+ rc = flash_area_write(fap, curr_off, wbs_aligned, write_size);
+
+ if (rc != 0) {
+ goto out;
+ }
+
+ curr_off += write_size;
+ img_chunk += write_size;
+ img_chunk_len -= write_size;
+ }
+ } else {
+ rc = flash_area_write(fap, curr_off, img_chunk, img_chunk_len);
+ }
+#else
rc = flash_area_write(fap, curr_off, img_chunk, img_chunk_len);
+#endif
+
if (rc == 0 && rem_bytes) {
/* Non-zero rem_bytes means that last chunk needs alignment; the aligned
* part, in the img_chunk_len - rem_bytes count bytes, has already been
diff --git a/boot/zephyr/Kconfig.serial_recovery b/boot/zephyr/Kconfig.serial_recovery
index 225c430..336b085 100644
--- a/boot/zephyr/Kconfig.serial_recovery
+++ b/boot/zephyr/Kconfig.serial_recovery
@@ -51,6 +51,14 @@
Note that 0 is default upload target when no explicit
selection is done.
+config BOOT_SERIAL_UNALIGNED_BUFFER_SIZE
+ int "Stack buffer for unaligned memory writes"
+ default 64
+ help
+ Specifies the stack usage for a buffer which is used for unaligned
+ memory access when data is written to a device with memory alignment
+ requirements. Set to 0 to disable.
+
config BOOT_MAX_LINE_INPUT_LEN
int "Maximum input line length"
default 512
diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h
index fbdcddd..1092687 100644
--- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h
+++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h
@@ -245,6 +245,10 @@
#define MCUBOOT_SERIAL_MAX_RECEIVE_SIZE CONFIG_BOOT_SERIAL_MAX_RECEIVE_SIZE
#endif
+#ifdef CONFIG_BOOT_SERIAL_UNALIGNED_BUFFER_SIZE
+#define MCUBOOT_SERIAL_UNALIGNED_BUFFER_SIZE CONFIG_BOOT_SERIAL_UNALIGNED_BUFFER_SIZE
+#endif
+
/* Support 32-byte aligned flash sizes */
#if DT_HAS_CHOSEN(zephyr_flash)
#if DT_PROP_OR(DT_CHOSEN(zephyr_flash), write_block_size, 0) > 8