From 41bf07e6ce5493980be30c49d6179483889ca153 Mon Sep 17 00:00:00 2001 From: Laukik Hase Date: Tue, 8 Apr 2025 16:08:45 +0530 Subject: [PATCH] refactor(esp_tee): Remove the deprecated TEE secure storage partition subtype --- .../include/esp_flash_partitions.h | 1 - .../src/bootloader_utility.c | 3 - .../esp_partition/include/esp_partition.h | 1 - .../esp_tee/include/private/esp_tee_binary.h | 4 + .../components/tee_flash_mgr/esp_tee_flash.c | 11 +- .../components/tee_sec_storage/CMakeLists.txt | 5 +- .../tee_sec_storage/tee_sec_storage.c | 7 +- components/partition_table/gen_esp32part.py | 267 +++++++++++------- .../partitions_singleapp_tee.csv | 3 +- .../partitions_two_ota_tee.csv | 3 +- 10 files changed, 190 insertions(+), 115 deletions(-) diff --git a/components/bootloader_support/include/esp_flash_partitions.h b/components/bootloader_support/include/esp_flash_partitions.h index 663e2053e4..d50fd48f24 100644 --- a/components/bootloader_support/include/esp_flash_partitions.h +++ b/components/bootloader_support/include/esp_flash_partitions.h @@ -41,7 +41,6 @@ extern "C" { #define PART_SUBTYPE_PARTITION_TABLE_OTA 0x01 #define PART_SUBTYPE_DATA_TEE_OTA 0x90 -#define PART_SUBTYPE_DATA_TEE_SEC_STORAGE 0x91 #define PART_TYPE_END 0xff #define PART_SUBTYPE_END 0xff diff --git a/components/bootloader_support/src/bootloader_utility.c b/components/bootloader_support/src/bootloader_utility.c index 5b44163166..322db4a755 100644 --- a/components/bootloader_support/src/bootloader_utility.c +++ b/components/bootloader_support/src/bootloader_utility.c @@ -226,9 +226,6 @@ bool bootloader_utility_load_partition_table(bootloader_state_t *bs) bs->tee_ota_info = partition->pos; partition_usage = "TEE OTA data"; break; - case PART_SUBTYPE_DATA_TEE_SEC_STORAGE: /* TEE secure storage */ - partition_usage = "TEE secure storage"; - break; #endif default: partition_usage = "Unknown data"; diff --git a/components/esp_partition/include/esp_partition.h b/components/esp_partition/include/esp_partition.h index 2636bf3106..268197a795 100644 --- a/components/esp_partition/include/esp_partition.h +++ b/components/esp_partition/include/esp_partition.h @@ -114,7 +114,6 @@ typedef enum { ESP_PARTITION_SUBTYPE_DATA_LITTLEFS = 0x83, //!< LITTLEFS partition ESP_PARTITION_SUBTYPE_DATA_TEE_OTA = 0x90, //!< TEE OTA selection partition - ESP_PARTITION_SUBTYPE_DATA_TEE_SEC_STORAGE= 0x91, //!< TEE secure storage partition #if __has_include("extra_partition_subtypes.inc") #include "extra_partition_subtypes.inc" diff --git a/components/esp_tee/include/private/esp_tee_binary.h b/components/esp_tee/include/private/esp_tee_binary.h index d2edc56eae..40edae82ad 100644 --- a/components/esp_tee/include/private/esp_tee_binary.h +++ b/components/esp_tee/include/private/esp_tee_binary.h @@ -39,6 +39,10 @@ extern "C" { #error "CONFIG_SECURE_TEE_INTR_STACK_SIZE must be 16-byte (0x10) aligned" #endif +/* TEE Secure Storage partition label and NVS namespace */ +#define ESP_TEE_SEC_STG_PART_LABEL "secure_storage" +#define ESP_TEE_SEC_STG_NVS_NAMESPACE "tee_sec_stg_ns" + /* NOTE: ESP32-C6 - TEE/REE memory regions */ /* TEE I/DRAM */ #define SOC_S_IRAM_START (SOC_IRAM_LOW) diff --git a/components/esp_tee/subproject/components/tee_flash_mgr/esp_tee_flash.c b/components/esp_tee/subproject/components/tee_flash_mgr/esp_tee_flash.c index 8c81afa7cb..8b3add20c2 100644 --- a/components/esp_tee/subproject/components/tee_flash_mgr/esp_tee_flash.c +++ b/components/esp_tee/subproject/components/tee_flash_mgr/esp_tee_flash.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -166,7 +166,14 @@ esp_err_t esp_tee_flash_setup_prot_ctx(uint8_t tee_boot_part) if (type == PART_TYPE_APP) { needs_protection = (subtype == PART_SUBTYPE_TEE_0 || subtype == PART_SUBTYPE_TEE_1); } else if (type == PART_TYPE_DATA) { - needs_protection = (subtype == PART_SUBTYPE_DATA_TEE_OTA || subtype == PART_SUBTYPE_DATA_TEE_SEC_STORAGE); + if (subtype == PART_SUBTYPE_DATA_TEE_OTA) { + needs_protection = true; + } else if (subtype == PART_SUBTYPE_DATA_WIFI) { + size_t label_len = strlen(ESP_TEE_SEC_STG_PART_LABEL); + if (memcmp(partition_entry->partition.label, ESP_TEE_SEC_STG_PART_LABEL, label_len) == 0) { + needs_protection = true; + } + } } if (needs_protection) { diff --git a/components/esp_tee/subproject/components/tee_sec_storage/CMakeLists.txt b/components/esp_tee/subproject/components/tee_sec_storage/CMakeLists.txt index 6dcd248d19..2d911922c6 100644 --- a/components/esp_tee/subproject/components/tee_sec_storage/CMakeLists.txt +++ b/components/esp_tee/subproject/components/tee_sec_storage/CMakeLists.txt @@ -1,14 +1,13 @@ idf_build_get_property(esp_tee_build ESP_TEE_BUILD) set(srcs) -set(priv_requires efuse mbedtls spi_flash) +set(priv_requires esp_tee) if(esp_tee_build) list(APPEND srcs "tee_sec_storage.c") - list(APPEND priv_requires esp_partition log nvs_flash tee_flash_mgr) + list(APPEND priv_requires efuse esp_partition log mbedtls nvs_flash spi_flash tee_flash_mgr) else() list(APPEND srcs "tee_sec_storage_wrapper.c") - set(priv_requires esp_tee) endif() idf_component_register(SRCS ${srcs} diff --git a/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c b/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c index 8383e72401..dcb3a8236e 100644 --- a/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c +++ b/components/esp_tee/subproject/components/tee_sec_storage/tee_sec_storage.c @@ -75,9 +75,6 @@ typedef struct { _Static_assert(sizeof(sec_stg_key_t) == 256, "Incorrect sec_stg_key_t size"); -#define TEE_SEC_STG_PART_LABEL "tee_nvs" -#define TEE_SEC_STG_NVS_NAMESPACE "tee_sec_stg" - static nvs_handle_t tee_nvs_hdl; static const char *TAG = "secure_storage"; @@ -217,12 +214,12 @@ esp_err_t esp_tee_sec_storage_init(void) return err; } - err = nvs_flash_secure_init_partition(TEE_SEC_STG_PART_LABEL, &cfg); + err = nvs_flash_secure_init_partition(ESP_TEE_SEC_STG_PART_LABEL, &cfg); if (err != ESP_OK) { return err; } - err = nvs_open_from_partition(TEE_SEC_STG_PART_LABEL, TEE_SEC_STG_NVS_NAMESPACE, NVS_READWRITE, &tee_nvs_hdl); + err = nvs_open_from_partition(ESP_TEE_SEC_STG_PART_LABEL, ESP_TEE_SEC_STG_NVS_NAMESPACE, NVS_READWRITE, &tee_nvs_hdl); if (err != ESP_OK) { return err; } diff --git a/components/partition_table/gen_esp32part.py b/components/partition_table/gen_esp32part.py index 05f8233297..396f6ff22f 100755 --- a/components/partition_table/gen_esp32part.py +++ b/components/partition_table/gen_esp32part.py @@ -18,9 +18,9 @@ import re import struct import sys -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 +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 MIN_PARTITION_SUBTYPE_APP_OTA = 0x10 NUM_PARTITION_SUBTYPE_APP_OTA = 16 @@ -49,7 +49,7 @@ NVS_RW_MIN_PARTITION_SIZE = 0x3000 def get_ptype_as_int(ptype): - """ Convert a string which might be numeric or the name of a partition type to an integer """ + """Convert a string which might be numeric or the name of a partition type to an integer""" try: return TYPES[ptype] except KeyError: @@ -87,13 +87,12 @@ SUBTYPES = { 'spiffs': 0x82, 'littlefs': 0x83, 'tee_ota': 0x90, - 'tee_sec_stg': 0x91, }, } def get_subtype_as_int(ptype, subtype): - """ Convert a string which might be numeric or the name of a partition subtype to an integer """ + """Convert a string which might be numeric or the name of a partition subtype to an integer""" try: return SUBTYPES[get_ptype_as_int(ptype)][subtype] except KeyError: @@ -149,7 +148,7 @@ def add_extra_subtypes(csv): try: fields = [line.strip() for line in line_no.split(',')] for subtype, subtype_values in SUBTYPES.items(): - if (int(fields[2], 16) in subtype_values.values() and subtype == get_partition_type(fields[0])): + if int(fields[2], 16) in subtype_values.values() and subtype == get_partition_type(fields[0]): raise ValueError('Found duplicate value in partition subtype') SUBTYPES[TYPES[fields[0]]][fields[1]] = int(fields[2], 16) except InputError as err: @@ -165,13 +164,13 @@ recovery_bootloader_offset = None def status(msg): - """ Print status message to stderr """ + """Print status message to stderr""" if not quiet: critical(msg) def critical(msg): - """ Print critical message to stderr """ + """Print critical message to stderr""" sys.stderr.write(msg) sys.stderr.write('\n') @@ -211,7 +210,10 @@ class PartitionTable(list): try: res.append(PartitionDefinition.from_csv(line, line_no + 1)) except InputError as err: - raise InputError('Error at line %d: %s\nPlease check extra_partition_subtypes.inc file in build/config directory' % (line_no + 1, err)) + raise InputError( + 'Error at line %d: %s\nPlease check extra_partition_subtypes.inc file in build/config directory' + % (line_no + 1, err) + ) except Exception: critical('Unexpected error parsing CSV line %d: %s' % (line_no + 1, line)) raise @@ -219,20 +221,23 @@ class PartitionTable(list): # fix up missing offsets & negative sizes last_end = offset_part_table + PARTITION_TABLE_SIZE # first offset after partition table for e in res: - is_primary_bootloader = (e.type == BOOTLOADER_TYPE and e.subtype == SUBTYPES[e.type]['primary']) - is_primary_partition_table = (e.type == PARTITION_TABLE_TYPE and e.subtype == SUBTYPES[e.type]['primary']) + is_primary_bootloader = e.type == BOOTLOADER_TYPE and e.subtype == SUBTYPES[e.type]['primary'] + is_primary_partition_table = e.type == PARTITION_TABLE_TYPE and e.subtype == SUBTYPES[e.type]['primary'] if is_primary_bootloader or is_primary_partition_table: # They do not participate in the restoration of missing offsets continue if e.offset is not None and e.offset < last_end: if e == res[0]: - raise InputError('CSV Error at line %d: Partitions overlap. Partition sets offset 0x%x. ' - 'But partition table occupies the whole sector 0x%x. ' - 'Use a free offset 0x%x or higher.' - % (e.line_no, e.offset, offset_part_table, last_end)) + raise InputError( + 'CSV Error at line %d: Partitions overlap. Partition sets offset 0x%x. ' + 'But partition table occupies the whole sector 0x%x. ' + 'Use a free offset 0x%x or higher.' % (e.line_no, e.offset, offset_part_table, last_end) + ) else: - raise InputError('CSV Error at line %d: Partitions overlap. Partition sets offset 0x%x. Previous partition ends 0x%x' - % (e.line_no, e.offset, last_end)) + raise InputError( + 'CSV Error at line %d: Partitions overlap. Partition sets offset 0x%x. ' + 'Previous partition ends 0x%x' % (e.line_no, e.offset, last_end) + ) if e.offset is None: pad_to = get_alignment_offset_for_type(e.type) if last_end % pad_to != 0: @@ -245,8 +250,8 @@ class PartitionTable(list): return res def __getitem__(self, item): - """ Allow partition table access via name as well as by - numeric index. """ + """Allow partition table access via name as well as by + numeric index.""" if isinstance(item, str): for x in self: if x.name == item: @@ -256,8 +261,8 @@ class PartitionTable(list): return super(PartitionTable, self).__getitem__(item) def find_by_type(self, ptype, subtype): - """ Return a partition by type & subtype, returns - None if not found """ + """Return a partition by type & subtype, returns + None if not found""" # convert ptype & subtypes names (if supplied this way) to integer values ptype = get_ptype_as_int(ptype) subtype = get_subtype_as_int(ptype, subtype) @@ -285,21 +290,25 @@ class PartitionTable(list): # print sorted duplicate partitions by name if len(duplicates) != 0: critical('A list of partitions that have the same name:') - for p in sorted(self, key=lambda x:x.name): + for p in sorted(self, key=lambda x: x.name): if len(duplicates.intersection([p.name])) != 0: critical('%s' % (p.to_csv())) raise InputError('Partition names must be unique') # check for overlaps 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 < offset_part_table + PARTITION_TABLE_SIZE: - is_primary_bootloader = (p.type == BOOTLOADER_TYPE and p.subtype == SUBTYPES[p.type]['primary']) - is_primary_partition_table = (p.type == PARTITION_TABLE_TYPE and p.subtype == SUBTYPES[p.type]['primary']) + is_primary_bootloader = p.type == BOOTLOADER_TYPE and p.subtype == SUBTYPES[p.type]['primary'] + is_primary_partition_table = p.type == PARTITION_TABLE_TYPE and p.subtype == SUBTYPES[p.type]['primary'] if not (is_primary_bootloader or is_primary_partition_table): - raise InputError('Partition offset 0x%x is below 0x%x' % (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)) + raise InputError( + 'Partition at 0x%x overlaps 0x%x-0x%x' % (p.offset, last.offset, last.offset + last.size - 1) + ) last = p # check that otadata should be unique @@ -307,7 +316,10 @@ class PartitionTable(list): if len(otadata_duplicates) > 1: for p in otadata_duplicates: critical('%s' % (p.to_csv())) - raise InputError('Found multiple otadata partitions. Only one partition can be defined with type="data"(1) and subtype="ota"(0).') + raise InputError( + 'Found multiple otadata partitions. Only one partition can be defined with ' + 'type="data"(1) and subtype="ota"(0).' + ) if len(otadata_duplicates) == 1 and otadata_duplicates[0].size != 0x2000: p = otadata_duplicates[0] @@ -315,11 +327,16 @@ class PartitionTable(list): raise InputError('otadata partition must have size = 0x2000') # Above checks but for TEE otadata - otadata_duplicates = [p for p in self if p.type == TYPES['data'] and p.subtype == SUBTYPES[DATA_TYPE]['tee_ota']] + otadata_duplicates = [ + p for p in self if p.type == TYPES['data'] and p.subtype == SUBTYPES[DATA_TYPE]['tee_ota'] + ] if len(otadata_duplicates) > 1: for p in otadata_duplicates: critical('%s' % (p.to_csv())) - raise InputError('Found multiple TEE otadata partitions. Only one partition can be defined with type="data"(1) and subtype="tee_ota"(0x90).') + raise InputError( + 'Found multiple TEE otadata partitions. Only one partition can be defined with ' + 'type="data"(1) and subtype="tee_ota"(0x90).' + ) if len(otadata_duplicates) == 1 and otadata_duplicates[0].size != 0x2000: p = otadata_duplicates[0] @@ -327,8 +344,8 @@ class PartitionTable(list): raise InputError('TEE otadata partition must have size = 0x2000') def flash_size(self): - """ Return the size that partitions will occupy in flash - (ie the offset the last partition ends at) + """Return the size that partitions will occupy in flash + (ie the offset the last partition ends at) """ try: last = sorted(self, reverse=True)[0] @@ -337,31 +354,36 @@ class PartitionTable(list): return last.offset + last.size def verify_size_fits(self, flash_size_bytes: int) -> None: - """ Check that partition table fits into the given flash size. - Raises InputError otherwise. + """Check that partition table fits into the given flash size. + Raises InputError otherwise. """ table_size = self.flash_size() if flash_size_bytes < table_size: mb = 1024 * 1024 - raise InputError('Partitions tables occupies %.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." % - (table_size / mb, table_size, flash_size_bytes / mb)) + raise InputError( + 'Partitions tables occupies %.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." + % (table_size / mb, table_size, flash_size_bytes / mb) + ) @classmethod def from_binary(cls, b): md5 = hashlib.md5() result = cls() - for o in range(0,len(b),32): - data = b[o:o + 32] + for o in range(0, len(b), 32): + data = b[o : o + 32] if len(data) != 32: 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 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:]))) + 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)) @@ -373,25 +395,21 @@ class PartitionTable(list): result += MD5_PARTITION_BEGIN + hashlib.md5(result).digest() if len(result) >= MAX_PARTITION_LENGTH: 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 return result def to_csv(self, simple_formatting=False): - rows = ['# ESP-IDF Partition Table', - '# Name, Type, SubType, Offset, Size, Flags'] + rows = ['# ESP-IDF Partition Table', '# Name, Type, SubType, Offset, Size, Flags'] rows += [x.to_csv(simple_formatting) for x in self] return '\n'.join(rows) + '\n' class PartitionDefinition(object): - MAGIC_BYTES = b'\xAA\x50' + MAGIC_BYTES = b'\xaa\x50' # dictionary maps flag name (as used in CSV flags list, property name) # to bit set in flags words in binary format - FLAGS = { - 'encrypted': 0, - 'readonly': 1 - } + FLAGS = {'encrypted': 0, 'readonly': 1} # add subtypes for the 16 OTA slot values ("ota_XX, etc.") for ota_slot in range(NUM_PARTITION_SUBTYPE_APP_OTA): @@ -412,7 +430,7 @@ class PartitionDefinition(object): @classmethod def from_csv(cls, line, line_no): - """ Parse a line from the CSV """ + """Parse a line from the CSV""" line_w_defaults = line + ',,,,' # lazy way to support default fields fields = [f.strip() for f in line_w_defaults.split(',')] @@ -436,18 +454,34 @@ class PartitionDefinition(object): return res def __eq__(self, other): - return self.name == other.name and self.type == other.type \ - and self.subtype == other.subtype and self.offset == other.offset \ + return ( + self.name == other.name + and self.type == other.type + and self.subtype == other.subtype + and self.offset == other.offset and self.size == other.size + ) def __repr__(self): def maybe_hex(x): return '0x%x' % x if x is not None else 'None' - return "PartitionDefinition('%s', 0x%x, 0x%x, %s, %s)" % (self.name, self.type, self.subtype or 0, - maybe_hex(self.offset), maybe_hex(self.size)) + + return "PartitionDefinition('%s', 0x%x, 0x%x, %s, %s)" % ( + self.name, + self.type, + self.subtype or 0, + maybe_hex(self.offset), + maybe_hex(self.size), + ) def __str__(self): - return "Part '%s' %d/%d @ 0x%x size 0x%x" % (self.name, self.type, self.subtype, self.offset or -1, self.size or -1) + return "Part '%s' %d/%d @ 0x%x size 0x%x" % ( + self.name, + self.type, + self.subtype, + self.offset or -1, + self.size or -1, + ) def __cmp__(self, other): return self.offset - other.offset @@ -479,7 +513,7 @@ class PartitionDefinition(object): def parse_size(self, strval, ptype): if ptype == BOOTLOADER_TYPE: if primary_bootloader_offset is None: - raise InputError(f'Primary bootloader offset is not defined. Please use --primary-bootloader-offset') + raise InputError('Primary bootloader offset is not defined. Please use --primary-bootloader-offset') return offset_part_table - primary_bootloader_offset if ptype == PARTITION_TABLE_TYPE: return PARTITION_TABLE_SIZE @@ -491,11 +525,13 @@ class PartitionDefinition(object): if ptype == BOOTLOADER_TYPE: if psubtype == SUBTYPES[ptype]['primary']: if primary_bootloader_offset is None: - raise InputError(f'Primary bootloader offset is not defined. Please use --primary-bootloader-offset') + raise InputError('Primary bootloader offset is not defined. Please use --primary-bootloader-offset') return primary_bootloader_offset if psubtype == SUBTYPES[ptype]['recovery']: if recovery_bootloader_offset is None: - raise InputError(f'Recovery bootloader offset is not defined. Please use --recovery-bootloader-offset') + raise InputError( + 'Recovery bootloader offset is not defined. Please use --recovery-bootloader-offset' + ) return recovery_bootloader_offset if ptype == PARTITION_TABLE_TYPE and psubtype == SUBTYPES[ptype]['primary']: return offset_part_table @@ -521,24 +557,36 @@ class PartitionDefinition(object): raise ValidationError(self, 'Size 0x%x is not aligned to 0x%x' % (self.size, size_align)) if self.name in TYPES and TYPES.get(self.name, '') != self.type: - critical("WARNING: Partition has name '%s' which is a partition type, but does not match this partition's " - 'type (0x%x). Mistake in partition table?' % (self.name, self.type)) + critical( + "WARNING: Partition has name '%s' which is a partition type, but does not match this partition's " + 'type (0x%x). Mistake in partition table?' % (self.name, self.type) + ) all_subtype_names = [] for names in (t.keys() for t in SUBTYPES.values()): all_subtype_names += names if self.name in all_subtype_names and SUBTYPES.get(self.type, {}).get(self.name, '') != self.subtype: - critical("WARNING: Partition has name '%s' which is a partition subtype, but this partition has " - 'non-matching type 0x%x and subtype 0x%x. Mistake in partition table?' % (self.name, self.type, self.subtype)) + critical( + "WARNING: Partition has name '%s' which is a partition subtype, but this partition has " + 'non-matching type 0x%x and subtype 0x%x. Mistake in partition table?' + % (self.name, self.type, self.subtype) + ) always_rw_data_subtypes = [SUBTYPES[DATA_TYPE]['ota'], SUBTYPES[DATA_TYPE]['coredump']] if self.type == TYPES['data'] and self.subtype in always_rw_data_subtypes and self.readonly is True: - raise ValidationError(self, "'%s' partition of type %s and subtype %s is always read-write and cannot be read-only" % - (self.name, self.type, self.subtype)) + raise ValidationError( + self, + "'%s' partition of type %s and subtype %s is always read-write and cannot be read-only" + % (self.name, self.type, self.subtype), + ) if self.type == TYPES['data'] and self.subtype == SUBTYPES[DATA_TYPE]['nvs']: if self.size < NVS_RW_MIN_PARTITION_SIZE and self.readonly is False: - raise ValidationError(self, """'%s' partition of type %s and subtype %s of this size (0x%x) must be flagged as 'readonly' \ -(the size of read/write NVS has to be at least 0x%x)""" % (self.name, self.type, self.subtype, self.size, NVS_RW_MIN_PARTITION_SIZE)) + raise ValidationError( + self, + """'%s' partition of type %s and subtype %s of this size (0x%x) must be flagged as 'readonly' \ +(the size of read/write NVS has to be at least 0x%x)""" + % (self.name, self.type, self.subtype, self.size, NVS_RW_MIN_PARTITION_SIZE), + ) STRUCT_FORMAT = b'<2sBBLL16sL' @@ -547,14 +595,13 @@ class PartitionDefinition(object): if len(b) != 32: raise InputError('Partition definition length must be exactly 32 bytes. Got %d bytes.' % len(b)) res = cls() - (magic, res.type, res.subtype, res.offset, - res.size, res.name, flags) = struct.unpack(cls.STRUCT_FORMAT, b) + (magic, res.type, res.subtype, res.offset, res.size, res.name, flags) = struct.unpack(cls.STRUCT_FORMAT, b) if b'\x00' in res.name: # strip null byte padding from name string - res.name = res.name[:res.name.index(b'\x00')] + res.name = res.name[: res.name.index(b'\x00')] res.name = res.name.decode() if magic != cls.MAGIC_BYTES: raise InputError('Invalid magic bytes (%r) for partition definition' % magic) - for flag,bit in cls.FLAGS.items(): + for flag, bit in cls.FLAGS.items(): if flags & (1 << bit): setattr(res, flag, True) flags &= ~(1 << bit) @@ -567,37 +614,45 @@ class PartitionDefinition(object): def to_binary(self): flags = sum((1 << self.FLAGS[flag]) for flag in self.get_flags_list()) - return struct.pack(self.STRUCT_FORMAT, - self.MAGIC_BYTES, - self.type, self.subtype, - self.offset, self.size, - self.name.encode(), - flags) + return struct.pack( + self.STRUCT_FORMAT, + self.MAGIC_BYTES, + self.type, + self.subtype, + self.offset, + self.size, + self.name.encode(), + flags, + ) def to_csv(self, simple_formatting=False): def addr_format(a, include_sizes): if not simple_formatting and include_sizes: - for (val, suffix) in [(0x100000, 'M'), (0x400, 'K')]: + for val, suffix in [(0x100000, 'M'), (0x400, 'K')]: if a % val == 0: return '%d%s' % (a // val, suffix) return '0x%x' % a def lookup_keyword(t, keywords): - for k,v in keywords.items(): + for k, v in keywords.items(): if simple_formatting is False and t == v: return k return '%d' % t def generate_text_flags(): - """ colon-delimited list of flags """ + """colon-delimited list of flags""" return ':'.join(self.get_flags_list()) - return ','.join([self.name, - lookup_keyword(self.type, TYPES), - lookup_keyword(self.subtype, SUBTYPES.get(self.type, {})), - addr_format(self.offset, False), - addr_format(self.size, True), - generate_text_flags()]) + return ','.join( + [ + self.name, + lookup_keyword(self.type, TYPES), + lookup_keyword(self.subtype, SUBTYPES.get(self.type, {})), + addr_format(self.offset, False), + addr_format(self.size, True), + generate_text_flags(), + ] + ) def parse_int(v, keywords={}): @@ -627,21 +682,42 @@ def main(): global recovery_bootloader_offset 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', '32MB', '64MB', '128MB']) - parser.add_argument('--disable-md5sum', help='Disable md5 checksum for the partition table', default=False, action='store_true') + parser.add_argument( + '--flash-size', + help='Optional flash size limit, checks partition table fits in flash', + nargs='?', + choices=['1MB', '2MB', '4MB', '8MB', '16MB', '32MB', '64MB', '128MB'], + ) + parser.add_argument( + '--disable-md5sum', help='Disable md5 checksum for the partition table', default=False, action='store_true' + ) parser.add_argument('--no-verify', help="Don't verify partition table fields", action='store_true') - parser.add_argument('--verify', '-v', help='Verify partition table fields (deprecated, this behaviour is ' - 'enabled by default and this flag does nothing.', action='store_true') + parser.add_argument( + '--verify', + '-v', + help='Verify partition table fields (deprecated, this behaviour is ' + 'enabled by default and this flag does nothing.', + action='store_true', + ) parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true') parser.add_argument('--offset', '-o', help='Set offset partition table', default='0x8000') parser.add_argument('--primary-bootloader-offset', help='Set primary bootloader offset', default=None) parser.add_argument('--recovery-bootloader-offset', help='Set recovery bootloader offset', default=None) - parser.add_argument('--secure', help='Require app partitions to be suitable for secure boot', nargs='?', const=SECURE_V1, choices=[SECURE_V1, SECURE_V2]) + parser.add_argument( + '--secure', + help='Require app partitions to be suitable for secure boot', + nargs='?', + const=SECURE_V1, + choices=[SECURE_V1, SECURE_V2], + ) parser.add_argument('--extra-partition-subtypes', help='Extra partition subtype entries', nargs='*') parser.add_argument('input', help='Path to CSV or binary file to parse.', type=argparse.FileType('rb')) - parser.add_argument('output', help='Path to output converted binary or CSV file. Will use stdout if omitted.', - nargs='?', default='-') + parser.add_argument( + 'output', + help='Path to output converted binary or CSV file. Will use stdout if omitted.', + nargs='?', + default='-', + ) args = parser.parse_args() @@ -702,8 +778,7 @@ class InputError(RuntimeError): class ValidationError(InputError): def __init__(self, partition, message): - super(ValidationError, self).__init__( - 'Partition %s invalid: %s' % (partition.name, message)) + super(ValidationError, self).__init__('Partition %s invalid: %s' % (partition.name, message)) if __name__ == '__main__': diff --git a/components/partition_table/partitions_singleapp_tee.csv b/components/partition_table/partitions_singleapp_tee.csv index 0916323b32..d55557eedf 100644 --- a/components/partition_table/partitions_singleapp_tee.csv +++ b/components/partition_table/partitions_singleapp_tee.csv @@ -1,8 +1,7 @@ # Name, Type, SubType, Offset, Size, Flags # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap tee, app, tee_0, , 192K, -tee_nvs, data, nvs, , 32K, -secure_storage, data, tee_sec_stg, , 32K, +secure_storage, data, nvs, , 64K, factory, app, factory, , 1536K, nvs, data, nvs, , 24K, phy_init, data, phy, , 4K, diff --git a/components/partition_table/partitions_two_ota_tee.csv b/components/partition_table/partitions_two_ota_tee.csv index 441fdeaa83..7d9669c1db 100644 --- a/components/partition_table/partitions_two_ota_tee.csv +++ b/components/partition_table/partitions_two_ota_tee.csv @@ -3,8 +3,7 @@ tee_0, app, tee_0, , 192K, tee_1, app, tee_1, , 192K, tee_otadata, data, tee_ota, , 8K, -tee_nvs, data, nvs, , 32K, -secure_storage, data, tee_sec_stg, , 24K, +secure_storage, data, nvs, , 56K, ota_0, app, ota_0, , 1536K, ota_1, app, ota_1, , 1536K, otadata, data, ota, , 8K,