mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-08 04:56:43 +00:00
882 lines
38 KiB
Rust
882 lines
38 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;
|
|
|
|
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";
|
|
|
|
// 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;
|
|
generate_version(do_version);
|
|
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: offset 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")?;
|
|
let mut language_set = false;
|
|
for feature in features {
|
|
builder.add_feature(&feature);
|
|
if feature.starts_with("xous/lang-") {
|
|
track_language_changes(&feature)?;
|
|
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);
|
|
}
|
|
|
|
if !language_set {
|
|
// the default language is english
|
|
track_language_changes("en")?;
|
|
}
|
|
let gdb_stub = env::args().filter(|x| x == "--gdb-stub").count() != 0;
|
|
if gdb_stub {
|
|
builder.add_kernel_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();
|
|
}
|
|
|
|
// manage an ugly patch we have to do to selectively configure AES for only cramium-soc targets
|
|
match builder::search_in_file("services/aes/Cargo.toml", "default = []") {
|
|
Ok(false) => {
|
|
builder::search_and_replace_in_file(
|
|
"services/aes/Cargo.toml",
|
|
"default = [\"cramium-soc\"]",
|
|
"default = []",
|
|
)
|
|
.expect("couldn't patch AES");
|
|
|
|
// revert these just in case - but don't throw an error if the strings aren't found
|
|
builder::search_and_replace_in_file(
|
|
"Cargo.toml",
|
|
"# [patch.crates-io.curve25519-dalek]",
|
|
"[patch.crates-io.curve25519-dalek]",
|
|
)
|
|
.ok();
|
|
builder::search_and_replace_in_file(
|
|
"Cargo.toml",
|
|
"# git = \"https://github.com/betrusted-io/curve25519-dalek.git\"",
|
|
"git = \"https://github.com/betrusted-io/curve25519-dalek.git\"",
|
|
)
|
|
.ok();
|
|
builder::search_and_replace_in_file(
|
|
"Cargo.toml",
|
|
"# branch = \"main\" # c25519",
|
|
"branch = \"main\" # c25519",
|
|
)
|
|
.ok();
|
|
builder::search_and_replace_in_file(
|
|
"services/root-keys/Cargo.toml",
|
|
"# features = [\"auto-release\", \"warn-fallback\"]",
|
|
"features = [\"auto-release\", \"warn-fallback\"]",
|
|
)
|
|
.ok();
|
|
builder::search_and_replace_in_file(
|
|
"services/shellchat/Cargo.toml",
|
|
"# features = [\"auto-release\", \"warn-fallback\"]",
|
|
"features = [\"auto-release\", \"warn-fallback\"]",
|
|
)
|
|
.ok();
|
|
|
|
match builder::search_in_file("services/aes/Cargo.toml", "default = []") {
|
|
Ok(false) => {
|
|
return Err(
|
|
"Couldn't revert services/aes/Cargo.toml -- is the file writeable or corrupted?"
|
|
.into(),
|
|
);
|
|
}
|
|
_ => (),
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
let mut broken_aes_cleanup = false;
|
|
|
|
// ---- 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_cramium_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",
|
|
"cram-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", "xous-log", "xous-names", "modals", "bao-video", "cramium-emu"];
|
|
builder
|
|
// hosted-baosec feature added below
|
|
.target_hosted_baosec()
|
|
.add_services(&bao_pkgs)
|
|
.add_apps(&get_cratespecs());
|
|
}
|
|
Some("pddb-ci") => {
|
|
builder
|
|
.target_hosted()
|
|
.add_services(&user_pkgs)
|
|
.add_feature("pddb/ci")
|
|
.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());
|
|
}
|
|
|
|
// ------ 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);
|
|
}
|
|
|
|
// ------ Cramium hardware image configs ------
|
|
Some("cramium-sim") | Some("cramium-soc") => {
|
|
match task.as_deref() {
|
|
Some("cramium-soc") => {
|
|
let board = "board-dabao";
|
|
// select the board
|
|
builder.add_feature(board);
|
|
builder.add_loader_feature(board);
|
|
builder.add_kernel_feature(board);
|
|
}
|
|
_ => (), // don't add any board because this is simulation
|
|
};
|
|
|
|
// 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 cramium_flash_pkgs =
|
|
["xous-log", "xous-names", "cram-mbox1", "cram-mbox2" /* "cram-hal-service" */].to_vec();
|
|
let cramium_swap_pkgs = [].to_vec();
|
|
|
|
builder.add_loader_feature("debug-print");
|
|
// 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_feature("mass-storage");
|
|
// builder.add_feature("ditherpunk");
|
|
|
|
builder.add_loader_feature("sram-margin");
|
|
match task.as_deref() {
|
|
Some("cramium-sim") => builder.target_cramium_fpga(),
|
|
Some("cramium-soc") => builder.target_cramium_soc(),
|
|
_ => panic!("should be unreachable"),
|
|
};
|
|
broken_aes_cleanup = true;
|
|
|
|
for service in cramium_flash_pkgs {
|
|
builder.add_service(service, LoaderRegion::Flash);
|
|
}
|
|
builder.add_services(&get_cratespecs());
|
|
for service in cramium_swap_pkgs {
|
|
builder.add_service(service, LoaderRegion::Swap);
|
|
}
|
|
}
|
|
|
|
Some("baosec") => {
|
|
let board = "board-baosec";
|
|
// select the board
|
|
builder.add_feature(board);
|
|
builder.add_loader_feature(board);
|
|
builder.add_kernel_feature(board);
|
|
|
|
// 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-cramium 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.
|
|
// - cram-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-cramium 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-cramium" */].to_vec(); /* "usb-cramium" */
|
|
let bao_swap_pkgs = ["cram-hal-service", "bao-console", "bao-video"].to_vec(); /* "bao-video" */
|
|
if !builder.is_swap_set() {
|
|
builder.set_swap(0, 8 * 1024 * 1024);
|
|
}
|
|
builder.add_loader_feature("swap");
|
|
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 NTO..
|
|
builder.add_kernel_feature("v2p");
|
|
builder.add_loader_feature("sram-margin");
|
|
builder.add_loader_feature("usb");
|
|
builder.add_loader_feature("updates");
|
|
match task.as_deref() {
|
|
Some("baosec") => builder.target_cramium_soc(),
|
|
_ => panic!("should be unreachable"),
|
|
};
|
|
broken_aes_cleanup = true;
|
|
|
|
// 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());
|
|
for service in bao_swap_pkgs {
|
|
builder.add_service(service, LoaderRegion::Swap);
|
|
}
|
|
}
|
|
|
|
// ------ 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()?,
|
|
Some("wycheproof-import") => wycheproof_import()?,
|
|
Some("dummy-template") => generate_app_menus(&Vec::new()),
|
|
_ => print_help(),
|
|
}
|
|
builder.build()?;
|
|
|
|
// AES is broken in the current rev of the Cramium SoC. This unpatches the crate so other builds can
|
|
// work properly.
|
|
if broken_aes_cleanup {
|
|
builder::search_and_replace_in_file(
|
|
"services/aes/Cargo.toml",
|
|
"default = [\"cramium-soc\"]",
|
|
"default = []",
|
|
)
|
|
.expect("couldn't patch AES");
|
|
builder::search_and_replace_in_file(
|
|
"Cargo.toml",
|
|
"# [patch.crates-io.curve25519-dalek]",
|
|
"[patch.crates-io.curve25519-dalek]",
|
|
)
|
|
.expect("couldn't patch curve25519");
|
|
builder::search_and_replace_in_file(
|
|
"Cargo.toml",
|
|
"# git = \"https://github.com/betrusted-io/curve25519-dalek.git\"",
|
|
"git = \"https://github.com/betrusted-io/curve25519-dalek.git\"",
|
|
)
|
|
.expect("couldn't patch curve25519");
|
|
builder::search_and_replace_in_file(
|
|
"Cargo.toml",
|
|
"# branch = \"main\" # c25519",
|
|
"branch = \"main\" # c25519",
|
|
)
|
|
.expect("couldn't patch curve25519");
|
|
builder::search_and_replace_in_file(
|
|
"services/root-keys/Cargo.toml",
|
|
"# features = [\"auto-release\", \"warn-fallback\"]",
|
|
"features = [\"auto-release\", \"warn-fallback\"]",
|
|
)
|
|
.expect("couldn't patch rootkeys");
|
|
builder::search_and_replace_in_file(
|
|
"services/shellchat/Cargo.toml",
|
|
"# features = [\"auto-release\", \"warn-fallback\"]",
|
|
"features = [\"auto-release\", \"warn-fallback\"]",
|
|
)
|
|
.expect("couldn't patch shellchat");
|
|
}
|
|
match builder::search_in_file("services/aes/Cargo.toml", "default = []") {
|
|
Ok(false) => {
|
|
println!(
|
|
"Build configuration is out of sync: cramium-soc patch on AES crate was not cleared out"
|
|
);
|
|
return Err("services/aes/Cargo.toml is in a bad state! Revert any patches to the file.".into());
|
|
}
|
|
_ => {}
|
|
}
|
|
// 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]]
|
|
[--lkey [loader key]] [--kkey [kernel key]]
|
|
[--swap [offset:size]]
|
|
[--app [cratespec]]
|
|
[--service [cratespec]]
|
|
[--no-timestamp]
|
|
[--no-verify]
|
|
[--gdb-stub]
|
|
[--debug-loader]
|
|
[--offline]
|
|
[--change-target]
|
|
|
|
[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.
|
|
|
|
- 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.
|
|
cramium-soc BSP validation image for Cramium. Contains a superset of features, in various states of testing.
|
|
cramium-sim Tiny target for verilator simulation
|
|
baosec Baosec application target image.
|
|
|
|
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.
|
|
|
|
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)
|
|
}
|