summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian J. Nemec <bnemec@google.com>2022-02-07 09:24:37 -0800
committerCommit Bot <commit-bot@chromium.org>2022-02-15 21:31:20 +0000
commit3027a7553e51785be1395af10b9545aa1a32ff99 (patch)
tree8eeddf54e82ccc19d3fb4ec6bec2ca5b17f2656d
parent0f6242e8bd99e0b1fe4d2f15e95bf48eb7daa516 (diff)
downloadchrome-ec-3027a7553e51785be1395af10b9545aa1a32ff99.tar.gz
stm32: Add the DFU Boot Manager
Added the DFU Boot Manager to control the switch between the DFU and main application region. The DFU Bootmanager performs self checks when the application boots. If any of the following conditions are true it will jump into DFU: * The system backup registers contain a 'Jump to DFU' request. * The start of the RW region is erased indicating the prior firmware update has failed. * An optional check can be enabled to record the number of consecutive unexpected reboots which will be useful for developer test images to avoid locked systems. Testing requires enabling multiple configuration settings set in the follower CL which enables it on Servo_v4. dfu-util version 0.9 lacks the 'leave' parameter required to automatically jump out, systems using this would need to be power cycled to leave DFU. BRANCH=servo BUG=b:217955677 TEST=Enabled the DFU configuration on a Servo_v4. Verified that the runtime identifier is correctly recognized by dfu-util and pydfu.py implementations of the DFU host protocol. Verified firmware updates via the DFU protocol function correctly. TEST=sudo dfu-util -a 0 -s 0x08000000:leave -e -D ec.bin Verified that dfu-util can program the application region. Signed-off-by: Brian Nemec <bnemec@chromium.org> Change-Id: Ie535efc91318244574949542c03efa0b5973cbe5 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3443960 Tested-by: Brian Nemec <bnemec@google.com> Reviewed-by: Sam Hurst <shurst@google.com> Commit-Queue: Brian Nemec <bnemec@google.com>
-rw-r--r--Makefile4
-rw-r--r--chip/stm32/build.mk2
-rw-r--r--chip/stm32/config-stm32f07x.h3
-rw-r--r--chip/stm32/config-stm32f373.h3
-rw-r--r--chip/stm32/config-stm32f4.h3
-rw-r--r--chip/stm32/config-stm32f76x.h3
-rw-r--r--chip/stm32/config-stm32g41xb.h3
-rw-r--r--chip/stm32/config-stm32g473xc.h3
-rw-r--r--chip/stm32/config-stm32h7x3.h3
-rw-r--r--chip/stm32/config-stm32l100.h3
-rw-r--r--chip/stm32/config-stm32l15x.h3
-rw-r--r--chip/stm32/config-stm32l431.h3
-rw-r--r--chip/stm32/config-stm32l442.h3
-rw-r--r--chip/stm32/config-stm32l476.h3
-rw-r--r--chip/stm32/config-stm32l552xe.h3
-rw-r--r--chip/stm32/dfu_bootmanager_main.c181
-rw-r--r--chip/stm32/dfu_bootmanager_shared.c52
-rw-r--r--chip/stm32/dfu_bootmanager_shared.h62
-rw-r--r--chip/stm32/usb_dfu_runtime.c3
-rw-r--r--common/build.mk2
-rw-r--r--include/config.h18
-rw-r--r--include/task.h2
-rw-r--r--util/config_allowed.txt3
23 files changed, 366 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index e0aff80f67..43712434a3 100644
--- a/Makefile
+++ b/Makefile
@@ -212,7 +212,8 @@ _mock_cfg := $(foreach t,$(_mock_lst) ,HAS_MOCK_$(t))
CPPFLAGS += $(foreach t,$(_mock_cfg),-D$(t)=$(EMPTY))
$(foreach c,$(_mock_cfg),$(eval $(c)=y))
-ifneq "$(CONFIG_COMMON_RUNTIME)" "y"
+ifneq ($(CONFIG_COMMON_RUNTIME),y)
+ifneq ($(CONFIG_DFU_BOOTMANAGER_MAIN),ro)
_irq_list:=$(shell $(CPP) $(CPPFLAGS) -P -Ichip/$(CHIP) -I$(BASEDIR) \
-I$(BDIR) -D"ENABLE_IRQ(x)=EN_IRQ x" \
-imacros chip/$(CHIP)/registers.h \
@@ -220,6 +221,7 @@ ifneq "$(CONFIG_COMMON_RUNTIME)" "y"
CPPFLAGS+=$(foreach irq,$(_irq_list),\
-D"irq_$(irq)_handler_optional=irq_$(irq)_handler")
endif
+endif
# Compute RW firmware size and offset
_rw_off_str:=$(shell echo "CONFIG_RW_MEM_OFF" | $(CPP) $(CPPFLAGS) -P \
diff --git a/chip/stm32/build.mk b/chip/stm32/build.mk
index 3990b8d4d7..5eefc00d4f 100644
--- a/chip/stm32/build.mk
+++ b/chip/stm32/build.mk
@@ -81,6 +81,8 @@ chip-$(CHIP_FAMILY_STM32F3)+=flash-f.o
chip-$(CHIP_FAMILY_STM32F4)+=flash-f.o
endif
chip-$(CONFIG_ADC)+=adc-$(CHIP_FAMILY).o
+chip-$(CONFIG_DFU_BOOTMANAGER_MAIN)+=dfu_bootmanager_main.o
+chip-$(CONFIG_DFU_BOOTMANAGER_SHARED)+=dfu_bootmanager_shared.o
chip-$(CONFIG_DFU_RUNTIME)+=usb_dfu_runtime.o
chip-$(CONFIG_STM32_CHARGER_DETECT)+=charger_detect.o
chip-$(CONFIG_DEBUG_PRINTF)+=debug_printf.o
diff --git a/chip/stm32/config-stm32f07x.h b/chip/stm32/config-stm32f07x.h
index 918a117a22..2aa8f6d37d 100644
--- a/chip/stm32/config-stm32f07x.h
+++ b/chip/stm32/config-stm32f07x.h
@@ -27,3 +27,6 @@
#define CONFIG_USB_RAM_SIZE 1024
#define CONFIG_USB_RAM_ACCESS_TYPE uint16_t
#define CONFIG_USB_RAM_ACCESS_SIZE 2
+
+/* DFU Address */
+#define STM32_DFU_BASE 0x1fffC800
diff --git a/chip/stm32/config-stm32f373.h b/chip/stm32/config-stm32f373.h
index 3df5bfce67..7694db4421 100644
--- a/chip/stm32/config-stm32f373.h
+++ b/chip/stm32/config-stm32f373.h
@@ -23,3 +23,6 @@
#define CONFIG_USB_RAM_SIZE 512
#define CONFIG_USB_RAM_ACCESS_TYPE uint32_t
#define CONFIG_USB_RAM_ACCESS_SIZE 4
+
+/* DFU Address */
+#define STM32_DFU_BASE 0x1fffd800
diff --git a/chip/stm32/config-stm32f4.h b/chip/stm32/config-stm32f4.h
index 73c9a3694f..46303444fc 100644
--- a/chip/stm32/config-stm32f4.h
+++ b/chip/stm32/config-stm32f4.h
@@ -70,3 +70,6 @@
#define CONFIG_IRQ_COUNT 97
#undef CONFIG_CMD_CHARGEN
+
+/* DFU Address */
+#define STM32_DFU_BASE 0x1fff0000
diff --git a/chip/stm32/config-stm32f76x.h b/chip/stm32/config-stm32f76x.h
index d027ad62fb..aa7f7ac5c0 100644
--- a/chip/stm32/config-stm32f76x.h
+++ b/chip/stm32/config-stm32f76x.h
@@ -58,3 +58,6 @@
/* Number of IRQ vectors on the NVIC */
#define CONFIG_IRQ_COUNT 109
+
+/* DFU Address */
+#define STM32_DFU_BASE 0x1ff00000
diff --git a/chip/stm32/config-stm32g41xb.h b/chip/stm32/config-stm32g41xb.h
index 4f1ed96871..d6ec8696fb 100644
--- a/chip/stm32/config-stm32g41xb.h
+++ b/chip/stm32/config-stm32g41xb.h
@@ -58,3 +58,6 @@
#define CONFIG_USB_RAM_SIZE 1024
#define CONFIG_USB_RAM_ACCESS_TYPE uint16_t
#define CONFIG_USB_RAM_ACCESS_SIZE 2
+
+/* DFU Address */
+#define STM32_DFU_BASE 0x1fff0000
diff --git a/chip/stm32/config-stm32g473xc.h b/chip/stm32/config-stm32g473xc.h
index 1cb5133121..0317b69491 100644
--- a/chip/stm32/config-stm32g473xc.h
+++ b/chip/stm32/config-stm32g473xc.h
@@ -63,3 +63,6 @@
#define CONFIG_USB_RAM_SIZE 1024
#define CONFIG_USB_RAM_ACCESS_TYPE uint16_t
#define CONFIG_USB_RAM_ACCESS_SIZE 2
+
+/* DFU Address */
+#define STM32_DFU_BASE 0x1fff0000
diff --git a/chip/stm32/config-stm32h7x3.h b/chip/stm32/config-stm32h7x3.h
index da94b09069..11da24b849 100644
--- a/chip/stm32/config-stm32h7x3.h
+++ b/chip/stm32/config-stm32h7x3.h
@@ -71,3 +71,6 @@
#define MPU_ATTR_FLASH_MEMORY 0x02
/* SRAM Data is Normal memory type / non-shareable / write-back, write-alloc */
#define MPU_ATTR_INTERNAL_SRAM 0x0B
+
+/* DFU Address */
+#define STM32_DFU_BASE 0x1ff00000
diff --git a/chip/stm32/config-stm32l100.h b/chip/stm32/config-stm32l100.h
index 2c4efcc6df..2132fab4dd 100644
--- a/chip/stm32/config-stm32l100.h
+++ b/chip/stm32/config-stm32l100.h
@@ -41,3 +41,6 @@
#define CONFIG_USB_RAM_SIZE 512
#define CONFIG_USB_RAM_ACCESS_TYPE uint32_t
#define CONFIG_USB_RAM_ACCESS_SIZE 4
+
+/* DFU Address */
+#define STM32_DFU_BASE 0x1ff00000
diff --git a/chip/stm32/config-stm32l15x.h b/chip/stm32/config-stm32l15x.h
index 0b32f95572..9f957d8981 100644
--- a/chip/stm32/config-stm32l15x.h
+++ b/chip/stm32/config-stm32l15x.h
@@ -42,3 +42,6 @@
#define CONFIG_USB_RAM_SIZE 512
#define CONFIG_USB_RAM_ACCESS_TYPE uint32_t
#define CONFIG_USB_RAM_ACCESS_SIZE 4
+
+/* DFU Address */
+#define STM32_DFU_BASE 0x1ff00000
diff --git a/chip/stm32/config-stm32l431.h b/chip/stm32/config-stm32l431.h
index 7021bc2ce8..64d8d39327 100644
--- a/chip/stm32/config-stm32l431.h
+++ b/chip/stm32/config-stm32l431.h
@@ -75,3 +75,6 @@
#define WP_BANK_COUNT 63
#define PSTATE_BANK 62
#define PSTATE_BANK_COUNT 1
+
+/* DFU Address */
+#define STM32_DFU_BASE 0x1fff0000
diff --git a/chip/stm32/config-stm32l442.h b/chip/stm32/config-stm32l442.h
index 54ba9bac8d..8a2a284d69 100644
--- a/chip/stm32/config-stm32l442.h
+++ b/chip/stm32/config-stm32l442.h
@@ -22,3 +22,6 @@
/* Number of IRQ vectors on the NVIC */
#define CONFIG_IRQ_COUNT 82
+
+/* DFU Address */
+#define STM32_DFU_BASE 0x1fff0000
diff --git a/chip/stm32/config-stm32l476.h b/chip/stm32/config-stm32l476.h
index 2e0084fd94..7f6fbb0f84 100644
--- a/chip/stm32/config-stm32l476.h
+++ b/chip/stm32/config-stm32l476.h
@@ -18,3 +18,6 @@
/* Number of IRQ vectors on the NVIC */
#define CONFIG_IRQ_COUNT 82
+
+/* DFU Address */
+#define STM32_DFU_BASE 0x1fff0000
diff --git a/chip/stm32/config-stm32l552xe.h b/chip/stm32/config-stm32l552xe.h
index dab0400775..1b9c34c4aa 100644
--- a/chip/stm32/config-stm32l552xe.h
+++ b/chip/stm32/config-stm32l552xe.h
@@ -34,3 +34,6 @@
/* Number of DMA channels supported (8 channels each for DMA1 and DMA2) */
#define DMAC_COUNT 16
+
+/* DFU Address */
+#define STM32_DFU_BASE 0x0bf90000
diff --git a/chip/stm32/dfu_bootmanager_main.c b/chip/stm32/dfu_bootmanager_main.c
new file mode 100644
index 0000000000..462dd08b60
--- /dev/null
+++ b/chip/stm32/dfu_bootmanager_main.c
@@ -0,0 +1,181 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * DFU Boot Manager Main for STM32
+ *
+ * When the Boot Manager Main is enabled, the RO application skips the
+ * common runtime and setup. This reduces the flash size and avoids clock,
+ * interrupt, and setup steps which conflict with the built in Boot Loaders
+ * while minimizing the Flash Size.
+ *
+ * The Boot Manager Main will perform self checks of the Flash and backup
+ * memory. Based on these results it will boot into the DFU or RW Application.
+ */
+
+#include "clock.h"
+#include "dfu_bootmanager_shared.h"
+#include "flash.h"
+#include "registers.h"
+#include "task.h"
+
+#ifdef CONFIG_DFU_BOOTMANAGER_MAX_REBOOT_COUNT
+#if CONFIG_DFU_BOOTMANAGER_MAX_REBOOT_COUNT <= 0 || \
+ CONFIG_DFU_BOOTMANAGER_MAX_REBOOT_COUNT > DFU_BOOTMANAGER_VALUE_DFU
+#error "Max reboot count is out of range"
+#endif
+#endif /* CONFIG_DFU_BOOTMANAGER_MAX_REBOOT_COUNT */
+
+/*
+ * Checks if the RW region is valid by reading the first 8 bytes of flash, it
+ * should not start with an erased block.
+ *
+ * The DFU boot manager should not jump into the RW region if it contains
+ * invalid code as the EC is be unstable. A check will be performed to validate
+ * the start of the RW region to verify that it contains valid data.
+ * DFU programmers should erase this section of flash first and at this point,
+ * the EC will no longer be able to jump into the RW application.
+ *
+ * The normal DFU programming sequence programming will work, but by
+ * splitting into the following sequence we can protect against additional
+ * failures.
+ *
+ * 1. Erase the first RW flash section. This will lock the EC out of RW.
+ * 2. Update the remaining flash. Erase, program, and read back flash to
+ * to verify the operation was successful. Regions of the flash which
+ * are difficult to repair if an error occurs should be programmed next.
+ * 3. Program the first RW flash section and exit DFU mode if verification is
+ * successful.
+ *
+ * @return 1 if erased, 0 if not erased
+ */
+static int rw_is_empty(void)
+{
+ return crec_flash_is_erased(CONFIG_RW_MEM_OFF, 8);
+}
+
+/*
+ * Reads the backup registers. This will trigger a jump to DFU if either
+ * the application has requested it or if the reboot counter indicates
+ * the device is likely in a bad state. A counter recording the number
+ * of reboots will be incremented.
+ *
+ * @returns True if the backup memory region indicates we should boot into DFU.
+ */
+static bool backup_boot_checks(void)
+{
+ uint8_t value;
+
+ if (dfu_bootmanager_backup_read(&value)) {
+ /* Value stored is not valid, set it to a valid value. */
+ dfu_bootmanager_backup_write(DFU_BOOTMANAGER_VALUE_CLEAR);
+ return false;
+ }
+ if (value == DFU_BOOTMANAGER_VALUE_DFU)
+ return true;
+#ifdef CONFIG_DFU_BOOTMANAGER_MAX_REBOOT_COUNT
+ if (value >= CONFIG_DFU_BOOTMANAGER_MAX_REBOOT_COUNT)
+ return true;
+ /* Increment the reboot loop counter. */
+ value++;
+ dfu_bootmanager_backup_write(value);
+#endif /* CONFIG_DFU_BOOTMANAGER_MAX_REBOOT_COUNT */
+ return false;
+}
+
+/*
+ * Performs the minimal set of initialization required for the boot manager.
+ * The main application region or DFU boot loader have different prerequisites,
+ * any configurations that are enabled either need to be benign with both
+ * images or disabled prior to the jumps.
+ */
+static void dfu_bootmanager_init(void)
+{
+ /* enable clock on Power module */
+#ifndef CHIP_FAMILY_STM32H7
+#ifdef CHIP_FAMILY_STM32L4
+ STM32_RCC_APB1ENR1 |= STM32_RCC_PWREN;
+#else
+ STM32_RCC_APB1ENR |= STM32_RCC_PWREN;
+#endif
+#endif
+#if defined(CHIP_FAMILY_STM32F4)
+ /* enable backup registers */
+ STM32_RCC_AHB1ENR |= STM32_RCC_AHB1ENR_BKPSRAMEN;
+#elif defined(CHIP_FAMILY_STM32H7)
+ /* enable backup registers */
+ STM32_RCC_AHB4ENR |= BIT(28);
+#elif defined(CHIP_FAMILY_STM32L4)
+ /* enable RTC APB clock */
+ STM32_RCC_APB1ENR1 |= STM32_RCC_APB1ENR1_RTCAPBEN;
+#else
+ /* enable backup registers */
+ STM32_RCC_APB1ENR |= BIT(27);
+#endif
+ /* Delay 1 APB clock cycle after the clock is enabled */
+ clock_wait_bus_cycles(BUS_APB, 1);
+ /* Enable access to RCC CSR register and RTC backup registers */
+ STM32_PWR_CR |= BIT(8);
+}
+
+static void jump_to_rw(void)
+{
+ void (*addr)(void);
+
+ addr = (void (*)(void)) (*((uint32_t *) (CONFIG_PROGRAM_MEMORY_BASE +
+ CONFIG_RW_MEM_OFF + 4)));
+
+ addr();
+}
+
+static void jump_to_dfu(void)
+{
+ void (*addr)(void);
+
+ addr = (void (*)(void)) (*((uint32_t *) (STM32_DFU_BASE + 4)));
+
+ /* Clear the scratchpad. */
+ dfu_bootmanager_backup_write(DFU_BOOTMANAGER_VALUE_CLEAR);
+ addr();
+}
+
+/*
+ * DFU Boot Manager main. It'll check if the RW region is not fully programmed
+ * or if the backup memory indicates we should reboot into DFU.
+ */
+int main(void)
+{
+ dfu_bootmanager_init();
+
+ if (rw_is_empty() || backup_boot_checks())
+ jump_to_dfu();
+ jump_to_rw();
+
+ return 0;
+}
+
+/*
+ * The RW application will replace the vector table and exception handlers
+ * shortly after the jump. If the application is corrupt and fails before
+ * this, the only action that can be done is jumping into DFU mode.
+ */
+void exception_panic(void)
+{
+ dfu_bootmanager_enter_dfu();
+}
+
+/*
+ * Function stubs which are required by bkpdata.c and system.c:
+ * Interrupts are always disabled in the Boot Manager so we do not
+ * need to worry about concurrent access.
+ */
+
+void task_clear_pending_irq(int irq) {}
+void interrupt_disable(void) {}
+void mutex_lock(mutex_t *mtx) {}
+void mutex_unlock(mutex_t *mtx) {}
+
+bool in_interrupt_context(void)
+{
+ return false;
+}
diff --git a/chip/stm32/dfu_bootmanager_shared.c b/chip/stm32/dfu_bootmanager_shared.c
new file mode 100644
index 0000000000..212ee0a9e9
--- /dev/null
+++ b/chip/stm32/dfu_bootmanager_shared.c
@@ -0,0 +1,52 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * DFU Boot Manager shared utilities for STM32
+ */
+
+#include "bkpdata.h"
+#include "clock.h"
+#include "dfu_bootmanager_shared.h"
+#include "flash.h"
+#include "registers.h"
+#include "task.h"
+
+/*
+ * The Servo platforms do not have any free backup regions. The scratchpad
+ * is only with the console command scratchpad and on some of the tests so
+ * we'll use the scratchpad region.
+ */
+#ifdef CONFIG_CMD_SCRATCHPAD
+#error "The scratchpad is used, define a backup region for the DFU fields."
+#endif /* CONFIG_CMD_SCRATCHPAD */
+
+int dfu_bootmanager_enter_dfu(void)
+{
+ dfu_bootmanager_backup_write(DFU_BOOTMANAGER_VALUE_DFU);
+ system_reset(0);
+ return 0;
+}
+
+void dfu_bootmanager_clear(void)
+{
+ dfu_bootmanager_backup_write(DFU_BOOTMANAGER_VALUE_CLEAR);
+}
+
+void dfu_bootmanager_backup_write(uint8_t value)
+{
+ uint16_t data = DFU_BOOTMANAGER_VALID_CHECK | value;
+
+ bkpdata_write(BKPDATA_INDEX_SCRATCHPAD, data);
+}
+
+int dfu_bootmanager_backup_read(uint8_t *value)
+{
+ uint16_t data = bkpdata_read(BKPDATA_INDEX_SCRATCHPAD);
+ uint16_t valid_check = data & DFU_BOOTMANAGER_VALID_MASK;
+
+ *value = (uint8_t)(data & DFU_BOOTMANAGER_VALUE_MASK);
+ if (valid_check != DFU_BOOTMANAGER_VALID_CHECK)
+ return EC_ERROR_UNKNOWN;
+ return EC_SUCCESS;
+}
diff --git a/chip/stm32/dfu_bootmanager_shared.h b/chip/stm32/dfu_bootmanager_shared.h
new file mode 100644
index 0000000000..4003583ee2
--- /dev/null
+++ b/chip/stm32/dfu_bootmanager_shared.h
@@ -0,0 +1,62 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * DFU Boot Manager shared utilities for STM32
+ *
+ * These of utilities required by the Boot Manager Main and RW Application.
+ * These allow the systems to start the sequence to enter DFU, clear the
+ * state, and access the backup registers.
+ */
+
+#ifndef __DFU_BOOTMANAGER_SHARED_H
+#define __DFU_BOOTMANAGER_SHARED_H
+
+#include "common.h"
+
+/* Registers to validate the backup memory region. */
+#define DFU_BOOTMANAGER_VALUE_MASK 0x00FF
+#define DFU_BOOTMANAGER_VALID_MASK 0xFF00
+#define DFU_BOOTMANAGER_VALID_CHECK 0xAA00
+
+#define DFU_BOOTMANAGER_VALUE_CLEAR 0
+#define DFU_BOOTMANAGER_VALUE_DFU UINT8_MAX
+
+/*
+ * Reset and enter the DFU mode.
+ *
+ * The system will set flags to the backup memory to enter DFU and issue
+ * a reset. The Boot Manager will send the system to DFU mode.
+ *
+ * @return EC_SUCCESS, or non-zero if error.
+ */
+int dfu_bootmanager_enter_dfu(void);
+
+/*
+ * Clear the DFU Boot Manager backup memory state.
+ *
+ * If the CONFIG_DFU_BOOTMANAGER_MAX_REBOOT_COUNT setting is enabled, this
+ * allows the RW application to clear the counter to indicate the application
+ * is working as expected.
+ */
+void dfu_bootmanager_clear(void);
+
+/*
+ * Write the value to the backup registers and sets the bitmasks
+ * indicating the field is valid.
+ *
+ * @param value New value to store.
+ */
+void dfu_bootmanager_backup_write(uint8_t value);
+
+/*
+ * Reads the backup registers and performs validation. The value stored
+ * within the VALUE_MASK is returned and the status code indicates
+ * if the valid check passed.
+ *
+ * @param value[out] Value stored within the DFU_BOOTMANAGER_VALUE_MASK
+ * @return EC_SUCCESS, or non-zero if validation failed.
+ */
+int dfu_bootmanager_backup_read(uint8_t *value);
+
+#endif /* __DFU_BOOTMANAGER_SHARED_H */
diff --git a/chip/stm32/usb_dfu_runtime.c b/chip/stm32/usb_dfu_runtime.c
index b902f32af2..7626faec8e 100644
--- a/chip/stm32/usb_dfu_runtime.c
+++ b/chip/stm32/usb_dfu_runtime.c
@@ -3,6 +3,7 @@
* found in the LICENSE file.
*/
+#include "dfu_bootmanager_shared.h"
#include "registers.h"
#include "usb_descriptor.h"
#include "usb_dfu_runtime.h"
@@ -51,7 +52,7 @@ static int dfu_runtime_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx)
/* Host is requesting a jump from application to DFU mode. */
STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0);
- return 0;
+ return dfu_bootmanager_enter_dfu();
} else if (packet.bmRequestType ==
(USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) {
if (packet.bRequest == USB_DFU_RUNTIME_REQ_GET_STATUS) {
diff --git a/common/build.mk b/common/build.mk
index d00a7f8bb1..25dbce2333 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -215,9 +215,11 @@ common-$(CONFIG_AUDIO_CODEC_WOV)+=hotword_dsp_api.o
endif
ifneq ($(CONFIG_COMMON_RUNTIME),)
+ifneq ($(CONFIG_DFU_BOOTMANAGER_MAIN),ro)
common-$(CONFIG_MALLOC)+=shmalloc.o
common-$(call not_cfg,$(CONFIG_MALLOC))+=shared_mem.o
endif
+endif
ifeq ($(CTS_MODULE),)
common-$(TEST_BUILD)+=test_util.o
diff --git a/include/config.h b/include/config.h
index a7cbf5a6fe..393db87432 100644
--- a/include/config.h
+++ b/include/config.h
@@ -5425,6 +5425,24 @@
#undef CONFIG_DFU_RUNTIME
/*
+ * Indicates this region is a DFU Boot Manager and is a minimal runtime.
+ */
+#undef CONFIG_DFU_BOOTMANAGER_MAIN
+/*
+ * Enables DFU Boot Manager reboot loop protection. When unexpected reboots
+ * occur, a counter is incremented which will enter DFU once it exceeds
+ * the value defined. This parameter should only be enabled on setups which
+ * can issue the command to exit DFU.
+ */
+#undef CONFIG_DFU_BOOTMANAGER_MAX_REBOOT_COUNT
+
+/*
+ * Enables access to shared utilities required for the application
+ * and DFU Boot Manager. This allows the application to enter DFU.
+ */
+#undef CONFIG_DFU_BOOTMANAGER_SHARED
+
+/*
* If defined, charge_get_state returns a special status if battery is
* discharging and battery is nearly full.
*/
diff --git a/include/task.h b/include/task.h
index a99c2af79e..d2a19e7a52 100644
--- a/include/task.h
+++ b/include/task.h
@@ -463,7 +463,9 @@ struct irq_def {
/* Include ec.irqlist here for compilation dependency */
#define ENABLE_IRQ(x)
+#if !defined(CONFIG_DFU_BOOTMANAGER_MAIN)
#include "ec.irqlist"
+#endif /* !defined(CONFIG_DFU_BOOTMANAGER_MAIN) */
#endif /* CONFIG_COMMON_RUNTIME */
#endif /* !CONFIG_ZEPHYR */
diff --git a/util/config_allowed.txt b/util/config_allowed.txt
index 805ff8b627..abe12413cc 100644
--- a/util/config_allowed.txt
+++ b/util/config_allowed.txt
@@ -362,6 +362,9 @@ CONFIG_DELAY_DSW_PWROK_TO_PWRBTN
CONFIG_DETACHABLE_BASE
CONFIG_DEVICE_EVENT
CONFIG_DEVICE_STATE
+CONFIG_DFU_BOOTMANAGER_MAIN
+CONFIG_DFU_BOOTMANAGER_MAX_REBOOT_COUNT
+CONFIG_DFU_BOOTMANAGER_SHARED
CONFIG_DFU_RUNTIME
CONFIG_DMA
CONFIG_DMA_DEFAULT_HANDLERS