blob: 089f75b2b135d959b819a999ffcd4f54abe7b359 [file] [log] [blame]
David Brown5153bd62017-01-06 11:16:53 -07001/*
2 * Copyright (c) 2012-2014 Wind River Systems, Inc.
Tamas Banee6615d2020-09-30 07:58:48 +01003 * Copyright (c) 2020 Arm Limited
Jamie McCraeb3e3ce32023-02-22 09:11:57 +00004 * Copyright (c) 2021-2023 Nordic Semiconductor ASA
David Brown5153bd62017-01-06 11:16:53 -07005 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
Marti Bolivareb940802017-05-01 23:15:29 -040019#include <assert.h>
Gerard Marull-Paretas34dd9e72022-05-09 12:13:12 +020020#include <zephyr/kernel.h>
Gerard Marull-Paretas3cd2cec2022-05-09 12:10:05 +020021#include <zephyr/devicetree.h>
22#include <zephyr/drivers/gpio.h>
23#include <zephyr/sys/__assert.h>
24#include <zephyr/drivers/flash.h>
25#include <zephyr/drivers/timer/system_timer.h>
26#include <zephyr/usb/usb_device.h>
Evan Gates4632d8d2018-06-28 13:27:40 -070027#include <soc.h>
Gerard Marull-Paretas3cd2cec2022-05-09 12:10:05 +020028#include <zephyr/linker/linker-defs.h>
David Brown5153bd62017-01-06 11:16:53 -070029
Lucas Tamborrino9bf7ce82023-09-05 11:20:50 -030030#if defined(CONFIG_ARM)
Gerard Marull-Paretas11ecbf62023-06-30 09:58:41 +020031#include <cmsis_core.h>
Lucas Tamborrino9bf7ce82023-09-05 11:20:50 -030032#endif
Yonatan Schachterb22eb6a2022-07-29 18:16:09 +030033
Marti Bolivar51181cf2017-03-20 11:03:41 -040034#include "target.h"
35
Marti Bolivar4a97b4c2017-01-31 18:20:02 -050036#include "bootutil/bootutil_log.h"
Ricardo Salveti3a2c1242017-01-19 10:22:35 -020037#include "bootutil/image.h"
38#include "bootutil/bootutil.h"
Tamas Banee6615d2020-09-30 07:58:48 +010039#include "bootutil/fault_injection_hardening.h"
Jamie McCrae56cb6102022-03-23 11:57:03 +000040#include "bootutil/mcuboot_status.h"
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +020041#include "flash_map_backend/flash_map_backend.h"
Ricardo Salveti3a2c1242017-01-19 10:22:35 -020042
Marek Matej67693442023-01-23 17:54:36 +010043/* Check if Espressif target is supported */
44#ifdef CONFIG_SOC_FAMILY_ESP32
45
46#include <bootloader_init.h>
47#include <esp_loader.h>
48
49#define IMAGE_INDEX_0 0
50#define IMAGE_INDEX_1 1
51
52#define PRIMARY_SLOT 0
53#define SECONDARY_SLOT 1
54
55#define IMAGE0_PRIMARY_START_ADDRESS \
56 DT_PROP_BY_IDX(DT_NODE_BY_FIXED_PARTITION_LABEL(image_0), reg, 0)
57#define IMAGE0_PRIMARY_SIZE \
58 DT_PROP_BY_IDX(DT_NODE_BY_FIXED_PARTITION_LABEL(image_0), reg, 1)
59
60#define IMAGE1_PRIMARY_START_ADDRESS \
61 DT_PROP_BY_IDX(DT_NODE_BY_FIXED_PARTITION_LABEL(image_1), reg, 0)
62#define IMAGE1_PRIMARY_SIZE \
63 DT_PROP_BY_IDX(DT_NODE_BY_FIXED_PARTITION_LABEL(image_1), reg, 1)
64
65#endif /* CONFIG_SOC_FAMILY_ESP32 */
66
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020067#ifdef CONFIG_MCUBOOT_SERIAL
Marko Kiiskila149b4572018-06-06 14:18:54 +030068#include "boot_serial/boot_serial.h"
69#include "serial_adapter/serial_adapter.h"
70
71const struct boot_uart_funcs boot_funcs = {
72 .read = console_read,
73 .write = console_write
74};
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020075#endif
76
Jamie McCraeb3e3ce32023-02-22 09:11:57 +000077#ifdef CONFIG_BOOT_SERIAL_BOOT_MODE
78#include <zephyr/retention/bootmode.h>
79#endif
80
Josh Gao837cf882020-11-13 18:51:27 -080081#if defined(CONFIG_BOOT_USB_DFU_WAIT) || defined(CONFIG_BOOT_USB_DFU_GPIO)
Gerard Marull-Paretas3cd2cec2022-05-09 12:10:05 +020082#include <zephyr/usb/class/usb_dfu.h>
Rajavardhan Gundi51c9d702019-02-20 14:08:52 +053083#endif
84
Andrzej Puzdrowski9a605b62020-03-16 13:34:30 +010085#if CONFIG_MCUBOOT_CLEANUP_ARM_CORE
86#include <arm_cleanup.h>
87#endif
88
Jamie McCrae35941fe2023-03-28 10:04:18 +010089#ifdef CONFIG_BOOT_SERIAL_PIN_RESET
90#include <zephyr/drivers/hwinfo.h>
91#endif
92
Gerard Marull-Paretasa513b8e2021-01-26 22:50:38 +010093/* CONFIG_LOG_MINIMAL is the legacy Kconfig property,
94 * replaced by CONFIG_LOG_MODE_MINIMAL.
95 */
Dominik Ermel5b7ed6a2021-02-26 14:26:48 +000096#if (defined(CONFIG_LOG_MODE_MINIMAL) || defined(CONFIG_LOG_MINIMAL))
97#define ZEPHYR_LOG_MODE_MINIMAL 1
98#endif
Gerard Marull-Paretasa513b8e2021-01-26 22:50:38 +010099
Marek Pietafb47d2e2022-03-11 14:24:07 +0100100/* CONFIG_LOG_IMMEDIATE is the legacy Kconfig property,
101 * replaced by CONFIG_LOG_MODE_IMMEDIATE.
102 */
103#if (defined(CONFIG_LOG_MODE_IMMEDIATE) || defined(CONFIG_LOG_IMMEDIATE))
104#define ZEPHYR_LOG_MODE_IMMEDIATE 1
105#endif
106
107#if defined(CONFIG_LOG) && !defined(ZEPHYR_LOG_MODE_IMMEDIATE) && \
Dominik Ermel5b7ed6a2021-02-26 14:26:48 +0000108 !defined(ZEPHYR_LOG_MODE_MINIMAL)
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +0100109#ifdef CONFIG_LOG_PROCESS_THREAD
110#warning "The log internal thread for log processing can't transfer the log"\
111 "well for MCUBoot."
112#else
Gerard Marull-Paretas3cd2cec2022-05-09 12:10:05 +0200113#include <zephyr/logging/log_ctrl.h>
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +0100114
Krzysztof Chruscinski821214e2020-03-24 07:50:32 +0100115#define BOOT_LOG_PROCESSING_INTERVAL K_MSEC(30) /* [ms] */
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +0100116
117/* log are processing in custom routine */
Andrzej Puzdrowskiaf148532020-02-25 12:51:26 +0100118K_THREAD_STACK_DEFINE(boot_log_stack, CONFIG_MCUBOOT_LOG_THREAD_STACK_SIZE);
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +0100119struct k_thread boot_log_thread;
Andrzej Puzdrowski84591632020-02-24 11:50:19 +0100120volatile bool boot_log_stop = false;
121K_SEM_DEFINE(boot_log_sem, 1, 1);
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +0100122
123/* log processing need to be initalized by the application */
124#define ZEPHYR_BOOT_LOG_START() zephyr_boot_log_start()
Andrzej Puzdrowski84591632020-02-24 11:50:19 +0100125#define ZEPHYR_BOOT_LOG_STOP() zephyr_boot_log_stop()
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +0100126#endif /* CONFIG_LOG_PROCESS_THREAD */
127#else
128/* synchronous log mode doesn't need to be initalized by the application */
129#define ZEPHYR_BOOT_LOG_START() do { } while (false)
Andrzej Puzdrowski84591632020-02-24 11:50:19 +0100130#define ZEPHYR_BOOT_LOG_STOP() do { } while (false)
Marek Pietafb47d2e2022-03-11 14:24:07 +0100131#endif /* defined(CONFIG_LOG) && !defined(ZEPHYR_LOG_MODE_IMMEDIATE) && \
132 * !defined(ZEPHYR_LOG_MODE_MINIMAL)
133 */
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +0100134
Jon Helge Nistade58f9bd2019-11-25 15:59:52 +0100135#ifdef CONFIG_SOC_FAMILY_NRF
Radoslaw Koppel72006692021-12-06 16:15:21 +0100136#include <helpers/nrfx_reset_reason.h>
Jon Helge Nistade58f9bd2019-11-25 15:59:52 +0100137
138static inline bool boot_skip_serial_recovery()
139{
Radoslaw Koppel72006692021-12-06 16:15:21 +0100140 uint32_t rr = nrfx_reset_reason_get();
Jon Helge Nistade58f9bd2019-11-25 15:59:52 +0100141
Radoslaw Koppel72006692021-12-06 16:15:21 +0100142 return !(rr == 0 || (rr & NRFX_RESET_REASON_RESETPIN_MASK));
Jon Helge Nistade58f9bd2019-11-25 15:59:52 +0100143}
144#else
145static inline bool boot_skip_serial_recovery()
146{
147 return false;
148}
149#endif
150
Carlos Falgueras Garcíaa4b4b0f2021-06-22 10:00:22 +0200151BOOT_LOG_MODULE_REGISTER(mcuboot);
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +0100152
Jamie McCraeb3e3ce32023-02-22 09:11:57 +0000153/* Validate serial recovery configuration */
154#ifdef CONFIG_MCUBOOT_SERIAL
155#if !defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) && \
156 !defined(CONFIG_BOOT_SERIAL_WAIT_FOR_DFU) && \
Jamie McCraefd79db32023-03-10 11:19:36 +0000157 !defined(CONFIG_BOOT_SERIAL_BOOT_MODE) && \
Jamie McCrae35941fe2023-03-28 10:04:18 +0100158 !defined(CONFIG_BOOT_SERIAL_NO_APPLICATION) && \
159 !defined(CONFIG_BOOT_SERIAL_PIN_RESET)
Jamie McCraeb3e3ce32023-02-22 09:11:57 +0000160#error "Serial recovery selected without an entrance mode set"
161#endif
162#endif
163
Jared Wolff8e4d7912021-01-21 19:34:05 -0500164#ifdef CONFIG_MCUBOOT_INDICATION_LED
Jared Wolff8e4d7912021-01-21 19:34:05 -0500165
166/*
167 * The led0 devicetree alias is optional. If present, we'll use it
168 * to turn on the LED whenever the button is pressed.
169 */
Andrzej Puzdrowski2f545b82022-05-26 14:28:07 +0200170#if DT_NODE_EXISTS(DT_ALIAS(mcuboot_led0))
Andrzej Puzdrowski5f317e42022-05-26 15:30:14 +0200171#define LED0_NODE DT_ALIAS(mcuboot_led0)
Andrzej Puzdrowski2f545b82022-05-26 14:28:07 +0200172#elif DT_NODE_EXISTS(DT_ALIAS(bootloader_led0))
173#warning "bootloader-led0 alias is deprecated; use mcuboot-led0 instead"
Jared Wolff8e4d7912021-01-21 19:34:05 -0500174#define LED0_NODE DT_ALIAS(bootloader_led0)
Andrzej Puzdrowski2f545b82022-05-26 14:28:07 +0200175#endif
Jared Wolff8e4d7912021-01-21 19:34:05 -0500176
177#if DT_NODE_HAS_STATUS(LED0_NODE, okay) && DT_NODE_HAS_PROP(LED0_NODE, gpios)
Andrzej Puzdrowski5f317e42022-05-26 15:30:14 +0200178static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
Josh Gao837cf882020-11-13 18:51:27 -0800179#else
Jared Wolff8e4d7912021-01-21 19:34:05 -0500180/* A build error here means your board isn't set up to drive an LED. */
181#error "Unsupported board: led0 devicetree alias is not defined"
182#endif
183
Jared Wolff8e4d7912021-01-21 19:34:05 -0500184void led_init(void)
185{
Martin Jäger477ed812022-07-21 11:45:45 +0200186 if (!device_is_ready(led0.port)) {
187 BOOT_LOG_ERR("Didn't find LED device referred by the LED0_NODE\n");
188 return;
189 }
Josh Gao837cf882020-11-13 18:51:27 -0800190
Martin Jäger477ed812022-07-21 11:45:45 +0200191 gpio_pin_configure_dt(&led0, GPIO_OUTPUT);
192 gpio_pin_set_dt(&led0, 0);
Jared Wolff8e4d7912021-01-21 19:34:05 -0500193}
Andrzej Puzdrowski5f317e42022-05-26 15:30:14 +0200194#endif /* CONFIG_MCUBOOT_INDICATION_LED */
Jared Wolff8e4d7912021-01-21 19:34:05 -0500195
Andrew Boie7238f512017-03-02 13:39:06 -0800196void os_heap_init(void);
197
198#if defined(CONFIG_ARM)
Rafał Kuźniad854bb62020-06-17 15:06:47 +0200199
Rafał Kuźniad854bb62020-06-17 15:06:47 +0200200#ifdef CONFIG_SW_VECTOR_RELAY
201extern void *_vector_table_pointer;
Rafał Kuźniad854bb62020-06-17 15:06:47 +0200202#endif
203
Andrew Boie7238f512017-03-02 13:39:06 -0800204struct arm_vector_table {
David Brown0d0652a2017-04-11 17:33:30 -0600205 uint32_t msp;
206 uint32_t reset;
David Brown5153bd62017-01-06 11:16:53 -0700207};
208
Andrew Boie7238f512017-03-02 13:39:06 -0800209static void do_boot(struct boot_rsp *rsp)
210{
David Brown0d0652a2017-04-11 17:33:30 -0600211 struct arm_vector_table *vt;
Andrew Boie7238f512017-03-02 13:39:06 -0800212
David Brown0d0652a2017-04-11 17:33:30 -0600213 /* The beginning of the image is the ARM vector table, containing
214 * the initial stack pointer address and the reset vector
215 * consecutively. Manually set the stack pointer and jump into the
216 * reset vector
217 */
Daniel DeGrassee4574442022-09-01 15:47:01 -0500218#ifdef CONFIG_BOOT_RAM_LOAD
219 /* Get ram address for image */
220 vt = (struct arm_vector_table *)(rsp->br_hdr->ih_load_addr + rsp->br_hdr->ih_hdr_size);
221#else
222 uintptr_t flash_base;
223 int rc;
224
225 /* Jump to flash image */
Marti Bolivareb940802017-05-01 23:15:29 -0400226 rc = flash_device_base(rsp->br_flash_dev_id, &flash_base);
227 assert(rc == 0);
228
229 vt = (struct arm_vector_table *)(flash_base +
230 rsp->br_image_off +
David Brown0d0652a2017-04-11 17:33:30 -0600231 rsp->br_hdr->ih_hdr_size);
Daniel DeGrassee4574442022-09-01 15:47:01 -0500232#endif
Arvid Rosén9ed399c2020-08-19 08:57:11 +0200233
Joakim Andersson90b8f692022-12-21 15:52:53 +0100234 if (IS_ENABLED(CONFIG_SYSTEM_TIMER_HAS_DISABLE_SUPPORT)) {
235 sys_clock_disable();
236 }
Andrzej Puzdrowskie9c6b4d2021-12-14 14:09:02 +0100237
Johann Fischerd2e87aa2021-08-27 13:30:07 +0200238#ifdef CONFIG_USB_DEVICE_STACK
Emanuele Di Santoc4bf7802018-07-20 11:39:57 +0200239 /* Disable the USB to prevent it from firing interrupts */
240 usb_disable();
241#endif
Andrzej Puzdrowski9a605b62020-03-16 13:34:30 +0100242#if CONFIG_MCUBOOT_CLEANUP_ARM_CORE
243 cleanup_arm_nvic(); /* cleanup NVIC registers */
Ioannis Glaropoulos70af7082020-10-22 15:14:48 +0200244
Ryan McClelland179d8fa2022-05-20 23:53:35 -0700245#ifdef CONFIG_CPU_CORTEX_M_HAS_CACHE
Ioannis Glaropoulos70af7082020-10-22 15:14:48 +0200246 /* Disable instruction cache and data cache before chain-load the application */
247 SCB_DisableDCache();
248 SCB_DisableICache();
249#endif
250
Henrik Brix Andersen008f4a72020-12-08 14:40:19 +0100251#if CONFIG_CPU_HAS_ARM_MPU || CONFIG_CPU_HAS_NXP_MPU
Ioannis Glaropoulos70af7082020-10-22 15:14:48 +0200252 z_arm_clear_arm_mpu_config();
Andrzej Puzdrowski9a605b62020-03-16 13:34:30 +0100253#endif
Rafał Kuźniad854bb62020-06-17 15:06:47 +0200254
Håkon Øye Amundsen6a8dbba2020-10-01 12:52:38 +0000255#if defined(CONFIG_BUILTIN_STACK_GUARD) && \
256 defined(CONFIG_CPU_CORTEX_M_HAS_SPLIM)
257 /* Reset limit registers to avoid inflicting stack overflow on image
258 * being booted.
259 */
260 __set_PSPLIM(0);
261 __set_MSPLIM(0);
262#endif
263
Sigvart Hovland9647c462021-08-20 16:33:55 +0200264#else
265 irq_lock();
Ioannis Glaropoulos70af7082020-10-22 15:14:48 +0200266#endif /* CONFIG_MCUBOOT_CLEANUP_ARM_CORE */
267
Rafał Kuźniad854bb62020-06-17 15:06:47 +0200268#ifdef CONFIG_BOOT_INTR_VEC_RELOC
Rafał Kuźnia505c6e62020-07-17 13:18:15 +0200269#if defined(CONFIG_SW_VECTOR_RELAY)
270 _vector_table_pointer = vt;
271#ifdef CONFIG_CPU_CORTEX_M_HAS_VTOR
272 SCB->VTOR = (uint32_t)__vector_relay_table;
Rafał Kuźniad854bb62020-06-17 15:06:47 +0200273#endif
Rafał Kuźnia505c6e62020-07-17 13:18:15 +0200274#elif defined(CONFIG_CPU_CORTEX_M_HAS_VTOR)
275 SCB->VTOR = (uint32_t)vt;
276#endif /* CONFIG_SW_VECTOR_RELAY */
277#else /* CONFIG_BOOT_INTR_VEC_RELOC */
278#if defined(CONFIG_CPU_CORTEX_M_HAS_VTOR) && defined(CONFIG_SW_VECTOR_RELAY)
279 _vector_table_pointer = _vector_start;
280 SCB->VTOR = (uint32_t)__vector_relay_table;
281#endif
282#endif /* CONFIG_BOOT_INTR_VEC_RELOC */
Rafał Kuźniad854bb62020-06-17 15:06:47 +0200283
David Brown57837b92018-03-13 15:56:38 -0600284 __set_MSP(vt->msp);
Andrzej Puzdrowski9a605b62020-03-16 13:34:30 +0100285#if CONFIG_MCUBOOT_CLEANUP_ARM_CORE
286 __set_CONTROL(0x00); /* application will configures core on its own */
Andrzej Puzdrowski56c15e72020-10-29 09:16:50 +0100287 __ISB();
Andrzej Puzdrowski9a605b62020-03-16 13:34:30 +0100288#endif
David Brown0d0652a2017-04-11 17:33:30 -0600289 ((void (*)(void))vt->reset)();
Andrew Boie7238f512017-03-02 13:39:06 -0800290}
Rajavardhan Gundi40c28e32018-12-09 13:32:01 +0530291
Marek Matej67693442023-01-23 17:54:36 +0100292#elif defined(CONFIG_XTENSA) || defined(CONFIG_RISCV)
293
294#ifndef CONFIG_SOC_FAMILY_ESP32
295
Rajavardhan Gundi40c28e32018-12-09 13:32:01 +0530296#define SRAM_BASE_ADDRESS 0xBE030000
297
298static void copy_img_to_SRAM(int slot, unsigned int hdr_offset)
299{
300 const struct flash_area *fap;
301 int area_id;
302 int rc;
303 unsigned char *dst = (unsigned char *)(SRAM_BASE_ADDRESS + hdr_offset);
304
305 BOOT_LOG_INF("Copying image to SRAM");
306
307 area_id = flash_area_id_from_image_slot(slot);
308 rc = flash_area_open(area_id, &fap);
309 if (rc != 0) {
Fabio Utzigcac58f62019-09-06 08:52:35 -0300310 BOOT_LOG_ERR("flash_area_open failed with %d\n", rc);
Rajavardhan Gundi40c28e32018-12-09 13:32:01 +0530311 goto done;
312 }
313
314 rc = flash_area_read(fap, hdr_offset, dst, fap->fa_size - hdr_offset);
315 if (rc != 0) {
Fabio Utzigcac58f62019-09-06 08:52:35 -0300316 BOOT_LOG_ERR("flash_area_read failed with %d\n", rc);
Rajavardhan Gundi40c28e32018-12-09 13:32:01 +0530317 goto done;
318 }
319
320done:
321 flash_area_close(fap);
322}
Marek Matej67693442023-01-23 17:54:36 +0100323#endif /* !CONFIG_SOC_FAMILY_ESP32 */
Rajavardhan Gundi40c28e32018-12-09 13:32:01 +0530324
325/* Entry point (.ResetVector) is at the very beginning of the image.
326 * Simply copy the image to a suitable location and jump there.
327 */
328static void do_boot(struct boot_rsp *rsp)
329{
330 void *start;
331
332 BOOT_LOG_INF("br_image_off = 0x%x\n", rsp->br_image_off);
333 BOOT_LOG_INF("ih_hdr_size = 0x%x\n", rsp->br_hdr->ih_hdr_size);
334
Marek Matej67693442023-01-23 17:54:36 +0100335#ifdef CONFIG_SOC_FAMILY_ESP32
336 int slot = (rsp->br_image_off == IMAGE0_PRIMARY_START_ADDRESS) ?
337 PRIMARY_SLOT : SECONDARY_SLOT;
338 /* Load memory segments and start from entry point */
339 start_cpu0_image(IMAGE_INDEX_0, slot, rsp->br_hdr->ih_hdr_size);
340#else
Rajavardhan Gundi40c28e32018-12-09 13:32:01 +0530341 /* Copy from the flash to HP SRAM */
342 copy_img_to_SRAM(0, rsp->br_hdr->ih_hdr_size);
343
344 /* Jump to entry point */
345 start = (void *)(SRAM_BASE_ADDRESS + rsp->br_hdr->ih_hdr_size);
346 ((void (*)(void))start)();
Marek Matej67693442023-01-23 17:54:36 +0100347#endif /* CONFIG_SOC_FAMILY_ESP32 */
Rajavardhan Gundi40c28e32018-12-09 13:32:01 +0530348}
349
Andrew Boie7238f512017-03-02 13:39:06 -0800350#else
351/* Default: Assume entry point is at the very beginning of the image. Simply
352 * lock interrupts and jump there. This is the right thing to do for X86 and
353 * possibly other platforms.
354 */
355static void do_boot(struct boot_rsp *rsp)
356{
David Brown0d0652a2017-04-11 17:33:30 -0600357 void *start;
Martin Jäger477ed812022-07-21 11:45:45 +0200358
Jim Tanee1b7b92022-04-07 11:26:28 +0800359#if defined(MCUBOOT_RAM_LOAD)
360 start = (void *)(rsp->br_hdr->ih_load_addr + rsp->br_hdr->ih_hdr_size);
361#else
362 uintptr_t flash_base;
Marti Bolivareb940802017-05-01 23:15:29 -0400363 int rc;
Andrew Boie7238f512017-03-02 13:39:06 -0800364
Marti Bolivareb940802017-05-01 23:15:29 -0400365 rc = flash_device_base(rsp->br_flash_dev_id, &flash_base);
366 assert(rc == 0);
367
368 start = (void *)(flash_base + rsp->br_image_off +
369 rsp->br_hdr->ih_hdr_size);
Jim Tanee1b7b92022-04-07 11:26:28 +0800370#endif
Andrew Boie7238f512017-03-02 13:39:06 -0800371
David Brown0d0652a2017-04-11 17:33:30 -0600372 /* Lock interrupts and dive into the entry point */
373 irq_lock();
374 ((void (*)(void))start)();
Andrew Boie7238f512017-03-02 13:39:06 -0800375}
376#endif
David Brown5153bd62017-01-06 11:16:53 -0700377
Marek Pietafb47d2e2022-03-11 14:24:07 +0100378#if defined(CONFIG_LOG) && !defined(ZEPHYR_LOG_MODE_IMMEDIATE) && \
Dominik Ermel5b7ed6a2021-02-26 14:26:48 +0000379 !defined(CONFIG_LOG_PROCESS_THREAD) && !defined(ZEPHYR_LOG_MODE_MINIMAL)
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +0100380/* The log internal thread for log processing can't transfer log well as has too
381 * low priority.
382 * Dedicated thread for log processing below uses highest application
383 * priority. This allows to transmit all logs without adding k_sleep/k_yield
384 * anywhere else int the code.
385 */
386
387/* most simple log processing theread */
388void boot_log_thread_func(void *dummy1, void *dummy2, void *dummy3)
389{
390 (void)dummy1;
391 (void)dummy2;
392 (void)dummy3;
393
Martin Jäger477ed812022-07-21 11:45:45 +0200394 log_init();
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +0100395
Martin Jäger477ed812022-07-21 11:45:45 +0200396 while (1) {
Martin Jäger31751822022-07-21 11:49:32 +0200397#if defined(CONFIG_LOG1) || defined(CONFIG_LOG2)
398 /* support Zephyr legacy logging implementation before commit c5f2cde */
Martin Jäger477ed812022-07-21 11:45:45 +0200399 if (log_process(false) == false) {
Martin Jäger31751822022-07-21 11:49:32 +0200400#else
401 if (log_process() == false) {
402#endif
Martin Jäger477ed812022-07-21 11:45:45 +0200403 if (boot_log_stop) {
404 break;
405 }
406 k_sleep(BOOT_LOG_PROCESSING_INTERVAL);
407 }
408 }
Andrzej Puzdrowski84591632020-02-24 11:50:19 +0100409
Martin Jäger477ed812022-07-21 11:45:45 +0200410 k_sem_give(&boot_log_sem);
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +0100411}
412
413void zephyr_boot_log_start(void)
414{
Martin Jäger477ed812022-07-21 11:45:45 +0200415 /* start logging thread */
416 k_thread_create(&boot_log_thread, boot_log_stack,
417 K_THREAD_STACK_SIZEOF(boot_log_stack),
418 boot_log_thread_func, NULL, NULL, NULL,
419 K_HIGHEST_APPLICATION_THREAD_PRIO, 0,
420 BOOT_LOG_PROCESSING_INTERVAL);
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +0100421
Martin Jäger477ed812022-07-21 11:45:45 +0200422 k_thread_name_set(&boot_log_thread, "logging");
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +0100423}
Andrzej Puzdrowski84591632020-02-24 11:50:19 +0100424
425void zephyr_boot_log_stop(void)
426{
427 boot_log_stop = true;
428
429 /* wait until log procesing thread expired
430 * This can be reworked using a thread_join() API once a such will be
431 * available in zephyr.
432 * see https://github.com/zephyrproject-rtos/zephyr/issues/21500
433 */
434 (void)k_sem_take(&boot_log_sem, K_FOREVER);
435}
Marek Pietafb47d2e2022-03-11 14:24:07 +0100436#endif /* defined(CONFIG_LOG) && !defined(ZEPHYR_LOG_MODE_IMMEDIATE) && \
437 * !defined(CONFIG_LOG_PROCESS_THREAD) && !defined(ZEPHYR_LOG_MODE_MINIMAL)
438 */
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +0100439
Jamie McCraeb3e3ce32023-02-22 09:11:57 +0000440#if defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) || defined(CONFIG_BOOT_USB_DFU_GPIO)
Andrzej Puzdrowski2ab49872022-04-09 13:03:58 +0200441
442#ifdef CONFIG_MCUBOOT_SERIAL
Andrzej Puzdrowski7ed0e6d2022-04-09 13:25:35 +0200443#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_SERIAL_DETECT_DELAY
444#else
445#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_USB_DFU_DETECT_DELAY
446#endif
447
Andrzej Puzdrowski7ed0e6d2022-04-09 13:25:35 +0200448#define BUTTON_0_NODE DT_ALIAS(mcuboot_button0)
449
450#if DT_NODE_EXISTS(BUTTON_0_NODE) && DT_NODE_HAS_PROP(BUTTON_0_NODE, gpios)
Andrzej Puzdrowski7ed0e6d2022-04-09 13:25:35 +0200451static const struct gpio_dt_spec button0 = GPIO_DT_SPEC_GET(BUTTON_0_NODE, gpios);
Jamie McCraeb3e3ce32023-02-22 09:11:57 +0000452#else
Jamie McCrae9551b6e2023-02-28 15:47:42 +0000453#error "Serial recovery/USB DFU button must be declared in device tree as 'mcuboot_button0'"
Andrzej Puzdrowski2ab49872022-04-09 13:03:58 +0200454#endif
455
456static bool detect_pin(void)
Josh Gao837cf882020-11-13 18:51:27 -0800457{
458 int rc;
Andrzej Puzdrowski2ab49872022-04-09 13:03:58 +0200459 int pin_active;
Josh Gao837cf882020-11-13 18:51:27 -0800460
Andrzej Puzdrowski7ed0e6d2022-04-09 13:25:35 +0200461 if (!device_is_ready(button0.port)) {
462 __ASSERT(false, "GPIO device is not ready.\n");
463 return false;
464 }
Josh Gao837cf882020-11-13 18:51:27 -0800465
Andrzej Puzdrowski7ed0e6d2022-04-09 13:25:35 +0200466 rc = gpio_pin_configure_dt(&button0, GPIO_INPUT);
Josh Gao837cf882020-11-13 18:51:27 -0800467 __ASSERT(rc == 0, "Failed to initialize boot detect pin.\n");
468
Andrzej Puzdrowski7ed0e6d2022-04-09 13:25:35 +0200469 rc = gpio_pin_get_dt(&button0);
Andrzej Puzdrowski2ab49872022-04-09 13:03:58 +0200470 pin_active = rc;
Andrzej Puzdrowski8bd30812021-03-22 08:19:41 +0100471
Josh Gao837cf882020-11-13 18:51:27 -0800472 __ASSERT(rc >= 0, "Failed to read boot detect pin.\n");
473
Andrzej Puzdrowski2ab49872022-04-09 13:03:58 +0200474 if (pin_active) {
475 if (BUTTON_0_DETECT_DELAY > 0) {
Andrzej Puzdrowski9b974562021-05-17 11:37:00 +0200476#ifdef CONFIG_MULTITHREADING
Josh Gao837cf882020-11-13 18:51:27 -0800477 k_sleep(K_MSEC(50));
Andrzej Puzdrowski9b974562021-05-17 11:37:00 +0200478#else
479 k_busy_wait(50000);
480#endif
Josh Gao837cf882020-11-13 18:51:27 -0800481
482 /* Get the uptime for debounce purposes. */
483 int64_t timestamp = k_uptime_get();
484
485 for(;;) {
Andrzej Puzdrowski7ed0e6d2022-04-09 13:25:35 +0200486 rc = gpio_pin_get_dt(&button0);
Andrzej Puzdrowski2ab49872022-04-09 13:03:58 +0200487 pin_active = rc;
Josh Gao837cf882020-11-13 18:51:27 -0800488 __ASSERT(rc >= 0, "Failed to read boot detect pin.\n");
489
490 /* Get delta from when this started */
491 uint32_t delta = k_uptime_get() - timestamp;
492
493 /* If not pressed OR if pressed > debounce period, stop. */
Andrzej Puzdrowski2ab49872022-04-09 13:03:58 +0200494 if (delta >= BUTTON_0_DETECT_DELAY || !pin_active) {
Josh Gao837cf882020-11-13 18:51:27 -0800495 break;
496 }
497
498 /* Delay 1 ms */
Andrzej Puzdrowski9b974562021-05-17 11:37:00 +0200499#ifdef CONFIG_MULTITHREADING
Josh Gao837cf882020-11-13 18:51:27 -0800500 k_sleep(K_MSEC(1));
Andrzej Puzdrowski9b974562021-05-17 11:37:00 +0200501#else
502 k_busy_wait(1000);
503#endif
Josh Gao837cf882020-11-13 18:51:27 -0800504 }
505 }
506 }
507
Andrzej Puzdrowski2ab49872022-04-09 13:03:58 +0200508 return (bool)pin_active;
Josh Gao837cf882020-11-13 18:51:27 -0800509}
510#endif
511
Jamie McCrae6902abb2023-04-04 13:50:43 +0100512#ifdef CONFIG_MCUBOOT_SERIAL
513static void boot_serial_enter()
514{
515 int rc;
516
517#ifdef CONFIG_MCUBOOT_INDICATION_LED
518 gpio_pin_set_dt(&led0, 1);
519#endif
520
521 mcuboot_status_change(MCUBOOT_STATUS_SERIAL_DFU_ENTERED);
522
523 BOOT_LOG_INF("Enter the serial recovery mode");
524 rc = boot_console_init();
525 __ASSERT(rc == 0, "Error initializing boot console.\n");
526 boot_serial_start(&boot_funcs);
527 __ASSERT(0, "Bootloader serial process was terminated unexpectedly.\n");
528}
529#endif
530
Keith Packardec2ac822023-04-27 09:56:10 -0700531int main(void)
David Brown5153bd62017-01-06 11:16:53 -0700532{
David Brown0d0652a2017-04-11 17:33:30 -0600533 struct boot_rsp rsp;
534 int rc;
Michael Grand5047f032022-11-24 16:49:56 +0100535 FIH_DECLARE(fih_rc, FIH_FAILURE);
David Brown5153bd62017-01-06 11:16:53 -0700536
Jamie McCraeb3e3ce32023-02-22 09:11:57 +0000537#ifdef CONFIG_BOOT_SERIAL_BOOT_MODE
538 int32_t boot_mode;
539#endif
540
Jamie McCrae35941fe2023-03-28 10:04:18 +0100541#ifdef CONFIG_BOOT_SERIAL_PIN_RESET
542 uint32_t reset_cause;
543#endif
544
Jeppe Odgaard4420bb62023-04-11 09:43:10 +0200545 MCUBOOT_WATCHDOG_SETUP();
Andrzej Puzdrowski210b3182020-10-13 13:52:15 +0200546 MCUBOOT_WATCHDOG_FEED();
547
Dominik Ermelcd07ed32021-02-17 15:18:01 +0000548#if !defined(MCUBOOT_DIRECT_XIP)
David Brown0d0652a2017-04-11 17:33:30 -0600549 BOOT_LOG_INF("Starting bootloader");
Dominik Ermelcd07ed32021-02-17 15:18:01 +0000550#else
551 BOOT_LOG_INF("Starting Direct-XIP bootloader");
552#endif
Ricardo Salveti7cf3d9e2017-01-18 16:38:22 -0200553
Jared Wolff8e4d7912021-01-21 19:34:05 -0500554#ifdef CONFIG_MCUBOOT_INDICATION_LED
555 /* LED init */
556 led_init();
557#endif
558
David Brown0d0652a2017-04-11 17:33:30 -0600559 os_heap_init();
David Brown5153bd62017-01-06 11:16:53 -0700560
Andrzej Puzdrowski3f092bd2020-02-17 13:25:32 +0100561 ZEPHYR_BOOT_LOG_START();
562
Tamas Banee6615d2020-09-30 07:58:48 +0100563 (void)rc;
564
Jamie McCrae56cb6102022-03-23 11:57:03 +0000565 mcuboot_status_change(MCUBOOT_STATUS_STARTUP);
566
Jamie McCraeb3e3ce32023-02-22 09:11:57 +0000567#ifdef CONFIG_BOOT_SERIAL_ENTRANCE_GPIO
Andrzej Puzdrowski2ab49872022-04-09 13:03:58 +0200568 if (detect_pin() &&
Josh Gao837cf882020-11-13 18:51:27 -0800569 !boot_skip_serial_recovery()) {
Jamie McCrae6902abb2023-04-04 13:50:43 +0100570 boot_serial_enter();
Josh Gao837cf882020-11-13 18:51:27 -0800571 }
572#endif
573
Jamie McCrae35941fe2023-03-28 10:04:18 +0100574#ifdef CONFIG_BOOT_SERIAL_PIN_RESET
575 rc = hwinfo_get_reset_cause(&reset_cause);
576
577 if (rc == 0 && reset_cause == RESET_PIN) {
Jamie McCrae35941fe2023-03-28 10:04:18 +0100578 (void)hwinfo_clear_reset_cause();
Jamie McCrae6902abb2023-04-04 13:50:43 +0100579 boot_serial_enter();
Jamie McCrae35941fe2023-03-28 10:04:18 +0100580 }
581#endif
582
Josh Gao837cf882020-11-13 18:51:27 -0800583#if defined(CONFIG_BOOT_USB_DFU_GPIO)
Andrzej Puzdrowski2ab49872022-04-09 13:03:58 +0200584 if (detect_pin()) {
Josh Gao837cf882020-11-13 18:51:27 -0800585#ifdef CONFIG_MCUBOOT_INDICATION_LED
Andrzej Puzdrowski5f317e42022-05-26 15:30:14 +0200586 gpio_pin_set_dt(&led0, 1);
Josh Gao837cf882020-11-13 18:51:27 -0800587#endif
Jamie McCrae56cb6102022-03-23 11:57:03 +0000588
589 mcuboot_status_change(MCUBOOT_STATUS_USB_DFU_ENTERED);
590
Josh Gao837cf882020-11-13 18:51:27 -0800591 rc = usb_enable(NULL);
592 if (rc) {
593 BOOT_LOG_ERR("Cannot enable USB");
594 } else {
595 BOOT_LOG_INF("Waiting for USB DFU");
596 wait_for_usb_dfu(K_FOREVER);
597 BOOT_LOG_INF("USB DFU wait time elapsed");
598 }
599 }
600#elif defined(CONFIG_BOOT_USB_DFU_WAIT)
Andrzej Puzdrowskiac1f1ff2020-02-05 08:40:12 +0100601 rc = usb_enable(NULL);
602 if (rc) {
603 BOOT_LOG_ERR("Cannot enable USB");
604 } else {
605 BOOT_LOG_INF("Waiting for USB DFU");
Jamie McCrae56cb6102022-03-23 11:57:03 +0000606
607 mcuboot_status_change(MCUBOOT_STATUS_USB_DFU_WAITING);
608
Josh Gao837cf882020-11-13 18:51:27 -0800609 wait_for_usb_dfu(K_MSEC(CONFIG_BOOT_USB_DFU_WAIT_DELAY_MS));
Andrzej Puzdrowskiac1f1ff2020-02-05 08:40:12 +0100610 BOOT_LOG_INF("USB DFU wait time elapsed");
Jamie McCrae56cb6102022-03-23 11:57:03 +0000611
612 mcuboot_status_change(MCUBOOT_STATUS_USB_DFU_TIMED_OUT);
Andrzej Puzdrowskiac1f1ff2020-02-05 08:40:12 +0100613 }
Rajavardhan Gundi51c9d702019-02-20 14:08:52 +0530614#endif
615
Wouter Cappellee3822f82022-01-19 15:39:43 +0100616#ifdef CONFIG_BOOT_SERIAL_WAIT_FOR_DFU
617 /* Initialize the boot console, so we can already fill up our buffers while
618 * waiting for the boot image check to finish. This image check, can take
619 * some time, so it's better to reuse thistime to already receive the
620 * initial mcumgr command(s) into our buffers
621 */
622 rc = boot_console_init();
623 int timeout_in_ms = CONFIG_BOOT_SERIAL_WAIT_FOR_DFU_TIMEOUT;
624 uint32_t start = k_uptime_get_32();
625#endif
626
Tamas Banee6615d2020-09-30 07:58:48 +0100627 FIH_CALL(boot_go, fih_rc, &rsp);
Wouter Cappellee3822f82022-01-19 15:39:43 +0100628
Jamie McCraeb3e3ce32023-02-22 09:11:57 +0000629#ifdef CONFIG_BOOT_SERIAL_BOOT_MODE
630 boot_mode = bootmode_check(BOOT_MODE_TYPE_BOOTLOADER);
631
632 if (boot_mode == 1) {
633 /* Boot mode to stay in bootloader, clear status and enter serial
634 * recovery mode
635 */
Jamie McCraeb3e3ce32023-02-22 09:11:57 +0000636 bootmode_clear();
Jamie McCrae6902abb2023-04-04 13:50:43 +0100637 boot_serial_enter();
Jamie McCraeb3e3ce32023-02-22 09:11:57 +0000638 }
639#endif
640
Wouter Cappellee3822f82022-01-19 15:39:43 +0100641#ifdef CONFIG_BOOT_SERIAL_WAIT_FOR_DFU
642 timeout_in_ms -= (k_uptime_get_32() - start);
643 if( timeout_in_ms <= 0 ) {
644 /* at least one check if time was expired */
645 timeout_in_ms = 1;
646 }
Jamie McCrae254714b2022-04-07 09:00:31 +0100647 boot_serial_check_start(&boot_funcs,timeout_in_ms);
Wouter Cappellee3822f82022-01-19 15:39:43 +0100648#endif
649
Michael Grand5047f032022-11-24 16:49:56 +0100650 if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
David Brown0d0652a2017-04-11 17:33:30 -0600651 BOOT_LOG_ERR("Unable to find bootable image");
Jamie McCrae56cb6102022-03-23 11:57:03 +0000652
653 mcuboot_status_change(MCUBOOT_STATUS_NO_BOOTABLE_IMAGE_FOUND);
654
Jamie McCraefd79db32023-03-10 11:19:36 +0000655#ifdef CONFIG_BOOT_SERIAL_NO_APPLICATION
656 /* No bootable image and configuration set to remain in serial
657 * recovery mode
658 */
Jamie McCrae6902abb2023-04-04 13:50:43 +0100659 boot_serial_enter();
Jamie McCraefd79db32023-03-10 11:19:36 +0000660#endif
661
Tamas Banee6615d2020-09-30 07:58:48 +0100662 FIH_PANIC;
David Brown0d0652a2017-04-11 17:33:30 -0600663 }
David Brown5153bd62017-01-06 11:16:53 -0700664
Marti Bolivar88f48d92017-05-01 22:30:02 -0400665 BOOT_LOG_INF("Bootloader chainload address offset: 0x%x",
666 rsp.br_image_off);
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +0200667
Dominik Ermelcd07ed32021-02-17 15:18:01 +0000668#if defined(MCUBOOT_DIRECT_XIP)
669 BOOT_LOG_INF("Jumping to the image slot");
670#else
David Brown0d0652a2017-04-11 17:33:30 -0600671 BOOT_LOG_INF("Jumping to the first image slot");
Dominik Ermelcd07ed32021-02-17 15:18:01 +0000672#endif
Jamie McCrae56cb6102022-03-23 11:57:03 +0000673
674 mcuboot_status_change(MCUBOOT_STATUS_BOOTABLE_IMAGE_FOUND);
675
Andrzej Puzdrowski84591632020-02-24 11:50:19 +0100676 ZEPHYR_BOOT_LOG_STOP();
David Brown0d0652a2017-04-11 17:33:30 -0600677 do_boot(&rsp);
David Brown5153bd62017-01-06 11:16:53 -0700678
Jamie McCrae56cb6102022-03-23 11:57:03 +0000679 mcuboot_status_change(MCUBOOT_STATUS_BOOT_FAILED);
680
David Brown0d0652a2017-04-11 17:33:30 -0600681 BOOT_LOG_ERR("Never should get here");
682 while (1)
683 ;
David Brown5153bd62017-01-06 11:16:53 -0700684}