Skip to content

Commit 83fe188

Browse files
authored
Add HostFlash commands (#392)
Add HostFlashRead and {Start, Get}HostFlashHash
1 parent 2514035 commit 83fe188

File tree

13 files changed

+276
-3
lines changed

13 files changed

+276
-3
lines changed

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ nix = { version = "0.27.1", features = ["net"] }
4444
omicron-zone-package = "0.11.0"
4545
once_cell = "1.21.3"
4646
paste = "1.0.15"
47+
parse_int = "0.6"
4748
rand = "0.8.5"
4849
serde = { version = "1.0", default-features = false, features = ["derive"] }
4950
serde-big-array = "0.5.1"

faux-mgs/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ hex.workspace = true
1414
humantime.workspace = true
1515
nix.workspace = true
1616
rand.workspace = true
17+
parse_int.workspace = true
1718
serde.workspace = true
1819
serde_json.workspace = true
1920
sha2.workspace = true

faux-mgs/src/main.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,9 @@ enum Command {
247247
},
248248

249249
/// Get or set startup options on an SP.
250-
StartupOptions { options: Option<u64> },
250+
StartupOptions {
251+
options: Option<u64>,
252+
},
251253

252254
/// Ask SP for its inventory.
253255
Inventory,
@@ -305,7 +307,9 @@ enum Command {
305307
UsartDetach,
306308

307309
/// Serve host phase 2 images.
308-
ServeHostPhase2 { directory: PathBuf },
310+
ServeHostPhase2 {
311+
directory: PathBuf,
312+
},
309313

310314
/// Upload a new image to the SP or one of its components.
311315
///
@@ -454,6 +458,20 @@ enum Command {
454458
#[clap(subcommand)]
455459
cmd: DumpCommand,
456460
},
461+
/// Read Host flash at address
462+
ReadHostFlash {
463+
slot: u16,
464+
// Giving addresses in hex is nice and the default clap parser
465+
// does not support that
466+
#[clap(value_parser = parse_int::parse::<u32>)]
467+
addr: u32,
468+
},
469+
StartHostFlashHash {
470+
slot: u16,
471+
},
472+
GetHostFlashHash {
473+
slot: u16,
474+
},
457475
}
458476

459477
#[derive(Subcommand, Debug, Clone)]
@@ -1702,6 +1720,18 @@ async fn run_command(
17021720
}
17031721
}
17041722
},
1723+
Command::ReadHostFlash { slot, addr } => {
1724+
let result = sp.read_host_flash(slot, addr).await?;
1725+
Ok(Output::Lines(vec![format!("{result:x?}")]))
1726+
}
1727+
Command::StartHostFlashHash { slot } => {
1728+
sp.start_host_flash_hash(slot).await?;
1729+
Ok(Output::Lines(vec!["hash started".to_string()]))
1730+
}
1731+
Command::GetHostFlashHash { slot } => {
1732+
let result = sp.get_host_flash_hash(slot).await?;
1733+
Ok(Output::Lines(vec![format!("{result:x?}")]))
1734+
}
17051735
}
17061736
}
17071737

gateway-messages/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ pub const MAX_SERIALIZED_SIZE: usize = 1024;
3838
/// Size for a memory page in the Root of Trust (LPC55)
3939
pub const ROT_PAGE_SIZE: usize = 512;
4040

41+
/// Size for a host flash page
42+
pub const HF_PAGE_SIZE: usize = 256;
43+
4144
/// Module specifying the minimum and current version of the MGS protocol.
4245
///
4346
/// Our primary mechanism for serializing requests and responses is enums
@@ -66,7 +69,7 @@ pub const ROT_PAGE_SIZE: usize = 512;
6669
/// for more detail and discussion.
6770
pub mod version {
6871
pub const MIN: u32 = 2;
69-
pub const CURRENT: u32 = 18;
72+
pub const CURRENT: u32 = 19;
7073

7174
/// MGS protocol version in which SP watchdog messages were added
7275
pub const WATCHDOG_VERSION: u32 = 12;

gateway-messages/src/mgs_to_sp.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,21 @@ pub enum MgsRequest {
221221
},
222222

223223
Dump(DumpRequest),
224+
225+
/// Read the host flash at the specified address for the current
226+
/// persistent slot. Always returns one (host) page size
227+
ReadHostFlash {
228+
slot: u16,
229+
addr: u32,
230+
},
231+
/// Start a hash of the specified flash bank
232+
StartHostFlashHash {
233+
slot: u16,
234+
},
235+
/// sha2-256 sum of the slot
236+
GetHostFlashHash {
237+
slot: u16,
238+
},
224239
}
225240

226241
#[derive(

gateway-messages/src/sp_impl.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ use crate::TlvPage;
4949
use crate::UpdateChunk;
5050
use crate::UpdateId;
5151
use crate::UpdateStatus;
52+
use crate::HF_PAGE_SIZE;
5253
use crate::ROT_PAGE_SIZE;
5354
use hubpack::error::Error as HubpackError;
5455
use hubpack::error::Result as HubpackResult;
@@ -405,6 +406,17 @@ pub trait SpHandler {
405406
seq: u32,
406407
buf: &mut [u8],
407408
) -> Result<Option<DumpSegment>, SpError>;
409+
410+
fn read_host_flash(
411+
&mut self,
412+
slot: u16,
413+
addr: u32,
414+
buf: &mut [u8],
415+
) -> Result<(), SpError>;
416+
417+
fn start_host_flash_hash(&mut self, slot: u16) -> Result<(), SpError>;
418+
419+
fn get_host_flash_hash(&mut self, slot: u16) -> Result<[u8; 32], SpError>;
408420
}
409421

410422
/// Handle a single incoming message.
@@ -1006,6 +1018,20 @@ fn handle_mgs_request<H: SpHandler>(
10061018
}
10071019
r.map(|d| SpResponse::Dump(DumpResponse::TaskDumpRead(d)))
10081020
}
1021+
MgsRequest::ReadHostFlash { slot, addr } => {
1022+
let r = handler.read_host_flash(slot, addr, trailing_tx_buf);
1023+
if r.is_ok() {
1024+
outgoing_trailing_data =
1025+
Some(OutgoingTrailingData::ShiftFromTail(HF_PAGE_SIZE));
1026+
}
1027+
r.map(|_| SpResponse::ReadHostFlash)
1028+
}
1029+
MgsRequest::StartHostFlashHash { slot } => handler
1030+
.start_host_flash_hash(slot)
1031+
.map(|_| SpResponse::StartHostFlashHashAck),
1032+
MgsRequest::GetHostFlashHash { slot } => {
1033+
handler.get_host_flash_hash(slot).map(SpResponse::HostFlashHash)
1034+
}
10091035
};
10101036

10111037
let response = match result {
@@ -1411,6 +1437,26 @@ mod tests {
14111437
) -> Result<Option<DumpSegment>, SpError> {
14121438
unimplemented!()
14131439
}
1440+
1441+
fn read_host_flash(
1442+
&mut self,
1443+
_slot: u16,
1444+
_addr: u32,
1445+
_buf: &mut [u8],
1446+
) -> Result<(), SpError> {
1447+
unimplemented!()
1448+
}
1449+
1450+
fn start_host_flash_hash(&mut self, _slot: u16) -> Result<(), SpError> {
1451+
unimplemented!()
1452+
}
1453+
1454+
fn get_host_flash_hash(
1455+
&mut self,
1456+
_slot: u16,
1457+
) -> Result<[u8; 32], SpError> {
1458+
unimplemented!()
1459+
}
14141460
}
14151461

14161462
#[cfg(feature = "std")]

gateway-messages/src/sp_to_mgs.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,15 @@ pub enum SpResponse {
168168
/// Response to a `SetPowerState` request indicating that the system was
169169
/// already in the desired power state and no transition occurred.
170170
PowerStateUnchanged,
171+
172+
/// Packet contains the host flash data
173+
ReadHostFlash,
174+
175+
/// Started a hash of a flash bank
176+
StartHostFlashHashAck,
177+
178+
/// sha2-256 hash of a flash bank
179+
HostFlashHash([u8; 32]),
171180
}
172181

173182
/// Identifier for one of of an SP's KSZ8463 management-network-facing ports.
@@ -1093,6 +1102,7 @@ pub enum SpError {
10931102
Watchdog(WatchdogError),
10941103
Monorail(MonorailError),
10951104
Dump(DumpError),
1105+
Hf(HfError),
10961106
}
10971107

10981108
impl fmt::Display for SpError {
@@ -1207,6 +1217,7 @@ impl fmt::Display for SpError {
12071217
Self::Watchdog(e) => write!(f, "watchdog: {}", e),
12081218
Self::Monorail(e) => write!(f, "monorail: {}", e),
12091219
Self::Dump(e) => write!(f, "dump: {}", e),
1220+
Self::Hf(e) => write!(f, "hf: {}", e),
12101221
}
12111222
}
12121223
}
@@ -1708,3 +1719,37 @@ impl fmt::Display for DumpError {
17081719
write!(f, "{s}")
17091720
}
17101721
}
1722+
1723+
/// Errors encountered when reading host flash. This isn't all the possible
1724+
/// host flash errors but enough of the ones we should see commonly
1725+
///
1726+
/// This value is wrapped by [`SpError`]
1727+
#[derive(
1728+
Debug, Clone, Copy, Eq, PartialEq, SerializedSize, Serialize, Deserialize,
1729+
)]
1730+
pub enum HfError {
1731+
NotMuxedToSp,
1732+
BadAddress,
1733+
QspiTimeout,
1734+
QspiTransferError,
1735+
HashUncalculated,
1736+
RecalculateHash,
1737+
HashInProgress,
1738+
}
1739+
1740+
impl fmt::Display for HfError {
1741+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1742+
let s = match self {
1743+
Self::NotMuxedToSp => "Host flash not muxed to SP",
1744+
Self::BadAddress => "Bad host flash address",
1745+
Self::QspiTimeout => "Host QSPI timeout",
1746+
Self::QspiTransferError => {
1747+
"Host QSPI Transfer Error (check address)"
1748+
}
1749+
Self::HashUncalculated => "No hash calculated for slot",
1750+
Self::RecalculateHash => "Slot requires hash recalculation",
1751+
Self::HashInProgress => "Hash calcuation in progress",
1752+
};
1753+
write!(f, "{s}")
1754+
}
1755+
}

gateway-messages/tests/versioning/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ mod v15;
2424
mod v16;
2525
mod v17;
2626
mod v18;
27+
mod v19;
2728

2829
pub fn assert_serialized<T: Serialize + SerializedSize + std::fmt::Debug>(
2930
expected: &[u8],
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
//! This source file is named after the protocol version being tested,
6+
//! e.g. v01.rs implements tests for protocol version 1.
7+
//! The tested protocol version is represented by "$VERSION" below.
8+
//!
9+
//! The tests in this module check that the serialized form of messages from MGS
10+
//! protocol version $VERSION have not changed.
11+
//!
12+
//! If a test in this module fails, _do not change the test_! This means you
13+
//! have changed, deleted, or reordered an existing message type or enum
14+
//! variant, and you should revert that change. This will remain true until we
15+
//! bump the `version::MIN` to a value higher than $VERSION, at which point these
16+
//! tests can be removed as we will stop supporting $VERSION.
17+
18+
use super::assert_serialized;
19+
use gateway_messages::{HfError, MgsRequest, SpError, SpResponse};
20+
21+
#[test]
22+
fn read_host_flash() {
23+
let request = MgsRequest::ReadHostFlash { slot: 0, addr: 0 };
24+
assert_serialized(&[47, 0, 0, 0, 0, 0, 0], &request);
25+
26+
let request = MgsRequest::StartHostFlashHash { slot: 0 };
27+
assert_serialized(&[48, 0, 0], &request);
28+
29+
let request = MgsRequest::GetHostFlashHash { slot: 0 };
30+
assert_serialized(&[49, 0, 0], &request);
31+
32+
let response = SpResponse::ReadHostFlash;
33+
assert_serialized(&[49], &response);
34+
35+
let response = SpResponse::StartHostFlashHashAck;
36+
assert_serialized(&[50], &response);
37+
38+
let response = SpResponse::HostFlashHash([0; 32]);
39+
assert_serialized(
40+
&[
41+
51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
42+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43+
],
44+
&response,
45+
);
46+
47+
for (i, e) in [
48+
HfError::NotMuxedToSp,
49+
HfError::BadAddress,
50+
HfError::QspiTimeout,
51+
HfError::QspiTransferError,
52+
HfError::HashUncalculated,
53+
HfError::RecalculateHash,
54+
HfError::HashInProgress,
55+
]
56+
.into_iter()
57+
.enumerate()
58+
{
59+
let request = SpError::Hf(e);
60+
assert_serialized(&[38, i as u8], &request);
61+
}
62+
}

0 commit comments

Comments
 (0)