mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-15 16:26:48 +00:00
Implement bundle content digest and cache
This commit is contained in:
parent
a685253a1a
commit
d98ed8cec1
2
Makefile
2
Makefile
@ -97,7 +97,7 @@ KTEST_TESTABLE := \
|
|||||||
all: build
|
all: build
|
||||||
|
|
||||||
install_osdk:
|
install_osdk:
|
||||||
@cargo install cargo-osdk --path osdk --force
|
@cargo install cargo-osdk --path osdk
|
||||||
|
|
||||||
build:
|
build:
|
||||||
@make --no-print-directory -C regression
|
@make --no-print-directory -C regression
|
||||||
|
78
osdk/Cargo.lock
generated
78
osdk/Cargo.lock
generated
@ -86,6 +86,15 @@ version = "2.4.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bstr"
|
name = "bstr"
|
||||||
version = "1.9.1"
|
version = "1.9.1"
|
||||||
@ -131,10 +140,17 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"sha2",
|
||||||
"toml",
|
"toml",
|
||||||
"which",
|
"which",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.1"
|
version = "4.5.1"
|
||||||
@ -181,12 +197,41 @@ 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 = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "difflib"
|
name = "difflib"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
|
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "doc-comment"
|
name = "doc-comment"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@ -238,6 +283,16 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.3"
|
version = "0.14.3"
|
||||||
@ -460,6 +515,17 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
@ -518,6 +584,12 @@ dependencies = [
|
|||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.12"
|
version = "1.0.12"
|
||||||
@ -530,6 +602,12 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wait-timeout"
|
name = "wait-timeout"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -18,6 +18,7 @@ log = "0.4.20"
|
|||||||
regex = "1.10.3"
|
regex = "1.10.3"
|
||||||
serde = { version = "1.0.195", features = ["derive"] }
|
serde = { version = "1.0.195", features = ["derive"] }
|
||||||
serde_json = "1.0.111"
|
serde_json = "1.0.111"
|
||||||
|
sha2 = "0.10.8"
|
||||||
toml = { version = "0.8.8", features = ["preserve_order"] }
|
toml = { version = "0.8.8", features = ["preserve_order"] }
|
||||||
which = "6.0.0"
|
which = "6.0.0"
|
||||||
|
|
||||||
|
@ -15,15 +15,25 @@ OSDK (short for Operating System Development Kit) is designed to simplify the de
|
|||||||
|
|
||||||
Currenly, `cargo-osdk` only supports x86_64 ubuntu system.
|
Currenly, `cargo-osdk` only supports x86_64 ubuntu system.
|
||||||
|
|
||||||
`cargo-osdk` requires the following tools to be installed:
|
To run a kernel with QEMU, `cargo-osdk` requires the following tools to be installed:
|
||||||
- Rust >= 1.75.0
|
- Rust >= 1.75.0
|
||||||
- Gcc compiler
|
- cargo-binutils
|
||||||
|
- gcc
|
||||||
|
- qemu-system-x86_64
|
||||||
|
- grub-mkrescue
|
||||||
|
- ovmf
|
||||||
|
- xorriso
|
||||||
|
|
||||||
About how to install Rust, you can refer to the [official site](https://www.rust-lang.org/tools/install).
|
About how to install Rust, you can refer to the [official site](https://www.rust-lang.org/tools/install).
|
||||||
|
|
||||||
Gcc compiler can be installed by
|
After installing Rust, you can install Cargo tools by
|
||||||
```bash
|
```bash
|
||||||
apt install build-essential
|
cargo install cargo-binutils
|
||||||
|
```
|
||||||
|
|
||||||
|
Other tools can be installed by
|
||||||
|
```bash
|
||||||
|
apt install build-essential grub2-common qemu-system-x86 ovmf xorriso
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Install
|
#### Install
|
||||||
@ -44,17 +54,6 @@ cargo install --force cargo-osdk
|
|||||||
|
|
||||||
Here we provide a simple demo to demonstrate how to create and run a simple kernel with `cargo-osdk`.
|
Here we provide a simple demo to demonstrate how to create and run a simple kernel with `cargo-osdk`.
|
||||||
|
|
||||||
Suppose you are on a x86_64 ubuntu machine, to run a kernel with QEMU, the following tools should be installed:
|
|
||||||
- qemu-system-x86_64
|
|
||||||
- grub-mkrescue
|
|
||||||
- ovmf
|
|
||||||
- xorriso
|
|
||||||
|
|
||||||
If these tools are missing, they can be installed by
|
|
||||||
```bash
|
|
||||||
apt install grub2-common qemu-system-x86 ovmf xorriso
|
|
||||||
```
|
|
||||||
|
|
||||||
With `cargo-osdk`, a kernel project can be created by one command
|
With `cargo-osdk`, a kernel project can be created by one command
|
||||||
```bash
|
```bash
|
||||||
cargo osdk new --kernel my-first-os
|
cargo osdk new --kernel my-first-os
|
||||||
@ -105,15 +104,17 @@ ovmf = "/usr/bin/ovmf" # <7>
|
|||||||
path = "/usr/bin/qemu-system-x86_64" # <8>
|
path = "/usr/bin/qemu-system-x86_64" # <8>
|
||||||
machine = "q35" # <9>
|
machine = "q35" # <9>
|
||||||
args = [ # <10>
|
args = [ # <10>
|
||||||
"--enable-kvm",
|
"-enable-kvm",
|
||||||
"-m 2G",
|
"-m 2G",
|
||||||
"--device virtio-keyboard-pci,disable-legacy=on,disable-modern=off"
|
"-device virtio-keyboard-pci,disable-legacy=on,disable-modern=off"
|
||||||
]
|
]
|
||||||
|
|
||||||
[qemu.'cfg(feature="iommu")'] # <11>
|
[qemu.'cfg(feature="iommu")'] # <11>
|
||||||
path = "/usr/local/sbin/qemu-kvm" # <8>
|
path = "/usr/local/sbin/qemu-kvm" # <8>
|
||||||
machine = "q35" # <9>
|
machine = "q35" # <9>
|
||||||
args = [ # <10>
|
args = [ # <10>
|
||||||
|
"-enable-kvm",
|
||||||
|
"-m 2G",
|
||||||
"-device virtio-keyboard-pci,disable-legacy=on,disable-modern=off,iommu_platform=on,ats=on",
|
"-device virtio-keyboard-pci,disable-legacy=on,disable-modern=off,iommu_platform=on,ats=on",
|
||||||
"-device intel-iommu,intremap=on,device-iotlb=on"
|
"-device intel-iommu,intremap=on,device-iotlb=on"
|
||||||
]
|
]
|
||||||
@ -145,18 +146,7 @@ Optional. Default is `q35`.
|
|||||||
The allowed values are `q35` and `microvm`.
|
The allowed values are `q35` and `microvm`.
|
||||||
10. Additional arguments passed to QEMU.
|
10. Additional arguments passed to QEMU.
|
||||||
Optional. The default value is empty.
|
Optional. The default value is empty.
|
||||||
Each argument should be in the form `KEY VALUE` (separated by space), or `KEY` if no value is required. Some keys can appear multiple times (e.g., `--device`, `--netdev`), while other keys can appear at most once. Certain keys, such as `-cpu` and `-machine`, are not allowed to be set here as they may conflict with the internal settings of `cargo-osdk`.
|
Each argument should be in the form `KEY VALUE` (separated by space), or `KEY` if no value is required. Some keys can appear multiple times (e.g., `-device`, `-netdev`), while other keys can appear at most once. Certain keys, such as `-cpu` and `-machine`, are not allowed to be set here as they may conflict with the internal settings of `cargo-osdk`.
|
||||||
11. Conditional QEMU settings.
|
11. Conditional QEMU settings.
|
||||||
Optional. The default value is empty.
|
Optional. The default value is empty.
|
||||||
Conditional QEMU settings allow for a condition to be specified after `qemu`. Currently, `cargo-osdk` only supports the condition `cfg(feature="FEATURE")`, which activates the QEMU settings only if the `FEATURE` is set. The `FEATURE` must be defined in the project's `Cargo.toml`. At most one conditional setting can be activated at a time. If multiple conditional settings can be activated simultaneously, `cargo-osdk` will report an error. In the future, `cargo-osdk` will support all possible conditions that [Rust conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html) supports.
|
Conditional QEMU settings allow for a condition to be specified after `qemu`. Currently, `cargo-osdk` only supports the condition `cfg(feature="FEATURE")`, which activates the QEMU settings only if the `FEATURE` is set. The `FEATURE` must be defined in the project's `Cargo.toml`. At most one conditional setting can be activated at a time. If multiple conditional settings can be activated simultaneously, `cargo-osdk` will report an error. In the future, `cargo-osdk` will support all possible conditions that [Rust conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html) supports.
|
||||||
|
|
||||||
|
|
||||||
### The framekernel architecture
|
|
||||||
|
|
||||||
The architecture divides the OS development into two distinct realms: the safe world and the unsafe world. In the safe world, only safe Rust code is allowed, while the unsafe world can tap into the power of the unsafe keyword. At the heart of the unsafe world lies `aster-frame`, a compact framework with limited functionalities. It encapsulates essential OS operations such as booting, physical memory management, context switching, and more.
|
|
||||||
|
|
||||||
With `aster-frame` as the foundation, higher-level OS functionalities like process management, file systems, network protocols, and even device drivers can be built upon it using only safe Rust. This segregation ensures that critical operations are handled securely in the unsafe realm while allowing for the development of complex and feature-rich OS components.
|
|
||||||
|
|
||||||
In addition to OS functionalities, `aster-frame` also provides development utilities, including kernel mode unit test support. The shared base of crates built on `aster-frame` allows for easy reuse and facilitates the creation of sophisticated operating systems with rich features.
|
|
||||||
|
|
||||||
Overall, this architectural approach promotes safety and modularity, empowering developers to build robust and advanced OS systems using Rust.
|
|
@ -1,33 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
pub struct AsterBin {
|
|
||||||
pub path: PathBuf,
|
|
||||||
pub typ: AsterBinType,
|
|
||||||
pub version: String,
|
|
||||||
pub sha256sum: String,
|
|
||||||
pub stripped: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
pub enum AsterBinType {
|
|
||||||
Elf(AsterElfMeta),
|
|
||||||
BzImage(AsterBzImageMeta),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
pub struct AsterElfMeta {
|
|
||||||
pub has_linux_header: bool,
|
|
||||||
pub has_pvh_header: bool,
|
|
||||||
pub has_multiboot_header: bool,
|
|
||||||
pub has_multiboot2_header: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
pub struct AsterBzImageMeta {
|
|
||||||
pub support_legacy32_boot: bool,
|
|
||||||
pub support_efi_boot: bool,
|
|
||||||
pub support_efi_handover: bool,
|
|
||||||
}
|
|
87
osdk/src/bundle/bin.rs
Normal file
87
osdk/src/bundle/bin.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fs,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::file::BundleFile;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct AsterBin {
|
||||||
|
path: PathBuf,
|
||||||
|
typ: AsterBinType,
|
||||||
|
version: String,
|
||||||
|
sha256sum: String,
|
||||||
|
stripped: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub enum AsterBinType {
|
||||||
|
Elf(AsterElfMeta),
|
||||||
|
BzImage(AsterBzImageMeta),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct AsterElfMeta {
|
||||||
|
pub has_linux_header: bool,
|
||||||
|
pub has_pvh_header: bool,
|
||||||
|
pub has_multiboot_header: bool,
|
||||||
|
pub has_multiboot2_header: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct AsterBzImageMeta {
|
||||||
|
pub support_legacy32_boot: bool,
|
||||||
|
pub support_efi_boot: bool,
|
||||||
|
pub support_efi_handover: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BundleFile for AsterBin {
|
||||||
|
fn path(&self) -> &PathBuf {
|
||||||
|
&self.path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sha256sum(&self) -> &String {
|
||||||
|
&self.sha256sum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsterBin {
|
||||||
|
pub fn new(path: impl AsRef<Path>, typ: AsterBinType, version: String, stripped: bool) -> Self {
|
||||||
|
let created = Self {
|
||||||
|
path: path.as_ref().to_path_buf(),
|
||||||
|
typ,
|
||||||
|
version,
|
||||||
|
sha256sum: String::new(),
|
||||||
|
stripped,
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
sha256sum: created.calculate_sha256sum(),
|
||||||
|
..created
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn version(&self) -> &String {
|
||||||
|
&self.version
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stripped(&self) -> bool {
|
||||||
|
self.stripped
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move the binary to the `base` directory and convert the path to a relative path.
|
||||||
|
pub fn move_to(self, base: impl AsRef<Path>) -> Self {
|
||||||
|
let file_name = self.path.file_name().unwrap();
|
||||||
|
let copied_path = base.as_ref().join(file_name);
|
||||||
|
fs::copy(&self.path, copied_path).unwrap();
|
||||||
|
fs::remove_file(&self.path).unwrap();
|
||||||
|
Self {
|
||||||
|
path: PathBuf::from(file_name),
|
||||||
|
typ: self.typ,
|
||||||
|
version: self.version,
|
||||||
|
sha256sum: self.sha256sum,
|
||||||
|
stripped: self.stripped,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
66
osdk/src/bundle/file.rs
Normal file
66
osdk/src/bundle/file.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fs, io,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
|
/// A trait for files in a bundle. The file in a bundle should have it's digest and be validatable.
|
||||||
|
pub trait BundleFile {
|
||||||
|
fn path(&self) -> &PathBuf;
|
||||||
|
|
||||||
|
fn sha256sum(&self) -> &String;
|
||||||
|
|
||||||
|
fn calculate_sha256sum(&self) -> String {
|
||||||
|
let mut file = fs::File::open(self.path()).unwrap();
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
let _n = io::copy(&mut file, &mut hasher).unwrap();
|
||||||
|
format!("{:x}", hasher.finalize())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate(&self) -> bool {
|
||||||
|
self.sha256sum() == &self.calculate_sha256sum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct Initramfs {
|
||||||
|
path: PathBuf,
|
||||||
|
sha256sum: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BundleFile for Initramfs {
|
||||||
|
fn path(&self) -> &PathBuf {
|
||||||
|
&self.path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sha256sum(&self) -> &String {
|
||||||
|
&self.sha256sum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Initramfs {
|
||||||
|
pub fn new(path: impl AsRef<Path>) -> Self {
|
||||||
|
let created = Self {
|
||||||
|
path: path.as_ref().to_path_buf(),
|
||||||
|
sha256sum: String::new(),
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
sha256sum: created.calculate_sha256sum(),
|
||||||
|
..created
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move the initramfs to the `base` directory and convert the path to a relative path.
|
||||||
|
pub fn copy_to(self, base: impl AsRef<Path>) -> Self {
|
||||||
|
let name = self.path.file_name().unwrap();
|
||||||
|
let dest = base.as_ref().join(name);
|
||||||
|
fs::copy(&self.path, dest).unwrap();
|
||||||
|
Self {
|
||||||
|
path: PathBuf::from(name),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,20 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
pub mod bin;
|
||||||
|
pub mod file;
|
||||||
|
pub mod vm_image;
|
||||||
|
|
||||||
|
use bin::AsterBin;
|
||||||
|
use file::{BundleFile, Initramfs};
|
||||||
|
use vm_image::AsterVmImage;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::Command,
|
process::Command,
|
||||||
|
time::SystemTime,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bin::AsterBin,
|
|
||||||
cli::CargoArgs,
|
cli::CargoArgs,
|
||||||
config_manager::{
|
config_manager::{
|
||||||
boot::Boot,
|
boot::Boot,
|
||||||
@ -15,7 +23,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
error::Errno,
|
error::Errno,
|
||||||
error_msg,
|
error_msg,
|
||||||
vm_image::AsterVmImage,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The osdk bundle artifact that stores as `bundle` directory.
|
/// The osdk bundle artifact that stores as `bundle` directory.
|
||||||
@ -28,39 +35,111 @@ pub struct Bundle {
|
|||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The osdk bundle artifact manifest that stores as `bundle.toml`.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct BundleManifest {
|
||||||
|
pub kcmd_args: Vec<String>,
|
||||||
|
pub initramfs: Option<Initramfs>,
|
||||||
|
pub aster_bin: Option<AsterBin>,
|
||||||
|
pub vm_image: Option<AsterVmImage>,
|
||||||
|
pub boot: Boot,
|
||||||
|
pub qemu: Qemu,
|
||||||
|
pub cargo_args: CargoArgs,
|
||||||
|
pub last_modified: SystemTime,
|
||||||
|
}
|
||||||
|
|
||||||
impl Bundle {
|
impl Bundle {
|
||||||
pub fn new(manifest: BundleManifest, path: impl AsRef<Path>) -> Self {
|
/// This function creates a new `Bundle` without adding any files.
|
||||||
|
pub fn new(
|
||||||
|
path: impl AsRef<Path>,
|
||||||
|
kcmd_args: Vec<String>,
|
||||||
|
boot: Boot,
|
||||||
|
qemu: Qemu,
|
||||||
|
cargo_args: CargoArgs,
|
||||||
|
) -> Self {
|
||||||
std::fs::create_dir_all(path.as_ref()).unwrap();
|
std::fs::create_dir_all(path.as_ref()).unwrap();
|
||||||
let created = Self {
|
let mut created = Self {
|
||||||
manifest,
|
manifest: BundleManifest {
|
||||||
|
kcmd_args,
|
||||||
|
initramfs: None,
|
||||||
|
aster_bin: None,
|
||||||
|
vm_image: None,
|
||||||
|
boot,
|
||||||
|
qemu,
|
||||||
|
cargo_args,
|
||||||
|
last_modified: SystemTime::now(),
|
||||||
|
},
|
||||||
path: path.as_ref().to_path_buf(),
|
path: path.as_ref().to_path_buf(),
|
||||||
};
|
};
|
||||||
created.write_manifest_content();
|
created.write_manifest_to_fs();
|
||||||
created
|
created
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: the load function should be used when implementing build cache, but it is not
|
// Load the bundle from the file system. If the bundle does not exist or have inconsistencies,
|
||||||
// implemented yet.
|
// it will return `None`.
|
||||||
#[allow(dead_code)]
|
pub fn load(path: impl AsRef<Path>) -> Option<Self> {
|
||||||
pub fn load(path: impl AsRef<Path>) -> Self {
|
|
||||||
let manifest_file_path = path.as_ref().join("bundle.toml");
|
let manifest_file_path = path.as_ref().join("bundle.toml");
|
||||||
let manifest_file_content = std::fs::read_to_string(manifest_file_path).unwrap();
|
let manifest_file_content = std::fs::read_to_string(manifest_file_path).ok()?;
|
||||||
let manifest: BundleManifest = toml::from_str(&manifest_file_content).unwrap();
|
let manifest: BundleManifest = toml::from_str(&manifest_file_content).ok()?;
|
||||||
// TODO: check integrity of the loaded bundle.
|
|
||||||
Self {
|
let original_dir = std::env::current_dir().unwrap();
|
||||||
|
std::env::set_current_dir(&path).unwrap();
|
||||||
|
|
||||||
|
if let Some(aster_bin) = &manifest.aster_bin {
|
||||||
|
if !aster_bin.validate() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(vm_image) = &manifest.vm_image {
|
||||||
|
if !vm_image.validate() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(initramfs) = &manifest.initramfs {
|
||||||
|
if !initramfs.validate() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::env::set_current_dir(original_dir).unwrap();
|
||||||
|
|
||||||
|
Some(Self {
|
||||||
manifest,
|
manifest,
|
||||||
path: path.as_ref().to_path_buf(),
|
path: path.as_ref().to_path_buf(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can_run_with_config(&self, config: &RunConfig) -> bool {
|
pub fn can_run_with_config(&self, config: &RunConfig) -> bool {
|
||||||
|
// Compare the manifest with the run configuration.
|
||||||
// TODO: This pairwise comparison will result in some false negatives. We may
|
// TODO: This pairwise comparison will result in some false negatives. We may
|
||||||
// fix it by pondering upon each fields with more care.
|
// fix it by pondering upon each fields with more care.
|
||||||
self.manifest.kcmd_args == config.manifest.kcmd_args
|
if self.manifest.kcmd_args != config.manifest.kcmd_args
|
||||||
&& self.manifest.initramfs == config.manifest.initramfs
|
|| self.manifest.boot != config.manifest.boot
|
||||||
&& self.manifest.boot == config.manifest.boot
|
|| self.manifest.qemu != config.manifest.qemu
|
||||||
&& self.manifest.qemu == config.manifest.qemu
|
|| self.manifest.cargo_args != config.cargo_args
|
||||||
&& self.manifest.cargo_args == config.cargo_args
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare the initramfs.
|
||||||
|
match (&self.manifest.initramfs, &config.manifest.initramfs) {
|
||||||
|
(Some(initramfs), Some(initramfs_path)) => {
|
||||||
|
let config_initramfs = Initramfs::new(initramfs_path);
|
||||||
|
if initramfs.sha256sum() != config_initramfs.sha256sum() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(None, None) => {}
|
||||||
|
_ => {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn last_modified_time(&self) -> SystemTime {
|
||||||
|
self.manifest.last_modified
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&self, config: &RunConfig) {
|
pub fn run(&self, config: &RunConfig) {
|
||||||
@ -84,7 +163,9 @@ impl Bundle {
|
|||||||
error_msg!("Kernel ELF binary is required for Microvm");
|
error_msg!("Kernel ELF binary is required for Microvm");
|
||||||
std::process::exit(Errno::RunBundle as _);
|
std::process::exit(Errno::RunBundle as _);
|
||||||
};
|
};
|
||||||
qemu_cmd.arg("-kernel").arg(self.path.join(&aster_bin.path));
|
qemu_cmd
|
||||||
|
.arg("-kernel")
|
||||||
|
.arg(self.path.join(aster_bin.path()));
|
||||||
let Some(ref initramfs) = config.manifest.initramfs else {
|
let Some(ref initramfs) = config.manifest.initramfs else {
|
||||||
error_msg!("Initramfs is required for Microvm");
|
error_msg!("Initramfs is required for Microvm");
|
||||||
std::process::exit(Errno::RunBundle as _);
|
std::process::exit(Errno::RunBundle as _);
|
||||||
@ -100,7 +181,7 @@ impl Bundle {
|
|||||||
error_msg!("VM image is required for QEMU booting");
|
error_msg!("VM image is required for QEMU booting");
|
||||||
std::process::exit(Errno::RunBundle as _);
|
std::process::exit(Errno::RunBundle as _);
|
||||||
};
|
};
|
||||||
qemu_cmd.arg("-cdrom").arg(self.path.join(&vm_image.path));
|
qemu_cmd.arg("-cdrom").arg(self.path.join(vm_image.path()));
|
||||||
if let Some(ovmf) = &config.manifest.boot.ovmf {
|
if let Some(ovmf) = &config.manifest.boot.ovmf {
|
||||||
qemu_cmd.arg("-drive").arg(format!(
|
qemu_cmd.arg("-drive").arg(format!(
|
||||||
"if=pflash,format=raw,unit=0,readonly=on,file={}",
|
"if=pflash,format=raw,unit=0,readonly=on,file={}",
|
||||||
@ -136,61 +217,37 @@ impl Bundle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_vm_image(&mut self, vm_image: &AsterVmImage) {
|
/// Move the vm_image into the bundle.
|
||||||
|
pub fn consume_vm_image(&mut self, vm_image: AsterVmImage) {
|
||||||
if self.manifest.vm_image.is_some() {
|
if self.manifest.vm_image.is_some() {
|
||||||
panic!("vm_image already exists");
|
panic!("vm_image already exists");
|
||||||
}
|
}
|
||||||
let file_name = vm_image.path.file_name().unwrap();
|
self.manifest.vm_image = Some(vm_image.move_to(&self.path));
|
||||||
let copied_path = self.path.join(file_name);
|
self.write_manifest_to_fs();
|
||||||
std::fs::copy(&vm_image.path, copied_path).unwrap();
|
|
||||||
self.manifest.vm_image = Some(AsterVmImage {
|
|
||||||
path: file_name.into(),
|
|
||||||
typ: vm_image.typ.clone(),
|
|
||||||
aster_version: vm_image.aster_version.clone(),
|
|
||||||
sha256sum: vm_image.sha256sum.clone(),
|
|
||||||
});
|
|
||||||
self.write_manifest_content();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_aster_bin(&mut self, aster_bin: &AsterBin) {
|
/// Move the aster_bin into the bundle.
|
||||||
|
pub fn consume_aster_bin(&mut self, aster_bin: AsterBin) {
|
||||||
if self.manifest.aster_bin.is_some() {
|
if self.manifest.aster_bin.is_some() {
|
||||||
panic!("aster_bin already exists");
|
panic!("aster_bin already exists");
|
||||||
}
|
}
|
||||||
let file_name = aster_bin.path.file_name().unwrap();
|
self.manifest.aster_bin = Some(aster_bin.move_to(&self.path));
|
||||||
let copied_path = self.path.join(file_name);
|
self.write_manifest_to_fs();
|
||||||
std::fs::copy(&aster_bin.path, copied_path).unwrap();
|
|
||||||
self.manifest.aster_bin = Some(AsterBin {
|
|
||||||
path: file_name.into(),
|
|
||||||
typ: aster_bin.typ.clone(),
|
|
||||||
version: aster_bin.version.clone(),
|
|
||||||
sha256sum: aster_bin.sha256sum.clone(),
|
|
||||||
stripped: aster_bin.stripped,
|
|
||||||
});
|
|
||||||
self.write_manifest_content();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_manifest_content(&self) {
|
/// Copy the initramfs into the bundle.
|
||||||
|
pub fn add_initramfs(&mut self, initramfs: Initramfs) {
|
||||||
|
if self.manifest.initramfs.is_some() {
|
||||||
|
panic!("initramfs already exists");
|
||||||
|
}
|
||||||
|
self.manifest.initramfs = Some(initramfs.copy_to(&self.path));
|
||||||
|
self.write_manifest_to_fs();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_manifest_to_fs(&mut self) {
|
||||||
|
self.manifest.last_modified = SystemTime::now();
|
||||||
let manifest_file_content = toml::to_string(&self.manifest).unwrap();
|
let manifest_file_content = toml::to_string(&self.manifest).unwrap();
|
||||||
let manifest_file_path = self.path.join("bundle.toml");
|
let manifest_file_path = self.path.join("bundle.toml");
|
||||||
std::fs::write(manifest_file_path, manifest_file_content).unwrap();
|
std::fs::write(manifest_file_path, manifest_file_content).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The osdk bundle artifact manifest that stores as `bundle.toml`.
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
pub struct BundleManifest {
|
|
||||||
#[serde(default)]
|
|
||||||
pub kcmd_args: Vec<String>,
|
|
||||||
#[serde(default)]
|
|
||||||
pub initramfs: Option<PathBuf>,
|
|
||||||
#[serde(default)]
|
|
||||||
pub aster_bin: Option<AsterBin>,
|
|
||||||
#[serde(default)]
|
|
||||||
pub vm_image: Option<AsterVmImage>,
|
|
||||||
#[serde(default)]
|
|
||||||
pub boot: Boot,
|
|
||||||
#[serde(default)]
|
|
||||||
pub qemu: Qemu,
|
|
||||||
#[serde(default)]
|
|
||||||
pub cargo_args: CargoArgs,
|
|
||||||
}
|
|
66
osdk/src/bundle/vm_image.rs
Normal file
66
osdk/src/bundle/vm_image.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fs,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::file::BundleFile;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct AsterVmImage {
|
||||||
|
path: PathBuf,
|
||||||
|
typ: AsterVmImageType,
|
||||||
|
aster_version: String,
|
||||||
|
sha256sum: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub enum AsterVmImageType {
|
||||||
|
GrubIso(AsterGrubIsoImageMeta),
|
||||||
|
// TODO: add more vm image types such as qcow2, etc.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct AsterGrubIsoImageMeta {
|
||||||
|
pub grub_version: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BundleFile for AsterVmImage {
|
||||||
|
fn path(&self) -> &PathBuf {
|
||||||
|
&self.path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sha256sum(&self) -> &String {
|
||||||
|
&self.sha256sum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsterVmImage {
|
||||||
|
pub fn new(path: impl AsRef<Path>, typ: AsterVmImageType, aster_version: String) -> Self {
|
||||||
|
let created = Self {
|
||||||
|
path: path.as_ref().to_path_buf(),
|
||||||
|
typ,
|
||||||
|
aster_version,
|
||||||
|
sha256sum: String::new(),
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
sha256sum: created.calculate_sha256sum(),
|
||||||
|
..created
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move the binary to the `base` directory and convert the path to a relative path.
|
||||||
|
pub fn move_to(self, base: impl AsRef<Path>) -> Self {
|
||||||
|
let file_name = self.path.file_name().unwrap();
|
||||||
|
let copied_path = base.as_ref().join(file_name);
|
||||||
|
fs::copy(&self.path, copied_path).unwrap();
|
||||||
|
fs::remove_file(&self.path).unwrap();
|
||||||
|
Self {
|
||||||
|
path: PathBuf::from(file_name),
|
||||||
|
typ: self.typ,
|
||||||
|
aster_version: self.aster_version,
|
||||||
|
sha256sum: self.sha256sum,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,10 @@ use std::{
|
|||||||
use linux_bzimage_builder::{legacy32_rust_target_json, make_bzimage, BzImageType};
|
use linux_bzimage_builder::{legacy32_rust_target_json, make_bzimage, BzImageType};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bin::{AsterBin, AsterBinType, AsterBzImageMeta, AsterElfMeta},
|
bundle::{
|
||||||
|
bin::{AsterBin, AsterBinType, AsterBzImageMeta, AsterElfMeta},
|
||||||
|
file::BundleFile,
|
||||||
|
},
|
||||||
config_manager::boot::BootProtocol,
|
config_manager::boot::BootProtocol,
|
||||||
utils::get_current_crate_info,
|
utils::get_current_crate_info,
|
||||||
};
|
};
|
||||||
@ -52,30 +55,35 @@ pub fn make_install_bzimage(
|
|||||||
let install_path = install_dir.as_ref().join(target_name);
|
let install_path = install_dir.as_ref().join(target_name);
|
||||||
info!("Building bzImage");
|
info!("Building bzImage");
|
||||||
println!("install_path: {:?}", install_path);
|
println!("install_path: {:?}", install_path);
|
||||||
make_bzimage(&install_path, image_type, &aster_elf.path, &setup_bin);
|
make_bzimage(&install_path, image_type, aster_elf.path(), &setup_bin);
|
||||||
|
|
||||||
AsterBin {
|
AsterBin::new(
|
||||||
path: install_path,
|
&install_path,
|
||||||
typ: AsterBinType::BzImage(AsterBzImageMeta {
|
AsterBinType::BzImage(AsterBzImageMeta {
|
||||||
support_legacy32_boot: matches!(protocol, BootProtocol::LinuxLegacy32),
|
support_legacy32_boot: matches!(protocol, BootProtocol::LinuxLegacy32),
|
||||||
support_efi_boot: false,
|
support_efi_boot: false,
|
||||||
support_efi_handover: matches!(protocol, BootProtocol::LinuxEfiHandover64),
|
support_efi_handover: matches!(protocol, BootProtocol::LinuxEfiHandover64),
|
||||||
}),
|
}),
|
||||||
version: aster_elf.version.clone(),
|
aster_elf.version().clone(),
|
||||||
sha256sum: "TODO".to_string(),
|
aster_elf.stripped(),
|
||||||
stripped: aster_elf.stripped,
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn strip_elf_for_qemu(install_dir: impl AsRef<Path>, elf: &AsterBin) -> AsterBin {
|
pub fn strip_elf_for_qemu(install_dir: impl AsRef<Path>, elf: &AsterBin) -> AsterBin {
|
||||||
let stripped_elf_path = {
|
let stripped_elf_path = {
|
||||||
let elf_name = elf.path.file_name().unwrap().to_str().unwrap().to_string();
|
let elf_name = elf
|
||||||
|
.path()
|
||||||
|
.file_name()
|
||||||
|
.unwrap()
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.to_string();
|
||||||
install_dir.as_ref().join(elf_name + ".stripped.elf")
|
install_dir.as_ref().join(elf_name + ".stripped.elf")
|
||||||
};
|
};
|
||||||
|
|
||||||
// We use rust-strip to reduce the kernel image size.
|
// We use rust-strip to reduce the kernel image size.
|
||||||
let status = Command::new("rust-strip")
|
let status = Command::new("rust-strip")
|
||||||
.arg(&elf.path)
|
.arg(elf.path())
|
||||||
.arg("-o")
|
.arg("-o")
|
||||||
.arg(stripped_elf_path.as_os_str())
|
.arg(stripped_elf_path.as_os_str())
|
||||||
.status();
|
.status();
|
||||||
@ -112,18 +120,17 @@ pub fn strip_elf_for_qemu(install_dir: impl AsRef<Path>, elf: &AsterBin) -> Aste
|
|||||||
file.write_all(&bytes).unwrap();
|
file.write_all(&bytes).unwrap();
|
||||||
file.flush().unwrap();
|
file.flush().unwrap();
|
||||||
|
|
||||||
AsterBin {
|
AsterBin::new(
|
||||||
path: stripped_elf_path,
|
&stripped_elf_path,
|
||||||
typ: AsterBinType::Elf(AsterElfMeta {
|
AsterBinType::Elf(AsterElfMeta {
|
||||||
has_linux_header: false,
|
has_linux_header: false,
|
||||||
has_pvh_header: false,
|
has_pvh_header: false,
|
||||||
has_multiboot_header: true,
|
has_multiboot_header: true,
|
||||||
has_multiboot2_header: true,
|
has_multiboot2_header: true,
|
||||||
}),
|
}),
|
||||||
version: elf.version.clone(),
|
elf.version().clone(),
|
||||||
sha256sum: "TODO".to_string(),
|
true,
|
||||||
stripped: true,
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SetupInstallArch {
|
enum SetupInstallArch {
|
||||||
|
@ -7,10 +7,13 @@ use std::{
|
|||||||
|
|
||||||
use super::bin::make_install_bzimage;
|
use super::bin::make_install_bzimage;
|
||||||
use crate::{
|
use crate::{
|
||||||
bin::AsterBin,
|
bundle::{
|
||||||
|
bin::AsterBin,
|
||||||
|
file::BundleFile,
|
||||||
|
vm_image::{AsterGrubIsoImageMeta, AsterVmImage, AsterVmImageType},
|
||||||
|
},
|
||||||
config_manager::{boot::BootProtocol, BuildConfig},
|
config_manager::{boot::BootProtocol, BuildConfig},
|
||||||
utils::get_current_crate_info,
|
utils::get_current_crate_info,
|
||||||
vm_image::{AsterGrubIsoImageMeta, AsterVmImage, AsterVmImageType},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn create_bootdev_image(
|
pub fn create_bootdev_image(
|
||||||
@ -46,7 +49,7 @@ pub fn create_bootdev_image(
|
|||||||
BootProtocol::Multiboot | BootProtocol::Multiboot2 => {
|
BootProtocol::Multiboot | BootProtocol::Multiboot2 => {
|
||||||
// Copy the kernel image to the boot directory.
|
// Copy the kernel image to the boot directory.
|
||||||
let target_path = iso_root.join("boot").join(&target_name);
|
let target_path = iso_root.join("boot").join(&target_name);
|
||||||
fs::copy(&aster_bin.path, target_path).unwrap();
|
fs::copy(aster_bin.path(), target_path).unwrap();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -77,14 +80,13 @@ pub fn create_bootdev_image(
|
|||||||
panic!("Failed to run {:#?}.", grub_mkrescue_cmd);
|
panic!("Failed to run {:#?}.", grub_mkrescue_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
AsterVmImage {
|
AsterVmImage::new(
|
||||||
path: iso_path.clone(),
|
iso_path,
|
||||||
typ: AsterVmImageType::GrubIso(AsterGrubIsoImageMeta {
|
AsterVmImageType::GrubIso(AsterGrubIsoImageMeta {
|
||||||
grub_version: get_grub_mkrescue_version(grub_mkrescue_bin),
|
grub_version: get_grub_mkrescue_version(grub_mkrescue_bin),
|
||||||
}),
|
}),
|
||||||
aster_version: aster_bin.version.clone(),
|
aster_bin.version().clone(),
|
||||||
sha256sum: "TODO".to_string(),
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_grub_cfg(
|
fn generate_grub_cfg(
|
||||||
|
@ -14,8 +14,11 @@ use bin::strip_elf_for_qemu;
|
|||||||
use super::utils::{cargo, COMMON_CARGO_ARGS, DEFAULT_TARGET_RELPATH};
|
use super::utils::{cargo, COMMON_CARGO_ARGS, DEFAULT_TARGET_RELPATH};
|
||||||
use crate::{
|
use crate::{
|
||||||
base_crate::new_base_crate,
|
base_crate::new_base_crate,
|
||||||
bin::{AsterBin, AsterBinType, AsterElfMeta},
|
bundle::{
|
||||||
bundle::{Bundle, BundleManifest},
|
bin::{AsterBin, AsterBinType, AsterElfMeta},
|
||||||
|
file::Initramfs,
|
||||||
|
Bundle,
|
||||||
|
},
|
||||||
cli::CargoArgs,
|
cli::CargoArgs,
|
||||||
config_manager::{qemu::QemuMachine, BuildConfig},
|
config_manager::{qemu::QemuMachine, BuildConfig},
|
||||||
error::Errno,
|
error::Errno,
|
||||||
@ -70,30 +73,31 @@ pub fn do_build(
|
|||||||
cargo_target_directory: impl AsRef<Path>,
|
cargo_target_directory: impl AsRef<Path>,
|
||||||
config: &BuildConfig,
|
config: &BuildConfig,
|
||||||
) -> Bundle {
|
) -> Bundle {
|
||||||
|
if bundle_path.as_ref().exists() {
|
||||||
|
std::fs::remove_dir_all(&bundle_path).unwrap();
|
||||||
|
}
|
||||||
|
let mut bundle = Bundle::new(
|
||||||
|
&bundle_path,
|
||||||
|
config.manifest.kcmd_args.clone(),
|
||||||
|
config.manifest.boot.clone(),
|
||||||
|
config.manifest.qemu.clone(),
|
||||||
|
config.cargo_args.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(ref initramfs) = config.manifest.initramfs {
|
if let Some(ref initramfs) = config.manifest.initramfs {
|
||||||
if !initramfs.exists() {
|
if !initramfs.exists() {
|
||||||
error_msg!("initramfs file not found: {}", initramfs.display());
|
error_msg!("initramfs file not found: {}", initramfs.display());
|
||||||
process::exit(Errno::BuildCrate as _);
|
process::exit(Errno::BuildCrate as _);
|
||||||
}
|
}
|
||||||
|
bundle.add_initramfs(Initramfs::new(initramfs));
|
||||||
};
|
};
|
||||||
let mut bundle = Bundle::new(
|
|
||||||
BundleManifest {
|
|
||||||
kcmd_args: config.manifest.kcmd_args.clone(),
|
|
||||||
initramfs: config.manifest.initramfs.clone(),
|
|
||||||
aster_bin: None,
|
|
||||||
vm_image: None,
|
|
||||||
boot: config.manifest.boot.clone(),
|
|
||||||
qemu: config.manifest.qemu.clone(),
|
|
||||||
cargo_args: config.cargo_args.clone(),
|
|
||||||
},
|
|
||||||
&bundle_path,
|
|
||||||
);
|
|
||||||
info!("Building kernel ELF");
|
info!("Building kernel ELF");
|
||||||
let aster_elf = build_kernel_elf(&config.cargo_args, &cargo_target_directory);
|
let aster_elf = build_kernel_elf(&config.cargo_args, &cargo_target_directory);
|
||||||
|
|
||||||
if matches!(config.manifest.qemu.machine, QemuMachine::Microvm) {
|
if matches!(config.manifest.qemu.machine, QemuMachine::Microvm) {
|
||||||
let stripped_elf = strip_elf_for_qemu(&osdk_target_directory, &aster_elf);
|
let stripped_elf = strip_elf_for_qemu(&osdk_target_directory, &aster_elf);
|
||||||
bundle.add_aster_bin(&stripped_elf);
|
bundle.consume_aster_bin(stripped_elf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: A boot device is required if we use GRUB. Actually you can boot
|
// TODO: A boot device is required if we use GRUB. Actually you can boot
|
||||||
@ -107,7 +111,7 @@ pub fn do_build(
|
|||||||
config.manifest.initramfs.as_ref(),
|
config.manifest.initramfs.as_ref(),
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
bundle.add_vm_image(&bootdev_image);
|
bundle.consume_vm_image(bootdev_image);
|
||||||
}
|
}
|
||||||
|
|
||||||
bundle
|
bundle
|
||||||
@ -141,16 +145,15 @@ fn build_kernel_elf(args: &CargoArgs, cargo_target_directory: impl AsRef<Path>)
|
|||||||
}
|
}
|
||||||
.join(get_current_crate_info().name);
|
.join(get_current_crate_info().name);
|
||||||
|
|
||||||
AsterBin {
|
AsterBin::new(
|
||||||
path: aster_bin_path,
|
aster_bin_path,
|
||||||
typ: AsterBinType::Elf(AsterElfMeta {
|
AsterBinType::Elf(AsterElfMeta {
|
||||||
has_linux_header: false,
|
has_linux_header: false,
|
||||||
has_pvh_header: false,
|
has_pvh_header: false,
|
||||||
has_multiboot_header: true,
|
has_multiboot_header: true,
|
||||||
has_multiboot2_header: true,
|
has_multiboot2_header: true,
|
||||||
}),
|
}),
|
||||||
version: get_current_crate_info().version,
|
get_current_crate_info().version,
|
||||||
sha256sum: "TODO".to_string(),
|
false,
|
||||||
stripped: false,
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,10 @@ fn kernel_main() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(ktest)]
|
#[cfg(ktest)]
|
||||||
mod test {
|
mod tests {
|
||||||
#[ktest]
|
#[ktest]
|
||||||
fn trivial_test() {
|
fn it_works() {
|
||||||
assert_eq!(1 + 1, 2);
|
let memory_regions = aster_frame::boot::memory_regions();
|
||||||
|
assert!(!memory_regions.is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,8 @@ pub fn execute_new_command(args: &NewArgs) {
|
|||||||
|
|
||||||
/// OSDK assumes that the toolchain used by the kernel should be same same as the toolchain
|
/// OSDK assumes that the toolchain used by the kernel should be same same as the toolchain
|
||||||
/// specified in the asterinas workspace.
|
/// specified in the asterinas workspace.
|
||||||
macro_rules! aster_rust_toolchain {
|
fn aster_rust_toolchain() -> &'static str {
|
||||||
() => {
|
include_str!("../../../../rust-toolchain.toml")
|
||||||
include_str!("../../../../rust-toolchain.toml")
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_manifest_dependencies(cargo_metadata: &serde_json::Value, crate_name: &str) {
|
fn add_manifest_dependencies(cargo_metadata: &serde_json::Value, crate_name: &str) {
|
||||||
@ -126,7 +124,7 @@ fn add_rust_toolchain(cargo_metadata: &serde_json::Value) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let contents = aster_rust_toolchain!();
|
let contents = aster_rust_toolchain();
|
||||||
fs::write(rust_toolchain_path, contents).unwrap();
|
fs::write(rust_toolchain_path, contents).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +175,7 @@ fn get_package_metadata<'a>(
|
|||||||
|
|
||||||
fn check_rust_toolchain(toolchain: &toml::Table) {
|
fn check_rust_toolchain(toolchain: &toml::Table) {
|
||||||
let expected = {
|
let expected = {
|
||||||
let contents = aster_rust_toolchain!();
|
let contents = aster_rust_toolchain();
|
||||||
toml::Table::from_str(contents).unwrap()
|
toml::Table::from_str(contents).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
time::{Duration, SystemTime},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{build::create_base_and_build, utils::DEFAULT_TARGET_RELPATH};
|
use super::{build::create_base_and_build, utils::DEFAULT_TARGET_RELPATH};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
bundle::Bundle,
|
||||||
config_manager::{BuildConfig, RunConfig},
|
config_manager::{BuildConfig, RunConfig},
|
||||||
utils::{get_current_crate_info, get_target_directory},
|
utils::{get_cargo_metadata, get_current_crate_info, get_target_directory},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn execute_run_command(config: &RunConfig) {
|
pub fn execute_run_command(config: &RunConfig) {
|
||||||
@ -11,13 +17,34 @@ pub fn execute_run_command(config: &RunConfig) {
|
|||||||
let osdk_target_directory = ws_target_directory.join(DEFAULT_TARGET_RELPATH);
|
let osdk_target_directory = ws_target_directory.join(DEFAULT_TARGET_RELPATH);
|
||||||
let target_name = get_current_crate_info().name;
|
let target_name = get_current_crate_info().name;
|
||||||
let default_bundle_directory = osdk_target_directory.join(target_name);
|
let default_bundle_directory = osdk_target_directory.join(target_name);
|
||||||
|
let existing_bundle = Bundle::load(&default_bundle_directory);
|
||||||
|
|
||||||
|
// If the source is not since modified and the last build is recent, we can reuse the existing bundle.
|
||||||
|
if let Some(existing_bundle) = existing_bundle {
|
||||||
|
if existing_bundle.can_run_with_config(config) {
|
||||||
|
if let Ok(built_since) =
|
||||||
|
SystemTime::now().duration_since(existing_bundle.last_modified_time())
|
||||||
|
{
|
||||||
|
if built_since < Duration::from_secs(600) {
|
||||||
|
let workspace_root = {
|
||||||
|
let meta = get_cargo_metadata(None::<&str>, None::<&[&str]>).unwrap();
|
||||||
|
PathBuf::from(meta.get("workspace_root").unwrap().as_str().unwrap())
|
||||||
|
};
|
||||||
|
if get_last_modified_time(workspace_root) < existing_bundle.last_modified_time()
|
||||||
|
{
|
||||||
|
existing_bundle.run(config);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let required_build_config = BuildConfig {
|
let required_build_config = BuildConfig {
|
||||||
manifest: config.manifest.clone(),
|
manifest: config.manifest.clone(),
|
||||||
cargo_args: config.cargo_args.clone(),
|
cargo_args: config.cargo_args.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Check if the bundle is already built and compatible with the run configuration.
|
|
||||||
let bundle = create_base_and_build(
|
let bundle = create_base_and_build(
|
||||||
default_bundle_directory,
|
default_bundle_directory,
|
||||||
&osdk_target_directory,
|
&osdk_target_directory,
|
||||||
@ -27,3 +54,21 @@ pub fn execute_run_command(config: &RunConfig) {
|
|||||||
|
|
||||||
bundle.run(config);
|
bundle.run(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_last_modified_time(path: impl AsRef<Path>) -> SystemTime {
|
||||||
|
let mut last_modified = SystemTime::UNIX_EPOCH;
|
||||||
|
for entry in std::fs::read_dir(path).unwrap() {
|
||||||
|
let entry = entry.unwrap();
|
||||||
|
if entry.file_name() == "target" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let metadata = entry.metadata().unwrap();
|
||||||
|
if metadata.is_dir() {
|
||||||
|
last_modified = std::cmp::max(last_modified, get_last_modified_time(&entry.path()));
|
||||||
|
} else {
|
||||||
|
last_modified = std::cmp::max(last_modified, metadata.modified().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_modified
|
||||||
|
}
|
||||||
|
@ -8,14 +8,12 @@ extern crate log;
|
|||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
|
||||||
mod base_crate;
|
mod base_crate;
|
||||||
mod bin;
|
|
||||||
mod bundle;
|
mod bundle;
|
||||||
mod cli;
|
mod cli;
|
||||||
mod commands;
|
mod commands;
|
||||||
mod config_manager;
|
mod config_manager;
|
||||||
mod error;
|
mod error;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod vm_image;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// init logger
|
// init logger
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
pub struct AsterVmImage {
|
|
||||||
pub path: PathBuf,
|
|
||||||
pub typ: AsterVmImageType,
|
|
||||||
pub aster_version: String,
|
|
||||||
pub sha256sum: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
pub enum AsterVmImageType {
|
|
||||||
GrubIso(AsterGrubIsoImageMeta),
|
|
||||||
// TODO: add more vm image types such as qcow2, etc.
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
pub struct AsterGrubIsoImageMeta {
|
|
||||||
pub grub_version: String,
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user