Skip to content

Commit

Permalink
Add support for reading out CMPA/CFPA regions
Browse files Browse the repository at this point in the history
The CMPA/CFPA regions of the RoT contain the settings for which
certificates are required for a particular device. Allow those
settings to be extracted to verify images before installing.
  • Loading branch information
labbott committed Sep 13, 2023
1 parent 8c948f4 commit 043c305
Show file tree
Hide file tree
Showing 19 changed files with 304 additions and 38 deletions.
4 changes: 3 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ zip = { version = "0.6", default-features = false, features = ["bzip2"] }

# Oxide forks and repos
dice-mfg-msgs = { git = "https://github.com/oxidecomputer/dice-util", default-features = false, version = "0.2.1" }
gateway-messages = { git = "https://github.com/oxidecomputer/management-gateway-service", default-features = false, features = ["smoltcp"] }
gateway-messages = { git = "https://github.com/oxidecomputer/management-gateway-service", default-features = false, features = ["smoltcp"], branch = "read-rot-message" }
hif = { git = "https://github.com/oxidecomputer/hif", default-features = false }
humpty = { git = "https://github.com/oxidecomputer/humpty", default-features = false, version = "0.1.3" }
hubtools = { git = "https://github.com/oxidecomputer/hubtools", default-features = false, version = "0.4.1" }
Expand Down
2 changes: 1 addition & 1 deletion app/oxide-rot-1/app-dev.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ task-slots = ["syscon_driver"]
[tasks.sprot]
name = "drv-lpc55-sprot-server"
priority = 6
max-sizes = {flash = 44384, ram = 32768}
max-sizes = {flash = 45216, ram = 32768}
uses = ["flexcomm8", "bootrom"]
features = ["spi0"]
start = true
Expand Down
2 changes: 1 addition & 1 deletion app/oxide-rot-1/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ task-slots = ["syscon_driver"]
[tasks.sprot]
name = "drv-lpc55-sprot-server"
priority = 6
max-sizes = {flash = 44384, ram = 32768}
max-sizes = {flash = 45216, ram = 32768}
uses = ["flexcomm8", "bootrom"]
features = ["spi0"]
start = true
Expand Down
2 changes: 1 addition & 1 deletion app/rot-carrier/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ task-slots = ["syscon_driver"]
[tasks.sprot]
name = "drv-lpc55-sprot-server"
priority = 6
max-sizes = {flash = 44384, ram = 32768}
max-sizes = {flash = 45216, ram = 32768}
uses = ["flexcomm8", "bootrom"]
features = ["spi0"]
start = true
Expand Down
1 change: 1 addition & 0 deletions drv/lpc55-sprot-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mutable-statics = { path = "../../lib/mutable-statics" }
ringbuf = { path = "../../lib/ringbuf" }
task-jefe-api = { path = "../../task/jefe-api" }
userlib = { path = "../../sys/userlib" }
lpc55-rom-data = { path = "../../lib/lpc55-rom-data" }

[build-dependencies]
build-lpc55pins = { path = "../../build/lpc55pins" }
Expand Down
31 changes: 29 additions & 2 deletions drv/lpc55-sprot-server/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
use crate::Trace;
use attest_api::Attest;
use crc::{Crc, CRC_32_CKSUM};
use drv_lpc55_update_api::{SlotId, Update};
use drv_lpc55_update_api::{RotPage, SlotId, Update};
use drv_sprot_api::{
AttestReq, AttestRsp, CabooseReq, CabooseRsp, DumpReq, DumpRsp, ReqBody,
Request, Response, RotIoStats, RotState, RotStatus, RspBody,
Request, Response, RotIoStats, RotPageRsp, RotState, RotStatus, RspBody,
SprocketsError, SprotError, SprotProtocolError, UpdateReq, UpdateRsp,
CURRENT_VERSION, MIN_VERSION, REQUEST_BUF_SIZE, RESPONSE_BUF_SIZE,
};
Expand Down Expand Up @@ -46,6 +46,7 @@ pub struct StartupState {
pub enum TrailingData {
Caboose { slot: SlotId, start: u32, size: u32 },
Attest { index: u32, offset: u32, size: u32 },
RotPage { page: RotPage },
}

pub struct Handler {
Expand Down Expand Up @@ -152,6 +153,22 @@ impl Handler {
}
}
}
Some(TrailingData::RotPage { page }) => {
let size: usize = lpc55_rom_data::FLASH_PAGE_SIZE;
static_assertions::const_assert!(
lpc55_rom_data::FLASH_PAGE_SIZE
<= drv_sprot_api::MAX_BLOB_SIZE
);
match Response::pack_with_cb(&rsp_body, tx_buf, |buf| {
self.update
.read_rot_page(page, &mut buf[..size])
.map_err(|e| RspBody::Page(Err(e)))?;
Ok(size)
}) {
Ok(size) => size,
Err(e) => Response::pack(&Ok(e), tx_buf),
}
}
_ => Response::pack(&rsp_body, tx_buf),
}
}
Expand Down Expand Up @@ -300,6 +317,16 @@ impl Handler {
};
Ok((RspBody::Attest(rsp), None))
}
ReqBody::RotPage { page } => {
// This command returns a variable amount of data that belongs
// in the trailing data region of the response. We return a
// marker struct with the data necessary retrieve this data so
// the work can be done elsewhere.
Ok((
RspBody::Page(Ok(RotPageRsp::RotPage)),
Some(TrailingData::RotPage { page }),
))
}
}
}
}
13 changes: 13 additions & 0 deletions drv/lpc55-update-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,19 @@ pub struct RotBootInfo {
pub slot_b_sha3_256_digest: Option<[u8; 32]>,
}

#[derive(Clone, Copy, Serialize, Deserialize, SerializedSize)]
pub enum RotPage {
// The manufacturing area that cannot be changed
Cmpa,
// The field page that is currently active (highest version)
CfpaActive,
// The field page that will be applied after the next reboot (assuming
// version is incremented)
CfpaScratch,
// The field page that is not currently active (lower version, ignoring scratch)
CfpaInactive,
}

/// Target for an update operation
///
/// This `enum` is used as part of the wire format for SP-RoT communication, and
Expand Down
89 changes: 78 additions & 11 deletions drv/lpc55-update-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ use core::convert::Infallible;
use core::mem::MaybeUninit;
use drv_lpc55_flash::BYTES_PER_FLASH_PAGE;
use drv_lpc55_update_api::{
RawCabooseError, RotBootInfo, SlotId, SwitchDuration, UpdateTarget,
RawCabooseError, RotBootInfo, RotPage, SlotId, SwitchDuration, UpdateTarget,
};
use drv_update_api::UpdateError;
use idol_runtime::{ClientError, Leased, LenLimit, RequestError, R};
use idol_runtime::{ClientError, Leased, LenLimit, RequestError, R, W};
use stage0_handoff::{
HandoffData, HandoffDataLoadError, ImageVersion, RotBootState,
};
Expand Down Expand Up @@ -69,12 +69,19 @@ const BLOCK_SIZE_BYTES: usize = BYTES_PER_FLASH_PAGE;
const MAX_LEASE: usize = 1024;
const HEADER_BLOCK: usize = 0;

const CMPA_FLASH_WORD: u32 = 0x9E40;
const CFPA_PING_FLASH_WORD: u32 = 0x9E00;
const CFPA_PONG_FLASH_WORD: u32 = 0x9E20;
const CFPA_SCRATCH_FLASH_WORD: u32 = 0x9DE0;
const CFPA_SCRATCH_FLASH_ADDR: u32 = CFPA_SCRATCH_FLASH_WORD << 4;
const BOOT_PREFERENCE_FLASH_WORD_OFFSET: u32 = 0x10;

#[derive(PartialEq)]
enum CfpaPage {
Active,
Inactive,
}

impl idl::InOrderUpdateImpl for ServerImpl<'_> {
fn prep_image_update(
&mut self,
Expand Down Expand Up @@ -325,7 +332,7 @@ impl idl::InOrderUpdateImpl for ServerImpl<'_> {
// Ping 0x9_E000 0x9E00
// Pong 0x9_E200 0x9E20
let (cfpa_word_number, _) =
self.cfpa_word_number_and_version()?;
self.cfpa_word_number_and_version(CfpaPage::Active)?;

// Read current CFPA contents.
let mut cfpa = [[0u32; 4]; 512 / 16];
Expand Down Expand Up @@ -425,11 +432,44 @@ impl idl::InOrderUpdateImpl for ServerImpl<'_> {
self.syscon.chip_reset();
panic!()
}

fn read_rot_page(
&mut self,
_: &RecvMessage,
page: RotPage,
dest: LenLimit<Leased<W, [u8]>, BYTES_PER_FLASH_PAGE>,
) -> Result<(), RequestError<UpdateError>> {
let start_addr = match page {
RotPage::Cmpa => CMPA_FLASH_WORD << 4,
RotPage::CfpaScratch => CFPA_SCRATCH_FLASH_ADDR,
RotPage::CfpaActive => {
let (cfpa_word, _) =
self.cfpa_word_number_and_version(CfpaPage::Active)?;
cfpa_word << 4
}
RotPage::CfpaInactive => {
let (cfpa_word, _) =
self.cfpa_word_number_and_version(CfpaPage::Inactive)?;
cfpa_word << 4
}
};

const PAGE_SIZE: u32 = BYTES_PER_FLASH_PAGE as u32;

copy_from_flash_range(
&self.flash,
start_addr..(start_addr + PAGE_SIZE),
0..PAGE_SIZE,
dest,
)?;
Ok(())
}
}

impl ServerImpl<'_> {
fn cfpa_word_number_and_version(
&mut self,
page: CfpaPage,
) -> Result<(u32, u32), UpdateError> {
// Read the two versions. We do this with smaller buffers so
// we don't need 2x 512B buffers to read the entire CFPAs.
Expand All @@ -447,12 +487,12 @@ impl ServerImpl<'_> {
core::slice::from_mut(&mut pong_header),
)?;

// Work out where to read the authoritative contents from.
let val = if ping_header[1] >= pong_header[1] {
(CFPA_PING_FLASH_WORD, ping_header[1])
} else {
(CFPA_PONG_FLASH_WORD, pong_header[1])
};
let val =
if ping_header[1] >= pong_header[1] && page == CfpaPage::Active {
(CFPA_PING_FLASH_WORD, ping_header[1])
} else {
(CFPA_PONG_FLASH_WORD, pong_header[1])
};

Ok(val)
}
Expand All @@ -462,7 +502,7 @@ impl ServerImpl<'_> {
&mut self,
) -> Result<(SlotId, Option<SlotId>, Option<SlotId>), UpdateError> {
let (cfpa_word_number, cfpa_version) =
self.cfpa_word_number_and_version()?;
self.cfpa_word_number_and_version(CfpaPage::Active)?;

// Read the authoritative boot selection
let boot_selection_word_number =
Expand Down Expand Up @@ -883,6 +923,33 @@ fn copy_from_caboose_chunk(
Ok(())
}

fn copy_from_flash_range(
flash: &drv_lpc55_flash::Flash<'_>,
range: core::ops::Range<u32>,
pos: core::ops::Range<u32>,
data: LenLimit<Leased<W, [u8]>, BYTES_PER_FLASH_PAGE>,
) -> Result<(), RequestError<UpdateError>> {
// Early exit if the caller didn't provide enough space in the lease
let mut remaining = pos.end - pos.start;
if remaining as usize > data.len() {
return Err(RequestError::Fail(ClientError::BadLease))?;
}

const BUF_SIZE: usize = 128;
let mut offset = 0;
let mut buf = [0u8; BUF_SIZE];
while remaining > 0 {
let count = remaining.min(buf.len() as u32);
let buf = &mut buf[..count as usize];
indirect_flash_read(flash, range.start + pos.start + offset, buf)?;
data.write_range(offset as usize..(offset + count) as usize, buf)
.map_err(|_| RequestError::Fail(ClientError::WentAway))?;
offset += count;
remaining -= count;
}
Ok(())
}

task_slot!(SYSCON, syscon);
task_slot!(JEFE, jefe);

Expand Down Expand Up @@ -915,7 +982,7 @@ include!(concat!(env!("OUT_DIR"), "/notifications.rs"));
mod idl {
use super::{
HandoffDataLoadError, ImageVersion, RawCabooseError, RotBootInfo,
RotBootState, SlotId, SwitchDuration, UpdateTarget,
RotPage, SlotId, SwitchDuration, UpdateTarget,
};

include!(concat!(env!("OUT_DIR"), "/server_stub.rs"));
Expand Down
32 changes: 29 additions & 3 deletions drv/sprot-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ pub use error::{
use crc::{Crc, CRC_16_XMODEM};
use derive_more::From;
pub use drv_lpc55_update_api::{
HandoffDataLoadError, RawCabooseError, RotBootInfo, RotBootState, RotSlot,
SlotId, SwitchDuration, UpdateTarget,
HandoffDataLoadError, RawCabooseError, RotBootInfo, RotBootState, RotPage,
RotSlot, SlotId, SwitchDuration, UpdateTarget,
};
pub use drv_update_api::UpdateError;
use hubpack::SerializedSize;
use idol_runtime::{Leased, LenLimit, R};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
Expand All @@ -46,7 +47,7 @@ pub const MIN_VERSION: Version = Version(2);
/// Code between the `CURRENT_VERSION` and `MIN_VERSION` must remain
/// compatible. Use the rules described in the comments for [`Msg`] to evolve
/// the protocol such that this remains true.
pub const CURRENT_VERSION: Version = Version(3);
pub const CURRENT_VERSION: Version = Version(4);

/// We allow room in the buffer for message evolution
pub const REQUEST_BUF_SIZE: usize = 1024;
Expand Down Expand Up @@ -316,6 +317,21 @@ where
)]
pub struct Version(pub u32);

#[derive(Clone, Serialize, Deserialize, SerializedSize)]
pub enum CfpaState {
/// The CFPA page used by the ROM
Active,
/// The CFPA that will be applied on the next update
Pending,
/// The CFPA region that is neither pending or active
Alternate,
}

#[derive(Clone, Serialize, Deserialize, SerializedSize)]
pub enum PageReq {
Page(RotPage),
}

/// The body of a sprot request.
///
/// See [`Msg`] for details about versioning and message evolution.
Expand All @@ -330,6 +346,8 @@ pub enum ReqBody {
// Added in sprot protocol version 3
Caboose(CabooseReq),
Attest(AttestReq),
// Added in sprot protocol version 4
RotPage { page: RotPage },
}

/// Instruct the RoT to take a dump of the SP via SWD
Expand Down Expand Up @@ -424,6 +442,14 @@ pub enum RspBody {
Caboose(Result<CabooseRsp, RawCabooseError>),

Attest(Result<AttestRsp, AttestError>),

Page(Result<RotPageRsp, UpdateError>),
}

/// A response for reading a ROT page
#[derive(Copy, Clone, Serialize, Deserialize, SerializedSize)]
pub enum RotPageRsp {
RotPage,
}

/// A response from the Dumper
Expand Down
Loading

0 comments on commit 043c305

Please sign in to comment.