From 01001fac25855186b9ee83e05d3ec09178eb0f61 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Mon, 17 Mar 2025 15:55:29 +0900
Subject: [PATCH 01/40] Add an example of extract and enumerate partition table
 information

---
 README.md                             |   1 +
 flash/CMakeLists.txt                  |   3 +-
 flash/partition_info/CMakeLists.txt   |  11 ++
 flash/partition_info/partition_info.c | 154 ++++++++++++++++++++++++++
 flash/partition_info/pt.json          |  46 ++++++++
 5 files changed, 214 insertions(+), 1 deletion(-)
 create mode 100644 flash/partition_info/CMakeLists.txt
 create mode 100644 flash/partition_info/partition_info.c
 create mode 100644 flash/partition_info/pt.json

diff --git a/README.md b/README.md
index 5a436a348..0fb329c85 100644
--- a/README.md
+++ b/README.md
@@ -102,6 +102,7 @@ App|Description
 [xip_stream](flash/xip_stream) | Stream data using the XIP stream hardware, which allows data to be DMA'd in the background whilst executing code from flash.
 [ssi_dma](flash/ssi_dma) | DMA directly from the flash interface (continuous SCK clocking) for maximum bulk read performance.
 [runtime_flash_permissions](flash/runtime_flash_permissions) | Demonstrates adding partitions at runtime to change the flash permissions
+[partition_info](flash/partition_info) | Extract and enumerate partition information (address ranges, permissions, IDs, and names) from the partition table.
 
 ### FreeRTOS
 
diff --git a/flash/CMakeLists.txt b/flash/CMakeLists.txt
index 22de94038..fe03dcba9 100644
--- a/flash/CMakeLists.txt
+++ b/flash/CMakeLists.txt
@@ -5,6 +5,7 @@ if (TARGET hardware_flash)
     add_subdirectory_exclude_platforms(ssi_dma "rp2350.*")
     add_subdirectory_exclude_platforms(xip_stream)
     add_subdirectory_exclude_platforms(runtime_flash_permissions rp2040)
+    add_subdirectory_exclude_platforms(partition_info rp2040)
 else()
     message("Skipping flash examples as hardware_flash is unavailable on this platform")
-endif()
\ No newline at end of file
+endif()
diff --git a/flash/partition_info/CMakeLists.txt b/flash/partition_info/CMakeLists.txt
new file mode 100644
index 000000000..a1ce9ceac
--- /dev/null
+++ b/flash/partition_info/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_executable(partition_info partition_info.c)
+target_link_libraries(partition_info PRIVATE
+  pico_stdlib
+  pico_bootrom
+)
+
+pico_embed_pt_in_binary(partition_info ${CMAKE_CURRENT_LIST_DIR}/pt.json)
+pico_enable_stdio_usb(partition_info 1)
+pico_add_extra_outputs(partition_info)
+example_auto_set_url(partition_info)
+
diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
new file mode 100644
index 000000000..084f246b7
--- /dev/null
+++ b/flash/partition_info/partition_info.c
@@ -0,0 +1,154 @@
+/**
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdio.h>
+#include <pico/stdlib.h>
+#include <pico/bootrom.h>
+#include "boot/picobin.h"
+
+
+#define PART_LOC_FIRST(x) ( ((x) & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB )
+#define PART_LOC_LAST(x)  ( ((x) & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS)  >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB )
+
+/*
+ * Stores partition table information and data read status
+ */
+typedef struct {
+    int flags;
+    uint32_t *table;
+    size_t table_size;
+    int partition_count;
+    uint32_t unpartitioned_space_first_sector;
+    uint32_t unpartitioned_space_last_sector;
+    uint32_t permission;
+    int current_partition;
+    size_t idx;
+} pico_partition_t;
+
+/*
+ * Stores information on each partition
+ */
+typedef struct {
+    uint32_t first_sector;
+    uint32_t last_sector;
+    uint32_t permission;
+    uint64_t partition_id;
+    char name[127 + 1];
+} pico_partition_entry_t;
+
+
+/*
+ * Read the partition table information.
+ * See the RP2350 datasheet 5.1.2, 5.4.8.16 for flags and structures that can be specified.
+ */
+int pico_partitions_open(pico_partition_t *pt, int flags) {
+    pt->flags = flags;
+    static __attribute__((aligned(4))) uint32_t workarea[816] = {0};
+    int rc = rom_get_partition_table_info(workarea, sizeof(workarea), flags);
+    if (rc < 0) {
+        return rc;
+    }
+    pt->table = workarea;
+    pt->table_size = rc * 4;  // word to bytes
+    pt->partition_count = ((uint8_t*)workarea)[4];
+    uint32_t location = workarea[2];
+    pt->unpartitioned_space_first_sector = PART_LOC_FIRST(location);
+    pt->unpartitioned_space_last_sector = PART_LOC_LAST(location);
+    pt->permission = workarea[3];
+    pt->idx = 4;
+    pt->current_partition = 0;
+
+    return 0;
+}
+
+/*
+ * Parse a partition table and extract information
+ */
+size_t pico_partitions_parse(pico_partition_t *pt, pico_partition_entry_t *p) {
+    size_t idx = pt->idx;
+    if (pt->flags & PT_INFO_PARTITION_LOCATION_AND_FLAGS) {
+        uint32_t location = pt->table[idx++];
+        p->first_sector = PART_LOC_FIRST(location);
+        p->last_sector  = PART_LOC_LAST(location);
+        p->permission   = pt->table[idx++];
+    } else {
+        p->first_sector = 0;
+        p->last_sector = 0;
+        p->permission = 0;
+    }
+
+    if (pt->flags & PT_INFO_PARTITION_ID) {
+        uint32_t id_low  = pt->table[idx++];
+        uint32_t id_high = pt->table[idx++];
+        p->partition_id = ((uint64_t)id_high << 32) | id_low;
+    } else {
+        p->partition_id = 0;
+    }
+
+    if (pt->flags & PT_INFO_PARTITION_NAME) {
+        uint8_t *name_field = (uint8_t *)&pt->table[idx];
+        uint8_t name_length = name_field[0];
+        uint8_t *name_src = name_field + 1;
+        memcpy(p->name, name_src, name_length);
+        p->name[name_length] = '\0';
+        size_t total_name_bytes = 1 + name_length;
+        size_t padded_bytes = (total_name_bytes + 3) & ~((size_t)3);
+        idx += padded_bytes / 4;
+    } else {
+        p->name[0] = '\0';
+    }
+    return idx;
+}
+
+/*
+ * Extract one partition information
+ */
+bool pico_partitions_next(pico_partition_t *pt, pico_partition_entry_t *p) {
+    if (pt->current_partition >= pt->partition_count) {
+        return false;
+    }
+    pt->idx = pico_partitions_parse(pt, p);
+    pt->current_partition++;
+    return true;
+}
+
+int main() {
+    stdio_init_all();
+
+    pico_partition_t pt;
+    pico_partitions_open(&pt, PT_INFO_PT_INFO | PT_INFO_PARTITION_LOCATION_AND_FLAGS |
+                              PT_INFO_PARTITION_ID | PT_INFO_PARTITION_NAME);
+    printf("un-partitioned_space: S(%s%s) NSBOOT(%s%s) NS(%s%s)\n",
+           (pt.permission & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
+           (pt.permission & PICOBIN_PARTITION_PERMISSION_S_W_BITS ? "w" : ""),
+           (pt.permission & PICOBIN_PARTITION_PERMISSION_NSBOOT_R_BITS ? "r" : ""),
+           (pt.permission & PICOBIN_PARTITION_PERMISSION_NSBOOT_W_BITS ? "w" : ""),
+           (pt.permission & PICOBIN_PARTITION_PERMISSION_NS_R_BITS ? "r" : ""),
+           (pt.permission & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""));
+    printf("patitions:\n");
+    pico_partition_entry_t p;
+    while (pico_partitions_next(&pt, &p)) {
+        printf("%3d:", pt.current_partition - 1);
+        if (pt.flags & PT_INFO_PARTITION_LOCATION_AND_FLAGS) {
+            printf("    %08x->%08x S(%s%s) NSBOOT(%s%s) NS(%s%s)",
+                   p.first_sector * 4096, p.last_sector * 4096,
+                   (p.permission & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
+                   (p.permission & PICOBIN_PARTITION_PERMISSION_S_W_BITS ? "w" : ""),
+                   (p.permission & PICOBIN_PARTITION_PERMISSION_NSBOOT_R_BITS ? "r" : ""),
+                   (p.permission & PICOBIN_PARTITION_PERMISSION_NSBOOT_W_BITS ? "w" : ""),
+                   (p.permission & PICOBIN_PARTITION_PERMISSION_NS_R_BITS ? "r" : ""),
+                   (p.permission & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""));
+
+        }
+        if (pt.flags & PT_INFO_PARTITION_ID) {
+            printf(", id=%016llx", p.partition_id);
+        }
+        if (pt.flags & PT_INFO_PARTITION_NAME) {
+            printf(", \"%s\"", p.name);
+        }
+        printf("\n");
+    }
+
+    return 0;
+}
diff --git a/flash/partition_info/pt.json b/flash/partition_info/pt.json
new file mode 100644
index 000000000..2ad68e1e4
--- /dev/null
+++ b/flash/partition_info/pt.json
@@ -0,0 +1,46 @@
+{
+  "version": [1, 0],
+  "unpartitioned": {
+    "families": ["absolute"],
+    "permissions": {
+      "secure": "rw",
+      "nonsecure": "rw",
+      "bootloader": "rw"
+    }
+  },
+  "partitions": [
+    {
+      "name": "Firmware",
+      "id": 1,
+      "size": "512K",
+      "families": ["rp2350-arm-s", "rp2350-riscv"],
+      "permissions": {
+        "secure": "rw",
+        "nonsecure": "rw",
+        "bootloader": "rw"
+      }
+    },
+    {
+      "name": "Data",
+      "id": 2,
+      "size": "512K",
+      "families": ["rp2350-arm-s", "rp2350-riscv"],
+      "permissions": {
+        "secure": "rw",
+        "nonsecure": "rw",
+        "bootloader": "rw"
+      }
+    },
+    {
+      "name": "Read only Data",
+      "id": 3,
+      "size": "512K",
+      "families": ["rp2350-arm-s", "rp2350-riscv"],
+      "permissions": {
+        "secure": "r",
+        "nonsecure": "r",
+        "bootloader": "r"
+      }
+    }
+  ]
+}

From a0ceb2b5eb78ba81f3ec386b2973c0eb2b4372db Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Mon, 17 Mar 2025 16:07:31 +0900
Subject: [PATCH 02/40] update comments

---
 flash/partition_info/CMakeLists.txt   |  1 -
 flash/partition_info/partition_info.c | 17 +++++++++++------
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/flash/partition_info/CMakeLists.txt b/flash/partition_info/CMakeLists.txt
index a1ce9ceac..cb5b6e284 100644
--- a/flash/partition_info/CMakeLists.txt
+++ b/flash/partition_info/CMakeLists.txt
@@ -8,4 +8,3 @@ pico_embed_pt_in_binary(partition_info ${CMAKE_CURRENT_LIST_DIR}/pt.json)
 pico_enable_stdio_usb(partition_info 1)
 pico_add_extra_outputs(partition_info)
 example_auto_set_url(partition_info)
-
diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 084f246b7..482c90376 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -1,4 +1,6 @@
 /**
+ * Copyright (c) 2025 Hiroyuki OYAMA <oyama@module.jp>
+ * Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,6 +13,8 @@
 #define PART_LOC_FIRST(x) ( ((x) & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB )
 #define PART_LOC_LAST(x)  ( ((x) & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS)  >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB )
 
+#define WORD_SIZE  4
+
 /*
  * Stores partition table information and data read status
  */
@@ -50,13 +54,13 @@ int pico_partitions_open(pico_partition_t *pt, int flags) {
         return rc;
     }
     pt->table = workarea;
-    pt->table_size = rc * 4;  // word to bytes
-    pt->partition_count = ((uint8_t*)workarea)[4];
+    pt->table_size = rc * WORD_SIZE;  // word to bytes
     uint32_t location = workarea[2];
     pt->unpartitioned_space_first_sector = PART_LOC_FIRST(location);
     pt->unpartitioned_space_last_sector = PART_LOC_LAST(location);
     pt->permission = workarea[3];
-    pt->idx = 4;
+    pt->partition_count = ((uint8_t*)workarea)[4];
+    pt->idx = 4;  // point to the beggining of eath table
     pt->current_partition = 0;
 
     return 0;
@@ -92,9 +96,10 @@ size_t pico_partitions_parse(pico_partition_t *pt, pico_partition_entry_t *p) {
         uint8_t *name_src = name_field + 1;
         memcpy(p->name, name_src, name_length);
         p->name[name_length] = '\0';
-        size_t total_name_bytes = 1 + name_length;
-        size_t padded_bytes = (total_name_bytes + 3) & ~((size_t)3);
-        idx += padded_bytes / 4;
+        size_t total_name_field_length = 1 + name_length;
+        // Name field is padded to word size
+        size_t padded_bytes = (total_name_field_length + 3) & ~((size_t)3);
+        idx += padded_bytes / WORD_SIZE;
     } else {
         p->name[0] = '\0';
     }

From d2883d1cfffd0aa3d9ca99a8c454f6d32d60807f Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Mon, 17 Mar 2025 16:25:07 +0900
Subject: [PATCH 03/40] Remove redundant attribute specifiers

---
 flash/partition_info/partition_info.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 482c90376..e5742d452 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -38,17 +38,18 @@ typedef struct {
     uint32_t last_sector;
     uint32_t permission;
     uint64_t partition_id;
-    char name[127 + 1];
+    char name[127 + 1];  // name length is indicated by 7 bits
 } pico_partition_entry_t;
 
 
 /*
  * Read the partition table information.
+ *
  * See the RP2350 datasheet 5.1.2, 5.4.8.16 for flags and structures that can be specified.
  */
 int pico_partitions_open(pico_partition_t *pt, int flags) {
     pt->flags = flags;
-    static __attribute__((aligned(4))) uint32_t workarea[816] = {0};
+    static uint32_t workarea[816];
     int rc = rom_get_partition_table_info(workarea, sizeof(workarea), flags);
     if (rc < 0) {
         return rc;

From 10150677e3e2041d138e509f03f46384354e8e7d Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Wed, 19 Mar 2025 17:12:48 +0900
Subject: [PATCH 04/40] Rename structs, specify partition family, remove magic
 numbers

---
 flash/partition_info/CMakeLists.txt   | 13 +++--
 flash/partition_info/partition_info.c | 72 +++++++++++++--------------
 flash/partition_info/pt.json          |  7 +--
 3 files changed, 49 insertions(+), 43 deletions(-)

diff --git a/flash/partition_info/CMakeLists.txt b/flash/partition_info/CMakeLists.txt
index cb5b6e284..6e3cbbc63 100644
--- a/flash/partition_info/CMakeLists.txt
+++ b/flash/partition_info/CMakeLists.txt
@@ -1,10 +1,15 @@
 add_executable(partition_info partition_info.c)
+
 target_link_libraries(partition_info PRIVATE
-  pico_stdlib
-  pico_bootrom
-)
+        pico_stdlib
+        pico_bootrom
+        )
 
+# not necessary for the example functionality, but shows you how you would add a partition table
 pico_embed_pt_in_binary(partition_info ${CMAKE_CURRENT_LIST_DIR}/pt.json)
-pico_enable_stdio_usb(partition_info 1)
+
+# create map/bin/hex/uf2 file etc.
 pico_add_extra_outputs(partition_info)
+
+# add url via pico_set_program_url
 example_auto_set_url(partition_info)
diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index e5742d452..de6a0b525 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -1,5 +1,4 @@
 /**
- * Copyright (c) 2025 Hiroyuki OYAMA <oyama@module.jp>
  * Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -12,23 +11,28 @@
 
 #define PART_LOC_FIRST(x) ( ((x) & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB )
 #define PART_LOC_LAST(x)  ( ((x) & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS)  >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB )
+#define WORD_PADDED_BYTES(x)  ((x + 3) & ~3)
 
 #define WORD_SIZE  4
+#define PARTITION_LOCATION_AND_FLAGS_SIZE  2
+#define PARTITION_ID_SIZE                  2
+#define PARTITION_NAME_MAX                 127
+#define PARTITION_SIZE_MAX  (PARTITION_LOCATION_AND_FLAGS_SIZE + PARTITION_ID_SIZE + PARTITION_NAME_MAX + 1)
 
 /*
  * Stores partition table information and data read status
  */
 typedef struct {
-    int flags;
-    uint32_t *table;
+    uint32_t workarea[4 + PARTITION_TABLE_MAX_PARTITIONS * PARTITION_SIZE_MAX];
     size_t table_size;
+    uint32_t fields;
     int partition_count;
     uint32_t unpartitioned_space_first_sector;
     uint32_t unpartitioned_space_last_sector;
     uint32_t permission;
     int current_partition;
     size_t idx;
-} pico_partition_t;
+} pico_partition_table_t;
 
 /*
  * Stores information on each partition
@@ -38,8 +42,8 @@ typedef struct {
     uint32_t last_sector;
     uint32_t permission;
     uint64_t partition_id;
-    char name[127 + 1];  // name length is indicated by 7 bits
-} pico_partition_entry_t;
+    char name[PARTITION_NAME_MAX + 1];  // name length is indicated by 7 bits
+} pico_partition_t;
 
 
 /*
@@ -47,21 +51,21 @@ typedef struct {
  *
  * See the RP2350 datasheet 5.1.2, 5.4.8.16 for flags and structures that can be specified.
  */
-int pico_partitions_open(pico_partition_t *pt, int flags) {
-    pt->flags = flags;
-    static uint32_t workarea[816];
-    int rc = rom_get_partition_table_info(workarea, sizeof(workarea), flags);
+int pico_partitions_open(pico_partition_table_t *pt, int flags) {
+    int rc = rom_get_partition_table_info(pt->workarea, sizeof(pt->workarea), flags);
     if (rc < 0) {
         return rc;
     }
-    pt->table = workarea;
     pt->table_size = rc * WORD_SIZE;  // word to bytes
-    uint32_t location = workarea[2];
+
+    size_t pos = 0;
+    pt->fields = pt->workarea[pos++];
+    pt->partition_count = pt->workarea[pos++] & 0x000000FF;
+    uint32_t location = pt->workarea[pos++];
     pt->unpartitioned_space_first_sector = PART_LOC_FIRST(location);
     pt->unpartitioned_space_last_sector = PART_LOC_LAST(location);
-    pt->permission = workarea[3];
-    pt->partition_count = ((uint8_t*)workarea)[4];
-    pt->idx = 4;  // point to the beggining of eath table
+    pt->permission = pt->workarea[pos++];
+    pt->idx = pos;  // point to the beggining of eath partition
     pt->current_partition = 0;
 
     return 0;
@@ -70,37 +74,34 @@ int pico_partitions_open(pico_partition_t *pt, int flags) {
 /*
  * Parse a partition table and extract information
  */
-size_t pico_partitions_parse(pico_partition_t *pt, pico_partition_entry_t *p) {
+size_t pico_partitions_parse(pico_partition_table_t *pt, pico_partition_t *p) {
     size_t idx = pt->idx;
-    if (pt->flags & PT_INFO_PARTITION_LOCATION_AND_FLAGS) {
-        uint32_t location = pt->table[idx++];
+    if (pt->fields & PT_INFO_PARTITION_LOCATION_AND_FLAGS) {
+        uint32_t location = pt->workarea[idx++];
         p->first_sector = PART_LOC_FIRST(location);
         p->last_sector  = PART_LOC_LAST(location);
-        p->permission   = pt->table[idx++];
+        p->permission   = pt->workarea[idx++];
     } else {
         p->first_sector = 0;
         p->last_sector = 0;
         p->permission = 0;
     }
 
-    if (pt->flags & PT_INFO_PARTITION_ID) {
-        uint32_t id_low  = pt->table[idx++];
-        uint32_t id_high = pt->table[idx++];
+    if (pt->fields & PT_INFO_PARTITION_ID) {
+        uint32_t id_low  = pt->workarea[idx++];
+        uint32_t id_high = pt->workarea[idx++];
         p->partition_id = ((uint64_t)id_high << 32) | id_low;
     } else {
         p->partition_id = 0;
     }
 
-    if (pt->flags & PT_INFO_PARTITION_NAME) {
-        uint8_t *name_field = (uint8_t *)&pt->table[idx];
+    if (pt->fields & PT_INFO_PARTITION_NAME) {
+        uint8_t *name_field = (uint8_t *)&pt->workarea[idx];
         uint8_t name_length = name_field[0];
-        uint8_t *name_src = name_field + 1;
-        memcpy(p->name, name_src, name_length);
+        memcpy(p->name, name_field + 1, name_length);
         p->name[name_length] = '\0';
         size_t total_name_field_length = 1 + name_length;
-        // Name field is padded to word size
-        size_t padded_bytes = (total_name_field_length + 3) & ~((size_t)3);
-        idx += padded_bytes / WORD_SIZE;
+        idx += WORD_PADDED_BYTES(total_name_field_length) / WORD_SIZE;
     } else {
         p->name[0] = '\0';
     }
@@ -110,7 +111,7 @@ size_t pico_partitions_parse(pico_partition_t *pt, pico_partition_entry_t *p) {
 /*
  * Extract one partition information
  */
-bool pico_partitions_next(pico_partition_t *pt, pico_partition_entry_t *p) {
+bool pico_partitions_next(pico_partition_table_t *pt, pico_partition_t *p) {
     if (pt->current_partition >= pt->partition_count) {
         return false;
     }
@@ -122,7 +123,7 @@ bool pico_partitions_next(pico_partition_t *pt, pico_partition_entry_t *p) {
 int main() {
     stdio_init_all();
 
-    pico_partition_t pt;
+    pico_partition_table_t pt;
     pico_partitions_open(&pt, PT_INFO_PT_INFO | PT_INFO_PARTITION_LOCATION_AND_FLAGS |
                               PT_INFO_PARTITION_ID | PT_INFO_PARTITION_NAME);
     printf("un-partitioned_space: S(%s%s) NSBOOT(%s%s) NS(%s%s)\n",
@@ -133,10 +134,10 @@ int main() {
            (pt.permission & PICOBIN_PARTITION_PERMISSION_NS_R_BITS ? "r" : ""),
            (pt.permission & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""));
     printf("patitions:\n");
-    pico_partition_entry_t p;
+    pico_partition_t p;
     while (pico_partitions_next(&pt, &p)) {
         printf("%3d:", pt.current_partition - 1);
-        if (pt.flags & PT_INFO_PARTITION_LOCATION_AND_FLAGS) {
+        if (pt.fields & PT_INFO_PARTITION_LOCATION_AND_FLAGS) {
             printf("    %08x->%08x S(%s%s) NSBOOT(%s%s) NS(%s%s)",
                    p.first_sector * 4096, p.last_sector * 4096,
                    (p.permission & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
@@ -145,12 +146,11 @@ int main() {
                    (p.permission & PICOBIN_PARTITION_PERMISSION_NSBOOT_W_BITS ? "w" : ""),
                    (p.permission & PICOBIN_PARTITION_PERMISSION_NS_R_BITS ? "r" : ""),
                    (p.permission & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""));
-
         }
-        if (pt.flags & PT_INFO_PARTITION_ID) {
+        if (pt.fields & PT_INFO_PARTITION_ID) {
             printf(", id=%016llx", p.partition_id);
         }
-        if (pt.flags & PT_INFO_PARTITION_NAME) {
+        if (pt.fields & PT_INFO_PARTITION_NAME) {
             printf(", \"%s\"", p.name);
         }
         printf("\n");
diff --git a/flash/partition_info/pt.json b/flash/partition_info/pt.json
index 2ad68e1e4..b3ea9ac90 100644
--- a/flash/partition_info/pt.json
+++ b/flash/partition_info/pt.json
@@ -12,8 +12,9 @@
     {
       "name": "Firmware",
       "id": 1,
+      "start": 0,
       "size": "512K",
-      "families": ["rp2350-arm-s", "rp2350-riscv"],
+      "families": ["rp2350-arm-ns", "rp2350-arm-s", "rp2350-riscv"],
       "permissions": {
         "secure": "rw",
         "nonsecure": "rw",
@@ -24,7 +25,7 @@
       "name": "Data",
       "id": 2,
       "size": "512K",
-      "families": ["rp2350-arm-s", "rp2350-riscv"],
+      "families": ["data"],
       "permissions": {
         "secure": "rw",
         "nonsecure": "rw",
@@ -35,7 +36,7 @@
       "name": "Read only Data",
       "id": 3,
       "size": "512K",
-      "families": ["rp2350-arm-s", "rp2350-riscv"],
+      "families": ["data"],
       "permissions": {
         "secure": "r",
         "nonsecure": "r",

From 8b874492116117e29297c9f1b6dca2b97c3297e5 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Wed, 19 Mar 2025 19:12:27 +0900
Subject: [PATCH 05/40] Changed partition table reads to be split into
 fixed-length field sections and variable-length field sections

---
 flash/partition_info/partition_info.c | 120 +++++++++++++-------------
 1 file changed, 62 insertions(+), 58 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index de6a0b525..0f5b6b74c 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -17,14 +17,13 @@
 #define PARTITION_LOCATION_AND_FLAGS_SIZE  2
 #define PARTITION_ID_SIZE                  2
 #define PARTITION_NAME_MAX                 127
-#define PARTITION_SIZE_MAX  (PARTITION_LOCATION_AND_FLAGS_SIZE + PARTITION_ID_SIZE + PARTITION_NAME_MAX + 1)
+#define PARTITION_TABLE_FIXED_INFO_SIZE    (4 + PARTITION_TABLE_MAX_PARTITIONS * (PARTITION_LOCATION_AND_FLAGS_SIZE + PARTITION_ID_SIZE))
 
 /*
  * Stores partition table information and data read status
  */
 typedef struct {
-    uint32_t workarea[4 + PARTITION_TABLE_MAX_PARTITIONS * PARTITION_SIZE_MAX];
-    size_t table_size;
+    uint32_t table[PARTITION_TABLE_FIXED_INFO_SIZE];
     uint32_t fields;
     int partition_count;
     uint32_t unpartitioned_space_first_sector;
@@ -32,6 +31,7 @@ typedef struct {
     uint32_t permission;
     int current_partition;
     size_t idx;
+    int status;
 } pico_partition_table_t;
 
 /*
@@ -40,7 +40,7 @@ typedef struct {
 typedef struct {
     uint32_t first_sector;
     uint32_t last_sector;
-    uint32_t permission;
+    uint32_t flags_and_permissions;
     uint64_t partition_id;
     char name[PARTITION_NAME_MAX + 1];  // name length is indicated by 7 bits
 } pico_partition_t;
@@ -51,71 +51,74 @@ typedef struct {
  *
  * See the RP2350 datasheet 5.1.2, 5.4.8.16 for flags and structures that can be specified.
  */
-int pico_partitions_open(pico_partition_table_t *pt, int flags) {
-    int rc = rom_get_partition_table_info(pt->workarea, sizeof(pt->workarea), flags);
+int pico_partitions_open(pico_partition_table_t *pt) {
+    // Reads a fixed size fields
+    int rc = rom_get_partition_table_info(pt->table, sizeof(pt->table),
+                                          (PT_INFO_PT_INFO |
+                                           PT_INFO_PARTITION_LOCATION_AND_FLAGS |
+                                           PT_INFO_PARTITION_ID));
     if (rc < 0) {
+        pt->status = rc;
         return rc;
     }
-    pt->table_size = rc * WORD_SIZE;  // word to bytes
 
     size_t pos = 0;
-    pt->fields = pt->workarea[pos++];
-    pt->partition_count = pt->workarea[pos++] & 0x000000FF;
-    uint32_t location = pt->workarea[pos++];
+    pt->fields = pt->table[pos++];
+    pt->partition_count = pt->table[pos++] & 0x000000FF;
+    uint32_t location = pt->table[pos++];
     pt->unpartitioned_space_first_sector = PART_LOC_FIRST(location);
     pt->unpartitioned_space_last_sector = PART_LOC_LAST(location);
-    pt->permission = pt->workarea[pos++];
-    pt->idx = pos;  // point to the beggining of eath partition
+    pt->permission = pt->table[pos++];
     pt->current_partition = 0;
+    pt->idx = pos;
+    pt->status = 0;
 
     return 0;
 }
 
 /*
- * Parse a partition table and extract information
+ * Extract each partition information
  */
-size_t pico_partitions_parse(pico_partition_table_t *pt, pico_partition_t *p) {
-    size_t idx = pt->idx;
-    if (pt->fields & PT_INFO_PARTITION_LOCATION_AND_FLAGS) {
-        uint32_t location = pt->workarea[idx++];
-        p->first_sector = PART_LOC_FIRST(location);
-        p->last_sector  = PART_LOC_LAST(location);
-        p->permission   = pt->workarea[idx++];
-    } else {
-        p->first_sector = 0;
-        p->last_sector = 0;
-        p->permission = 0;
+bool pico_partitions_next(pico_partition_table_t *pt, pico_partition_t *p) {
+    if (pt->current_partition >= pt->partition_count) {
+        return false;
     }
 
-    if (pt->fields & PT_INFO_PARTITION_ID) {
-        uint32_t id_low  = pt->workarea[idx++];
-        uint32_t id_high = pt->workarea[idx++];
+    size_t idx = pt->idx;
+    uint32_t location = pt->table[idx++];
+    p->first_sector = PART_LOC_FIRST(location);
+    p->last_sector = PART_LOC_LAST(location);
+    p->flags_and_permissions = pt->table[idx++];
+
+    if (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_ID_BITS) {
+        uint32_t id_low  = pt->table[idx++];
+        uint32_t id_high = pt->table[idx++];
         p->partition_id = ((uint64_t)id_high << 32) | id_low;
     } else {
         p->partition_id = 0;
     }
-
-    if (pt->fields & PT_INFO_PARTITION_NAME) {
-        uint8_t *name_field = (uint8_t *)&pt->workarea[idx];
-        uint8_t name_length = name_field[0];
-        memcpy(p->name, name_field + 1, name_length);
+    pt->idx = idx;
+
+    if (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS) {
+        // Read variable length fields
+        uint32_t name_buf[(PARTITION_NAME_MAX + 1) / WORD_SIZE] = {0};
+        int rc = rom_get_partition_table_info(name_buf, sizeof(name_buf),
+                                              (pt->current_partition << 24 |
+                                               PT_INFO_SINGLE_PARTITION |
+                                               PT_INFO_PARTITION_NAME));
+        if (rc < 0) {
+            pt->status = rc;
+            return false;
+        }
+        uint32_t __attribute__((unused)) fields = name_buf[0];
+        uint8_t *name_buf_u8 = (uint8_t *)&name_buf[1];
+        uint8_t name_length = *name_buf_u8++;
+        memcpy(p->name, name_buf_u8, name_length);
         p->name[name_length] = '\0';
-        size_t total_name_field_length = 1 + name_length;
-        idx += WORD_PADDED_BYTES(total_name_field_length) / WORD_SIZE;
     } else {
         p->name[0] = '\0';
     }
-    return idx;
-}
 
-/*
- * Extract one partition information
- */
-bool pico_partitions_next(pico_partition_table_t *pt, pico_partition_t *p) {
-    if (pt->current_partition >= pt->partition_count) {
-        return false;
-    }
-    pt->idx = pico_partitions_parse(pt, p);
     pt->current_partition++;
     return true;
 }
@@ -124,8 +127,7 @@ int main() {
     stdio_init_all();
 
     pico_partition_table_t pt;
-    pico_partitions_open(&pt, PT_INFO_PT_INFO | PT_INFO_PARTITION_LOCATION_AND_FLAGS |
-                              PT_INFO_PARTITION_ID | PT_INFO_PARTITION_NAME);
+    pico_partitions_open(&pt);
     printf("un-partitioned_space: S(%s%s) NSBOOT(%s%s) NS(%s%s)\n",
            (pt.permission & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
            (pt.permission & PICOBIN_PARTITION_PERMISSION_S_W_BITS ? "w" : ""),
@@ -137,24 +139,26 @@ int main() {
     pico_partition_t p;
     while (pico_partitions_next(&pt, &p)) {
         printf("%3d:", pt.current_partition - 1);
-        if (pt.fields & PT_INFO_PARTITION_LOCATION_AND_FLAGS) {
-            printf("    %08x->%08x S(%s%s) NSBOOT(%s%s) NS(%s%s)",
-                   p.first_sector * 4096, p.last_sector * 4096,
-                   (p.permission & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
-                   (p.permission & PICOBIN_PARTITION_PERMISSION_S_W_BITS ? "w" : ""),
-                   (p.permission & PICOBIN_PARTITION_PERMISSION_NSBOOT_R_BITS ? "r" : ""),
-                   (p.permission & PICOBIN_PARTITION_PERMISSION_NSBOOT_W_BITS ? "w" : ""),
-                   (p.permission & PICOBIN_PARTITION_PERMISSION_NS_R_BITS ? "r" : ""),
-                   (p.permission & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""));
-        }
-        if (pt.fields & PT_INFO_PARTITION_ID) {
+        printf("    %08x->%08x S(%s%s) NSBOOT(%s%s) NS(%s%s)",
+               p.first_sector * 4096, p.last_sector * 4096,
+               (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
+               (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_W_BITS ? "w" : ""),
+               (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NSBOOT_R_BITS ? "r" : ""),
+               (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NSBOOT_W_BITS ? "w" : ""),
+               (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NS_R_BITS ? "r" : ""),
+               (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""));
+        if (p.flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_ID_BITS) {
             printf(", id=%016llx", p.partition_id);
         }
-        if (pt.fields & PT_INFO_PARTITION_NAME) {
+        if (p.flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS) {
             printf(", \"%s\"", p.name);
         }
         printf("\n");
     }
+    if (pt.status != 0) {
+        fprintf(stderr, "rom_get_partition_table_info rc=%d\n", pt.status);
+        return 1;
+    }
 
     return 0;
 }

From c5aa4c14a247c6e60868b1155490af5d58a73b91 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Sat, 22 Mar 2025 01:32:50 +0900
Subject: [PATCH 06/40] Update flash/partition_info/partition_info.c

Co-authored-by: will-v-pi <108662275+will-v-pi@users.noreply.github.com>
---
 flash/partition_info/partition_info.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 0f5b6b74c..c93632273 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -140,7 +140,7 @@ int main() {
     while (pico_partitions_next(&pt, &p)) {
         printf("%3d:", pt.current_partition - 1);
         printf("    %08x->%08x S(%s%s) NSBOOT(%s%s) NS(%s%s)",
-               p.first_sector * 4096, p.last_sector * 4096,
+               p.first_sector * 4096, (p.last_sector + 1) * 4096,
                (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
                (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_W_BITS ? "w" : ""),
                (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NSBOOT_R_BITS ? "r" : ""),

From 2496fe70cd5a575f1820e9a125e8d382f8abc460 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Sat, 22 Mar 2025 01:33:44 +0900
Subject: [PATCH 07/40] panic if the table cannot be retrieved

Co-authored-by: will-v-pi <108662275+will-v-pi@users.noreply.github.com>
---
 flash/partition_info/partition_info.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index c93632273..67679c887 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -156,8 +156,7 @@ int main() {
         printf("\n");
     }
     if (pt.status != 0) {
-        fprintf(stderr, "rom_get_partition_table_info rc=%d\n", pt.status);
-        return 1;
+        panic("rom_get_partition_table_info returned %d", pt.status);
     }
 
     return 0;

From 5681d7120dd3a216fb06189002f1eea6b8d5bddc Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Sat, 22 Mar 2025 01:34:23 +0900
Subject: [PATCH 08/40] fixed TYPO `patitions`

Co-authored-by: will-v-pi <108662275+will-v-pi@users.noreply.github.com>
---
 flash/partition_info/partition_info.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 67679c887..c04c2238e 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -135,7 +135,7 @@ int main() {
            (pt.permission & PICOBIN_PARTITION_PERMISSION_NSBOOT_W_BITS ? "w" : ""),
            (pt.permission & PICOBIN_PARTITION_PERMISSION_NS_R_BITS ? "r" : ""),
            (pt.permission & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""));
-    printf("patitions:\n");
+    printf("partitions:\n");
     pico_partition_t p;
     while (pico_partitions_next(&pt, &p)) {
         printf("%3d:", pt.current_partition - 1);

From 0f96a367d5367f128c1083c4132c837aa88a72af Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Sat, 22 Mar 2025 01:34:59 +0900
Subject: [PATCH 09/40] rename to match the partition struct

Co-authored-by: will-v-pi <108662275+will-v-pi@users.noreply.github.com>
---
 flash/partition_info/partition_info.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index c04c2238e..ffb11b79b 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -28,7 +28,7 @@ typedef struct {
     int partition_count;
     uint32_t unpartitioned_space_first_sector;
     uint32_t unpartitioned_space_last_sector;
-    uint32_t permission;
+    uint32_t flags_and_permissions;
     int current_partition;
     size_t idx;
     int status;

From 9bdba25764534f0c760d66e16c81b76641c71862 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Sat, 22 Mar 2025 01:35:24 +0900
Subject: [PATCH 10/40] remove WORD_SIZE

Co-authored-by: will-v-pi <108662275+will-v-pi@users.noreply.github.com>
---
 flash/partition_info/partition_info.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index ffb11b79b..e2144a7c3 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -101,7 +101,7 @@ bool pico_partitions_next(pico_partition_table_t *pt, pico_partition_t *p) {
 
     if (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS) {
         // Read variable length fields
-        uint32_t name_buf[(PARTITION_NAME_MAX + 1) / WORD_SIZE] = {0};
+        uint32_t name_buf[(PARTITION_NAME_MAX + 1) / sizeof(uint32_t)] = {0};
         int rc = rom_get_partition_table_info(name_buf, sizeof(name_buf),
                                               (pt->current_partition << 24 |
                                                PT_INFO_SINGLE_PARTITION |

From 7d9edfabf22d5d69aab788dd1cb8fc1d72491097 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Sat, 22 Mar 2025 01:35:42 +0900
Subject: [PATCH 11/40] update comment

Co-authored-by: will-v-pi <108662275+will-v-pi@users.noreply.github.com>
---
 flash/partition_info/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flash/partition_info/CMakeLists.txt b/flash/partition_info/CMakeLists.txt
index 6e3cbbc63..e19ed2c3f 100644
--- a/flash/partition_info/CMakeLists.txt
+++ b/flash/partition_info/CMakeLists.txt
@@ -5,7 +5,7 @@ target_link_libraries(partition_info PRIVATE
         pico_bootrom
         )
 
-# not necessary for the example functionality, but shows you how you would add a partition table
+# add a partition table
 pico_embed_pt_in_binary(partition_info ${CMAKE_CURRENT_LIST_DIR}/pt.json)
 
 # create map/bin/hex/uf2 file etc.

From 87eddeca769bb90b7b4950e85cdcca4c0beaa77d Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Sat, 22 Mar 2025 01:36:00 +0900
Subject: [PATCH 12/40] remove unused define

Co-authored-by: will-v-pi <108662275+will-v-pi@users.noreply.github.com>
---
 flash/partition_info/partition_info.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index e2144a7c3..f7c209a49 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -11,7 +11,6 @@
 
 #define PART_LOC_FIRST(x) ( ((x) & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB )
 #define PART_LOC_LAST(x)  ( ((x) & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS)  >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB )
-#define WORD_PADDED_BYTES(x)  ((x + 3) & ~3)
 
 #define WORD_SIZE  4
 #define PARTITION_LOCATION_AND_FLAGS_SIZE  2

From bbb165624f7c9b155b8703ed003e847598bcb435 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Sat, 22 Mar 2025 01:36:24 +0900
Subject: [PATCH 13/40] remove unused defined WORD_SIZE

Co-authored-by: will-v-pi <108662275+will-v-pi@users.noreply.github.com>
---
 flash/partition_info/partition_info.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index f7c209a49..805b77e27 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -12,7 +12,6 @@
 #define PART_LOC_FIRST(x) ( ((x) & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB )
 #define PART_LOC_LAST(x)  ( ((x) & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS)  >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB )
 
-#define WORD_SIZE  4
 #define PARTITION_LOCATION_AND_FLAGS_SIZE  2
 #define PARTITION_ID_SIZE                  2
 #define PARTITION_NAME_MAX                 127

From 8f3564dec8aa38c521e4aaec6608db036c41ade3 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Sat, 22 Mar 2025 01:47:59 +0900
Subject: [PATCH 14/40] Name unified to flags_and_permissions

---
 flash/partition_info/partition_info.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 805b77e27..75939212c 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -66,7 +66,7 @@ int pico_partitions_open(pico_partition_table_t *pt) {
     uint32_t location = pt->table[pos++];
     pt->unpartitioned_space_first_sector = PART_LOC_FIRST(location);
     pt->unpartitioned_space_last_sector = PART_LOC_LAST(location);
-    pt->permission = pt->table[pos++];
+    pt->flags_and_permissions = pt->table[pos++];
     pt->current_partition = 0;
     pt->idx = pos;
     pt->status = 0;
@@ -127,12 +127,12 @@ int main() {
     pico_partition_table_t pt;
     pico_partitions_open(&pt);
     printf("un-partitioned_space: S(%s%s) NSBOOT(%s%s) NS(%s%s)\n",
-           (pt.permission & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
-           (pt.permission & PICOBIN_PARTITION_PERMISSION_S_W_BITS ? "w" : ""),
-           (pt.permission & PICOBIN_PARTITION_PERMISSION_NSBOOT_R_BITS ? "r" : ""),
-           (pt.permission & PICOBIN_PARTITION_PERMISSION_NSBOOT_W_BITS ? "w" : ""),
-           (pt.permission & PICOBIN_PARTITION_PERMISSION_NS_R_BITS ? "r" : ""),
-           (pt.permission & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""));
+           (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
+           (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_W_BITS ? "w" : ""),
+           (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NSBOOT_R_BITS ? "r" : ""),
+           (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NSBOOT_W_BITS ? "w" : ""),
+           (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NS_R_BITS ? "r" : ""),
+           (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""));
     printf("partitions:\n");
     pico_partition_t p;
     while (pico_partitions_next(&pt, &p)) {

From ee6d8d6998427f365eb27193e2bace77142a810c Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Tue, 25 Mar 2025 13:06:02 +0900
Subject: [PATCH 15/40] Unify pico-sdk header file includes to ""

---
 flash/partition_info/partition_info.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 75939212c..4bb8b9dca 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -4,8 +4,8 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 #include <stdio.h>
-#include <pico/stdlib.h>
-#include <pico/bootrom.h>
+#include "pico/stdlib.h"
+#include "pico/bootrom.h"
 #include "boot/picobin.h"
 
 

From b463a69eb80177a4a926fc41b01f80bae3365766 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Tue, 25 Mar 2025 13:08:00 +0900
Subject: [PATCH 16/40] Fix typo in comment: change "Reads a fixed size fields"
 to "Reads fixed size fields"

---
 flash/partition_info/partition_info.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 4bb8b9dca..819f59b58 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -50,7 +50,7 @@ typedef struct {
  * See the RP2350 datasheet 5.1.2, 5.4.8.16 for flags and structures that can be specified.
  */
 int pico_partitions_open(pico_partition_table_t *pt) {
-    // Reads a fixed size fields
+    // Reads fixed size fields
     int rc = rom_get_partition_table_info(pt->table, sizeof(pt->table),
                                           (PT_INFO_PT_INFO |
                                            PT_INFO_PARTITION_LOCATION_AND_FLAGS |

From 555ded5357554647af54b25d4bbfad773050a016 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Tue, 25 Mar 2025 13:10:38 +0900
Subject: [PATCH 17/40] =?UTF-8?q?Rename=20the=20position=20field=20in=20th?=
 =?UTF-8?q?e=20partition=20table=20to=20=E2=80=9Cpos"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 flash/partition_info/partition_info.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 819f59b58..a7e675aed 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -28,7 +28,7 @@ typedef struct {
     uint32_t unpartitioned_space_last_sector;
     uint32_t flags_and_permissions;
     int current_partition;
-    size_t idx;
+    size_t pos;
     int status;
 } pico_partition_table_t;
 
@@ -68,7 +68,7 @@ int pico_partitions_open(pico_partition_table_t *pt) {
     pt->unpartitioned_space_last_sector = PART_LOC_LAST(location);
     pt->flags_and_permissions = pt->table[pos++];
     pt->current_partition = 0;
-    pt->idx = pos;
+    pt->pos = pos;
     pt->status = 0;
 
     return 0;
@@ -82,20 +82,20 @@ bool pico_partitions_next(pico_partition_table_t *pt, pico_partition_t *p) {
         return false;
     }
 
-    size_t idx = pt->idx;
-    uint32_t location = pt->table[idx++];
+    size_t pos = pt->pos;
+    uint32_t location = pt->table[pos++];
     p->first_sector = PART_LOC_FIRST(location);
     p->last_sector = PART_LOC_LAST(location);
-    p->flags_and_permissions = pt->table[idx++];
+    p->flags_and_permissions = pt->table[pos++];
 
     if (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_ID_BITS) {
-        uint32_t id_low  = pt->table[idx++];
-        uint32_t id_high = pt->table[idx++];
+        uint32_t id_low  = pt->table[pos++];
+        uint32_t id_high = pt->table[pos++];
         p->partition_id = ((uint64_t)id_high << 32) | id_low;
     } else {
         p->partition_id = 0;
     }
-    pt->idx = idx;
+    pt->pos = pos;
 
     if (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS) {
         // Read variable length fields

From 9bce48ccd70de01d176170808313479111be0a11 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Tue, 25 Mar 2025 13:16:16 +0900
Subject: [PATCH 18/40] Changed function names to prevent misleading as if they
 were SDK APIs.

---
 flash/partition_info/partition_info.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index a7e675aed..4e3f1faa4 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -49,7 +49,7 @@ typedef struct {
  *
  * See the RP2350 datasheet 5.1.2, 5.4.8.16 for flags and structures that can be specified.
  */
-int pico_partitions_open(pico_partition_table_t *pt) {
+int open_partition_table(pico_partition_table_t *pt) {
     // Reads fixed size fields
     int rc = rom_get_partition_table_info(pt->table, sizeof(pt->table),
                                           (PT_INFO_PT_INFO |
@@ -77,7 +77,7 @@ int pico_partitions_open(pico_partition_table_t *pt) {
 /*
  * Extract each partition information
  */
-bool pico_partitions_next(pico_partition_table_t *pt, pico_partition_t *p) {
+bool read_next_partition(pico_partition_table_t *pt, pico_partition_t *p) {
     if (pt->current_partition >= pt->partition_count) {
         return false;
     }
@@ -125,7 +125,7 @@ int main() {
     stdio_init_all();
 
     pico_partition_table_t pt;
-    pico_partitions_open(&pt);
+    open_partition_table(&pt);
     printf("un-partitioned_space: S(%s%s) NSBOOT(%s%s) NS(%s%s)\n",
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_W_BITS ? "w" : ""),
@@ -135,7 +135,7 @@ int main() {
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""));
     printf("partitions:\n");
     pico_partition_t p;
-    while (pico_partitions_next(&pt, &p)) {
+    while (read_next_partition(&pt, &p)) {
         printf("%3d:", pt.current_partition - 1);
         printf("    %08x->%08x S(%s%s) NSBOOT(%s%s) NS(%s%s)",
                p.first_sector * 4096, (p.last_sector + 1) * 4096,

From b5c2fbe57bef582d0a88b9ae938e6a504a96b70c Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Tue, 25 Mar 2025 13:21:10 +0900
Subject: [PATCH 19/40] Initialize `pt->partition_count = 0`

---
 flash/partition_info/partition_info.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 4e3f1faa4..639100d22 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -56,6 +56,7 @@ int open_partition_table(pico_partition_table_t *pt) {
                                            PT_INFO_PARTITION_LOCATION_AND_FLAGS |
                                            PT_INFO_PARTITION_ID));
     if (rc < 0) {
+        pt->partition_count = 0;
         pt->status = rc;
         return rc;
     }

From 08896229c36f988585c330312dc954e62ff50778 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Tue, 25 Mar 2025 13:35:33 +0900
Subject: [PATCH 20/40] The fields of the partition table read are added
 `assert()`

---
 flash/partition_info/partition_info.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 639100d22..6c80c5402 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -3,6 +3,7 @@
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
+#include <assert.h>
 #include <stdio.h>
 #include "pico/stdlib.h"
 #include "pico/bootrom.h"
@@ -51,10 +52,8 @@ typedef struct {
  */
 int open_partition_table(pico_partition_table_t *pt) {
     // Reads fixed size fields
-    int rc = rom_get_partition_table_info(pt->table, sizeof(pt->table),
-                                          (PT_INFO_PT_INFO |
-                                           PT_INFO_PARTITION_LOCATION_AND_FLAGS |
-                                           PT_INFO_PARTITION_ID));
+    uint32_t flags = PT_INFO_PT_INFO | PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_PARTITION_ID;
+    int rc = rom_get_partition_table_info(pt->table, sizeof(pt->table), flags);
     if (rc < 0) {
         pt->partition_count = 0;
         pt->status = rc;
@@ -63,6 +62,7 @@ int open_partition_table(pico_partition_table_t *pt) {
 
     size_t pos = 0;
     pt->fields = pt->table[pos++];
+    assert(pt->fields == flags);
     pt->partition_count = pt->table[pos++] & 0x000000FF;
     uint32_t location = pt->table[pos++];
     pt->unpartitioned_space_first_sector = PART_LOC_FIRST(location);
@@ -101,15 +101,15 @@ bool read_next_partition(pico_partition_table_t *pt, pico_partition_t *p) {
     if (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS) {
         // Read variable length fields
         uint32_t name_buf[(PARTITION_NAME_MAX + 1) / sizeof(uint32_t)] = {0};
+        uint32_t flags = PT_INFO_SINGLE_PARTITION | PT_INFO_PARTITION_NAME;
         int rc = rom_get_partition_table_info(name_buf, sizeof(name_buf),
-                                              (pt->current_partition << 24 |
-                                               PT_INFO_SINGLE_PARTITION |
-                                               PT_INFO_PARTITION_NAME));
+                                              (pt->current_partition << 24 | flags));
         if (rc < 0) {
             pt->status = rc;
             return false;
         }
         uint32_t __attribute__((unused)) fields = name_buf[0];
+        assert(fields == flags);
         uint8_t *name_buf_u8 = (uint8_t *)&name_buf[1];
         uint8_t name_length = *name_buf_u8++;
         memcpy(p->name, name_buf_u8, name_length);

From 8dd6b0ee841082e892465486ff229ca81a5bce4d Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Wed, 26 Mar 2025 15:26:12 +0900
Subject: [PATCH 21/40] Check the return code of `open_partition_table`

---
 flash/partition_info/partition_info.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 6c80c5402..9d9a9a972 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -126,7 +126,12 @@ int main() {
     stdio_init_all();
 
     pico_partition_table_t pt;
-    open_partition_table(&pt);
+    int rc;
+    rc = open_partition_table(&pt);
+    if (rc != 0) {
+        panic("rom_get_partition_table_info returned %d", pt.status);
+    }
+
     printf("un-partitioned_space: S(%s%s) NSBOOT(%s%s) NS(%s%s)\n",
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_W_BITS ? "w" : ""),

From b53dfbc95d04ce0fe78b60da86cda76c07f54dea Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Wed, 26 Mar 2025 15:27:52 +0900
Subject: [PATCH 22/40] Define and use SECTOR_SIZE

---
 flash/partition_info/partition_info.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 9d9a9a972..7665aa4ed 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -17,6 +17,7 @@
 #define PARTITION_ID_SIZE                  2
 #define PARTITION_NAME_MAX                 127
 #define PARTITION_TABLE_FIXED_INFO_SIZE    (4 + PARTITION_TABLE_MAX_PARTITIONS * (PARTITION_LOCATION_AND_FLAGS_SIZE + PARTITION_ID_SIZE))
+#define SECTOR_SIZE 4096
 
 /*
  * Stores partition table information and data read status
@@ -144,7 +145,7 @@ int main() {
     while (read_next_partition(&pt, &p)) {
         printf("%3d:", pt.current_partition - 1);
         printf("    %08x->%08x S(%s%s) NSBOOT(%s%s) NS(%s%s)",
-               p.first_sector * 4096, (p.last_sector + 1) * 4096,
+               p.first_sector * SECTOR_SIZE, (p.last_sector + 1) * SECTOR_SIZE,
                (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
                (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_W_BITS ? "w" : ""),
                (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NSBOOT_R_BITS ? "r" : ""),

From 4822ae37e8ae9e6c94b6bf6bdd430ca0044d4727 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Wed, 26 Mar 2025 15:30:01 +0900
Subject: [PATCH 23/40] Fix partition name work buffer length

---
 flash/partition_info/partition_info.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 7665aa4ed..12ed1f5e8 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -101,7 +101,7 @@ bool read_next_partition(pico_partition_table_t *pt, pico_partition_t *p) {
 
     if (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS) {
         // Read variable length fields
-        uint32_t name_buf[(PARTITION_NAME_MAX + 1) / sizeof(uint32_t)] = {0};
+        uint32_t name_buf[((PARTITION_NAME_MAX + 1) / sizeof(uint32_t)) + 1] = {0};
         uint32_t flags = PT_INFO_SINGLE_PARTITION | PT_INFO_PARTITION_NAME;
         int rc = rom_get_partition_table_info(name_buf, sizeof(name_buf),
                                               (pt->current_partition << 24 | flags));

From c5fd635eef3794ea4f66a7ec04f55870b2661cd9 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Wed, 26 Mar 2025 15:32:35 +0900
Subject: [PATCH 24/40] Mask the first bit of the partition name length field

---
 flash/partition_info/partition_info.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 12ed1f5e8..92c66ee8f 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -112,7 +112,7 @@ bool read_next_partition(pico_partition_table_t *pt, pico_partition_t *p) {
         uint32_t __attribute__((unused)) fields = name_buf[0];
         assert(fields == flags);
         uint8_t *name_buf_u8 = (uint8_t *)&name_buf[1];
-        uint8_t name_length = *name_buf_u8++;
+        uint8_t name_length = *name_buf_u8++ & 0x7F;
         memcpy(p->name, name_buf_u8, name_length);
         p->name[name_length] = '\0';
     } else {

From c88a23c2ecfda77cd977f9849a447aefbb200812 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Wed, 26 Mar 2025 15:47:57 +0900
Subject: [PATCH 25/40] Add `has_partition` flag

---
 flash/partition_info/partition_info.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 92c66ee8f..0b341b2ce 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -25,6 +25,7 @@
 typedef struct {
     uint32_t table[PARTITION_TABLE_FIXED_INFO_SIZE];
     uint32_t fields;
+    bool has_partition;
     int partition_count;
     uint32_t unpartitioned_space_first_sector;
     uint32_t unpartitioned_space_last_sector;
@@ -64,7 +65,9 @@ int open_partition_table(pico_partition_table_t *pt) {
     size_t pos = 0;
     pt->fields = pt->table[pos++];
     assert(pt->fields == flags);
-    pt->partition_count = pt->table[pos++] & 0x000000FF;
+    pt->partition_count = pt->table[pos] & 0x000000FF;
+    pt->has_partition = pt->table[pos] & 0x00000100;
+    pos++;
     uint32_t location = pt->table[pos++];
     pt->unpartitioned_space_first_sector = PART_LOC_FIRST(location);
     pt->unpartitioned_space_last_sector = PART_LOC_LAST(location);
@@ -132,7 +135,11 @@ int main() {
     if (rc != 0) {
         panic("rom_get_partition_table_info returned %d", pt.status);
     }
-
+    if (!pt.has_partition) {
+        printf("there is no partition table\n");
+    } else if (pt.partition_count == 0) {
+        printf("the partition table is empty\n");
+    }
     printf("un-partitioned_space: S(%s%s) NSBOOT(%s%s) NS(%s%s)\n",
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_W_BITS ? "w" : ""),
@@ -140,6 +147,7 @@ int main() {
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NSBOOT_W_BITS ? "w" : ""),
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NS_R_BITS ? "r" : ""),
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""));
+
     printf("partitions:\n");
     pico_partition_t p;
     while (read_next_partition(&pt, &p)) {

From 869bf750add72df72fd13166586bf651966bd466 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Wed, 26 Mar 2025 18:22:06 +0900
Subject: [PATCH 26/40] rename `open_partition_table` to `read_partition_table`

---
 flash/partition_info/partition_info.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 0b341b2ce..903108c91 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -52,7 +52,7 @@ typedef struct {
  *
  * See the RP2350 datasheet 5.1.2, 5.4.8.16 for flags and structures that can be specified.
  */
-int open_partition_table(pico_partition_table_t *pt) {
+int read_partition_table(pico_partition_table_t *pt) {
     // Reads fixed size fields
     uint32_t flags = PT_INFO_PT_INFO | PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_PARTITION_ID;
     int rc = rom_get_partition_table_info(pt->table, sizeof(pt->table), flags);
@@ -131,7 +131,7 @@ int main() {
 
     pico_partition_table_t pt;
     int rc;
-    rc = open_partition_table(&pt);
+    rc = read_partition_table(&pt);
     if (rc != 0) {
         panic("rom_get_partition_table_info returned %d", pt.status);
     }

From 4005c6f1fc49f3b43de0e92ee694b543c0b80781 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Wed, 26 Mar 2025 18:26:15 +0900
Subject: [PATCH 27/40] Use the predefined `FLASH_SECTOR_SIZE`

---
 flash/partition_info/CMakeLists.txt   | 1 +
 flash/partition_info/partition_info.c | 5 ++---
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/flash/partition_info/CMakeLists.txt b/flash/partition_info/CMakeLists.txt
index e19ed2c3f..3fcf564f9 100644
--- a/flash/partition_info/CMakeLists.txt
+++ b/flash/partition_info/CMakeLists.txt
@@ -3,6 +3,7 @@ add_executable(partition_info partition_info.c)
 target_link_libraries(partition_info PRIVATE
         pico_stdlib
         pico_bootrom
+        hardware_flash
         )
 
 # add a partition table
diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 903108c91..54f3769ff 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -8,7 +8,7 @@
 #include "pico/stdlib.h"
 #include "pico/bootrom.h"
 #include "boot/picobin.h"
-
+#include "hardware/flash.h"
 
 #define PART_LOC_FIRST(x) ( ((x) & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB )
 #define PART_LOC_LAST(x)  ( ((x) & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS)  >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB )
@@ -17,7 +17,6 @@
 #define PARTITION_ID_SIZE                  2
 #define PARTITION_NAME_MAX                 127
 #define PARTITION_TABLE_FIXED_INFO_SIZE    (4 + PARTITION_TABLE_MAX_PARTITIONS * (PARTITION_LOCATION_AND_FLAGS_SIZE + PARTITION_ID_SIZE))
-#define SECTOR_SIZE 4096
 
 /*
  * Stores partition table information and data read status
@@ -153,7 +152,7 @@ int main() {
     while (read_next_partition(&pt, &p)) {
         printf("%3d:", pt.current_partition - 1);
         printf("    %08x->%08x S(%s%s) NSBOOT(%s%s) NS(%s%s)",
-               p.first_sector * SECTOR_SIZE, (p.last_sector + 1) * SECTOR_SIZE,
+               p.first_sector * FLASH_SECTOR_SIZE, (p.last_sector + 1) * FLASH_SECTOR_SIZE,
                (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
                (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_W_BITS ? "w" : ""),
                (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NSBOOT_R_BITS ? "r" : ""),

From 8d1d4679c6559ca6032d8441e041c657671f36fe Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Wed, 26 Mar 2025 18:59:38 +0900
Subject: [PATCH 28/40] rename `has_partition` to `has_partition_table`

---
 flash/partition_info/partition_info.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 54f3769ff..57ad2936b 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -24,7 +24,7 @@
 typedef struct {
     uint32_t table[PARTITION_TABLE_FIXED_INFO_SIZE];
     uint32_t fields;
-    bool has_partition;
+    bool has_partition_table;
     int partition_count;
     uint32_t unpartitioned_space_first_sector;
     uint32_t unpartitioned_space_last_sector;
@@ -65,7 +65,7 @@ int read_partition_table(pico_partition_table_t *pt) {
     pt->fields = pt->table[pos++];
     assert(pt->fields == flags);
     pt->partition_count = pt->table[pos] & 0x000000FF;
-    pt->has_partition = pt->table[pos] & 0x00000100;
+    pt->has_partition_table = pt->table[pos] & 0x00000100;
     pos++;
     uint32_t location = pt->table[pos++];
     pt->unpartitioned_space_first_sector = PART_LOC_FIRST(location);
@@ -134,7 +134,7 @@ int main() {
     if (rc != 0) {
         panic("rom_get_partition_table_info returned %d", pt.status);
     }
-    if (!pt.has_partition) {
+    if (!pt.has_partition_table) {
         printf("there is no partition table\n");
     } else if (pt.partition_count == 0) {
         printf("the partition table is empty\n");

From ce5b409fd2b2c882622f0af73fd5beb541db8bb5 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Wed, 26 Mar 2025 19:08:47 +0900
Subject: [PATCH 29/40] Skip printing empty partitions

---
 flash/partition_info/partition_info.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 57ad2936b..283e68567 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -147,6 +147,9 @@ int main() {
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NS_R_BITS ? "r" : ""),
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""));
 
+    if (pt.partition_count == 0) {
+        return 0;
+    }
     printf("partitions:\n");
     pico_partition_t p;
     while (read_next_partition(&pt, &p)) {

From d9909f97d2bfecd461411067b60ae231fdbb4e55 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Thu, 27 Mar 2025 14:25:26 +0900
Subject: [PATCH 30/40] Added printing of extra family IDs

---
 flash/partition_info/CMakeLists.txt   |  2 +-
 flash/partition_info/partition_info.c | 59 ++++++++++++++++-----
 flash/partition_info/uf2_family_ids.c | 75 +++++++++++++++++++++++++++
 flash/partition_info/uf2_family_ids.h | 23 ++++++++
 4 files changed, 145 insertions(+), 14 deletions(-)
 create mode 100644 flash/partition_info/uf2_family_ids.c
 create mode 100644 flash/partition_info/uf2_family_ids.h

diff --git a/flash/partition_info/CMakeLists.txt b/flash/partition_info/CMakeLists.txt
index 3fcf564f9..ee24d95fa 100644
--- a/flash/partition_info/CMakeLists.txt
+++ b/flash/partition_info/CMakeLists.txt
@@ -1,4 +1,4 @@
-add_executable(partition_info partition_info.c)
+add_executable(partition_info partition_info.c uf2_family_ids.c)
 
 target_link_libraries(partition_info PRIVATE
         pico_stdlib
diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 283e68567..3b9a2a536 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -9,6 +9,7 @@
 #include "pico/bootrom.h"
 #include "boot/picobin.h"
 #include "hardware/flash.h"
+#include "uf2_family_ids.h"
 
 #define PART_LOC_FIRST(x) ( ((x) & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB )
 #define PART_LOC_LAST(x)  ( ((x) & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS)  >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB )
@@ -16,6 +17,7 @@
 #define PARTITION_LOCATION_AND_FLAGS_SIZE  2
 #define PARTITION_ID_SIZE                  2
 #define PARTITION_NAME_MAX                 127
+#define PARTITION_EXTRA_FAMILY_ID_MAX      3
 #define PARTITION_TABLE_FIXED_INFO_SIZE    (4 + PARTITION_TABLE_MAX_PARTITIONS * (PARTITION_LOCATION_AND_FLAGS_SIZE + PARTITION_ID_SIZE))
 
 /*
@@ -43,6 +45,8 @@ typedef struct {
     uint32_t flags_and_permissions;
     uint64_t partition_id;
     char name[PARTITION_NAME_MAX + 1];  // name length is indicated by 7 bits
+    uint32_t extra_family_id_count;
+    uint32_t extra_family_ids[PARTITION_EXTRA_FAMILY_ID_MAX];
 } pico_partition_t;
 
 
@@ -101,25 +105,34 @@ bool read_next_partition(pico_partition_table_t *pt, pico_partition_t *p) {
     }
     pt->pos = pos;
 
-    if (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS) {
+    p->extra_family_id_count = (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_ACCEPTS_NUM_EXTRA_FAMILIES_BITS)
+                                   >> PICOBIN_PARTITION_FLAGS_ACCEPTS_NUM_EXTRA_FAMILIES_LSB;
+    if (p->extra_family_id_count | (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS)) {
         // Read variable length fields
-        uint32_t name_buf[((PARTITION_NAME_MAX + 1) / sizeof(uint32_t)) + 1] = {0};
-        uint32_t flags = PT_INFO_SINGLE_PARTITION | PT_INFO_PARTITION_NAME;
-        int rc = rom_get_partition_table_info(name_buf, sizeof(name_buf),
+        uint32_t extra_family_id_and_name[PARTITION_EXTRA_FAMILY_ID_MAX + (((PARTITION_NAME_MAX + 1) / sizeof(uint32_t)) + 1)];
+        uint32_t flags = PT_INFO_SINGLE_PARTITION | PT_INFO_PARTITION_FAMILY_IDS | PT_INFO_PARTITION_NAME;
+        int rc = rom_get_partition_table_info(extra_family_id_and_name, sizeof(extra_family_id_and_name),
                                               (pt->current_partition << 24 | flags));
         if (rc < 0) {
             pt->status = rc;
             return false;
         }
-        uint32_t __attribute__((unused)) fields = name_buf[0];
+        size_t pos = 0;
+        uint32_t __attribute__((unused)) fields = extra_family_id_and_name[pos++];
         assert(fields == flags);
-        uint8_t *name_buf_u8 = (uint8_t *)&name_buf[1];
-        uint8_t name_length = *name_buf_u8++ & 0x7F;
-        memcpy(p->name, name_buf_u8, name_length);
-        p->name[name_length] = '\0';
-    } else {
-        p->name[0] = '\0';
+        for (size_t i = 0; i < p->extra_family_id_count; i++, pos++) {
+            p->extra_family_ids[i] = extra_family_id_and_name[pos];
+        }
+
+        if (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS) {
+            uint8_t *name_buf = (uint8_t *)&extra_family_id_and_name[pos];
+            uint8_t name_length = *name_buf++ & 0x7F;
+            memcpy(p->name, name_buf, name_length);
+            p->name[name_length] = '\0';
+        }
     }
+    if (!(p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS))
+         p->name[0] = '\0';
 
     pt->current_partition++;
     return true;
@@ -139,13 +152,20 @@ int main() {
     } else if (pt.partition_count == 0) {
         printf("the partition table is empty\n");
     }
-    printf("un-partitioned_space: S(%s%s) NSBOOT(%s%s) NS(%s%s)\n",
+
+    uf2_family_ids_t *family_ids = uf2_family_ids_new();
+    uf2_family_ids_add_default_families(family_ids, pt.flags_and_permissions);
+    char *str_family_ids = uf2_family_ids_join(family_ids, ", ");
+    printf("un-partitioned_space: S(%s%s) NSBOOT(%s%s) NS(%s%s) uf2 { %s }\n",
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_W_BITS ? "w" : ""),
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NSBOOT_R_BITS ? "r" : ""),
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NSBOOT_W_BITS ? "w" : ""),
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NS_R_BITS ? "r" : ""),
-           (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""));
+           (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""),
+           str_family_ids);
+    free(str_family_ids);
+    uf2_family_ids_free(family_ids);
 
     if (pt.partition_count == 0) {
         return 0;
@@ -154,6 +174,7 @@ int main() {
     pico_partition_t p;
     while (read_next_partition(&pt, &p)) {
         printf("%3d:", pt.current_partition - 1);
+
         printf("    %08x->%08x S(%s%s) NSBOOT(%s%s) NS(%s%s)",
                p.first_sector * FLASH_SECTOR_SIZE, (p.last_sector + 1) * FLASH_SECTOR_SIZE,
                (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
@@ -168,6 +189,18 @@ int main() {
         if (p.flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS) {
             printf(", \"%s\"", p.name);
         }
+
+        // print UF2 family ID
+        family_ids = uf2_family_ids_new();
+        uf2_family_ids_add_default_families(family_ids, p.flags_and_permissions);
+        for (size_t i = 0; i < p.extra_family_id_count; i++) {
+            uf2_family_ids_add_extra_family_id(family_ids, p.extra_family_ids[i]);
+        }
+        str_family_ids = uf2_family_ids_join(family_ids, ", ");
+        printf(", uf2 { %s }", str_family_ids);
+        uf2_family_ids_free(family_ids);
+        free(str_family_ids);
+
         printf("\n");
     }
     if (pt.status != 0) {
diff --git a/flash/partition_info/uf2_family_ids.c b/flash/partition_info/uf2_family_ids.c
new file mode 100644
index 000000000..7c64fb703
--- /dev/null
+++ b/flash/partition_info/uf2_family_ids.c
@@ -0,0 +1,75 @@
+#include "uf2_family_ids.h"
+
+#define UF2_FAMILY_ID_HEX_SIZE   (2 + 8 * 2 + 1)
+
+uf2_family_ids_t *uf2_family_ids_new(void) {
+    uf2_family_ids_t *ids = malloc(sizeof(uf2_family_ids_t));
+    ids->count = 0;
+    ids->items = NULL;
+    return ids;
+}
+
+void uf2_family_ids_add(uf2_family_ids_t *ids, const char *str) {
+    ids->items = realloc(ids->items, (ids->count + 1) * sizeof(char *));
+    ids->items[ids->count] = strdup(str);
+    if (ids->items[ids->count] == NULL) {
+        perror("strdup");
+        return;
+    }
+    ids->count++;
+}
+
+char *uf2_family_ids_join(const uf2_family_ids_t *ids, const char *sep) {
+    size_t total_length = 0;
+    size_t sep_length = strlen(sep);
+
+    for (size_t i = 0; i < ids->count; i++) {
+        total_length += strlen(ids->items[i]);
+        if (i < ids->count - 1)
+            total_length += sep_length;
+    }
+
+    char *result = calloc(1, total_length + 1);
+    if (!result) {
+        perror("calloc");
+        return NULL;
+    }
+
+    result[0] = '\0';
+    for (size_t i = 0; i < ids->count; i++) {
+        strcat(result, ids->items[i]);
+        if (i < ids->count - 1)
+            strcat(result, sep);
+    }
+
+    return result;
+}
+
+void uf2_family_ids_free(uf2_family_ids_t *ids) {
+    for (size_t i = 0; i < ids->count; i++) {
+        free(ids->items[i]);
+    }
+    free(ids->items);
+    free(ids);
+}
+
+void uf2_family_ids_add_default_families(uf2_family_ids_t *ids, uint32_t flags) {
+    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_ABSOLUTE_BITS)
+        uf2_family_ids_add(ids, "absolute");
+    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2040_BITS)
+        uf2_family_ids_add(ids, "rp2040");
+    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2350_ARM_S_BITS)
+        uf2_family_ids_add(ids, "rp2350-arm-s");
+    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2350_ARM_NS_BITS)
+        uf2_family_ids_add(ids, "rp2350-arm-ns");
+    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2350_RISCV_BITS)
+        uf2_family_ids_add(ids, "rp2350-riscv");
+    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_DATA_BITS)
+        uf2_family_ids_add(ids, "data");
+}
+
+void uf2_family_ids_add_extra_family_id(uf2_family_ids_t *ids, uint32_t family_id) {
+    char hex_id[UF2_FAMILY_ID_HEX_SIZE];
+    sprintf(hex_id, "0x%08x", family_id);
+    uf2_family_ids_add(ids, hex_id);
+}
diff --git a/flash/partition_info/uf2_family_ids.h b/flash/partition_info/uf2_family_ids.h
new file mode 100644
index 000000000..d4b6ed6d0
--- /dev/null
+++ b/flash/partition_info/uf2_family_ids.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pico/stdlib.h"
+#include "boot/picobin.h"
+
+
+typedef struct {
+    size_t count;
+    char **items;
+} uf2_family_ids_t;
+
+
+uf2_family_ids_t *uf2_family_ids_new(void);
+void uf2_family_ids_add(uf2_family_ids_t *ids, const char *str);
+char *uf2_family_ids_join(const uf2_family_ids_t *ids, const char *sep);
+void uf2_family_ids_free(uf2_family_ids_t *ids);
+
+void uf2_family_ids_add_default_families(uf2_family_ids_t *ids, uint32_t flags);
+void uf2_family_ids_add_extra_family_id(uf2_family_ids_t *ids, uint32_t family_id);

From ce6dda8043dd80eddcfc82c548741ae8124da42f Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Thu, 27 Mar 2025 22:02:40 +0900
Subject: [PATCH 31/40] Add `p->has_name`

---
 flash/partition_info/partition_info.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 3b9a2a536..1056bc3af 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -44,6 +44,7 @@ typedef struct {
     uint32_t last_sector;
     uint32_t flags_and_permissions;
     uint64_t partition_id;
+    bool has_name;
     char name[PARTITION_NAME_MAX + 1];  // name length is indicated by 7 bits
     uint32_t extra_family_id_count;
     uint32_t extra_family_ids[PARTITION_EXTRA_FAMILY_ID_MAX];
@@ -107,7 +108,8 @@ bool read_next_partition(pico_partition_table_t *pt, pico_partition_t *p) {
 
     p->extra_family_id_count = (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_ACCEPTS_NUM_EXTRA_FAMILIES_BITS)
                                    >> PICOBIN_PARTITION_FLAGS_ACCEPTS_NUM_EXTRA_FAMILIES_LSB;
-    if (p->extra_family_id_count | (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS)) {
+    p->has_name = p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS;
+    if (p->extra_family_id_count | p->has_name) {
         // Read variable length fields
         uint32_t extra_family_id_and_name[PARTITION_EXTRA_FAMILY_ID_MAX + (((PARTITION_NAME_MAX + 1) / sizeof(uint32_t)) + 1)];
         uint32_t flags = PT_INFO_SINGLE_PARTITION | PT_INFO_PARTITION_FAMILY_IDS | PT_INFO_PARTITION_NAME;
@@ -124,14 +126,14 @@ bool read_next_partition(pico_partition_table_t *pt, pico_partition_t *p) {
             p->extra_family_ids[i] = extra_family_id_and_name[pos];
         }
 
-        if (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS) {
+        if (p->has_name) {
             uint8_t *name_buf = (uint8_t *)&extra_family_id_and_name[pos];
             uint8_t name_length = *name_buf++ & 0x7F;
             memcpy(p->name, name_buf, name_length);
             p->name[name_length] = '\0';
         }
     }
-    if (!(p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS))
+    if (!(p->has_name))
          p->name[0] = '\0';
 
     pt->current_partition++;

From 7edee22da0ccf99e228ca95780b2603e6256cf91 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Thu, 27 Mar 2025 22:13:21 +0900
Subject: [PATCH 32/40] Changed default_family to be registered at `new`

---
 flash/partition_info/partition_info.c |  6 ++--
 flash/partition_info/uf2_family_ids.c | 49 ++++++++++++++-------------
 flash/partition_info/uf2_family_ids.h |  4 +--
 3 files changed, 28 insertions(+), 31 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 1056bc3af..dd87dbb43 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -155,8 +155,7 @@ int main() {
         printf("the partition table is empty\n");
     }
 
-    uf2_family_ids_t *family_ids = uf2_family_ids_new();
-    uf2_family_ids_add_default_families(family_ids, pt.flags_and_permissions);
+    uf2_family_ids_t *family_ids = uf2_family_ids_new(pt.flags_and_permissions);
     char *str_family_ids = uf2_family_ids_join(family_ids, ", ");
     printf("un-partitioned_space: S(%s%s) NSBOOT(%s%s) NS(%s%s) uf2 { %s }\n",
            (pt.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_S_R_BITS ? "r" : ""),
@@ -193,8 +192,7 @@ int main() {
         }
 
         // print UF2 family ID
-        family_ids = uf2_family_ids_new();
-        uf2_family_ids_add_default_families(family_ids, p.flags_and_permissions);
+        family_ids = uf2_family_ids_new(p.flags_and_permissions);
         for (size_t i = 0; i < p.extra_family_id_count; i++) {
             uf2_family_ids_add_extra_family_id(family_ids, p.extra_family_ids[i]);
         }
diff --git a/flash/partition_info/uf2_family_ids.c b/flash/partition_info/uf2_family_ids.c
index 7c64fb703..c789e481e 100644
--- a/flash/partition_info/uf2_family_ids.c
+++ b/flash/partition_info/uf2_family_ids.c
@@ -2,14 +2,7 @@
 
 #define UF2_FAMILY_ID_HEX_SIZE   (2 + 8 * 2 + 1)
 
-uf2_family_ids_t *uf2_family_ids_new(void) {
-    uf2_family_ids_t *ids = malloc(sizeof(uf2_family_ids_t));
-    ids->count = 0;
-    ids->items = NULL;
-    return ids;
-}
-
-void uf2_family_ids_add(uf2_family_ids_t *ids, const char *str) {
+static void _add(uf2_family_ids_t *ids, const char *str) {
     ids->items = realloc(ids->items, (ids->count + 1) * sizeof(char *));
     ids->items[ids->count] = strdup(str);
     if (ids->items[ids->count] == NULL) {
@@ -19,6 +12,29 @@ void uf2_family_ids_add(uf2_family_ids_t *ids, const char *str) {
     ids->count++;
 }
 
+static void _add_default_families(uf2_family_ids_t *ids, uint32_t flags) {
+    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_ABSOLUTE_BITS)
+        _add(ids, "absolute");
+    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2040_BITS)
+        _add(ids, "rp2040");
+    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2350_ARM_S_BITS)
+        _add(ids, "rp2350-arm-s");
+    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2350_ARM_NS_BITS)
+        _add(ids, "rp2350-arm-ns");
+    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2350_RISCV_BITS)
+        _add(ids, "rp2350-riscv");
+    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_DATA_BITS)
+        _add(ids, "data");
+}
+
+uf2_family_ids_t *uf2_family_ids_new(uint32_t flags) {
+    uf2_family_ids_t *ids = malloc(sizeof(uf2_family_ids_t));
+    ids->count = 0;
+    ids->items = NULL;
+    _add_default_families(ids, flags);
+    return ids;
+}
+
 char *uf2_family_ids_join(const uf2_family_ids_t *ids, const char *sep) {
     size_t total_length = 0;
     size_t sep_length = strlen(sep);
@@ -53,23 +69,8 @@ void uf2_family_ids_free(uf2_family_ids_t *ids) {
     free(ids);
 }
 
-void uf2_family_ids_add_default_families(uf2_family_ids_t *ids, uint32_t flags) {
-    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_ABSOLUTE_BITS)
-        uf2_family_ids_add(ids, "absolute");
-    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2040_BITS)
-        uf2_family_ids_add(ids, "rp2040");
-    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2350_ARM_S_BITS)
-        uf2_family_ids_add(ids, "rp2350-arm-s");
-    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2350_ARM_NS_BITS)
-        uf2_family_ids_add(ids, "rp2350-arm-ns");
-    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_RP2350_RISCV_BITS)
-        uf2_family_ids_add(ids, "rp2350-riscv");
-    if (flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_DEFAULT_FAMILY_DATA_BITS)
-        uf2_family_ids_add(ids, "data");
-}
-
 void uf2_family_ids_add_extra_family_id(uf2_family_ids_t *ids, uint32_t family_id) {
     char hex_id[UF2_FAMILY_ID_HEX_SIZE];
     sprintf(hex_id, "0x%08x", family_id);
-    uf2_family_ids_add(ids, hex_id);
+    _add(ids, hex_id);
 }
diff --git a/flash/partition_info/uf2_family_ids.h b/flash/partition_info/uf2_family_ids.h
index d4b6ed6d0..d052cc1dc 100644
--- a/flash/partition_info/uf2_family_ids.h
+++ b/flash/partition_info/uf2_family_ids.h
@@ -14,10 +14,8 @@ typedef struct {
 } uf2_family_ids_t;
 
 
-uf2_family_ids_t *uf2_family_ids_new(void);
-void uf2_family_ids_add(uf2_family_ids_t *ids, const char *str);
+uf2_family_ids_t *uf2_family_ids_new(uint32_t flags);
 char *uf2_family_ids_join(const uf2_family_ids_t *ids, const char *sep);
 void uf2_family_ids_free(uf2_family_ids_t *ids);
 
-void uf2_family_ids_add_default_families(uf2_family_ids_t *ids, uint32_t flags);
 void uf2_family_ids_add_extra_family_id(uf2_family_ids_t *ids, uint32_t family_id);

From 1066f756aa9b2bb693dcb086ba2765b50b9d837c Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Thu, 27 Mar 2025 22:18:16 +0900
Subject: [PATCH 33/40] Unify alloc/free hierarchy

---
 flash/partition_info/partition_info.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index dd87dbb43..bd44447d3 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -198,8 +198,8 @@ int main() {
         }
         str_family_ids = uf2_family_ids_join(family_ids, ", ");
         printf(", uf2 { %s }", str_family_ids);
-        uf2_family_ids_free(family_ids);
         free(str_family_ids);
+        uf2_family_ids_free(family_ids);
 
         printf("\n");
     }

From b11896119d4ca10c23d952570d08b163db95fb8e Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Thu, 27 Mar 2025 22:21:56 +0900
Subject: [PATCH 34/40] Move `PARTITION_EXTRA_FAMILY_ID_MAX` to
 uf2_family_ids.h

---
 flash/partition_info/partition_info.c | 1 -
 flash/partition_info/uf2_family_ids.h | 2 ++
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index bd44447d3..f6a7435cf 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -17,7 +17,6 @@
 #define PARTITION_LOCATION_AND_FLAGS_SIZE  2
 #define PARTITION_ID_SIZE                  2
 #define PARTITION_NAME_MAX                 127
-#define PARTITION_EXTRA_FAMILY_ID_MAX      3
 #define PARTITION_TABLE_FIXED_INFO_SIZE    (4 + PARTITION_TABLE_MAX_PARTITIONS * (PARTITION_LOCATION_AND_FLAGS_SIZE + PARTITION_ID_SIZE))
 
 /*
diff --git a/flash/partition_info/uf2_family_ids.h b/flash/partition_info/uf2_family_ids.h
index d052cc1dc..7b6423715 100644
--- a/flash/partition_info/uf2_family_ids.h
+++ b/flash/partition_info/uf2_family_ids.h
@@ -8,6 +8,8 @@
 #include "boot/picobin.h"
 
 
+#define PARTITION_EXTRA_FAMILY_ID_MAX      3
+
 typedef struct {
     size_t count;
     char **items;

From c37dcbef0e2d572defd330dffff1b5e259c89143 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Thu, 27 Mar 2025 22:29:39 +0900
Subject: [PATCH 35/40] Change `pos` to `pos_` in the block to avoid conflicts

---
 flash/partition_info/partition_info.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index f6a7435cf..b8a4ce9bb 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -118,15 +118,15 @@ bool read_next_partition(pico_partition_table_t *pt, pico_partition_t *p) {
             pt->status = rc;
             return false;
         }
-        size_t pos = 0;
-        uint32_t __attribute__((unused)) fields = extra_family_id_and_name[pos++];
+        size_t pos_ = 0;
+        uint32_t __attribute__((unused)) fields = extra_family_id_and_name[pos_++];
         assert(fields == flags);
-        for (size_t i = 0; i < p->extra_family_id_count; i++, pos++) {
-            p->extra_family_ids[i] = extra_family_id_and_name[pos];
+        for (size_t i = 0; i < p->extra_family_id_count; i++, pos_++) {
+            p->extra_family_ids[i] = extra_family_id_and_name[pos_];
         }
 
         if (p->has_name) {
-            uint8_t *name_buf = (uint8_t *)&extra_family_id_and_name[pos];
+            uint8_t *name_buf = (uint8_t *)&extra_family_id_and_name[pos_];
             uint8_t name_length = *name_buf++ & 0x7F;
             memcpy(p->name, name_buf, name_length);
             p->name[name_length] = '\0';

From 9c19b3c8a86417b2713205329fb8d88a3a1c8bcc Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Thu, 27 Mar 2025 22:32:09 +0900
Subject: [PATCH 36/40] Fixed typo from `extra_family_id_and_name` to
 `extra_family_ids_and_name`

---
 flash/partition_info/partition_info.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index b8a4ce9bb..92cf0ea9d 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -110,23 +110,23 @@ bool read_next_partition(pico_partition_table_t *pt, pico_partition_t *p) {
     p->has_name = p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS;
     if (p->extra_family_id_count | p->has_name) {
         // Read variable length fields
-        uint32_t extra_family_id_and_name[PARTITION_EXTRA_FAMILY_ID_MAX + (((PARTITION_NAME_MAX + 1) / sizeof(uint32_t)) + 1)];
+        uint32_t extra_family_ids_and_name[PARTITION_EXTRA_FAMILY_ID_MAX + (((PARTITION_NAME_MAX + 1) / sizeof(uint32_t)) + 1)];
         uint32_t flags = PT_INFO_SINGLE_PARTITION | PT_INFO_PARTITION_FAMILY_IDS | PT_INFO_PARTITION_NAME;
-        int rc = rom_get_partition_table_info(extra_family_id_and_name, sizeof(extra_family_id_and_name),
+        int rc = rom_get_partition_table_info(extra_family_ids_and_name, sizeof(extra_family_ids_and_name),
                                               (pt->current_partition << 24 | flags));
         if (rc < 0) {
             pt->status = rc;
             return false;
         }
         size_t pos_ = 0;
-        uint32_t __attribute__((unused)) fields = extra_family_id_and_name[pos_++];
+        uint32_t __attribute__((unused)) fields = extra_family_ids_and_name[pos_++];
         assert(fields == flags);
         for (size_t i = 0; i < p->extra_family_id_count; i++, pos_++) {
-            p->extra_family_ids[i] = extra_family_id_and_name[pos_];
+            p->extra_family_ids[i] = extra_family_ids_and_name[pos_];
         }
 
         if (p->has_name) {
-            uint8_t *name_buf = (uint8_t *)&extra_family_id_and_name[pos_];
+            uint8_t *name_buf = (uint8_t *)&extra_family_ids_and_name[pos_];
             uint8_t name_length = *name_buf++ & 0x7F;
             memcpy(p->name, name_buf, name_length);
             p->name[name_length] = '\0';

From cda403ee1b2252be95cb4c44af65d87a42d3f761 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Fri, 28 Mar 2025 02:36:40 +0900
Subject: [PATCH 37/40] Removed redundant brackets

---
 flash/partition_info/partition_info.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 92cf0ea9d..83b901c99 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -132,7 +132,7 @@ bool read_next_partition(pico_partition_table_t *pt, pico_partition_t *p) {
             p->name[name_length] = '\0';
         }
     }
-    if (!(p->has_name))
+    if (!p->has_name)
          p->name[0] = '\0';
 
     pt->current_partition++;

From a0e81bd197c1d897b69bd19f98e432e79ec4b186 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Fri, 28 Mar 2025 10:34:42 +0900
Subject: [PATCH 38/40] Move comment for `PARTITION_NAME_MAX`

---
 flash/partition_info/partition_info.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 83b901c99..19983611f 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -16,7 +16,7 @@
 
 #define PARTITION_LOCATION_AND_FLAGS_SIZE  2
 #define PARTITION_ID_SIZE                  2
-#define PARTITION_NAME_MAX                 127
+#define PARTITION_NAME_MAX                 127  // name length is indicated by 7 bits
 #define PARTITION_TABLE_FIXED_INFO_SIZE    (4 + PARTITION_TABLE_MAX_PARTITIONS * (PARTITION_LOCATION_AND_FLAGS_SIZE + PARTITION_ID_SIZE))
 
 /*
@@ -44,7 +44,7 @@ typedef struct {
     uint32_t flags_and_permissions;
     uint64_t partition_id;
     bool has_name;
-    char name[PARTITION_NAME_MAX + 1];  // name length is indicated by 7 bits
+    char name[PARTITION_NAME_MAX + 1];
     uint32_t extra_family_id_count;
     uint32_t extra_family_ids[PARTITION_EXTRA_FAMILY_ID_MAX];
 } pico_partition_t;

From ff8d2b4970e9035d71f3bd0e90b1cb282ee6339c Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Fri, 28 Mar 2025 10:44:42 +0900
Subject: [PATCH 39/40] Utilize `p->has_name`. Add `p->has_id`

---
 flash/partition_info/partition_info.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/flash/partition_info/partition_info.c b/flash/partition_info/partition_info.c
index 19983611f..9691ad3a9 100644
--- a/flash/partition_info/partition_info.c
+++ b/flash/partition_info/partition_info.c
@@ -42,6 +42,7 @@ typedef struct {
     uint32_t first_sector;
     uint32_t last_sector;
     uint32_t flags_and_permissions;
+    bool has_id;
     uint64_t partition_id;
     bool has_name;
     char name[PARTITION_NAME_MAX + 1];
@@ -95,8 +96,10 @@ bool read_next_partition(pico_partition_table_t *pt, pico_partition_t *p) {
     p->first_sector = PART_LOC_FIRST(location);
     p->last_sector = PART_LOC_LAST(location);
     p->flags_and_permissions = pt->table[pos++];
+    p->has_name = p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS;
+    p->has_id = p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_ID_BITS;
 
-    if (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_ID_BITS) {
+    if (p->has_id) {
         uint32_t id_low  = pt->table[pos++];
         uint32_t id_high = pt->table[pos++];
         p->partition_id = ((uint64_t)id_high << 32) | id_low;
@@ -107,7 +110,6 @@ bool read_next_partition(pico_partition_table_t *pt, pico_partition_t *p) {
 
     p->extra_family_id_count = (p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_ACCEPTS_NUM_EXTRA_FAMILIES_BITS)
                                    >> PICOBIN_PARTITION_FLAGS_ACCEPTS_NUM_EXTRA_FAMILIES_LSB;
-    p->has_name = p->flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS;
     if (p->extra_family_id_count | p->has_name) {
         // Read variable length fields
         uint32_t extra_family_ids_and_name[PARTITION_EXTRA_FAMILY_ID_MAX + (((PARTITION_NAME_MAX + 1) / sizeof(uint32_t)) + 1)];
@@ -183,10 +185,10 @@ int main() {
                (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NSBOOT_W_BITS ? "w" : ""),
                (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NS_R_BITS ? "r" : ""),
                (p.flags_and_permissions & PICOBIN_PARTITION_PERMISSION_NS_W_BITS ? "w" : ""));
-        if (p.flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_ID_BITS) {
+        if (p.has_id) {
             printf(", id=%016llx", p.partition_id);
         }
-        if (p.flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS) {
+        if (p.has_name) {
             printf(", \"%s\"", p.name);
         }
 

From 9eb7c332b786e247807722a758690c03f50b01b7 Mon Sep 17 00:00:00 2001
From: Hiroyuki OYAMA <oyama@module.jp>
Date: Fri, 28 Mar 2025 10:53:19 +0900
Subject: [PATCH 40/40] Add sample extra family id to `pt.json`

---
 flash/partition_info/pt.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flash/partition_info/pt.json b/flash/partition_info/pt.json
index b3ea9ac90..ae68abac7 100644
--- a/flash/partition_info/pt.json
+++ b/flash/partition_info/pt.json
@@ -14,7 +14,7 @@
       "id": 1,
       "start": 0,
       "size": "512K",
-      "families": ["rp2350-arm-ns", "rp2350-arm-s", "rp2350-riscv"],
+      "families": ["rp2350-arm-ns", "rp2350-arm-s", "rp2350-riscv", "0x12345678"],
       "permissions": {
         "secure": "rw",
         "nonsecure": "rw",