Kaynağa Gözat

Merge pull request #40 from guttatus/xtask

workflow(prototyper): Use cargo-xtask instead of cargo-make
guttatus 4 ay önce
ebeveyn
işleme
085540a878

+ 4 - 0
.cargo/config.toml

@@ -0,0 +1,4 @@
+[alias]
+xtask = "run --package xtask --release --"
+prototyper = "xtask prototyper"
+test-kernel = "xtask test"

+ 199 - 0
Cargo.lock

@@ -8,6 +8,55 @@ version = "0.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a01ba40421eca6c4f1afcedd8465fba6d9e5ef8e0e13060d0141e4cded4ab4a"
 checksum = "8a01ba40421eca6c4f1afcedd8465fba6d9e5ef8e0e13060d0141e4cded4ab4a"
 
 
+[[package]]
+name = "anstream"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
+dependencies = [
+ "anstyle",
+ "windows-sys",
+]
+
 [[package]]
 [[package]]
 name = "autocfg"
 name = "autocfg"
 version = "1.4.0"
 version = "1.4.0"
@@ -26,6 +75,52 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 
+[[package]]
+name = "clap"
+version = "4.5.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+
 [[package]]
 [[package]]
 name = "critical-section"
 name = "critical-section"
 version = "1.2.0"
 version = "1.2.0"
@@ -50,6 +145,18 @@ version = "0.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7fbe69badc2e0dc98ad2787648fa140b5772d24b49e9a6b180a67e1348f7544c"
 checksum = "7fbe69badc2e0dc98ad2787648fa140b5772d24b49e9a6b180a67e1348f7544c"
 
 
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
 [[package]]
 [[package]]
 name = "lock_api"
 name = "lock_api"
 version = "0.4.12"
 version = "0.4.12"
@@ -276,6 +383,12 @@ dependencies = [
  "lock_api",
  "lock_api",
 ]
 ]
 
 
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
 [[package]]
 [[package]]
 name = "syn"
 name = "syn"
 version = "2.0.89"
 version = "2.0.89"
@@ -308,6 +421,12 @@ version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
 checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
 
 
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
 [[package]]
 [[package]]
 name = "vcell"
 name = "vcell"
 version = "0.1.3"
 version = "0.1.3"
@@ -322,3 +441,83 @@ checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"
 dependencies = [
 dependencies = [
  "vcell",
  "vcell",
 ]
 ]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "xtask"
+version = "0.1.0"
+dependencies = [
+ "clap",
+]

+ 2 - 1
Cargo.toml

@@ -3,7 +3,8 @@ resolver = "2"
 members = [
 members = [
   "prototyper",
   "prototyper",
   "test-kernel",
   "test-kernel",
-  "supervisor"
+  "supervisor", 
+  "xtask"
 ]
 ]
 
 
 [workspace.package]
 [workspace.package]

+ 0 - 68
Makefile.toml

@@ -1,68 +0,0 @@
-[config]
-default_to_workspace = false
-
-[tasks.clean]
-command = "cargo"
-args = ["clean"]
-
-[tasks.prototyper-nemu-build]
-command = "cargo"
-args = ["build", "-prustsbi-prototyper", "--release", "--target", "riscv64imac-unknown-none-elf", "-Zbuild-std=core", "--features=nemu,payload"]
-env = {"RUSTFLAGS"="-C relocation-model=pie -C link-arg=-pie" }
-
-[tasks.prototyper-nemu]
-command = "rust-objcopy"
-args = [
-        "--binary-architecture=riscv64",
-        "target/riscv64imac-unknown-none-elf/release/rustsbi-prototyper",
-        "--output-target=binary",
-        "target/riscv64imac-unknown-none-elf/release/rustsbi-prototyper.bin",
-]
-dependencies = ["prototyper-nemu-build"]
-
-[tasks.prototyper-build]
-command = "cargo"
-args = [
-        "build",
-        "-prustsbi-prototyper",
-        "--release",
-        "--target",
-        "riscv64imac-unknown-none-elf",
-        "-Zbuild-std=core",
-]
-env = { "RUSTFLAGS" = "-C relocation-model=pie -C link-arg=-pie" }
-
-[tasks.prototyper]
-command = "rust-objcopy"
-args = [
-        "--binary-architecture=riscv64",
-        "target/riscv64imac-unknown-none-elf/release/rustsbi-prototyper",
-        "--output-target=binary",
-        "target/riscv64imac-unknown-none-elf/release/rustsbi-prototyper.bin",
-]
-dependencies = ["prototyper-build"]
-
-[tasks.test-kernel-build]
-command = "cargo"
-args = ["build", "-prustsbi-test-kernel", "--release"]
-env = { "RUSTFLAGS"= { unset = true }}
-
-[tasks.test-kernel]
-command = "rust-objcopy"
-args = [
-        "--binary-architecture=riscv64",
-        "target/riscv64imac-unknown-none-elf/release/rustsbi-test-kernel",
-        "--output-target=binary",
-        "target/riscv64imac-unknown-none-elf/release/rustsbi-test-kernel.bin",
-]
-dependencies = ["test-kernel-build"]
-
-[tasks.test-kernel-itb]
-script = '''
-cp test-kernel/scripts/rustsbi-test-kernel.its target/riscv64imac-unknown-none-elf/release
-cd target/riscv64imac-unknown-none-elf/release/
-mkimage -f rustsbi-test-kernel.its  rustsbi-test-kernel.itb
-rm rustsbi-test-kernel.its
-cd ../../../
-'''
-dependencies = ["prototyper", "test-kernel"]

+ 0 - 8
README.md

@@ -4,14 +4,6 @@ RustSBI Prototyper is a developing RISC-V Secure Bootloader solution. It can be
 
 
 ## Setting Up the Development Environment
 ## Setting Up the Development Environment
 
 
-### Install Cargo Make
-
-Cargo Make is a Rust task runner and build tool, which is essential for development.
-
-```bash
-cargo install cargo-make
-```
-
 ### Optional Tools
 ### Optional Tools
 
 
 The following tools are not mandatory but can be useful for enhancing your development experience.
 The following tools are not mandatory but can be useful for enhancing your development experience.

+ 1 - 1
docs/booting-fedora-in-qemu-using-uboot-and-rustsbi.md

@@ -51,7 +51,7 @@ $ cd prototyper
 编译RustSBI  Prototyper
 编译RustSBI  Prototyper
 
 
 ``` shell
 ``` shell
-$ cargo make prototyper
+$ cargo prototyper
 ```
 ```
 
 
 ## 编译U-Boot SPL
 ## 编译U-Boot SPL

+ 1 - 1
docs/booting-freebsd-in-qemu-using-uboot-and-rustsbi.md

@@ -93,7 +93,7 @@ $ cd prototyper
 编译RustSBI  Prototyper
 编译RustSBI  Prototyper
 
 
 ``` shell
 ``` shell
-$ cargo make prototyper
+$ cargo prototyper
 ```
 ```
 
 
 ## 编译U-Boot SPL
 ## 编译U-Boot SPL

+ 1 - 1
docs/booting-linux-kernel-in-qemu-using-uboot-and-rustsbi.md

@@ -280,7 +280,7 @@ $ cd prototyper
 编译RustSBI  Prototyper
 编译RustSBI  Prototyper
 
 
 ``` shell
 ``` shell
-$ cargo make prototyper
+$ cargo prototyper
 ```
 ```
 
 
 ## 编译U-Boot SPL
 ## 编译U-Boot SPL

+ 1 - 1
docs/booting-openEuler-23.09-in-qemu-using-uboot-and-rustsbi.md

@@ -50,7 +50,7 @@ $ cd prototyper
 编译RustSBI  Prototyper
 编译RustSBI  Prototyper
 
 
 ``` shell
 ``` shell
-$ cargo make prototyper
+$ cargo prototyper
 ```
 ```
 
 
 ## 编译U-Boot SPL
 ## 编译U-Boot SPL

+ 1 - 1
docs/booting-openwrt-in-qemu-using-uboot-and-rustsbi.md

@@ -56,7 +56,7 @@ $ cd prototyper
 编译RustSBI  Prototyper
 编译RustSBI  Prototyper
 
 
 ``` shell
 ``` shell
-$ cargo make prototyper
+$ cargo prototyper
 ```
 ```
 
 
 ## 编译U-Boot SPL
 ## 编译U-Boot SPL

+ 1 - 1
docs/booting-polyos-in-qemu-using-uboot-and-rustsbi.md

@@ -20,7 +20,7 @@ $ cd prototyper
 编译RustSBI  Prototyper
 编译RustSBI  Prototyper
 
 
 ``` shell
 ``` shell
-$ cargo make prototyper
+$ cargo prototyper
 ```
 ```
 
 
 ### Clone & Compile U-Boot
 ### Clone & Compile U-Boot

+ 2 - 1
docs/booting-test-kernel-in-qemu-using-uboot-and-rustsbi.md

@@ -103,7 +103,8 @@ $ cd prototyper
 编译RustSBI Prototyper和Test Kernel
 编译RustSBI Prototyper和Test Kernel
 
 
 ``` shell
 ``` shell
-$ cargo make test-kernel-itb
+$ cargo prototyper
+$ cargo test-kernel --pack
 ```
 ```
 
 
 本小节将使用二进制文件 `./target/riscv64imac-unknown-none-elf/release/rustsbi-test-kernel.itb`。
 本小节将使用二进制文件 `./target/riscv64imac-unknown-none-elf/release/rustsbi-test-kernel.itb`。

+ 1 - 1
docs/booting-ubuntu-24.04.1-in-qemu-using-uboot-and-rustsbi.md

@@ -53,7 +53,7 @@ $ cd prototyper
 编译RustSBI  Prototyper
 编译RustSBI  Prototyper
 
 
 ``` shell
 ``` shell
-$ cargo make prototyper
+$ cargo prototyper
 ```
 ```
 
 
 ## 编译U-Boot SPL
 ## 编译U-Boot SPL

+ 2 - 2
prototyper/src/platform/payload.rs

@@ -24,7 +24,7 @@ pub fn get_boot_info(_nonstandard_a2: usize) -> BootInfo {
 #[link_section = ".fw_fdt"]
 #[link_section = ".fw_fdt"]
 pub unsafe extern "C" fn raw_fdt() {
 pub unsafe extern "C" fn raw_fdt() {
     asm!(
     asm!(
-        concat!(".incbin \"", env!("PROTOTYPER_FDT"), "\""),
+        concat!(".incbin \"", env!("PROTOTYPER_FDT_PATH"), "\""),
         options(noreturn)
         options(noreturn)
     );
     );
 }
 }
@@ -33,7 +33,7 @@ pub unsafe extern "C" fn raw_fdt() {
 #[link_section = ".payload"]
 #[link_section = ".payload"]
 pub unsafe extern "C" fn payload_image() {
 pub unsafe extern "C" fn payload_image() {
     asm!(
     asm!(
-        concat!(".incbin \"", env!("PROTOTYPER_IMAGE"), "\""),
+        concat!(".incbin \"", env!("PROTOTYPER_PAYLOAD_PATH"), "\""),
         options(noreturn)
         options(noreturn)
     );
     );
 }
 }

+ 9 - 0
xtask/Cargo.toml

@@ -0,0 +1,9 @@
+[package]
+name = "xtask"
+version = "0.1.0"
+edition.workspace = true
+license.workspace = true
+repository.workspace = true
+
+[dependencies]
+clap = { version = "4.5.4", features = ["derive", "env", "suggestions"] }

+ 40 - 0
xtask/src/main.rs

@@ -0,0 +1,40 @@
+use std::process::ExitCode;
+use clap::{Parser, Subcommand};
+
+#[macro_use]
+mod utils;
+mod prototyper;
+mod test;
+
+
+use crate::prototyper::PrototyperArg;
+use crate::test::TestArg;
+
+#[derive(Parser)]
+#[clap(
+    name = "xtask",
+    about = "A task runner for building, running and testing Prototyper",
+    long_about = None,
+)]
+struct Cli {
+    #[clap(subcommand)]
+    cmd: Cmd,
+}
+
+#[derive(Subcommand)]
+enum Cmd {
+    Prototyper(PrototyperArg),
+    Test(TestArg),
+}
+
+fn main() -> ExitCode {
+    if let Some(code) = match Cli::parse().cmd {
+        Cmd::Prototyper(ref arg) => prototyper::run(arg),
+        Cmd::Test(ref arg) => test::run(arg),
+    } {
+        if code.success() {
+            return ExitCode::SUCCESS;
+        }
+    }
+    ExitCode::FAILURE
+}

+ 68 - 0
xtask/src/prototyper.rs

@@ -0,0 +1,68 @@
+use std::{
+    env,
+    process::{Command, ExitStatus},
+};
+
+use clap::Args;
+
+use crate::utils::cargo;
+use crate::utils::CmdOptional;
+
+#[derive(Debug, Args, Clone)]
+pub struct PrototyperArg {
+    #[clap(long, short = 'f')]
+    pub features: Vec<String>,
+
+    #[clap(long, env = "PROTOTYPER_FDT_PATH")]
+    pub fdt: Option<String>,
+
+    #[clap(long, env = "PROTOTYPER_PAYLOAD_PATH")]
+    pub payload: Option<String>,
+}
+
+#[must_use]
+pub fn run(arg: &PrototyperArg) -> Option<ExitStatus> {
+    let arch = "riscv64imac-unknown-none-elf";
+    let fdt = arg.fdt.clone();
+    let payload = arg.payload.clone();
+
+    cargo::Cargo::new("build")
+        .package("rustsbi-prototyper")
+        .target(arch)
+        .unstable("build-std", ["core"])
+        .env("RUSTFLAGS", "-C relocation-model=pie -C link-arg=-pie")
+        .features(&arg.features)
+        .optional(arg.fdt.is_some(), |cargo| {
+            export_env!("PROTOTYPER_FDT_PATH" ?= fdt.unwrap());
+            cargo.features(["fdt".to_string()])
+        })
+        .optional(payload.is_some(), |cargo| {
+            export_env!("PROTOTYPER_PAYLOAD_PATH" ?= payload.unwrap());
+            cargo.features(["payload".to_string()])
+        })
+        .release()
+        .status()
+        .ok()?;
+
+    Command::new("rust-objcopy")
+        .args(["-O", "binary"])
+        .arg("--binary-architecture=riscv64")
+        .arg(
+            env::current_dir()
+                .unwrap()
+                .join("target")
+                .join(arch.to_string())
+                .join("release")
+                .join("rustsbi-prototyper"),
+        )
+        .arg(
+            env::current_dir()
+                .unwrap()
+                .join("target")
+                .join(arch.to_string())
+                .join("release")
+                .join("rustsbi-prototyper.bin"),
+        )
+        .status()
+        .ok()
+}

+ 72 - 0
xtask/src/test.rs

@@ -0,0 +1,72 @@
+use std::{
+    env, fs,
+    process::{Command, ExitStatus},
+};
+
+use clap::Args;
+
+use crate::utils::cargo;
+
+#[derive(Debug, Args, Clone)]
+pub struct TestArg {
+    /// Package Prototyper and Test-Kernel
+    #[clap(long)]
+    pub pack: bool,
+}
+
+#[must_use]
+pub fn run(arg: &TestArg) -> Option<ExitStatus> {
+    let arch = "riscv64imac-unknown-none-elf";
+    let current_dir = env::current_dir();
+    let target_dir = current_dir
+        .as_ref()
+        .unwrap()
+        .join("target")
+        .join(arch.to_string())
+        .join("release");
+
+    cargo::Cargo::new("build")
+        .package("rustsbi-test-kernel")
+        .target(arch)
+        .release()
+        .status()
+        .ok()?;
+
+    let exit_status = Command::new("rust-objcopy")
+        .args(["-O", "binary"])
+        .arg("--binary-architecture=riscv64")
+        .arg(target_dir.join("rustsbi-test-kernel"))
+        .arg(target_dir.join("rustsbi-test-kernel.bin"))
+        .status()
+        .ok()?;
+
+    if arg.pack {
+        match fs::exists(target_dir.join("rustsbi-prototyper.bin")) {
+            Ok(true) => {}
+            Ok(false) => {
+                panic!(" Couldn't open \"rustsbi-prototyper.bin\": No such file or directory. Please compile Prototyper first");
+            }
+            Err(_) => {
+                panic!("Can't check existence of file rustsbi-prototyper.bin, please compile Prototyper first");
+            }
+        }
+        fs::copy(
+            current_dir
+                .as_ref()
+                .unwrap()
+                .join("test-kernel")
+                .join("scripts")
+                .join("rustsbi-test-kernel.its"),
+            target_dir.join("rustsbi-test-kernel.its"),
+        )
+        .ok()?;
+        env::set_current_dir(&target_dir).ok()?;
+        Command::new("mkimage")
+            .args(["-f", "rustsbi-test-kernel.its"])
+            .arg("rustsbi-test-kernel.itb")
+            .status()
+            .ok()?;
+        fs::remove_file(env::current_dir().unwrap().join("rustsbi-test-kernel.its")).ok()?;
+    }
+    Some(exit_status)
+}

+ 105 - 0
xtask/src/utils/cargo.rs

@@ -0,0 +1,105 @@
+use std::{
+    ffi::OsStr,
+    ops::{Deref, DerefMut},
+    path::Path,
+    process::Command,
+};
+
+use super::CmdOptional;
+
+pub struct Cargo {
+    cmd: Command,
+}
+
+#[allow(unused)]
+impl Cargo {
+    pub fn new(action: &str) -> Self {
+        let mut cmd = Command::new(env!("CARGO"));
+        cmd.arg(action);
+        Self { cmd }
+    }
+
+    pub fn package<S: AsRef<OsStr>>(&mut self, package: S) -> &mut Self {
+        self.args(["--package", package.as_ref().to_str().unwrap()]);
+        self
+    }
+
+    pub fn work_dir<S: AsRef<Path>>(&mut self, dir: S) -> &mut Self {
+        self.current_dir(dir);
+        self
+    }
+
+    pub fn release(&mut self) -> &mut Self {
+        self.arg("--release");
+        self
+    }
+
+    pub fn target<S: AsRef<OsStr>>(&mut self, target: S) -> &mut Self {
+        self.args(["--target", target.as_ref().to_str().unwrap()]);
+        self
+    }
+
+    pub fn features<I, S>(&mut self, features: I) -> &mut Self
+    where
+        I: IntoIterator<Item = S>,
+        S: AsRef<OsStr>,
+    {
+        self.args([
+            "--features",
+            features
+                .into_iter()
+                .map(|f| f.as_ref().to_str().unwrap().to_string())
+                .collect::<Vec<_>>()
+                .join(",")
+                .as_ref(),
+        ]);
+        self
+    }
+
+    pub fn no_default_features(&mut self) -> &mut Self {
+        self.arg("--no-default-features");
+        self
+    }
+
+    pub fn unstable<I, S>(&mut self, key: S, values: I) -> &mut Self
+    where
+        I: IntoIterator<Item = S>,
+        S: AsRef<OsStr>,
+    {
+        self.arg(format!(
+            "-Z{}={}",
+            key.as_ref().to_str().unwrap(),
+            values
+                .into_iter()
+                .map(|f| f.as_ref().to_str().unwrap().to_string())
+                .collect::<Vec<_>>()
+                .join(",")
+        ));
+        self
+    }
+
+    pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self
+    where
+        K: AsRef<OsStr>,
+        V: AsRef<OsStr>,
+    {
+        self.cmd.env(key, value);
+        self
+    }
+}
+
+impl CmdOptional for Cargo {}
+
+impl Deref for Cargo {
+    type Target = Command;
+
+    fn deref(&self) -> &Self::Target {
+        &self.cmd
+    }
+}
+
+impl DerefMut for Cargo {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.cmd
+    }
+}

+ 13 - 0
xtask/src/utils/envs.rs

@@ -0,0 +1,13 @@
+macro_rules! export_env {
+    ($env:literal ?= $val:expr) => {
+        if std::env::vars_os().all(|(k, _)| k != $env) {
+            std::env::set_var($env, $val);
+        }
+    };
+    ($env0:literal ?= $val0:expr, $($env:literal ?= $val:expr,)+) => {
+        export_env!($env0 ?= $val0);
+        $(
+            export_env!($env ?= $val);
+        )+
+    };
+}

+ 13 - 0
xtask/src/utils/mod.rs

@@ -0,0 +1,13 @@
+pub mod cargo; 
+
+#[macro_use]
+pub mod envs;
+
+pub trait CmdOptional {
+    fn optional(&mut self, pred: bool, f: impl FnOnce(&mut Self) -> &mut Self) -> &mut Self {
+        if pred {
+            f(self);
+        }
+        self
+    }
+}