Skip to content

Commit a4d28d2

Browse files
committed
Add rom_pick_ab_update_partition function
1 parent f3459a4 commit a4d28d2

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

src/rp2_common/pico_bootrom/bootrom.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
#include "pico/bootrom.h"
88
#include "boot/picoboot.h"
99
#include "boot/picobin.h"
10+
#if !PICO_RP2040
11+
#include "hardware/rcp.h"
12+
#endif
1013

1114
/// \tag::table_lookup[]
1215

@@ -64,6 +67,23 @@ void __attribute__((noreturn)) rom_reset_usb_boot(uint32_t usb_activity_gpio_pin
6467
}
6568

6669
#if !PICO_RP2040
70+
71+
72+
// Generated from adding the following code into the bootrom
73+
// scan_workarea_t* scan_workarea = (scan_workarea_t*)workarea;
74+
// printf("VERSION_DOWNGRADE_ERASE_ADDR %08x\n", &(always->zero_init.version_downgrade_erase_flash_addr));
75+
// printf("TBYB_FLAG_ADDR %08x\n", &(always->zero_init.tbyb_flag_flash_addr));
76+
// printf("IMAGE_DEF_VERIFIED %08x\n", (uint32_t)&(scan_workarea->parsed_block_loops[0].image_def.core.verified) - (uint32_t)scan_workarea);
77+
// printf("IMAGE_DEF_TBYB_FLAGGED %08x\n", (uint32_t)&(scan_workarea->parsed_block_loops[0].image_def.core.tbyb_flagged) - (uint32_t)scan_workarea);
78+
// printf("IMAGE_DEF_BASE %08x\n", (uint32_t)&(scan_workarea->parsed_block_loops[0].image_def.core.enclosing_window.base) - (uint32_t)scan_workarea);
79+
// printf("IMAGE_DEF_REL_BLOCK_OFFSET %08x\n", (uint32_t)&(scan_workarea->parsed_block_loops[0].image_def.core.window_rel_block_offset) - (uint32_t)scan_workarea);
80+
#define VERSION_DOWNGRADE_ERASE_ADDR *(uint32_t*)0x400e0338
81+
#define TBYB_FLAG_ADDR *(uint32_t*)0x400e0348
82+
#define IMAGE_DEF_VERIFIED(scan_workarea) *(uint32_t*)(0x64 + (uint32_t)scan_workarea)
83+
#define IMAGE_DEF_TBYB_FLAGGED(scan_workarea) *(uint32_t*)(0x4c + (uint32_t)scan_workarea)
84+
#define IMAGE_DEF_BASE(scan_workarea) *(uint32_t*)(0x54 + (uint32_t)scan_workarea)
85+
#define IMAGE_DEF_REL_BLOCK_OFFSET(scan_workarea) *(uint32_t*)(0x5c + (uint32_t)scan_workarea)
86+
6787
bool rom_get_boot_random(uint32_t out[4]) {
6888
uint32_t result[5];
6989
rom_get_sys_info_fn func = (rom_get_sys_info_fn) rom_func_lookup_inline(ROM_FUNC_GET_SYS_INFO);
@@ -104,4 +124,62 @@ int rom_add_flash_runtime_partition(uint32_t start_offset, uint32_t size, uint32
104124
}
105125
return PICO_ERROR_INSUFFICIENT_RESOURCES;
106126
}
127+
128+
int rom_pick_ab_update_partition(uint32_t *workarea_base, uint32_t workarea_size, uint partition_a_num) {
129+
uint32_t flash_update_base = 0;
130+
bool tbyb_boot = false;
131+
uint32_t saved_erase_addr = 0;
132+
if (rom_get_last_boot_type() == BOOT_TYPE_FLASH_UPDATE) {
133+
// For a flash update boot, get the flash update base
134+
boot_info_t boot_info = {};
135+
int ret = rom_get_boot_info(&boot_info);
136+
if (ret) {
137+
flash_update_base = boot_info.reboot_params[0];
138+
if (boot_info.tbyb_and_update_info & BOOT_TBYB_AND_UPDATE_FLAG_BUY_PENDING) {
139+
// A buy is pending, so the main software has not been bought
140+
tbyb_boot = true;
141+
// Save the erase address, as this will be overwritten by rom_pick_ab_partition
142+
saved_erase_addr = VERSION_DOWNGRADE_ERASE_ADDR;
143+
}
144+
}
145+
}
146+
147+
int rc = rom_pick_ab_partition((uint8_t*)workarea_base, workarea_size, partition_a_num, flash_update_base);
148+
149+
if (IMAGE_DEF_VERIFIED(workarea_base) != RCP_MASK_TRUE) {
150+
// Chosen partition failed verification
151+
return BOOTROM_ERROR_NOT_FOUND;
152+
}
153+
154+
if (IMAGE_DEF_TBYB_FLAGGED(workarea_base)) {
155+
// The chosen partition is TBYB
156+
if (tbyb_boot) {
157+
// The boot partition is also TBYB - cannot update both, so prioritise boot partition
158+
// Restore the erase address saved earlier
159+
VERSION_DOWNGRADE_ERASE_ADDR = saved_erase_addr;
160+
return BOOTROM_ERROR_NOT_PERMITTED;
161+
} else {
162+
// Update the tbyb flash address, so that explicit_buy will clear the flag for the chosen partition
163+
TBYB_FLAG_ADDR =
164+
IMAGE_DEF_BASE(workarea_base)
165+
+ IMAGE_DEF_REL_BLOCK_OFFSET(workarea_base) + 4;
166+
}
167+
} else {
168+
// The chosen partition is not TBYB
169+
if (tbyb_boot && saved_erase_addr) {
170+
// The boot partition was TBYB, and requires an erase
171+
if (VERSION_DOWNGRADE_ERASE_ADDR) {
172+
// But both the chosen partition requires an erase too
173+
// As before, prioritise the boot partition, and restore it's saved erase_address
174+
VERSION_DOWNGRADE_ERASE_ADDR = saved_erase_addr;
175+
return BOOTROM_ERROR_NOT_PERMITTED;
176+
} else {
177+
// The chosen partition doesn't require an erase, so we're fine
178+
VERSION_DOWNGRADE_ERASE_ADDR = saved_erase_addr;
179+
}
180+
}
181+
}
182+
183+
return rc;
184+
}
107185
#endif

src/rp2_common/pico_bootrom/include/pico/bootrom.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,22 @@ static inline int rom_get_last_boot_type(void) {
10461046
*/
10471047
int rom_add_flash_runtime_partition(uint32_t start_offset, uint32_t size, uint32_t permissions);
10481048

1049+
/*! \brief Pick A/B partition for a separate partition
1050+
* \ingroup pico_bootrom
1051+
*
1052+
* This will perform extra checks to prevent disrupting a main image TBYB, and return errors
1053+
*
1054+
* Also checks that the chosen partition contained a valid image
1055+
*
1056+
* \param workarea_base base address of work area
1057+
* \param workarea_size size of work area
1058+
* @param partition_a_num the A partition of the pair
1059+
* @return >= 0 the partition number picked
1060+
* BOOTROM_ERROR_NOT_PERMITTED if not possible to do an update correctly, eg if both main image and data image are TBYB
1061+
* BOOTROM_ERROR_NOT_FOUND if the chosen partition failed verification
1062+
*/
1063+
int rom_pick_ab_update_partition(uint32_t *workarea_base, uint32_t workarea_size, uint partition_a_num);
1064+
10491065
#endif
10501066

10511067
#ifdef __cplusplus

0 commit comments

Comments
 (0)