refactor(esp_tee): Remove the deprecated TEE secure storage partition subtype

This commit is contained in:
Laukik Hase
2025-04-08 16:08:45 +05:30
parent d116567a66
commit 41bf07e6ce
10 changed files with 190 additions and 115 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 tee, app, tee_0, , 192K,
4 tee_nvs, data, nvs, , 32K, secure_storage, data, nvs, , 64K,
secure_storage, data, tee_sec_stg, , 32K,
5 factory, app, factory, , 1536K,
6 nvs, data, nvs, , 24K,
7 phy_init, data, phy, , 4K,

View File

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

1 # Name, Type, SubType, Offset, Size, Flags
3 tee_0, app, tee_0, , 192K,
4 tee_1, app, tee_1, , 192K,
5 tee_otadata, data, tee_ota, , 8K,
6 tee_nvs, data, nvs, , 32K, secure_storage, data, nvs, , 56K,
secure_storage, data, tee_sec_stg, , 24K,
7 ota_0, app, ota_0, , 1536K,
8 ota_1, app, ota_1, , 1536K,
9 otadata, data, ota, , 8K,