Commit b3e3ce39 authored by Jamie McCrae's avatar Jamie McCrae Committed by Dominik Ermel
Browse files

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: default avatarJamie McCrae <jamie.mccrae@nordicsemi.no>
parent e5c57dd1
Loading
Loading
Loading
Loading
+33 −14
Original line number Diff line number Diff line
# 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 @@ 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
@@ -128,6 +118,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
@@ -153,8 +144,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
@@ -166,7 +175,17 @@ 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).

endmenu

config BOOT_SERIAL_IMG_GRP_HASH
	bool "Image list hash support"
+39 −9
Original line number Diff line number Diff line
/*
 * 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 <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 @@ 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)
#error "Serial recovery selected without an entrance mode set"
#endif
#endif

#ifdef CONFIG_MCUBOOT_INDICATION_LED

/*
@@ -385,7 +398,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 +406,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)
@@ -468,6 +476,10 @@ void main(void)
    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 @@ 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
@@ -552,6 +564,24 @@ 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
         */
#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 ) {