Commit e3822f81 authored by Wouter Cappelle's avatar Wouter Cappelle Committed by David Brown
Browse files

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: default avatarWouter Cappelle <wouter.cappelle@crodeon.com>
parent c028d450
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -43,6 +43,15 @@ struct boot_uart_funcs {
 */
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
+44 −5
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ const struct boot_uart_funcs *boot_uf;
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 @@ boot_serial_input(char *buf, int len)
    } else {
        bs_rc_rsp(MGMT_ERR_ENOTSUP);
    }
#ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU
    bs_entry = true;
#endif
}

static void
@@ -678,25 +682,29 @@ boot_serial_in_dec(char *in, int inlen, char *out, int *out_off, int maxout)
 * 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 @@ boot_serial_start(const struct boot_uart_funcs *f)
                 */
                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_start(const struct boot_uart_funcs *f)
            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
+15 −0
Original line number Diff line number Diff line
@@ -618,6 +618,21 @@ config BOOT_SERIAL_ENCRYPT_EC256
	  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
+4 −0
Original line number Diff line number Diff line
@@ -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,
+21 −0
Original line number Diff line number Diff line
@@ -506,7 +506,28 @@ void main(void)
    }
#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;