mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
Prepare OSDK for multi arch support and the upcoming refactor
This commit is contained in:
parent
0ecb919e73
commit
735d7b7b11
1
.gitignore
vendored
1
.gitignore
vendored
@ -20,4 +20,3 @@ virtio-net.pcap
|
||||
|
||||
# vscode launch config file
|
||||
.vscode/launch.json
|
||||
.vscode/launch.bak
|
||||
|
19
Makefile
19
Makefile
@ -1,26 +1,29 @@
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
# Project-wide options.
|
||||
ARCH ?= x86_64
|
||||
# End of project-wide options.
|
||||
|
||||
# The Makefile provides a way to run arbitrary tests in the kernel
|
||||
# mode using the kernel command line.
|
||||
# Here are the options for the auto test feature.
|
||||
AUTO_TEST ?= none
|
||||
BOOT_LOADER ?= grub
|
||||
BOOT_PROTOCOL ?= multiboot2
|
||||
QEMU_MACHINE ?= q35
|
||||
BUILD_SYSCALL_TEST ?= 0
|
||||
EMULATE_IOMMU ?= 0
|
||||
ENABLE_KVM ?= 1
|
||||
EXTRA_BLOCKLISTS_DIRS ?= ""
|
||||
INTEL_TDX ?= 0
|
||||
QEMU_MACHINE ?= q35
|
||||
RELEASE_MODE ?= 0
|
||||
SKIP_GRUB_MENU ?= 1
|
||||
SYSCALL_TEST_DIR ?= /tmp
|
||||
EXTRA_BLOCKLISTS_DIRS ?= ""
|
||||
RELEASE_MODE ?= 0
|
||||
GDB_TCP_PORT ?= 1234
|
||||
# End of auto test features.
|
||||
|
||||
CARGO_OSDK := ~/.cargo/bin/cargo-osdk
|
||||
|
||||
CARGO_OSDK_ARGS :=
|
||||
CARGO_OSDK_ARGS := --arch=$(ARCH)
|
||||
|
||||
ifeq ($(AUTO_TEST), syscall)
|
||||
BUILD_SYSCALL_TEST := 1
|
||||
@ -140,12 +143,12 @@ else ifeq ($(AUTO_TEST), boot)
|
||||
endif
|
||||
|
||||
.PHONY: gdb_server
|
||||
gdb_server: initramfs $(CARGO_OSDK)
|
||||
@cargo osdk run $(CARGO_OSDK_ARGS) -G --vsc --gdb-server-addr :$(GDB_TCP_PORT)
|
||||
gdb_server: build
|
||||
@cd kernel && cargo osdk run $(CARGO_OSDK_ARGS) -G --vsc --gdb-server-addr :1234
|
||||
|
||||
.PHONY: gdb_client
|
||||
gdb_client: $(CARGO_OSDK)
|
||||
@cd kernel && cargo osdk debug $(CARGO_OSDK_ARGS) --remote :$(GDB_TCP_PORT)
|
||||
@cd kernel && cargo osdk debug $(CARGO_OSDK_ARGS) --remote :1234
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
|
15
OSDK.toml
15
OSDK.toml
@ -13,8 +13,9 @@ initramfs = "regression/build/initramfs.cpio.gz"
|
||||
protocol = "multiboot2"
|
||||
loader = "grub"
|
||||
ovmf = "/root/ovmf/release"
|
||||
opensbi = "/root/opensbi-virt-firmware"
|
||||
|
||||
[qemu]
|
||||
[qemu.'cfg(arch="x86_64")']
|
||||
machine = "q35"
|
||||
drive_files = [
|
||||
["regression/build/ext2.img", "if=none,format=raw,id=x0"],
|
||||
@ -39,7 +40,7 @@ args = [
|
||||
"-device virtconsole,chardev=mux",
|
||||
]
|
||||
|
||||
[qemu.'cfg(select="iommu")']
|
||||
[qemu.'cfg(arch="x86_64", select="iommu")']
|
||||
machine = "q35"
|
||||
drive_files = [
|
||||
["regression/build/ext2.img", "if=none,format=raw,id=x0"],
|
||||
@ -66,7 +67,7 @@ args = [
|
||||
"-device ioh3420,id=pcie.0,chassis=1",
|
||||
]
|
||||
|
||||
[qemu.'cfg(select="microvm")']
|
||||
[qemu.'cfg(arch="x86_64", select="microvm")']
|
||||
machine = "microvm"
|
||||
drive_files = [
|
||||
["regression/build/ext2.img", "if=none,format=raw,id=x0"],
|
||||
@ -92,3 +93,11 @@ args = [
|
||||
"-device virtio-serial-device",
|
||||
"-device virtconsole,chardev=mux",
|
||||
]
|
||||
|
||||
[qemu.'cfg(arch="riscv64")']
|
||||
machine = "virt"
|
||||
args = [
|
||||
"--no-reboot",
|
||||
"-m 2G",
|
||||
"-nographic",
|
||||
]
|
||||
|
@ -74,10 +74,6 @@ Start a GDB-enabled VM of Asterinas with OSDK and wait for debugging connection:
|
||||
make gdb_server
|
||||
```
|
||||
|
||||
The server will listen at the default address specified in `Makefile`, i.e., a local TCP port `:1234`.
|
||||
Change the address in `Makefile` for your convenience,
|
||||
and check `cargo osdk run -h` for more details about the address.
|
||||
|
||||
Two options are provided to interact with the debug server.
|
||||
|
||||
- A GDB client: start a GDB client in another terminal.
|
||||
|
@ -23,7 +23,7 @@ Options related with debugging:
|
||||
Requires [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb).
|
||||
- `--gdb-server-addr <ADDR>`: The network address on which the GDB server listens,
|
||||
it can be either a path for the UNIX domain socket or a TCP port on an IP address.
|
||||
[default: `.aster-gdb-socket`(a local UNIX socket)]
|
||||
[default: .aster-gdb-socket]
|
||||
|
||||
See [Debug Command](debug.md) to interact with the GDB server in terminal.
|
||||
|
||||
|
1
osdk/Cargo.lock
generated
1
osdk/Cargo.lock
generated
@ -138,7 +138,6 @@ dependencies = [
|
||||
"linux-bzimage-builder",
|
||||
"log",
|
||||
"quote",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
|
@ -16,7 +16,6 @@ lazy_static = "1.4.0"
|
||||
linux-bzimage-builder = { path = "../framework/libs/linux-bzimage/builder" }
|
||||
log = "0.4.20"
|
||||
quote = "1.0.35"
|
||||
regex = "1.10.3"
|
||||
serde = { version = "1.0.195", features = ["derive"] }
|
||||
serde_json = "1.0.111"
|
||||
sha2 = "0.10.8"
|
||||
|
85
osdk/src/arch.rs
Normal file
85
osdk/src/arch.rs
Normal file
@ -0,0 +1,85 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use clap::{builder::PossibleValue, ValueEnum};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
/// Supported architectures.
|
||||
///
|
||||
/// The target triple for each architecture is fixed and shall not
|
||||
/// be assigned by the user. This is also different from the first
|
||||
/// element of the target triple, but akin to the "target_arch" cfg
|
||||
/// of Cargo:
|
||||
/// <https://doc.rust-lang.org/reference/conditional-compilation.html#target_arch>
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Arch {
|
||||
Aarch64,
|
||||
X86_64,
|
||||
RiscV64,
|
||||
}
|
||||
|
||||
impl ValueEnum for Arch {
|
||||
fn value_variants<'a>() -> &'a [Self] {
|
||||
&[Arch::Aarch64, Arch::RiscV64, Arch::X86_64]
|
||||
}
|
||||
|
||||
fn to_possible_value(&self) -> Option<PossibleValue> {
|
||||
match self {
|
||||
Arch::Aarch64 => Some(PossibleValue::new(self.to_str())),
|
||||
Arch::RiscV64 => Some(PossibleValue::new(self.to_str())),
|
||||
Arch::X86_64 => Some(PossibleValue::new(self.to_str())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Arch {
|
||||
/// Get the target triple for the architecture.
|
||||
pub fn triple(&self) -> String {
|
||||
match self {
|
||||
Arch::Aarch64 => "aarch64-unknown-none".to_owned(),
|
||||
Arch::RiscV64 => "riscv64gc-unknown-none-elf".to_owned(),
|
||||
Arch::X86_64 => "x86_64-unknown-none".to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Arch::Aarch64 => "aarch64",
|
||||
Arch::RiscV64 => "riscv64",
|
||||
Arch::X86_64 => "x86_64",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Arch {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.to_str())
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the default architecture implied by the host rustc's default architecture.
|
||||
pub fn get_default_arch() -> Arch {
|
||||
let output = std::process::Command::new("rustc")
|
||||
.arg("-vV")
|
||||
.output()
|
||||
.expect("Failed to run rustc to get the host target");
|
||||
let output =
|
||||
std::str::from_utf8(&output.stdout).expect("`rustc -vV` didn't return utf8 output");
|
||||
|
||||
let field = "host: ";
|
||||
let host = output
|
||||
.lines()
|
||||
.find(|l| l.starts_with(field))
|
||||
.map(|l| &l[field.len()..])
|
||||
.expect("`rustc -vV` didn't give a line for host")
|
||||
.to_string();
|
||||
|
||||
match host.split('-').next() {
|
||||
Some(host_arch) => match host_arch {
|
||||
"aarch64" => Arch::Aarch64,
|
||||
"riscv64gc" => Arch::RiscV64,
|
||||
"x86_64" => Arch::X86_64,
|
||||
_ => panic!("The host has an unsupported native architecture"),
|
||||
},
|
||||
None => panic!("`rustc -vV` gave a host with unknown format"),
|
||||
}
|
||||
}
|
@ -57,9 +57,18 @@ pub fn new_base_crate(
|
||||
let original_dir = std::env::current_dir().unwrap();
|
||||
std::env::set_current_dir(&base_crate_path).unwrap();
|
||||
|
||||
// Add linker.ld file
|
||||
let linker_ld = include_str!("x86_64.ld.template");
|
||||
fs::write("x86_64.ld", linker_ld).unwrap();
|
||||
// Add linker script files
|
||||
macro_rules! include_linker_script {
|
||||
([$($linker_script:literal),+]) => {$(
|
||||
fs::write(
|
||||
base_crate_path.as_ref().join($linker_script),
|
||||
include_str!(concat!($linker_script, ".template"))
|
||||
).unwrap();
|
||||
)+};
|
||||
}
|
||||
// TODO: currently just x86_64 works; add support for other architectures
|
||||
// here when the framework is ready
|
||||
include_linker_script!(["x86_64.ld"]);
|
||||
|
||||
// Overrite the main.rs file
|
||||
let main_rs = include_str!("main.rs.template");
|
||||
|
@ -193,6 +193,27 @@ impl Bundle {
|
||||
));
|
||||
}
|
||||
}
|
||||
QemuMachine::Virt => {
|
||||
qemu_cmd.arg("-machine").arg("virt");
|
||||
let Some(ref vm_image) = self.manifest.vm_image else {
|
||||
error_msg!("VM image is required for QEMU booting");
|
||||
std::process::exit(Errno::RunBundle as _);
|
||||
};
|
||||
qemu_cmd.arg("-kernel").arg(self.path.join(vm_image.path()));
|
||||
let Some(ref initramfs) = config.manifest.initramfs else {
|
||||
error_msg!("Initramfs is required for Virt machine");
|
||||
std::process::exit(Errno::RunBundle as _);
|
||||
};
|
||||
qemu_cmd.arg("-initrd").arg(initramfs);
|
||||
qemu_cmd
|
||||
.arg("-append")
|
||||
.arg(config.manifest.kcmd_args.join(" "));
|
||||
let Some(ref opensbi) = self.manifest.boot.opensbi else {
|
||||
error_msg!("OpenSBI is required for Virt machine");
|
||||
std::process::exit(Errno::RunBundle as _);
|
||||
};
|
||||
qemu_cmd.arg("-bios").arg(opensbi);
|
||||
}
|
||||
};
|
||||
qemu_cmd.arg("-cpu").arg("Icelake-Server,+x2apic");
|
||||
|
||||
|
@ -5,6 +5,7 @@ use std::path::PathBuf;
|
||||
use clap::{crate_version, Args, Parser};
|
||||
|
||||
use crate::{
|
||||
arch::Arch,
|
||||
commands::{
|
||||
execute_build_command, execute_debug_command, execute_forwarded_command,
|
||||
execute_new_command, execute_run_command, execute_test_command,
|
||||
@ -190,16 +191,12 @@ pub struct CargoArgs {
|
||||
pub release: bool,
|
||||
#[arg(long, value_name = "FEATURES", help = "List of features to activate")]
|
||||
pub features: Vec<String>,
|
||||
#[arg(
|
||||
long = "config",
|
||||
help = "Override a configuration value",
|
||||
value_name = "KEY=VALUE"
|
||||
)]
|
||||
pub override_configs: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct OsdkArgs {
|
||||
#[arg(long, value_name = "ARCH", help = "The architecture to build for")]
|
||||
pub arch: Option<Arch>,
|
||||
#[arg(
|
||||
long = "select",
|
||||
help = "Select the specific configuration provided in the OSDK manifest",
|
||||
|
@ -3,12 +3,13 @@
|
||||
mod bin;
|
||||
mod grub;
|
||||
|
||||
use std::{path::Path, process};
|
||||
use std::{ffi::OsString, path::Path, process};
|
||||
|
||||
use bin::strip_elf_for_qemu;
|
||||
|
||||
use super::util::{cargo, profile_name_adapter, COMMON_CARGO_ARGS, DEFAULT_TARGET_RELPATH};
|
||||
use super::util::{cargo, COMMON_CARGO_ARGS, DEFAULT_TARGET_RELPATH};
|
||||
use crate::{
|
||||
arch::Arch,
|
||||
base_crate::new_base_crate,
|
||||
bundle::{
|
||||
bin::{AsterBin, AsterBinType, AsterElfMeta},
|
||||
@ -93,7 +94,12 @@ pub fn do_build(
|
||||
};
|
||||
|
||||
info!("Building kernel ELF");
|
||||
let aster_elf = build_kernel_elf(&config.cargo_args, &cargo_target_directory, rustflags);
|
||||
let aster_elf = build_kernel_elf(
|
||||
&config.arch,
|
||||
&config.cargo_args,
|
||||
&cargo_target_directory,
|
||||
rustflags,
|
||||
);
|
||||
|
||||
if matches!(config.manifest.qemu.machine, QemuMachine::Microvm) {
|
||||
let stripped_elf = strip_elf_for_qemu(&osdk_target_directory, &aster_elf);
|
||||
@ -118,19 +124,20 @@ pub fn do_build(
|
||||
}
|
||||
|
||||
fn build_kernel_elf(
|
||||
args: &CargoArgs,
|
||||
arch: &Arch,
|
||||
cargo_args: &CargoArgs,
|
||||
cargo_target_directory: impl AsRef<Path>,
|
||||
rustflags: &[&str],
|
||||
) -> AsterBin {
|
||||
let target = "x86_64-unknown-none";
|
||||
let target_os_string = OsString::from(&arch.triple());
|
||||
let rustc_linker_script_arg = format!("-C link-arg=-T{}.ld", arch);
|
||||
|
||||
let env_rustflags = std::env::var("RUSTFLAGS").unwrap_or_default();
|
||||
let mut rustflags = Vec::from(rustflags);
|
||||
// We disable RELRO and PIC here because they cause link failures
|
||||
rustflags.extend(vec![
|
||||
&env_rustflags,
|
||||
"-C link-arg=-Tx86_64.ld",
|
||||
"-C code-model=kernel",
|
||||
&rustc_linker_script_arg,
|
||||
"-C relocation-model=static",
|
||||
"-Z relro-level=off",
|
||||
// We do not really allow unwinding except for kernel testing. However, we need to specify
|
||||
@ -142,26 +149,25 @@ fn build_kernel_elf(
|
||||
command.env_remove("RUSTUP_TOOLCHAIN");
|
||||
command.env("RUSTFLAGS", rustflags.join(" "));
|
||||
command.arg("build");
|
||||
command.arg("--target").arg(target);
|
||||
command.arg("--target").arg(&target_os_string);
|
||||
command
|
||||
.arg("--target-dir")
|
||||
.arg(cargo_target_directory.as_ref());
|
||||
command.args(COMMON_CARGO_ARGS);
|
||||
command.arg("--profile=".to_string() + &args.profile);
|
||||
for override_config in &args.override_configs {
|
||||
command.arg("--config").arg(override_config);
|
||||
}
|
||||
|
||||
command.arg("--profile=".to_string() + &cargo_args.profile);
|
||||
let status = command.status().unwrap();
|
||||
if !status.success() {
|
||||
error_msg!("Cargo build failed");
|
||||
process::exit(Errno::ExecuteCommand as _);
|
||||
}
|
||||
|
||||
let aster_bin_path = cargo_target_directory.as_ref().join(target);
|
||||
let aster_bin_path = aster_bin_path
|
||||
.join(profile_name_adapter(&args.profile))
|
||||
.join(get_current_crate_info().name);
|
||||
let aster_bin_path = cargo_target_directory.as_ref().join(&target_os_string);
|
||||
let aster_bin_path = if cargo_args.profile == "dev" {
|
||||
aster_bin_path.join("debug")
|
||||
} else {
|
||||
aster_bin_path.join(&cargo_args.profile)
|
||||
}
|
||||
.join(get_current_crate_info().name);
|
||||
|
||||
AsterBin::new(
|
||||
aster_bin_path,
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use crate::commands::util::{bin_file_name, profile_name_adapter};
|
||||
use crate::commands::util::{bin_file_name, profile_adapter};
|
||||
use crate::config_manager::DebugConfig;
|
||||
|
||||
use crate::util::get_target_directory;
|
||||
@ -9,7 +9,7 @@ use std::process::Command;
|
||||
pub fn execute_debug_command(config: &DebugConfig) {
|
||||
let DebugConfig { cargo_args, remote } = config;
|
||||
|
||||
let profile = profile_name_adapter(&cargo_args.profile);
|
||||
let profile = profile_adapter(&cargo_args.profile);
|
||||
let file_path = get_target_directory()
|
||||
.join("x86_64-unknown-none")
|
||||
.join(profile)
|
||||
|
@ -14,6 +14,8 @@ pub use self::{
|
||||
run::execute_run_command, test::execute_test_command,
|
||||
};
|
||||
|
||||
use crate::arch::get_default_arch;
|
||||
|
||||
/// Execute the forwarded cargo command with args containing the subcommand and its arguments.
|
||||
pub fn execute_forwarded_command(subcommand: &str, args: &Vec<String>) -> ! {
|
||||
let mut cargo = util::cargo();
|
||||
@ -21,7 +23,7 @@ pub fn execute_forwarded_command(subcommand: &str, args: &Vec<String>) -> ! {
|
||||
.arg(subcommand)
|
||||
.args(util::COMMON_CARGO_ARGS)
|
||||
.arg("--target")
|
||||
.arg("x86_64-unknown-none")
|
||||
.arg(get_default_arch().triple())
|
||||
.args(args);
|
||||
let status = cargo.status().expect("Failed to execute cargo");
|
||||
std::process::exit(status.code().unwrap_or(1));
|
||||
|
@ -60,42 +60,16 @@ pub fn execute_run_command(config: &RunConfig) {
|
||||
.collect();
|
||||
let mut manifest = config.manifest.clone();
|
||||
manifest.qemu.args.extend(qemu_gdb_args);
|
||||
|
||||
// FIXME: Disable KVM from QEMU args in debug mode.
|
||||
// Currently, the QEMU GDB server does not work properly with KVM enabled.
|
||||
let args_num = manifest.qemu.args.len();
|
||||
manifest.qemu.args.retain(|x| !x.contains("kvm"));
|
||||
if manifest.qemu.args.len() != args_num {
|
||||
println!(
|
||||
"[WARNING] KVM is forced to be disabled in GDB server currently. \
|
||||
Options related with KVM are ignored."
|
||||
);
|
||||
}
|
||||
|
||||
manifest
|
||||
} else {
|
||||
config.manifest.clone()
|
||||
}
|
||||
},
|
||||
cargo_args: {
|
||||
fn is_release_profile(cfg: &RunConfig) -> bool {
|
||||
cfg.cargo_args.profile == "release" || cfg.cargo_args.release
|
||||
}
|
||||
if config.gdb_server_args.is_gdb_enabled && is_release_profile(config) {
|
||||
let mut cargo_args = config.cargo_args.clone();
|
||||
cargo_args
|
||||
.override_configs
|
||||
.push("profile.release.debug=true".to_owned());
|
||||
cargo_args
|
||||
} else {
|
||||
config.cargo_args.clone()
|
||||
}
|
||||
},
|
||||
..config.clone()
|
||||
};
|
||||
let _vsc_launch_file = config.gdb_server_args.vsc_launch_file.then(|| {
|
||||
vsc::check_gdb_config(&config.gdb_server_args);
|
||||
let profile = super::util::profile_name_adapter(&config.cargo_args.profile);
|
||||
let profile = super::util::profile_adapter(&config.cargo_args.profile);
|
||||
vsc::VscLaunchConfig::new(profile, &config.gdb_server_args.gdb_server_addr)
|
||||
});
|
||||
|
||||
@ -121,9 +95,11 @@ pub fn execute_run_command(config: &RunConfig) {
|
||||
}
|
||||
|
||||
let required_build_config = BuildConfig {
|
||||
arch: config.arch.clone(),
|
||||
manifest: config.manifest.clone(),
|
||||
cargo_args: config.cargo_args.clone(),
|
||||
};
|
||||
|
||||
let bundle = create_base_and_build(
|
||||
default_bundle_directory,
|
||||
&osdk_target_directory,
|
||||
|
@ -56,6 +56,7 @@ pub static KTEST_CRATE_WHITELIST: Option<&[&str]> = Some(&{:#?});
|
||||
let target_name = get_current_crate_info().name;
|
||||
let default_bundle_directory = osdk_target_directory.join(target_name);
|
||||
let required_build_config = BuildConfig {
|
||||
arch: config.arch.clone(),
|
||||
manifest: config.manifest.clone(),
|
||||
cargo_args: config.cargo_args.clone(),
|
||||
};
|
||||
@ -72,6 +73,7 @@ pub static KTEST_CRATE_WHITELIST: Option<&[&str]> = Some(&{:#?});
|
||||
std::env::set_current_dir(original_dir).unwrap();
|
||||
|
||||
let required_run_config = RunConfig {
|
||||
arch: config.arch.clone(),
|
||||
manifest: required_build_config.manifest.clone(),
|
||||
cargo_args: required_build_config.cargo_args.clone(),
|
||||
gdb_server_args: GdbServerArgs::default(),
|
||||
|
@ -15,7 +15,7 @@ pub fn cargo() -> Command {
|
||||
Command::new("cargo")
|
||||
}
|
||||
|
||||
pub fn profile_name_adapter(profile: &str) -> &str {
|
||||
pub fn profile_adapter(profile: &str) -> &str {
|
||||
match profile {
|
||||
"dev" => "debug",
|
||||
_ => profile,
|
||||
|
@ -14,8 +14,10 @@ pub struct Boot {
|
||||
pub protocol: BootProtocol,
|
||||
/// The path of `grub_mkrecue`. Only be `Some(_)` if `loader` is `BootLoader::grub`.
|
||||
pub grub_mkrescue: Option<PathBuf>,
|
||||
/// The path of ovmf. Only be `Some(_)` if `protocol` is `BootProtocol::LinuxEfiHandover64`.
|
||||
/// The path of OVMF binaries. Only required if `protocol` is `BootProtocol::LinuxEfiHandover64`.
|
||||
pub ovmf: Option<PathBuf>,
|
||||
/// The path of OpenSBI binaries. Only required for RISC-V.
|
||||
pub opensbi: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
137
osdk/src/config_manager/cfg.rs
Normal file
137
osdk/src/config_manager/cfg.rs
Normal file
@ -0,0 +1,137 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! A module for handling configurations.
|
||||
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
fmt::{self, Display},
|
||||
};
|
||||
|
||||
/// A configuration that looks like "cfg(k1=v1, k2=v2, ...)".
|
||||
#[derive(Debug, Clone, Eq, Ord, PartialOrd, PartialEq, Serialize)]
|
||||
pub struct Cfg(BTreeMap<String, String>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CfgParseError(String);
|
||||
|
||||
impl fmt::Display for CfgParseError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Failed to parse cfg: {}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::StdError for CfgParseError {}
|
||||
impl serde::de::Error for CfgParseError {
|
||||
fn custom<T: fmt::Display>(msg: T) -> Self {
|
||||
Self(msg.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl CfgParseError {
|
||||
pub fn new(s: &str) -> Self {
|
||||
Self(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// This is to allow constructions like `Cfg::from([("arch", "foo"), ("select", "bar")])`.
|
||||
/// Making things easier for testing.
|
||||
impl<K, V, const N: usize> From<[(K, V); N]> for Cfg
|
||||
where
|
||||
K: Into<String>,
|
||||
V: Into<String>,
|
||||
{
|
||||
fn from(array: [(K, V); N]) -> Self {
|
||||
let mut cfg = BTreeMap::new();
|
||||
for (k, v) in array.into_iter() {
|
||||
cfg.insert(k.into(), v.into());
|
||||
}
|
||||
Self(cfg)
|
||||
}
|
||||
}
|
||||
|
||||
impl Cfg {
|
||||
pub fn new() -> Self {
|
||||
Self(BTreeMap::new())
|
||||
}
|
||||
|
||||
pub fn from_str(s: &str) -> Result<Self, CfgParseError> {
|
||||
let s = s.trim();
|
||||
|
||||
// Match the leading "cfg(" and trailing ")"
|
||||
if !s.starts_with("cfg(") || !s.ends_with(')') {
|
||||
return Err(CfgParseError::new(s));
|
||||
}
|
||||
let s = &s[4..s.len() - 1];
|
||||
|
||||
let mut cfg = BTreeMap::new();
|
||||
for kv in s.split(',').map(|s| s.trim()).filter(|s| !s.is_empty()) {
|
||||
let kv: Vec<_> = kv.split('=').collect();
|
||||
if kv.len() != 2 {
|
||||
return Err(CfgParseError::new(s));
|
||||
}
|
||||
cfg.insert(
|
||||
kv[0].trim().to_string(),
|
||||
kv[1].trim().trim_matches('\"').to_string(),
|
||||
);
|
||||
}
|
||||
Ok(Self(cfg))
|
||||
}
|
||||
|
||||
pub fn check_allowed(&self, allowed_keys: &[&str]) -> bool {
|
||||
for (k, _) in self.0.iter() {
|
||||
if allowed_keys.iter().all(|&key| k != key) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, k: String, v: String) {
|
||||
self.0.insert(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Cfg {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "cfg(")?;
|
||||
for (i, (k, v)) in self.0.iter().enumerate() {
|
||||
write!(f, "{}=\"{}\"", k, v)?;
|
||||
if i != self.0.len() - 1 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_cfg_from_str() {
|
||||
let cfg = Cfg::from([("arch", "x86_64"), ("select", "foo")]);
|
||||
let cfg1 = Cfg::from_str("cfg(arch = \"x86_64\", select=\"foo\", )").unwrap();
|
||||
let cfg2 = Cfg::from_str("cfg(arch=\"x86_64\",select=\"foo\")").unwrap();
|
||||
let cfg3 = Cfg::from_str("cfg( arch=\"x86_64\", select=\"foo\" )").unwrap();
|
||||
assert_eq!(cfg, cfg1);
|
||||
assert_eq!(cfg, cfg2);
|
||||
assert_eq!(cfg, cfg3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cfg_display() {
|
||||
let cfg = Cfg::from([("arch", "x86_64"), ("select", "foo")]);
|
||||
let cfg_string = cfg.to_string();
|
||||
let cfg_back = Cfg::from_str(&cfg_string).unwrap();
|
||||
assert_eq!(cfg_string, "cfg(arch=\"x86_64\", select=\"foo\")");
|
||||
assert_eq!(cfg, cfg_back);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_cfg_strings() {
|
||||
Cfg::from_str("cfg(,,,,arch=\"x86_64 \", select=\"foo\")").is_err();
|
||||
Cfg::from_str("cfg(arch=\"x86_64\", select=\"foo\"").is_err();
|
||||
Cfg::from_str("cfg(arch=x86_64,,, select=\"foo\") ").is_err();
|
||||
}
|
||||
}
|
@ -5,13 +5,13 @@ use std::{
|
||||
process,
|
||||
};
|
||||
|
||||
use regex::Regex;
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::{
|
||||
boot::Boot,
|
||||
qemu::{CfgQemu, Qemu},
|
||||
};
|
||||
use crate::config_manager::cfg::Cfg;
|
||||
use crate::{error::Errno, error_msg};
|
||||
|
||||
/// The osdk manifest from configuration file and command line arguments.
|
||||
@ -24,9 +24,10 @@ pub struct OsdkManifest {
|
||||
}
|
||||
|
||||
impl OsdkManifest {
|
||||
pub fn from_toml_manifest<S: AsRef<str>>(
|
||||
pub fn from_toml_manifest(
|
||||
toml_manifest: TomlManifest,
|
||||
selection: Option<S>,
|
||||
arch: Option<String>,
|
||||
selection: Option<String>,
|
||||
) -> Self {
|
||||
let TomlManifest {
|
||||
mut kcmd_args,
|
||||
@ -35,9 +36,9 @@ impl OsdkManifest {
|
||||
boot,
|
||||
qemu,
|
||||
} = toml_manifest;
|
||||
let CfgQemu { default, cfg } = qemu;
|
||||
let CfgQemu { default, cfg_map } = qemu;
|
||||
|
||||
let Some(cfg) = cfg else {
|
||||
let Some(cfg_map) = cfg_map else {
|
||||
return Self {
|
||||
kcmd_args,
|
||||
initramfs,
|
||||
@ -46,32 +47,46 @@ impl OsdkManifest {
|
||||
};
|
||||
};
|
||||
|
||||
for cfg in cfg.keys() {
|
||||
check_cfg(cfg);
|
||||
for cfg in cfg_map.keys() {
|
||||
const ALLOWED_KEYS: &[&str] = &["arch", "select"];
|
||||
if !cfg.check_allowed(ALLOWED_KEYS) {
|
||||
error_msg!("cfg {:#?} is not allowed to be used in `OSDK.toml`", cfg);
|
||||
process::exit(Errno::ParseMetadata as _);
|
||||
}
|
||||
}
|
||||
|
||||
let mut qemu_args = None;
|
||||
|
||||
let mut selected_args: Vec<_> = if let Some(sel) = selection {
|
||||
cfg.into_iter()
|
||||
.filter_map(|(cfg, args)| {
|
||||
if cfg.contains(sel.as_ref()) {
|
||||
Some(args)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
let mut args_matches: Vec<_> = if arch.is_none() && selection.is_none() {
|
||||
vec![]
|
||||
} else {
|
||||
let mut need_cfg = Cfg::new();
|
||||
if let Some(arch) = arch {
|
||||
need_cfg.insert("arch".to_string(), arch);
|
||||
}
|
||||
if let Some(selection) = selection {
|
||||
need_cfg.insert("select".to_string(), selection);
|
||||
}
|
||||
cfg_map
|
||||
.into_iter()
|
||||
.filter_map(
|
||||
|(cfg, args)| {
|
||||
if need_cfg == cfg {
|
||||
Some(args)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
.collect()
|
||||
};
|
||||
|
||||
if selected_args.len() > 1 {
|
||||
error_msg!("Multiple selections are not allowed");
|
||||
if args_matches.len() > 1 {
|
||||
error_msg!("Multiple CFGs matched using the command line arguments");
|
||||
process::exit(Errno::ParseMetadata as _);
|
||||
} else if selected_args.len() == 1 {
|
||||
qemu_args = Some(selected_args.remove(0));
|
||||
} else if selected_args.is_empty() {
|
||||
} else if args_matches.len() == 1 {
|
||||
qemu_args = Some(args_matches.remove(0));
|
||||
} else if args_matches.is_empty() {
|
||||
qemu_args = Some(default);
|
||||
}
|
||||
|
||||
@ -146,28 +161,3 @@ fn check_args(arg_name: &str, args: &[String]) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check cfg that is in the form that we can accept
|
||||
fn check_cfg(cfg: &str) {
|
||||
if SELECT_REGEX.captures(cfg).is_none() {
|
||||
error_msg!("{} is not allowed to be used after `qemu` in `OSDK.toml`. Currently we only allow cfgs like `cfg(select=\"foo\")`", cfg);
|
||||
process::exit(Errno::ParseMetadata as _);
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref SELECT_REGEX: Regex = Regex::new(r#"cfg\(select="(?P<select>\w+)"\)"#).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn extract_selection() {
|
||||
let text = "cfg(select=\"abc123_\")";
|
||||
let captures = SELECT_REGEX.captures(text).unwrap();
|
||||
let selection = captures.name("select").unwrap().as_str();
|
||||
assert_eq!(selection, "abc123_");
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
//! `RunConfig` and `TestConfig`. These `*Config` are used for `build`, `run` and `test` subcommand.
|
||||
|
||||
pub mod boot;
|
||||
pub mod cfg;
|
||||
pub mod manifest;
|
||||
pub mod qemu;
|
||||
|
||||
@ -22,6 +23,7 @@ use self::{
|
||||
manifest::{OsdkManifest, TomlManifest},
|
||||
};
|
||||
use crate::{
|
||||
arch::{get_default_arch, Arch},
|
||||
cli::{BuildArgs, CargoArgs, DebugArgs, GdbServerArgs, OsdkArgs, RunArgs, TestArgs},
|
||||
error::Errno,
|
||||
error_msg,
|
||||
@ -39,14 +41,17 @@ fn get_final_manifest(cargo_args: &CargoArgs, osdk_args: &OsdkArgs) -> OsdkManif
|
||||
/// Configurations for build subcommand
|
||||
#[derive(Debug)]
|
||||
pub struct BuildConfig {
|
||||
pub arch: Arch,
|
||||
pub manifest: OsdkManifest,
|
||||
pub cargo_args: CargoArgs,
|
||||
}
|
||||
|
||||
impl BuildConfig {
|
||||
pub fn parse(args: &BuildArgs) -> Self {
|
||||
let arch = args.osdk_args.arch.clone().unwrap_or_else(get_default_arch);
|
||||
let cargo_args = parse_cargo_args(&args.cargo_args);
|
||||
Self {
|
||||
arch,
|
||||
manifest: get_final_manifest(&cargo_args, &args.osdk_args),
|
||||
cargo_args,
|
||||
}
|
||||
@ -56,6 +61,7 @@ impl BuildConfig {
|
||||
/// Configurations for run subcommand
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RunConfig {
|
||||
pub arch: Arch,
|
||||
pub manifest: OsdkManifest,
|
||||
pub cargo_args: CargoArgs,
|
||||
pub gdb_server_args: GdbServerArgs,
|
||||
@ -63,8 +69,10 @@ pub struct RunConfig {
|
||||
|
||||
impl RunConfig {
|
||||
pub fn parse(args: &RunArgs) -> Self {
|
||||
let arch = args.osdk_args.arch.clone().unwrap_or_else(get_default_arch);
|
||||
let cargo_args = parse_cargo_args(&args.cargo_args);
|
||||
Self {
|
||||
arch,
|
||||
manifest: get_final_manifest(&cargo_args, &args.osdk_args),
|
||||
cargo_args,
|
||||
gdb_server_args: args.gdb_server_args.clone(),
|
||||
@ -90,6 +98,7 @@ impl DebugConfig {
|
||||
/// Configurations for test subcommand
|
||||
#[derive(Debug)]
|
||||
pub struct TestConfig {
|
||||
pub arch: Arch,
|
||||
pub manifest: OsdkManifest,
|
||||
pub cargo_args: CargoArgs,
|
||||
pub test_name: Option<String>,
|
||||
@ -97,8 +106,10 @@ pub struct TestConfig {
|
||||
|
||||
impl TestConfig {
|
||||
pub fn parse(args: &TestArgs) -> Self {
|
||||
let arch = args.osdk_args.arch.clone().unwrap_or_else(get_default_arch);
|
||||
let cargo_args = parse_cargo_args(&args.cargo_args);
|
||||
Self {
|
||||
arch,
|
||||
manifest: get_final_manifest(&cargo_args, &args.osdk_args),
|
||||
cargo_args,
|
||||
test_name: args.test_name.clone(),
|
||||
@ -109,7 +120,7 @@ impl TestConfig {
|
||||
/// FIXME: I guess OSDK manifest is definitely NOT per workspace. It's per crate. When you cannot
|
||||
/// find a manifest per crate, find it in the upper levels.
|
||||
/// I don't bother to do it now, just fix the relpaths.
|
||||
fn load_osdk_manifest<S: AsRef<str>>(cargo_args: &CargoArgs, selection: Option<S>) -> OsdkManifest {
|
||||
fn load_osdk_manifest(cargo_args: &CargoArgs, osdk_args: &OsdkArgs) -> OsdkManifest {
|
||||
let feature_strings = get_feature_strings(cargo_args);
|
||||
let cargo_metadata = get_cargo_metadata(None::<&str>, Some(&feature_strings)).unwrap();
|
||||
let workspace_root = PathBuf::from(
|
||||
@ -138,7 +149,14 @@ fn load_osdk_manifest<S: AsRef<str>>(cargo_args: &CargoArgs, selection: Option<S
|
||||
);
|
||||
process::exit(Errno::ParseMetadata as _);
|
||||
});
|
||||
let mut osdk_manifest = OsdkManifest::from_toml_manifest(toml_manifest, selection);
|
||||
let mut osdk_manifest = OsdkManifest::from_toml_manifest(
|
||||
toml_manifest,
|
||||
osdk_args
|
||||
.arch
|
||||
.as_ref()
|
||||
.map(|s| s.to_string()),
|
||||
osdk_args.select.as_ref().map(|s| s.to_string()),
|
||||
);
|
||||
osdk_manifest.check_canonicalize_all_paths(workspace_root);
|
||||
osdk_manifest
|
||||
}
|
||||
@ -147,13 +165,15 @@ fn load_osdk_manifest<S: AsRef<str>>(cargo_args: &CargoArgs, selection: Option<S
|
||||
/// 1. Split `features` in `cargo_args` to ensure each string contains exactly one feature.
|
||||
/// 2. Change `profile` to `release` if `--release` is set.
|
||||
fn parse_cargo_args(cargo_args: &CargoArgs) -> CargoArgs {
|
||||
let features = cargo_args
|
||||
.features
|
||||
.iter()
|
||||
.flat_map(|feature| feature.split(','))
|
||||
.filter(|feature| !feature.is_empty())
|
||||
.map(|feature| feature.to_string())
|
||||
.collect();
|
||||
let mut features = Vec::new();
|
||||
|
||||
for feature in cargo_args.features.iter() {
|
||||
for feature in feature.split(',') {
|
||||
if !feature.is_empty() {
|
||||
features.push(feature.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let profile = if cargo_args.release {
|
||||
"release".to_string()
|
||||
@ -165,7 +185,6 @@ fn parse_cargo_args(cargo_args: &CargoArgs) -> CargoArgs {
|
||||
profile,
|
||||
release: cargo_args.release,
|
||||
features,
|
||||
override_configs: cargo_args.override_configs.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ use serde::{
|
||||
Deserialize, Deserializer,
|
||||
};
|
||||
|
||||
use super::cfg::Cfg;
|
||||
use super::get_key;
|
||||
use crate::{error::Errno, error_msg};
|
||||
|
||||
@ -38,12 +39,12 @@ pub struct DriveFile {
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize)]
|
||||
pub struct CfgQemu {
|
||||
pub default: Qemu,
|
||||
pub cfg: Option<BTreeMap<String, Qemu>>,
|
||||
pub cfg_map: Option<BTreeMap<Cfg, Qemu>>,
|
||||
}
|
||||
|
||||
impl CfgQemu {
|
||||
pub fn new(default: Qemu, cfg: Option<BTreeMap<String, Qemu>>) -> Self {
|
||||
Self { default, cfg }
|
||||
pub fn new(default: Qemu, cfg_map: Option<BTreeMap<Cfg, Qemu>>) -> Self {
|
||||
Self { default, cfg_map }
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,7 +58,7 @@ impl<'de> Deserialize<'de> for CfgQemu {
|
||||
Args,
|
||||
Machine,
|
||||
DriveFiles,
|
||||
Cfg(String),
|
||||
Cfg(Cfg),
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Field {
|
||||
@ -83,7 +84,10 @@ impl<'de> Deserialize<'de> for CfgQemu {
|
||||
"machine" => Ok(Field::Machine),
|
||||
"path" => Ok(Field::Path),
|
||||
"drive_files" => Ok(Field::DriveFiles),
|
||||
v => Ok(Field::Cfg(v.to_string())),
|
||||
v => Ok(Field::Cfg(Cfg::from_str(v).unwrap_or_else(|e| {
|
||||
error_msg!("Error parsing cfg: {}", e);
|
||||
process::exit(Errno::ParseMetadata as _);
|
||||
}))),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -106,7 +110,7 @@ impl<'de> Deserialize<'de> for CfgQemu {
|
||||
A: de::MapAccess<'de>,
|
||||
{
|
||||
let mut default = Qemu::default();
|
||||
let mut cfgs = BTreeMap::new();
|
||||
let mut cfg_map = BTreeMap::<Cfg, Qemu>::new();
|
||||
|
||||
while let Some(key) = map.next_key()? {
|
||||
match key {
|
||||
@ -124,12 +128,12 @@ impl<'de> Deserialize<'de> for CfgQemu {
|
||||
}
|
||||
Field::Cfg(cfg) => {
|
||||
let qemu_args = map.next_value()?;
|
||||
cfgs.insert(cfg, qemu_args);
|
||||
cfg_map.insert(cfg, qemu_args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(CfgQemu::new(default, Some(cfgs)))
|
||||
Ok(CfgQemu::new(default, Some(cfg_map)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,6 +147,7 @@ pub enum QemuMachine {
|
||||
Microvm,
|
||||
#[default]
|
||||
Q35,
|
||||
Virt,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for QemuMachine {
|
||||
@ -150,6 +155,7 @@ impl<'a> From<&'a str> for QemuMachine {
|
||||
match value {
|
||||
"microvm" => Self::Microvm,
|
||||
"q35" => Self::Q35,
|
||||
"virt" => Self::Virt,
|
||||
_ => {
|
||||
error_msg!("{} is not a valid option for `qemu.machine`", value);
|
||||
process::exit(Errno::ParseMetadata as _);
|
||||
|
@ -5,7 +5,7 @@ args = [
|
||||
"-device virtio-serial-pci,disable-legacy=on,disable-modern=off"
|
||||
]
|
||||
|
||||
[qemu.'cfg(select="intel_tdx")']
|
||||
[qemu.'cfg(arch="x86_64", select="intel_tdx")']
|
||||
|
||||
[qemu.'cfg(select="iommu")']
|
||||
args = [
|
||||
|
@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::*;
|
||||
use crate::config_manager::cfg::Cfg;
|
||||
|
||||
#[test]
|
||||
fn split_kcmd_args_test() {
|
||||
@ -83,6 +84,26 @@ fn apply_kv_array_test() {
|
||||
assert_eq!(expected, array);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cfg_from_str() {
|
||||
let cfg = Cfg::from([("arch", "x86_64"), ("select", "foo")]);
|
||||
let cfg1 = Cfg::from_str(" cfg(arch = \"x86_64\", select=\"foo\", )").unwrap();
|
||||
let cfg2 = Cfg::from_str("cfg(arch=\"x86_64\",select=\"foo\")").unwrap();
|
||||
let cfg3 = Cfg::from_str(" cfg( arch=\"x86_64\", select=\"foo\" )").unwrap();
|
||||
assert_eq!(cfg, cfg1);
|
||||
assert_eq!(cfg, cfg2);
|
||||
assert_eq!(cfg, cfg3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cfg_display() {
|
||||
let cfg = Cfg::from([("arch", "x86_64"), ("select", "foo")]);
|
||||
let cfg_string = cfg.to_string();
|
||||
let cfg_back = Cfg::from_str(&cfg_string).unwrap();
|
||||
assert_eq!(cfg_string, "cfg(arch=\"x86_64\", select=\"foo\")");
|
||||
assert_eq!(cfg, cfg_back);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_osdk_manifest() {
|
||||
let content = include_str!("OSDK.toml.empty");
|
||||
@ -116,37 +137,40 @@ fn conditional_manifest() {
|
||||
toml::from_str(content).unwrap()
|
||||
};
|
||||
|
||||
assert!(toml_manifest.qemu.cfg.is_some());
|
||||
assert!(toml_manifest.qemu.cfg_map.is_some());
|
||||
assert!(toml_manifest
|
||||
.qemu
|
||||
.cfg
|
||||
.cfg_map
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.contains_key(&String::from("cfg(select=\"intel_tdx\")")));
|
||||
.contains_key(&Cfg::from([("arch", "x86_64"), ("select", "intel_tdx")])));
|
||||
assert!(toml_manifest
|
||||
.qemu
|
||||
.cfg
|
||||
.cfg_map
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.contains_key(&String::from("cfg(select=\"iommu\")")));
|
||||
.contains_key(&Cfg::from([("select", "iommu")])));
|
||||
|
||||
// Default selection
|
||||
let selection: Option<&str> = None;
|
||||
let manifest = OsdkManifest::from_toml_manifest(toml_manifest.clone(), selection);
|
||||
let arch = None;
|
||||
let selection: Option<String> = None;
|
||||
let manifest = OsdkManifest::from_toml_manifest(toml_manifest.clone(), arch, selection);
|
||||
assert!(manifest.qemu.args.contains(&String::from(
|
||||
"-device virtio-keyboard-pci,disable-legacy=on,disable-modern=off"
|
||||
)));
|
||||
|
||||
// Iommu
|
||||
let selection: Option<&str> = Some("iommu");
|
||||
let manifest = OsdkManifest::from_toml_manifest(toml_manifest.clone(), selection);
|
||||
let arch = None;
|
||||
let selection: Option<String> = Some("iommu".to_owned());
|
||||
let manifest = OsdkManifest::from_toml_manifest(toml_manifest.clone(), arch, selection);
|
||||
assert!(manifest
|
||||
.qemu
|
||||
.args
|
||||
.contains(&String::from("-device ioh3420,id=pcie.0,chassis=1")));
|
||||
|
||||
// Tdx
|
||||
let selection: Option<&str> = Some("intel_tdx");
|
||||
let manifest = OsdkManifest::from_toml_manifest(toml_manifest.clone(), selection);
|
||||
let arch = Some("x86_64".to_owned());
|
||||
let selection: Option<String> = Some("intel_tdx".to_owned());
|
||||
let manifest = OsdkManifest::from_toml_manifest(toml_manifest.clone(), arch, selection);
|
||||
assert!(manifest.qemu.args.is_empty());
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ extern crate log;
|
||||
#[macro_use]
|
||||
extern crate serde;
|
||||
|
||||
mod arch;
|
||||
mod base_crate;
|
||||
mod bundle;
|
||||
mod cli;
|
||||
|
Loading…
x
Reference in New Issue
Block a user