1 /*
2  * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <stdint.h>
7 #include "sdkconfig.h"
8 #include "esp_attr.h"
9 #include "esp_log.h"
10 #include "esp_image_format.h"
11 #include "flash_qio_mode.h"
12 
13 #include "bootloader_init.h"
14 #include "bootloader_clock.h"
15 #include "bootloader_common.h"
16 #include "bootloader_flash_config.h"
17 #include "bootloader_mem.h"
18 #include "bootloader_console.h"
19 #include "bootloader_flash_priv.h"
20 #include "esp_private/bootloader_flash_internal.h"
21 #include "esp_cpu.h"
22 #include "soc/dport_reg.h"
23 #include "soc/efuse_reg.h"
24 #include "soc/gpio_periph.h"
25 #include "soc/gpio_sig_map.h"
26 #include "soc/io_mux_reg.h"
27 #include "soc/rtc.h"
28 #include "soc/spi_periph.h"
29 #include "hal/gpio_hal.h"
30 #include "xtensa/config/core.h"
31 #include "xt_instr_macros.h"
32 
33 #include "esp32/rom/cache.h"
34 #include "esp_rom_gpio.h"
35 #include "esp_rom_efuse.h"
36 #include "esp_rom_sys.h"
37 #include "esp_rom_spiflash.h"
38 #include "esp_efuse.h"
39 #include "esp_flash_internal.h"
40 
41 static const char *TAG = "boot.esp32";
42 
43 #if !CONFIG_APP_BUILD_TYPE_RAM
bootloader_reset_mmu(void)44 static void bootloader_reset_mmu(void)
45 {
46     /* completely reset MMU in case serial bootloader was running */
47     Cache_Read_Disable(0);
48 #if !CONFIG_FREERTOS_UNICORE
49     Cache_Read_Disable(1);
50 #endif
51     Cache_Flush(0);
52 #if !CONFIG_FREERTOS_UNICORE
53     Cache_Flush(1);
54 #endif
55     mmu_init(0);
56 #if !CONFIG_FREERTOS_UNICORE
57     /* The lines which manipulate DPORT_APP_CACHE_MMU_IA_CLR bit are
58         necessary to work around a hardware bug. */
59     DPORT_REG_SET_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
60     mmu_init(1);
61     DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
62 #endif
63 
64     /* normal ROM boot exits with DROM0 cache unmasked,
65         but serial bootloader exits with it masked. */
66     DPORT_REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DROM0);
67 #if !CONFIG_FREERTOS_UNICORE
68     DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DROM0);
69 #endif
70 }
71 #endif //#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
72 
bootloader_check_rated_cpu_clock(void)73 static esp_err_t bootloader_check_rated_cpu_clock(void)
74 {
75     int rated_freq = bootloader_clock_get_rated_freq_mhz();
76     if (rated_freq < CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ) {
77         ESP_LOGE(TAG, "Chip CPU frequency rated for %dMHz, configured for %dMHz. Modify CPU frequency in menuconfig",
78                  rated_freq, CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ);
79         return ESP_FAIL;
80     }
81     return ESP_OK;
82 }
83 
wdt_reset_cpu0_info_enable(void)84 static void wdt_reset_cpu0_info_enable(void)
85 {
86     //We do not reset core1 info here because it didn't work before cpu1 was up. So we put it into call_start_cpu1.
87     DPORT_REG_SET_BIT(DPORT_PRO_CPU_RECORD_CTRL_REG, DPORT_PRO_CPU_PDEBUG_ENABLE | DPORT_PRO_CPU_RECORD_ENABLE);
88     DPORT_REG_CLR_BIT(DPORT_PRO_CPU_RECORD_CTRL_REG, DPORT_PRO_CPU_RECORD_ENABLE);
89 }
90 
wdt_reset_info_dump(int cpu)91 static void wdt_reset_info_dump(int cpu)
92 {
93     uint32_t inst = 0, pid = 0, stat = 0, data = 0, pc = 0,
94              lsstat = 0, lsaddr = 0, lsdata = 0, dstat = 0;
95     const char *cpu_name = cpu ? "APP" : "PRO";
96 
97     if (cpu == 0) {
98         stat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_STATUS_REG);
99         pid = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PID_REG);
100         inst = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGINST_REG);
101         dstat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGSTATUS_REG);
102         data = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGDATA_REG);
103         pc = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGPC_REG);
104         lsstat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0STAT_REG);
105         lsaddr = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0ADDR_REG);
106         lsdata = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0DATA_REG);
107     } else {
108 #if !CONFIG_FREERTOS_UNICORE
109         stat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_STATUS_REG);
110         pid = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PID_REG);
111         inst = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGINST_REG);
112         dstat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGSTATUS_REG);
113         data = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGDATA_REG);
114         pc = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGPC_REG);
115         lsstat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0STAT_REG);
116         lsaddr = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0ADDR_REG);
117         lsdata = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0DATA_REG);
118 #endif
119     }
120 
121     if (DPORT_RECORD_PDEBUGINST_SZ(inst) == 0 &&
122             DPORT_RECORD_PDEBUGSTATUS_BBCAUSE(dstat) == DPORT_RECORD_PDEBUGSTATUS_BBCAUSE_WAITI) {
123         ESP_LOGW(TAG, "WDT reset info: %s CPU PC=0x%"PRIx32" (waiti mode)", cpu_name, pc);
124     } else {
125         ESP_LOGW(TAG, "WDT reset info: %s CPU PC=0x%"PRIx32, cpu_name, pc);
126     }
127     ESP_LOGD(TAG, "WDT reset info: %s CPU STATUS        0x%08"PRIx32, cpu_name, stat);
128     ESP_LOGD(TAG, "WDT reset info: %s CPU PID           0x%08"PRIx32, cpu_name, pid);
129     ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGINST    0x%08"PRIx32, cpu_name, inst);
130     ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGSTATUS  0x%08"PRIx32, cpu_name, dstat);
131     ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGDATA    0x%08"PRIx32, cpu_name, data);
132     ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGPC      0x%08"PRIx32, cpu_name, pc);
133     ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0STAT 0x%08"PRIx32, cpu_name, lsstat);
134     ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0ADDR 0x%08"PRIx32, cpu_name, lsaddr);
135     ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0DATA 0x%08"PRIx32, cpu_name, lsdata);
136 }
137 
bootloader_check_wdt_reset(void)138 static void bootloader_check_wdt_reset(void)
139 {
140     int wdt_rst = 0;
141     soc_reset_reason_t rst_reas[2];
142 
143     rst_reas[0] = esp_rom_get_reset_reason(0);
144     rst_reas[1] = esp_rom_get_reset_reason(1);
145     if (rst_reas[0] == RESET_REASON_CORE_RTC_WDT || rst_reas[0] == RESET_REASON_CORE_MWDT0 || rst_reas[0] == RESET_REASON_CORE_MWDT1 ||
146         rst_reas[0] == RESET_REASON_CPU0_MWDT0 || rst_reas[0] == RESET_REASON_CPU0_RTC_WDT) {
147         ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
148         wdt_rst = 1;
149     }
150     if (rst_reas[1] == RESET_REASON_CORE_RTC_WDT || rst_reas[1] == RESET_REASON_CORE_MWDT0 || rst_reas[1] == RESET_REASON_CORE_MWDT1 ||
151         rst_reas[1] == RESET_REASON_CPU1_MWDT1 || rst_reas[1] == RESET_REASON_CPU1_RTC_WDT) {
152         ESP_LOGW(TAG, "APP CPU has been reset by WDT.");
153         wdt_rst = 1;
154     }
155     if (wdt_rst) {
156         // if reset by WDT dump info from trace port
157         wdt_reset_info_dump(0);
158 #if !CONFIG_FREERTOS_UNICORE
159         wdt_reset_info_dump(1);
160 #endif
161     }
162     wdt_reset_cpu0_info_enable();
163 }
164 
bootloader_init(void)165 esp_err_t bootloader_init(void)
166 {
167     esp_err_t ret = ESP_OK;
168 
169 #if XCHAL_ERRATUM_572
170     uint32_t memctl = XCHAL_CACHE_MEMCTL_DEFAULT;
171     WSR(MEMCTL, memctl);
172 #endif // XCHAL_ERRATUM_572
173 
174 // In RAM_APP, memory will be initialized in `call_start_cpu0`
175 #if !CONFIG_APP_BUILD_TYPE_RAM
176     bootloader_init_mem();
177 
178     // check that static RAM is after the stack
179 #ifndef NDEBUG
180     {
181         assert(&_bss_start <= &_bss_end);
182         assert(&_data_start <= &_data_end);
183         // int *sp = esp_cpu_get_sp();
184         // assert((unsigned*)sp < (unsigned*)&_bss_start);
185         // assert((unsigned*)sp < (unsigned*)&_data_start);
186     }
187 #endif
188 #ifndef __ZEPHYR__
189     // clear bss section
190     bootloader_clear_bss_section();
191 #endif
192 #endif // !CONFIG_APP_BUILD_TYPE_RAM
193 
194     // init eFuse virtual mode (read eFuses to RAM)
195 #ifdef CONFIG_EFUSE_VIRTUAL
196     ESP_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
197 #ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
198     esp_efuse_init_virtual_mode_in_ram();
199 #endif
200 #endif /* CONFIG_EFUSE_VIRTUAL */
201     // bootst up vddsdio
202     bootloader_common_vddsdio_configure();
203     // check rated CPU clock
204     if ((ret = bootloader_check_rated_cpu_clock()) != ESP_OK) {
205         return ret;
206     }
207     // config clock
208     bootloader_clock_configure();
209     // initialize uart console, from now on, we can use esp_log
210     bootloader_console_init();
211     // print 2nd bootloader banner
212     bootloader_print_banner();
213 
214 #ifndef CONFIG_BOOTLOADER_MCUBOOT
215     spi_flash_init_chip_state();
216     if ((ret = esp_flash_init_default_chip()) != ESP_OK) {
217         return ret;
218     }
219 #endif
220 
221 #if !CONFIG_APP_BUILD_TYPE_RAM
222     // reset MMU
223     bootloader_reset_mmu();
224     // update flash ID
225     bootloader_flash_update_id();
226     // Check and run XMC startup flow
227     if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
228         ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
229         return ret;
230     }
231     // read bootloader header
232     if ((ret = bootloader_read_bootloader_header()) != ESP_OK) {
233         return ret;
234     }
235     // read chip revision and check if it's compatible to bootloader
236     if ((ret = bootloader_check_bootloader_validity()) != ESP_OK) {
237         return ret;
238     }
239     // initialize spi flash
240     if ((ret = bootloader_init_spi_flash()) != ESP_OK) {
241         return ret;
242     }
243 #endif // #if !CONFIG_APP_BUILD_TYPE_RAM
244 
245     // check whether a WDT reset happend
246     bootloader_check_wdt_reset();
247     // config WDT
248     bootloader_config_wdt();
249     // enable RNG early entropy source
250     bootloader_enable_random();
251 
252     return ret;
253 }
254