mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/expansion_space_for_bootloader' into 'master'
partition_table: Moving to custom offset See merge request idf/esp-idf!2263
This commit is contained in:
commit
43b6c76bba
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
||||
|
@ -21,7 +21,6 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define ESP_PARTITION_TABLE_ADDR 0x8000
|
||||
#define ESP_PARTITION_MAGIC 0x50AA
|
||||
#define ESP_PARTITION_MAGIC_MD5 0xEBEB
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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) $<
|
||||
|
@ -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:
|
||||
|
121
components/partition_table/parttool.py
Executable file
121
components/partition_table/parttool.py
Executable file
@ -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)
|
@ -17,7 +17,7 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
#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;
|
||||
|
@ -406,15 +406,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)
|
||||
@ -544,7 +544,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.
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user