mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-04 04:27:34 +00:00
1247 lines
51 KiB
Rust
1247 lines
51 KiB
Rust
mod app_manifest;
|
|
mod versioning;
|
|
use app_manifest::generate_app_menus;
|
|
use versioning::*;
|
|
mod utils;
|
|
use utils::*;
|
|
mod builder;
|
|
use builder::*;
|
|
mod verifier;
|
|
use std::{env, fs, path::Path, path::PathBuf};
|
|
|
|
use verifier::*;
|
|
|
|
/// specifies the hardware target variant for the SoC
|
|
const PRECURSOR_SOC_VERSION: &str = "pvt";
|
|
|
|
/*
|
|
Some notes on kernel versions versus backups.
|
|
|
|
At v0.9.8-791, migrations from v1 PDDB were deprecated
|
|
At v0.9.9-42, backups were introduced, with a backup header version of v1.0
|
|
At v0.9.9-466, a bug parsing minor versions was fixed;
|
|
now the minor version field of the backup header is actually compatible for restore
|
|
header version is now v1.1
|
|
|
|
The latest kernel can parse everything down to v0.9.8-791's backup.
|
|
However, backups generated by the latest kernel require at least v0.9.9-466 to read it,
|
|
due to the minor version masking bug.
|
|
|
|
The MIN_XOUS_VERSION field is the oldest backup that a given kernel can parse.
|
|
Backups older than this cannot be parsed because the migration code for that backup
|
|
was deprecated. The main purpose of this field is to assist the restore script
|
|
in selecting a kernel: it will automatically downgrade a kernel as far as it must
|
|
read a very old backup. This tag is *not* useful for enforcing a minimum
|
|
version of the kernel to read a very *new* backup.
|
|
|
|
Instead, when picking a kernel to restore from, the latest kernel should always be picked,
|
|
that is also able to parse the backup. In the case of developing a new breaking change
|
|
on backups, the bleeding-edge directory must be added to the list of selectable URLs.
|
|
*/
|
|
const MIN_XOUS_VERSION: &str = "v0.9.8-791";
|
|
|
|
/// target triple for precursor builds
|
|
pub(crate) const TARGET_TRIPLE_RISCV32: &str = "riscv32imac-unknown-xous-elf";
|
|
pub(crate) const TARGET_TRIPLE_RISCV32_KERNEL: &str = "riscv32imac-unknown-none-elf";
|
|
/// target triple for ARM builds
|
|
pub(crate) const TARGET_TRIPLE_ARM: &str = "armv7a-unknown-xous-elf";
|
|
pub(crate) const TARGET_TRIPLE_ARM_KERNEL: &str = "armv7a-unknown-none-elf";
|
|
|
|
/// Size of the "statics" region used to initialize baremetal targets
|
|
const STATICS_LEN: usize = 0x100;
|
|
|
|
// because I have nowhere else to note this. The commit that contains the rkyv-enum derive
|
|
// refactor to work around warnings thrown by Rust 1.64.0 is: f815ed85b58b671178fbf53b4cea34186fc406eb
|
|
// We could undo this if it turns out to be a compiler regression.
|
|
|
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
let mut builder = Builder::new();
|
|
// encodes a timestamp into the build, unless '--no-timestamp' is passed
|
|
let do_version = env::args().filter(|x| x == "--no-timestamp").count() == 0;
|
|
let git_describe_opt = get_flag("--git-describe")?.first().cloned();
|
|
let git_rev_opt = get_flag("--git-rev")?.first().cloned();
|
|
generate_version(do_version, git_describe_opt.clone());
|
|
if let Some(desc) = git_describe_opt {
|
|
builder.set_git_describe(desc);
|
|
}
|
|
if let Some(rev) = git_rev_opt {
|
|
builder.set_git_rev(rev);
|
|
}
|
|
let cargo_configs = get_flag("--config")?;
|
|
builder.set_cargo_configs(cargo_configs.clone());
|
|
if do_version {
|
|
builder.add_feature("timestamp");
|
|
};
|
|
|
|
// A base set of packages. This is all you need for a normal
|
|
// operating system that can run libstd
|
|
let base_pkgs = [
|
|
"xous-ticktimer", // "well known" service: thread scheduling
|
|
"xous-log", // "well known" service: debug logging
|
|
"xous-names", // "well known" service: manage inter-server connection lookup
|
|
"xous-susres", // ticktimer registers with susres to coordinate time continuity across sleeps
|
|
]
|
|
.to_vec();
|
|
// minimal set of packages to do bare-iron graphical I/O
|
|
let gfx_base_pkgs = [
|
|
&base_pkgs[..],
|
|
&[
|
|
"graphics-server", // raw (unprotected) frame buffer primitives
|
|
"early_settings", // required by keyboard
|
|
"keyboard", // required by graphics-server
|
|
"spinor", // required by keyboard - to save key mapping
|
|
"llio", // required by spinor
|
|
],
|
|
]
|
|
.concat();
|
|
// packages in the user image - most of the services at this layer have cross-dependencies
|
|
let user_pkgs = [
|
|
&gfx_base_pkgs[..],
|
|
&[
|
|
// net services
|
|
"com",
|
|
"net",
|
|
"dns",
|
|
// UX abstractions
|
|
"gam",
|
|
"ime-frontend",
|
|
"ime-plugin-shell",
|
|
"codec",
|
|
"modals",
|
|
// security
|
|
"root-keys",
|
|
"trng",
|
|
"sha2",
|
|
// "engine-25519",
|
|
"jtag",
|
|
// GUI front end
|
|
"status",
|
|
"shellchat",
|
|
// filesystem
|
|
"pddb",
|
|
// usb services
|
|
"usb-device-xous",
|
|
],
|
|
]
|
|
.concat();
|
|
// for fast testing of compilation targets of the PDDB to real hardware
|
|
let pddb_dev_pkgs = [&base_pkgs[..], &["pddb", "sha2"]].concat();
|
|
// for fast checking of AES hardware accelerator
|
|
let aes_test_pkgs = ["xous-ticktimer", "xous-log", "aes-test"].to_vec();
|
|
|
|
// ---- extract position independent args ----
|
|
let loader_key = get_flag("--lkey")?;
|
|
if !loader_key.is_empty() {
|
|
builder.loader_key_file(loader_key[0].to_string());
|
|
}
|
|
let kernel_key = get_flag("--kkey")?;
|
|
if !kernel_key.is_empty() {
|
|
builder.kernel_key_file(kernel_key[0].to_string());
|
|
}
|
|
let swap_key = get_flag("--swap")?;
|
|
if swap_key.len() != 0 {
|
|
let swap_parts: Vec<&str> = swap_key[0].split(':').collect();
|
|
if swap_parts.len() != 2 {
|
|
return Err(
|
|
"Error: --swap argument should be of the form [offset]:[size] as hex numbers without 0x"
|
|
.into(),
|
|
);
|
|
}
|
|
|
|
let offset = match u32::from_str_radix(swap_parts[0], 16) {
|
|
Ok(o) => o,
|
|
Err(e) => {
|
|
return Err(format!(
|
|
"Error: offset should be hex number without 0x prefix {}: {:?}",
|
|
swap_parts[0], e
|
|
)
|
|
.into());
|
|
}
|
|
};
|
|
|
|
let size = match u32::from_str_radix(swap_parts[1], 16) {
|
|
Ok(o) => o,
|
|
Err(e) => {
|
|
return Err(format!(
|
|
"Error: size should be hex number without 0x prefix {}: {:?}",
|
|
swap_parts[1], e
|
|
)
|
|
.into());
|
|
}
|
|
};
|
|
|
|
builder.set_swap(offset, size);
|
|
}
|
|
|
|
let extra_apps = get_flag("--app")?;
|
|
builder.add_apps(&extra_apps);
|
|
let extra_services = get_flag("--service")?;
|
|
builder.add_services(&extra_services);
|
|
// extract features, and especially track language features
|
|
let features = get_flag("--feature")?;
|
|
|
|
setup_curve25519_backend(&features);
|
|
|
|
let mut language_set = false;
|
|
for feature in features {
|
|
builder.add_feature(&feature);
|
|
if feature.starts_with("xous/lang-") {
|
|
track_language_changes(&feature, &cargo_configs)?;
|
|
language_set = true;
|
|
}
|
|
}
|
|
let kern_features = get_flag("--kernel-feature")?;
|
|
for feature in kern_features {
|
|
builder.add_kernel_feature(&feature);
|
|
}
|
|
let loader_features = get_flag("--loader-feature")?;
|
|
for feature in loader_features {
|
|
builder.add_loader_feature(&feature);
|
|
}
|
|
let detached_app_features = get_flag("--app-feature")?;
|
|
for feature in detached_app_features {
|
|
builder.add_detached_app_feature(&feature);
|
|
}
|
|
|
|
if !language_set {
|
|
// the default language is english
|
|
track_language_changes("en", &cargo_configs)?;
|
|
}
|
|
let gdb_stub = env::args().filter(|x| x == "--gdb-stub").count() != 0;
|
|
if gdb_stub {
|
|
builder.add_kernel_feature("gdb-stub");
|
|
builder.add_feature("gdb-stub");
|
|
}
|
|
if env::args().filter(|x| x == "--debug-loader").count() != 0 {
|
|
builder.add_loader_feature("debug-print");
|
|
}
|
|
if env::args().filter(|x| x == "--offline").count() != 0 {
|
|
builder.add_global_flag("--offline");
|
|
}
|
|
if env::args().filter(|x| x == "--change-target").count() != 0 {
|
|
builder.set_change_target_flag();
|
|
}
|
|
|
|
// ---- now process the verb plus position dependent arguments ----
|
|
let mut args = env::args();
|
|
let task = args.nth(1);
|
|
match task.as_deref() {
|
|
Some("install-toolkit") | Some("install-toolchain") => {
|
|
let arg = env::args().nth(2);
|
|
ensure_compiler(
|
|
&Some(TARGET_TRIPLE_RISCV32),
|
|
true,
|
|
arg.map(|x| x == "--force").unwrap_or(false),
|
|
)?;
|
|
ensure_kernel_compiler(&Some(TARGET_TRIPLE_RISCV32_KERNEL), true)?;
|
|
}
|
|
// ----- renode configs --------
|
|
Some("renode-image") => {
|
|
builder.target_renode().add_services(&user_pkgs).add_apps(&get_cratespecs());
|
|
builder.add_loader_feature("resume");
|
|
// builder.add_loader_feature("debug-print");
|
|
}
|
|
Some("renode-image-debug") => {
|
|
builder
|
|
.target_renode()
|
|
.add_loader_feature("resume")
|
|
.add_services(&user_pkgs)
|
|
.stream(BuildStream::Debug)
|
|
.add_apps(&get_cratespecs());
|
|
}
|
|
Some("renode-test") => {
|
|
builder.target_renode().add_services(&base_pkgs).add_services(&get_cratespecs());
|
|
}
|
|
Some("libstd-test") => {
|
|
builder.target_renode().add_services(&base_pkgs).add_services(&get_cratespecs());
|
|
builder.add_loader_feature("renode-bypass");
|
|
}
|
|
Some("libstd-net") => {
|
|
builder.target_renode().add_services(&base_pkgs).add_services(&get_cratespecs());
|
|
builder.add_loader_feature("renode-bypass").add_loader_feature("renode-minimal");
|
|
builder
|
|
.add_service("net", LoaderRegion::Ram)
|
|
.add_service("com", LoaderRegion::Ram)
|
|
.add_service("llio", LoaderRegion::Ram)
|
|
.add_service("dns", LoaderRegion::Ram);
|
|
}
|
|
Some("renode-aes-test") => {
|
|
builder.target_renode().add_services(&aes_test_pkgs).add_services(&get_cratespecs());
|
|
}
|
|
Some("ffi-test") => {
|
|
builder.target_renode().add_services(&gfx_base_pkgs).add_services(&get_cratespecs());
|
|
builder.add_service("ffi-test", LoaderRegion::Ram);
|
|
builder.add_loader_feature("renode-bypass");
|
|
}
|
|
Some("renode-swap") => {
|
|
let swap_pkgs = ["xous-ticktimer", "xous-log", "xous-susres"];
|
|
if !builder.is_swap_set() {
|
|
builder.set_swap(0x4020_0000, 4 * 1024 * 1024);
|
|
}
|
|
builder.target_renode();
|
|
// builder.target_bao1x_soc();
|
|
builder.add_loader_feature("debug-print");
|
|
builder.add_loader_feature("swap");
|
|
builder.add_kernel_feature("swap");
|
|
builder.add_feature("swap");
|
|
builder.add_kernel_feature("debug-swap");
|
|
// builder.add_kernel_feature("debug-swap-verbose");
|
|
// builder.add_kernel_feature("debug-print");
|
|
builder.add_loader_feature("resume");
|
|
// It is important that this is the first service added, because the swapper *must* be in PID 2
|
|
builder.add_service("xous-swapper", LoaderRegion::Flash);
|
|
builder.add_kernel_feature("swap");
|
|
|
|
for service in swap_pkgs {
|
|
builder.add_service(service, LoaderRegion::Flash);
|
|
}
|
|
let swap_pkgs = [
|
|
"xous-names",
|
|
"trng",
|
|
"graphics-server",
|
|
"llio",
|
|
"early_settings", // required by keyboard
|
|
"spinor",
|
|
"keyboard",
|
|
"gam",
|
|
"modals",
|
|
"ime-plugin-shell",
|
|
"ime-frontend",
|
|
"test-swapper",
|
|
// "bao1x-console",
|
|
]
|
|
.to_vec();
|
|
for service in swap_pkgs {
|
|
builder.add_service(service, LoaderRegion::Swap);
|
|
}
|
|
|
|
builder.add_apps(get_cratespecs());
|
|
}
|
|
|
|
// ------- hosted mode configs -------
|
|
Some("run") => {
|
|
builder
|
|
.target_hosted()
|
|
.add_services(&user_pkgs)
|
|
.add_feature("pddbtest")
|
|
.add_feature("ditherpunk")
|
|
.add_feature("tls")
|
|
// .add_feature("test-rekey")
|
|
.add_apps(&get_cratespecs());
|
|
}
|
|
Some("baosec-emu") => {
|
|
let bao_pkgs = [
|
|
"xous-ticktimer",
|
|
"keystore",
|
|
"xous-log",
|
|
"xous-names",
|
|
"usb-bao1x",
|
|
"bao1x-emu",
|
|
"bao-console",
|
|
"modals",
|
|
"pddb",
|
|
"bao-video",
|
|
"vault2",
|
|
];
|
|
builder.add_feature("pddbtest");
|
|
builder
|
|
// hosted-baosec feature added below
|
|
.target_hosted_baosec()
|
|
.add_services(&bao_pkgs)
|
|
.add_apps(&get_cratespecs());
|
|
|
|
// safe because xtask is single-threaded - the build to setup the emulation run is strictly
|
|
// single-threaded the read of the variable will be multi-threaded, but it will be set
|
|
// by that point in time.
|
|
unsafe {
|
|
std::env::set_var("UUID", "1234567812345678123456781234567812345678123456781234567812345678");
|
|
}
|
|
// builder.add_feature("modal-testing");
|
|
}
|
|
Some("pddb-ci") => {
|
|
builder
|
|
.target_hosted()
|
|
.add_services(&user_pkgs)
|
|
.add_feature("pddb/ci")
|
|
.add_feature("pddb/pddbtest")
|
|
.add_feature("pddb/autobasis")
|
|
.add_feature("pddb/deterministic");
|
|
}
|
|
Some("pddb-btest") => {
|
|
builder
|
|
.target_hosted()
|
|
.add_services(&user_pkgs)
|
|
.add_feature("pddbtest")
|
|
.add_feature("autobasis") // this will make secret basis tracking synthetic and automated for stress testing
|
|
.add_feature("autobasis-ci")
|
|
.add_feature("pddb/deterministic");
|
|
}
|
|
Some("hosted-debug") => {
|
|
builder
|
|
.target_hosted()
|
|
.add_services(&user_pkgs)
|
|
.add_feature("pddbtest")
|
|
.add_feature("ditherpunk")
|
|
.add_feature("tracking-alloc")
|
|
.add_feature("tls")
|
|
.stream(BuildStream::Debug)
|
|
.add_apps(&get_cratespecs());
|
|
}
|
|
Some("gfx-dev") => {
|
|
builder
|
|
.target_hosted()
|
|
.add_services(&gfx_base_pkgs)
|
|
.add_services(&get_cratespecs())
|
|
.add_feature("graphics-server/gfx-testing");
|
|
}
|
|
Some("hosted-ci") => {
|
|
builder.target_hosted().add_services(&user_pkgs).hosted_build_only().add_apps(&get_cratespecs());
|
|
}
|
|
Some("hosted-bao1x-ci") => {
|
|
let bao_pkgs = [
|
|
"xous-ticktimer",
|
|
"keystore",
|
|
"xous-log",
|
|
"xous-names",
|
|
"bao1x-emu",
|
|
"bao-console",
|
|
"modals",
|
|
"pddb",
|
|
"bao-video",
|
|
"vault2",
|
|
];
|
|
builder
|
|
.target_hosted_baosec()
|
|
.add_services(&bao_pkgs)
|
|
.hosted_build_only()
|
|
.add_apps(&get_cratespecs());
|
|
}
|
|
|
|
// ------ Precursor hardware image configs ------
|
|
Some("app-image") => {
|
|
builder
|
|
.target_precursor(PRECURSOR_SOC_VERSION)
|
|
.add_services(&user_pkgs)
|
|
.add_feature("mass-storage") // add this in by default to help with testing
|
|
.add_apps(&get_cratespecs());
|
|
}
|
|
Some("app-image-xip") => {
|
|
builder
|
|
.target_precursor(PRECURSOR_SOC_VERSION)
|
|
//.add_services(&user_pkgs)
|
|
.add_feature("mass-storage"); // add this in by default to help with testing
|
|
for service in user_pkgs {
|
|
if (service != "shellchat") && (service != "ime-plugin-shell" && (service != "net")) {
|
|
builder.add_service(service, LoaderRegion::Ram);
|
|
} else {
|
|
builder.add_service(service, LoaderRegion::Flash);
|
|
}
|
|
}
|
|
for app in get_cratespecs() {
|
|
builder.add_app(&app, LoaderRegion::Flash);
|
|
}
|
|
}
|
|
Some("perf-image") => {
|
|
// `--feature vaultperf` will make `vault` the performance manager, in exclusion of shellchat
|
|
if !builder.has_feature("shellperf") && !builder.has_feature("vaultperf") {
|
|
// select `shellchat` as the performance manager by default.
|
|
builder.add_feature("shellperf");
|
|
}
|
|
// note: to use this image, you need to load a version of the SOC that has the performance
|
|
// counters built in. this can be generated using the command `python3
|
|
// .\betrusted_soc.py -e .\dummy.nky --perfcounter` in the betrusted-soc repo.
|
|
//
|
|
// to read out performance monitoring data, use the `usb_update.py` script as follows:
|
|
// ` python3 .\..\usb_update.py --dump v2p.txt --dump-file .\ring_aes_8.bin`
|
|
// where the `v2p.txt` file contains a virtual to physical mapping that is generated by the
|
|
// `perflib` framework and formatted in a fashion that can be automatically extracted
|
|
// by the usb_update script.
|
|
builder
|
|
.target_precursor("c809403-perflib")
|
|
.add_services(&user_pkgs)
|
|
.add_apps(&get_cratespecs())
|
|
.add_feature("perfcounter")
|
|
.add_kernel_feature("v2p");
|
|
}
|
|
Some("dvt-image") => {
|
|
// this image targets a mostly deprecated DVT hardware generation. The purpose of it is to re-use
|
|
// some of the now-defunct hardware for eFuse code testing, especially since FPGAs
|
|
// have gotten very scarce. Once the eFuse path is validated, we could remove this
|
|
// target.
|
|
let mut services: Vec<String> = user_pkgs.into_iter().map(String::from).collect();
|
|
services.retain(|x| x != "codec"); // codec is not compatible with DVT boards
|
|
|
|
builder
|
|
.target_precursor("2753c12-dvt")
|
|
.add_services(&services)
|
|
.add_feature("no-codec")
|
|
.add_feature("dvt")
|
|
.add_apps(&get_cratespecs());
|
|
}
|
|
Some("tts") => {
|
|
builder.target_precursor(PRECURSOR_SOC_VERSION);
|
|
|
|
let mut pkgs = user_pkgs.to_vec();
|
|
pkgs.push("tts-frontend");
|
|
pkgs.push("ime-plugin-tts");
|
|
pkgs.retain(|&pkg| pkg != "ime-plugin-shell");
|
|
|
|
builder.add_services(&pkgs)
|
|
.add_apps(&get_cratespecs())
|
|
.add_service("espeak-embedded#https://ci.betrusted.io/job/espeak-embedded/lastSuccessfulBuild/artifact/target/riscv32imac-unknown-xous-elf/release/espeak-embedded",
|
|
LoaderRegion::Ram)
|
|
.override_locale("en-tts")
|
|
.add_feature("tts")
|
|
.add_feature("braille");
|
|
}
|
|
Some("tiny") => {
|
|
builder
|
|
.target_precursor(PRECURSOR_SOC_VERSION)
|
|
.add_services(&base_pkgs)
|
|
.add_services(&get_cratespecs());
|
|
}
|
|
Some("usbdev") => {
|
|
builder
|
|
.target_precursor(PRECURSOR_SOC_VERSION)
|
|
.add_services(&base_pkgs)
|
|
.add_services(&get_cratespecs());
|
|
//builder.add_service("usb-test");
|
|
builder.add_service("usb-device-xous", LoaderRegion::Ram);
|
|
}
|
|
Some("pddb-dev") => {
|
|
builder
|
|
.target_precursor(PRECURSOR_SOC_VERSION)
|
|
.add_services(&pddb_dev_pkgs)
|
|
.add_services(&get_cratespecs());
|
|
}
|
|
Some("trng-test") => {
|
|
builder
|
|
.target_precursor(PRECURSOR_SOC_VERSION)
|
|
.add_services(&user_pkgs)
|
|
.add_feature("urandomtest");
|
|
}
|
|
Some("ro-test") => {
|
|
builder
|
|
.target_precursor(PRECURSOR_SOC_VERSION)
|
|
.add_services(&user_pkgs)
|
|
.add_feature("ringosctest");
|
|
}
|
|
Some("av-test") => {
|
|
builder
|
|
.target_precursor(PRECURSOR_SOC_VERSION)
|
|
.add_services(&user_pkgs)
|
|
.add_feature("avalanchetest");
|
|
}
|
|
Some("compile-apps") => {
|
|
builder.target_precursor_no_image(PRECURSOR_SOC_VERSION).add_services(&gfx_base_pkgs);
|
|
}
|
|
|
|
// ------ bao1x hardware image configs ------
|
|
Some("bao1x-sim") | Some("bao1x") => {
|
|
match task.as_deref() {
|
|
Some("bao1x") => {
|
|
let board = "board-dabao";
|
|
// select the board
|
|
builder.add_feature(board);
|
|
builder.add_loader_feature(board);
|
|
builder.add_kernel_feature(board);
|
|
}
|
|
Some("bao1x-sim") => {
|
|
let board = "board-dabao";
|
|
// select the board
|
|
builder.add_feature(board);
|
|
builder.add_loader_feature(board);
|
|
builder.add_kernel_feature(board);
|
|
builder.kernel_disable_defaults(); // need to turn of kernel DUART exclusive access so console can work!
|
|
}
|
|
_ => panic!("unhandled configuration"),
|
|
};
|
|
|
|
// placement in flash is a tension between dev convenience and RAM usage. Things in flash
|
|
// are resident, non-swapable, but end up making the slow kernel burn process take longer.
|
|
let bao1x_flash_pkgs = [
|
|
"xous-log",
|
|
"xous-names",
|
|
"xous-ticktimer",
|
|
"bao1x-mbox1",
|
|
"bao1x-mbox2", /* "bao1x-hal-service" */
|
|
]
|
|
.to_vec();
|
|
let bao1x_swap_pkgs = [].to_vec();
|
|
|
|
builder.add_loader_feature("debug-print");
|
|
builder.add_loader_feature("verilator-only");
|
|
// builder.add_kernel_feature("debug-print");
|
|
// builder.add_kernel_feature("debug-swap-verbose");
|
|
|
|
// builder.add_feature("quantum-timer");
|
|
// builder.add_feature("auto-trng"); // automatically initialize TRNG tester inside USB stack
|
|
builder.add_kernel_feature("v2p");
|
|
builder.add_kernel_feature("verilator-only");
|
|
// builder.add_feature("mass-storage");
|
|
// builder.add_feature("ditherpunk");
|
|
|
|
builder.add_loader_feature("sram-margin");
|
|
match task.as_deref() {
|
|
Some("bao1x-sim") => builder.target_bao1x_soc(),
|
|
Some("bao1x") => builder.target_bao1x_soc(),
|
|
_ => panic!("should be unreachable"),
|
|
};
|
|
|
|
for service in bao1x_flash_pkgs {
|
|
builder.add_service(service, LoaderRegion::Flash);
|
|
}
|
|
builder.add_services(&get_cratespecs());
|
|
for service in bao1x_swap_pkgs {
|
|
builder.add_service(service, LoaderRegion::Swap);
|
|
}
|
|
}
|
|
|
|
Some("baremetal-artybio") => {
|
|
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 =
|
|
cargo(&cargo_configs).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("baremetal-artyvexii") => {
|
|
builder.set_baremetal(true);
|
|
builder.target_artyvexii();
|
|
}
|
|
|
|
Some("baremetal-bao1x") | Some("bao1x-baremetal-baosec") => {
|
|
let board = "board-baosec";
|
|
builder.set_board(board);
|
|
builder.add_loader_feature(board);
|
|
builder.add_loader_feature("bao1x-usb");
|
|
let sigblock_size = bao1x_api::signatures::SIGBLOCK_LEN;
|
|
update_flash_origin(
|
|
"baremetal/src/platform/bao1x/link.x",
|
|
(bao1x_api::BAREMETAL_START + sigblock_size + STATICS_LEN) as u32,
|
|
)?;
|
|
builder.set_baremetal(true).target_baremetal_bao1x("baremetal").set_sigblock_size(sigblock_size);
|
|
}
|
|
|
|
Some("bao1x-baremetal-dabao") => {
|
|
let board = "board-dabao";
|
|
builder.set_board(board);
|
|
builder.add_loader_feature(board);
|
|
builder.add_loader_feature("bao1x-usb");
|
|
let sigblock_size = bao1x_api::signatures::SIGBLOCK_LEN;
|
|
update_flash_origin(
|
|
"baremetal/src/platform/bao1x/link.x",
|
|
(bao1x_api::BAREMETAL_START + sigblock_size + STATICS_LEN) as u32,
|
|
)?;
|
|
builder.set_baremetal(true).target_baremetal_bao1x("baremetal").set_sigblock_size(sigblock_size);
|
|
}
|
|
|
|
Some("baremetal-bao1x-evb") => {
|
|
let sigblock_size = bao1x_api::signatures::SIGBLOCK_LEN;
|
|
update_flash_origin(
|
|
"baremetal/src/platform/bao1x/link.x",
|
|
(0x6100_0000 + sigblock_size + STATICS_LEN) as u32,
|
|
)?;
|
|
builder.set_baremetal(true);
|
|
builder.add_loader_feature("bao1x-evb");
|
|
builder.set_sigblock_size(sigblock_size);
|
|
builder.target_baremetal_bao1x("baremetal");
|
|
}
|
|
|
|
Some("bao1x-boot0") => {
|
|
let sigblock_size = bao1x_api::signatures::SIGBLOCK_LEN;
|
|
update_flash_origin(
|
|
"bao1x-boot/boot0/link.x",
|
|
(bao1x_api::BOOT0_START + sigblock_size + STATICS_LEN) as u32,
|
|
)?;
|
|
builder
|
|
.set_baremetal(true)
|
|
.target_baremetal_bao1x("bao1x-boot0")
|
|
.set_sigblock_size(sigblock_size);
|
|
}
|
|
|
|
Some("bao1x-boot1") => {
|
|
let sigblock_size = bao1x_api::signatures::SIGBLOCK_LEN;
|
|
update_flash_origin(
|
|
"bao1x-boot/boot1/src/platform/bao1x/link.x",
|
|
(bao1x_api::BOOT1_START + sigblock_size + STATICS_LEN) as u32,
|
|
)?;
|
|
// builder.add_loader_feature("unsafe-debug");
|
|
builder
|
|
.set_baremetal(true)
|
|
.target_baremetal_bao1x("bao1x-boot1")
|
|
.set_sigblock_size(sigblock_size);
|
|
}
|
|
|
|
Some("bao1x-alt-boot1") => {
|
|
let sigblock_size = bao1x_api::signatures::SIGBLOCK_LEN;
|
|
update_flash_origin(
|
|
"bao1x-boot/boot1/src/platform/bao1x/link.x",
|
|
(bao1x_api::LOADER_START + sigblock_size + STATICS_LEN) as u32,
|
|
)?;
|
|
builder.add_loader_feature("alt-boot1");
|
|
// builder.add_loader_feature("force-dabao");
|
|
builder
|
|
.set_baremetal(true)
|
|
.target_baremetal_bao1x("bao1x-alt-boot1")
|
|
.set_sigblock_size(sigblock_size);
|
|
}
|
|
|
|
Some("bao1x-boot1-lite") => {
|
|
let sigblock_size = bao1x_api::signatures::SIGBLOCK_LEN;
|
|
update_flash_origin(
|
|
"bao1x-boot/boot1/src/platform/bao1x/link.x",
|
|
(bao1x_api::BOOT1_START + sigblock_size + STATICS_LEN) as u32,
|
|
)?;
|
|
// builder.add_loader_feature("unsafe-debug");
|
|
builder
|
|
.set_baremetal(true)
|
|
.target_baremetal_bao1x("bao1x-boot1")
|
|
.add_loader_feature("oem-baosec-lite")
|
|
.set_sigblock_size(sigblock_size);
|
|
}
|
|
|
|
Some("bao1x-alt-boot1-lite") => {
|
|
let sigblock_size = bao1x_api::signatures::SIGBLOCK_LEN;
|
|
update_flash_origin(
|
|
"bao1x-boot/boot1/src/platform/bao1x/link.x",
|
|
(bao1x_api::LOADER_START + sigblock_size + STATICS_LEN) as u32,
|
|
)?;
|
|
builder.add_loader_feature("alt-boot1");
|
|
// builder.add_loader_feature("force-dabao");
|
|
builder
|
|
.set_baremetal(true)
|
|
.target_baremetal_bao1x("bao1x-alt-boot1")
|
|
.add_loader_feature("oem-baosec-lite")
|
|
.set_sigblock_size(sigblock_size);
|
|
}
|
|
|
|
Some("baosec") => {
|
|
baosec_common(&mut builder)?;
|
|
}
|
|
|
|
Some("baosec-lite") => {
|
|
baosec_common(&mut builder)?;
|
|
builder.add_feature("oem-baosec-lite");
|
|
builder.add_loader_feature("oem-baosec-lite");
|
|
}
|
|
|
|
Some("baosec-improper-keystore") => {
|
|
let board = "board-baosec";
|
|
let sigblock_size = bao1x_api::signatures::SIGBLOCK_LEN;
|
|
update_flash_origin(
|
|
"loader/src/platform/bao1x/link.x",
|
|
(bao1x_api::LOADER_START + sigblock_size + STATICS_LEN) as u32,
|
|
)?;
|
|
// select the board
|
|
builder.set_board(board);
|
|
builder.add_feature(board);
|
|
builder.add_loader_feature(board);
|
|
builder.add_kernel_feature(board);
|
|
builder.set_sigblock_size(sigblock_size);
|
|
|
|
let bao_rram_pkgs = [
|
|
"xous-ticktimer",
|
|
"xous-log",
|
|
"xous-names",
|
|
"usb-bao1x",
|
|
"bao1x-hal-service",
|
|
"bao-console",
|
|
"keystore", // deliberately out of order
|
|
"bao-video",
|
|
]
|
|
.to_vec();
|
|
if !builder.is_swap_set() {
|
|
// reserve 3MiB for system services: ultimately, "pddb, modals, and bao-video"
|
|
builder.set_swap(0, bao1x_api::offsets::baosec::SWAP_RAM_LEN as _);
|
|
}
|
|
builder.add_loader_feature("swap");
|
|
builder.add_kernel_feature("swap");
|
|
builder.add_feature("swap");
|
|
|
|
builder.add_loader_feature("debug-print");
|
|
builder.add_kernel_feature("v2p");
|
|
builder.target_bao1x_soc();
|
|
|
|
// It is important that this is the first service added, because the swapper *must* be in PID 2
|
|
builder.add_service("xous-swapper", LoaderRegion::Flash);
|
|
|
|
for service in bao_rram_pkgs {
|
|
builder.add_service(service, LoaderRegion::Flash);
|
|
}
|
|
builder.add_services(&get_cratespecs());
|
|
}
|
|
|
|
Some("dabao") => {
|
|
let board = "board-dabao";
|
|
let sigblock_size = bao1x_api::signatures::SIGBLOCK_LEN;
|
|
update_flash_origin(
|
|
"loader/src/platform/bao1x/link.x",
|
|
(bao1x_api::LOADER_START + sigblock_size + STATICS_LEN) as u32,
|
|
)?;
|
|
// select the board
|
|
builder.set_board(board);
|
|
builder.add_feature(board);
|
|
builder.add_loader_feature(board);
|
|
builder.add_kernel_feature(board);
|
|
builder.add_detached_app_feature(board);
|
|
builder.set_sigblock_size(sigblock_size);
|
|
|
|
// minimal set of services for app development on a dabao. Need to save space for the app itself!
|
|
let bao_rram_pkgs =
|
|
["xous-ticktimer", "keystore", "xous-log", "xous-names", "usb-bao1x", "bao1x-hal-service"]
|
|
.to_vec();
|
|
let bao_app_pkgs: Vec<&'static str> = [].to_vec();
|
|
|
|
builder.add_loader_feature("debug-print");
|
|
builder.add_kernel_feature("v2p");
|
|
builder.add_kernel_feature("print-panics");
|
|
builder.add_kernel_feature("debug-proc");
|
|
match task.as_deref() {
|
|
Some("dabao") => builder.target_bao1x_soc(),
|
|
_ => panic!("should be unreachable"),
|
|
};
|
|
|
|
for service in bao_rram_pkgs {
|
|
builder.add_service(service, LoaderRegion::Flash);
|
|
}
|
|
builder.add_apps(&bao_app_pkgs);
|
|
|
|
for app in get_cratespecs() {
|
|
let (name, region) = crate::builder::region_from_name(&app, LoaderRegion::Flash);
|
|
builder.add_app(name, region);
|
|
}
|
|
}
|
|
|
|
// ------ ARM hardware image configs ------
|
|
Some("arm-tiny") => {
|
|
builder
|
|
.target_arm()
|
|
.add_services([
|
|
"xous-log",
|
|
"xous-ticktimer",
|
|
"xous-names",
|
|
"ticktimer-test-client",
|
|
])
|
|
.add_kernel_feature("v2p") // required to use LCD DMA with lcd-console
|
|
.add_feature("atsama5d27")
|
|
.add_feature("lcd-console")
|
|
.add_services(&get_cratespecs())
|
|
.stream(BuildStream::Release);
|
|
}
|
|
|
|
// ---- other single-purpose commands ----
|
|
Some("generate-locales") => generate_locales(&cargo_configs)?,
|
|
Some("wycheproof-import") => wycheproof_import(&cargo_configs)?,
|
|
Some("dummy-template") => generate_app_menus(&Vec::new()),
|
|
task => {
|
|
if let Some(task) = task {
|
|
eprintln!("error: task {task:?} not recognized");
|
|
}
|
|
|
|
print_help();
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
// clean up any duplicates - this is an artifact of wanting to include dabao-console
|
|
// as a "default app" to make behavior more intuitive for beginners trying out dabao,
|
|
// but also wanting to list it in the UI as an app so that developers are /aware/ of
|
|
// dabao-console as an app they can modify. Simply hiding it by sticking it in the services
|
|
// directory makes in hard to discover. Maybe this will be changed to handle it entirely
|
|
// at the UI layer but anyways - this avoids accidental duplicate processes which is a good thing
|
|
// in general.
|
|
builder.deduplicate_processes();
|
|
builder.build()?;
|
|
|
|
// the intent of this call is to check that crates we are sourcing from crates.io
|
|
// match the crates in our local source. The usual cause of an inconsistency is
|
|
// a maintainer forgot to publish a change to crates.io.
|
|
//
|
|
// Note a key problem is that we don't check that the Cargo.toml files are correct,
|
|
// because the manifest format is heavily modified on upload to crates.io.
|
|
// This means that an attacker who controlls crates.io (or any part of the chain
|
|
// from manifest upload to download) can freely modify dependencies, rendering
|
|
// source code equivalence checking moot.
|
|
//
|
|
// this has to be called after the build because the crates need to be downloaded for
|
|
// checking before you can check them!
|
|
let do_verify = env::args().filter(|x| x == "--no-verify").count() == 0;
|
|
if do_verify {
|
|
match check_project_consistency() {
|
|
Ok(()) => Ok(()),
|
|
Err(e) => {
|
|
// Explain to developers why this step is important.
|
|
println!(
|
|
"Local source changes have not been published. If you meant to modify core components,"
|
|
);
|
|
println!(
|
|
"activate patches in top-level Cargo.toml to redirect crates.io to the local source tree."
|
|
);
|
|
println!("Otherwise, your local changes are IGNORED.");
|
|
println!("Use the `--no-verify` argument to suppress this warning.");
|
|
Err(e)
|
|
}
|
|
}
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
fn print_help() {
|
|
eprintln!(
|
|
"cargo xtask [verb] [cratespecs ..]
|
|
[--feature [feature name]]
|
|
[--loader-feature [loader feature name]]
|
|
[--kernel-feature [kernel feature name]]
|
|
[--app-feature [detached app feature name]]
|
|
[--lkey [loader key]] [--kkey [kernel key]]
|
|
[--swap [offset:size]]
|
|
[--app [cratespec]]
|
|
[--service [cratespec]]
|
|
[--no-timestamp]
|
|
[--no-verify]
|
|
[--gdb-stub]
|
|
[--debug-loader]
|
|
[--offline]
|
|
[--change-target]
|
|
[--git-describe version]
|
|
[--git-rev commit]
|
|
|
|
[cratespecs] is a list of 0 or more items of the following syntax:
|
|
[name] crate 'name' to be built from local source
|
|
[name@version] crate 'name' to be fetched from crates.io at the specified version
|
|
[name#URL] pre-built binary crate of 'name' downloaded from a server at 'URL'
|
|
[path-to-binary] file path to a prebuilt binary image on local machine.
|
|
Files in '.' must be specified as './file' to avoid confusion with local source
|
|
[name:path-to-binary] file path to a prebuilt binary image on local machine which will be renamed.
|
|
This is useful if the binary image is an app since the name will be required
|
|
for registration with the gam.
|
|
Files in '.' must be specified as './file' to avoid confusion with local source
|
|
|
|
The [cratespecs] list is treated as apps or services based on the context of [verb]. Additional crates can
|
|
be merged in with explicit app/service treatment with the following flags:
|
|
[--app] [cratespec] [cratespec] is treated as an additional app
|
|
[--service] [cratespec] [cratespec] is treated as an additional service
|
|
|
|
[--lkey] and [--kkey] Paths to alternate private key files for loader and kernel key signing (defaults to developer key)
|
|
[--no-timestamp] Do not include a timestamp in the build. By default, `ticktimer` is rebuilt on every run to encode a timestamp.
|
|
[--no-verify] Do not verify that local sources match crates.io downloaded sources
|
|
[--gdb-stub] Build the kernel with GDB support
|
|
[--debug-loader] Enable debug printing in the loader
|
|
[--offline] Avoid network traffic
|
|
[--swap offset:size] Specify a region for swap memory. The behavior of this depends on the target.
|
|
[--change-target] Used to clean the cached target/*/*/build/SVD_PATH when changing build targets.
|
|
This will also force a full rebuild every time the flag is specified.
|
|
[--git-describe version] Force a git describe version string (e.g., 'v0.10.0-19-g0d934e1') instead of running `git describe --long`. For build systems that lack git state.
|
|
Note: there is no sanity checking on the passed version. If it's specified incorrectly, subtle, weird things could happen.
|
|
[--git-rev commit] Force a git commit hash (e.g., '0d934e1...') for swap image nonce. Required with --git-describe for reproducible builds.
|
|
|
|
- An 'app' must be enumerated in apps/manifest.json.
|
|
A pre-processor configures the launch menu based on the list of specified apps.
|
|
- A 'service' is merged into the device image without any pre-processing.
|
|
|
|
[verb] options:
|
|
Hardware images:
|
|
app-image-xip Precursor user image with XIP (frees more RAM for apps). [cratespecs] are apps
|
|
app-image Precursor user image (all services in RAM). [cratespecs] are apps
|
|
perf-image Precursor user image, with performance profiling. [cratespecs] are apps
|
|
tts builds an image with text to speech support via externally linked C executable. [cratespecs] are apps
|
|
usbdev minimal, insecure build for new USB core bring-up. [cratespecs] are services
|
|
trng-test automation framework for TRNG testing (CPRNG seeded by RO^AV). [cratespecs] ignored.
|
|
ro-test automation framework for TRNG testing (RO directly, no CPRNG). [cratespecs] ignored.
|
|
av-test automation framework for TRNG testing (AV directly, no CPRNG). [cratespecs] ignored.
|
|
tiny Precursor tiny image. For testing with services built out-of-tree.
|
|
baosec Baosec application target image.
|
|
dabao Dabao application target image.
|
|
bao1x-baremetal-baosec Baremetal image for baosec boards.
|
|
bao1x-baremetal-dabao Baremetal image for dabao boards.
|
|
bao1x-boot0 Boot0 partition for baochip1x targets.
|
|
bao1x-boot1 Boot1 partition for baochip1x targets.
|
|
bao1x-alt-boot1 Alterante boot1 partition for baochip1x targets. Burns into the 'loader/baremetal' region
|
|
and allows for updating of boot1 when this partition is active.
|
|
|
|
Hosted emulation:
|
|
run Run user image in hosted mode with release flags. [cratespecs] are apps
|
|
baosec-emu Run user image in hosted mode but for the baosec target
|
|
pddb-ci PDDB config for CI testing (eg: TRNG->deterministic for reproducible errors). [cratespecs] ignored.
|
|
pddb-btest PDDB stress tester for secret basis creation/deletion [cratespecs] ignored.
|
|
hosted-debug Run user image in hosted mode with debug flags. [cratespecs] are apps
|
|
gfx-dev Testing mode for graphics primitives. [cratespecs] are services
|
|
pddb-dev Testing for compilation errors on hardware targets on the PDDB.
|
|
hosted-ci Check that precursor hosted mode isn't broken
|
|
hosted-bao1x-ci Check that bao1x hosted mode isn't broken
|
|
|
|
Renode emulation:
|
|
renode-image Renode user image. Unspecified [cratespecs] are apps
|
|
renode-test Renode test image. Unspecified [cratespecs] are services
|
|
renode-image-debug Renode user image with --debug flag set
|
|
libstd-test Renode test image that includes the minimum packages. [cratespecs] are services
|
|
Bypasses sig checks, keys locked out.
|
|
libstd-net Renode test image for testing network functions. Bypasses sig checks, keys locked out.
|
|
ffi-test builds an image for testing C-FFI bindings and integration. [cratespecs] are services
|
|
renode-aes-test Renode image for AES emulation development. Extremely minimal.
|
|
|
|
Other commands:
|
|
generate-locales (re)generate the locales include for the language selected in locales/src/locale.rs
|
|
wycheproof-import generate binary test vectors for engine-25519 from whycheproof-import/x25519.json
|
|
install-toolkit installs Xous toolkit with no prompt, useful in CI. Specify `--force` to remove existing toolchains
|
|
compile-apps Just compiles the apps specified in [cratespecs], for example in order to use app server
|
|
dummy-template Generate dummy templates for formatting and checking purposes
|
|
|
|
Note: By default, the `ticktimer` will get rebuilt every time. You can skip this by appending `--no-timestamp` to the command.
|
|
"
|
|
)
|
|
}
|
|
|
|
type DynError = Box<dyn std::error::Error>;
|
|
|
|
/// [cratespecs] are positional arguments, and is a list of 0 to N tokens that immediately
|
|
/// follow [verb]
|
|
fn get_cratespecs() -> Vec<String> {
|
|
let mut cratespecs = Vec::<String>::new();
|
|
let mut args = env::args();
|
|
args.nth(1); // skip the verb
|
|
for arg in args {
|
|
if arg.starts_with('-') {
|
|
// stop processing the list as soon as first named argument is found
|
|
break;
|
|
}
|
|
cratespecs.push(arg)
|
|
}
|
|
cratespecs
|
|
}
|
|
|
|
fn get_flag(flag: &str) -> Result<Vec<String>, DynError> {
|
|
let mut list = Vec::<String>::new();
|
|
let args = env::args();
|
|
let mut flag_found = false;
|
|
for arg in args {
|
|
if arg == flag {
|
|
flag_found = true;
|
|
continue;
|
|
}
|
|
if flag_found {
|
|
if arg.starts_with('-') {
|
|
eprintln!("Malformed arguments. Expected argument after flag {}, but found {}", flag, arg);
|
|
return Err("Bad arguments".into());
|
|
}
|
|
list.push(arg);
|
|
flag_found = false;
|
|
continue;
|
|
}
|
|
}
|
|
Ok(list)
|
|
}
|
|
|
|
fn setup_curve25519_backend(features: &Vec<String>) {
|
|
// Determine workspace root (xtask assumed to be in subdir)
|
|
let workspace_root = locate_workspace_root().expect("Failed to find workspace root");
|
|
let config_path = workspace_root.join(".cargo/config.toml");
|
|
|
|
// assume that the system has the curve25519 accelerator if it's not the vexii-test config
|
|
let has_accelerator = !features.contains(&"vexii-test".to_string());
|
|
|
|
// Desired cfg value
|
|
let desired_cfg = if has_accelerator {
|
|
"curve25519_dalek_backend=\"u32e_backend\""
|
|
} else {
|
|
"curve25519_dalek_backend=\"u32_backend\""
|
|
};
|
|
|
|
// Read original lines
|
|
let original = fs::read_to_string(&config_path).expect("Failed to read config.toml");
|
|
let mut modified = false;
|
|
let mut in_target = false;
|
|
|
|
let lines: Vec<String> = original
|
|
.lines()
|
|
.map(|line| {
|
|
let trimmed = line.trim();
|
|
|
|
// Detect section
|
|
if trimmed.starts_with("[target.") && trimmed.contains("riscv32imac-unknown-xous-elf") {
|
|
in_target = true;
|
|
return line.to_string();
|
|
}
|
|
|
|
if in_target && trimmed.starts_with('[') && trimmed != "[target.riscv32imac-unknown-xous-elf]" {
|
|
in_target = false; // exited the block
|
|
}
|
|
|
|
if in_target && trimmed.starts_with("rustflags") {
|
|
if trimmed.contains(desired_cfg) {
|
|
return line.to_string(); // already correct
|
|
}
|
|
|
|
// Replace line with correct cfg
|
|
modified = true;
|
|
return format!(r#"rustflags = ["--cfg", '{}']"#, desired_cfg);
|
|
}
|
|
|
|
line.to_string()
|
|
})
|
|
.collect();
|
|
|
|
// Only write if modified
|
|
if modified {
|
|
fs::write(&config_path, lines.join("\n")).expect("Failed to write config.toml");
|
|
println!("Updated .cargo/config.toml");
|
|
} else {
|
|
println!("No change needed in .cargo/config.toml");
|
|
}
|
|
}
|
|
|
|
/// Traverse upward to find workspace root (directory with `.cargo/config.toml`)
|
|
fn locate_workspace_root() -> Option<PathBuf> {
|
|
let mut dir = env::current_dir().ok()?;
|
|
while !dir.join(".cargo/config.toml").exists() {
|
|
if !dir.pop() {
|
|
return None;
|
|
}
|
|
}
|
|
Some(dir)
|
|
}
|
|
|
|
fn update_flash_origin<P: AsRef<Path>>(path: P, new_origin: u32) -> std::io::Result<()> {
|
|
let content = fs::read_to_string(&path)?;
|
|
let updated = content
|
|
.lines()
|
|
.map(|line| {
|
|
if line.trim_start().starts_with("FLASH") && line.contains("ORIGIN") {
|
|
let parts: Vec<&str> = line.split(',').collect();
|
|
let origin_part = format!("ORIGIN = 0x{:08X}", new_origin);
|
|
let length_part = parts.iter().find(|s| s.trim().starts_with("LENGTH")).unwrap_or(&"");
|
|
format!(" FLASH : {}, {}", origin_part, length_part.trim())
|
|
} else {
|
|
line.to_string()
|
|
}
|
|
})
|
|
.collect::<Vec<String>>()
|
|
.join("\n");
|
|
|
|
fs::write(path, updated)?;
|
|
Ok(())
|
|
}
|
|
|
|
fn baosec_common(builder: &mut Builder) -> std::io::Result<()> {
|
|
let board = "board-baosec";
|
|
let sigblock_size = bao1x_api::signatures::SIGBLOCK_LEN;
|
|
update_flash_origin(
|
|
"loader/src/platform/bao1x/link.x",
|
|
(bao1x_api::LOADER_START + sigblock_size + STATICS_LEN) as u32,
|
|
)?;
|
|
// select the board
|
|
builder.set_board(board);
|
|
builder.add_feature(board);
|
|
builder.add_loader_feature(board);
|
|
builder.add_kernel_feature(board);
|
|
builder.set_sigblock_size(sigblock_size);
|
|
|
|
// placement in flash is a tension between dev convenience and RAM usage. Things in flash
|
|
// are resident, non-swapable, but end up making the slow kernel burn process take longer.
|
|
// Layout:
|
|
// - kernel, ticktimer, log, names, swapper are essential services and stay resident. Must be <1 MiB
|
|
// total.
|
|
// - usb-bao1x is latency-sensitive and runs a handler in a non-swappable IRQ context, and thus cannot
|
|
// be swapped out. It contains the USB stack and API layer. It needs to maintain a mutex with
|
|
// bao-video as the camera cannot run simultaneously with the USB stack due to sharing of the IFRAM
|
|
// space.
|
|
// - bao1x-hal-service contains all the non-latency sensitive hardware APIs
|
|
// - bao-video pulls camera + display + qr decoding into a single package single memory space to
|
|
// optimize performance. Must maintain a mutex with usb-bao1x on the camera IFRAM space.
|
|
// - bao-console is the serial debug console handler
|
|
// - [planned] pddb server
|
|
// - [planned] vault application
|
|
let bao_rram_pkgs = [
|
|
"xous-ticktimer",
|
|
"xous-log",
|
|
"xous-names",
|
|
"usb-bao1x",
|
|
"bao1x-hal-service",
|
|
"modals",
|
|
"pddb",
|
|
"bao-video",
|
|
]
|
|
.to_vec();
|
|
let bao_swap_pkgs = [].to_vec();
|
|
if !builder.is_swap_set() {
|
|
// reserve 3MiB for system services: ultimately, "pddb, modals, and bao-video"
|
|
builder.set_swap(0, bao1x_api::offsets::baosec::SWAP_RAM_LEN as _);
|
|
}
|
|
builder.add_loader_feature("swap");
|
|
builder.add_kernel_feature("print-panics");
|
|
builder.add_kernel_feature("swap");
|
|
builder.add_feature("swap");
|
|
|
|
builder.add_loader_feature("debug-print");
|
|
// the following feature needs to be uncommented if we also enable
|
|
// debug-print-swapper inside xous-swapper
|
|
if false {
|
|
builder.add_loader_feature("userspace-swap-debug");
|
|
builder.add_feature("debug-print-swapper");
|
|
// use this to enable debug in USB, when the package is selected
|
|
// builder.add_feature("debug-print-usb");
|
|
} else {
|
|
}
|
|
// builder.add_kernel_feature("debug-swap");
|
|
// builder.add_kernel_feature("debug-print");
|
|
// builder.add_kernel_feature("debug-swap-verbose");
|
|
// builder.add_feature("quantum-timer"); // this isn't in bao1x..
|
|
builder.add_kernel_feature("v2p");
|
|
builder.target_bao1x_soc();
|
|
|
|
// It is important that this is the first service added, because the swapper *must* be in PID 2
|
|
builder.add_service("xous-swapper", LoaderRegion::Flash);
|
|
// It is important that this is the second service added, as keystore *must* be in PID 3
|
|
// (as constrained by the coreuser setting that is locked out by the time Xous runs)
|
|
builder.add_service("keystore", LoaderRegion::Flash);
|
|
|
|
for service in bao_rram_pkgs {
|
|
builder.add_service(service, LoaderRegion::Flash);
|
|
}
|
|
for service in bao_swap_pkgs {
|
|
builder.add_service(service, LoaderRegion::Swap);
|
|
}
|
|
|
|
for app in get_cratespecs() {
|
|
let (name, region) = crate::builder::region_from_name(&app, LoaderRegion::Swap);
|
|
builder.add_service(name, region);
|
|
}
|
|
// builder.add_feature("modal-testing");
|
|
Ok(())
|
|
}
|