mirror of
https://github.com/raspberrypi/pico-sdk.git
synced 2025-12-10 07:14:36 +01:00
Add rom_pick_ab_update_partition function (#2182)
This commit is contained in:
parent
332eb5345b
commit
bbb94e51f9
6 changed files with 136 additions and 3 deletions
|
|
@ -19,6 +19,7 @@ alias(
|
|||
"//src/rp2_common/boot_bootrom_headers:__pkg__",
|
||||
"//src/rp2_common/hardware_boot_lock:__pkg__",
|
||||
"//src/rp2_common/pico_flash:__pkg__",
|
||||
"//src/rp2_common/hardware_rcp:__pkg__",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,19 @@ load("//bazel:defs.bzl", "compatible_with_rp2")
|
|||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
# Picotool needs this (transitively through
|
||||
# //src/rp2_common/pico_bootrom:pico_bootrom_headers), so we can't strictly
|
||||
# constrain compatibility.
|
||||
cc_library(
|
||||
name = "hardware_rcp_headers",
|
||||
hdrs = ["include/hardware/rcp.h"],
|
||||
includes = ["include"],
|
||||
visibility = ["//src/rp2_common/pico_bootrom:__pkg__"],
|
||||
deps = [
|
||||
"//src:pico_platform_internal",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "hardware_rcp",
|
||||
hdrs = ["include/hardware/rcp.h"],
|
||||
|
|
|
|||
|
|
@ -15,13 +15,15 @@
|
|||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// RCP instructions (this header is Arm-only)
|
||||
#if defined(PICO_RP2350) && !defined(__riscv)
|
||||
// RCP masks
|
||||
#if !PICO_RP2040
|
||||
|
||||
#define RCP_MASK_TRUE _u(0xa500a500)
|
||||
#define RCP_MASK_FALSE _u(0x00c300c3)
|
||||
#define RCP_MASK_INTXOR _u(0x96009600)
|
||||
|
||||
// RCP instructions (these instructions are Arm-only)
|
||||
#if HAS_REDUNDANCY_COPROCESSOR
|
||||
// ----------------------------------------------------------------------------
|
||||
// Macros and inline functions for use in C files
|
||||
#ifndef __ASSEMBLER__
|
||||
|
|
@ -994,7 +996,8 @@ rcp_switch_u8_to_ch_cl rcp_canary_check_nodelay_impl \tag, \x
|
|||
cdp p7, #0, c0, c0, c0, #1
|
||||
.endm
|
||||
|
||||
#endif // !__riscv
|
||||
#endif // HAS_REDUNDANCY_COPROCESSOR
|
||||
#endif // !PICO_RP2040
|
||||
#endif // __ASSEMBLER__
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ cc_library(
|
|||
"//src/rp2_common/boot_bootrom_headers",
|
||||
"//src/rp2_common/hardware_boot_lock:hardware_boot_lock_headers",
|
||||
"//src/rp2_common/pico_flash:pico_flash_headers",
|
||||
"//src/rp2_common/hardware_rcp:hardware_rcp_headers",
|
||||
] + select({
|
||||
"//bazel/constraint:host": ["//src/host/hardware_sync"],
|
||||
"//conditions:default": ["//src/rp2_common/hardware_sync"],
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
#include "pico/bootrom.h"
|
||||
#include "boot/picoboot.h"
|
||||
#include "boot/picobin.h"
|
||||
#if !PICO_RP2040
|
||||
#include "hardware/rcp.h"
|
||||
#endif
|
||||
|
||||
/// \tag::table_lookup[]
|
||||
|
||||
|
|
@ -108,4 +111,89 @@ int rom_add_flash_runtime_partition(uint32_t start_offset, uint32_t size, uint32
|
|||
}
|
||||
return PICO_ERROR_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
int rom_pick_ab_update_partition(uint32_t *workarea_base, uint32_t workarea_size, uint partition_a_num) {
|
||||
#if PICO_RP2350
|
||||
// Generated from adding the following code into the bootrom
|
||||
// scan_workarea_t* scan_workarea = (scan_workarea_t*)workarea;
|
||||
// printf("VERSION_DOWNGRADE_ERASE_ADDR %08x\n", &(always->zero_init.version_downgrade_erase_flash_addr));
|
||||
// printf("TBYB_FLAG_ADDR %08x\n", &(always->zero_init.tbyb_flag_flash_addr));
|
||||
// printf("IMAGE_DEF_VERIFIED %08x\n", (uint32_t)&(scan_workarea->parsed_block_loops[0].image_def.core.verified) - (uint32_t)scan_workarea);
|
||||
// printf("IMAGE_DEF_TBYB_FLAGGED %08x\n", (uint32_t)&(scan_workarea->parsed_block_loops[0].image_def.core.tbyb_flagged) - (uint32_t)scan_workarea);
|
||||
// printf("IMAGE_DEF_BASE %08x\n", (uint32_t)&(scan_workarea->parsed_block_loops[0].image_def.core.enclosing_window.base) - (uint32_t)scan_workarea);
|
||||
// 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);
|
||||
#define VERSION_DOWNGRADE_ERASE_ADDR *(uint32_t*)0x400e0338
|
||||
#define TBYB_FLAG_ADDR *(uint32_t*)0x400e0348
|
||||
#define IMAGE_DEF_VERIFIED(scan_workarea) *(uint32_t*)(0x64 + (uint32_t)scan_workarea)
|
||||
#define IMAGE_DEF_TBYB_FLAGGED(scan_workarea) *(bool*)(0x4c + (uint32_t)scan_workarea)
|
||||
#define IMAGE_DEF_BASE(scan_workarea) *(uint32_t*)(0x54 + (uint32_t)scan_workarea)
|
||||
#define IMAGE_DEF_REL_BLOCK_OFFSET(scan_workarea) *(uint32_t*)(0x5c + (uint32_t)scan_workarea)
|
||||
#else
|
||||
// Prevent linting errors
|
||||
#define VERSION_DOWNGRADE_ERASE_ADDR *(uint32_t*)NULL
|
||||
#define TBYB_FLAG_ADDR *(uint32_t*)NULL
|
||||
#define IMAGE_DEF_VERIFIED(scan_workarea) *(uint32_t*)(NULL + (uint32_t)scan_workarea)
|
||||
#define IMAGE_DEF_TBYB_FLAGGED(scan_workarea) *(bool*)(NULL + (uint32_t)scan_workarea)
|
||||
#define IMAGE_DEF_BASE(scan_workarea) *(uint32_t*)(NULL + (uint32_t)scan_workarea)
|
||||
#define IMAGE_DEF_REL_BLOCK_OFFSET(scan_workarea) *(uint32_t*)(NULL + (uint32_t)scan_workarea)
|
||||
|
||||
panic_unsupported();
|
||||
#endif
|
||||
|
||||
uint32_t flash_update_base = 0;
|
||||
bool tbyb_boot = false;
|
||||
uint32_t saved_erase_addr = 0;
|
||||
if (rom_get_last_boot_type() == BOOT_TYPE_FLASH_UPDATE) {
|
||||
// For a flash update boot, get the flash update base
|
||||
boot_info_t boot_info = {};
|
||||
int ret = rom_get_boot_info(&boot_info);
|
||||
if (ret) {
|
||||
flash_update_base = boot_info.reboot_params[0];
|
||||
if (boot_info.tbyb_and_update_info & BOOT_TBYB_AND_UPDATE_FLAG_BUY_PENDING) {
|
||||
// A buy is pending, so the main software has not been bought
|
||||
tbyb_boot = true;
|
||||
// Save the erase address, as this will be overwritten by rom_pick_ab_partition
|
||||
saved_erase_addr = VERSION_DOWNGRADE_ERASE_ADDR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int rc = rom_pick_ab_partition((uint8_t*)workarea_base, workarea_size, partition_a_num, flash_update_base);
|
||||
|
||||
if (IMAGE_DEF_VERIFIED(workarea_base) != RCP_MASK_TRUE) {
|
||||
// Chosen partition failed verification
|
||||
return BOOTROM_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (IMAGE_DEF_TBYB_FLAGGED(workarea_base)) {
|
||||
// The chosen partition is TBYB
|
||||
if (tbyb_boot) {
|
||||
// The boot partition is also TBYB - cannot update both, so prioritise boot partition
|
||||
// Restore the erase address saved earlier
|
||||
VERSION_DOWNGRADE_ERASE_ADDR = saved_erase_addr;
|
||||
return BOOTROM_ERROR_NOT_PERMITTED;
|
||||
} else {
|
||||
// Update the tbyb flash address, so that explicit_buy will clear the flag for the chosen partition
|
||||
TBYB_FLAG_ADDR =
|
||||
IMAGE_DEF_BASE(workarea_base)
|
||||
+ IMAGE_DEF_REL_BLOCK_OFFSET(workarea_base) + 4;
|
||||
}
|
||||
} else {
|
||||
// The chosen partition is not TBYB
|
||||
if (tbyb_boot && saved_erase_addr) {
|
||||
// The boot partition was TBYB, and requires an erase
|
||||
if (VERSION_DOWNGRADE_ERASE_ADDR) {
|
||||
// But both the chosen partition requires an erase too
|
||||
// As before, prioritise the boot partition, and restore it's saved erase_address
|
||||
VERSION_DOWNGRADE_ERASE_ADDR = saved_erase_addr;
|
||||
return BOOTROM_ERROR_NOT_PERMITTED;
|
||||
} else {
|
||||
// The chosen partition doesn't require an erase, so we're fine
|
||||
VERSION_DOWNGRADE_ERASE_ADDR = saved_erase_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -749,6 +749,9 @@ static inline int rom_load_partition_table(uint8_t *workarea_base, uint32_t work
|
|||
*
|
||||
* NOTE: This method does not look at owner partitions, only the A partition passed and it's corresponding B partition.
|
||||
*
|
||||
* NOTE: You should not call this method directly when performing a Flash Update Boot before calling `explicit_buy`, as it may prevent
|
||||
* any version downgrade from occuring - instead \see rom_pick_ab_update_partition() which wraps this function.
|
||||
*
|
||||
* \param workarea_base base address of work area
|
||||
* \param workarea_size size of work area
|
||||
* \param partition_a_num the A partition of the pair
|
||||
|
|
@ -1091,6 +1094,30 @@ static inline int rom_get_last_boot_type(void) {
|
|||
*/
|
||||
int rom_add_flash_runtime_partition(uint32_t start_offset, uint32_t size, uint32_t permissions);
|
||||
|
||||
/*! \brief Pick A/B partition without disturbing any in progress update or TBYB boot
|
||||
* \ingroup pico_bootrom
|
||||
*
|
||||
* This will call `rom_pick_ab_partition` using the `flash_update_boot_window_base` from the current boot, while performing extra checks to prevent disrupting
|
||||
* a main image TBYB boot. It requires the same minimum workarea size as `rom_pick_ab_partition`.
|
||||
* \see rom_pick_ab_partition()
|
||||
*
|
||||
* For example, if an `explicit_buy` is pending then calling `pick_ab_partition` would normally clear the saved flash erase address for the version downgrade,
|
||||
* so the required erase of the other partition would not occur when `explicit_buy` is called - this function saves and restores that address to prevent this
|
||||
* issue, and returns `BOOTROM_ERROR_NOT_PERMITTED` if the partition chosen by `pick_ab_partition` also requires a flash erase version downgrade (as you can't
|
||||
* erase 2 partitions with one `explicit_buy` call).
|
||||
*
|
||||
* It also checks that the chosen partition contained a valid image (e.g. a signed image when using secure boot), and returns `BOOTROM_ERROR_NOT_FOUND`
|
||||
* if it does not.
|
||||
*
|
||||
* \param workarea_base base address of work area
|
||||
* \param workarea_size size of work area
|
||||
* \param partition_a_num the A partition of the pair
|
||||
* \return >= 0 the partition number picked
|
||||
* BOOTROM_ERROR_NOT_PERMITTED if not possible to do an update correctly, e.g. if both main image and data image are TBYB
|
||||
* BOOTROM_ERROR_NOT_FOUND if the chosen partition failed verification
|
||||
*/
|
||||
int rom_pick_ab_update_partition(uint32_t *workarea_base, uint32_t workarea_size, uint partition_a_num);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue