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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
78
79
80
84
85
86
87
91
92
93
94
95
96
97
98
99
100
101
104
105
106
107
108
112
113
114
115
116
119
120
121
122
123
124
125
126
127
128
129
130
131
132
136
137
138
139
143
144
145
146
147
148
149
150
151
152
153
154
155
177
178
179
183
186
189
192
198
201
202
203
213
223
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
245
246
249
250
253
254
255
256
257
258
273
274
285
286
287
288
289
299
300
301
302
303
304
305
306
307
308
309
314
315
316
317
318
319
320
321
322
323
324
325
326
338
339
340
341
342
343
344
345
346
347
348
351
352
355
356
357
358
359
360
361
370
371
372
373
374
391
392
393
394
395
396
397
403
404
405
406
407
408
409
410
411
417
418
419
423
424
431
432
433
434
435
436
437
438
439
443
444
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
478
479
480
481
482
483
484
485
486
494
495
496
497
498
504
505
506
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
534
535
536
548
549
550
562
563
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
633
634
635
641
642
643
653
654
655
656
657
658
659
660
661
662
663
664
666
667
668
671
672
673
677
678
679
680
690
691
704
705
706
707
720
721
722
731
732
733
734
735
739
740
741
742
743
744
745
746
747
748
754
755
756
757
758
759
760
761
762
763
764
765
768
769
773
774
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
850
851
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
874
875
876
877
878
879
881
882
883
884
885
886
887
888
889
890
891
892
893
899
900
908
909
910
911
912
913
914
915
916
917
923
924
929
930
931
932
933
934
935
936
937
941
942
943
944
945
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1015
1016
1017
1018
1019
1020
1021
1024
1025
1026
1027
1028
1029
1030
1033
1034
1035
1036
1037
1038
1039
1043
1044
1045
1046
1047
1048
1049
1050
1051
/* ... */
#include <string.h>
#include <stdint.h>
#include <limits.h>
#include <sys/param.h>
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_rom_sys.h"
#include "esp_rom_uart.h"
#include "sdkconfig.h"9 includes
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/cache.h"
#endif
#include "esp_rom_spiflash.h"
#include "soc/soc.h"
#include "soc/soc_caps.h"
#include "soc/rtc.h"
#include "soc/efuse_periph.h"
#include "soc/rtc_periph.h"
#include "soc/timer_periph.h"
#include "hal/mmu_hal.h"
#include "hal/mmu_ll.h"
#include "hal/cache_types.h"
#include "hal/cache_ll.h"
#include "hal/cache_hal.h"
#include "esp_cpu.h"
#include "esp_image_format.h"
#include "esp_app_desc.h"
#include "esp_secure_boot.h"
#include "esp_flash_encrypt.h"17 includes
#ifndef BOOTLOADER_BUILD
#include "spi_flash_mmap.h"
#endif
#include "esp_flash_partitions.h"
#include "bootloader_flash_priv.h"
#include "bootloader_random.h"
#include "bootloader_config.h"
#include "bootloader_common.h"
#include "bootloader_utility.h"
#include "bootloader_sha.h"
#include "bootloader_console.h"
#include "bootloader_soc.h"
#include "bootloader_memory_utils.h"
#include "esp_efuse.h"
#include "esp_fault.h"12 includes
static const char *TAG = "boot";
#define MAP_ERR_MSG "Image contains multiple %s segments. Only the last one will be mapped."
static bool ota_has_initial_contents;
static void load_image(const esp_image_metadata_t *image_data);
static void unpack_load_app(const esp_image_metadata_t *data);
static void set_cache_and_start_app(uint32_t drom_addr,
uint32_t drom_load_addr,
uint32_t drom_size,
uint32_t irom_addr,
uint32_t irom_load_addr,
uint32_t irom_size,
const esp_image_metadata_t *data);
esp_err_t bootloader_common_read_otadata(const esp_partition_pos_t *ota_info, esp_ota_select_entry_t *two_otadata)
{
const esp_ota_select_entry_t *ota_select_map;
if (ota_info->offset == 0) {
return ESP_ERR_NOT_FOUND;
}{...}
if (ota_info->size < 2 * SPI_SEC_SIZE) {
ESP_LOGE(TAG, "ota_info partition size %"PRIu32" is too small (minimum %d bytes)", ota_info->size, (2 * SPI_SEC_SIZE));
return ESP_FAIL;
}{...}
ESP_LOGD(TAG, "OTA data offset 0x%"PRIx32, ota_info->offset);
ota_select_map = bootloader_mmap(ota_info->offset, ota_info->size);
if (!ota_select_map) {
ESP_LOGE(TAG, "bootloader_mmap(0x%"PRIx32", 0x%"PRIx32") failed", ota_info->offset, ota_info->size);
return ESP_FAIL;
}{...}
memcpy(&two_otadata[0], ota_select_map, sizeof(esp_ota_select_entry_t));
memcpy(&two_otadata[1], (uint8_t *)ota_select_map + SPI_SEC_SIZE, sizeof(esp_ota_select_entry_t));
bootloader_munmap(ota_select_map);
return ESP_OK;
}{ ... }
esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t *partition, esp_app_desc_t *app_desc)
{
if (partition == NULL || app_desc == NULL || partition->offset == 0) {
return ESP_ERR_INVALID_ARG;
}{...}
const uint32_t app_desc_offset = sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t);
const uint32_t mmap_size = app_desc_offset + sizeof(esp_app_desc_t);
const uint8_t *image = bootloader_mmap(partition->offset, mmap_size);
if (image == NULL) {
ESP_LOGE(TAG, "bootloader_mmap(0x%"PRIx32", 0x%"PRIx32") failed", partition->offset, mmap_size);
return ESP_FAIL;
}{...}
memcpy(app_desc, image + app_desc_offset, sizeof(esp_app_desc_t));
bootloader_munmap(image);
if (app_desc->magic_word != ESP_APP_DESC_MAGIC_WORD) {
return ESP_ERR_NOT_FOUND;
}{...}
return ESP_OK;
}{ ... }
bool bootloader_utility_load_partition_table(bootloader_state_t *bs)
{
const esp_partition_info_t *partitions;
const char *partition_usage;
esp_err_t err;
int num_partitions;
partitions = bootloader_mmap(ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN);
if (!partitions) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN);
return false;
}{...}
ESP_LOGD(TAG, "mapped partition table 0x%x at 0x%x", ESP_PARTITION_TABLE_OFFSET, (intptr_t)partitions);
err = esp_partition_table_verify(partitions, true, &num_partitions);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to verify partition table");
return false;
}{...}
ESP_LOGI(TAG, "Partition Table:");
ESP_LOGI(TAG, "## Label Usage Type ST Offset Length");
for (int i = 0; i < num_partitions; i++) {
const esp_partition_info_t *partition = &partitions[i];
ESP_LOGD(TAG, "load partition table entry 0x%x", (intptr_t)partition);
ESP_LOGD(TAG, "type=%x subtype=%x", partition->type, partition->subtype);
partition_usage = "unknown";
switch (partition->type) {
case PART_TYPE_APP:
switch (partition->subtype) {
case PART_SUBTYPE_FACTORY:
bs->factory = partition->pos;
partition_usage = "factory app";
break;...
case PART_SUBTYPE_TEST:
bs->test = partition->pos;
partition_usage = "test app";
break;...
default:
if ((partition->subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) {
bs->ota[partition->subtype & PART_SUBTYPE_OTA_MASK] = partition->pos;
++bs->app_count;
partition_usage = "OTA app";
}{...} else {
partition_usage = "Unknown app";
}{...}
break;...
}{...}
break; ...
case PART_TYPE_DATA:
switch (partition->subtype) {
case PART_SUBTYPE_DATA_OTA:
bs->ota_info = partition->pos;
partition_usage = "OTA data";
break;...
case PART_SUBTYPE_DATA_RF:
partition_usage = "RF data";
break;...
case PART_SUBTYPE_DATA_WIFI:
partition_usage = "WiFi data";
break;...
case PART_SUBTYPE_DATA_NVS_KEYS:
partition_usage = "NVS keys";
break;...
case PART_SUBTYPE_DATA_EFUSE_EM:
partition_usage = "efuse";
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
esp_efuse_init_virtual_mode_in_flash(partition->pos.offset, partition->pos.size);
#endif
break;...
default:
partition_usage = "Unknown data";
break;...
}{...}
break; ...
case PART_TYPE_BOOTLOADER:
switch (partition->subtype) {
case PART_SUBTYPE_BOOTLOADER_PRIMARY:
partition_usage = "primary bootloader";
break;...
case PART_SUBTYPE_BOOTLOADER_OTA:
partition_usage = "ota bootloader";
break;...
}{...}
break; ...
case PART_TYPE_PARTITION_TABLE:
switch (partition->subtype) {
case PART_SUBTYPE_PARTITION_TABLE_PRIMARY:
partition_usage = "primary partition_table";
break;...
case PART_SUBTYPE_PARTITION_TABLE_OTA:
partition_usage = "ota partition_table";
break;...
}{...}
break; ...
default:
break;...
}{...}
ESP_LOGI(TAG, "%2d %-16s %-16s %02x %02x %08"PRIx32" %08"PRIx32, i, partition->label, partition_usage,
partition->type, partition->subtype,
partition->pos.offset, partition->pos.size);
}{...}
bootloader_munmap(partitions);
ESP_LOGI(TAG, "End of partition table");
return true;
}{ ... }
static esp_partition_pos_t index_to_partition(const bootloader_state_t *bs, int index)
{
if (index == FACTORY_INDEX) {
return bs->factory;
}{...}
if (index == TEST_APP_INDEX) {
return bs->test;
}{...}
if (index >= 0 && index < MAX_OTA_SLOTS && index < (int)bs->app_count) {
return bs->ota[index];
}{...}
esp_partition_pos_t invalid = { 0 };
return invalid;
}{ ... }
static void log_invalid_app_partition(int index)
{
const char *not_bootable = " is not bootable";
switch (index) {
case FACTORY_INDEX:
ESP_LOGE(TAG, "Factory app partition%s", not_bootable);
break;...
case TEST_APP_INDEX:
ESP_LOGE(TAG, "Factory test app partition%s", not_bootable);
break;...
default:
ESP_LOGE(TAG, "OTA app partition slot %d%s", index, not_bootable);
break;...
}{...}
}{ ... }
static esp_err_t write_otadata(esp_ota_select_entry_t *otadata, uint32_t offset, bool write_encrypted)
{
esp_err_t err = bootloader_flash_erase_sector(offset / FLASH_SECTOR_SIZE);
if (err == ESP_OK) {
err = bootloader_flash_write(offset, otadata, sizeof(esp_ota_select_entry_t), write_encrypted);
}{...}
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error in write_otadata operation. err = 0x%x", err);
}{...}
return err;
}{ ... }
static bool check_anti_rollback(const esp_partition_pos_t *partition)
{
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
esp_app_desc_t app_desc = {};
esp_err_t err = bootloader_common_get_partition_description(partition, &app_desc);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to get partition description %d", err);
return false;
}{...}
bool sec_ver = esp_efuse_check_secure_version(app_desc.secure_version);
ESP_FAULT_ASSERT(sec_ver == esp_efuse_check_secure_version(app_desc.secure_version));
return sec_ver;/* ... */
#else
return true;
#endif
}{ ... }
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
static void update_anti_rollback(const esp_partition_pos_t *partition)
{
esp_app_desc_t app_desc;
esp_err_t err = bootloader_common_get_partition_description(partition, &app_desc);
if (err == ESP_OK) {
esp_efuse_update_secure_version(app_desc.secure_version);
}{...} else {
ESP_LOGE(TAG, "Failed to get partition description %d", err);
}{...}
}{...}
static int get_active_otadata_with_check_anti_rollback(const bootloader_state_t *bs, esp_ota_select_entry_t *two_otadata)
{
uint32_t ota_seq;
uint32_t ota_slot;
bool valid_otadata[2];
valid_otadata[0] = bootloader_common_ota_select_valid(&two_otadata[0]);
valid_otadata[1] = bootloader_common_ota_select_valid(&two_otadata[1]);
bool sec_ver_valid_otadata[2] = { 0 };
for (int i = 0; i < 2; ++i) {
if (valid_otadata[i] == true) {
ota_seq = two_otadata[i].ota_seq - 1;
ota_slot = ota_seq % bs->app_count;
if (check_anti_rollback(&bs->ota[ota_slot]) == false) {
ESP_LOGD(TAG, "OTA slot %"PRIu32" has an app with secure_version, this version is smaller than in the device. This OTA slot will not be selected.", ota_slot);
}{...} else {
sec_ver_valid_otadata[i] = true;
}{...}
}{...}
}{...}
return bootloader_common_select_otadata(two_otadata, sec_ver_valid_otadata, true);
}{...}
/* ... */#endif
int bootloader_utility_get_selected_boot_partition(const bootloader_state_t *bs)
{
esp_ota_select_entry_t otadata[2];
int boot_index = FACTORY_INDEX;
if (bs->ota_info.offset == 0) {
return FACTORY_INDEX;
}{...}
if (bootloader_common_read_otadata(&bs->ota_info, otadata) != ESP_OK) {
return INVALID_INDEX;
}{...}
ota_has_initial_contents = false;
ESP_LOGD(TAG, "otadata[0]: sequence values 0x%08"PRIx32, otadata[0].ota_seq);
ESP_LOGD(TAG, "otadata[1]: sequence values 0x%08"PRIx32, otadata[1].ota_seq);
#ifdef CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
bool write_encrypted = esp_flash_encryption_enabled();
for (int i = 0; i < 2; ++i) {
if (otadata[i].ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
ESP_LOGD(TAG, "otadata[%d] is marking as ABORTED", i);
otadata[i].ota_state = ESP_OTA_IMG_ABORTED;
write_otadata(&otadata[i], bs->ota_info.offset + FLASH_SECTOR_SIZE * i, write_encrypted);
}{...}
}{...}
#endif/* ... */
#ifndef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
if ((bootloader_common_ota_select_invalid(&otadata[0]) &&
bootloader_common_ota_select_invalid(&otadata[1])) ||
bs->app_count == 0) {
ESP_LOGD(TAG, "OTA sequence numbers both empty (all-0xFF) or partition table does not have bootable ota_apps (app_count=%"PRIu32")", bs->app_count);
if (bs->factory.offset != 0) {
ESP_LOGI(TAG, "Defaulting to factory image");
boot_index = FACTORY_INDEX;
}{...} else {
ESP_LOGI(TAG, "No factory image, trying OTA 0");
boot_index = 0;
if ((otadata[0].ota_seq == UINT32_MAX || otadata[0].crc != bootloader_common_ota_select_crc(&otadata[0])) &&
(otadata[1].ota_seq == UINT32_MAX || otadata[1].crc != bootloader_common_ota_select_crc(&otadata[1]))) {
ota_has_initial_contents = true;
}{...}
}{...}
}{...} else {
int active_otadata = bootloader_common_get_active_otadata(otadata);
#else
ESP_LOGI(TAG, "Enabled a check secure version of app for anti rollback");
ESP_LOGI(TAG, "Secure version (from eFuse) = %"PRIu32, esp_efuse_read_secure_version());
if ((otadata[0].ota_seq == UINT32_MAX || otadata[0].crc != bootloader_common_ota_select_crc(&otadata[0])) &&
(otadata[1].ota_seq == UINT32_MAX || otadata[1].crc != bootloader_common_ota_select_crc(&otadata[1]))) {
ESP_LOGI(TAG, "otadata[0..1] in initial state");
ota_has_initial_contents = true;
}{...} else {
int active_otadata = get_active_otadata_with_check_anti_rollback(bs, otadata);
#endif
if (active_otadata != -1) {
ESP_LOGD(TAG, "Active otadata[%d]", active_otadata);
uint32_t ota_seq = otadata[active_otadata].ota_seq - 1;
boot_index = ota_seq % bs->app_count;
ESP_LOGD(TAG, "Mapping seq %"PRIu32" -> OTA slot %d", ota_seq, boot_index);
#ifdef CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
if (otadata[active_otadata].ota_state == ESP_OTA_IMG_NEW) {
ESP_LOGD(TAG, "otadata[%d] is selected as new and marked PENDING_VERIFY state", active_otadata);
otadata[active_otadata].ota_state = ESP_OTA_IMG_PENDING_VERIFY;
write_otadata(&otadata[active_otadata], bs->ota_info.offset + FLASH_SECTOR_SIZE * active_otadata, write_encrypted);
}{...}
#endif/* ... */
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
if (otadata[active_otadata].ota_state == ESP_OTA_IMG_VALID) {
update_anti_rollback(&bs->ota[boot_index]);
}{...}
#endif/* ... */
}{...} else if (bs->factory.offset != 0) {
ESP_LOGE(TAG, "ota data partition invalid, falling back to factory");
boot_index = FACTORY_INDEX;
}{...} else {
ESP_LOGE(TAG, "ota data partition invalid and no factory, will try all partitions");
boot_index = FACTORY_INDEX;
}{...}
}{...}
return boot_index;
}{ ... }
static bool try_load_partition(const esp_partition_pos_t *partition, esp_image_metadata_t *data)
{
if (partition->size == 0) {
ESP_LOGD(TAG, "Can't boot from zero-length partition");
return false;
}{...}
#ifdef BOOTLOADER_BUILD
if (bootloader_load_image(partition, data) == ESP_OK) {
ESP_LOGI(TAG, "Loaded app from partition at offset 0x%" PRIx32, partition->offset);
return true;
}{...}
#endif/* ... */
return false;
}{ ... }
static void set_actual_ota_seq(const bootloader_state_t *bs, int index)
{
if (index > FACTORY_INDEX && ota_has_initial_contents == true) {
esp_ota_select_entry_t otadata;
memset(&otadata, 0xFF, sizeof(otadata));
otadata.ota_seq = index + 1;
otadata.ota_state = ESP_OTA_IMG_VALID;
otadata.crc = bootloader_common_ota_select_crc(&otadata);
bool write_encrypted = esp_flash_encryption_enabled();
write_otadata(&otadata, bs->ota_info.offset + FLASH_SECTOR_SIZE * 0, write_encrypted);
ESP_LOGI(TAG, "Set actual ota_seq=%"PRIu32" in otadata[0]", otadata.ota_seq);
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
update_anti_rollback(&bs->ota[index]);
#endif
}{...}
#if CONFIG_BOOTLOADER_RESERVE_RTC_MEM
#ifdef CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP
esp_partition_pos_t partition = index_to_partition(bs, index);
bootloader_common_update_rtc_retain_mem(&partition, true);/* ... */
#else
bootloader_common_update_rtc_retain_mem(NULL, true);
#endif/* ... */
#endif
}{ ... }
#ifdef CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP
void bootloader_utility_load_boot_image_from_deep_sleep(void)
{
if (esp_rom_get_reset_reason(0) == RESET_REASON_CORE_DEEP_SLEEP) {
#if SOC_RTC_FAST_MEM_SUPPORTED
esp_partition_pos_t *partition = bootloader_common_get_rtc_retain_mem_partition();
esp_image_metadata_t image_data;
if (partition != NULL && bootloader_load_image_no_verify(partition, &image_data) == ESP_OK) {
ESP_LOGI(TAG, "Fast booting app from partition at offset 0x%"PRIx32, partition->offset);
bootloader_common_update_rtc_retain_mem(NULL, true);
load_image(&image_data);
}{...}
/* ... */#else
bootloader_state_t bs = {0};
if (bootloader_utility_load_partition_table(&bs)) {
int index_of_last_loaded_app = FACTORY_INDEX;
esp_ota_select_entry_t otadata[2];
if (bs.ota_info.size && bootloader_common_read_otadata(&bs.ota_info, otadata) == ESP_OK) {
int active_otadata = bootloader_common_get_active_otadata(otadata);
if (active_otadata != -1) {
index_of_last_loaded_app = (otadata[active_otadata].ota_seq - 1) % bs.app_count;
}{...}
}{...}
esp_partition_pos_t partition = index_to_partition(&bs, index_of_last_loaded_app);
esp_image_metadata_t image_data;
if (partition.size && bootloader_load_image_no_verify(&partition, &image_data) == ESP_OK) {
ESP_LOGI(TAG, "Fast booting app from partition at offset 0x%"PRIx32, partition.offset);
load_image(&image_data);
}{...}
}{...}
/* ... */#endif
ESP_LOGE(TAG, "Fast booting is not successful");
ESP_LOGI(TAG, "Try to load an app as usual with all validations");
}{...}
}{...}
/* ... */#endif
#define TRY_LOG_FORMAT "Trying partition index %d offs 0x%"PRIx32" size 0x%"PRIx32
void bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_index)
{
int index = start_index;
esp_partition_pos_t part;
esp_image_metadata_t image_data = {0};
if (start_index == TEST_APP_INDEX) {
if (check_anti_rollback(&bs->test) && try_load_partition(&bs->test, &image_data)) {
load_image(&image_data);
}{...} else {
ESP_LOGE(TAG, "No bootable test partition in the partition table");
bootloader_reset();
}{...}
}{...}
for (index = start_index; index >= FACTORY_INDEX; index--) {
part = index_to_partition(bs, index);
if (part.size == 0) {
continue;
}{...}
ESP_LOGD(TAG, TRY_LOG_FORMAT, index, part.offset, part.size);
if (check_anti_rollback(&part) && try_load_partition(&part, &image_data)) {
set_actual_ota_seq(bs, index);
load_image(&image_data);
}{...}
log_invalid_app_partition(index);
}{...}
for (index = start_index + 1; index < (int)bs->app_count; index++) {
part = index_to_partition(bs, index);
if (part.size == 0) {
continue;
}{...}
ESP_LOGD(TAG, TRY_LOG_FORMAT, index, part.offset, part.size);
if (check_anti_rollback(&part) && try_load_partition(&part, &image_data)) {
set_actual_ota_seq(bs, index);
load_image(&image_data);
}{...}
log_invalid_app_partition(index);
}{...}
if (check_anti_rollback(&bs->test) && try_load_partition(&bs->test, &image_data)) {
ESP_LOGW(TAG, "Falling back to test app as only bootable partition");
load_image(&image_data);
}{...}
ESP_LOGE(TAG, "No bootable app partitions in the partition table");
bzero(&image_data, sizeof(esp_image_metadata_t));
bootloader_reset();
}{ ... }
static void load_image(const esp_image_metadata_t *image_data)
{
/* ... */
#if defined(CONFIG_SECURE_BOOT) || defined(CONFIG_SECURE_FLASH_ENC_ENABLED)
esp_err_t err;
#endif
#ifdef CONFIG_SECURE_BOOT_FLASH_ENC_KEYS_BURN_TOGETHER
if (esp_secure_boot_enabled() ^ esp_flash_encrypt_initialized_once()) {
ESP_LOGE(TAG, "Secure Boot and Flash Encryption cannot be enabled separately, only together (their keys go into one eFuse key block)");
return;
}{...}
if (!esp_secure_boot_enabled() || !esp_flash_encryption_enabled()) {
esp_efuse_batch_write_begin();
}{...}
#endif/* ... */
#ifdef CONFIG_SECURE_BOOT_V2_ENABLED
err = esp_secure_boot_v2_permanently_enable(image_data);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Secure Boot v2 failed (%d)", err);
return;
}{...}
#endif/* ... */
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
/* ... */
err = esp_secure_boot_generate_digest();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Bootloader digest generation for secure boot failed (%d).", err);
return;
}{...}
#endif/* ... */
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
/* ... */
ESP_LOGI(TAG, "Checking flash encryption...");
bool flash_encryption_enabled = esp_flash_encrypt_state();
if (!flash_encryption_enabled) {
#ifdef CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
ESP_LOGE(TAG, "flash encryption is not enabled, and SECURE_FLASH_REQUIRE_ALREADY_ENABLED is set, refusing to boot.");
return;/* ... */
#endif
if (esp_flash_encrypt_is_write_protected(true)) {
return;
}{...}
err = esp_flash_encrypt_init();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Initialization of Flash Encryption key failed (%d)", err);
return;
}{...}
}{...}
#ifdef CONFIG_SECURE_BOOT_FLASH_ENC_KEYS_BURN_TOGETHER
if (!esp_secure_boot_enabled() || !flash_encryption_enabled) {
err = esp_efuse_batch_write_commit();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error programming eFuses (err=0x%x).", err);
return;
}{...}
assert(esp_secure_boot_enabled());
ESP_LOGI(TAG, "Secure boot permanently enabled");
}{...}
#endif/* ... */
if (!flash_encryption_enabled) {
err = esp_flash_encrypt_contents();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Encryption flash contents failed (%d)", err);
return;
}{...}
err = esp_flash_encrypt_enable();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Enabling of Flash encryption failed (%d)", err);
return;
}{...}
}{...}
#endif/* ... */
#ifdef CONFIG_SECURE_BOOT_V1_ENABLED
/* ... */
ESP_LOGI(TAG, "Checking secure boot...");
err = esp_secure_boot_permanently_enable();
if (err != ESP_OK) {
ESP_LOGE(TAG, "FAILED TO ENABLE SECURE BOOT (%d).", err);
/* ... */
abort();
}{...}
#endif/* ... */
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
if (!flash_encryption_enabled && esp_flash_encryption_enabled()) {
/* ... */
ESP_LOGI(TAG, "Resetting with flash encryption enabled...");
esp_rom_output_tx_wait_idle(0);
bootloader_reset();
}{...}
#endif/* ... */
ESP_LOGI(TAG, "Disabling RNG early entropy source...");
bootloader_random_disable();
/* ... */
bootloader_ana_clock_glitch_reset_config(false);
unpack_load_app(image_data);
}{ ... }
#if SOC_MMU_DI_VADDR_SHARED
static void unpack_load_app(const esp_image_metadata_t *data)
{
/* ... */
uint32_t rom_addr[2] = {};
uint32_t rom_load_addr[2] = {};
uint32_t rom_size[2] = {};
int rom_index = 0;
for (int i = 0; i < data->image.segment_count; i++) {
const esp_image_segment_header_t *header = &data->segments[i];
bool text_or_rodata = false;
if (header->load_addr >= SOC_DROM_LOW && header->load_addr < SOC_DROM_HIGH) {
text_or_rodata = true;
}{...}
#if SOC_MMU_PER_EXT_MEM_TARGET
if (header->load_addr >= SOC_EXTRAM_LOW && header->load_addr < SOC_EXTRAM_HIGH) {
text_or_rodata = true;
}{...}
/* ... */#endif
if (text_or_rodata) {
/* ... */
assert(rom_index < 2);
rom_addr[rom_index] = data->segment_data[i];
rom_load_addr[rom_index] = header->load_addr;
rom_size[rom_index] = header->data_len;
rom_index++;
}{...}
}{...}
assert(rom_index == 2);
ESP_EARLY_LOGD(TAG, "calling set_cache_and_start_app");
set_cache_and_start_app(rom_addr[0],
rom_load_addr[0],
rom_size[0],
rom_addr[1],
rom_load_addr[1],
rom_size[1],
data);
}{...}
/* ... */
#else
static void unpack_load_app(const esp_image_metadata_t *data)
{
uint32_t drom_addr = 0;
uint32_t drom_load_addr = 0;
uint32_t drom_size = 0;
uint32_t irom_addr = 0;
uint32_t irom_load_addr = 0;
uint32_t irom_size = 0;
for (int i = 0; i < data->image.segment_count; i++) {
const esp_image_segment_header_t *header = &data->segments[i];
if (header->load_addr >= SOC_DROM_LOW && header->load_addr < SOC_DROM_HIGH) {
if (drom_addr != 0) {
ESP_EARLY_LOGE(TAG, MAP_ERR_MSG, "DROM");
}{...} else {
ESP_EARLY_LOGD(TAG, "Mapping segment %d as %s", i, "DROM");
}{...}
drom_addr = data->segment_data[i];
drom_load_addr = header->load_addr;
drom_size = header->data_len;
}{...}
if (header->load_addr >= SOC_IROM_LOW && header->load_addr < SOC_IROM_HIGH) {
if (irom_addr != 0) {
ESP_EARLY_LOGE(TAG, MAP_ERR_MSG, "IROM");
}{...} else {
ESP_EARLY_LOGD(TAG, "Mapping segment %d as %s", i, "IROM");
}{...}
irom_addr = data->segment_data[i];
irom_load_addr = header->load_addr;
irom_size = header->data_len;
}{...}
}{...}
ESP_EARLY_LOGD(TAG, "calling set_cache_and_start_app");
set_cache_and_start_app(drom_addr,
drom_load_addr,
drom_size,
irom_addr,
irom_load_addr,
irom_size,
data);
}{ ... }
/* ... */#endif
__attribute__((unused))
static bool s_flash_seg_needs_map(uint32_t vaddr)
{
#if SOC_MMU_PER_EXT_MEM_TARGET
bool is_psram = esp_ptr_in_extram((void *)vaddr);
return !is_psram;/* ... */
#else
return true;/* ... */
#endif
}{ ... }
static void set_cache_and_start_app(
uint32_t drom_addr,
uint32_t drom_load_addr,
uint32_t drom_size,
uint32_t irom_addr,
uint32_t irom_load_addr,
uint32_t irom_size,
const esp_image_metadata_t *data)
{
int rc __attribute__((unused));
const uint32_t entry_addr = data->image.entry_addr;
const uint32_t mmu_page_size = data->mmu_page_size;
ESP_EARLY_LOGD(TAG, "configure drom and irom and start");
#if CONFIG_IDF_TARGET_ESP32
Cache_Read_Disable(0);
Cache_Flush(0);/* ... */
#else
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
#endif
#if SOC_MMU_PAGE_SIZE_CONFIGURABLE
mmu_ll_set_page_size(0, mmu_page_size);/* ... */
#endif
mmu_hal_unmap_all();
uint32_t drom_load_addr_aligned = drom_load_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size);
uint32_t drom_addr_aligned = drom_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size);
ESP_EARLY_LOGV(TAG, "rodata starts from paddr=0x%08" PRIx32 ", vaddr=0x%08" PRIx32 ", size=0x%" PRIx32, drom_addr, drom_load_addr, drom_size);
drom_size = (drom_load_addr - drom_load_addr_aligned) + drom_size;
#if CONFIG_IDF_TARGET_ESP32
uint32_t drom_page_count = (drom_size + SPI_FLASH_MMU_PAGE_SIZE - 1) / SPI_FLASH_MMU_PAGE_SIZE;
rc = cache_flash_mmu_set(0, 0, drom_load_addr_aligned, drom_addr_aligned, 64, drom_page_count);
ESP_EARLY_LOGV(TAG, "rc=%d", rc);
rc = cache_flash_mmu_set(1, 0, drom_load_addr_aligned, drom_addr_aligned, 64, drom_page_count);
ESP_EARLY_LOGV(TAG, "rc=%d", rc);
ESP_EARLY_LOGV(TAG, "after mapping rodata, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", drom_addr_aligned, drom_load_addr_aligned, drom_page_count * SPI_FLASH_MMU_PAGE_SIZE);/* ... */
#else
uint32_t actual_mapped_len = 0;
if (s_flash_seg_needs_map(drom_load_addr_aligned)) {
mmu_hal_map_region(0, MMU_TARGET_FLASH0, drom_load_addr_aligned, drom_addr_aligned, drom_size, &actual_mapped_len);
ESP_EARLY_LOGV(TAG, "after mapping rodata, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", drom_addr_aligned, drom_load_addr_aligned, actual_mapped_len);
}{...}
mmu_hal_map_region(0, MMU_TARGET_FLASH0, MMU_DROM_END_ENTRY_VADDR_FROM_VAL(mmu_page_size), drom_addr_aligned, mmu_page_size, &actual_mapped_len);
ESP_EARLY_LOGV(TAG, "mapped one page of the rodata, from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", drom_addr_aligned, MMU_LL_END_DROM_ENTRY_VADDR, actual_mapped_len);/* ... */
#endif
MAP DROM
uint32_t irom_load_addr_aligned = irom_load_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size);
uint32_t irom_addr_aligned = irom_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size);
ESP_EARLY_LOGV(TAG, "text starts from paddr=0x%08" PRIx32 ", vaddr=0x%08" PRIx32 ", size=0x%" PRIx32, irom_addr, irom_load_addr, irom_size);
irom_size = (irom_load_addr - irom_load_addr_aligned) + irom_size;
#if CONFIG_IDF_TARGET_ESP32
uint32_t irom_page_count = (irom_size + SPI_FLASH_MMU_PAGE_SIZE - 1) / SPI_FLASH_MMU_PAGE_SIZE;
rc = cache_flash_mmu_set(0, 0, irom_load_addr_aligned, irom_addr_aligned, 64, irom_page_count);
ESP_EARLY_LOGV(TAG, "rc=%d", rc);
rc = cache_flash_mmu_set(1, 0, irom_load_addr_aligned, irom_addr_aligned, 64, irom_page_count);
ESP_LOGV(TAG, "rc=%d", rc);
ESP_EARLY_LOGV(TAG, "after mapping text, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", irom_addr_aligned, irom_load_addr_aligned, irom_page_count * SPI_FLASH_MMU_PAGE_SIZE);/* ... */
#else
if (s_flash_seg_needs_map(irom_load_addr_aligned)) {
mmu_hal_map_region(0, MMU_TARGET_FLASH0, irom_load_addr_aligned, irom_addr_aligned, irom_size, &actual_mapped_len);
ESP_EARLY_LOGV(TAG, "after mapping text, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", irom_addr_aligned, irom_load_addr_aligned, actual_mapped_len);
}{...}
#endif/* ... */
MAP IROM
cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, drom_load_addr_aligned, drom_size);
cache_ll_l1_enable_bus(0, bus_mask);
bus_mask = cache_ll_l1_get_bus(0, irom_load_addr_aligned, irom_size);
cache_ll_l1_enable_bus(0, bus_mask);
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
bus_mask = cache_ll_l1_get_bus(1, drom_load_addr_aligned, drom_size);
cache_ll_l1_enable_bus(1, bus_mask);
bus_mask = cache_ll_l1_get_bus(1, irom_load_addr_aligned, irom_size);
cache_ll_l1_enable_bus(1, bus_mask);/* ... */
#endif
Enable corresponding buses
#if CONFIG_IDF_TARGET_ESP32
Cache_Read_Enable(0);/* ... */
#else
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
#endif
ESP_LOGD(TAG, "start: 0x%08"PRIx32, entry_addr);
bootloader_atexit();
typedef void (*entry_t)(void) __attribute__((noreturn));
entry_t entry = ((entry_t) entry_addr);
(*entry)();
}{ ... }
void bootloader_reset(void)
{
#ifdef BOOTLOADER_BUILD
bootloader_atexit();
esp_rom_delay_us(1000);
esp_rom_software_reset_system();
while (1) { } /* ... */
#else
abort();
#endif
}{ ... }
void bootloader_atexit(void)
{
#ifdef BOOTLOADER_BUILD
bootloader_console_deinit();
#else
abort();
#endif
}{ ... }
esp_err_t bootloader_sha256_hex_to_str(char *out_str, const uint8_t *in_array_hex, size_t len)
{
if (out_str == NULL || in_array_hex == NULL || len == 0) {
return ESP_ERR_INVALID_ARG;
}{...}
for (size_t i = 0; i < len; i++) {
for (int shift = 0; shift < 2; shift++) {
uint8_t nibble = (in_array_hex[i] >> (shift ? 0 : 4)) & 0x0F;
if (nibble < 10) {
out_str[i * 2 + shift] = '0' + nibble;
}{...} else {
out_str[i * 2 + shift] = 'a' + nibble - 10;
}{...}
}{...}
}{...}
return ESP_OK;
}{ ... }
void bootloader_debug_buffer(const void *buffer, size_t length, const char *label)
{
#if CONFIG_BOOTLOADER_LOG_LEVEL >= 4
const uint8_t *bytes = (const uint8_t *)buffer;
const size_t output_len = MIN(length, 128);
char hexbuf[128 * 2 + 1];
bootloader_sha256_hex_to_str(hexbuf, bytes, output_len);
hexbuf[output_len * 2] = '\0';
ESP_LOGD(TAG, "%s: %s", label, hexbuf);/* ... */
#else
(void) buffer;
(void) length;
(void) label;/* ... */
#endif
}{ ... }
esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest)
{
if (digest == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
uint32_t mmu_free_pages_count = bootloader_mmap_get_free_pages();
bootloader_sha256_handle_t sha_handle = NULL;
sha_handle = bootloader_sha256_start();
if (sha_handle == NULL) {
return ESP_ERR_NO_MEM;
}{...}
while (len > 0) {
uint32_t mmu_page_offset = ((flash_offset & MMAP_ALIGNED_MASK) != 0) ? 1 : 0;
uint32_t partial_image_len = MIN(len, ((mmu_free_pages_count - mmu_page_offset) * SPI_FLASH_MMU_PAGE_SIZE));
const void * image = bootloader_mmap(flash_offset, partial_image_len);
if (image == NULL) {
bootloader_sha256_finish(sha_handle, NULL);
return ESP_FAIL;
}{...}
bootloader_sha256_data(sha_handle, image, partial_image_len);
bootloader_munmap(image);
flash_offset += partial_image_len;
len -= partial_image_len;
}{...}
bootloader_sha256_finish(sha_handle, digest);
return ESP_OK;
}{ ... }