partition_table: warn if data partition offset is not 4kB aligned

If a partition offset is not aligned to 4 kB, erase operations will
fail, even if they are aligned to 4 kB relative to the partition
start. This is because the underlying esp_flash_erase_range function
only works when the address is aligned to 4 kB.

Not making this an error for now, since applications might be using
read-only non-4kB aligned partitions, which still work fine.
Will change this behavior in IDF 5.0, requiring 4 kB alignment for all
partitions.

Closes https://github.com/espressif/esp-idf/issues/7295
Closes https://github.com/espressif/esp-idf/issues/7350
This commit is contained in:
Ivan Grokhotkov 2021-08-23 08:09:28 +02:00
parent 54595887f6
commit b56c9aafe4
2 changed files with 33 additions and 7 deletions

View File

@ -92,6 +92,19 @@ def get_subtype_as_int(ptype, subtype):
return subtype
ALIGNMENT = {
APP_TYPE: 0x10000,
DATA_TYPE: 0x4,
}
STRICT_DATA_ALIGNMENT = 0x1000
def get_alignment_for_type(ptype):
return ALIGNMENT.get(ptype, ALIGNMENT[DATA_TYPE])
quiet = False
md5sum = True
secure = False
@ -161,7 +174,7 @@ class PartitionTable(list):
raise InputError('CSV Error: Partitions overlap. Partition at line %d sets offset 0x%x. Previous partition ends 0x%x'
% (e.line_no, e.offset, last_end))
if e.offset is None:
pad_to = 0x10000 if e.type == APP_TYPE else 4
pad_to = get_alignment_for_type(e.type)
if last_end % pad_to != 0:
last_end += pad_to - (last_end % pad_to)
e.offset = last_end
@ -287,11 +300,6 @@ class PartitionTable(list):
class PartitionDefinition(object):
MAGIC_BYTES = b'\xAA\x50'
ALIGNMENT = {
APP_TYPE: 0x10000,
DATA_TYPE: 0x04,
}
# dictionary maps flag name (as used in CSV flags list, property name)
# to bit set in flags words in binary format
FLAGS = {
@ -388,9 +396,14 @@ class PartitionDefinition(object):
raise ValidationError(self, 'Subtype field is not set')
if self.offset is None:
raise ValidationError(self, 'Offset field is not set')
align = self.ALIGNMENT.get(self.type, 4)
align = get_alignment_for_type(self.type)
if self.offset % align:
raise ValidationError(self, 'Offset 0x%x is not aligned to 0x%x' % (self.offset, align))
# The alignment requirement for non-app partition is 4 bytes, but it should be 4 kB.
# Print a warning for now, make it an error in IDF 5.0 (IDF-3742).
if self.type != APP_TYPE and self.offset % STRICT_DATA_ALIGNMENT:
critical('WARNING: Partition %s not aligned to 0x%x.'
'This is deprecated and will be considered an error in the future release.' % (self.name, STRICT_DATA_ALIGNMENT))
if self.size % align and secure and self.type == APP_TYPE:
raise ValidationError(self, 'Size 0x%x is not aligned to 0x%x' % (self.size, align))
if self.size is None:

View File

@ -451,6 +451,19 @@ ota_1, 0, ota_1, , 1M,
self.assertIn('WARNING', sys.stderr.getvalue())
self.assertIn('partition subtype', sys.stderr.getvalue())
sys.stderr = io.StringIO()
csv_3 = 'nvs, data, nvs, 0x8800, 32k'
gen_esp32part.PartitionTable.from_csv(csv_3).verify()
self.assertIn('WARNING', sys.stderr.getvalue())
self.assertIn('not aligned to 0x1000', sys.stderr.getvalue())
sys.stderr = io.StringIO()
csv_4 = 'factory, app, factory, 0x10000, 0x100100\n' \
'nvs, data, nvs, , 32k'
gen_esp32part.PartitionTable.from_csv(csv_4).verify()
self.assertIn('WARNING', sys.stderr.getvalue())
self.assertIn('not aligned to 0x1000', sys.stderr.getvalue())
finally:
sys.stderr = sys.__stderr__