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 eaf738fae9
commit fc0f90e8aa
4 changed files with 191 additions and 15 deletions

View File

@ -55,15 +55,16 @@ SUBTYPES = {
"test": 0x20, "test": 0x20,
}, },
DATA_TYPE: { DATA_TYPE: {
"ota": 0x00, 'ota': 0x00,
"phy": 0x01, 'phy': 0x01,
"nvs": 0x02, 'nvs': 0x02,
"coredump": 0x03, 'coredump': 0x03,
"nvs_keys": 0x04, 'nvs_keys': 0x04,
"efuse": 0x05, 'efuse': 0x05,
"esphttpd": 0x80, 'undefined': 0x06,
"fat": 0x81, 'esphttpd': 0x80,
"spiffs": 0x82, 'fat': 0x81,
'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)
@ -333,8 +346,10 @@ class PartitionDefinition(object):
return parse_int(strval, TYPES) return parse_int(strval, TYPES)
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

@ -0,0 +1,96 @@
// Copyright 2015-2016 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.
#ifndef __ESP_PARTITION_H__
#define __ESP_PARTITION_H__
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
ESP_PARTITION_TYPE_APP = 0x00, //!< Application partition type
ESP_PARTITION_TYPE_DATA = 0x01, //!< Data partition type
} esp_partition_type_t;
typedef enum {
ESP_PARTITION_SUBTYPE_APP_FACTORY = 0x00, //!< Factory application partition
ESP_PARTITION_SUBTYPE_APP_OTA_MIN = 0x10, //!< Base for OTA partition subtypes
ESP_PARTITION_SUBTYPE_APP_OTA_0 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 0, //!< OTA partition 0
ESP_PARTITION_SUBTYPE_APP_OTA_1 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 1, //!< OTA partition 1
ESP_PARTITION_SUBTYPE_APP_OTA_2 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 2, //!< OTA partition 2
ESP_PARTITION_SUBTYPE_APP_OTA_3 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 3, //!< OTA partition 3
ESP_PARTITION_SUBTYPE_APP_OTA_4 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 4, //!< OTA partition 4
ESP_PARTITION_SUBTYPE_APP_OTA_5 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 5, //!< OTA partition 5
ESP_PARTITION_SUBTYPE_APP_OTA_6 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 6, //!< OTA partition 6
ESP_PARTITION_SUBTYPE_APP_OTA_7 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 7, //!< OTA partition 7
ESP_PARTITION_SUBTYPE_APP_OTA_8 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 8, //!< OTA partition 8
ESP_PARTITION_SUBTYPE_APP_OTA_9 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 9, //!< OTA partition 9
ESP_PARTITION_SUBTYPE_APP_OTA_10 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 10,//!< OTA partition 10
ESP_PARTITION_SUBTYPE_APP_OTA_11 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 11,//!< OTA partition 11
ESP_PARTITION_SUBTYPE_APP_OTA_12 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 12,//!< OTA partition 12
ESP_PARTITION_SUBTYPE_APP_OTA_13 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 13,//!< OTA partition 13
ESP_PARTITION_SUBTYPE_APP_OTA_14 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 14,//!< OTA partition 14
ESP_PARTITION_SUBTYPE_APP_OTA_15 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 15,//!< OTA partition 15
ESP_PARTITION_SUBTYPE_APP_OTA_MAX = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 16,//!< Max subtype of OTA partition
ESP_PARTITION_SUBTYPE_APP_TEST = 0x20, //!< Test application partition
ESP_PARTITION_SUBTYPE_DATA_OTA = 0x00, //!< OTA selection partition
ESP_PARTITION_SUBTYPE_DATA_PHY = 0x01, //!< PHY init data partition
ESP_PARTITION_SUBTYPE_DATA_NVS = 0x02, //!< NVS partition
ESP_PARTITION_SUBTYPE_DATA_COREDUMP = 0x03, //!< COREDUMP partition
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_UNDEFINED = 0x06, //!< Undefined (or unspecified) data partition
ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD = 0x80, //!< ESPHTTPD partition
ESP_PARTITION_SUBTYPE_DATA_FAT = 0x81, //!< FAT partition
ESP_PARTITION_SUBTYPE_DATA_SPIFFS = 0x82, //!< SPIFFS partition
ESP_PARTITION_SUBTYPE_ANY = 0xff, //!< Used to search for partitions with any subtype
} esp_partition_subtype_t;
/**
* @brief Opaque partition iterator type
*/
typedef struct esp_partition_iterator_opaque_* esp_partition_iterator_t;
/**
* @brief partition information structure
*
* This is not the format in flash, that format is esp_partition_info_t.
*
* However, this is the format used by this API.
*/
typedef struct {
void* flash_chip; /*!< SPI flash chip on which the partition resides */
esp_partition_type_t type; /*!< partition type (app/data) */
esp_partition_subtype_t subtype; /*!< partition subtype */
uint32_t address; /*!< starting address of the partition in flash */
uint32_t size; /*!< size of the partition, in bytes */
char label[17]; /*!< partition label, zero-terminated ASCII string */
bool encrypted; /*!< flag is set to true if partition is encrypted */
} esp_partition_t;
#ifdef __cplusplus
}
#endif
#endif /* __ESP_PARTITION_H__ */