1 /*
2 * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <string.h>
8
9 #include <bootutil/bootutil_log.h>
10
11 #include <bootutil/fault_injection_hardening.h>
12
13 #include "bootloader_flash_priv.h"
14 #include "esp_flash_encrypt.h"
15 #include "soc/soc_memory_layout.h"
16 #include "esp_log.h"
17
18 #if !defined(CONFIG_SOC_SERIES_ESP32C2) && \
19 !defined(CONFIG_SOC_SERIES_ESP32C3) && \
20 !defined(CONFIG_SOC_SERIES_ESP32C6)
21 #include "soc/dport_reg.h"
22 #endif
23
24 #include "esp_rom_sys.h"
25 #include "soc/gpio_periph.h"
26 #include "soc/rtc_periph.h"
27 #ifndef CONFIG_SOC_SERIES_ESP32C6
28 #include "soc/rtc_cntl_reg.h"
29 #endif
30 #include "esp_cpu.h"
31
32 #if CONFIG_SOC_SERIES_ESP32
33 #include "esp32/rom/uart.h"
34 #include "esp32/rom/cache.h"
35 #define LP_RTC_PREFIX "RTC"
36 #elif CONFIG_SOC_SERIES_ESP32S2
37 #include "esp32s2/rom/uart.h"
38 #define LP_RTC_PREFIX "RTC"
39 #elif CONFIG_SOC_SERIES_ESP32S3
40 #include "esp32s3/rom/uart.h"
41 #include "esp32s3/rom/cache.h"
42 #define LP_RTC_PREFIX "RTC"
43 #elif CONFIG_SOC_SERIES_ESP32C2
44 #include "esp32c2/rom/uart.h"
45 #elif CONFIG_SOC_SERIES_ESP32C3
46 #include "esp32c3/rom/uart.h"
47 #define LP_RTC_PREFIX "RTC"
48 #elif CONFIG_SOC_SERIES_ESP32C6
49 #include "esp32c6/rom/uart.h"
50 #define LP_RTC_PREFIX "LP"
51 #endif
52
53 #include "esp_mcuboot_image.h"
54 #include "esp_image_loader.h"
55 #include "flash_map_backend/flash_map_backend.h"
56 #include <zephyr/drivers/timer/system_timer.h>
57
58 #ifdef CONFIG_ESP_MULTI_PROCESSOR_BOOT
59 #include "app_cpu_start.h"
60 #endif
61
load_segment(const struct flash_area * fap,uint32_t data_addr,uint32_t data_len,uint32_t load_addr)62 static int load_segment(const struct flash_area *fap, uint32_t data_addr,
63 uint32_t data_len, uint32_t load_addr)
64 {
65 const uint32_t *data = (const uint32_t *)esp_rom_flash_mmap((fap->fa_off + data_addr), data_len);
66 if (!data) {
67 BOOT_LOG_ERR("%s: Bootloader mmap failed", __func__);
68 return -1;
69 }
70 memcpy((void *)load_addr, data, data_len);
71 esp_rom_flash_unmmap(data);
72 return 0;
73 }
74
esp_app_image_load(int image_index,int slot,unsigned int hdr_offset,unsigned int * entry_addr)75 void esp_app_image_load(int image_index, int slot,
76 unsigned int hdr_offset, unsigned int *entry_addr)
77 {
78 const struct flash_area *fap;
79 int area_id;
80 int rc;
81
82 area_id = flash_area_id_from_multi_image_slot(image_index, slot);
83 rc = flash_area_open(area_id, &fap);
84 if (rc != 0) {
85 BOOT_LOG_ERR("%s: flash_area_open failed with %d", __func__, rc);
86 }
87
88 BOOT_LOG_INF("Loading image %d - slot %d from flash, area id: %d",
89 image_index, slot, area_id);
90
91 const uint32_t *data = (const uint32_t *)esp_rom_flash_mmap((fap->fa_off + hdr_offset),
92 sizeof(esp_image_load_header_t));
93 esp_image_load_header_t load_header = {0};
94 memcpy((void *)&load_header, data, sizeof(esp_image_load_header_t));
95 esp_rom_flash_unmmap(data);
96
97 if (load_header.header_magic != ESP_LOAD_HEADER_MAGIC) {
98 BOOT_LOG_ERR("Load header magic verification failed. Aborting");
99 FIH_PANIC;
100 }
101
102 if (!esp_ptr_in_iram((void *)load_header.iram_dest_addr) ||
103 !esp_ptr_in_iram((void *)(load_header.iram_dest_addr + load_header.iram_size))) {
104 BOOT_LOG_ERR("IRAM region in load header is not valid. Aborting");
105 FIH_PANIC;
106 }
107
108 if (!esp_ptr_in_dram((void *)load_header.dram_dest_addr) ||
109 !esp_ptr_in_dram((void *)(load_header.dram_dest_addr + load_header.dram_size))) {
110 BOOT_LOG_ERR("DRAM region in load header is not valid. Aborting");
111 FIH_PANIC;
112 }
113
114 #if SOC_RTC_FAST_MEM_SUPPORTED
115 if (!esp_ptr_in_rtc_iram_fast((void *)load_header.lp_rtc_iram_dest_addr) ||
116 !esp_ptr_in_rtc_iram_fast((void *)(load_header.lp_rtc_iram_dest_addr + load_header.lp_rtc_iram_size))) {
117 BOOT_LOG_ERR("%s_IRAM region in load header is not valid. Aborting", LP_RTC_PREFIX);
118 FIH_PANIC;
119 }
120 #endif
121
122 #if SOC_RTC_SLOW_MEM_SUPPORTED
123 if (!esp_ptr_in_rtc_slow((void *)load_header.lp_rtc_dram_dest_addr) ||
124 !esp_ptr_in_rtc_slow((void *)(load_header.lp_rtc_dram_dest_addr + load_header.lp_rtc_dram_size))) {
125 BOOT_LOG_ERR("%s_RAM region in load header is not valid. Aborting %p", LP_RTC_PREFIX, load_header.lp_rtc_dram_dest_addr);
126 FIH_PANIC;
127 }
128 #endif
129
130 if (!esp_ptr_in_iram((void *)load_header.entry_addr)) {
131 BOOT_LOG_ERR("Application entry point (%xh) is not in IRAM. Aborting",
132 load_header.entry_addr);
133 FIH_PANIC;
134 }
135
136 BOOT_LOG_INF("Application start=%xh", load_header.entry_addr);
137
138 #if SOC_RTC_FAST_MEM_SUPPORTED || SOC_RTC_SLOW_MEM_SUPPORTED
139 if (load_header.lp_rtc_dram_size > 0) {
140 soc_reset_reason_t reset_reason = esp_rom_get_reset_reason(0);
141
142 /* Unless waking from deep sleep (implying RTC memory is intact), load its segments */
143 if (reset_reason != RESET_REASON_CORE_DEEP_SLEEP) {
144 BOOT_LOG_INF("%s_RAM segment: paddr=%08xh, vaddr=%08xh, size=%05xh (%6d) load", LP_RTC_PREFIX,
145 (fap->fa_off + load_header.lp_rtc_dram_flash_offset), load_header.lp_rtc_dram_dest_addr,
146 load_header.lp_rtc_dram_size, load_header.lp_rtc_dram_size);
147 load_segment(fap, load_header.lp_rtc_dram_flash_offset,
148 load_header.lp_rtc_dram_size, load_header.lp_rtc_dram_dest_addr);
149 } else {
150 BOOT_LOG_INF("%s_RAM segment: paddr=%08xh, vaddr=%08xh, size=%05xh (%6d) noload", LP_RTC_PREFIX,
151 load_header.lp_rtc_dram_flash_offset, load_header.lp_rtc_dram_dest_addr,
152 load_header.lp_rtc_dram_size, load_header.lp_rtc_dram_size);
153 }
154 }
155
156 if (load_header.lp_rtc_iram_size > 0) {
157 BOOT_LOG_INF("%s_IRAM segment: paddr=%08xh, vaddr=%08xh, size=%05xh (%6d) load", LP_RTC_PREFIX,
158 (fap->fa_off + load_header.lp_rtc_iram_flash_offset), load_header.lp_rtc_iram_dest_addr,
159 load_header.lp_rtc_iram_size, load_header.lp_rtc_iram_size);
160 load_segment(fap, load_header.lp_rtc_iram_flash_offset,
161 load_header.lp_rtc_iram_size, load_header.lp_rtc_iram_dest_addr);
162 }
163 #endif
164
165 BOOT_LOG_INF("DRAM segment: paddr=%08xh, vaddr=%08xh, size=%05xh (%6d) load",
166 (fap->fa_off + load_header.dram_flash_offset), load_header.dram_dest_addr,
167 load_header.dram_size, load_header.dram_size);
168 load_segment(fap, load_header.dram_flash_offset,
169 load_header.dram_size, load_header.dram_dest_addr);
170
171 BOOT_LOG_INF("IRAM segment: paddr=%08xh, vaddr=%08xh, size=%05xh (%6d) load",
172 (fap->fa_off + load_header.iram_flash_offset), load_header.iram_dest_addr,
173 load_header.iram_size, load_header.iram_size);
174 load_segment(fap, load_header.iram_flash_offset,
175 load_header.iram_size, load_header.iram_dest_addr);
176
177 uart_tx_wait_idle(0);
178
179 assert(entry_addr != NULL);
180 *entry_addr = load_header.entry_addr;
181 }
182
start_cpu0_image(int image_index,int slot,unsigned int hdr_offset)183 void start_cpu0_image(int image_index, int slot, unsigned int hdr_offset)
184 {
185 unsigned int entry_addr;
186 esp_app_image_load(image_index, slot, hdr_offset, &entry_addr);
187
188 if (IS_ENABLED(CONFIG_SYSTEM_TIMER_HAS_DISABLE_SUPPORT)) {
189 sys_clock_disable();
190 }
191
192 ((void (*)(void))entry_addr)(); /* Call to application entry address should not return */
193 FIH_PANIC; /* It should not get here */
194 }
195
196 #ifdef CONFIG_ESP_MULTI_PROCESSOR_BOOT
197
appcpu_start(uint32_t entry_addr)198 void appcpu_start(uint32_t entry_addr)
199 {
200 ESP_LOGI(TAG, "Starting APPCPU");
201
202 #if defined(CONFIG_SOC_SERIES_ESP32)
203 Cache_Flush(1);
204 Cache_Read_Enable(1);
205 #endif
206
207 esp_cpu_unstall(1);
208
209 #if defined(CONFIG_SOC_SERIES_ESP32)
210 DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
211 DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
212 DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
213 DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
214 #elif defined(CONFIG_SOC_SERIES_ESP32S3)
215 // Enable clock and reset APP CPU. Note that OpenOCD may have already
216 // enabled clock and taken APP CPU out of reset. In this case don't reset
217 // APP CPU again, as that will clear the breakpoints which may have already
218 // been set.
219 if (!REG_GET_BIT(SYSTEM_CORE_1_CONTROL_0_REG, SYSTEM_CONTROL_CORE_1_CLKGATE_EN)) {
220 REG_SET_BIT(SYSTEM_CORE_1_CONTROL_0_REG, SYSTEM_CONTROL_CORE_1_CLKGATE_EN);
221 REG_CLR_BIT(SYSTEM_CORE_1_CONTROL_0_REG, SYSTEM_CONTROL_CORE_1_RUNSTALL);
222 REG_SET_BIT(SYSTEM_CORE_1_CONTROL_0_REG, SYSTEM_CONTROL_CORE_1_RESETTING);
223 REG_CLR_BIT(SYSTEM_CORE_1_CONTROL_0_REG, SYSTEM_CONTROL_CORE_1_RESETTING);
224 }
225 #endif
226 ets_set_appcpu_boot_addr(entry_addr);
227 ets_delay_us(10000);
228 uart_tx_wait_idle(0);
229 ESP_LOGI(TAG, "APPCPU start sequence complete");
230 }
231
start_cpu1_image(int image_index,int slot,unsigned int hdr_offset)232 void start_cpu1_image(int image_index, int slot, unsigned int hdr_offset)
233 {
234 unsigned int entry_addr;
235 esp_app_image_load(image_index, slot, hdr_offset, &entry_addr);
236 appcpu_start(entry_addr);
237 }
238 #endif
239