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