diff --git a/components/bootloader/subproject/main/bootloader_start.c b/components/bootloader/subproject/main/bootloader_start.c index 64af8268e..d7c314b2e 100644 --- a/components/bootloader/subproject/main/bootloader_start.c +++ b/components/bootloader/subproject/main/bootloader_start.c @@ -27,7 +27,7 @@ static const char* TAG = "boot"; -static esp_err_t select_image (esp_image_metadata_t *image_data); +static int select_partition_number (bootloader_state_t *bs); static int selected_boot_partition(const bootloader_state_t *bs); /* * We arrive here after the ROM bootloader finished loading this second stage bootloader from flash. @@ -37,41 +37,32 @@ static int selected_boot_partition(const bootloader_state_t *bs); void call_start_cpu0() { // 1. Hardware initialization - if(bootloader_init() != ESP_OK){ + if (bootloader_init() != ESP_OK) { return; } - // 2. Select image to boot - esp_image_metadata_t image_data; - if(select_image(&image_data) != ESP_OK){ - return; - } - - // 3. Loading the selected image - bootloader_utility_load_image(&image_data); -} - -// Selects image to boot -static esp_err_t select_image (esp_image_metadata_t *image_data) -{ - // 1. Load partition table + // 2. Select the number of boot partition bootloader_state_t bs = { 0 }; - if (!bootloader_utility_load_partition_table(&bs)) { - ESP_LOGE(TAG, "load partition table error!"); - return ESP_FAIL; - } - - // 2. Select boot partition - int boot_index = selected_boot_partition(&bs); - if(boot_index == INVALID_INDEX) { - return ESP_FAIL; // Unrecoverable failure (not due to corrupt ota data or bad partition contents) + int boot_index = select_partition_number(&bs); + if (boot_index == INVALID_INDEX) { + return; } // 3. Load the app image for booting - if (!bootloader_utility_load_boot_image(&bs, boot_index, image_data)) { - return ESP_FAIL; + bootloader_utility_load_boot_image(&bs, boot_index); +} + +// Select the number of boot partition +static int select_partition_number (bootloader_state_t *bs) +{ + // 1. Load partition table + if (!bootloader_utility_load_partition_table(bs)) { + ESP_LOGE(TAG, "load partition table error!"); + return INVALID_INDEX; } - return ESP_OK; + + // 2. Select the number of boot partition + return selected_boot_partition(bs); } /* diff --git a/components/bootloader/subproject/main/esp32.bootloader.ld b/components/bootloader/subproject/main/esp32.bootloader.ld index 54fe1a9a3..2c5778c39 100644 --- a/components/bootloader/subproject/main/esp32.bootloader.ld +++ b/components/bootloader/subproject/main/esp32.bootloader.ld @@ -8,12 +8,14 @@ Linker file used to link the bootloader. The main purpose is to make sure the bootloader can load into main memory without overwriting itself. */ + MEMORY { /* I/O */ dport0_seg (RW) : org = 0x3FF00000, len = 0x10 - /* IRAM POOL1, used for APP CPU cache. We can abuse it in bootloader because APP CPU is still held in reset, the main app enables APP CPU cache */ - iram_seg (RWX) : org = 0x40078000, len = 0x8000 + /* IRAM POOL1, used for APP CPU cache. Bootloader runs from here during the final stage of loading the app because APP CPU is still held in reset, the main app enables APP CPU cache */ + iram_loader_seg (RWX) : org = 0x40078000, len = 0x8000 /* 32KB, APP CPU cache */ + iram_seg (RWX) : org = 0x40080000, len = 0x10000 /* 64KB, IRAM */ /* 64k at the end of DRAM, after ROM bootloader stack */ dram_seg (RW) : org = 0x3FFF0000, len = 0x10000 } @@ -24,7 +26,30 @@ ENTRY(call_start_cpu0); SECTIONS { - .iram1.text : + + .iram_loader.text : + { + . = ALIGN (16); + _stext = .; + _text_start = ABSOLUTE(.); + *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.iram1 .iram1.*) /* catch stray IRAM_ATTR */ + *liblog.a:(.literal .text .literal.* .text.*) + *libgcc.a:(.literal .text .literal.* .text.*) + *libbootloader_support.a:bootloader_utility.o(.literal .text .literal.* .text.*) + *libbootloader_support.a:esp_image_format.o(.literal .text .literal.* .text.*) + *libbootloader_support.a:bootloader_random.o(.literal .text .literal.* .text.*) + *libbootloader_support.a:bootloader_flash.o(.literal .text .literal.* .text.*) + *libbootloader_support.a:flash_partitions.o(.literal .text .literal.* .text.*) + *libbootloader_support.a:bootloader_sha.o(.literal .text .literal.* .text.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } > iram_loader_seg + + .iram.text : { . = ALIGN (16); *(.entry.text) @@ -121,7 +146,7 @@ SECTIONS _stext = .; _text_start = ABSOLUTE(.); *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) - *(.iram1 .iram1.*) /* catch stray IRAM_ATTR */ + *(.iram .iram.*) /* catch stray IRAM_ATTR */ *(.fini.literal) *(.fini) *(.gnu.version) diff --git a/components/bootloader_support/include/esp_flash_partitions.h b/components/bootloader_support/include/esp_flash_partitions.h index 843e5a283..98ab5b0f8 100644 --- a/components/bootloader_support/include/esp_flash_partitions.h +++ b/components/bootloader_support/include/esp_flash_partitions.h @@ -21,8 +21,7 @@ /* Pre-partition table fixed flash offsets */ #define ESP_BOOTLOADER_DIGEST_OFFSET 0x0 #define ESP_BOOTLOADER_OFFSET 0x1000 /* Offset of bootloader image. Has matching value in bootloader KConfig.projbuild file. */ -#define ESP_BOOTLOADER_SIZE (ESP_PARTITION_TABLE_OFFSET - ESP_BOOTLOADER_OFFSET) -#define ESP_PARTITION_TABLE_OFFSET 0x8000 /* Offset of partition table. Has matching value in partition_table Kconfig.projbuild file. */ +#define ESP_PARTITION_TABLE_OFFSET CONFIG_PARTITION_TABLE_OFFSET /* Offset of partition table. */ #define ESP_PARTITION_TABLE_MAX_LEN 0xC00 /* Maximum length of partition table data */ #define ESP_PARTITION_TABLE_MAX_ENTRIES (ESP_PARTITION_TABLE_MAX_LEN / sizeof(esp_partition_info_t)) /* Maximum length of partition table data, including terminating entry */ diff --git a/components/bootloader_support/include_priv/bootloader_utility.h b/components/bootloader_support/include_priv/bootloader_utility.h index 6cf6a77e1..d7231e685 100644 --- a/components/bootloader_support/include_priv/bootloader_utility.h +++ b/components/bootloader_support/include_priv/bootloader_utility.h @@ -40,25 +40,15 @@ bool bootloader_utility_load_partition_table(bootloader_state_t* bs); int bootloader_utility_get_selected_boot_partition(const bootloader_state_t *bs); /** - * @brief Load the app image for booting. + * @brief Load the selected partition and start application. * * Start from partition 'start_index', if not bootable then work backwards to FACTORY_INDEX * (ie try any OTA slots in descending order and then the factory partition). * If still nothing, start from 'start_index + 1' and work up to highest numbered OTA partition. * If still nothing, try TEST_APP_INDEX. + * Everything this function calls must be located in the iram_loader_seg segment. * * @param[in] bs Bootloader state structure. * @param[in] start_index The index from which the search for images begins. - * @param[out] result The image found. - * @return Returns true on success, false if there's no bootable app in the partition table. */ -bool bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_index, esp_image_metadata_t *result); - -/** - * @brief Loading the selected image. - * - * Copy loaded segments to RAM, set up caches for mapped segments, and start application. - * - * @param[in] data Structure to hold on-flash image metadata. - */ -void bootloader_utility_load_image(const esp_image_metadata_t* image_data); +__attribute__((noreturn)) void bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_index); diff --git a/components/bootloader_support/src/bootloader_common.c b/components/bootloader_support/src/bootloader_common.c index 0d72c3e11..2743d367d 100644 --- a/components/bootloader_support/src/bootloader_common.c +++ b/components/bootloader_support/src/bootloader_common.c @@ -99,7 +99,7 @@ bool bootloader_common_erase_part_type_data(const char *list_erase, bool ota_dat #ifdef CONFIG_SECURE_BOOT_ENABLED if (esp_secure_boot_enabled()) { ESP_LOGI(TAG, "Verifying partition table signature..."); - err = esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_MAX_LEN); + err = esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to verify partition table signature."); return false; @@ -108,12 +108,12 @@ bool bootloader_common_erase_part_type_data(const char *list_erase, bool ota_dat } #endif - partitions = bootloader_mmap(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_MAX_LEN); + 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_ADDR, ESP_PARTITION_TABLE_MAX_LEN); + 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_ADDR, (intptr_t)partitions); + ESP_LOGD(TAG, "mapped partition table 0x%x at 0x%x", ESP_PARTITION_TABLE_OFFSET, (intptr_t)partitions); err = esp_partition_table_basic_verify(partitions, true, &num_partitions); if (err != ESP_OK) { diff --git a/components/bootloader_support/src/bootloader_utility.c b/components/bootloader_support/src/bootloader_utility.c index eeaee2179..6ab3e50c5 100644 --- a/components/bootloader_support/src/bootloader_utility.c +++ b/components/bootloader_support/src/bootloader_utility.c @@ -55,6 +55,7 @@ static const char* TAG = "boot"; /* Reduce literal size for some generic string literals */ #define MAP_ERR_MSG "Image contains multiple %s segments. Only the last one will be mapped." +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, @@ -74,7 +75,7 @@ bool bootloader_utility_load_partition_table(bootloader_state_t* bs) #ifdef CONFIG_SECURE_BOOT_ENABLED if(esp_secure_boot_enabled()) { ESP_LOGI(TAG, "Verifying partition table signature..."); - err = esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_MAX_LEN); + err = esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to verify partition table signature."); return false; @@ -83,12 +84,12 @@ bool bootloader_utility_load_partition_table(bootloader_state_t* bs) } #endif - partitions = bootloader_mmap(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_MAX_LEN); + 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_ADDR, ESP_PARTITION_TABLE_MAX_LEN); - return false; + 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_ADDR, (intptr_t)partitions); + ESP_LOGD(TAG, "mapped partition table 0x%x at 0x%x", ESP_PARTITION_TABLE_OFFSET, (intptr_t)partitions); err = esp_partition_table_basic_verify(partitions, true, &num_partitions); if (err != ESP_OK) { @@ -287,18 +288,21 @@ static bool try_load_partition(const esp_partition_pos_t *partition, esp_image_m #define TRY_LOG_FORMAT "Trying partition index %d offs 0x%x size 0x%x" -bool bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_index, esp_image_metadata_t *result) +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; + if(start_index == TEST_APP_INDEX) { - if (try_load_partition(&bs->test, result)) { - return true; + if (try_load_partition(&bs->test, &image_data)) { + load_image(&image_data); } else { ESP_LOGE(TAG, "No bootable test partition in the partition table"); - return false; + return; } } + /* work backwards from start_index, down to the factory app */ for(index = start_index; index >= FACTORY_INDEX; index--) { part = index_to_partition(bs, index); @@ -306,8 +310,8 @@ bool bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_ continue; } ESP_LOGD(TAG, TRY_LOG_FORMAT, index, part.offset, part.size); - if (try_load_partition(&part, result)) { - return true; + if (try_load_partition(&part, &image_data)) { + load_image(&image_data); } log_invalid_app_partition(index); } @@ -319,23 +323,23 @@ bool bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_ continue; } ESP_LOGD(TAG, TRY_LOG_FORMAT, index, part.offset, part.size); - if (try_load_partition(&part, result)) { - return true; + if (try_load_partition(&part, &image_data)) { + load_image(&image_data); } log_invalid_app_partition(index); } - if (try_load_partition(&bs->test, result)) { + if (try_load_partition(&bs->test, &image_data)) { ESP_LOGW(TAG, "Falling back to test app as only bootable partition"); - return true; + load_image(&image_data); } ESP_LOGE(TAG, "No bootable app partitions in the partition table"); - bzero(result, sizeof(esp_image_metadata_t)); - return false; + bzero(&image_data, sizeof(esp_image_metadata_t)); } -void bootloader_utility_load_image(const esp_image_metadata_t* image_data) +// Copy loaded segments to RAM, set up caches for mapped segments, and start application. +static void load_image(const esp_image_metadata_t* image_data) { #if defined(CONFIG_SECURE_BOOT_ENABLED) || defined(CONFIG_FLASH_ENCRYPTION_ENABLED) esp_err_t err; @@ -463,7 +467,7 @@ static void set_cache_and_start_app( // Application will need to do Cache_Flush(1) and Cache_Read_Enable(1) ESP_LOGD(TAG, "start: 0x%08x", entry_addr); - typedef void (*entry_t)(void); + typedef void (*entry_t)(void) __attribute__((noreturn)); entry_t entry = ((entry_t) entry_addr); // TODO: we have used quite a bit of stack at this point. diff --git a/components/esp32/Makefile.projbuild b/components/esp32/Makefile.projbuild index 63318dd66..cedd6e104 100644 --- a/components/esp32/Makefile.projbuild +++ b/components/esp32/Makefile.projbuild @@ -4,8 +4,8 @@ PHY_INIT_DATA_OBJ = $(BUILD_DIR_BASE)/phy_init_data.o PHY_INIT_DATA_BIN = $(BUILD_DIR_BASE)/phy_init_data.bin # Command to flash PHY init data partition -PHY_INIT_DATA_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(CONFIG_PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN) -ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN) +PHY_INIT_DATA_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN) +ESPTOOL_ALL_FLASH_ARGS += $(PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN) ESP32_COMPONENT_PATH := $(COMPONENT_PATH) diff --git a/components/esp32/include/esp_flash_data_types.h b/components/esp32/include/esp_flash_data_types.h index 3e44b2639..bb5aa2998 100644 --- a/components/esp32/include/esp_flash_data_types.h +++ b/components/esp32/include/esp_flash_data_types.h @@ -21,7 +21,6 @@ extern "C" { #endif -#define ESP_PARTITION_TABLE_ADDR 0x8000 #define ESP_PARTITION_MAGIC 0x50AA #define ESP_PARTITION_MAGIC_MD5 0xEBEB diff --git a/components/esptool_py/Makefile.projbuild b/components/esptool_py/Makefile.projbuild index dce6b0af2..c542c526d 100644 --- a/components/esptool_py/Makefile.projbuild +++ b/components/esptool_py/Makefile.projbuild @@ -33,7 +33,7 @@ ESPTOOL_ELF2IMAGE_OPTIONS := ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z,-u) $(ESPTOOL_WRITE_FLASH_OPTIONS) -ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN) +ESPTOOL_ALL_FLASH_ARGS += $(APP_OFFSET) $(APP_BIN) ifdef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES ifndef IS_BOOTLOADER_BUILD @@ -50,16 +50,16 @@ APP_BIN_UNSIGNED ?= $(APP_BIN) $(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC) $(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) $(ESPTOOL_ELF2IMAGE_OPTIONS) -o $@ $< -flash: all_binaries $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) - @echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(CONFIG_APP_OFFSET))..." +flash: all_binaries $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info + @echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(APP_OFFSET))..." ifdef CONFIG_SECURE_BOOT_ENABLED @echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)" endif $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS) -app-flash: $(APP_BIN) $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) - @echo "Flashing app to serial port $(ESPPORT), offset $(CONFIG_APP_OFFSET)..." - $(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN) +app-flash: $(APP_BIN) $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info + @echo "Flashing app to serial port $(ESPPORT), offset $(APP_OFFSET)..." + $(ESPTOOLPY_WRITE_FLASH) $(APP_OFFSET) $(APP_BIN) # Submodules normally added in component.mk, but can be added # at the project level as long as qualified path diff --git a/components/partition_table/Kconfig.projbuild b/components/partition_table/Kconfig.projbuild index 09635d67a..db311145e 100644 --- a/components/partition_table/Kconfig.projbuild +++ b/components/partition_table/Kconfig.projbuild @@ -27,22 +27,6 @@ config PARTITION_TABLE_CUSTOM_FILENAME Name of the custom partition CSV filename. This path is evaluated relative to the project root directory. -config PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET - hex "Factory app partition offset" if PARTITION_TABLE_CUSTOM - default 0x10000 - help - If using a custom partition table, specify the offset in the flash - where 'make flash' should write the built app. - -config PARTITION_TABLE_CUSTOM_PHY_DATA_OFFSET - hex "PHY data partition offset" if PARTITION_TABLE_CUSTOM - depends on ESP32_PHY_INIT_DATA_IN_PARTITION - default 0xf000 - help - If using a custom partition table, specify the offset in the flash - where 'make flash' should write the initial PHY data file. - - config PARTITION_TABLE_FILENAME string default partitions_singleapp.csv if PARTITION_TABLE_SINGLE_APP && !ESP32_ENABLE_COREDUMP_TO_FLASH @@ -51,16 +35,13 @@ config PARTITION_TABLE_FILENAME default partitions_two_ota_coredump.csv if PARTITION_TABLE_TWO_OTA && ESP32_ENABLE_COREDUMP_TO_FLASH default PARTITION_TABLE_CUSTOM_FILENAME if PARTITION_TABLE_CUSTOM -config APP_OFFSET - hex - default PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET if PARTITION_TABLE_CUSTOM - default 0x10000 # this is the factory app offset used by the default tables - -config PHY_DATA_OFFSET - depends on ESP32_PHY_INIT_DATA_IN_PARTITION - hex - default PARTITION_TABLE_CUSTOM_PHY_DATA_OFFSET if PARTITION_TABLE_CUSTOM - default 0xf000 # this is the factory app offset used by the default tables +config PARTITION_TABLE_OFFSET + hex "Offset of partition table" + default 0x8000 + help + The address of partition table (by default 0x8000). + Allows you to move the partition table, it gives more space for the bootloader. + Note that the bootloader and app will both need to be compiled with the same PARTITION_TABLE_OFFSET value. config PARTITION_TABLE_MD5 bool "Generate an MD5 checksum for the partition table" diff --git a/components/partition_table/Makefile.projbuild b/components/partition_table/Makefile.projbuild index 930737fff..35dc4f0db 100644 --- a/components/partition_table/Makefile.projbuild +++ b/components/partition_table/Makefile.projbuild @@ -6,7 +6,7 @@ # the partition table binary as part of the build process. This # binary is then added to the list of files for esptool.py to flash. # -.PHONY: partition_table partition_table-flash partition_table-clean +.PHONY: partition_table partition_table-flash partition_table-clean partition_table_get_info PARTITION_MD5_OPT := ifneq ("$(CONFIG_PARTITION_TABLE_MD5)", "y") @@ -18,10 +18,12 @@ ifneq ("$(CONFIG_ESPTOOLPY_FLASHSIZE)", "") PARTITION_FLASHSIZE_OPT := --flash-size $(CONFIG_ESPTOOLPY_FLASHSIZE) endif -GEN_ESP32PART := $(PYTHON) $(COMPONENT_PATH)/gen_esp32part.py -q $(PARTITION_MD5_OPT) $(PARTITION_FLASHSIZE_OPT) +# Address of partition table +PARTITION_TABLE_OFFSET := $(CONFIG_PARTITION_TABLE_OFFSET) +PARTITION_TABLE_OFFSET_ARG := --offset $(PARTITION_TABLE_OFFSET) -# Has a matching value in bootloader_support esp_flash_partitions.h -PARTITION_TABLE_OFFSET := 0x8000 +GEN_ESP32PART := $(PYTHON) $(COMPONENT_PATH)/gen_esp32part.py -q $(PARTITION_MD5_OPT) $(PARTITION_FLASHSIZE_OPT) $(PARTITION_TABLE_OFFSET_ARG) +GET_PART_INFO := $(COMPONENT_PATH)/parttool.py -q # if CONFIG_PARTITION_TABLE_FILENAME is unset, means we haven't re-generated config yet... ifneq ("$(CONFIG_PARTITION_TABLE_FILENAME)","") @@ -51,12 +53,19 @@ $(PARTITION_TABLE_BIN_UNSIGNED): $(PARTITION_TABLE_CSV_PATH) $(SDKCONFIG_MAKEFIL @echo "Building partitions from $(PARTITION_TABLE_CSV_PATH)..." $(GEN_ESP32PART) $< $@ -all_binaries: $(PARTITION_TABLE_BIN) +all_binaries: $(PARTITION_TABLE_BIN) partition_table_get_info + +partition_table_get_info: $(PARTITION_TABLE_BIN) + $(eval PHY_DATA_OFFSET:=$(shell $(GET_PART_INFO) --type data --subtype phy --offset $(PARTITION_TABLE_BIN))) + $(eval APP_OFFSET:=$(shell $(GET_PART_INFO) --type app --subtype factory --offset $(PARTITION_TABLE_BIN))) + +export APP_OFFSET +export PHY_DATA_OFFSET PARTITION_TABLE_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(PARTITION_TABLE_OFFSET) $(PARTITION_TABLE_BIN) ESPTOOL_ALL_FLASH_ARGS += $(PARTITION_TABLE_OFFSET) $(PARTITION_TABLE_BIN) -partition_table: $(PARTITION_TABLE_BIN) +partition_table: $(PARTITION_TABLE_BIN) partition_table_get_info @echo "Partition table binary generated. Contents:" @echo $(SEPARATOR) $(GEN_ESP32PART) $< diff --git a/components/partition_table/gen_esp32part.py b/components/partition_table/gen_esp32part.py index 0e3a0b7e9..39f657b0c 100755 --- a/components/partition_table/gen_esp32part.py +++ b/components/partition_table/gen_esp32part.py @@ -31,11 +31,13 @@ import binascii MAX_PARTITION_LENGTH = 0xC00 # 3K for partition data (96 entries) leaves 1K in a 4K sector for signature MD5_PARTITION_BEGIN = b"\xEB\xEB" + b"\xFF" * 14 # The first 2 bytes are like magic numbers for MD5 sum +PARTITION_TABLE_SIZE = 0x1000 # Size of partition table -__version__ = '1.0' +__version__ = '1.1' quiet = False md5sum = True +offset_part_table = 0 def status(msg): """ Print status message to stderr """ @@ -77,8 +79,11 @@ class PartitionTable(list): raise # fix up missing offsets & negative sizes - last_end = 0x5000 # first offset after partition table + last_end = offset_part_table + PARTITION_TABLE_SIZE # first offset after partition table for e in res: + if offset_part_table != 0 and e.offset is not None and e.offset < last_end: + critical("WARNING: 0x%x address in the partition table is below 0x%x" % (e.offset, last_end)) + e.offset = None if e.offset is None: pad_to = 0x10000 if e.type == PartitionDefinition.APP_TYPE else 4 if last_end % pad_to != 0: @@ -108,8 +113,8 @@ class PartitionTable(list): # check for overlaps last = None for p in sorted(self, key=lambda x:x.offset): - if p.offset < 0x5000: - raise InputError("Partition offset 0x%x is below 0x5000" % p.offset) + if p.offset < offset_part_table + PARTITION_TABLE_SIZE: + raise InputError("Partition offset 0x%x is below 0x%x" % (p.offset, offset_part_table + PARTITION_TABLE_SIZE)) if last is not None and p.offset < last.offset + last.size: raise InputError("Partition at 0x%x overlaps 0x%x-0x%x" % (p.offset, last.offset, last.offset+last.size-1)) last = p @@ -370,6 +375,7 @@ def parse_int(v, keywords={}): def main(): global quiet global md5sum + global offset_part_table parser = argparse.ArgumentParser(description='ESP32 partition table utility') parser.add_argument('--flash-size', help='Optional flash size limit, checks partition table fits in flash', @@ -377,7 +383,8 @@ def main(): parser.add_argument('--disable-md5sum', help='Disable md5 checksum for the partition table', default=False, action='store_true') parser.add_argument('--verify', '-v', help='Verify partition table fields', default=True, action='store_false') parser.add_argument('--quiet', '-q', help="Don't print status messages to stderr", action='store_true') - + parser.add_argument('--offset', '-o', help='Set offset partition table', default='0x8000') + parser.add_argument('input', help='Path to CSV or binary file to parse. Will use stdin if omitted.', type=argparse.FileType('rb'), default=sys.stdin) parser.add_argument('output', help='Path to output converted binary or CSV file. Will use stdout if omitted, unless the --display argument is also passed (in which case only the summary is printed.)', nargs='?', @@ -387,6 +394,7 @@ def main(): quiet = args.quiet md5sum = not args.disable_md5sum + offset_part_table = int(args.offset, 0) input = args.input.read() input_is_binary = input[0:2] == PartitionDefinition.MAGIC_BYTES if input_is_binary: diff --git a/components/partition_table/parttool.py b/components/partition_table/parttool.py new file mode 100755 index 000000000..e6ccf2532 --- /dev/null +++ b/components/partition_table/parttool.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python +# +# parttool returns info about the required partition. +# +# This utility is used by the make system to get information +# about the start addresses: partition table, factory area, phy area. +# +# Copyright 2018 Espressif Systems (Shanghai) PTE LTD +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import print_function, division +import argparse +import os +import re +import struct +import sys +import hashlib +import binascii +import gen_esp32part as gen + +__version__ = '1.0' + +quiet = False + +def status(msg): + """ Print status message to stderr """ + if not quiet: + critical(msg) + +def critical(msg): + """ Print critical message to stderr """ + if not quiet: + sys.stderr.write(msg) + sys.stderr.write('\n') + +def main(): + global quiet + parser = argparse.ArgumentParser(description='Returns info about the required partition.') + + parser.add_argument('--quiet', '-q', help="Don't print status messages to stderr", action='store_true') + parser.add_argument('--partition-name', '-p', help='The name of the required partition', type=str, default=None) + parser.add_argument('--type', '-t', help='The type of the required partition', type=str, default=None) + parser.add_argument('--subtype', '-s', help='The subtype of the required partition', type=str, default=None) + + parser.add_argument('--offset', '-o', help='Return offset of required partition', action="store_true", default=None) + parser.add_argument('--size', help='Return size of required partition', action="store_true", default=None) + + parser.add_argument('input', help='Path to CSV or binary file to parse. Will use stdin if omitted.', type=argparse.FileType('rb'), default=sys.stdin) + + args = parser.parse_args() + + quiet = args.quiet + + input = args.input.read() + input_is_binary = input[0:2] == gen.PartitionDefinition.MAGIC_BYTES + if input_is_binary: + status("Parsing binary partition input...") + table = gen.PartitionTable.from_binary(input) + else: + input = input.decode() + status("Parsing CSV input...") + table = gen.PartitionTable.from_csv(input) + + if args.partition_name is not None: + offset = 0 + size = 0 + for p in table: + if p.name == args.partition_name: + offset = p.offset + size = p.size + break; + if args.offset is not None: + print('0x%x ' % (offset)) + if args.size is not None: + print('0x%x' % (size)) + return 0 + + if args.type is not None and args.subtype is not None: + offset = 0 + size = 0 + TYPES = gen.PartitionDefinition.TYPES + SUBTYPES = gen.PartitionDefinition.SUBTYPES + for p in table: + if p.type == TYPES[args.type]: + if p.subtype == SUBTYPES[TYPES[args.type]][args.subtype]: + offset = p.offset + size = p.size + break; + if args.offset is not None: + print('0x%x ' % (offset)) + if args.size is not None: + print('0x%x' % (size)) + return 0 + +class InputError(RuntimeError): + def __init__(self, e): + super(InputError, self).__init__(e) + + +class ValidationError(InputError): + def __init__(self, partition, message): + super(ValidationError, self).__init__( + "Partition %s invalid: %s" % (partition.name, message)) + + +if __name__ == '__main__': + try: + main() + except InputError as e: + print(e, file=sys.stderr) + sys.exit(2) diff --git a/components/spi_flash/partition.c b/components/spi_flash/partition.c index 1c3ac610f..400329199 100644 --- a/components/spi_flash/partition.c +++ b/components/spi_flash/partition.c @@ -17,7 +17,7 @@ #include #include #include - +#include "esp_flash_partitions.h" #include "esp_attr.h" #include "esp_flash_data_types.h" #include "esp_spi_flash.h" @@ -145,14 +145,14 @@ static esp_err_t load_partitions() const uint32_t* ptr; spi_flash_mmap_handle_t handle; // map 64kB block where partition table is located - esp_err_t err = spi_flash_mmap(ESP_PARTITION_TABLE_ADDR & 0xffff0000, + esp_err_t err = spi_flash_mmap(ESP_PARTITION_TABLE_OFFSET & 0xffff0000, SPI_FLASH_SEC_SIZE, SPI_FLASH_MMAP_DATA, (const void**) &ptr, &handle); if (err != ESP_OK) { return err; } // calculate partition address within mmap-ed region const esp_partition_info_t* it = (const esp_partition_info_t*) - (ptr + (ESP_PARTITION_TABLE_ADDR & 0xffff) / sizeof(*ptr)); + (ptr + (ESP_PARTITION_TABLE_OFFSET & 0xffff) / sizeof(*ptr)); const esp_partition_info_t* end = it + SPI_FLASH_SEC_SIZE / sizeof(*it); // tail of the linked list of partitions partition_list_item_t* last = NULL; diff --git a/make/project.mk b/make/project.mk index 01b29bcb3..72a3e6f9a 100644 --- a/make/project.mk +++ b/make/project.mk @@ -405,15 +405,15 @@ $(APP_ELF): $(foreach libcomp,$(COMPONENT_LIBRARIES),$(BUILD_DIR_BASE)/$(libcomp $(summary) LD $(patsubst $(PWD)/%,%,$@) $(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP) -app: $(APP_BIN) +app: $(APP_BIN) partition_table_get_info ifeq ("$(CONFIG_SECURE_BOOT_ENABLED)$(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)","y") # secure boot enabled, but remote sign app image @echo "App built but not signed. Signing step via espsecure.py:" @echo "espsecure.py sign_data --keyfile KEYFILE $(APP_BIN)" @echo "Then flash app command is:" - @echo $(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN) + @echo $(ESPTOOLPY_WRITE_FLASH) $(APP_OFFSET) $(APP_BIN) else @echo "App built. Default flash app command is:" - @echo $(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN) + @echo $(ESPTOOLPY_WRITE_FLASH) $(APP_OFFSET) $(APP_BIN) endif all_binaries: $(APP_BIN) @@ -543,7 +543,7 @@ list-components: $(foreach cp,$(COMPONENT_PATHS),$(info $(cp))) # print flash command, so users can dump this to config files and download somewhere without idf -print_flash_cmd: +print_flash_cmd: partition_table_get_info echo $(ESPTOOL_WRITE_FLASH_OPTIONS) $(ESPTOOL_ALL_FLASH_ARGS) | sed -e 's:'$(PWD)/build/'::g' # Check toolchain version using the output of xtensa-esp32-elf-gcc --version command. diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index a78581024..6fc884a00 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -4,6 +4,7 @@ components/espcoredump/espcoredump.py components/heap/test_multi_heap_host/test_all_configs.sh components/idf_test/unit_test/TestCaseScript/IDFUnitTest/__init__.py components/partition_table/gen_esp32part.py +components/partition_table/parttool.py components/partition_table/test_gen_esp32part_host/gen_esp32part_tests.py components/ulp/esp32ulp_mapgen.py docs/check_doc_warnings.sh