Merge branch 'feature/get_partition_info_v3.1' into 'release/v3.1'

feat(partition_table): Compiling script gets partition information from partition binary (backport v3.1)

See merge request sdk/ESP8266_RTOS_SDK!820
This commit is contained in:
Dong Heng
2019-03-06 11:53:34 +08:00
10 changed files with 287 additions and 213 deletions

View File

@ -35,8 +35,8 @@ PHY_INIT_DATA_OBJ = $(BUILD_DIR_BASE)/phy_init_data.o
PHY_INIT_DATA_BIN = $(BUILD_DIR_BASE)/phy_init_data.bin PHY_INIT_DATA_BIN = $(BUILD_DIR_BASE)/phy_init_data.bin
# Command to flash PHY init data partition # Command to flash PHY init data partition
PHY_INIT_DATA_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(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 += $(CONFIG_PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN) ESPTOOL_ALL_FLASH_ARGS += $(PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN)
ESP8266_COMPONENT_PATH := $(COMPONENT_PATH) ESP8266_COMPONENT_PATH := $(COMPONENT_PATH)
@ -91,51 +91,35 @@ OTA2_BIN := ./build/$(PROJECT_NAME).app2.bin
OTA_V2_TO_V3_BIN := ./build/$(PROJECT_NAME).v2_to_v3.ota.bin OTA_V2_TO_V3_BIN := ./build/$(PROJECT_NAME).v2_to_v3.ota.bin
ifndef CONFIG_APP2_OFFSET ifndef CONFIG_ESP8266_BOOT_COPY_APP
CONFIG_APP2_OFFSET := $(CONFIG_APP1_OFFSET) ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB
__COMBILE_OTA_BIN := 1
endif
endif endif
ifndef CONFIG_APP2_SIZE $(OTA1_BIN): all_binaries
CONFIG_APP2_SIZE := $(CONFIG_APP1_SIZE) @cp $(RAW_BIN) $(OTA1_BIN)
endif @echo [GEN] $(OTA1_BIN)
OTA1_OFFSET := $(CONFIG_APP1_OFFSET) $(OTA2_BIN): $(OTA1_BIN)
ifdef CONFIG_ESP8266_BOOT_COPY_APP ifdef __COMBILE_OTA_BIN
OTA2_LINK_OFFSET := $(CONFIG_APP1_OFFSET)
else
OTA2_LINK_OFFSET := $(CONFIG_APP2_OFFSET)
endif
$(OTA2_BIN): all_binaries
ifneq ($(OTA1_OFFSET), $(OTA2_LINK_OFFSET))
@rm -f ./build/esp8266/esp8266_out.ld @rm -f ./build/esp8266/esp8266_out.ld
@make APP_OFFSET=$(OTA2_LINK_OFFSET) APP_SIZE=$(CONFIG_APP2_SIZE) CFLAGS= CXXFLAGS= @export CFLAGS= && export CXXFLAGS= && make APP_OFFSET=$(APP2_OFFSET) APP_SIZE=$(APP2_SIZE)
endif endif
@cp $(RAW_BIN) $(OTA2_BIN) @cp $(RAW_BIN) $(OTA2_BIN)
@echo [GEN] $(OTA2_BIN) @echo [GEN] $(OTA2_BIN)
$(OTA1_BIN): all_binaries $(OTA_BIN): $(OTA2_BIN)
ifneq ($(OTA1_OFFSET), $(OTA2_LINK_OFFSET))
@rm -f ./build/esp8266/esp8266_out.ld
endif
@make APP_OFFSET=$(OTA1_OFFSET) APP_SIZE=$(CONFIG_APP1_SIZE) CFLAGS= CXXFLAGS=
@cp $(RAW_BIN) $(OTA1_BIN)
@echo [GEN] $(OTA1_BIN)
$(OTA_BIN): $(OTA1_BIN) $(OTA2_BIN)
@cp $(OTA1_BIN) $(OTA_BIN) @cp $(OTA1_BIN) $(OTA_BIN)
ifneq ($(OTA1_OFFSET), $(OTA2_LINK_OFFSET)) ifdef __COMBILE_OTA_BIN
@cat $(OTA2_BIN) >> $(OTA_BIN) @cat $(OTA2_BIN) >> $(OTA_BIN)
endif
@cp $(OTA1_BIN) $(RAW_BIN) @cp $(OTA1_BIN) $(RAW_BIN)
endif
@echo [GEN] $(OTA_BIN) @echo [GEN] $(OTA_BIN)
ifdef CONFIG_ESP8266_OTA_FROM_OLD ifdef CONFIG_ESP8266_OTA_FROM_OLD
$(OTA_V2_TO_V3_BIN): $(OTA_BIN) $(OTA_V2_TO_V3_BIN):
@cp $(RAW_BIN) $(RAW_BIN).tmp.bak
@cp $(OTA1_BIN) $(RAW_BIN)
@python $(IDF_PATH)/tools/pack_fw.py --output $(OTA_V2_TO_V3_BIN) pack3 $(ESPTOOL_ALL_FLASH_ARGS) @python $(IDF_PATH)/tools/pack_fw.py --output $(OTA_V2_TO_V3_BIN) pack3 $(ESPTOOL_ALL_FLASH_ARGS)
@cp $(RAW_BIN).tmp.bak $(RAW_BIN)
@echo [GEN] $(OTA_V2_TO_V3_BIN) @echo [GEN] $(OTA_V2_TO_V3_BIN)
endif endif

View File

@ -41,10 +41,8 @@ COMPONENT_ADD_LINKER_DEPS := $(ALL_LIB_FILES) $(addprefix ld/,$(LINKER_SCRIPTS))
# saves us from having to add the target to a Makefile.projbuild # saves us from having to add the target to a Makefile.projbuild
$(COMPONENT_LIBRARY): esp8266_out.ld esp8266_common_out.ld $(COMPONENT_LIBRARY): esp8266_out.ld esp8266_common_out.ld
OUTLD_CFLAGS := -DAPP_OFFSET=$(APP_OFFSET) -DAPP_SIZE=$(APP_SIZE)
esp8266_out.ld: $(COMPONENT_PATH)/ld/esp8266.ld ../include/sdkconfig.h esp8266_out.ld: $(COMPONENT_PATH)/ld/esp8266.ld ../include/sdkconfig.h
$(CC) $(OUTLD_CFLAGS) -I ../include -C -P -x c -E $< -o $@ $(CC) $(CFLAGS) -I ../include -C -P -x c -E $< -o $@
esp8266_common_out.ld: $(COMPONENT_PATH)/ld/esp8266.common.ld ../include/sdkconfig.h esp8266_common_out.ld: $(COMPONENT_PATH)/ld/esp8266.common.ld ../include/sdkconfig.h
$(CC) -I ../include -C -P -x c -E $< -o $@ $(CC) -I ../include -C -P -x c -E $< -o $@

View File

@ -33,15 +33,6 @@ config PARTITION_TABLE_OFFSET
help help
The partition table cannot be placed at application address. The partition table cannot be placed at application address.
config PARTITION_TABLE_CUSTOM_PHY_DATA_OFFSET
hex "PHY data partition offset" if PARTITION_TABLE_CUSTOM
depends on ESP_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 config PARTITION_TABLE_FILENAME
string string
default partitions_singleapp.csv if PARTITION_TABLE_SINGLE_APP && !ESP32_ENABLE_COREDUMP_TO_FLASH default partitions_singleapp.csv if PARTITION_TABLE_SINGLE_APP && !ESP32_ENABLE_COREDUMP_TO_FLASH
@ -51,56 +42,6 @@ config PARTITION_TABLE_FILENAME
default partitions_two_ota_coredump.csv if PARTITION_TABLE_TWO_OTA && ESP32_ENABLE_COREDUMP_TO_FLASH 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 default PARTITION_TABLE_CUSTOM_FILENAME if PARTITION_TABLE_CUSTOM
config PHY_DATA_OFFSET
depends on ESP_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 APP2_SUPPORT
depends on ESPTOOLPY_FLASHSIZE_1MB && (PARTITION_TABLE_TWO_OTA || PARTITION_TABLE_CUSTOM)
bool "Support to setup partition parameter of APP2" if PARTITION_TABLE_CUSTOM
default y
help
Enable this option, if you want to have APP1 & APP2 in 1MB SPI Flash.
config APP1_OFFSET
hex "APP1 partition offset" if PARTITION_TABLE_CUSTOM
default 0x10000
help
If using a custom partition table, specify the offset in the flash
where the APP1 located.
It should be same as the value in the custom partition table CSV.
config APP1_SIZE
hex "APP1 partition size(by bytes)" if PARTITION_TABLE_CUSTOM
default 0x70000 if APP2_SUPPORT
default 0xF0000
help
APP1 partition size by bytes.
It should be same as the value in the custom partition table CSV.
config APP2_OFFSET
depends on APP2_SUPPORT
hex "APP2 partition offset" if PARTITION_TABLE_CUSTOM
default 0x80000
help
If using a custom partition table, specify the offset in the flash
where the APP2 located.
It should be same as the value in the custom partition table CSV.
config APP2_SIZE
depends on APP2_SUPPORT
hex "APP2 partition size(by bytes)" if PARTITION_TABLE_CUSTOM
default 0x70000
help
APP2 partition size by bytes.
It should be same as the value in the custom partition table CSV.
endmenu endmenu

View File

@ -6,14 +6,24 @@
# the partition table binary as part of the build process. This # 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. # 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 := "--disable-md5sum"
PARTITION_FLASHSIZE_OPT :=
ifneq ("$(CONFIG_ESPTOOLPY_FLASHSIZE)", "")
PARTITION_FLASHSIZE_OPT := --flash-size $(CONFIG_ESPTOOLPY_FLASHSIZE)
endif
PARTITION_SECURE_OPT :=
# Address of partition table
PARTITION_TABLE_OFFSET := $(CONFIG_PARTITION_TABLE_OFFSET)
PARTITION_TABLE_OFFSET_ARG := --offset $(PARTITION_TABLE_OFFSET)
# NB: gen_esp32part.py lives in the sdk/bin/ dir not component dir # NB: gen_esp32part.py lives in the sdk/bin/ dir not component dir
GEN_ESP32PART := $(PYTHON) $(COMPONENT_PATH)/gen_esp32part.py -q GEN_ESP32PART := $(PYTHON) $(COMPONENT_PATH)/gen_esp32part.py -q $(PARTITION_MD5_OPT) $(PARTITION_FLASHSIZE_OPT) $(PARTITION_TABLE_OFFSET_ARG) $(PARTITION_SECURE_OPT)
GET_PART_INFO := $(COMPONENT_PATH)/parttool.py -q
# Has a matching value in bootloader_support esp_flash_partitions.h
PARTITION_TABLE_OFFSET := $(CONFIG_PARTITION_TABLE_OFFSET)
# if CONFIG_PARTITION_TABLE_FILENAME is unset, means we haven't re-generated config yet... # if CONFIG_PARTITION_TABLE_FILENAME is unset, means we haven't re-generated config yet...
ifneq ("$(CONFIG_PARTITION_TABLE_FILENAME)","") ifneq ("$(CONFIG_PARTITION_TABLE_FILENAME)","")
@ -43,17 +53,22 @@ $(PARTITION_TABLE_BIN_UNSIGNED): $(PARTITION_TABLE_CSV_PATH) $(SDKCONFIG_MAKEFIL
@echo "Building partitions from $(PARTITION_TABLE_CSV_PATH)..." @echo "Building partitions from $(PARTITION_TABLE_CSV_PATH)..."
$(GEN_ESP32PART) $< $@ $(GEN_ESP32PART) $< $@
all_binaries: $(PARTITION_TABLE_BIN) all_binaries: $(PARTITION_TABLE_BIN) partition_table_get_info
APP_OFFSET ?= $(CONFIG_APP1_OFFSET) partition_table_get_info: $(PARTITION_TABLE_BIN)
APP_SIZE ?= $(CONFIG_APP1_SIZE) $(eval PHY_DATA_OFFSET:=$(shell $(GET_PART_INFO) --type data --subtype phy --offset $(PARTITION_TABLE_BIN)))
$(eval APP_OFFSET:=$(shell $(GET_PART_INFO) --default-boot-partition --offset $(PARTITION_TABLE_BIN)))
$(eval APP_SIZE:=$(shell $(GET_PART_INFO) --default-boot-partition --size $(PARTITION_TABLE_BIN)))
$(eval APP2_OFFSET:=$(shell $(GET_PART_INFO) --type app --subtype ota_1 --offset $(PARTITION_TABLE_BIN)))
$(eval APP2_SIZE:=$(shell $(GET_PART_INFO) --type app --subtype ota_1 --size $(PARTITION_TABLE_BIN)))
$(eval CFLAGS += -DAPP_OFFSET=$(APP_OFFSET) -DAPP_SIZE=$(APP_SIZE))
export APP_OFFSET APP_SIZE export PHY_DATA_OFFSET APP_OFFSET APP_SIZE APP2_OFFSET APP2_SIZE
PARTITION_TABLE_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(PARTITION_TABLE_OFFSET) $(PARTITION_TABLE_BIN) PARTITION_TABLE_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(PARTITION_TABLE_OFFSET) $(PARTITION_TABLE_BIN)
ESPTOOL_ALL_FLASH_ARGS += $(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 "Partition table binary generated. Contents:"
@echo $(SEPARATOR) @echo $(SEPARATOR)
$(GEN_ESP32PART) $< $(GEN_ESP32PART) $<
@ -68,6 +83,8 @@ partition_table-flash: $(PARTITION_TABLE_BIN)
partition_table-clean: partition_table-clean:
rm -f $(PARTITION_TABLE_BIN) rm -f $(PARTITION_TABLE_BIN)
global-macro: partition_table_get_info
clean: partition_table-clean clean: partition_table-clean
endif endif

View File

@ -4,7 +4,7 @@
# #
# Converts partition tables to/from CSV and binary formats. # Converts partition tables to/from CSV and binary formats.
# #
# See http://esp-idf.readthedocs.io/en/latest/api-guides/partition-tables.html # See https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/partition-tables.html
# for explanation of partition table structure and uses. # for explanation of partition table structure and uses.
# #
# Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD # Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
@ -26,12 +26,19 @@ import os
import re import re
import struct import struct
import sys import sys
import hashlib
import binascii
MAX_PARTITION_LENGTH = 0xC00 # 3K for partition data (96 entries) leaves 1K in a 4K sector for signature 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 quiet = False
md5sum = True
secure = False
offset_part_table = 0
def status(msg): def status(msg):
""" Print status message to stderr """ """ Print status message to stderr """
@ -73,8 +80,11 @@ class PartitionTable(list):
raise raise
# fix up missing offsets & negative sizes # 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: 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: if e.offset is None:
pad_to = 0x10000 if e.type == PartitionDefinition.APP_TYPE else 4 pad_to = 0x10000 if e.type == PartitionDefinition.APP_TYPE else 4
if last_end % pad_to != 0: if last_end % pad_to != 0:
@ -97,6 +107,38 @@ class PartitionTable(list):
else: else:
return super(PartitionTable, self).__getitem__(item) return super(PartitionTable, self).__getitem__(item)
def find_by_type(self, ptype, subtype):
""" Return a partition by type & subtype, returns
None if not found """
TYPES = PartitionDefinition.TYPES
SUBTYPES = PartitionDefinition.SUBTYPES
# convert ptype & subtypes names (if supplied this way) to integer values
try:
ptype = TYPES[ptype]
except KeyError:
try:
ptypes = int(ptype, 0)
except TypeError:
pass
try:
subtype = SUBTYPES[int(ptype)][subtype]
except KeyError:
try:
ptypes = int(ptype, 0)
except TypeError:
pass
for p in self:
if p.type == ptype and p.subtype == subtype:
return p
return None
def find_by_name(self, name):
for p in self:
if p.name == name:
return p
return None
def verify(self): def verify(self):
# verify each partition individually # verify each partition individually
for p in self: for p in self:
@ -104,14 +146,25 @@ class PartitionTable(list):
# check for overlaps # check for overlaps
last = None last = None
for p in sorted(self, key=lambda x:x.offset): for p in sorted(self, key=lambda x:x.offset):
if p.offset < 0x5000: if p.offset < offset_part_table + PARTITION_TABLE_SIZE:
raise InputError("Partition offset 0x%x is below 0x5000" % p.offset) 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: 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)) raise InputError("Partition at 0x%x overlaps 0x%x-0x%x" % (p.offset, last.offset, last.offset+last.size-1))
last = p last = p
def flash_size(self):
""" Return the size that partitions will occupy in flash
(ie the offset the last partition ends at)
"""
try:
last = sorted(self, reverse=True)[0]
except IndexError:
return 0 # empty table!
return last.offset + last.size
@classmethod @classmethod
def from_binary(cls, b): def from_binary(cls, b):
md5 = hashlib.md5();
result = cls() result = cls()
for o in range(0,len(b),32): for o in range(0,len(b),32):
data = b[o:o+32] data = b[o:o+32]
@ -119,11 +172,20 @@ class PartitionTable(list):
raise InputError("Partition table length must be a multiple of 32 bytes") raise InputError("Partition table length must be a multiple of 32 bytes")
if data == b'\xFF'*32: if data == b'\xFF'*32:
return result # got end marker return result # got end marker
if md5sum and data[:2] == MD5_PARTITION_BEGIN[:2]: #check only the magic number part
if data[16:] == md5.digest():
continue # the next iteration will check for the end marker
else:
raise InputError("MD5 checksums don't match! (computed: 0x%s, parsed: 0x%s)" % (md5.hexdigest(), binascii.hexlify(data[16:])))
else:
md5.update(data)
result.append(PartitionDefinition.from_binary(data)) result.append(PartitionDefinition.from_binary(data))
raise InputError("Partition table is missing an end-of-table marker") raise InputError("Partition table is missing an end-of-table marker")
def to_binary(self): def to_binary(self):
result = b"".join(e.to_binary() for e in self) result = b"".join(e.to_binary() for e in self)
if md5sum:
result += MD5_PARTITION_BEGIN + hashlib.md5(result).digest()
if len(result )>= MAX_PARTITION_LENGTH: if len(result )>= MAX_PARTITION_LENGTH:
raise InputError("Binary partition table length (%d) longer than max" % len(result)) raise InputError("Binary partition table length (%d) longer than max" % len(result))
result += b"\xFF" * (MAX_PARTITION_LENGTH - len(result)) # pad the sector, for signing result += b"\xFF" * (MAX_PARTITION_LENGTH - len(result)) # pad the sector, for signing
@ -154,6 +216,7 @@ class PartitionDefinition(object):
"phy" : 0x01, "phy" : 0x01,
"nvs" : 0x02, "nvs" : 0x02,
"coredump" : 0x03, "coredump" : 0x03,
"nvs_keys" : 0x04,
"esphttpd" : 0x80, "esphttpd" : 0x80,
"fat" : 0x81, "fat" : 0x81,
"spiffs" : 0x82, "spiffs" : 0x82,
@ -173,7 +236,7 @@ class PartitionDefinition(object):
"encrypted" : 0 "encrypted" : 0
} }
# add subtypes for the 16 OTA slot values ("ota_XXX, etc.") # add subtypes for the 16 OTA slot values ("ota_XX, etc.")
for ota_slot in range(16): for ota_slot in range(16):
SUBTYPES[TYPES["app"]]["ota_%d" % ota_slot] = 0x10 + ota_slot SUBTYPES[TYPES["app"]]["ota_%d" % ota_slot] = 0x10 + ota_slot
@ -226,6 +289,18 @@ class PartitionDefinition(object):
def __cmp__(self, other): def __cmp__(self, other):
return self.offset - other.offset return self.offset - other.offset
def __lt__(self, other):
return self.offset < other.offset
def __gt__(self, other):
return self.offset > other.offset
def __le__(self, other):
return self.offset <= other.offset
def __ge__(self, other):
return self.offset >= other.offset
def parse_type(self, strval): def parse_type(self, strval):
if strval == "": if strval == "":
raise InputError("Field 'type' can't be left empty.") raise InputError("Field 'type' can't be left empty.")
@ -251,6 +326,8 @@ class PartitionDefinition(object):
align = self.ALIGNMENT.get(self.type, 4) align = self.ALIGNMENT.get(self.type, 4)
if self.offset % align: if self.offset % align:
raise ValidationError(self, "Offset 0x%x is not aligned to 0x%x" % (self.offset, align)) raise ValidationError(self, "Offset 0x%x is not aligned to 0x%x" % (self.offset, align))
if self.size % align and secure:
raise ValidationError(self, "Size 0x%x is not aligned to 0x%x" % (self.size, align))
if self.size is None: if self.size is None:
raise ValidationError(self, "Size field is not set") raise ValidationError(self, "Size field is not set")
@ -333,11 +410,18 @@ def parse_int(v, keywords={}):
def main(): def main():
global quiet global quiet
global md5sum
global offset_part_table
global secure
parser = argparse.ArgumentParser(description='ESP32 partition table utility') parser = argparse.ArgumentParser(description='ESP32 partition table utility')
parser.add_argument('--flash-size', help='Optional flash size limit, checks partition table fits in flash',
nargs='?', choices=[ '1MB', '2MB', '4MB', '8MB', '16MB' ])
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('--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('--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('--secure', help="Require app partitions to be suitable for secure boot", action='store_true')
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('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.)', 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='?', nargs='?',
@ -346,6 +430,9 @@ def main():
args = parser.parse_args() args = parser.parse_args()
quiet = args.quiet quiet = args.quiet
md5sum = not args.disable_md5sum
secure = args.secure
offset_part_table = int(args.offset, 0)
input = args.input.read() input = args.input.read()
input_is_binary = input[0:2] == PartitionDefinition.MAGIC_BYTES input_is_binary = input[0:2] == PartitionDefinition.MAGIC_BYTES
if input_is_binary: if input_is_binary:
@ -360,6 +447,14 @@ def main():
status("Verifying table...") status("Verifying table...")
table.verify() table.verify()
if args.flash_size:
size_mb = int(args.flash_size.replace("MB", ""))
size = size_mb * 1024 * 1024 # flash memory uses honest megabytes!
table_size = table.flash_size()
if size < table_size:
raise InputError("Partitions defined in '%s' occupy %.1fMB of flash (%d bytes) which does not fit in configured flash size %dMB. Change the flash size in menuconfig under the 'Serial Flasher Config' menu." %
(args.input.name, table_size / 1024.0 / 1024.0, table_size, size_mb))
if input_is_binary: if input_is_binary:
output = table.to_csv() output = table.to_csv()
with sys.stdout if args.output == '-' else open(args.output, 'w') as f: with sys.stdout if args.output == '-' else open(args.output, 'w') as f:

View File

@ -0,0 +1,133 @@
#!/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-table-offset', help='The offset of the partition table in flash. Only consulted if partition table is in CSV format.', type=str, default='0x8000')
search_type = parser.add_mutually_exclusive_group()
search_type.add_argument('--partition-name', '-p', help='The name of the required partition', type=str, default=None)
search_type.add_argument('--type', '-t', help='The type of the required partition', type=str, default=None)
search_type.add_argument('--default-boot-partition', help='Select the default boot partition, '+
'using the same fallback logic as the IDF bootloader', action="store_true")
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")
parser.add_argument('--size', help='Return size of required partition', action="store_true")
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()
if args.type is not None and args.subtype is None:
status("If --type is specified, --subtype is required")
return 2
if args.type is None and args.subtype is not None:
status("--subtype is only used with --type")
return 2
quiet = args.quiet
gen.offset_part_table = int(args.partition_table_offset, 0)
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)
found_partition = None
if args.default_boot_partition:
search = [ "factory" ] + [ "ota_%d" % d for d in range(16) ]
for subtype in search:
found_partition = table.find_by_type("app", subtype)
if found_partition is not None:
break
elif args.partition_name is not None:
found_partition = table.find_by_name(args.partition_name)
elif args.type is not None:
found_partition = table.find_by_type(args.type, args.subtype)
else:
raise RuntimeError("invalid partition selection choice")
if found_partition is None:
return 1 # nothing found
if args.offset:
print('0x%x ' % (found_partition.offset))
if args.size:
print('0x%x' % (found_partition.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:
r = main()
sys.exit(r)
except InputError as e:
print(e, file=sys.stderr)
sys.exit(2)

View File

@ -76,75 +76,8 @@ Open a new terminal on your PC, set the following configurations, and then compi
[*] (**Expected**)ESP8266 update from old SDK by OTA [*] (**Expected**)ESP8266 update from old SDK by OTA
3. Configure the target custom partition 3. ESP8285(ESP8266 + 1MB flash) configuration:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The last 16KB flash, which is used to store system parameters of the old SDKs, must be reserved.
ESP8285(ESP8266 + 1MB flash) configuration:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Set the file "partitions_two_ota_v2tov3.1MB.csv" to configure the partition of the example. Users can refer to its note for the partition layout.
::
Partition Table --->
Partition Table (Custom partition table CSV) --->
Custom partition table CSV
(partitions_two_ota_v2tov3.1MB.csv) Custom partition CSV file
(0x5000) Partition table offset address at flash
[*] Support to setup partition parameter of APP2
(0x7000) APP1 partition offset
(0x77000) APP1 partition size(by bytes)
(0x85000) APP2 partition offset
(0x77000) APP2 partition size(by bytes)
Partition information of file "partitions_two_ota_v2tov3.1MB.csv" is following:
::
Name, Type, SubType, Offset, Size, Flags
phy_init, data, phy, 0x6000, 0x1000
ota_0, 0, ota_0, 0x7000, 0x77000
nvs, data, nvs, 0x7f000, 0x4000
otadata, data, ota, 0x83000, 0x2000
ota_1, 0, ota_1, 0x85000, 0x77000
- Partition table offset address at flash: partition table layout address
- APP1 partition offset: ota_0 base address
- APP1 partition size: ota_0 size
- APP2 partition offset: ota_1 base address
- APP2 partition size: ota_1 size
ESP8266 + 2MB(including larger size flash) flash configuration:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Set the file "partitions_two_ota_v2tov3.2MB.csv" to configure the partition of the example. Users can refer to its note for the partition layout.
::
Partition Table --->
Partition Table (Custom partition table CSV) --->
Custom partition table CSV
(partitions_two_ota_v2tov3.2MB.csv) Custom partition CSV file
(0x8000) Partition table offset address at flash
(0x10000) APP1 partition offset
(0xEC000) APP1 partition size(by bytes)
Partition information of file "partitions_two_ota_v2tov3.2MB.csv" is following:
::
Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x4000
otadata, data, ota, 0xd000, 0x2000
phy_init, data, phy, 0xf000, 0x1000
ota_0, 0, ota_0, 0x10000, 0xEC000
ota_1, 0, ota_1, 0x110000,0xEC000
- Partition table offset address at flash: partition table layout address
- APP1 partition offset: ota_0 base address
- APP1 partition size: ota_0 size
Configure the flash size according to your actual development board's flash. Configure the flash size according to your actual development board's flash.

View File

@ -53,32 +53,7 @@ Note: System will add the absolute path of the project to the head of the "Custo
(XXXXXX)Partition table offset address at flash (XXXXXX)Partition table offset address at flash
``` ```
## Step 3: Configurate application location: **make ota flash** will only download the app1 at **APP1 partition offset**.
Configurate application location at "mennuconfig" like following base on partition table file.
If you select 1MB flash, application location configuration menu is like following:
```
Partition Table --->
[*] Support to setup partition parameter of APP2
(0x5000) App1 offset address
(0x7B000) App1 size by bytes
(0x85000) App2 offset address
(0x7b000) App2 size by bytes
```
If you select 2MB flash and above size, application location configuration menu is like following:
```
Partition Table --->
(0x10000) APP1 partition offset
(0xF0000) APP1 partition size(by bytes)
```
Note: The firmware location information must be same as partition table file. **make ota flash** will only download the app1 at **APP1 partition offset**.
# Workflow # Workflow
@ -144,7 +119,7 @@ Serial flasher config --->
(X) 1 MB (X) 1 MB
``` ```
Configurate the application location information and it must be the same as the OTA example's information, you can refer to the **Step 3: Configurate application location** of **Custom partition configuration**. Configurate the application partition table information and it must be the same as the OTA example's information, you can refer to the **Custom partition configuration**.
Save your changes, and type `make` to build the example. Save your changes, and type `make` to build the example.

View File

@ -6,7 +6,3 @@ CONFIG_ESPTOOLPY_FLASHSIZE_1MB=y
CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_two_ota.1MB.mini.csv" CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_two_ota.1MB.mini.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x4000 CONFIG_PARTITION_TABLE_OFFSET=0x4000
CONFIG_APP1_OFFSET=0x6000
CONFIG_APP1_SIZE=0x7A000
CONFIG_APP2_OFFSET=0x86000
CONFIG_APP2_SIZE=0x7A000

View File

@ -192,6 +192,8 @@ COMPONENT_LDFLAGS :=
COMPONENT_SUBMODULES := COMPONENT_SUBMODULES :=
COMPONENT_LIBRARIES := COMPONENT_LIBRARIES :=
global-macro:
# COMPONENT_PROJECT_VARS is the list of component_project_vars.mk generated makefiles # COMPONENT_PROJECT_VARS is the list of component_project_vars.mk generated makefiles
# for each component. # for each component.
# #
@ -437,7 +439,7 @@ endef
define GenerateComponentTargets define GenerateComponentTargets
.PHONY: component-$(2)-build component-$(2)-clean .PHONY: component-$(2)-build component-$(2)-clean
component-$(2)-build: check-submodules $(call prereq_if_explicit, component-$(2)-clean) | $(BUILD_DIR_BASE)/$(2) component-$(2)-build: check-submodules global-macro $(call prereq_if_explicit, component-$(2)-clean) | $(BUILD_DIR_BASE)/$(2)
$(call ComponentMake,$(1),$(2)) build $(call ComponentMake,$(1),$(2)) build
component-$(2)-clean: | $(BUILD_DIR_BASE)/$(2) $(BUILD_DIR_BASE)/$(2)/component_project_vars.mk component-$(2)-clean: | $(BUILD_DIR_BASE)/$(2) $(BUILD_DIR_BASE)/$(2)/component_project_vars.mk