diff --git a/app/demo-stm32g0-nucleo/app-g070.toml b/app/demo-stm32g0-nucleo/app-g070.toml index 1be325868..b40cc349f 100644 --- a/app/demo-stm32g0-nucleo/app-g070.toml +++ b/app/demo-stm32g0-nucleo/app-g070.toml @@ -7,7 +7,7 @@ stacksize = 944 [kernel] name = "demo-stm32g0-nucleo" -requires = {flash = 19264, ram = 1632} +requires = {flash = 19264, ram = 1664} features = ["g070"] stacksize = 640 diff --git a/app/oxide-rot-1/app.toml b/app/oxide-rot-1/app.toml index 5058c33af..c59957995 100644 --- a/app/oxide-rot-1/app.toml +++ b/app/oxide-rot-1/app.toml @@ -10,7 +10,7 @@ version = 0 [kernel] name = "oxide-rot-1" -requires = {flash = 61252, ram = 2720} +requires = {flash = 61252, ram = 2736} features = ["dice-mfg"] [caboose] diff --git a/build/util/src/lib.rs b/build/util/src/lib.rs index a1bad19d4..912c56fbf 100644 --- a/build/util/src/lib.rs +++ b/build/util/src/lib.rs @@ -9,6 +9,14 @@ use std::collections::BTreeMap; use std::ffi::OsStr; use std::io::Write; +/// Maximum length, in bytes, of an image name (an entry in `image-names` in a +/// manifest). +/// +/// NOTE: If you modify this, the layout of `BOOTED_IMAGE` will change. Humility +/// won't be able to identify which image is running if the archive and target +/// have a different layout. +pub const MAX_IMAGE_NAME_LEN: usize = 8; + /// Reads the given environment variable and marks that it's used /// /// This ensures a rebuild if the variable changes diff --git a/build/xtask/src/dist.rs b/build/xtask/src/dist.rs index e4a742d2d..25142c0e7 100644 --- a/build/xtask/src/dist.rs +++ b/build/xtask/src/dist.rs @@ -1880,6 +1880,7 @@ fn build_kernel( let build_config = cfg.kernel_build_config(&[ ("HUBRIS_KCONFIG", &kconfig), ("HUBRIS_IMAGE_ID", &format!("{image_id}")), + ("HUBRIS_IMAGE_NAME", image_name), ("HUBRIS_FLASH_OUTPUTS", &flash_outputs), ]); build(cfg, "kernel", build_config, false)?; diff --git a/sys/kern/build.rs b/sys/kern/build.rs index 4482118fb..e8b5663af 100644 --- a/sys/kern/build.rs +++ b/sys/kern/build.rs @@ -406,6 +406,22 @@ fn generate_statics(generated: &Generated) -> Result<()> { .parse() .context("parsing HUBRIS_IMAGE_ID")?; + let max_name_len = build_util::MAX_IMAGE_NAME_LEN; + let image_name = + build_util::env_var("HUBRIS_IMAGE_NAME").unwrap_or_default(); + let image_name_bytes = image_name.as_bytes(); + if image_name_bytes.len() > max_name_len { + bail!( + "HUBRIS_IMAGE_NAME '{}' is {} bytes, but the max length is {}", + image_name, + image_name_bytes.len(), + max_name_len, + ); + } + let mut image_name_padded = vec![0u8; max_name_len]; + image_name_padded[..image_name_bytes.len()] + .copy_from_slice(image_name_bytes); + let out = build_util::out_dir(); let kconfig_path = out.join("kconfig.rs"); let mut file = @@ -425,6 +441,9 @@ fn generate_statics(generated: &Generated) -> Result<()> { #[unsafe(no_mangle)] pub static HUBRIS_IMAGE_ID: u64 = #image_id; + pub static HUBRIS_IMAGE_NAME: [u8; #max_name_len] = + [#(#image_name_padded),*]; + static mut HUBRIS_TASK_TABLE_SPACE: core::mem::MaybeUninit<[crate::task::Task; HUBRIS_TASK_COUNT]> = core::mem::MaybeUninit::uninit(); diff --git a/sys/kern/src/startup.rs b/sys/kern/src/startup.rs index be46a405b..57bfd4e21 100644 --- a/sys/kern/src/startup.rs +++ b/sys/kern/src/startup.rs @@ -8,7 +8,7 @@ use crate::atomic::AtomicExt; use crate::descs::{RegionAttributes, RegionDesc, TaskDesc, TaskFlags}; use crate::task::Task; use core::mem::MaybeUninit; -use core::sync::atomic::{AtomicBool, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicU8, Ordering, compiler_fence}; /// Tracks when a mutable reference to the task table is floating around in /// kernel code, to prevent production of a second one. This forms a sort of @@ -19,6 +19,25 @@ use core::sync::atomic::{AtomicBool, Ordering}; /// `false` late in `start_kernel`. static TASK_TABLE_IN_USE: AtomicBool = AtomicBool::new(true); +/// Magic marker written into the tail of `BOOTED_IMAGE`. This lets humility +/// confirm that it's reading from the right address and that the kernel has +/// finished populating `BOOTED_IMAGE`. +const BOOTED_IMAGE_MAGIC: [u8; 8] = *b"HUBRISID"; + +/// A record of which image is actually running. This is useful on systems with +/// multiple image slots, like the RoT's A/B images. +/// +/// Layout: +/// - little-endian `HUBRIS_IMAGE_ID` (8 bytes), +/// - null-padded `HUBRIS_IMAGE_NAME` (`build_util::MAX_IMAGE_NAME_LEN`=8 bytes) +/// - `BOOTED_IMAGE_MAGIC` (8 bytes) +#[unsafe(no_mangle)] +static BOOTED_IMAGE: [AtomicU8; BOOTED_IMAGE_LEN] = + [const { AtomicU8::new(0) }; BOOTED_IMAGE_LEN]; + +const BOOTED_IMAGE_LEN: usize = + 8 + HUBRIS_IMAGE_NAME.len() + BOOTED_IMAGE_MAGIC.len(); + pub const HUBRIS_FAULT_NOTIFICATION: u32 = 1; /// The main kernel entry point. @@ -47,6 +66,26 @@ pub unsafe fn start_kernel(tick_divisor: u32) -> ! { crate::arch::set_clock_freq(tick_divisor); } + // Record the ID and name of the image so that humility can tell which image + // is actually running on a system with A/B image slots. Write the magic + // marker last, so that if humility sees the marker it can trust that the ID + // and name are complete (and that it's reading from the correct memory + // address). + let (id_and_name, magic) = + BOOTED_IMAGE.split_at(BOOTED_IMAGE.len() - BOOTED_IMAGE_MAGIC.len()); + for (destination, byte) in id_and_name.iter().zip( + HUBRIS_IMAGE_ID + .to_le_bytes() + .into_iter() + .chain(HUBRIS_IMAGE_NAME.iter().copied()), + ) { + destination.store(byte, Ordering::Relaxed); + } + compiler_fence(Ordering::Release); + for (destination, byte) in magic.iter().zip(BOOTED_IMAGE_MAGIC) { + destination.store(byte, Ordering::Relaxed); + } + // Grab references to all our statics. let task_descs = &HUBRIS_TASK_DESCS; // Safety: this reference will remain unique so long as the "only called diff --git a/test/tests-stm32g0/app-g070.toml b/test/tests-stm32g0/app-g070.toml index 9a9a7d128..97a9f8727 100644 --- a/test/tests-stm32g0/app-g070.toml +++ b/test/tests-stm32g0/app-g070.toml @@ -6,7 +6,7 @@ memory = "memory-g070.toml" [kernel] name = "demo-stm32g0-nucleo" -requires = {flash = 19112, ram = 2832} +requires = {flash = 19112, ram = 2864} features = ["g070"] stacksize = 2048