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.
This commit is contained in:
bunnie 2025-06-14 01:42:23 +08:00
parent 0f6f6d10dc
commit ae06dfe1be
2 changed files with 111 additions and 15 deletions

View file

@ -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())

View file

@ -588,6 +588,49 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
}
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