boot_serial: zephyr: Add optional timeout to enter serial recovery
This PR adds the possibility to only enter the bootloader's
serial recovery mode when a mcumgr command is received within a
given timeout.
Signed-off-by: Wouter Cappelle <wouter.cappelle@crodeon.com>
diff --git a/boot/boot_serial/include/boot_serial/boot_serial.h b/boot/boot_serial/include/boot_serial/boot_serial.h
index 3393213..8c56fe7 100644
--- a/boot/boot_serial/include/boot_serial/boot_serial.h
+++ b/boot/boot_serial/include/boot_serial/boot_serial.h
@@ -43,6 +43,15 @@
*/
void boot_serial_start(const struct boot_uart_funcs *f);
+/**
+ * Start processing newtmgr commands for uploading image0 over serial.
+ * Assumes serial port is open and waits for download command.
+ * This function will return if there is no mcumgr command received within
+ * the given timeout. If a command is received within this timeout, the
+ * function is similar to boot_serial_start
+ */
+void boot_serial_check_start(const struct boot_uart_funcs *f, int timeout_in_ms);
+
#ifdef __cplusplus
}
#endif
diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c
index 7c1d0d9..680cdf0 100644
--- a/boot/boot_serial/src/boot_serial.c
+++ b/boot/boot_serial/src/boot_serial.c
@@ -93,6 +93,7 @@
static uint32_t curr_off;
static uint32_t img_size;
static struct nmgr_hdr *bs_hdr;
+static bool bs_entry;
static char bs_obuf[BOOT_SERIAL_OUT_MAX];
@@ -563,6 +564,9 @@
} else {
bs_rc_rsp(MGMT_ERR_ENOTSUP);
}
+#ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
+ bs_entry = true;
+#endif
}
static void
@@ -678,25 +682,29 @@
* Task which waits reading console, expecting to get image over
* serial port.
*/
-void
-boot_serial_start(const struct boot_uart_funcs *f)
+static void
+boot_serial_read_console(const struct boot_uart_funcs *f,int timeout_in_ms)
{
int rc;
int off;
int dec_off = 0;
int full_line;
int max_input;
+ int elapsed_in_ms = 0;
boot_uf = f;
max_input = sizeof(in_buf);
off = 0;
- while (1) {
+ while (timeout_in_ms > 0 || bs_entry) {
MCUBOOT_CPU_IDLE();
MCUBOOT_WATCHDOG_FEED();
+#ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
+ uint32_t start = k_uptime_get_32();
+#endif
rc = f->read(in_buf + off, sizeof(in_buf) - off, &full_line);
if (rc <= 0 && !full_line) {
- continue;
+ goto check_timeout;
}
off += rc;
if (!full_line) {
@@ -706,7 +714,7 @@
*/
off = 0;
}
- continue;
+ goto check_timeout;
}
if (in_buf[0] == SHELL_NLIP_PKT_START1 &&
in_buf[1] == SHELL_NLIP_PKT_START2) {
@@ -722,5 +730,36 @@
boot_serial_input(&dec_buf[2], dec_off - 2);
}
off = 0;
+check_timeout:
+ /* Subtract elapsed time */
+#ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
+ elapsed_in_ms = (k_uptime_get_32() - start);
+#endif
+ timeout_in_ms -= elapsed_in_ms;
}
}
+
+/*
+ * Task which waits reading console, expecting to get image over
+ * serial port.
+ */
+void
+boot_serial_start(const struct boot_uart_funcs *f)
+{
+ bs_entry = true;
+ boot_serial_read_console(f,0);
+}
+
+#ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
+/*
+ * Task which waits reading console for a certain amount of timeout.
+ * If within this timeout no mcumgr command is received, the function is
+ * returning, else the serial boot is never exited
+ */
+void
+boot_serial_check_start(const struct boot_uart_funcs *f, int timeout_in_ms)
+{
+ bs_entry = false;
+ boot_serial_read_console(f,timeout_in_ms);
+}
+#endif
diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig
index 0d32431..b3a5ac7 100644
--- a/boot/zephyr/Kconfig
+++ b/boot/zephyr/Kconfig
@@ -618,6 +618,21 @@
encryption mechanism used in this case is ECIES using primitives
described under "ECIES-P256 encryption" in docs/encrypted_images.md.
+config BOOT_SERIAL_WAIT_FOR_DFU
+ bool "Wait for a prescribed duration to see if DFU is invoked by receiving a mcumgr comand"
+ depends on BOOT_SERIAL_UART
+ help
+ If y, MCUboot waits for a prescribed duration of time to allow
+ for DFU to be invoked. The serial recovery can be entered by receiving any
+ mcumgr command.
+
+config BOOT_SERIAL_WAIT_FOR_DFU_TIMEOUT
+ int "Duration to wait for the serial DFU timeout in ms"
+ default 500
+ depends on BOOT_SERIAL_WAIT_FOR_DFU
+ help
+ timeout in ms for MCUboot to wait to allow for DFU to be invoked.
+
endif # MCUBOOT_SERIAL
config BOOT_INTR_VEC_RELOC
diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h
index 2539b5f..26d2bcb 100644
--- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h
+++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h
@@ -189,6 +189,10 @@
#define MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD
#endif
+#ifdef CONFIG_BOOT_SERIAL_WAIT_FOR_DFU
+#define MCUBOOT_SERIAL_WAIT_FOR_DFU
+#endif
+
/*
* The option enables code, currently in boot_serial, that attempts
* to erase flash progressively, as update fragments are received,
diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c
index cc726c5..cee7505 100644
--- a/boot/zephyr/main.c
+++ b/boot/zephyr/main.c
@@ -506,7 +506,28 @@
}
#endif
+#ifdef CONFIG_BOOT_SERIAL_WAIT_FOR_DFU
+ /* Initialize the boot console, so we can already fill up our buffers while
+ * waiting for the boot image check to finish. This image check, can take
+ * some time, so it's better to reuse thistime to already receive the
+ * initial mcumgr command(s) into our buffers
+ */
+ rc = boot_console_init();
+ int timeout_in_ms = CONFIG_BOOT_SERIAL_WAIT_FOR_DFU_TIMEOUT;
+ uint32_t start = k_uptime_get_32();
+#endif
+
FIH_CALL(boot_go, fih_rc, &rsp);
+
+#ifdef CONFIG_BOOT_SERIAL_WAIT_FOR_DFU
+ timeout_in_ms -= (k_uptime_get_32() - start);
+ if( timeout_in_ms <= 0 ) {
+ /* at least one check if time was expired */
+ timeout_in_ms = 1;
+ }
+ boot_serial_check_start(&boot_funcs,timeout_in_ms);
+#endif
+
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
BOOT_LOG_ERR("Unable to find bootable image");
FIH_PANIC;