From 869da85ef78e877d723ed6053d21dbc021fefd89 Mon Sep 17 00:00:00 2001 From: bunnie Date: Sat, 4 Oct 2025 00:51:25 +0800 Subject: [PATCH] add swap descriptors as structures; add offsets for boards In the API layer, the boards aren't setup with convenience flags. they are all laid out and the caller needs to know which board it's trying to resolve. This is because the API layer is agnostic to board and assumes the tool working with it knows what board it's working with already. The HAL layer tries to hide the board-specific stuff, and so API defines are re-imported there in a board-transparent fashion. Also add swap descriptors to the API crate, so that the image generation tools can refer to the exact same structures as are used inside the code, simplifying image creation maintenance. --- libs/bao1x-api/src/offsets.rs | 103 ++------------------------- libs/bao1x-api/src/offsets/baosec.rs | 33 +++++++++ libs/bao1x-api/src/offsets/common.rs | 98 +++++++++++++++++++++++++ libs/bao1x-api/src/offsets/dabao.rs | 24 +++++++ libs/bao1x-api/src/signatures.rs | 35 +++++++++ 5 files changed, 194 insertions(+), 99 deletions(-) create mode 100644 libs/bao1x-api/src/offsets/baosec.rs create mode 100644 libs/bao1x-api/src/offsets/common.rs create mode 100644 libs/bao1x-api/src/offsets/dabao.rs diff --git a/libs/bao1x-api/src/offsets.rs b/libs/bao1x-api/src/offsets.rs index 829c0e049..c26db0326 100644 --- a/libs/bao1x-api/src/offsets.rs +++ b/libs/bao1x-api/src/offsets.rs @@ -1,99 +1,4 @@ -// These define the start region of the partition. In general, each partition has signature -// metadata in them, but the first word in the signature is a jump instruction that takes you -// to the actual boot code. -pub const BOOT0_START: usize = 0x6000_0000; -pub const BOOT1_START: usize = 0x6002_0000; -pub const LOADER_START: usize = 0x6006_0000; -pub const BAREMETAL_START: usize = LOADER_START; -// kernel needs to start on a page boundary, so eat into the loader area a bit to allow that to happen. -pub const KERNEL_START: usize = 0x6008_0000 - crate::signatures::SIGBLOCK_LEN; - -// total storage area available in RRAM. Above this are reserved vectors for security apparatus. -pub const RRAM_STORAGE_LEN: usize = 0x3D_A000; - -// loadable apps all "start" at this address for UF2 updates -// however these are remapped into external flash based on a defragmentation table -// and app ID. The app ID also has to get encoded into this offset, likely to be -// stuck in bits 24-27, to give up to 16 app slots of up to 8MiB in size. -pub const APP_START_UF2: usize = 0x7000_0000; - -// Define a trait with just the offset -pub trait OneWayEncoding: TryFrom { - const OFFSET: usize; -} - -macro_rules! encode_oneway { - ( - #[offset = $offset:literal] - $(#[$meta:meta])* - pub enum $name:ident { - $( - $variant:ident - ),* $(,)? - } - ) => { - $(#[$meta])* - #[repr(u32)] - #[derive(Debug, Clone, Copy, PartialEq)] - pub enum $name { - $( - $variant - ),* - } - - impl $name { - const ALL: &'static [Self] = &[ - $(Self::$variant),* - ]; - } - - impl TryFrom for $name { - type Error = (); - - fn try_from(value: u32) -> Result { - let index = (value % Self::ALL.len() as u32) as usize; - Ok(Self::ALL[index]) - } - } - - impl OneWayEncoding for $name { - const OFFSET: usize = $offset; - } - }; -} - -encode_oneway! { - #[offset = 80] - pub enum BootWaitCoding { - Disable, - Enable, - } -} - -encode_oneway! { - #[offset = 81] - pub enum BoardTypeCoding { - Baosec, - Dabao, - Oem, - } -} - -encode_oneway! { - #[offset = 82] - pub enum AltBootCoding { - PrimaryPartition, - AlternatePartition, - } -} - -pub const PUBKEY_SLOTS: usize = 4; -/// Offset in the one-way counter array for loader key revocations. Provisions for up to four -/// key slots, from [116..=120]. -pub const LOADER_REVOCATION_OFFSET: usize = 116; -/// Offset in the one-way counter array for boot1 key revocations. Provisions for up to four -/// key slots, from [120..=123]. -pub const BOOT1_REVOCATION_OFFSET: usize = LOADER_REVOCATION_OFFSET + PUBKEY_SLOTS; -/// Offset in the one-way counter array for boot0 key revocations. Provisions for up to four -/// key slots, from [124..=127]. -pub const BOOT0_REVOCATION_OFFSET: usize = BOOT1_REVOCATION_OFFSET + PUBKEY_SLOTS; +pub mod baosec; +pub mod common; +pub use common::*; +pub mod dabao; diff --git a/libs/bao1x-api/src/offsets/baosec.rs b/libs/bao1x-api/src/offsets/baosec.rs new file mode 100644 index 000000000..af6787183 --- /dev/null +++ b/libs/bao1x-api/src/offsets/baosec.rs @@ -0,0 +1,33 @@ +// we actually have 16MiB on the initial prototypes, but constraining to smaller for cost reduction +pub const SPI_FLASH_LEN: usize = 8192 * 1024; +pub const SPI_FLASH_ID_MASK: u32 = 0xff_ff_ff; +// density 18, memory type 20, mfg ID C2 ==> MX25L128833F +// density 38, memory type 25, mfg ID C2 ==> MX25U12832F +// mfg ID 0b ==> XT25Q64FWOIGT cost down option (8MiB) +pub const SPI_FLASH_IDS: [u32; 3] = [0x1820c2, 0x3825c2, 0x17_60_0b]; + +// details of the SPINOR device +pub const SPINOR_PAGE_LEN: u32 = 0x100; +pub const SPINOR_ERASE_SIZE: u32 = 0x1000; // this is the smallest sector size. +pub const SPINOR_BULK_ERASE_SIZE: u32 = 0x1_0000; // this is the bulk erase size. + +// 4MiB vs 8MiB memory price is a very nominal difference (~$0.20 off of $2.40 budgetary) +// So it's either all-or-nothing: either we have 8MiB, or we have none, in the final +// configuration. +pub const SWAP_RAM_LEN: usize = 8192 * 1024; +pub const SWAP_RAM_ID_MASK: u32 = 0xff_ff; +// KGD 5D, mfg ID 9D; remainder of bits are part of the EID +pub const SWAP_RAM_IDS: [u32; 2] = [0x5d9d, 0x559d]; + +// "Partition table" of external SPI FLASH +pub const SWAP_FLASH_ORIGIN: usize = 0x0000_0000; +pub const SWAP_FLASH_RESERVED_LEN: usize = 4096 * 1024; + +// PDDB takes up "the rest of the space" - about 4MiB envisioned. Should be +// "enough" for storing a few hundred, passwords, dozens of x.509 certs, dozens of private keys, etc. +pub const PDDB_ORIGIN: usize = SWAP_FLASH_ORIGIN + SWAP_FLASH_RESERVED_LEN; +pub const PDDB_LEN: usize = SPI_FLASH_LEN - PDDB_ORIGIN; + +// Location of on-chip application segment, as offset from RRAM start +pub const APP_RRAM_OFFSET: usize = 0; +pub const APP_RRAM_LEN: usize = 0; diff --git a/libs/bao1x-api/src/offsets/common.rs b/libs/bao1x-api/src/offsets/common.rs new file mode 100644 index 000000000..78111976d --- /dev/null +++ b/libs/bao1x-api/src/offsets/common.rs @@ -0,0 +1,98 @@ +// These define the start region of the partition. In general, each partition has signature +// metadata in them, but the first word in the signature is a jump instruction that takes you +// to the actual boot code. +pub const BOOT0_START: usize = 0x6000_0000; +pub const BOOT1_START: usize = 0x6002_0000; +pub const LOADER_START: usize = 0x6006_0000; +pub const BAREMETAL_START: usize = LOADER_START; +// kernel needs to start on a page boundary, so eat into the loader area a bit to allow that to happen. +pub const KERNEL_START: usize = 0x6008_0000 - crate::signatures::SIGBLOCK_LEN; + +// total storage area available in RRAM. Above this are reserved vectors for security apparatus. +pub const RRAM_STORAGE_LEN: usize = 0x3D_A000; + +// loadable swap "starts" at these address for UF2 updates. They are are interpreted as +// zero-offsets from their respective "partitions" after masking for the top address location. +pub const SWAP_START_UF2: usize = 0x7000_0000; +pub const SWAP_UF2_LEN: usize = 0x0800_0000; // 128 MiB + +// Define a trait with just the offset +pub trait OneWayEncoding: TryFrom { + const OFFSET: usize; +} + +macro_rules! encode_oneway { + ( + #[offset = $offset:literal] + $(#[$meta:meta])* + pub enum $name:ident { + $( + $variant:ident + ),* $(,)? + } + ) => { + $(#[$meta])* + #[repr(u32)] + #[derive(Debug, Clone, Copy, PartialEq)] + pub enum $name { + $( + $variant + ),* + } + + impl $name { + const ALL: &'static [Self] = &[ + $(Self::$variant),* + ]; + } + + impl TryFrom for $name { + type Error = (); + + fn try_from(value: u32) -> Result { + let index = (value % Self::ALL.len() as u32) as usize; + Ok(Self::ALL[index]) + } + } + + impl OneWayEncoding for $name { + const OFFSET: usize = $offset; + } + }; +} + +encode_oneway! { + #[offset = 80] + pub enum BootWaitCoding { + Disable, + Enable, + } +} + +encode_oneway! { + #[offset = 81] + pub enum BoardTypeCoding { + Baosec, + Dabao, + Oem, + } +} + +encode_oneway! { + #[offset = 82] + pub enum AltBootCoding { + PrimaryPartition, + AlternatePartition, + } +} + +pub const PUBKEY_SLOTS: usize = 4; +/// Offset in the one-way counter array for loader key revocations. Provisions for up to four +/// key slots, from [116..=120]. +pub const LOADER_REVOCATION_OFFSET: usize = 116; +/// Offset in the one-way counter array for boot1 key revocations. Provisions for up to four +/// key slots, from [120..=123]. +pub const BOOT1_REVOCATION_OFFSET: usize = LOADER_REVOCATION_OFFSET + PUBKEY_SLOTS; +/// Offset in the one-way counter array for boot0 key revocations. Provisions for up to four +/// key slots, from [124..=127]. +pub const BOOT0_REVOCATION_OFFSET: usize = BOOT1_REVOCATION_OFFSET + PUBKEY_SLOTS; diff --git a/libs/bao1x-api/src/offsets/dabao.rs b/libs/bao1x-api/src/offsets/dabao.rs new file mode 100644 index 000000000..1df794854 --- /dev/null +++ b/libs/bao1x-api/src/offsets/dabao.rs @@ -0,0 +1,24 @@ +// no external SPI +pub const SPI_FLASH_LEN: usize = 0; +pub const SPI_FLASH_ID_MASK: u32 = 0xff_ff_ff; +pub const SPI_FLASH_IDS: [u32; 0] = []; + +// no external RAM +pub const SWAP_RAM_LEN: usize = 0; +pub const SWAP_RAM_ID_MASK: u32 = 0xff_ff; +// KGD 5D, mfg ID 9D; remainder of bits are part of the EID +pub const SWAP_RAM_IDS: [u32; 0] = []; + +// "Partition table" of external SPI FLASH +pub const SWAP_FLASH_ORIGIN: usize = 0x0000_0000; +pub const SWAP_FLASH_RESERVED_LEN: usize = 0; +pub const APP_FLASH_ORIGIN: usize = 0; +pub const APP_FLASH_RESERVED_LEN: usize = 0; + +// No PDDB, because no FLASH +pub const PDDB_ORIGIN: usize = 0; +pub const PDDB_LEN: usize = 0; + +// Location of on-chip application segment, as offset from RRAM start +pub const APP_RRAM_OFFSET: usize = 0x30_0000; +pub const APP_RRAM_LEN: usize = 0xD_A000; diff --git a/libs/bao1x-api/src/signatures.rs b/libs/bao1x-api/src/signatures.rs index 01fbe0460..c3b187bab 100644 --- a/libs/bao1x-api/src/signatures.rs +++ b/libs/bao1x-api/src/signatures.rs @@ -29,6 +29,9 @@ pub enum FunctionCode { /// Kernel region Kernel = 0x1_00, UpdatedKernel = 0x1_01, + /// Swap region + Swap = 0x80_00, + UpdatedSwap = 0x80_01, /// Application region App = 0x10_0000, UpdatedApp = 0x10_0001, @@ -93,3 +96,35 @@ pub struct SealedFields { impl AsRef<[u8]> for SealedFields { fn as_ref(&self) -> &[u8] { bytemuck::bytes_of(self) } } + +#[derive(Debug, Clone, Copy, Pod, Zeroable)] +#[repr(C)] +pub struct SwapSourceHeader { + pub version: u32, + pub partial_nonce: [u8; 8], + pub mac_offset: u32, + pub aad_len: u32, + // aad is limited to 64 bytes! + pub aad: [u8; 64], +} +impl AsRef<[u8]> for SwapSourceHeader { + fn as_ref(&self) -> &[u8] { bytemuck::bytes_of(self) } +} +impl Default for SwapSourceHeader { + fn default() -> Self { + Self { version: 0, partial_nonce: [0; 8], mac_offset: 0, aad_len: 0, aad: [0; 64] } + } +} + +#[repr(C)] +#[derive(Debug, Clone, Copy, Pod, Zeroable, Default)] +pub struct SwapDescriptor { + pub ram_offset: u32, + pub ram_size: u32, + pub name: u32, + pub key: [u8; 32], + pub flash_offset: u32, +} +impl AsRef<[u8]> for SwapDescriptor { + fn as_ref(&self) -> &[u8] { bytemuck::bytes_of(self) } +}