1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
33
34
39
40
45
46
47
48
49
50
51
52
53
54
55
56
57
58
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
91
92
98
99
100
101
102
103
104
105
106
107
108
109
111
112
114
115
116
117
118
119
120
121
122
123
126
127
128
131
132
133
135
136
140
141
142
146
147
148
149
150
151
152
153
154
155
156
157
161
162
163
164
168
169
175
176
177
178
182
183
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
225
226
227
238
239
240
241
242
243
244
245
246
249
253
254
255
256
257
258
259
260
261
262
263
281
282
283
284
285
286
287
288
289
290
291
292
293
297
298
299
300
301
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
332
333
334
335
336
337
338
341
342
343
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
364
365
366
367
368
369
370
374
375
379
383
384
385
386
387
388
389
390
391
392
393
394
395
400
401
406
407
412
413
414
415
416
417
421
422
429
430
431
432
437
438
443
444
449
450
451
452
453
459
460
461
465
466
467
471
472
476
477
478
479
482
483
484
485
486
487
488
489
490
491
492
493
494
495
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
532
533
534
535
536
537
540
541
542
543
544
545
546
547
548
549
553
556
557
558
559
560
561
562
563
564
565
568
569
570
571
572
578
579
580
581
588
589
590
591
592
593
594
595
597
598
599
600
601
602
603
604
605
606
607
608
609
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
642
645
646
647
648
649
650
651
652
653
654
655
659
660
661
666
667
679
680
681
691
692
693
694
695
696
697
698
699
700
701
702
709
710
715
716
717
718
719
720
721
724
725
729
730
731
732
733
734
738
739
740
746
747
748
749
750
751
752
753
754
755
761
762
763
764
765
766
767
768
769
773
774
775
776
779
780
784
785
786
787
788
789
790
791
794
795
796
797
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
824
825
826
829
830
837
838
857
858
859
860
861
870
871
872
873
876
880
881
882
883
884
885
886
887
888
895
896
897
898
899
900
901
910
911
912
913
914
917
918
919
920
921
922
925
926
927
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
947
948
949
952
955
956
957
958
959
962
963
964
965
966
967
968
969
970
971
972
973
974
975
980
981
982
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1006
1007
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1028
1029
1030
1031
1032
1033
1034
1035
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1071
1073
1075
1077
1079
1081
1083
1085
1087
1088
/* ... */
#include <string.h>
#include <sys/param.h>
#include <esp_cpu.h>
#include <bootloader_utility.h>
#include <esp_secure_boot.h>
#include <esp_fault.h>
#include <esp_log.h>
#include <esp_attr.h>
#include <bootloader_flash_priv.h>
#include <bootloader_random.h>
#include <bootloader_sha.h>
#include "bootloader_util.h"
#include "bootloader_common.h"
#include "esp_rom_sys.h"
#include "esp_efuse.h"
#include "esp_app_desc.h"
#include "bootloader_memory_utils.h"
#include "soc/soc_caps.h"
#include "hal/cache_ll.h"
#include "spi_flash_mmap.h"20 includes
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
/* ... */
#ifdef BOOTLOADER_BUILD
#ifdef CONFIG_SECURE_SIGNED_ON_BOOT
#define SECURE_BOOT_CHECK_SIGNATURE 1
#else
#define SECURE_BOOT_CHECK_SIGNATURE 0
#endif/* ... */
#else
#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE
#define SECURE_BOOT_CHECK_SIGNATURE 1
#else
#define SECURE_BOOT_CHECK_SIGNATURE 0
#endif/* ... */
#endif
static const char *TAG = "esp_image";
#define HASH_LEN ESP_IMAGE_HASH_LEN
#define SIXTEEN_MB 0x1000000
#define ESP_ROM_CHECKSUM_INITIAL 0xEF
#define STACK_LOAD_HEADROOM 32768
#ifdef BOOTLOADER_BUILD
/* ... */
static uint32_t ram_obfs_value[2];
/* ... */
#endif
static bool should_load(uint32_t load_addr);
static bool should_map(uint32_t load_addr);
static esp_err_t process_segments(esp_image_metadata_t *data, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum);
static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segment_header_t *header, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum, esp_image_metadata_t *metadata);
static esp_err_t process_segment_data(int segment, intptr_t load_addr, uint32_t data_addr, uint32_t data_len, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum, esp_image_metadata_t *metadata);
static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t *image, bool silent);
static esp_err_t verify_segment_header(int index, const esp_image_segment_header_t *segment, uint32_t segment_data_offs, esp_image_metadata_t *metadata, bool silent);
#define FAIL_LOAD(...) do { \
if (!silent) { \
ESP_LOGE(TAG, __VA_ARGS__); \
}{...} \
goto err; \
}{...} \
while(0)...
#define CHECK_ERR(func) do { \
if ((err = func) != ESP_OK) { \
goto err; \
}{...} \
}{...} \
while(0)...
static esp_err_t process_image_header(esp_image_metadata_t *data, uint32_t part_offset, bootloader_sha256_handle_t *sha_handle, bool do_verify, bool silent);
static esp_err_t process_appended_hash_and_sig(esp_image_metadata_t *data, uint32_t part_offset, uint32_t part_len, bool do_verify, bool silent);
static esp_err_t process_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data, bool silent, bool skip_check_checksum);
static esp_err_t __attribute__((unused)) verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data, uint8_t *image_digest, uint8_t *verified_digest);
static esp_err_t __attribute__((unused)) verify_simple_hash(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data);
static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data)
{
#ifdef BOOTLOADER_BUILD
bool do_load = (mode == ESP_IMAGE_LOAD) || (mode == ESP_IMAGE_LOAD_NO_VALIDATE);
bool do_verify = (mode == ESP_IMAGE_LOAD) || (mode == ESP_IMAGE_VERIFY) || (mode == ESP_IMAGE_VERIFY_SILENT);/* ... */
#else
bool do_load = false;
bool do_verify = true; /* ... */
#endif
bool silent = (mode == ESP_IMAGE_VERIFY_SILENT);
esp_err_t err = ESP_OK;
uint32_t checksum_word = ESP_ROM_CHECKSUM_INITIAL;
uint32_t *checksum = (do_verify) ? &checksum_word : NULL;
bootloader_sha256_handle_t sha_handle = NULL;
bool verify_sha;
#if (SECURE_BOOT_CHECK_SIGNATURE == 1)
uint8_t image_digest[HASH_LEN] = { [ 0 ... 31] = 0xEE };
uint8_t verified_digest[HASH_LEN] = { [ 0 ... 31 ] = 0x01 };/* ... */
#endif
if (data == NULL || part == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
#if CONFIG_SECURE_BOOT_V2_ENABLED
verify_sha = do_verify;/* ... */
#else
verify_sha = (part->offset != ESP_BOOTLOADER_OFFSET) && do_verify;/* ... */
#endif
if (part->size > SIXTEEN_MB) {
err = ESP_ERR_INVALID_ARG;
FAIL_LOAD("partition size 0x%"PRIx32" invalid, larger than 16MB", part->size);
}{...}
bootloader_sha256_handle_t *p_sha_handle = &sha_handle;
CHECK_ERR(process_image_header(data, part->offset, (verify_sha) ? p_sha_handle : NULL, do_verify, silent));
CHECK_ERR(process_segments(data, silent, do_load, sha_handle, checksum));
bool skip_check_checksum = !do_verify || esp_cpu_dbgr_is_attached();
CHECK_ERR(process_checksum(sha_handle, checksum_word, data, silent, skip_check_checksum));
CHECK_ERR(process_appended_hash_and_sig(data, part->offset, part->size, do_verify, silent));
if (verify_sha) {
#if (SECURE_BOOT_CHECK_SIGNATURE == 1)
#if defined(BOOTLOADER_BUILD) && !defined(CONFIG_SECURE_BOOT)
bool do_verify_sig = !esp_cpu_dbgr_is_attached();/* ... */
#else
bool do_verify_sig = true;
#endif
if (do_verify_sig) {
err = verify_secure_boot_signature(sha_handle, data, image_digest, verified_digest);
sha_handle = NULL;
}{...}
#else/* ... */
if (sha_handle != NULL && !esp_cpu_dbgr_is_attached()) {
err = verify_simple_hash(sha_handle, data);
sha_handle = NULL;
}{...}
#endif/* ... */
}{...}
if (sha_handle != NULL) {
bootloader_sha256_finish(sha_handle, NULL);
sha_handle = NULL;
}{...}
if (err != ESP_OK) {
goto err;
}{...}
#ifdef BOOTLOADER_BUILD
#if (SECURE_BOOT_CHECK_SIGNATURE == 1)
/* ... */
#if CONFIG_SECURE_BOOT_V2_ENABLED
ESP_FAULT_ASSERT(!esp_secure_boot_enabled() || memcmp(image_digest, verified_digest, HASH_LEN) == 0);
#else
ESP_FAULT_ASSERT(data->start_addr == ESP_BOOTLOADER_OFFSET || memcmp(image_digest, verified_digest, HASH_LEN) == 0);
#endif
/* ... */
#endif
if (do_load && ram_obfs_value[0] != 0 && ram_obfs_value[1] != 0) {
for (int i = 0; i < data->image.segment_count; i++) {
uint32_t load_addr = data->segments[i].load_addr;
if (should_load(load_addr)) {
uint32_t *loaded = (uint32_t *)load_addr;
for (size_t j = 0; j < data->segments[i].data_len / sizeof(uint32_t); j++) {
loaded[j] ^= (j & 1) ? ram_obfs_value[0] : ram_obfs_value[1];
}{...}
}{...}
}{...}
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
/* ... */
cache_ll_writeback_all(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA, CACHE_LL_ID_ALL);/* ... */
#endif
}{...}
#if CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
bool sec_ver = false;
if (do_load) {
sec_ver = esp_efuse_check_secure_version(data->secure_version);
if (!sec_ver) {
err = ESP_FAIL;
goto err;
}{...}
}{...}
ESP_FAULT_ASSERT(!do_load || sec_ver == true);/* ... */
#endif
/* ... */
#endif
return ESP_OK;
err:
if (err == ESP_OK) {
err = ESP_ERR_IMAGE_INVALID;
}{...}
if (sha_handle != NULL) {
bootloader_sha256_finish(sha_handle, NULL);
}{...}
bzero(data, sizeof(esp_image_metadata_t));
return err;
}{ ... }
esp_err_t bootloader_load_image(const esp_partition_pos_t *part, esp_image_metadata_t *data)
{
#if !defined(BOOTLOADER_BUILD)
return ESP_FAIL;
#else
esp_image_load_mode_t mode = ESP_IMAGE_LOAD;
#if !defined(CONFIG_SECURE_BOOT)
#if CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS
mode = ESP_IMAGE_LOAD_NO_VALIDATE;
#elif CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON
if (esp_rom_get_reset_reason(0) == RESET_REASON_CHIP_POWER_ON
#if SOC_EFUSE_HAS_EFUSE_RST_BUG
|| esp_rom_get_reset_reason(0) == RESET_REASON_CORE_EFUSE_CRC
#endif
) {
mode = ESP_IMAGE_LOAD_NO_VALIDATE;
}{...}
#endif/* ... */ /* ... */
#endif
return image_load(mode, part, data);/* ... */
#endif
}{ ... }
esp_err_t bootloader_load_image_no_verify(const esp_partition_pos_t *part, esp_image_metadata_t *data)
{
#ifdef BOOTLOADER_BUILD
return image_load(ESP_IMAGE_LOAD_NO_VALIDATE, part, data);
#else
return ESP_FAIL;
#endif
}{ ... }
esp_err_t esp_image_verify(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data)
{
return image_load(mode, part, data);
}{ ... }
esp_err_t esp_image_get_metadata(const esp_partition_pos_t *part, esp_image_metadata_t *metadata)
{
esp_err_t err;
if (metadata == NULL || part == NULL || part->size > SIXTEEN_MB) {
return ESP_ERR_INVALID_ARG;
}{...}
bool silent = true;
bool do_verify = false;
bool do_load = false;
CHECK_ERR(process_image_header(metadata, part->offset, NULL, do_verify, silent));
CHECK_ERR(process_segments(metadata, silent, do_load, NULL, NULL));
bool skip_check_checksum = true;
CHECK_ERR(process_checksum(NULL, 0, metadata, silent, skip_check_checksum));
CHECK_ERR(process_appended_hash_and_sig(metadata, part->offset, part->size, true, silent));
return ESP_OK;
err:
return err;
}{ ... }
static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t *image, bool silent)
{
esp_err_t err = ESP_OK;
ESP_LOGD(TAG, "image header: 0x%02x 0x%02x 0x%02x 0x%02x %08"PRIx32,
image->magic,
image->segment_count,
image->spi_mode,
image->spi_size,
image->entry_addr);
if (image->magic != ESP_IMAGE_HEADER_MAGIC) {
FAIL_LOAD("image at 0x%"PRIx32" has invalid magic byte (nothing flashed here?)", src_addr);
}{...}
CHECK_ERR(bootloader_common_check_chip_validity(image, ESP_IMAGE_APPLICATION));
if (image->segment_count > ESP_IMAGE_MAX_SEGMENTS) {
FAIL_LOAD("image at 0x%"PRIx32" segment count %d exceeds max %d", src_addr, image->segment_count, ESP_IMAGE_MAX_SEGMENTS);
}{...}
return err;
err:
if (err == ESP_OK) {
err = ESP_ERR_IMAGE_INVALID;
}{...}
return err;
}{ ... }
#ifdef BOOTLOADER_BUILD
/* ... */
static bool verify_load_addresses(int segment_index, intptr_t load_addr, intptr_t load_end, bool print_error, bool no_recurse)
{
const char *reason = NULL;
extern int _dram_start, _dram_end, _loader_text_start, _loader_text_end;
void *load_addr_p = (void *)load_addr;
void *load_inclusive_end_p = (void *)load_end - 0x1;
void *load_exclusive_end_p = (void *)load_end;
if (load_end == load_addr) {
return true;
}{...}
assert(load_end > load_addr);
if (esp_ptr_in_dram(load_addr_p) && esp_ptr_in_dram(load_inclusive_end_p)) {
intptr_t sp = (intptr_t)esp_cpu_get_sp();
if (bootloader_util_regions_overlap(sp - STACK_LOAD_HEADROOM, SOC_ROM_STACK_START,
load_addr, load_end)) {
reason = "overlaps bootloader stack";
goto invalid;
}{...}
/* ... */
if (bootloader_util_regions_overlap((intptr_t)&_dram_start, (intptr_t)&_dram_end, load_addr, load_end)) {
reason = "overlaps bootloader data";
goto invalid;
}{...}
/* ... */
if (!no_recurse && bootloader_util_regions_overlap(SOC_DIRAM_DRAM_LOW, SOC_DIRAM_DRAM_HIGH, load_addr, load_end)) {
intptr_t iram_load_addr, iram_load_end;
if (esp_ptr_in_diram_dram(load_addr_p)) {
iram_load_addr = (intptr_t)esp_ptr_diram_dram_to_iram(load_addr_p);
}{...} else {
iram_load_addr = (intptr_t)esp_ptr_diram_dram_to_iram((void *)SOC_DIRAM_DRAM_LOW);
}{...}
if (esp_ptr_in_diram_dram(load_inclusive_end_p)) {
iram_load_end = (intptr_t)esp_ptr_diram_dram_to_iram(load_exclusive_end_p);
}{...} else {
iram_load_end = (intptr_t)esp_ptr_diram_dram_to_iram((void *)SOC_DIRAM_DRAM_HIGH);
}{...}
if (iram_load_end < iram_load_addr) {
return verify_load_addresses(segment_index, iram_load_end, iram_load_addr, print_error, true);
}{...} else {
return verify_load_addresses(segment_index, iram_load_addr, iram_load_end, print_error, true);
}{...}
}{...}
}{...}
else if (esp_ptr_in_iram(load_addr_p) && esp_ptr_in_iram(load_inclusive_end_p)) {
if (bootloader_util_regions_overlap((intptr_t)&_loader_text_start, (intptr_t)&_loader_text_end,
load_addr, load_end)) {
reason = "overlaps loader IRAM";
goto invalid;
}{...}
/* ... */
if (!no_recurse && bootloader_util_regions_overlap(SOC_DIRAM_IRAM_LOW, SOC_DIRAM_IRAM_HIGH, load_addr, load_end)) {
intptr_t dram_load_addr, dram_load_end;
if (esp_ptr_in_diram_iram(load_addr_p)) {
dram_load_addr = (intptr_t)esp_ptr_diram_iram_to_dram(load_addr_p);
}{...} else {
dram_load_addr = (intptr_t)esp_ptr_diram_iram_to_dram((void *)SOC_DIRAM_IRAM_LOW);
}{...}
if (esp_ptr_in_diram_iram(load_inclusive_end_p)) {
dram_load_end = (intptr_t)esp_ptr_diram_iram_to_dram(load_exclusive_end_p);
}{...} else {
dram_load_end = (intptr_t)esp_ptr_diram_iram_to_dram((void *)SOC_DIRAM_IRAM_HIGH);
}{...}
if (dram_load_end < dram_load_addr) {
return verify_load_addresses(segment_index, dram_load_end, dram_load_addr, print_error, true);
}{...} else {
return verify_load_addresses(segment_index, dram_load_addr, dram_load_end, print_error, true);
}{...}
}{...}
}{...}
#if SOC_RTC_FAST_MEM_SUPPORTED
else if (esp_ptr_in_rtc_iram_fast(load_addr_p) && esp_ptr_in_rtc_iram_fast(load_inclusive_end_p)){
return true;
}{...} else if (esp_ptr_in_rtc_dram_fast(load_addr_p) && esp_ptr_in_rtc_dram_fast(load_inclusive_end_p)){
return true;
}{...}
/* ... */#endif
#if SOC_RTC_SLOW_MEM_SUPPORTED
else if (esp_ptr_in_rtc_slow(load_addr_p) && esp_ptr_in_rtc_slow(load_inclusive_end_p)) {
return true;
}{...}
/* ... */#endif
#if SOC_MEM_TCM_SUPPORTED
else if (esp_ptr_in_tcm(load_addr_p) && esp_ptr_in_tcm(load_inclusive_end_p)) {
return true;
}{...}
/* ... */#endif
else {
reason = "bad load address range";
goto invalid;
}{...}
return true;
invalid:
if (print_error) {
ESP_LOGE(TAG, "Segment %d 0x%08x-0x%08x invalid: %s", segment_index, load_addr, load_end, reason);
}{...}
return false;
}{...}
/* ... */#endif
static esp_err_t process_image_header(esp_image_metadata_t *data, uint32_t part_offset, bootloader_sha256_handle_t *sha_handle, bool do_verify, bool silent)
{
esp_err_t err;
bzero(data, sizeof(esp_image_metadata_t));
data->start_addr = part_offset;
ESP_LOGD(TAG, "reading image header @ 0x%"PRIx32, data->start_addr);
CHECK_ERR(bootloader_flash_read(data->start_addr, &data->image, sizeof(esp_image_header_t), true));
if (do_verify) {
if (SECURE_BOOT_CHECK_SIGNATURE || data->image.hash_appended) {
if (sha_handle != NULL) {
*sha_handle = bootloader_sha256_start();
if (*sha_handle == NULL) {
return ESP_ERR_NO_MEM;
}{...}
bootloader_sha256_data(*sha_handle, &data->image, sizeof(esp_image_header_t));
}{...}
}{...}
CHECK_ERR(verify_image_header(data->start_addr, &data->image, silent));
}{...}
data->image_len = sizeof(esp_image_header_t);
return ESP_OK;
err:
return err;
}{ ... }
static esp_err_t process_segments(esp_image_metadata_t *data, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum)
{
esp_err_t err = ESP_OK;
uint32_t start_segments = data->start_addr + data->image_len;
uint32_t next_addr = start_segments;
for (int i = 0; i < data->image.segment_count; i++) {
esp_image_segment_header_t *header = &data->segments[i];
ESP_LOGV(TAG, "loading segment header %d at offset 0x%"PRIx32, i, next_addr);
CHECK_ERR(process_segment(i, next_addr, header, silent, do_load, sha_handle, checksum, data));
next_addr += sizeof(esp_image_segment_header_t);
data->segment_data[i] = next_addr;
next_addr += header->data_len;
}{...}
uint32_t end_addr = next_addr;
if (end_addr < data->start_addr) {
FAIL_LOAD("image offset has wrapped");
}{...}
data->image_len += end_addr - start_segments;
ESP_LOGV(TAG, "image start 0x%08"PRIx32" end of last section 0x%08"PRIx32, data->start_addr, end_addr);
return err;
err:
if (err == ESP_OK) {
err = ESP_ERR_IMAGE_INVALID;
}{...}
return err;
}{ ... }
static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segment_header_t *header, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum, esp_image_metadata_t *metadata)
{
esp_err_t err;
err = bootloader_flash_read(flash_addr, header, sizeof(esp_image_segment_header_t), true);
if (err != ESP_OK) {
ESP_LOGE(TAG, "bootloader_flash_read failed at 0x%08"PRIx32, flash_addr);
return err;
}{...}
if (sha_handle != NULL) {
bootloader_sha256_data(sha_handle, header, sizeof(esp_image_segment_header_t));
}{...}
intptr_t load_addr = header->load_addr;
uint32_t data_len = header->data_len;
uint32_t data_addr = flash_addr + sizeof(esp_image_segment_header_t);
ESP_LOGV(TAG, "segment data length 0x%"PRIx32" data starts 0x%"PRIx32, data_len, data_addr);
CHECK_ERR(verify_segment_header(index, header, data_addr, metadata, silent));
if (data_len % 4 != 0) {
FAIL_LOAD("unaligned segment length 0x%"PRIx32, data_len);
}{...}
bool is_mapping = should_map(load_addr);
do_load = do_load && should_load(load_addr);
if (!silent) {
ESP_LOGI(TAG, "segment %d: paddr=%08"PRIx32" vaddr=%08x size=%05"PRIx32"h (%6"PRIu32") %s",
index, data_addr, load_addr,
data_len, data_len,
(do_load) ? "load" : (is_mapping) ? "map" : "");
}{...}
#ifdef BOOTLOADER_BUILD
if (do_load && data_len > 0) {
if (!verify_load_addresses(index, load_addr, load_addr + data_len, true, false)) {
return ESP_ERR_IMAGE_INVALID;
}{...}
}{...}
#endif/* ... */
uint32_t free_page_count = bootloader_mmap_get_free_pages();
ESP_LOGD(TAG, "free data page_count 0x%08"PRIx32, free_page_count);
uint32_t data_len_remain = data_len;
while (data_len_remain > 0) {
#if (SECURE_BOOT_CHECK_SIGNATURE == 1) && defined(BOOTLOADER_BUILD)
ESP_FAULT_ASSERT(!do_load || verify_load_addresses(0, load_addr, load_addr + data_len_remain, false, false));/* ... */
#endif
uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0;
data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE));
CHECK_ERR(process_segment_data(index, load_addr, data_addr, data_len, do_load, sha_handle, checksum, metadata));
data_addr += data_len;
data_len_remain -= data_len;
}{...}
return ESP_OK;
err:
if (err == ESP_OK) {
err = ESP_ERR_IMAGE_INVALID;
}{...}
return err;
}{ ... }
#if CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
/* ... */
__attribute__((optimize("O0")))
static size_t process_esp_app_desc_data(const uint32_t *src, bootloader_sha256_handle_t sha_handle, uint32_t *checksum, esp_image_metadata_t *metadata)
{
/* ... */
uint32_t data_buffer[2];
memcpy(data_buffer, src, sizeof(data_buffer));
assert(data_buffer[0] == ESP_APP_DESC_MAGIC_WORD);
metadata->secure_version = data_buffer[1];
if (checksum != NULL) {
*checksum ^= data_buffer[0] ^ data_buffer[1];
}{...}
if (sha_handle != NULL) {
bootloader_sha256_data(sha_handle, data_buffer, sizeof(data_buffer));
}{...}
ESP_FAULT_ASSERT(memcmp(data_buffer, src, sizeof(data_buffer)) == 0);
ESP_FAULT_ASSERT(memcmp(&metadata->secure_version, &src[1], sizeof(uint32_t)) == 0);
return sizeof(data_buffer);
}{...}
/* ... */#endif
static esp_err_t process_segment_data(int segment, intptr_t load_addr, uint32_t data_addr, uint32_t data_len, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum, esp_image_metadata_t *metadata)
{
if (!do_load && checksum == NULL) {
ESP_LOGD(TAG, "skipping checksum for segment");
return ESP_OK;
}{...}
const uint32_t *data = (const uint32_t *)bootloader_mmap(data_addr, data_len);
if (!data) {
ESP_LOGE(TAG, "bootloader_mmap(0x%"PRIx32", 0x%"PRIx32") failed",
data_addr, data_len);
return ESP_FAIL;
}{...}
if (checksum == NULL && sha_handle == NULL) {
memcpy((void *)load_addr, data, data_len);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
if (esp_ptr_in_iram((uint32_t *)load_addr)) {
/* ... */
cache_ll_writeback_all(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA, CACHE_LL_ID_ALL);
}{...}
#endif/* ... */
bootloader_munmap(data);
return ESP_OK;
}{...}
#ifdef BOOTLOADER_BUILD
while (ram_obfs_value[0] == 0 || ram_obfs_value[1] == 0) {
bootloader_fill_random(ram_obfs_value, sizeof(ram_obfs_value));
#if CONFIG_IDF_ENV_FPGA
ram_obfs_value[0] ^= 0x33;
ram_obfs_value[1] ^= 0x66;/* ... */
#endif
}{...}
uint32_t *dest = (uint32_t *)load_addr;/* ... */
#endif
const uint32_t *src = data;
if (segment == 0 && metadata->start_addr != ESP_BOOTLOADER_OFFSET) {
#if !CONFIG_IDF_TARGET_ESP32
const esp_app_desc_t *app_desc = (const esp_app_desc_t *)src;
esp_err_t ret = bootloader_common_check_efuse_blk_validity(app_desc->min_efuse_blk_rev_full, app_desc->max_efuse_blk_rev_full);
if (ret != ESP_OK) {
bootloader_munmap(data);
return ret;
}{...}
#endif/* ... */
#if CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
ESP_LOGD(TAG, "additional anti-rollback check 0x%"PRIx32, data_addr);
size_t len = process_esp_app_desc_data(src, sha_handle, checksum, metadata);
data_len -= len;
src += len / 4;
/* ... */
#endif
}{...}
for (size_t i = 0; i < data_len; i += 4) {
int w_i = i / 4;
uint32_t w = src[w_i];
if (checksum != NULL) {
*checksum ^= w;
}{...}
#ifdef BOOTLOADER_BUILD
if (do_load) {
dest[w_i] = w ^ ((w_i & 1) ? ram_obfs_value[0] : ram_obfs_value[1]);
}{...}
#endif/* ... */
const size_t SHA_CHUNK = 1024;
if (sha_handle != NULL && i % SHA_CHUNK == 0) {
bootloader_sha256_data(sha_handle, &src[w_i],
MIN(SHA_CHUNK, data_len - i));
}{...}
}{...}
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
if (do_load && esp_ptr_in_iram((uint32_t *)load_addr)) {
/* ... */
cache_ll_writeback_all(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA, CACHE_LL_ID_ALL);
}{...}
#endif/* ... */
bootloader_munmap(data);
return ESP_OK;
}{ ... }
static esp_err_t verify_segment_header(int index, const esp_image_segment_header_t *segment, uint32_t segment_data_offs, esp_image_metadata_t *metadata, bool silent)
{
if ((segment->data_len & 3) != 0
|| segment->data_len >= SIXTEEN_MB) {
if (!silent) {
ESP_LOGE(TAG, "invalid segment length 0x%"PRIx32, segment->data_len);
}{...}
return ESP_ERR_IMAGE_INVALID;
}{...}
uint32_t load_addr = segment->load_addr;
bool map_segment = should_map(load_addr);
#if SOC_MMU_PAGE_SIZE_CONFIGURABLE
if (index == 0 && metadata->start_addr != ESP_BOOTLOADER_OFFSET) {
const esp_app_desc_t *app_desc = (const esp_app_desc_t *)bootloader_mmap(segment_data_offs, sizeof(esp_app_desc_t));
if (!app_desc || app_desc->magic_word != ESP_APP_DESC_MAGIC_WORD) {
ESP_LOGE(TAG, "Failed to fetch app description header!");
return ESP_FAIL;
}{...}
metadata->mmu_page_size = (app_desc->mmu_page_size > 0) ? (1UL << app_desc->mmu_page_size) : SPI_FLASH_MMU_PAGE_SIZE;
if (metadata->mmu_page_size != SPI_FLASH_MMU_PAGE_SIZE) {
ESP_LOGI(TAG, "MMU page size mismatch, configured: 0x%x, found: 0x%"PRIx32, SPI_FLASH_MMU_PAGE_SIZE, metadata->mmu_page_size);
}{...}
bootloader_munmap(app_desc);
}{...} else if (index == 0 && metadata->start_addr == ESP_BOOTLOADER_OFFSET) {
metadata->mmu_page_size = SPI_FLASH_MMU_PAGE_SIZE;
}{...}
#else/* ... */
metadata->mmu_page_size = SPI_FLASH_MMU_PAGE_SIZE;
#endif
const int mmu_page_size = metadata->mmu_page_size;
ESP_LOGV(TAG, "MMU page size 0x%x", mmu_page_size);
/* ... */
ESP_LOGV(TAG, "segment %d map_segment %d segment_data_offs 0x%"PRIx32" load_addr 0x%"PRIx32,
index, map_segment, segment_data_offs, load_addr);
if (map_segment
&& ((segment_data_offs % mmu_page_size) != (load_addr % mmu_page_size))) {
if (!silent) {
ESP_LOGE(TAG, "Segment %d load address 0x%08"PRIx32", doesn't match data 0x%08"PRIx32,
index, load_addr, segment_data_offs);
}{...}
return ESP_ERR_IMAGE_INVALID;
}{...}
return ESP_OK;
}{ ... }
static bool should_map(uint32_t load_addr)
{
bool is_irom = (load_addr >= SOC_IROM_LOW) && (load_addr < SOC_IROM_HIGH);
bool is_drom = (load_addr >= SOC_DROM_LOW) && (load_addr < SOC_DROM_HIGH);
bool is_psram = false;
#if SOC_MMU_PER_EXT_MEM_TARGET
is_psram = (load_addr >= SOC_EXTRAM_LOW) && (load_addr < SOC_EXTRAM_HIGH);
#endif
return (is_irom || is_drom || is_psram);
}{ ... }
static bool should_load(uint32_t load_addr)
{
/* ... */
bool load_rtc_memory = esp_rom_get_reset_reason(0) != RESET_REASON_CORE_DEEP_SLEEP;
if (should_map(load_addr)) {
return false;
}{...}
if (load_addr < 0x10000000) {
return false;
}{...}
if (!load_rtc_memory) {
#if SOC_RTC_FAST_MEM_SUPPORTED
if (load_addr >= SOC_RTC_IRAM_LOW && load_addr < SOC_RTC_IRAM_HIGH) {
ESP_LOGD(TAG, "Skipping RTC fast memory segment at 0x%08"PRIx32, load_addr);
return false;
}{...}
if (load_addr >= SOC_RTC_DRAM_LOW && load_addr < SOC_RTC_DRAM_HIGH) {
ESP_LOGD(TAG, "Skipping RTC fast memory segment at 0x%08"PRIx32, load_addr);
return false;
}{...}
#endif/* ... */
#if SOC_RTC_SLOW_MEM_SUPPORTED
if (load_addr >= SOC_RTC_DATA_LOW && load_addr < SOC_RTC_DATA_HIGH) {
ESP_LOGD(TAG, "Skipping RTC slow memory segment at 0x%08"PRIx32, load_addr);
return false;
}{...}
#endif/* ... */
}{...}
return true;
}{ ... }
esp_err_t esp_image_verify_bootloader(uint32_t *length)
{
esp_image_metadata_t data;
esp_err_t err = esp_image_verify_bootloader_data(&data);
if (length != NULL) {
*length = (err == ESP_OK) ? data.image_len : 0;
}{...}
return err;
}{ ... }
esp_err_t esp_image_verify_bootloader_data(esp_image_metadata_t *data)
{
if (data == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
const esp_partition_pos_t bootloader_part = {
.offset = ESP_BOOTLOADER_OFFSET,
.size = ESP_PARTITION_TABLE_OFFSET - ESP_BOOTLOADER_OFFSET,
}{...};
return esp_image_verify(ESP_IMAGE_VERIFY,
&bootloader_part,
data);
}{ ... }
static esp_err_t process_appended_hash_and_sig(esp_image_metadata_t *data, uint32_t part_offset, uint32_t part_len, bool do_verify, bool silent)
{
esp_err_t err = ESP_OK;
if (data->image.hash_appended) {
if (do_verify) {
CHECK_ERR(bootloader_flash_read(data->start_addr + data->image_len, &data->image_digest, HASH_LEN, true));
}{...}
data->image_len += HASH_LEN;
}{...}
uint32_t sig_block_len = 0;
const uint32_t end = data->image_len;
#if CONFIG_SECURE_BOOT || CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT
if (part_offset == ESP_BOOTLOADER_OFFSET) {
#if CONFIG_SECURE_BOOT_V2_ENABLED
sig_block_len = ALIGN_UP(end, FLASH_SECTOR_SIZE) - end;
sig_block_len += sizeof(ets_secure_boot_signature_t);/* ... */
#endif
}{...} else {
#if CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME
sig_block_len = sizeof(esp_secure_boot_sig_block_t);
#else
sig_block_len = ALIGN_UP(end, FLASH_SECTOR_SIZE) - end;
sig_block_len += sizeof(ets_secure_boot_signature_t);/* ... */
#endif
}{...}
#endif/* ... */
const uint32_t full_image_len = end + sig_block_len;
if (full_image_len > part_len) {
FAIL_LOAD("Image length %"PRIu32" doesn't fit in partition length %"PRIu32, full_image_len, part_len);
}{...}
return err;
err:
if (err == ESP_OK) {
err = ESP_ERR_IMAGE_INVALID;
}{...}
return err;
}{ ... }
static esp_err_t process_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data, bool silent, bool skip_check_checksum)
{
esp_err_t err = ESP_OK;
uint32_t unpadded_length = data->image_len;
uint32_t length = unpadded_length + 1;
length = (length + 15) & ~15;
length = length - unpadded_length;
WORD_ALIGNED_ATTR uint8_t buf[16] = {0};
if (!skip_check_checksum || sha_handle != NULL) {
CHECK_ERR(bootloader_flash_read(data->start_addr + unpadded_length, buf, length, true));
}{...}
uint8_t read_checksum = buf[length - 1];
uint8_t calc_checksum = (checksum_word >> 24) ^ (checksum_word >> 16) ^ (checksum_word >> 8) ^ (checksum_word >> 0);
if (!skip_check_checksum && calc_checksum != read_checksum) {
FAIL_LOAD("Checksum failed. Calculated 0x%x read 0x%x", calc_checksum, read_checksum);
}{...}
if (sha_handle != NULL) {
bootloader_sha256_data(sha_handle, buf, length);
}{...}
data->image_len += length;
return err;
err:
if (err == ESP_OK) {
err = ESP_ERR_IMAGE_INVALID;
}{...}
return err;
}{ ... }
static esp_err_t verify_secure_boot_signature(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data, uint8_t *image_digest, uint8_t *verified_digest)
{
#if (SECURE_BOOT_CHECK_SIGNATURE == 1)
uint32_t end = data->start_addr + data->image_len;
ESP_LOGI(TAG, "Verifying image signature...");
if (data->image.hash_appended) {
const void *simple_hash = bootloader_mmap(end - HASH_LEN, HASH_LEN);
bootloader_sha256_data(sha_handle, simple_hash, HASH_LEN);
bootloader_munmap(simple_hash);
}{...}
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
uint32_t padded_end = ALIGN_UP(end, FLASH_SECTOR_SIZE);
if (padded_end > end) {
const void *padding = bootloader_mmap(end, padded_end - end);
bootloader_sha256_data(sha_handle, padding, padded_end - end);
bootloader_munmap(padding);
end = padded_end;
}{...}
#endif/* ... */
bootloader_sha256_finish(sha_handle, image_digest);
bootloader_debug_buffer(image_digest, HASH_LEN, "Calculated secure boot hash");
esp_err_t err = ESP_ERR_IMAGE_INVALID;
#if CONFIG_SECURE_BOOT || CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT
const void *sig_block;
ESP_FAULT_ASSERT(memcmp(image_digest, verified_digest, HASH_LEN) != 0);
#if defined(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
sig_block = bootloader_mmap(data->start_addr + data->image_len, sizeof(esp_secure_boot_sig_block_t));
err = esp_secure_boot_verify_ecdsa_signature_block(sig_block, image_digest, verified_digest);/* ... */
#else
sig_block = bootloader_mmap(end, sizeof(ets_secure_boot_signature_t));
err = esp_secure_boot_verify_sbv2_signature_block(sig_block, image_digest, verified_digest);/* ... */
#endif
bootloader_munmap(sig_block);/* ... */
#endif
if (err != ESP_OK) {
ESP_LOGE(TAG, "Secure boot signature verification failed");
ESP_LOGI(TAG, "Calculating simple hash to check for corruption...");
const void *whole_image = bootloader_mmap(data->start_addr, data->image_len - HASH_LEN);
if (whole_image != NULL) {
sha_handle = bootloader_sha256_start();
bootloader_sha256_data(sha_handle, whole_image, data->image_len - HASH_LEN);
bootloader_munmap(whole_image);
if (verify_simple_hash(sha_handle, data) != ESP_OK) {
ESP_LOGW(TAG, "image corrupted on flash");
}{...} else {
ESP_LOGW(TAG, "image valid, signature bad");
}{...}
}{...}
return ESP_ERR_IMAGE_INVALID;
}{...}
#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME || CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME
data->image_len = end - data->start_addr + sizeof(ets_secure_boot_signature_t);
#elif defined(CONFIG_SECURE_SIGNED_APPS_ECDSA_SCHEME)
if (data->start_addr != ESP_BOOTLOADER_OFFSET) {
data->image_len = end - data->start_addr + sizeof(esp_secure_boot_sig_block_t);
}{...}
#endif/* ... */
/* ... */
#endif
return ESP_OK;
}{ ... }
static esp_err_t verify_simple_hash(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data)
{
uint8_t image_hash[HASH_LEN] = { 0 };
bootloader_sha256_finish(sha_handle, image_hash);
bootloader_debug_buffer(image_hash, HASH_LEN, "Calculated hash");
if (memcmp(data->image_digest, image_hash, HASH_LEN) != 0) {
ESP_LOGE(TAG, "Image hash failed - image is corrupt");
bootloader_debug_buffer(data->image_digest, HASH_LEN, "Expected hash");
#if CONFIG_IDF_ENV_FPGA || CONFIG_IDF_ENV_BRINGUP
ESP_LOGW(TAG, "Ignoring invalid SHA-256 as running on FPGA / doing bringup");
return ESP_OK;/* ... */
#endif
return ESP_ERR_IMAGE_INVALID;
}{...}
return ESP_OK;
}{ ... }
int esp_image_get_flash_size(esp_image_flash_size_t app_flash_size)
{
switch (app_flash_size) {
case ESP_IMAGE_FLASH_SIZE_1MB:
return 1 * 1024 * 1024;...
case ESP_IMAGE_FLASH_SIZE_2MB:
return 2 * 1024 * 1024;...
case ESP_IMAGE_FLASH_SIZE_4MB:
return 4 * 1024 * 1024;...
case ESP_IMAGE_FLASH_SIZE_8MB:
return 8 * 1024 * 1024;...
case ESP_IMAGE_FLASH_SIZE_16MB:
return 16 * 1024 * 1024;...
case ESP_IMAGE_FLASH_SIZE_32MB:
return 32 * 1024 * 1024;...
case ESP_IMAGE_FLASH_SIZE_64MB:
return 64 * 1024 * 1024;...
case ESP_IMAGE_FLASH_SIZE_128MB:
return 128 * 1024 * 1024;...
default:
return 0;...
}{...}
}{ ... }