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.
This commit is contained in:
bunnie 2025-10-04 00:51:25 +08:00
parent 2175ea60f1
commit 869da85ef7
5 changed files with 194 additions and 99 deletions

View file

@ -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<u32> {
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<u32> for $name {
type Error = ();
fn try_from(value: u32) -> Result<Self, Self::Error> {
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;

View file

@ -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;

View file

@ -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<u32> {
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<u32> for $name {
type Error = ();
fn try_from(value: u32) -> Result<Self, Self::Error> {
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;

View file

@ -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;

View file

@ -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) }
}