boot: zephyr: serial_recovery: Add boot mode enter ability
Adds an optional entrance method for mcuboot's serial recovery by
using Zephyr's boot mode retention system, this allows for an
application to set the retained data and reboot into the bootloader.
This also adds a selection of how to enter serial recovery mode, it
no longer requires having a GPIO entrance mechanism. Entrance
methods have been added under a new Kconfig menu.
Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
diff --git a/boot/zephyr/Kconfig.serial_recovery b/boot/zephyr/Kconfig.serial_recovery
index d5c0101..5285e98 100644
--- a/boot/zephyr/Kconfig.serial_recovery
+++ b/boot/zephyr/Kconfig.serial_recovery
@@ -1,15 +1,13 @@
# Copyright (c) 2017-2020 Linaro Limited
# Copyright (c) 2020 Arm Limited
-# Copyright (c) 2017-2022 Nordic Semiconductor ASA
+# Copyright (c) 2017-2023 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
-
menuconfig MCUBOOT_SERIAL
bool "MCUboot serial recovery"
default n
select REBOOT
- select GPIO
select SERIAL
select UART_INTERRUPT_DRIVEN
select BASE64
@@ -96,14 +94,6 @@
by the number of receive buffers, BOOT_LINE_BUFS to allow for
optimal data transfer speeds).
-config BOOT_SERIAL_DETECT_DELAY
- int "Serial detect pin detection delay time [ms]"
- default 0
- help
- Used to prevent the bootloader from loading on button press.
- Useful for powering on when using the same button as
- the one used to place the device in bootloader mode.
-
config BOOT_ERASE_PROGRESSIVELY
bool "Erase flash progressively when receiving new firmware"
default y if SOC_FAMILY_NRF
@@ -128,6 +118,7 @@
function is required to process these commands.
if ENABLE_MGMT_PERUSER
+
config BOOT_MGMT_CUSTOM_STORAGE_ERASE
bool "Enable storage erase command"
help
@@ -153,8 +144,26 @@
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"
+menu "Entrance methods"
+
+menuconfig BOOT_SERIAL_ENTRANCE_GPIO
+ bool "GPIO"
+ default y
+ depends on GPIO
+ help
+ Use a GPIO to enter serial recovery mode.
+
+config BOOT_SERIAL_DETECT_DELAY
+ int "Serial detect pin detection delay time [ms]"
+ default 0
+ depends on BOOT_SERIAL_ENTRANCE_GPIO
+ help
+ Used to prevent the bootloader from loading on button press.
+ Useful for powering on when using the same button as
+ the one used to place the device in bootloader mode.
+
+menuconfig BOOT_SERIAL_WAIT_FOR_DFU
+ bool "Wait a prescribed duration to see if DFU is invoked by receiving a MCUmgr comand"
depends on BOOT_SERIAL_UART || BOOT_SERIAL_CDC_ACM
help
If y, MCUboot waits for a prescribed duration of time to allow
@@ -166,7 +175,17 @@
default 500
depends on BOOT_SERIAL_WAIT_FOR_DFU
help
- timeout in ms for MCUboot to wait to allow for DFU to be invoked.
+ Timeout in ms for MCUboot to wait to allow for DFU to be invoked.
+
+config BOOT_SERIAL_BOOT_MODE
+ bool "Check boot mode via retention subsystem"
+ depends on RETENTION_BOOT_MODE
+ help
+ Allows for entering serial recovery mode by using Zephyr's boot mode
+ retention system (i.e. an application must set the boot mode to stay
+ in serial recovery mode and reboot the module).
+
+endmenu
config BOOT_SERIAL_IMG_GRP_HASH
bool "Image list hash support"
diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c
index 5412796..8c2b98e 100644
--- a/boot/zephyr/main.c
+++ b/boot/zephyr/main.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
* Copyright (c) 2020 Arm Limited
- * Copyright (c) 2021 Nordic Semiconductor ASA
+ * Copyright (c) 2021-2023 Nordic Semiconductor ASA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,6 +52,10 @@
};
#endif
+#ifdef CONFIG_BOOT_SERIAL_BOOT_MODE
+#include <zephyr/retention/bootmode.h>
+#endif
+
#if defined(CONFIG_BOOT_USB_DFU_WAIT) || defined(CONFIG_BOOT_USB_DFU_GPIO)
#include <zephyr/usb/class/usb_dfu.h>
#endif
@@ -120,6 +124,15 @@
BOOT_LOG_MODULE_REGISTER(mcuboot);
+/* Validate serial recovery configuration */
+#ifdef CONFIG_MCUBOOT_SERIAL
+#if !defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) && \
+ !defined(CONFIG_BOOT_SERIAL_WAIT_FOR_DFU) && \
+ !defined(CONFIG_BOOT_SERIAL_BOOT_MODE)
+#error "Serial recovery selected without an entrance mode set"
+#endif
+#endif
+
#ifdef CONFIG_MCUBOOT_INDICATION_LED
/*
@@ -385,7 +398,7 @@
* !defined(CONFIG_LOG_PROCESS_THREAD) && !defined(ZEPHYR_LOG_MODE_MINIMAL)
*/
-#if defined(CONFIG_MCUBOOT_SERIAL) || defined(CONFIG_BOOT_USB_DFU_GPIO)
+#if defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) || defined(CONFIG_BOOT_USB_DFU_GPIO)
#ifdef CONFIG_MCUBOOT_SERIAL
#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_SERIAL_DETECT_DELAY
@@ -393,17 +406,12 @@
#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_USB_DFU_DETECT_DELAY
#endif
-
#define BUTTON_0_NODE DT_ALIAS(mcuboot_button0)
#if DT_NODE_EXISTS(BUTTON_0_NODE) && DT_NODE_HAS_PROP(BUTTON_0_NODE, gpios)
-
static const struct gpio_dt_spec button0 = GPIO_DT_SPEC_GET(BUTTON_0_NODE, gpios);
-
-#elif defined(CONFIG_MCUBOOT_SERIAL) || defined(CONFIG_BOOT_USB_DFU_GPIO)
-
+#else
#error "Serial recovery/USB DFU button must be declared in device tree as 'mcuboot_button0'"
-
#endif
static bool detect_pin(void)
@@ -468,6 +476,10 @@
int rc;
FIH_DECLARE(fih_rc, FIH_FAILURE);
+#ifdef CONFIG_BOOT_SERIAL_BOOT_MODE
+ int32_t boot_mode;
+#endif
+
MCUBOOT_WATCHDOG_FEED();
#if !defined(MCUBOOT_DIRECT_XIP)
@@ -489,7 +501,7 @@
mcuboot_status_change(MCUBOOT_STATUS_STARTUP);
-#ifdef CONFIG_MCUBOOT_SERIAL
+#ifdef CONFIG_BOOT_SERIAL_ENTRANCE_GPIO
if (detect_pin() &&
!boot_skip_serial_recovery()) {
#ifdef CONFIG_MCUBOOT_INDICATION_LED
@@ -552,6 +564,24 @@
FIH_CALL(boot_go, fih_rc, &rsp);
+#ifdef CONFIG_BOOT_SERIAL_BOOT_MODE
+ boot_mode = bootmode_check(BOOT_MODE_TYPE_BOOTLOADER);
+
+ if (boot_mode == 1) {
+ /* Boot mode to stay in bootloader, clear status and enter serial
+ * recovery mode
+ */
+#ifdef CONFIG_MCUBOOT_INDICATION_LED
+ gpio_pin_set_dt(&led0, 1);
+#endif
+
+ mcuboot_status_change(MCUBOOT_STATUS_SERIAL_DFU_ENTERED);
+ rc = boot_console_init();
+ bootmode_clear();
+ boot_serial_start(&boot_funcs);
+ }
+#endif
+
#ifdef CONFIG_BOOT_SERIAL_WAIT_FOR_DFU
timeout_in_ms -= (k_uptime_get_32() - start);
if( timeout_in_ms <= 0 ) {