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:
Angus Gratton 2018-06-18 12:34:53 +08:00
commit 43b6c76bba
16 changed files with 251 additions and 123 deletions

View File

@ -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);
}
/*

View File

@ -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)

View File

@ -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 */

View File

@ -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);

View File

@ -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) {

View File

@ -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.

View File

@ -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)

View File

@ -21,7 +21,6 @@ extern "C"
{
#endif
#define ESP_PARTITION_TABLE_ADDR 0x8000
#define ESP_PARTITION_MAGIC 0x50AA
#define ESP_PARTITION_MAGIC_MD5 0xEBEB

View File

@ -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

View File

@ -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"

View File

@ -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) $<

View File

@ -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:

View 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)

View File

@ -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;

View File

@ -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.

View File

@ -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