From d42bde037860a9b5328ebad6c9245fe49a241e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20M=C3=BAdry?= Date: Wed, 30 Aug 2023 17:03:04 +0200 Subject: [PATCH] feat(nvs): NVS tool add key consistency check --- .../nvs_flash/nvs_partition_tool/nvs_check.py | 56 ++++++++++++++----- .../nvs_flash/nvs_partition_tool/nvs_tool.py | 2 +- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/components/nvs_flash/nvs_partition_tool/nvs_check.py b/components/nvs_flash/nvs_partition_tool/nvs_check.py index 58adff7bef..fd38978e11 100644 --- a/components/nvs_flash/nvs_partition_tool/nvs_check.py +++ b/components/nvs_flash/nvs_partition_tool/nvs_check.py @@ -18,7 +18,7 @@ def integrity_check(nvs_partition: NVS_Partition, nvs_log: NVS_Logger) -> None: if len(nvs_partition.pages) < 3: nvs_log.info( nvs_log.yellow( - 'Partition has to have at least 3 pages to function properly!' + 'NVS Partition must contain 3 pages (sectors) at least to function properly!' ) ) @@ -26,10 +26,11 @@ def integrity_check(nvs_partition: NVS_Partition, nvs_log: NVS_Logger) -> None: if not any(page.header['status'] == 'Empty' for page in nvs_partition.pages): nvs_log.info( nvs_log.red( - 'There are no free (empty) pages in the partition, there needs to be at least one free page!' + '''No free (empty) page found in the NVS partition, +at least one free page is required for proper function!''' ) ) - nvs_log.info(nvs_log.red('Has the NVS partition been truncated?\n')) + nvs_log.info(nvs_log.red('NVS partition possibly truncated?\n')) for page in nvs_partition.pages: # page: NVS_Page @@ -42,12 +43,12 @@ def integrity_check(nvs_partition: NVS_Partition, nvs_log: NVS_Logger) -> None: if page.raw_entry_state_bitmap != bytearray({0xFF}) * nvs_const.entry_size: nvs_log.info( nvs_log.red( - 'Page is reported as empty but entry state bitmap is not empty!' + 'The page is reported as Empty but its entry state bitmap is not empty!' ) ) if any([not e.is_empty for e in page.entries]): nvs_log.info( - nvs_log.red('Page is reported as empty but there are data written!') + nvs_log.red('The page is reported as Empty but there are data written!') ) else: # Check page header CRC32 @@ -65,22 +66,35 @@ def integrity_check(nvs_partition: NVS_Partition, nvs_log: NVS_Logger) -> None: ) # Check all entries + seen_written_entires: Dict[str, list[NVS_Entry]] = {} for entry in page.entries: # entry: NVS_Entry - # Entry state check + # Entries stored in 'page.entries' are primitive data types, blob indexes or string/blob data + + # Variable length values themselves occupy whole 32 bytes (therefore metadata values are meaningless) + # and are stored in as entries inside string/blob data entry 'entry.children' list + + # Duplicate entry check (1) - same key, different index - find duplicates + if entry.state == 'Written': + if entry.key in seen_written_entires: + seen_written_entires[entry.key].append(entry) + else: + seen_written_entires[entry.key] = [entry] + + # Entry state check - doesn't check variable length values (metadata such as state are meaningless as all 32 bytes are pure data) if entry.is_empty: if entry.state == 'Written': nvs_log.info( nvs_log.red( - f' Entry #{entry.index:03d} is reported as written but is empty!' + f' Entry #{entry.index:03d} is reported as Written but it is empty!' ) ) continue elif entry.state == 'Erased': nvs_log.info( nvs_log.yellow( - f' Entry #{entry.index:03d} is reported as erased but is empty!' + f' Entry #{entry.index:03d} is reported as Erased but it is empty! (Only entries reported as Empty should be empty)' ) ) @@ -103,17 +117,16 @@ def integrity_check(nvs_partition: NVS_Partition, nvs_log: NVS_Logger) -> None: # Entry children CRC32 check if ( entry.metadata['span'] > 1 - and entry.metadata['crc']['data_original'] - != entry.metadata['crc']['data_computed'] + and (entry.metadata['crc']['data_original'] != entry.metadata['crc']['data_computed']) ): nvs_log.info( nvs_log.red( - f' Entry #{entry.index:03d} {entry.key} data has wrong CRC32!' + f' Entry #{entry.index:03d} {entry.key} data (string, blob) has wrong CRC32!' ), f'Written:', - nvs_log.red(f'{entry.metadata["crc"]["original"]:x}'), + nvs_log.red(f'{entry.metadata["crc"]["data_original"]:x}'), f'Generated:', - nvs_log.green(f'{entry.metadata["crc"]["computed"]:x}'), + nvs_log.green(f'{entry.metadata["crc"]["data_computed"]:x}'), ) # Entry type check @@ -161,6 +174,23 @@ def integrity_check(nvs_partition: NVS_Partition, nvs_log: NVS_Logger) -> None: else: used_namespaces[entry.metadata['namespace']] = None + # Duplicate entry check (2) - same key, different index - print duplicates + duplicate_entries_list = [seen_written_entires[key] for key in seen_written_entires if len(seen_written_entires[key]) > 1] + for duplicate_entries in duplicate_entries_list: + # duplicate_entries: list[NVS_Entry] + nvs_log.info( + nvs_log.red( + f'''Entry key {duplicate_entries[0].key} on page no. {page.header["page_index"]} +with status {page.header["status"]} is used by the following entries:''' + ) + ) + for entry in duplicate_entries: + nvs_log.info( + nvs_log.red( + f'Entry #{entry.index:03d} {entry.key} is a duplicate!' + ) + ) + nvs_log.info() # Blob checks diff --git a/components/nvs_flash/nvs_partition_tool/nvs_tool.py b/components/nvs_flash/nvs_partition_tool/nvs_tool.py index f59ea23107..d61de55bda 100644 --- a/components/nvs_flash/nvs_partition_tool/nvs_tool.py +++ b/components/nvs_flash/nvs_partition_tool/nvs_tool.py @@ -110,7 +110,7 @@ def main() -> None: if args.integrity_check: nvs_log.info() - nvs_check.integrity_check(nvs, nvs_logger) + nvs_check.integrity_check(nvs, nvs_log) if __name__ == '__main__':