Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
240 changes: 129 additions & 111 deletions src/rp2_common/hardware_rcp/include/hardware/rcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@
*/

// ----------------------------------------------------------------------------
// RCP masks
#if !PICO_RP2040
// RCP instructions (this header is Arm-only)
#if HAS_REDUNDANCY_COPROCESSOR
#ifdef __riscv
#error "HAS_REDUNDANCY_COPROCESSOR should be false on RISC-V"
#endif

#define rcp_is_true(x) ((x) == RCP_MASK_TRUE)
#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__
Expand Down Expand Up @@ -86,6 +88,7 @@ static __rcpinline void rcp_salt_core1_nodelay(uint64_t salt) {

// Get a 32-bit canary value. `tag` must be a constant expression.
#define rcp_canary_get(tag) ({ \
static_assert(!((tag) & ~0xffu), "Tag out of range"); \
uint32_t __canary_u32; \
rcp_asm ( \
"mrc p7, #0, %0, c%c1, c%c2, #1\n" \
Expand All @@ -96,6 +99,7 @@ static __rcpinline void rcp_salt_core1_nodelay(uint64_t salt) {
})

#define rcp_canary_get_nodelay(tag) ({ \
static_assert(!((tag) & ~0xffu), "Tag out of range"); \
uint32_t __canary_u32; \
rcp_asm ( \
"mrc2 p7, #0, %0, c%c1, c%c2, #1\n" \
Expand All @@ -107,6 +111,7 @@ static __rcpinline void rcp_salt_core1_nodelay(uint64_t salt) {

// Assert that canary matches result of rcp_canary_get with the same tags:
#define rcp_canary_check(tag, canary) ({ \
static_assert(!((tag) & ~0xffu), "Tag out of range"); \
rcp_asm ( \
"mcr p7, #0, %0, c%c1, c%c2, #1\n" \
: : "r" (canary), \
Expand All @@ -115,6 +120,7 @@ static __rcpinline void rcp_salt_core1_nodelay(uint64_t salt) {
})

#define rcp_canary_check_nodelay(tag, canary) ({ \
static_assert(!((tag) & ~0xffu), "Tag out of range"); \
rcp_asm ( \
"mcr2 p7, #0, %0, c%c1, c%c2, #1\n" \
: : "r" (canary), \
Expand All @@ -141,6 +147,9 @@ static __rcpinline uint32_t rcp_canary_status_nodelay(void) {
// ----------------------------------------------------------------------------
// RCP Boolean instructions

// These instructions assert that all their arguments are valid booleans, in
// addition to any other logical conditions

// Assert b is a valid boolean (0xa500a500u or 0x00c300c3u)
static __rcpinline void rcp_bvalid(uint32_t b) {
rcp_asm ("mcr p7, #1, %0, c0, c0, #0\n" : : "r" (b));
Expand Down Expand Up @@ -308,106 +317,8 @@ static __rcpinline __attribute__((noreturn)) void rcp_panic(void) {
#else // __ASSEMBLER__
#ifndef __riscv

// Assert b is a valid boolean (0xa500a500u or 0x00c300c3u)
.macro rcp_bvalid r
mcr p7, #1, \r , c0, c0, #0
.endm

.macro rcp_bvalid_nodelay r
mcr2 p7, #1, \r , c0, c0, #0
.endm

// Assert b is true (0xa500a500u)
.macro rcp_btrue r
mcr p7, #2, \r , c0, c0, #0
.endm

.macro rcp_btrue_nodelay r
mcr2 p7, #2, \r , c0, c0, #0
.endm

// Assert b is false (0x00c300c3u)
.macro rcp_bfalse r
mcr p7, #3, \r , c0, c0, #1
.endm

.macro rcp_bfalse_nodelay r
mcr2 p7, #3, \r , c0, c0, #1
.endm

// Assert b0 and b1 are both valid booleans
.macro rcp_b2valid b0, b1
mcrr p7, #0, \b0 , \b1 , c8
.endm

.macro rcp_b2valid_nodelay b0, b1
mcrr2 p7, #0, \b0 , \b1 , c8
.endm

// Assert b0 and b1 are both true
.macro rcp_b2and b0, b1
mcrr p7, #1, \b0 , \b1 , c0
.endm

.macro rcp_b2and_nodelay b0, b1
mcrr2 p7, #1, \b0 , \b1 , c0
.endm

// Assert b0 and b1 are valid, and at least one is true
.macro rcp_b2or b0, b1
mcrr p7, #2, \b0 , \b1 , c0
.endm

.macro rcp_b2or_nodelay b0, b1
mcrr2 p7, #2, \b0 , \b1 , c0
.endm

// Assert (b ^ mask) is a valid boolean
.macro rcp_bxorvalid b, mask
mcrr p7, #3, \b , \mask , c8
.endm

.macro rcp_bxorvalid_nodelay b, mask
mcrr2 p7, #3, \b , \mask , c8
.endm

// Assert (b ^ mask) is true
.macro rcp_bxortrue b, mask
mcrr p7, #4, \b , \mask , c0
.endm

.macro rcp_bxortrue_nodelay b, mask
mcrr2 p7, #4, \b , \mask , c0
.endm

// Assert (b ^ mask) is false
.macro rcp_bxorfalse b, mask
mcrr p7, #5, \b , \mask , c8
.endm

.macro rcp_bxorfalse_nodelay b, mask
mcrr2 p7, #5, \b , \mask , c8
.endm

// Assert (x ^ parity) == 0x96009600u
.macro rcp_ivalid x, parity
mcrr p7, #6, \x , \parity , c8
.endm

.macro rcp_ivalid_nodelay x, parity
mcrr2 p7, #6, \x , \parity , c8
.endm

// Assert x == y
.macro rcp_iequal x, y
mcrr p7, #7, \x , \y , c0
.endm

.macro rcp_iequal_nodelay x, y
mcrr2 p7, #7, \x , \y , c0
.endm

// They call this "metaprogramming" I think
// Meta-macro for evaluating assembler constant expressions and encoding as
// coprocessor register pairs:
.macro rcp_switch_u8_to_ch_cl macro_name, x, args:vararg
.if (\x) == 0
\macro_name c0, c0, \args
Expand Down Expand Up @@ -926,6 +837,114 @@ static __rcpinline __attribute__((noreturn)) void rcp_panic(void) {
.endif
.endm

// ----------------------------------------------------------------------------
// RCP Boolean instructions

// Assert b is a valid boolean (0xa500a500u or 0x00c300c3u)
.macro rcp_bvalid r
mcr p7, #1, \r , c0, c0, #0
.endm

.macro rcp_bvalid_nodelay r
mcr2 p7, #1, \r , c0, c0, #0
.endm

// Assert b is true (0xa500a500u)
.macro rcp_btrue r
mcr p7, #2, \r , c0, c0, #0
.endm

.macro rcp_btrue_nodelay r
mcr2 p7, #2, \r , c0, c0, #0
.endm

// Assert b is false (0x00c300c3u)
.macro rcp_bfalse r
mcr p7, #3, \r , c0, c0, #1
.endm

.macro rcp_bfalse_nodelay r
mcr2 p7, #3, \r , c0, c0, #1
.endm

// Assert b0 and b1 are both valid booleans
.macro rcp_b2valid b0, b1
mcrr p7, #0, \b0 , \b1 , c8
.endm

.macro rcp_b2valid_nodelay b0, b1
mcrr2 p7, #0, \b0 , \b1 , c8
.endm

// Assert b0 and b1 are both true
.macro rcp_b2and b0, b1
mcrr p7, #1, \b0 , \b1 , c0
.endm

.macro rcp_b2and_nodelay b0, b1
mcrr2 p7, #1, \b0 , \b1 , c0
.endm

// Assert b0 and b1 are valid, and at least one is true
.macro rcp_b2or b0, b1
mcrr p7, #2, \b0 , \b1 , c0
.endm

.macro rcp_b2or_nodelay b0, b1
mcrr2 p7, #2, \b0 , \b1 , c0
.endm

// Assert (b ^ mask) is a valid boolean
.macro rcp_bxorvalid b, mask
mcrr p7, #3, \b , \mask , c8
.endm

.macro rcp_bxorvalid_nodelay b, mask
mcrr2 p7, #3, \b , \mask , c8
.endm

// Assert (b ^ mask) is true
.macro rcp_bxortrue b, mask
mcrr p7, #4, \b , \mask , c0
.endm

.macro rcp_bxortrue_nodelay b, mask
mcrr2 p7, #4, \b , \mask , c0
.endm

// Assert (b ^ mask) is false
.macro rcp_bxorfalse b, mask
mcrr p7, #5, \b , \mask , c8
.endm

.macro rcp_bxorfalse_nodelay b, mask
mcrr2 p7, #5, \b , \mask , c8
.endm

// ----------------------------------------------------------------------------
// RCP Integer instructions

// Assert (x ^ parity) == 0x96009600u
.macro rcp_ivalid x, parity
mcrr p7, #6, \x , \parity , c8
.endm

.macro rcp_ivalid_nodelay x, parity
mcrr2 p7, #6, \x , \parity , c8
.endm

// Assert x == y
.macro rcp_iequal x, y
mcrr p7, #7, \x , \y , c0
.endm

.macro rcp_iequal_nodelay x, y
mcrr2 p7, #7, \x , \y , c0
.endm

// ----------------------------------------------------------------------------
// RCP Sequence count instructions

// Directly write 8-bit constant expression cnt to the sequence counter.
.macro rcp_count_set_impl h, l
mcr p7, #4, r0, \h , \l , #0
Expand Down Expand Up @@ -957,20 +976,20 @@ rcp_switch_u8_to_ch_cl rcp_count_check_impl, \cnt
rcp_switch_u8_to_ch_cl rcp_count_check_nodelay_impl, \cnt
.endm

// ----------------------------------------------------------------------------
// RCP Canary instructions

// Get a 32-bit canary value. `tag` must be a constant expression.
.macro rcp_canary_get_impl h, l, x
mrc p7, #0, \x, \h, \l, #1
.endm

.macro rcp_canary_get x, tag
rcp_switch_u8_to_ch_cl rcp_canary_get_impl \tag, \x
.endm

// Get a 32-bit canary value. `tag` must be a constant expression.
.macro rcp_canary_get_nodelay_impl h, l, x
mrc2 p7, #0, \x, \h, \l, #1
.endm

.macro rcp_canary_get_nodelay x, tag
rcp_switch_u8_to_ch_cl rcp_canary_get_nodelay_impl \tag, \x
.endm
Expand All @@ -979,15 +998,13 @@ rcp_switch_u8_to_ch_cl rcp_canary_get_nodelay_impl \tag, \x
.macro rcp_canary_check_impl h, l, x
mcr p7, #0, \x, \h, \l, #1
.endm

.macro rcp_canary_check x, tag
rcp_switch_u8_to_ch_cl rcp_canary_check_impl \tag, \x
.endm

.macro rcp_canary_check_nodelay_impl h, l, x
mcr2 p7, #0, \x, \h, \l, #1
.endm

.macro rcp_canary_check_nodelay x, tag
rcp_switch_u8_to_ch_cl rcp_canary_check_nodelay_impl \tag, \x
.endm
Expand All @@ -996,13 +1013,14 @@ rcp_switch_u8_to_ch_cl rcp_canary_check_nodelay_impl \tag, \x
cdp p7, #0, c0, c0, c0, #1
.endm

#endif // HAS_REDUNDANCY_COPROCESSOR
#endif // !PICO_RP2040
#endif // !__riscv
#endif // __ASSEMBLER__
// ----------------------------------------------------------------------------

#ifdef __cplusplus
}
#endif
#else
#define rcp_is_true(x) ((int32_t)(x) < 0)
#endif
#endif
2 changes: 1 addition & 1 deletion src/rp2_common/pico_bootrom/bootrom.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ int rom_pick_ab_update_partition(uint32_t *workarea_base, uint32_t workarea_size

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) {
if (!rcp_is_true(IMAGE_DEF_VERIFIED(workarea_base))) {
// Chosen partition failed verification
return BOOTROM_ERROR_NOT_FOUND;
}
Expand Down
Loading