1 /*
2  * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 #include <errno.h>
9 #include "esp_log.h"
10 #include "bootloader_flash_priv.h"
11 #include <zephyr/storage/flash_map.h>
12 #include "esp_app_format.h"
13 #include "bootloader_common.h"
14 #include "hal/efuse_ll.h"
15 #include "hal/efuse_hal.h"
16 #include "soc/chip_revision.h"
17 #include <hal/wdt_hal.h>
18 #include "soc_init.h"
19 
20 #define IS_MAX_REV_SET(max_chip_rev_full)                                                          \
21 	(((max_chip_rev_full) != 65535) && ((max_chip_rev_full) != 0))
22 
23 static const char *TAG = "soc_init";
24 
25 extern esp_image_header_t WORD_ALIGNED_ATTR bootloader_image_hdr;
26 
print_banner(void)27 void print_banner(void)
28 {
29 #ifdef CONFIG_MCUBOOT
30 	ESP_EARLY_LOGI(TAG, "MCUboot 2nd stage bootloader");
31 #elif CONFIG_BOOTLOADER_MCUBOOT
32 	ESP_EARLY_LOGI(TAG, "MCUboot Application image");
33 #else /* CONFIG_ESP_SIMPLE_BOOT */
34 	ESP_EARLY_LOGI(TAG, "ESP Simple boot");
35 #endif
36 	ESP_EARLY_LOGI(TAG, "compile time " __DATE__ " " __TIME__);
37 #ifndef CONFIG_SMP
38 #if (SOC_CPU_CORES_NUM > 1)
39 	ESP_EARLY_LOGW(TAG, "Unicore bootloader");
40 #endif
41 #else
42 	ESP_EARLY_LOGI(TAG, "Multicore bootloader");
43 #endif
44 }
45 
read_bootloader_header(void)46 int read_bootloader_header(void)
47 {
48 	/* load bootloader image header */
49 	if (esp_rom_flash_read(FIXED_PARTITION_OFFSET(boot_partition), &bootloader_image_hdr,
50 				      sizeof(esp_image_header_t), true) != 0) {
51 		ESP_EARLY_LOGE(TAG, "failed to load bootloader image header!");
52 		return -EIO;
53 	}
54 
55 	return 0;
56 }
57 
check_chip_validity(const esp_image_header_t * img_hdr,esp_image_type type)58 static int check_chip_validity(const esp_image_header_t *img_hdr, esp_image_type type)
59 {
60 	int err = 0;
61 	esp_chip_id_t chip_id = CONFIG_IDF_FIRMWARE_CHIP_ID;
62 
63 	if (chip_id != img_hdr->chip_id) {
64 		ESP_EARLY_LOGE(TAG, "mismatch chip ID, expected %d, found %d", chip_id,
65 			       img_hdr->chip_id);
66 		err = -EIO;
67 	} else {
68 		unsigned int revision = efuse_hal_chip_revision();
69 		unsigned int major_rev = revision / 100;
70 		unsigned int minor_rev = revision % 100;
71 		unsigned int min_rev = img_hdr->min_chip_rev_full;
72 
73 		if (type == ESP_IMAGE_BOOTLOADER || type == ESP_IMAGE_APPLICATION) {
74 			if (!ESP_CHIP_REV_ABOVE(revision, min_rev)) {
75 				ESP_EARLY_LOGE(
76 					TAG,
77 					"Image requires chip rev >= v%d.%d, but chip is v%d.%d",
78 					min_rev / 100, min_rev % 100, major_rev, minor_rev);
79 				err = ESP_FAIL;
80 			}
81 		}
82 		if (type == ESP_IMAGE_APPLICATION) {
83 			unsigned int max_rev = img_hdr->max_chip_rev_full;
84 
85 			if ((IS_MAX_REV_SET(max_rev) && (revision > max_rev) &&
86 			     !efuse_ll_get_disable_wafer_version_major())) {
87 				ESP_EARLY_LOGE(
88 					TAG,
89 					"Image requires chip rev <= v%d.%d, but chip is v%d.%d",
90 					max_rev / 100, max_rev % 100, major_rev, minor_rev);
91 				err = ESP_FAIL;
92 			}
93 		}
94 	}
95 
96 	return err;
97 }
98 
config_wdt(void)99 void config_wdt(void)
100 {
101 	/*
102 	 * At this point, the flashboot protection of RWDT and MWDT0 will have been
103 	 * automatically enabled. We can disable flashboot protection as it's not
104 	 * needed anymore. If configured to do so, we also initialize the RWDT to
105 	 * protect the remainder of the bootloader process.
106 	 */
107 	wdt_hal_context_t rwdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
108 
109 	wdt_hal_write_protect_disable(&rwdt_ctx);
110 	wdt_hal_set_flashboot_en(&rwdt_ctx, false);
111 	wdt_hal_write_protect_enable(&rwdt_ctx);
112 
113 	/* Disable MWDT0 flashboot protection. But only after we've enabled the RWDT first so that
114 	 * there's not gap in WDT protection.
115 	 */
116 	wdt_hal_context_t mwdt_ctx = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
117 
118 	wdt_hal_write_protect_disable(&mwdt_ctx);
119 	wdt_hal_set_flashboot_en(&mwdt_ctx, false);
120 	wdt_hal_write_protect_enable(&mwdt_ctx);
121 }
122 
check_bootloader_validity(void)123 int check_bootloader_validity(void)
124 {
125 	unsigned int revision = efuse_hal_chip_revision();
126 	unsigned int major = revision / 100;
127 	unsigned int minor = revision % 100;
128 
129 	ESP_EARLY_LOGI(TAG, "chip revision: v%d.%d", major, minor);
130 
131 #ifndef CONFIG_MCUBOOT
132 #if defined(CONFIG_SOC_SERIES_ESP32)
133 	if (major < 3) {
134 		ESP_EARLY_LOGE(TAG,
135 			       "You are using ESP32 chip revision (%d) that is unsupported. While "
136 			       "it may work, it could cause unexpected behavior or issues.",
137 			       major);
138 		ESP_EARLY_LOGE(TAG,
139 			       "Proceeding with this ESP32 chip revision is not recommended unless "
140 			       "you fully understand the potential risk and limitations.");
141 #if !defined(CONFIG_ESP32_USE_UNSUPPORTED_REVISION)
142 		ESP_EARLY_LOGE(
143 			TAG,
144 			"If you choose to continue, please enable "
145 			"'CONFIG_ESP32_USE_UNSUPPORTED_REVISION=y' in your project configuration.");
146 		config_wdt(); // disable watchdog to avoid reset
147 		abort();
148 #endif /* !CONFIG_ESP32_USE_UNSUPPORTED_REVISION */
149 	}
150 #endif /* CONFIG_SOC_SERIES_ESP32 */
151 #endif /* CONFIG_MCUBOOT */
152 
153 	/* compare with the one set in bootloader image header */
154 	if (check_chip_validity(&bootloader_image_hdr, ESP_IMAGE_BOOTLOADER) != 0) {
155 		return ESP_FAIL;
156 	}
157 	return 0;
158 }
159