From ae06dfe1beb5fcf0a03ad86fe6ffcd47ebc4c79a Mon Sep 17 00:00:00 2001 From: bunnie Date: Sat, 14 Jun 2025 01:42:23 +0800 Subject: [PATCH] add baremetal target this is a minimal target for building test images that need none of the xous goodies, but may rely upon e.g. APIs and libraries. Closer to coding for a baremetal embedded system. --- xtask/src/builder.rs | 83 ++++++++++++++++++++++++++++++++++++-------- xtask/src/main.rs | 43 +++++++++++++++++++++++ 2 files changed, 111 insertions(+), 15 deletions(-) diff --git a/xtask/src/builder.rs b/xtask/src/builder.rs index 5c36c176a..10b54a03e 100644 --- a/xtask/src/builder.rs +++ b/xtask/src/builder.rs @@ -147,6 +147,7 @@ pub(crate) struct Builder { /// when Some, specifies a swap region as offset, size swap: Option<(u32, u32)>, change_target: bool, + baremetal: bool, } impl Builder { @@ -176,9 +177,16 @@ impl Builder { no_image: false, swap: None, change_target: false, + baremetal: false, } } + /// Sets a flag if the build is just for a baremetal testing target + pub fn set_baremetal<'a>(&'a mut self, baremetal: bool) -> &'a mut Builder { + self.baremetal = baremetal; + self + } + /// Specify an alternate loader key, as a String that can encode a file name /// in the local directory, or a path + filename. #[allow(dead_code)] @@ -379,6 +387,19 @@ impl Builder { self } + /// Configure for Arty BIO validation board + pub fn target_artybio(&mut self) -> &mut Builder { + self.target = Some(crate::TARGET_TRIPLE_RISCV32.to_string()); + self.target_kernel = Some(crate::TARGET_TRIPLE_RISCV32_KERNEL.to_string()); + self.stream = BuildStream::Release; + self.utra_target = "artybio".to_string(); + self.run_svd2repl = false; + self.loader = CrateSpec::Local("baremetal".to_string(), LoaderRegion::Ram); + // this is actually a dummy, there is no kernel in baremetal + self.kernel = CrateSpec::Local("xous-kernel".to_string(), LoaderRegion::Ram); + self + } + /// Override the default kernel. For example, to use the kernel from crates.io, specify as /// "xous-kernel@0.9.9" #[allow(dead_code)] @@ -669,7 +690,7 @@ impl Builder { /// Consume the builder and execute the configured build task. This handles dispatching all /// configurations, including renode, hosted, and hardware targets. pub fn build(mut self) -> Result<(), DynError> { - if self.apps.is_empty() && self.services.is_empty() { + if self.apps.is_empty() && self.services.is_empty() && !self.baremetal { // no services were specified - don't build anything return Ok(()); } @@ -710,6 +731,9 @@ impl Builder { } else if self.utra_target.contains("hosted-baosec") { self.features.push("hosted-baosec".into()); self.kernel_features.push("hosted".into()); + } else if self.utra_target.contains("artybio") { + self.loader_features.push("artybio".into()); + self.loader_features.push(format!("utralib/{}", &self.utra_target)); } else { return Err("Target unknown: please check your UTRA target".into()); } @@ -827,20 +851,6 @@ impl Builder { std::fs::remove_file(&svd_spec_path).ok(); // don't fail if the file does not exist } - // ------ build the kernel ------ - let mut kernel_extra = vec![]; - if self.kernel_disable_defaults { - kernel_extra.push("--no-default-features".to_string()); - } - let kernel_path = self.builder( - &[self.kernel.clone()], - &self.kernel_features, - &self.target_kernel.as_deref(), - self.stream, - &kernel_extra, - false, - )?; - // ------ build the loader ------ // stash any LTO settings applied to the kernel; proper layout of the loader // block depends on the loader being compact and highly optimized. @@ -870,6 +880,49 @@ impl Builder { env::set_var("CARGO_PROFILE_RELEASE_CODEGEN_UNITS", existing); } + if self.baremetal { + // package and exit the baremetal, then we're done + let stream = self.stream.as_str(); + let mut output_file = PathBuf::new(); + output_file.push("target"); + output_file.push(self.target.as_ref().expect("target")); + output_file.push(stream); + output_file.push("baremetal.img"); + + let status = Command::new(cargo()) + .current_dir(project_root()) + .args([ + "run", + "--package", + "tools", + "--bin", + "copy-object", + "--", + &loader[0], + output_file.as_os_str().to_str().unwrap(), + ]) + .status()?; + if !status.success() { + return Err("cargo build failed".into()); + } else { + return Ok(()); + } + } + + // ------ build the kernel ------ + let mut kernel_extra = vec![]; + if self.kernel_disable_defaults { + kernel_extra.push("--no-default-features".to_string()); + } + let kernel_path = self.builder( + &[self.kernel.clone()], + &self.kernel_features, + &self.target_kernel.as_deref(), + self.stream, + &kernel_extra, + false, + )?; + // ------ if targeting renode, regenerate the Platform file ----- if self.run_svd2repl { Command::new(cargo()) diff --git a/xtask/src/main.rs b/xtask/src/main.rs index d80e1e8ec..608d43dff 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -588,6 +588,49 @@ fn main() -> Result<(), Box> { } } + Some("baremetal") => { + builder.set_baremetal(true); + builder.target_artybio(); + + /* + let existing_lto = env::var("CARGO_PROFILE_RELEASE_LTO").map(Some).unwrap_or(None); + let existing_codegen_units = + env::var("CARGO_PROFILE_RELEASE_CODEGEN_UNITS").map(Some).unwrap_or(None); + // these settings will generate the most compact code (but also the hardest to debug) + env::set_var("CARGO_PROFILE_RELEASE_LTO", "true"); + env::set_var("CARGO_PROFILE_RELEASE_CODEGEN_UNITS", "1"); + + let mut local_args = vec!["build"]; + /* + let output_root = format!( + "{}/target/{}{}/", + project_root().into_os_string().into_string().unwrap(), + crate::TARGET_TRIPLE_RISCV32_KERNEL, + stream.as_str(), + ); + local_args.push(&output_root); */ + + local_args.push("--target"); + local_args.push(crate::TARGET_TRIPLE_RISCV32_KERNEL); + + local_args.push("--features"); + local_args.push("artybio"); + + let status = + std::process::Command::new(cargo()).current_dir(project_root()).args(&local_args).status()?; + if !status.success() { + return Err("Baremetal build failed".into()); + } + + // restore the LTO settings + if let Some(existing) = existing_lto { + env::set_var("CARGO_PROFILE_RELEASE_LTO", existing); + } + if let Some(existing) = existing_codegen_units { + env::set_var("CARGO_PROFILE_RELEASE_CODEGEN_UNITS", existing); + }*/ + } + Some("baosec") => { let board = "board-baosec"; // select the board