-
Notifications
You must be signed in to change notification settings - Fork 911
Add a sample to read the partition table #627
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
01001fa
a0ceb2b
d2883d1
1015067
8b87449
c5aa4c1
2496fe7
5681d71
0f96a36
9bdba25
7d9edfa
87eddec
bbb1656
8f3564d
ee6d8d6
b463a69
555ded5
9bce48c
b5c2fbe
0889622
8dd6b0e
b53dfbc
4822ae3
c5fd635
c88a23c
869bf75
4005c6f
8d1d467
ce5b409
d9909f9
ce6dda8
7edee22
1066f75
b118961
c37dcbe
9c19b3c
cda403e
a0e81bd
ff8d2b4
9eb7c33
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
add_executable(partition_info partition_info.c uf2_family_ids.c) | ||
|
||
target_link_libraries(partition_info PRIVATE | ||
pico_stdlib | ||
pico_bootrom | ||
hardware_flash | ||
) | ||
|
||
# add a partition table | ||
pico_embed_pt_in_binary(partition_info ${CMAKE_CURRENT_LIST_DIR}/pt.json) | ||
|
||
# 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) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
/** | ||
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd. | ||
* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
#include <assert.h> | ||
#include <stdio.h> | ||
#include "pico/stdlib.h" | ||
#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 ) | ||
|
||
#define PARTITION_LOCATION_AND_FLAGS_SIZE 2 | ||
#define PARTITION_ID_SIZE 2 | ||
#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)) | ||
|
||
/* | ||
* Stores partition table information and data read status | ||
*/ | ||
typedef struct { | ||
uint32_t table[PARTITION_TABLE_FIXED_INFO_SIZE]; | ||
uint32_t fields; | ||
bool has_partition_table; | ||
int partition_count; | ||
uint32_t unpartitioned_space_first_sector; | ||
uint32_t unpartitioned_space_last_sector; | ||
uint32_t flags_and_permissions; | ||
int current_partition; | ||
size_t pos; | ||
int status; | ||
} pico_partition_table_t; | ||
|
||
/* | ||
* Stores information on each partition | ||
*/ | ||
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]; | ||
uint32_t extra_family_id_count; | ||
uint32_t extra_family_ids[PARTITION_EXTRA_FAMILY_ID_MAX]; | ||
} pico_partition_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 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); | ||
if (rc < 0) { | ||
pt->partition_count = 0; | ||
pt->status = rc; | ||
oyama marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return rc; | ||
} | ||
|
||
size_t pos = 0; | ||
pt->fields = pt->table[pos++]; | ||
assert(pt->fields == flags); | ||
pt->partition_count = pt->table[pos] & 0x000000FF; | ||
pt->has_partition_table = 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); | ||
lurch marked this conversation as resolved.
Show resolved
Hide resolved
|
||
pt->flags_and_permissions = pt->table[pos++]; | ||
pt->current_partition = 0; | ||
pt->pos = pos; | ||
pt->status = 0; | ||
|
||
return 0; | ||
} | ||
|
||
/* | ||
* Extract each partition information | ||
*/ | ||
bool read_next_partition(pico_partition_table_t *pt, pico_partition_t *p) { | ||
if (pt->current_partition >= pt->partition_count) { | ||
return false; | ||
} | ||
|
||
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[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->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; | ||
} else { | ||
p->partition_id = 0; | ||
} | ||
pt->pos = pos; | ||
|
||
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->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)]; | ||
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_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_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_ids_and_name[pos_]; | ||
} | ||
|
||
if (p->has_name) { | ||
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'; | ||
} | ||
} | ||
if (!p->has_name) | ||
p->name[0] = '\0'; | ||
|
||
pt->current_partition++; | ||
return true; | ||
} | ||
|
||
int main() { | ||
stdio_init_all(); | ||
|
||
pico_partition_table_t pt; | ||
int rc; | ||
rc = read_partition_table(&pt); | ||
if (rc != 0) { | ||
panic("rom_get_partition_table_info returned %d", pt.status); | ||
} | ||
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"); | ||
} | ||
|
||
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" : ""), | ||
(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" : ""), | ||
Comment on lines
+161
to
+167
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly to how you have a function ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Haha, I was about to suggest that you could use |
||
str_family_ids); | ||
free(str_family_ids); | ||
uf2_family_ids_free(family_ids); | ||
|
||
if (pt.partition_count == 0) { | ||
return 0; | ||
} | ||
printf("partitions:\n"); | ||
lurch marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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" : ""), | ||
(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.has_id) { | ||
printf(", id=%016llx", p.partition_id); | ||
} | ||
if (p.has_name) { | ||
printf(", \"%s\"", p.name); | ||
} | ||
|
||
// print UF2 family ID | ||
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]); | ||
} | ||
str_family_ids = uf2_family_ids_join(family_ids, ", "); | ||
printf(", uf2 { %s }", str_family_ids); | ||
free(str_family_ids); | ||
uf2_family_ids_free(family_ids); | ||
|
||
printf("\n"); | ||
} | ||
if (pt.status != 0) { | ||
panic("rom_get_partition_table_info returned %d", pt.status); | ||
} | ||
|
||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
{ | ||
"version": [1, 0], | ||
"unpartitioned": { | ||
"families": ["absolute"], | ||
"permissions": { | ||
"secure": "rw", | ||
"nonsecure": "rw", | ||
"bootloader": "rw" | ||
} | ||
}, | ||
"partitions": [ | ||
{ | ||
"name": "Firmware", | ||
"id": 1, | ||
"start": 0, | ||
"size": "512K", | ||
oyama marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"families": ["rp2350-arm-ns", "rp2350-arm-s", "rp2350-riscv", "0x12345678"], | ||
"permissions": { | ||
"secure": "rw", | ||
"nonsecure": "rw", | ||
"bootloader": "rw" | ||
} | ||
}, | ||
{ | ||
"name": "Data", | ||
"id": 2, | ||
"size": "512K", | ||
"families": ["data"], | ||
"permissions": { | ||
"secure": "rw", | ||
"nonsecure": "rw", | ||
"bootloader": "rw" | ||
} | ||
}, | ||
{ | ||
"name": "Read only Data", | ||
"id": 3, | ||
"size": "512K", | ||
"families": ["data"], | ||
"permissions": { | ||
"secure": "r", | ||
"nonsecure": "r", | ||
"bootloader": "r" | ||
} | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
#include "uf2_family_ids.h" | ||
|
||
#define UF2_FAMILY_ID_HEX_SIZE (2 + 8 * 2 + 1) | ||
|
||
static void _add(uf2_family_ids_t *ids, const char *str) { | ||
ids->items = realloc(ids->items, (ids->count + 1) * sizeof(char *)); | ||
lurch marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ids->items[ids->count] = strdup(str); | ||
if (ids->items[ids->count] == NULL) { | ||
perror("strdup"); | ||
return; | ||
} | ||
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); | ||
|
||
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_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); | ||
_add(ids, hex_id); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
#pragma once | ||
|
||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
#include "pico/stdlib.h" | ||
#include "boot/picobin.h" | ||
|
||
|
||
#define PARTITION_EXTRA_FAMILY_ID_MAX 3 | ||
|
||
typedef struct { | ||
size_t count; | ||
char **items; | ||
} uf2_family_ids_t; | ||
|
||
|
||
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_extra_family_id(uf2_family_ids_t *ids, uint32_t family_id); |
Uh oh!
There was an error while loading. Please reload this page.