diff --git a/Cargo.lock b/Cargo.lock index 04286fbdc..70477d2f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5265,8 +5265,10 @@ dependencies = [ "fnv", "gnarle", "goblin", + "hex", "hubtools", "indexmap", + "lpc55-rom-data", "lpc55_sign", "memchr", "multimap", diff --git a/app/gemini-bu/app.toml b/app/gemini-bu/app.toml index f65eff563..21c460194 100644 --- a/app/gemini-bu/app.toml +++ b/app/gemini-bu/app.toml @@ -3,6 +3,7 @@ target = "thumbv7em-none-eabihf" board = "gemini-bu-1" chip = "../../chips/stm32h7" stacksize = 896 +fwid = true [kernel] name = "gemini-bu" diff --git a/app/gimlet/base.toml b/app/gimlet/base.toml index d5724fb1f..7c250c6d7 100644 --- a/app/gimlet/base.toml +++ b/app/gimlet/base.toml @@ -2,6 +2,7 @@ target = "thumbv7em-none-eabihf" chip = "../../chips/stm32h7" memory = "memory-large.toml" stacksize = 896 +fwid = true [kernel] name = "gimlet" diff --git a/app/gimletlet/app-meanwell.toml b/app/gimletlet/app-meanwell.toml index 48ae8c3ad..dd7c92e0c 100644 --- a/app/gimletlet/app-meanwell.toml +++ b/app/gimletlet/app-meanwell.toml @@ -3,6 +3,7 @@ target = "thumbv7em-none-eabihf" board = "gimletlet-2" chip = "../../chips/stm32h7" stacksize = 896 +fwid = true [kernel] name = "gimletlet" diff --git a/app/gimletlet/app-mgmt.toml b/app/gimletlet/app-mgmt.toml index 67be14535..7df9c5434 100644 --- a/app/gimletlet/app-mgmt.toml +++ b/app/gimletlet/app-mgmt.toml @@ -3,6 +3,7 @@ target = "thumbv7em-none-eabihf" board = "gimletlet-1" chip = "../../chips/stm32h7" stacksize = 1024 +fwid = true [kernel] name = "gimletlet" diff --git a/app/gimletlet/app-sidecar-emulator.toml b/app/gimletlet/app-sidecar-emulator.toml index 7b8082874..ff725a672 100644 --- a/app/gimletlet/app-sidecar-emulator.toml +++ b/app/gimletlet/app-sidecar-emulator.toml @@ -4,6 +4,7 @@ board = "gimletlet-2" chip = "../../chips/stm32h7" memory = "memory-large.toml" stacksize = 896 +fwid = true [kernel] name = "gimletlet" diff --git a/app/gimletlet/app.toml b/app/gimletlet/app.toml index f8f430a86..7c12bbcae 100644 --- a/app/gimletlet/app.toml +++ b/app/gimletlet/app.toml @@ -6,6 +6,7 @@ memory = "memory-large.toml" stacksize = 896 epoch = 0 version = 0 +fwid = true [kernel] name = "gimletlet" diff --git a/app/lpc55xpresso/app-sprot.toml b/app/lpc55xpresso/app-sprot.toml index 0fe6f7f90..e6e156ac8 100644 --- a/app/lpc55xpresso/app-sprot.toml +++ b/app/lpc55xpresso/app-sprot.toml @@ -12,6 +12,7 @@ board = "lpcxpresso55s69" chip = "../../chips/lpc55" stacksize = 1024 image-names = ["a", "b"] +fwid = true [kernel] name = "lpc55xpresso" diff --git a/app/lpc55xpresso/app.toml b/app/lpc55xpresso/app.toml index 0331d639d..d62195c81 100644 --- a/app/lpc55xpresso/app.toml +++ b/app/lpc55xpresso/app.toml @@ -4,6 +4,7 @@ board = "lpcxpresso55s69" chip = "../../chips/lpc55" stacksize = 1024 image-names = ["a", "b"] +fwid = true [kernel] name = "lpc55xpresso" diff --git a/app/oxide-rot-1/app-dev.toml b/app/oxide-rot-1/app-dev.toml index f686543f9..8f5f3abdd 100644 --- a/app/oxide-rot-1/app-dev.toml +++ b/app/oxide-rot-1/app-dev.toml @@ -6,6 +6,7 @@ stacksize = 1024 image-names = ["a", "b"] epoch = 0 version = 0 +fwid = true [kernel] name = "oxide-rot-1" diff --git a/app/oxide-rot-1/app.toml b/app/oxide-rot-1/app.toml index b4db54abf..e42ee11f7 100644 --- a/app/oxide-rot-1/app.toml +++ b/app/oxide-rot-1/app.toml @@ -6,6 +6,7 @@ stacksize = 1024 image-names = ["a", "b"] epoch = 0 version = 0 +fwid = true [kernel] name = "oxide-rot-1" diff --git a/app/psc/base.toml b/app/psc/base.toml index e8e425ca5..a1649b6a9 100644 --- a/app/psc/base.toml +++ b/app/psc/base.toml @@ -2,6 +2,7 @@ target = "thumbv7em-none-eabihf" chip = "../../chips/stm32h7" memory = "memory-large.toml" stacksize = 896 +fwid = true [kernel] name = "psc" diff --git a/app/rot-carrier/app.toml b/app/rot-carrier/app.toml index b3520ed2c..788ec65b1 100644 --- a/app/rot-carrier/app.toml +++ b/app/rot-carrier/app.toml @@ -6,6 +6,7 @@ stacksize = 1024 image-names = ["a", "b"] epoch = 0 version = 0 +fwid = true [kernel] name = "rot-carrier" diff --git a/app/sidecar/base.toml b/app/sidecar/base.toml index 64ad18471..f53de237b 100644 --- a/app/sidecar/base.toml +++ b/app/sidecar/base.toml @@ -2,6 +2,7 @@ target = "thumbv7em-none-eabihf" chip = "../../chips/stm32h7" stacksize = 896 memory = "memory-large.toml" +fwid = true [kernel] name = "sidecar" diff --git a/build/xtask/Cargo.toml b/build/xtask/Cargo.toml index bf51f1c2e..883caaa66 100644 --- a/build/xtask/Cargo.toml +++ b/build/xtask/Cargo.toml @@ -21,6 +21,7 @@ dunce = { workspace = true } filetime = { workspace = true } fnv = { workspace = true } goblin = { workspace = true } +hex = "0.4" hubtools = { workspace = true } indexmap = { workspace = true } multimap = { workspace = true } @@ -42,6 +43,7 @@ zip = { workspace = true } gnarle = { path = "../../lib/gnarle", features = ["std"] } abi.path = "../../sys/abi" build-kconfig.path = "../kconfig" +lpc55-rom-data.path = "../../lib/lpc55-rom-data" toml-task.path = "../../lib/toml-task" toml-patch.path = "../toml-patch" diff --git a/build/xtask/src/config.rs b/build/xtask/src/config.rs index 9bdc3c656..ef2d2f2cd 100644 --- a/build/xtask/src/config.rs +++ b/build/xtask/src/config.rs @@ -27,6 +27,8 @@ struct RawConfig { epoch: u32, #[serde(default)] version: u32, + #[serde(default)] + fwid: bool, memory: Option, #[serde(default)] image_names: Vec, @@ -52,6 +54,7 @@ pub struct Config { pub chip: String, pub epoch: u32, pub version: u32, + pub fwid: bool, pub image_names: Vec, pub external_images: Vec, pub signing: Option, @@ -171,6 +174,7 @@ impl Config { chip: toml.chip, epoch: toml.epoch, version: toml.version, + fwid: toml.fwid, signing: toml.signing, stacksize: toml.stacksize, kernel: toml.kernel, diff --git a/build/xtask/src/dist.rs b/build/xtask/src/dist.rs index c0a75b840..fc83779fd 100644 --- a/build/xtask/src/dist.rs +++ b/build/xtask/src/dist.rs @@ -3,6 +3,7 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; +use std::ffi::OsStr; use std::fmt::Write as _; use std::fs::{self, File}; use std::hash::{Hash, Hasher}; @@ -14,8 +15,10 @@ use std::process::{Command, Stdio}; use anyhow::{anyhow, bail, Context, Result}; use atty::Stream; use indexmap::IndexMap; +use lpc55_rom_data::FLASH_PAGE_SIZE as LPC55_FLASH_PAGE_SIZE; use multimap::MultiMap; use path_slash::{PathBufExt, PathExt}; +use sha3::{Digest, Sha3_256}; use zerocopy::AsBytes; use crate::{ @@ -535,6 +538,10 @@ pub fn package( archive.overwrite()?; } + if cfg.toml.fwid { + write_fwid(&cfg, &image_name, &flash, &archive_name)?; + } + // Unzip the signed + caboose'd images into our build directory let archive = hubtools::RawHubrisArchive::load(&archive_name) .context("loading archive with hubtools")?; @@ -549,6 +556,67 @@ pub fn package( Ok(allocated) } +// generate file with hash of expected flash contents +fn write_fwid( + cfg: &PackageConfig, + image_name: &String, + flash: &Range, + archive_name: &PathBuf, +) -> Result<()> { + let mut archive = hubtools::RawHubrisArchive::load(archive_name) + .context("loading archive with hubtools")?; + + let bin = archive + .extract_file("img/final.bin") + .context("extracting final.bin after signing & caboosing")?; + + let chip_name = Path::new(&cfg.toml.chip); + + // determine length of padding + let pad = match chip_name.file_name().and_then(OsStr::to_str) { + Some("lpc55") => { + // Flash is programmed in 512 blocks. If the final block is not + // filled, it is padded with 0xff's. Unwritten flash pages cannot + // be read and are not included in the FWID calculation. + LPC55_FLASH_PAGE_SIZE - bin.len() % LPC55_FLASH_PAGE_SIZE + } + Some("stm32h7") => { + // all unprogrammed flash is read as 0xff + flash.end as usize - flash.start as usize - bin.len() + } + Some(c) => { + bail!("no FWID algorithm defined for chip: \"{}\"", c) + } + None => bail!("Failed to get file name of {}", chip_name.display()), + }; + + let mut sha = Sha3_256::new(); + sha.update(&bin); + + if pad != 0 { + sha.update(vec![0xff_u8; pad]) + } + + let digest = sha.finalize(); + + // after we've appended a newline fwid is immutable + let mut fwid = hex::encode(&digest); + writeln!(fwid, "").context("appending newline to FWID")?; + let fwid = fwid; + + // the archive already exists so we write the FWID to the same path in + // the build output and archive to keep the two consistent + fs::write(&cfg.img_file("final.fwid", image_name), &fwid) + .context("writing FWID to build output")?; + archive + .add_file("img/final.fwid", fwid.as_bytes()) + .context("writing FWID to archive")?; + + archive.overwrite()?; + + Ok(()) +} + fn write_gdb_script(cfg: &PackageConfig, image_name: &str) -> Result<()> { // Humility doesn't know about images right now. The gdb symbol file // paths all assume a flat layout with everything in dist. For now,