diff --git a/boot/zephyr/Kconfig.serial_recovery b/boot/zephyr/Kconfig.serial_recovery index b48ee9b5ef..fe211dc881 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 @@ -85,14 +83,6 @@ config BOOT_SERIAL_MAX_RECEIVE_SIZE 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 @@ -117,6 +107,7 @@ menuconfig ENABLE_MGMT_PERUSER function is required to process these commands. if ENABLE_MGMT_PERUSER + config BOOT_MGMT_CUSTOM_STORAGE_ERASE bool "Enable storage erase command" help @@ -142,8 +133,26 @@ 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" +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 @@ -155,6 +164,29 @@ config BOOT_SERIAL_WAIT_FOR_DFU_TIMEOUT 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). + +config BOOT_SERIAL_NO_APPLICATION + bool "Stay in bootloader if no application" + help + Allows for entering serial recovery mode if there is no bootable + application that the bootloader can jump to. + +config BOOT_SERIAL_PIN_RESET + bool "Check for device reset by pin" + select HWINFO + help + Checks if the module reset was caused by the reset pin and will + remain in bootloader serial recovery mode if it was. + +endmenu endif # MCUBOOT_SERIAL diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 541279602d..2deef1ef65 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 @@ const struct boot_uart_funcs boot_funcs = { }; #endif +#ifdef CONFIG_BOOT_SERIAL_BOOT_MODE +#include +#endif + #if defined(CONFIG_BOOT_USB_DFU_WAIT) || defined(CONFIG_BOOT_USB_DFU_GPIO) #include #endif @@ -60,6 +64,10 @@ const struct boot_uart_funcs boot_funcs = { #include #endif +#ifdef CONFIG_BOOT_SERIAL_PIN_RESET +#include +#endif + /* CONFIG_LOG_MINIMAL is the legacy Kconfig property, * replaced by CONFIG_LOG_MODE_MINIMAL. */ @@ -120,6 +128,17 @@ static inline bool boot_skip_serial_recovery() 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) && \ + !defined(CONFIG_BOOT_SERIAL_NO_APPLICATION) && \ + !defined(CONFIG_BOOT_SERIAL_PIN_RESET) +#error "Serial recovery selected without an entrance mode set" +#endif +#endif + #ifdef CONFIG_MCUBOOT_INDICATION_LED /* @@ -385,7 +404,7 @@ void zephyr_boot_log_stop(void) * !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 +412,12 @@ void zephyr_boot_log_stop(void) #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) @@ -462,12 +476,39 @@ static bool detect_pin(void) } #endif +#ifdef CONFIG_MCUBOOT_SERIAL +static void boot_serial_enter() +{ + int rc; + +#ifdef CONFIG_MCUBOOT_INDICATION_LED + gpio_pin_set_dt(&led0, 1); +#endif + + mcuboot_status_change(MCUBOOT_STATUS_SERIAL_DFU_ENTERED); + + BOOT_LOG_INF("Enter the serial recovery mode"); + rc = boot_console_init(); + __ASSERT(rc == 0, "Error initializing boot console.\n"); + boot_serial_start(&boot_funcs); + __ASSERT(0, "Bootloader serial process was terminated unexpectedly.\n"); +} +#endif + void main(void) { struct boot_rsp rsp; int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); +#ifdef CONFIG_BOOT_SERIAL_BOOT_MODE + int32_t boot_mode; +#endif + +#ifdef CONFIG_BOOT_SERIAL_PIN_RESET + uint32_t reset_cause; +#endif + MCUBOOT_WATCHDOG_FEED(); #if !defined(MCUBOOT_DIRECT_XIP) @@ -489,20 +530,19 @@ void main(void) 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 - gpio_pin_set_dt(&led0, 1); + boot_serial_enter(); + } #endif - mcuboot_status_change(MCUBOOT_STATUS_SERIAL_DFU_ENTERED); +#ifdef CONFIG_BOOT_SERIAL_PIN_RESET + rc = hwinfo_get_reset_cause(&reset_cause); - BOOT_LOG_INF("Enter the serial recovery mode"); - rc = boot_console_init(); - __ASSERT(rc == 0, "Error initializing boot console.\n"); - boot_serial_start(&boot_funcs); - __ASSERT(0, "Bootloader serial process was terminated unexpectedly.\n"); + if (rc == 0 && reset_cause == RESET_PIN) { + (void)hwinfo_clear_reset_cause(); + boot_serial_enter(); } #endif @@ -552,6 +592,18 @@ void main(void) 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 + */ + bootmode_clear(); + boot_serial_enter(); + } +#endif + #ifdef CONFIG_BOOT_SERIAL_WAIT_FOR_DFU timeout_in_ms -= (k_uptime_get_32() - start); if( timeout_in_ms <= 0 ) { @@ -566,6 +618,13 @@ void main(void) mcuboot_status_change(MCUBOOT_STATUS_NO_BOOTABLE_IMAGE_FOUND); +#ifdef CONFIG_BOOT_SERIAL_NO_APPLICATION + /* No bootable image and configuration set to remain in serial + * recovery mode + */ + boot_serial_enter(); +#endif + FIH_PANIC; }