partition_table: Fix case when a few similar to otadata partitions in the table

It was when in the partition table there is a partition with type="data" and suptype=""(empty),
in this case type=1, suptype=0. It is similar to otadata partition.

This commit fixes it, now it will handle it as type=1, suptype=6 (ESP_PARTITION_SUBTYPE_DATA_UNDEFINED).
This commit is contained in:
KonstantinKondrashov
2021-06-11 17:53:45 +05:00
parent 54b25318cd
commit 208b41975b
4 changed files with 86 additions and 5 deletions

View File

@ -61,6 +61,7 @@ SUBTYPES = {
'coredump': 0x03, 'coredump': 0x03,
'nvs_keys': 0x04, 'nvs_keys': 0x04,
'efuse': 0x05, 'efuse': 0x05,
'undefined': 0x06,
'esphttpd': 0x80, 'esphttpd': 0x80,
'fat': 0x81, 'fat': 0x81,
'spiffs': 0x82, 'spiffs': 0x82,
@ -107,8 +108,8 @@ class PartitionTable(list):
continue continue
try: try:
res.append(PartitionDefinition.from_csv(line, line_no + 1)) res.append(PartitionDefinition.from_csv(line, line_no + 1))
except InputError as e: except InputError as err:
raise InputError('Error at line %d: %s' % (line_no + 1, e)) raise InputError('Error at line %d: %s' % (line_no + 1, err))
except Exception: except Exception:
critical('Unexpected error parsing CSV line %d: %s' % (line_no + 1, line)) critical('Unexpected error parsing CSV line %d: %s' % (line_no + 1, line))
raise raise
@ -201,6 +202,18 @@ class PartitionTable(list):
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
# check that otadata should be unique
otadata_duplicates = [p for p in self if p.type == TYPES['data'] and p.subtype == SUBTYPES[DATA_TYPE]['ota']]
if len(otadata_duplicates) > 1:
for p in otadata_duplicates:
print(p.name, p.type, p.subtype)
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]
print(p.name, p.type, p.subtype, p.offset, p.size)
raise InputError('otadata partition must have size = 0x2000')
def flash_size(self): def flash_size(self):
""" Return the size that partitions will occupy in flash """ Return the size that partitions will occupy in flash
(ie the offset the last partition ends at) (ie the offset the last partition ends at)
@ -334,7 +347,9 @@ class PartitionDefinition(object):
def parse_subtype(self, strval): def parse_subtype(self, strval):
if strval == '': if strval == '':
return 0 # default if self.type == TYPES['app']:
raise InputError('App partition cannot have an empty subtype')
return SUBTYPES[DATA_TYPE]['undefined']
return parse_int(strval, SUBTYPES.get(self.type, {})) return parse_int(strval, SUBTYPES.get(self.type, {}))
def parse_address(self, strval): def parse_address(self, strval):

View File

@ -98,7 +98,7 @@ myota_0, 0, 0x10,, 0x100000
myota_1, 0, 0x11,, 0x100000 myota_1, 0, 0x11,, 0x100000
myota_15, 0, 0x1f,, 0x100000 myota_15, 0, 0x1f,, 0x100000
mytest, 0, 0x20,, 0x100000 mytest, 0, 0x20,, 0x100000
myota_status, 1, 0,, 0x100000 myota_status, 1, 0,, 0x2000
""" """
csv_nomagicnumbers = """ csv_nomagicnumbers = """
# Name, Type, SubType, Offset, Size # Name, Type, SubType, Offset, Size
@ -107,7 +107,7 @@ myota_0, app, ota_0,, 0x100000
myota_1, app, ota_1,, 0x100000 myota_1, app, ota_1,, 0x100000
myota_15, app, ota_15,, 0x100000 myota_15, app, ota_15,, 0x100000
mytest, app, test,, 0x100000 mytest, app, test,, 0x100000
myota_status, data, ota,, 0x100000 myota_status, data, ota,, 0x2000
""" """
# make two equivalent partition tables, one using # make two equivalent partition tables, one using
# magic numbers and one using shortcuts. Ensure they match # magic numbers and one using shortcuts. Ensure they match
@ -229,6 +229,30 @@ first, app, factory,, 1M, encrypted
tr = gen_esp32part.PartitionTable.from_binary(tb) tr = gen_esp32part.PartitionTable.from_binary(tb)
self.assertTrue(tr[0].encrypted) self.assertTrue(tr[0].encrypted)
def test_only_empty_subtype_is_not_0(self):
csv_txt = """
# Name,Type, SubType,Offset,Size
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
factory, app, factory, , 1M
ota_0, 0, ota_0, , 1M,
ota_1, 0, ota_1, , 1M,
storage, data, , , 512k,
storage2, data, undefined, , 12k,
"""
t = gen_esp32part.PartitionTable.from_csv(csv_txt)
t.verify()
self.assertEqual(t[1].name, 'otadata')
self.assertEqual(t[1].type, 1)
self.assertEqual(t[1].subtype, 0)
self.assertEqual(t[6].name, 'storage')
self.assertEqual(t[6].type, 1)
self.assertEqual(t[6].subtype, 0x06)
self.assertEqual(t[7].name, 'storage2')
self.assertEqual(t[7].type, 1)
self.assertEqual(t[7].subtype, 0x06)
class BinaryParserTests(Py23TestCase): class BinaryParserTests(Py23TestCase):
def test_parse_one_entry(self): def test_parse_one_entry(self):
@ -382,6 +406,46 @@ app,app, factory, 32K, 1M
t = gen_esp32part.PartitionTable.from_csv(csv) t = gen_esp32part.PartitionTable.from_csv(csv)
t.verify() t.verify()
def test_only_one_otadata(self):
csv_txt = """
# Name,Type, SubType,Offset,Size
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x2000,
otadata2, data, ota, , 0x2000,
factory, app, factory, , 1M
ota_0, 0, ota_0, , 1M,
ota_1, 0, ota_1, , 1M,
"""
with self.assertRaisesRegex(gen_esp32part.InputError, r'Found multiple otadata partitions'):
t = gen_esp32part.PartitionTable.from_csv(csv_txt)
t.verify()
def test_otadata_must_have_fixed_size(self):
csv_txt = """
# Name,Type, SubType,Offset,Size
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x3000,
factory, app, factory, , 1M
ota_0, 0, ota_0, , 1M,
ota_1, 0, ota_1, , 1M,
"""
with self.assertRaisesRegex(gen_esp32part.InputError, r'otadata partition must have size = 0x2000'):
t = gen_esp32part.PartitionTable.from_csv(csv_txt)
t.verify()
def test_app_cannot_have_empty_subtype(self):
csv_txt = """
# Name,Type, SubType,Offset,Size
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x2000,
factory, app, , , 1M
ota_0, 0, ota_0, , 1M,
ota_1, 0, ota_1, , 1M,
"""
with self.assertRaisesRegex(gen_esp32part.InputError, r'App partition cannot have an empty subtype'):
t = gen_esp32part.PartitionTable.from_csv(csv_txt)
t.verify()
def test_warnings(self): def test_warnings(self):
try: try:
sys.stderr = io.StringIO() # capture stderr sys.stderr = io.StringIO() # capture stderr

View File

@ -85,6 +85,7 @@ typedef enum {
ESP_PARTITION_SUBTYPE_DATA_COREDUMP = 0x03, //!< COREDUMP partition ESP_PARTITION_SUBTYPE_DATA_COREDUMP = 0x03, //!< COREDUMP partition
ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS = 0x04, //!< Partition for NVS keys ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS = 0x04, //!< Partition for NVS keys
ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM = 0x05, //!< Partition for emulate eFuse bits ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM = 0x05, //!< Partition for emulate eFuse bits
ESP_PARTITION_SUBTYPE_DATA_UNDEFINED = 0x06, //!< Undefined (or unspecified) data partition
ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD = 0x80, //!< ESPHTTPD partition ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD = 0x80, //!< ESPHTTPD partition
ESP_PARTITION_SUBTYPE_DATA_FAT = 0x81, //!< FAT partition ESP_PARTITION_SUBTYPE_DATA_FAT = 0x81, //!< FAT partition

View File

@ -57,6 +57,7 @@ typedef enum {
ESP_PARTITION_SUBTYPE_DATA_COREDUMP = 0x03, //!< COREDUMP partition ESP_PARTITION_SUBTYPE_DATA_COREDUMP = 0x03, //!< COREDUMP partition
ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS = 0x04, //!< Partition for NVS keys ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS = 0x04, //!< Partition for NVS keys
ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM = 0x05, //!< Partition for emulate eFuse bits ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM = 0x05, //!< Partition for emulate eFuse bits
ESP_PARTITION_SUBTYPE_DATA_UNDEFINED = 0x06, //!< Undefined (or unspecified) data partition
ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD = 0x80, //!< ESPHTTPD partition ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD = 0x80, //!< ESPHTTPD partition
ESP_PARTITION_SUBTYPE_DATA_FAT = 0x81, //!< FAT partition ESP_PARTITION_SUBTYPE_DATA_FAT = 0x81, //!< FAT partition