From b18204458b5fb7fcf55e817a646188cc0891e93e Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 26 Mar 2019 19:23:50 +0100 Subject: [PATCH 01/50] Update to 2018 edition --- Cargo.toml | 1 + src/args.rs | 2 +- src/build.rs | 4 ++-- src/main.rs | 6 ------ src/test.rs | 4 ++-- 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ff9eb3f..2f9d9bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ license = "MIT/Apache-2.0" name = "bootimage" version = "0.6.6" repository = "https://github.com/rust-osdev/bootimage" +edition = "2018" [dependencies] byteorder = "1.3.1" diff --git a/src/args.rs b/src/args.rs index 7fcc5b9..c9e8314 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; use std::{env, mem}; -use Command; +use crate::Command; pub(crate) fn parse_args() -> Command { let mut args = env::args().skip(1); diff --git a/src/build.rs b/src/build.rs index f1bc258..68560aa 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1,7 +1,7 @@ -use args::{self, Args}; +use crate::args::{self, Args}; use byteorder::{ByteOrder, LittleEndian}; use cargo_metadata::{self, Metadata as CargoMetadata}; -use config::{self, Config}; +use crate::config::{self, Config}; use failure::{self, Error, ResultExt}; use std::fs::File; use std::io::Write; diff --git a/src/main.rs b/src/main.rs index 4064403..2f3c49c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,3 @@ -extern crate byteorder; -extern crate cargo_metadata; -extern crate rayon; -extern crate toml; -extern crate wait_timeout; -extern crate xmas_elf; #[macro_use] extern crate failure; diff --git a/src/test.rs b/src/test.rs index b173e4a..8ff8dac 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,5 +1,5 @@ -use args::Args; -use build; +use crate::args::Args; +use crate::build; use failure::{Error, ResultExt}; use rayon::prelude::*; use std::io::Write; From 3d508ca922a5ca61d17df5a3b00fe0e9b6c58652 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 26 Mar 2019 23:27:17 +0100 Subject: [PATCH 02/50] Rewrite for new bootloader build system --- Cargo.lock | 23 ++ Cargo.toml | 2 + src/args.rs | 11 +- src/build.rs | 459 ----------------------------------- src/config.rs | 17 +- src/lib.rs | 434 +++++++++++++++++++++++++++++++++ src/main.rs | 40 ++- src/subcommand.rs | 3 + src/subcommand/build.rs | 67 +++++ src/subcommand/run.rs | 33 +++ src/{ => subcommand}/test.rs | 44 ++-- 11 files changed, 629 insertions(+), 504 deletions(-) delete mode 100644 src/build.rs create mode 100644 src/lib.rs create mode 100644 src/subcommand.rs create mode 100644 src/subcommand/build.rs create mode 100644 src/subcommand/run.rs rename src/{ => subcommand}/test.rs (85%) diff --git a/Cargo.lock b/Cargo.lock index 5d402a4..6b27efa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,6 +36,8 @@ dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "locate-cargo-manifest 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -128,6 +130,11 @@ name = "itoa" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "json" +version = "0.11.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lazy_static" version = "1.2.0" @@ -138,6 +145,19 @@ name = "libc" version = "0.2.42" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "llvm-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "locate-cargo-manifest" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "memoffset" version = "0.2.1" @@ -321,8 +341,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606" +"checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" "checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" +"checksum llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "955be5d0ca0465caf127165acb47964f911e2bc26073e865deb8be7189302faf" +"checksum locate-cargo-manifest 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d87d2c1ca6d2636268f961e70b024866db2d8244a46687527e7ed1a9360b8de" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" diff --git a/Cargo.toml b/Cargo.toml index 2f9d9bc..ded8653 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,8 @@ rayon = "1.0" toml = "0.5.0" wait-timeout = "0.2" xmas-elf = "0.6.2" +llvm-tools = "0.1.1" +locate-cargo-manifest = "0.1.0" [dependencies.cargo_metadata] version = "0.7.4" diff --git a/src/args.rs b/src/args.rs index c9e8314..e4c0041 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,6 +1,6 @@ +use crate::{config::Config, Command}; use std::path::{Path, PathBuf}; use std::{env, mem}; -use crate::Command; pub(crate) fn parse_args() -> Command { let mut args = env::args().skip(1); @@ -184,4 +184,13 @@ impl Args { self.cargo_args.push("--bin".into()); self.cargo_args.push(bin_name); } + + pub fn apply_default_target(&mut self, config: &Config, crate_root: &Path) { + if self.target().is_none() { + if let Some(ref target) = config.default_target { + let canonicalized_target = crate_root.join(target); + self.set_target(canonicalized_target.to_string_lossy().into_owned()); + } + } + } } diff --git a/src/build.rs b/src/build.rs deleted file mode 100644 index 68560aa..0000000 --- a/src/build.rs +++ /dev/null @@ -1,459 +0,0 @@ -use crate::args::{self, Args}; -use byteorder::{ByteOrder, LittleEndian}; -use cargo_metadata::{self, Metadata as CargoMetadata}; -use crate::config::{self, Config}; -use failure::{self, Error, ResultExt}; -use std::fs::File; -use std::io::Write; -use std::path::{Path, PathBuf}; -use std::{fmt, io, process}; -use xmas_elf; - -const BLOCK_SIZE: usize = 512; -type KernelInfoBlock = [u8; BLOCK_SIZE]; - -pub(crate) fn build(args: Args) -> Result<(), Error> { - let (args, config, metadata, root_dir, out_dir) = common_setup(args)?; - - build_impl(&args, &config, &metadata, &root_dir, &out_dir, true)?; - Ok(()) -} - -pub(crate) fn run(args: Args) -> Result<(), Error> { - let (args, config, metadata, root_dir, out_dir) = common_setup(args)?; - - let output_path = build_impl(&args, &config, &metadata, &root_dir, &out_dir, true)?; - run_impl(&args, &config, &output_path) -} - -pub(crate) fn common_setup( - mut args: Args, -) -> Result<(Args, Config, CargoMetadata, PathBuf, PathBuf), Error> { - fn out_dir(args: &Args, metadata: &CargoMetadata) -> PathBuf { - let target_dir = PathBuf::from(&metadata.target_directory); - let mut out_dir = target_dir; - if let &Some(ref target) = args.target() { - out_dir.push(Path::new(target).file_stem().unwrap().to_str().unwrap()); - } - if args.release() { - out_dir.push("release"); - } else { - out_dir.push("debug"); - } - out_dir - } - - let metadata = read_cargo_metadata(&args)?; - let manifest_path = args - .manifest_path() - .as_ref() - .map(Clone::clone) - .unwrap_or(Path::new("Cargo.toml").canonicalize().unwrap()); - let crate_root = manifest_path.parent().unwrap().to_path_buf(); - let config = config::read_config(manifest_path)?; - - if args.target().is_none() { - if let Some(ref target) = config.default_target { - let mut canonicalized_target = crate_root.clone(); - canonicalized_target.push(target); - args.set_target(canonicalized_target.to_string_lossy().into_owned()); - } - } - - if let &Some(ref target) = args.target() { - if !target.ends_with(".json") { - use std::io::{self, Write}; - use std::process; - - writeln!( - io::stderr(), - "Please pass a path to `--target` (with `.json` extension`): `--target {}.json`", - target - ) - .unwrap(); - process::exit(1); - } - } - - let out_dir = out_dir(&args, &metadata); - - Ok((args, config, metadata, crate_root, out_dir)) -} - -pub(crate) fn build_impl( - args: &Args, - config: &Config, - metadata: &CargoMetadata, - root_dir: &Path, - out_dir: &Path, - verbose: bool, -) -> Result { - let crate_ = metadata - .packages - .iter() - .find(|p| { - Path::new(&p.manifest_path) - .canonicalize() - .map(|path| path == config.manifest_path) - .unwrap_or(false) - }) - .expect("Could not read crate name from cargo metadata"); - let bin_name: String = args.bin_name().as_ref().unwrap_or(&crate_.name).clone(); - - let kernel = build_kernel(&out_dir, &bin_name, &args, verbose)?; - - let maybe_package = if let Some(ref path) = config.package_filepath { - Some( - File::open(path) - .with_context(|e| format!("Unable to open specified package file: {}", e))?, - ) - } else { - None - }; - - let maybe_package_size = if let Some(ref file) = maybe_package { - Some( - file.metadata() - .with_context(|e| format!("Failed to read specified package file: {}", e))? - .len(), - ) - } else { - None - }; - - let kernel_size = kernel - .metadata() - .with_context(|e| format!("Failed to read kernel output file: {}", e))? - .len(); - let kernel_info_block = create_kernel_info_block(kernel_size, maybe_package_size); - - let bootloader = build_bootloader(&metadata, &config) - .with_context(|e| format!("Failed to build bootloader: {}", e))?; - - create_disk_image( - root_dir, - out_dir, - &bin_name, - &config, - kernel, - maybe_package, - kernel_info_block, - &bootloader, - verbose, - ) -} - -fn run_impl(args: &Args, config: &Config, output_path: &Path) -> Result<(), Error> { - let command = &config.run_command[0]; - let mut command = process::Command::new(command); - for arg in &config.run_command[1..] { - command.arg(arg.replace( - "{}", - output_path.to_str().expect("output must be valid unicode"), - )); - } - command.args(&args.run_args); - command - .status() - .with_context(|e| format!("Failed to execute run `{:?}`: {}", command, e))?; - Ok(()) -} - -#[derive(Debug)] -pub struct CargoMetadataError { - error: String, -} - -impl fmt::Display for CargoMetadataError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.error) - } -} - -impl failure::Fail for CargoMetadataError {} - -fn read_cargo_metadata(args: &Args) -> Result { - run_cargo_fetch(args); - let metadata = { - let mut cmd = cargo_metadata::MetadataCommand::new(); - if let Some(ref path) = args.manifest_path() { - cmd.manifest_path(path.as_path()); - } - cmd.exec().map_err(|e| CargoMetadataError { - error: format!("{}", e), - })? - }; - Ok(metadata) -} - -fn build_kernel( - out_dir: &Path, - bin_name: &str, - args: &args::Args, - verbose: bool, -) -> Result { - // compile kernel - if verbose { - println!("Building kernel"); - } - let exit_status = run_xbuild(&args.cargo_args) - .with_context(|e| format!("Failed to run `cargo xbuild`: {}", e))?; - if !exit_status.success() { - process::exit(1) - } - - let mut kernel_path = out_dir.to_owned(); - kernel_path.push(bin_name); - let kernel = File::open(kernel_path) - .with_context(|e| format!("Failed to open kernel output file: {}", e))?; - Ok(kernel) -} - -fn run_xbuild(args: &[String]) -> io::Result { - let mut command = process::Command::new("cargo"); - command.arg("xbuild"); - command.args(args); - let exit_status = command.status()?; - - if !exit_status.success() { - let mut help_command = process::Command::new("cargo"); - help_command.arg("xbuild").arg("--help"); - help_command.stdout(process::Stdio::null()); - help_command.stderr(process::Stdio::null()); - if let Ok(help_exit_status) = help_command.status() { - if !help_exit_status.success() { - let mut stderr = io::stderr(); - writeln!( - stderr, - "Failed to run `cargo xbuild`. Perhaps it is not installed?" - )?; - writeln!(stderr, "Run `cargo install cargo-xbuild` to install it.")?; - } - } - } - - Ok(exit_status) -} - -fn run_cargo_fetch(args: &Args) { - let mut command = process::Command::new("cargo"); - command.arg("fetch"); - if let Some(manifest_path) = args.manifest_path() { - command.arg("--manifest-path"); - command.arg(manifest_path); - } - if !command.status().map(|s| s.success()).unwrap_or(false) { - process::exit(1); - } -} - -fn create_kernel_info_block(kernel_size: u64, maybe_package_size: Option) -> KernelInfoBlock { - let kernel_size = if kernel_size <= u64::from(u32::max_value()) { - kernel_size as u32 - } else { - panic!("Kernel can't be loaded by BIOS bootloader because is too big") - }; - - let package_size = if let Some(size) = maybe_package_size { - if size <= u64::from(u32::max_value()) { - size as u32 - } else { - panic!("Package can't be loaded by BIOS bootloader because is too big") - } - } else { - 0 - }; - - let mut kernel_info_block = [0u8; BLOCK_SIZE]; - LittleEndian::write_u32(&mut kernel_info_block[0..4], kernel_size); - LittleEndian::write_u32(&mut kernel_info_block[8..12], package_size); - - kernel_info_block -} - -fn build_bootloader(metadata: &CargoMetadata, config: &Config) -> Result, Error> { - use std::io::Read; - - let bootloader_metadata = metadata.packages.iter().find(|p| { - if let Some(name) = config.bootloader.name.as_ref() { - p.name == name.as_str() - } else { - p.name == "bootloader" || p.name == "bootloader_precompiled" - } - }); - let bootloader_metadata = - match bootloader_metadata { - Some(package_metadata) => package_metadata.clone(), - None => Err(format_err!("Bootloader dependency not found\n\n\ - You need to add a dependency on the `bootloader` or `bootloader_precompiled` crates \ - in your Cargo.toml.\n\nIn case you just updated bootimage from an earlier version, \ - check out the migration guide at https://github.com/rust-osdev/bootimage/pull/16. \ - Alternatively, you can downgrade to bootimage 0.4 again by executing \ - `cargo install bootimage --version {} --force`.", r#""^0.4""# - ))?, - }; - - let bootloader_manifest_path = Path::new(&bootloader_metadata.manifest_path); - let bootloader_dir = bootloader_manifest_path.parent().unwrap(); - - let mut bootloader_target_path = PathBuf::from(bootloader_dir); - bootloader_target_path.push(&config.bootloader.target); - - let bootloader_elf_path = if bootloader_metadata.name == "bootloader_precompiled" { - let mut bootloader_elf_path = bootloader_dir.to_path_buf(); - bootloader_elf_path.push("bootloader"); - bootloader_elf_path - } else { - let mut args = vec![ - String::from("--manifest-path"), - bootloader_metadata - .manifest_path - .as_os_str() - .to_os_string() - .into_string() - .expect("manifest path not valid unicode"), - String::from("--target"), - bootloader_target_path.display().to_string(), - String::from("--release"), - String::from("--features"), - config - .bootloader - .features - .iter() - .fold(String::new(), |i, j| i + " " + j), - ]; - - if !config.bootloader.default_features { - args.push(String::from("--no-default-features")); - } - - println!("Building bootloader v{}", bootloader_metadata.version); - let exit_status = - run_xbuild(&args).with_context(|e| format!("Failed to run `cargo xbuild`: {}", e))?; - if !exit_status.success() { - process::exit(1) - } - - let bootloader_metadata = { - let mut cmd = cargo_metadata::MetadataCommand::new(); - cmd.manifest_path(&bootloader_manifest_path); - cmd.no_deps(); - cmd.exec().map_err(|e| CargoMetadataError { - error: format!("{}", e), - })? - }; - let mut bootloader_elf_path = PathBuf::from(bootloader_metadata.target_directory); - bootloader_elf_path.push(config.bootloader.target.file_stem().unwrap()); - bootloader_elf_path.push("release"); - bootloader_elf_path.push("bootloader"); - bootloader_elf_path - }; - - let mut bootloader_elf_bytes = Vec::new(); - let mut bootloader = File::open(&bootloader_elf_path) - .with_context(|e| format!("Could not open bootloader: {}", e))?; - bootloader - .read_to_end(&mut bootloader_elf_bytes) - .with_context(|e| format!("Could not read bootloader: {}", e))?; - - // copy bootloader section of ELF file to bootloader_path - let elf_file = xmas_elf::ElfFile::new(&bootloader_elf_bytes).unwrap(); - xmas_elf::header::sanity_check(&elf_file).unwrap(); - let bootloader_section = elf_file - .find_section_by_name(".bootloader") - .expect("bootloader must have a .bootloader section"); - - Ok(Vec::from(bootloader_section.raw_data(&elf_file)).into_boxed_slice()) -} - -fn create_disk_image( - root_dir: &Path, - out_dir: &Path, - bin_name: &str, - config: &Config, - mut kernel: File, - mut maybe_package: Option, - kernel_info_block: KernelInfoBlock, - bootloader_data: &[u8], - verbose: bool, -) -> Result { - use std::io::{Read, Write}; - - let mut output_path = PathBuf::from(out_dir); - let file_name = format!("bootimage-{}.bin", bin_name); - output_path.push(file_name); - - if let Some(ref output) = config.output { - output_path = output.clone(); - } - - if verbose { - println!( - "Creating disk image at {}", - output_path - .strip_prefix(root_dir) - .unwrap_or(output_path.as_path()) - .display() - ); - } - let mut output = File::create(&output_path) - .with_context(|e| format!("Could not create output bootimage file: {}", e))?; - output - .write_all(&bootloader_data) - .with_context(|e| format!("Could not write output bootimage file: {}", e))?; - output - .write_all(&kernel_info_block) - .with_context(|e| format!("Could not write output bootimage file: {}", e))?; - - fn write_file_to_file(output: &mut File, datafile: &mut File) -> Result { - let data_size = datafile.metadata()?.len(); - let mut buffer = [0u8; 1024]; - let mut acc = 0; - loop { - let (n, interrupted) = match datafile.read(&mut buffer) { - Ok(0) => break, - Ok(n) => (n, false), - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => (0, true), - Err(e) => Err(e)?, - }; - if !interrupted { - acc += n; - output.write_all(&buffer[..n])? - } - } - - assert!(data_size == acc as u64); - - Ok(acc) - } - - fn pad_file(output: &mut File, written_size: usize, padding: &[u8]) -> Result<(), Error> { - let padding_size = (padding.len() - (written_size % padding.len())) % padding.len(); - output - .write_all(&padding[..padding_size]) - .with_context(|e| format!("Could not write to output file: {}", e))?; - Ok(()) - } - - // write out kernel elf file - - let kernel_size = write_file_to_file(&mut output, &mut kernel)?; - - pad_file(&mut output, kernel_size, &[0; 512])?; - - if let Some(ref mut package) = maybe_package { - println!("Writing specified package to output"); - let package_size = write_file_to_file(&mut output, package)?; - pad_file(&mut output, package_size, &[0; 512])?; - } - - if let Some(min_size) = config.minimum_image_size { - // we already wrote to output successfully, - // both metadata and set_len should succeed. - if output.metadata()?.len() < min_size { - output.set_len(min_size)?; - } - } - - Ok(output_path) -} diff --git a/src/config.rs b/src/config.rs index fad966a..24ca282 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,4 @@ +use crate::ErrorString; use failure::{Error, ResultExt}; use std::path::PathBuf; use toml::Value; @@ -6,11 +7,11 @@ use toml::Value; pub struct Config { pub manifest_path: PathBuf, pub default_target: Option, - pub output: Option, - pub bootloader: BootloaderConfig, - pub minimum_image_size: Option, + pub output: Option, // remove + pub bootloader: BootloaderConfig, // remove + pub minimum_image_size: Option, // remove pub run_command: Vec, - pub package_filepath: Option, + pub package_filepath: Option, // remove } #[derive(Debug, Clone)] @@ -21,7 +22,13 @@ pub struct BootloaderConfig { pub features: Vec, } -pub(crate) fn read_config(manifest_path: PathBuf) -> Result { +pub(crate) fn read_config(manifest_path: PathBuf) -> Result { + let config = read_config_inner(manifest_path) + .map_err(|err| format!("Failed to read bootimage configuration: {:?}", err))?; + Ok(config) +} + +pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result { use std::{fs::File, io::Read}; let cargo_toml: Value = { let mut content = String::new(); diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..73876cd --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,434 @@ +use std::{ + fmt, fs, io, + path::{Path, PathBuf}, + process::{self, Command}, +}; + +pub struct Builder { + kernel_manifest_path: PathBuf, + kernel_metadata: cargo_metadata::Metadata, +} + +impl Builder { + pub fn new(manifest_path: Option) -> Result { + let kernel_manifest_path = + manifest_path.unwrap_or(locate_cargo_manifest::locate_manifest()?); + let kernel_metadata = cargo_metadata::MetadataCommand::new() + .manifest_path(&kernel_manifest_path) + .exec()?; + Ok(Builder { + kernel_manifest_path, + kernel_metadata, + }) + } + + pub fn kernel_manifest_path(&self) -> &Path { + &self.kernel_manifest_path + } + + pub fn kernel_root(&self) -> &Path { + self.kernel_manifest_path + .parent() + .expect("kernel manifest has no parent directory") + } + + pub fn kernel_metadata(&self) -> &cargo_metadata::Metadata { + &self.kernel_metadata + } + + pub fn kernel_package(&self) -> Result<&cargo_metadata::Package, String> { + let mut packages = self.kernel_metadata.packages.iter(); + let kernel_package = packages.find(|p| &p.manifest_path == &self.kernel_manifest_path); + kernel_package.ok_or(format!( + "packages[manifest_path = `{}`]", + &self.kernel_manifest_path.display() + )) + } + + pub fn build_kernel(&self, args: &[String], quiet: bool) -> Result<(), BuildKernelError> { + if !quiet { + println!("Building kernel"); + } + + let cargo = std::env::var("CARGO").unwrap_or("cargo".to_owned()); + let mut cmd = process::Command::new(cargo); + cmd.arg("xbuild"); + cmd.args(args); + if !quiet { + cmd.stdout(process::Stdio::inherit()); + cmd.stderr(process::Stdio::inherit()); + } + let output = cmd.output().map_err(|err| BuildKernelError::Io { + message: "failed to execute kernel build", + error: err, + })?;; + if !output.status.success() { + let mut help_command = process::Command::new("cargo"); + help_command.arg("xbuild").arg("--help"); + help_command.stdout(process::Stdio::null()); + help_command.stderr(process::Stdio::null()); + if let Ok(help_exit_status) = help_command.status() { + if !help_exit_status.success() { + return Err(BuildKernelError::XbuildNotFound); + } + } + return Err(BuildKernelError::XbuildFailed { + stderr: output.stderr, + }); + } + + Ok(()) + } + + pub fn create_bootimage( + &self, + kernel_bin_path: &Path, + output_bin_path: &Path, + quiet: bool, + ) -> Result<(), CreateBootimageError> { + let metadata = self.kernel_metadata(); + + let bootloader_name = { + let kernel_package = self + .kernel_package() + .map_err(|key| CreateBootimageError::CargoMetadataIncomplete { key })?; + let mut dependencies = kernel_package.dependencies.iter(); + let bootloader_package = dependencies + .find(|p| p.rename.as_ref().unwrap_or(&p.name) == "bootloader") + .ok_or(CreateBootimageError::BootloaderNotFound)?; + bootloader_package.name.clone() + }; + let target_dir = metadata + .target_directory + .join("bootimage") + .join(&bootloader_name); + + let bootloader_pkg = metadata + .packages + .iter() + .find(|p| p.name == bootloader_name) + .ok_or(CreateBootimageError::CargoMetadataIncomplete { + key: format!("packages[name = `{}`", &bootloader_name), + })?; + let bootloader_root = bootloader_pkg.manifest_path.parent().ok_or( + CreateBootimageError::BootloaderInvalid( + "bootloader manifest has no target directory".into(), + ), + )?; + let bootloader_features = + { + let resolve = metadata.resolve.as_ref().ok_or( + CreateBootimageError::CargoMetadataIncomplete { + key: "resolve".into(), + }, + )?; + let bootloader_resolve = resolve + .nodes + .iter() + .find(|n| n.id == bootloader_pkg.id) + .ok_or(CreateBootimageError::CargoMetadataIncomplete { + key: format!("resolve[\"{}\"]", bootloader_name), + })?; + bootloader_resolve.features.clone() + }; + let bootloader_target_triple = + default_target_triple_from_cargo_config(&bootloader_root, false) + .map_err(CreateBootimageError::BootloaderInvalid)? + .ok_or(CreateBootimageError::BootloaderInvalid(format!( + "bootloader must have a default target" + )))?; + + // build bootloader + if !quiet { + println!("Building bootloader"); + } + + let cargo = std::env::var("CARGO").unwrap_or("cargo".to_owned()); + let mut cmd = process::Command::new(cargo); + cmd.arg("xbuild"); + cmd.arg("--manifest-path"); + cmd.arg(&bootloader_pkg.manifest_path); + cmd.arg("--target-dir").arg(&target_dir); + cmd.arg("--features") + .arg(bootloader_features.as_slice().join(" ")); + cmd.arg("--release"); + cmd.current_dir(bootloader_root); + cmd.env("KERNEL", kernel_bin_path); + cmd.env_remove("RUSTFLAGS"); + if !quiet { + cmd.stdout(process::Stdio::inherit()); + cmd.stderr(process::Stdio::inherit()); + } + let output = cmd.output().map_err(|err| CreateBootimageError::Io { + message: "failed to execute bootloader build command", + error: err, + })?; + if !output.status.success() { + return Err(CreateBootimageError::BootloaderBuildFailed { + stderr: output.stderr, + }); + } + + let bootloader_elf_path = target_dir + .join(&bootloader_target_triple) + .join("release") + .join(&bootloader_name); + + let llvm_tools = llvm_tools::LlvmTools::new()?; + let objcopy = llvm_tools + .tool(&llvm_tools::exe("llvm-objcopy")) + .ok_or(CreateBootimageError::LlvmObjcopyNotFound)?; + + // convert bootloader to binary + let mut cmd = Command::new(objcopy); + cmd.arg("-I").arg("elf64-x86-64"); + cmd.arg("-O").arg("binary"); + cmd.arg("--binary-architecture=i386:x86-64"); + cmd.arg(&bootloader_elf_path); + cmd.arg(&output_bin_path); + let output = cmd.output().map_err(|err| CreateBootimageError::Io { + message: "failed to execute llvm-objcopy command", + error: err, + })?; + if !output.status.success() { + return Err(CreateBootimageError::ObjcopyFailed { + stderr: output.stderr, + }); + } + + Ok(()) + } +} + +pub fn default_target_triple_from_cargo_config( + crate_root: &Path, + walk_up: bool, +) -> Result, String> { + let default_triple = default_target_from_cargo_config(crate_root, walk_up)?; + default_triple + .map(|(target, crate_root)| { + if target.ends_with(".json") { + crate_root + .join(target) + .file_stem() + .ok_or(String::from( + "The target path specfied in `build.target` has no file stem", + ))? + .to_os_string() + .into_string() + .map_err(|err| format!("Default target triple not valid UTF-8: {:?}", err)) + } else { + Ok(target) + } + }) + .transpose() +} + +fn default_target_from_cargo_config( + crate_root: &Path, + walk_up: bool, +) -> Result, String> { + let mut parent_dir = crate_root; + + loop { + let config_path = parent_dir.join(".cargo/config"); + if config_path.exists() { + let config_content = fs::read_to_string(config_path).map_err(|err| { + format!("Failed to read `.cargo/config` file of crate: {:?}", err) + })?; + let config = config_content.parse::().map_err(|err| { + format!( + "Failed to parse `.cargo/config` of crate as toml: {:?}", + err + ) + })?; + let target = config + .get("build") + .and_then(|v| v.get("target")) + .and_then(|v| v.as_str()) + .map(String::from); + if let Some(target) = target { + return Ok(Some((target, parent_dir.to_owned()))); + } + } + if walk_up { + parent_dir = match parent_dir.parent() { + Some(parent) => parent, + None => break, + } + } else { + break; + } + } + Ok(None) +} + +#[derive(Debug)] +pub enum BuilderError { + /// Failed to locate cargo manifest + LocateCargoManifest(locate_cargo_manifest::LocateManifestError), + /// Error while running `cargo metadata` + CargoMetadata(cargo_metadata::Error), +} + +impl fmt::Display for BuilderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + BuilderError::LocateCargoManifest(err) => writeln!( + f, + "Could not find Cargo.toml file starting from current folder: {:?}", + err + ), + BuilderError::CargoMetadata(err) => writeln!( + f, + "Error while running `cargo metadata` for current project: {:?}", + err + ), + } + } +} + +#[derive(Debug)] +pub enum BuildKernelError { + /// Could not find kernel package in cargo metadata, required for retrieving kernel crate name + KernelPackageNotFound, + /// An unexpected I/O error occurred + Io { + /// Desciption of the failed I/O operation + message: &'static str, + /// The I/O error that occured + error: io::Error, + }, + XbuildNotFound, + XbuildFailed { + stderr: Vec, + }, + CargoConfigInvalid { + path: PathBuf, + error: String, + }, +} + +impl fmt::Display for BuildKernelError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + BuildKernelError::KernelPackageNotFound => { + writeln!(f, "Could not find kernel package in cargo metadata, required for retrieving kernel crate name") + } + BuildKernelError::Io {message, error} => { + writeln!(f, "I/O error: {}: {}", message, error) + } + BuildKernelError::XbuildNotFound => { + writeln!(f, "Failed to run `cargo xbuild`. Perhaps it is not installed?\n\ + Run `cargo install cargo-xbuild` to install it.") + } + BuildKernelError::XbuildFailed{stderr} => { + writeln!(f, "Kernel build failed: {}", String::from_utf8_lossy(stderr)) + } + BuildKernelError::CargoConfigInvalid{path,error} => { + writeln!(f, "Failed to read cargo config at {}: {}", path.display(), error) + }, + } + } +} + +#[derive(Debug)] +pub enum CreateBootimageError { + /// Could not find some required information in the `cargo metadata` output + CargoMetadataIncomplete { + /// The required key that was not found + key: String, + }, + /// Bootloader dependency not found + BootloaderNotFound, + /// Bootloader dependency has not the right format + BootloaderInvalid(String), + BootloaderBuildFailed { + stderr: Vec, + }, + /// An unexpected I/O error occurred + Io { + /// Desciption of the failed I/O operation + message: &'static str, + /// The I/O error that occured + error: io::Error, + }, + /// There was a problem retrieving the `llvm-tools-preview` rustup component + LlvmTools(llvm_tools::Error), + /// The llvm-tools component did not contain the required `llvm-objcopy` executable + LlvmObjcopyNotFound, + /// The `llvm-objcopy` command failed + ObjcopyFailed { + stderr: Vec, + }, +} + +impl fmt::Display for CreateBootimageError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + CreateBootimageError::CargoMetadataIncomplete { key } => writeln!( + f, + "Could not find required key `{}` in cargo metadata output", + key + ), + CreateBootimageError::BootloaderNotFound => { + writeln!(f, "Bootloader dependency not found\n\n\ + You need to add a dependency on a crate named `bootloader` in your Cargo.toml.") + } + CreateBootimageError::BootloaderInvalid(err) => writeln!( + f, + "The `bootloader` dependency has not the right format: {}", + err + ), + CreateBootimageError::BootloaderBuildFailed { stderr } => writeln!( + f, + "Bootloader build failed:\n\n{}", + String::from_utf8_lossy(stderr) + ), + CreateBootimageError::Io { message, error } => { + writeln!(f, "I/O error: {}: {}", message, error) + } + CreateBootimageError::LlvmTools(err) => match err { + llvm_tools::Error::NotFound => writeln!( + f, + "Could not find the `llvm-tools-preview` rustup component.\n\n\ + You can install by executing `rustup component add llvm-tools-preview`." + ), + err => writeln!( + f, + "Failed to locate the `llvm-tools-preview` rustup component: {:?}", + err + ), + }, + CreateBootimageError::LlvmObjcopyNotFound => writeln!( + f, + "Could not find `llvm-objcopy` in the `llvm-tools-preview` rustup component." + ), + CreateBootimageError::ObjcopyFailed { stderr } => writeln!( + f, + "Failed to run `llvm-objcopy`: {}", + String::from_utf8_lossy(stderr) + ), + } + } +} + +// from implementations + +impl From for BuilderError { + fn from(err: locate_cargo_manifest::LocateManifestError) -> Self { + BuilderError::LocateCargoManifest(err) + } +} + +impl From for BuilderError { + fn from(err: cargo_metadata::Error) -> Self { + BuilderError::CargoMetadata(err) + } +} + +impl From for CreateBootimageError { + fn from(err: llvm_tools::Error) -> Self { + CreateBootimageError::LlvmTools(err) + } +} diff --git a/src/main.rs b/src/main.rs index 2f3c49c..70dd72f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,13 +2,13 @@ extern crate failure; use args::Args; -use std::{io, process}; +use std::{fmt, process}; mod args; -mod build; mod config; mod help; -mod test; + +mod subcommand; enum Command { NoSubcommand, @@ -23,20 +23,19 @@ enum Command { } pub fn main() { - use std::io::Write; if let Err(err) = run() { - writeln!(io::stderr(), "Error: {}", err).unwrap(); + eprintln!("Error: {}", err.display()); process::exit(1); } } -fn run() -> Result<(), failure::Error> { +fn run() -> Result<(), ErrorString> { let command = args::parse_args(); match command { + Command::Build(args) => subcommand::build::build(args), + Command::Run(args) => subcommand::run::run(args), + Command::Test(args) => subcommand::test::test(args), Command::NoSubcommand => help::no_subcommand(), - Command::Build(args) => build::build(args), - Command::Run(args) => build::run(args), - Command::Test(args) => test::test(args), Command::Help => Ok(help::help()), Command::BuildHelp => Ok(help::build_help()), Command::RunHelp => Ok(help::run_help()), @@ -44,3 +43,26 @@ fn run() -> Result<(), failure::Error> { Command::Version => Ok(println!("bootimage {}", env!("CARGO_PKG_VERSION"))), } } + +struct ErrorString(Box); + +impl ErrorString { + fn display(&self) -> &dyn fmt::Display { + &self.0 + } +} + +impl fmt::Debug for ErrorString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.display().fmt(f) + } +} + +impl From for ErrorString +where + T: fmt::Display + 'static, +{ + fn from(err: T) -> Self { + ErrorString(Box::new(err)) + } +} diff --git a/src/subcommand.rs b/src/subcommand.rs new file mode 100644 index 0000000..34bfd46 --- /dev/null +++ b/src/subcommand.rs @@ -0,0 +1,3 @@ +pub mod build; +pub mod run; +pub mod test; diff --git a/src/subcommand/build.rs b/src/subcommand/build.rs new file mode 100644 index 0000000..014e069 --- /dev/null +++ b/src/subcommand/build.rs @@ -0,0 +1,67 @@ +use crate::{args::Args, config, ErrorString}; +use bootimage::Builder; +use std::{ + path::{Path, PathBuf}, + process, +}; + +pub(crate) fn build(mut args: Args) -> Result<(), ErrorString> { + let builder = bootimage::Builder::new(args.manifest_path().clone())?; + let config = config::read_config(builder.kernel_manifest_path().to_owned())?; + args.apply_default_target(&config, builder.kernel_root()); + + build_impl(&builder, &mut args, false).map(|_| ()) +} + +pub(crate) fn build_impl( + builder: &Builder, + args: &Args, + quiet: bool, +) -> Result { + run_cargo_fetch(&args); + + builder.build_kernel(&args.cargo_args, quiet)?; + + let out_dir = out_dir(&args, &builder)?; + let kernel_package = builder + .kernel_package() + .map_err(|key| format!("Kernel package not found in cargo metadata (`{}`)", key))?; + let kernel_bin_name = args.bin_name().as_ref().unwrap_or(&kernel_package.name); + let kernel_path = out_dir.join(kernel_bin_name); + + let bootimage_path = out_dir.join(format!("bootimage-{}.bin", kernel_bin_name)); + builder.create_bootimage(&kernel_path, &bootimage_path, quiet)?; + Ok(bootimage_path) +} + +fn out_dir(args: &Args, builder: &bootimage::Builder) -> Result { + let target_dir = PathBuf::from(&builder.kernel_metadata().target_directory); + let mut out_dir = target_dir; + if let &Some(ref target) = args.target() { + out_dir.push(Path::new(target).file_stem().unwrap().to_str().unwrap()); + } else { + let default_triple = + bootimage::default_target_triple_from_cargo_config(builder.kernel_root(), true)?; + if let Some(triple) = default_triple { + out_dir.push(triple); + } + } + if args.release() { + out_dir.push("release"); + } else { + out_dir.push("debug"); + } + Ok(out_dir) +} + +fn run_cargo_fetch(args: &Args) { + let mut command = process::Command::new("cargo"); + command.arg("fetch"); + if let Some(manifest_path) = args.manifest_path() { + command.arg("--manifest-path"); + command.arg(manifest_path); + } + if !command.status().map(|s| s.success()).unwrap_or(false) { + process::exit(1); + } +} diff --git a/src/subcommand/run.rs b/src/subcommand/run.rs new file mode 100644 index 0000000..0804275 --- /dev/null +++ b/src/subcommand/run.rs @@ -0,0 +1,33 @@ +use crate::{args::Args, config, ErrorString}; +use std::process; + +pub(crate) fn run(mut args: Args) -> Result<(), ErrorString> { + use crate::subcommand::build; + + let builder = bootimage::Builder::new(args.manifest_path().clone())?; + let config = config::read_config(builder.kernel_manifest_path().to_owned())?; + args.apply_default_target(&config, builder.kernel_root()); + + let bootimage_path = build::build_impl(&builder, &mut args, false)?; + + let command = &config.run_command[0]; + let mut command = process::Command::new(command); + for arg in &config.run_command[1..] { + command.arg( + arg.replace( + "{}", + bootimage_path + .to_str() + .ok_or(ErrorString::from("bootimage path is not valid unicode"))?, + ), + ); + } + command.args(&args.run_args); + command.status().map_err(|err| { + ErrorString::from(format!( + "Failed to execute run command `{:?}`: {}", + command, err + )) + })?; + Ok(()) +} diff --git a/src/test.rs b/src/subcommand/test.rs similarity index 85% rename from src/test.rs rename to src/subcommand/test.rs index 8ff8dac..bd51062 100644 --- a/src/test.rs +++ b/src/subcommand/test.rs @@ -1,34 +1,25 @@ use crate::args::Args; -use crate::build; +use crate::config; +use crate::subcommand::build; use failure::{Error, ResultExt}; use rayon::prelude::*; use std::io::Write; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::time::Duration; use std::{fs, io, process}; use wait_timeout::ChildExt; -pub(crate) fn test(args: Args) -> Result<(), Error> { - let (args, config, metadata, root_dir, out_dir) = build::common_setup(args)?; +pub(crate) fn test(mut args: Args) -> Result<(), crate::ErrorString> { + let builder = bootimage::Builder::new(args.manifest_path().clone())?; + let config = config::read_config(builder.kernel_manifest_path().to_owned())?; + args.apply_default_target(&config, builder.kernel_root()); let test_args = args.clone(); - let test_config = { - let mut test_config = config.clone(); - test_config.output = None; - test_config - }; - - let test_targets = metadata - .packages - .iter() - .find(|p| { - Path::new(&p.manifest_path) - .canonicalize() - .map(|path| path == config.manifest_path) - .unwrap_or(false) - }) - .expect("Could not read crate name from cargo metadata") + let kernel_package = builder + .kernel_package() + .map_err(|key| format!("Kernel package not found it cargo metadata (`{}`)", key))?; + let test_targets = kernel_package .targets .iter() .filter(|t| t.kind == ["bin"] && t.name.starts_with("test-")) @@ -37,18 +28,11 @@ pub(crate) fn test(args: Args) -> Result<(), Error> { let mut target_args = test_args.clone(); target_args.set_bin_name(target.name.clone()); - let test_path = build::build_impl( - &target_args, - &test_config, - &metadata, - &root_dir, - &out_dir, - false, - ) - .expect(&format!("Failed to build test: {}", target.name)); + let test_bin_path = build::build_impl(&builder, &mut target_args, true) + .expect(&format!("Failed to build test: {}", target.name)); println!(""); - (target, test_path) + (target, test_bin_path) }) .collect::>(); From 89e9c50384a331da2f9f47bc3958c5a3d317bdfd Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 27 Mar 2019 09:49:44 +0100 Subject: [PATCH 03/50] Remove various config options --- src/config.rs | 124 -------------------------------------------------- 1 file changed, 124 deletions(-) diff --git a/src/config.rs b/src/config.rs index 24ca282..2c77154 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,19 +7,7 @@ use toml::Value; pub struct Config { pub manifest_path: PathBuf, pub default_target: Option, - pub output: Option, // remove - pub bootloader: BootloaderConfig, // remove - pub minimum_image_size: Option, // remove pub run_command: Vec, - pub package_filepath: Option, // remove -} - -#[derive(Debug, Clone)] -pub struct BootloaderConfig { - pub name: Option, - pub target: PathBuf, - pub default_features: bool, - pub features: Vec, } pub(crate) fn read_config(manifest_path: PathBuf) -> Result { @@ -78,94 +66,14 @@ pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result )); } - let bootloader_dependency = cargo_toml - .get("dependencies") - .and_then(|table| table.get("bootloader")); - let bootloader_default_features = - match bootloader_dependency.and_then(|table| table.get("default-features")) { - None => None, - Some(Value::Boolean(default_features)) => Some(*default_features), - Some(_) => { - return Err(format_err!( - "Bootloader 'default-features' field should be a bool!" - )); - } - }; - - let bootloader_features = match cargo_toml - .get("dependencies") - .and_then(|table| table.get("bootloader")) - .and_then(|table| table.get("features")) - { - None => None, - Some(Value::Array(array)) => { - let mut features = Vec::new(); - - for feature_string in array { - match feature_string { - Value::String(feature) => features.push(feature.clone()), - _ => return Err(format_err!("Bootloader features are malformed!")), - } - } - - Some(features) - } - Some(_) => return Err(format_err!("Bootloader features are malformed!")), - }; - let mut config = ConfigBuilder { manifest_path: Some(manifest_path), - bootloader: BootloaderConfigBuilder { - features: bootloader_features, - default_features: bootloader_default_features, - ..Default::default() - }, ..Default::default() }; for (key, value) in metadata { match (key.as_str(), value.clone()) { ("default-target", Value::String(s)) => config.default_target = From::from(s), - ("output", Value::String(s)) => config.output = Some(PathBuf::from(s)), - ("bootloader", Value::Table(t)) => { - for (key, value) in t { - match (key.as_str(), value) { - ("name", Value::String(s)) => config.bootloader.name = From::from(s), - ("target", Value::String(s)) => { - config.bootloader.target = Some(PathBuf::from(s)) - } - (k @ "precompiled", _) - | (k @ "version", _) - | (k @ "git", _) - | (k @ "branch", _) - | (k @ "path", _) => Err(format_err!( - "the \ - `package.metadata.bootimage.bootloader` key `{}` was deprecated\n\n\ - In case you just updated bootimage from an earlier version, \ - check out the migration guide at \ - https://github.com/rust-osdev/bootimage/pull/16.", - k - ))?, - (key, value) => Err(format_err!( - "unexpected \ - `package.metadata.bootimage.bootloader` key `{}` with value `{}`", - key, - value - ))?, - } - } - } - ("minimum-image-size", Value::Integer(x)) => { - if x >= 0 { - config.minimum_image_size = Some((x * 1024 * 1024) as u64); // MiB -> Byte - } else { - Err(format_err!( - "unexpected `package.metadata.bootimage` \ - key `minimum-image-size` with negative value `{}`", - value - ))? - } - } ("run-command", Value::Array(array)) => { let mut command = Vec::new(); for value in array { @@ -176,9 +84,6 @@ pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result } config.run_command = Some(command); } - ("package-file", Value::String(path)) => { - config.package_filepath = Some(PathBuf::from(path)); - } (key, value) => Err(format_err!( "unexpected `package.metadata.bootimage` \ key `{}` with value `{}`", @@ -194,19 +99,7 @@ pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result struct ConfigBuilder { manifest_path: Option, default_target: Option, - output: Option, - bootloader: BootloaderConfigBuilder, - minimum_image_size: Option, run_command: Option>, - package_filepath: Option, -} - -#[derive(Default)] -struct BootloaderConfigBuilder { - name: Option, - target: Option, - features: Option>, - default_features: Option, } impl Into for ConfigBuilder { @@ -214,28 +107,11 @@ impl Into for ConfigBuilder { Config { manifest_path: self.manifest_path.expect("manifest path must be set"), default_target: self.default_target, - output: self.output, - bootloader: self.bootloader.into(), - minimum_image_size: self.minimum_image_size, run_command: self.run_command.unwrap_or(vec![ "qemu-system-x86_64".into(), "-drive".into(), "format=raw,file={}".into(), ]), - package_filepath: self.package_filepath, - } - } -} - -impl Into for BootloaderConfigBuilder { - fn into(self) -> BootloaderConfig { - BootloaderConfig { - name: self.name, - target: self - .target - .unwrap_or(PathBuf::from("x86_64-bootloader.json")), - features: self.features.unwrap_or(Vec::with_capacity(0)), - default_features: self.default_features.unwrap_or(true), } } } From a1745f84838a6772d4beea3539a75e7529bf0cd1 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 27 Mar 2019 10:01:43 +0100 Subject: [PATCH 04/50] Remove the dependency on failure --- Cargo.lock | 67 ------------------------------------------ Cargo.toml | 5 ---- src/config.rs | 34 +++++---------------- src/main.rs | 7 ++--- src/subcommand/test.rs | 28 +++++++----------- 5 files changed, 20 insertions(+), 121 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6b27efa..94a0846 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,34 +8,12 @@ dependencies = [ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "backtrace" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "bootimage" version = "0.6.6" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "locate-cargo-manifest 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -61,11 +39,6 @@ dependencies = [ "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cc" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "cfg-if" version = "0.1.4" @@ -117,14 +90,6 @@ name = "error-chain" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "failure" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "itoa" version = "0.4.2" @@ -213,11 +178,6 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rustc-demangle" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "scopeguard" version = "0.3.3" @@ -293,25 +253,6 @@ dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "winapi" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "xmas-elf" version = "0.6.2" @@ -327,11 +268,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" -"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" -"checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" "checksum cargo_metadata 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "178d62b240c34223f265a4c1e275e37d62da163d421fc8d7f7e3ee340f803c57" -"checksum cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "2119ea4867bd2b8ed3aecab467709720b2d55b1bcfe09f772fd68066eaf15275" "checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" @@ -339,7 +277,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606" "checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" @@ -353,7 +290,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035" "checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" -"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" @@ -364,8 +300,5 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c5890a989fa47ecdc7bcb4c63a77a82c18f306714104b1decfd722db17b39e" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" -"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" "checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/Cargo.toml b/Cargo.toml index ded8653..4bd9804 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,8 +19,3 @@ locate-cargo-manifest = "0.1.0" [dependencies.cargo_metadata] version = "0.7.4" default-features = false - -[dependencies.failure] -version = "0.1.5" -default-features = false -features = ["std"] diff --git a/src/config.rs b/src/config.rs index 2c77154..5acd6e0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,4 @@ use crate::ErrorString; -use failure::{Error, ResultExt}; use std::path::PathBuf; use toml::Value; @@ -16,17 +15,17 @@ pub(crate) fn read_config(manifest_path: PathBuf) -> Result Ok(config) } -pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result { +pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result { use std::{fs::File, io::Read}; let cargo_toml: Value = { let mut content = String::new(); File::open(&manifest_path) - .with_context(|e| format!("Failed to open Cargo.toml: {}", e))? + .map_err(|e| format!("Failed to open Cargo.toml: {}", e))? .read_to_string(&mut content) - .with_context(|e| format!("Failed to read Cargo.toml: {}", e))?; + .map_err(|e| format!("Failed to read Cargo.toml: {}", e))?; content .parse::() - .with_context(|e| format!("Failed to parse Cargo.toml: {}", e))? + .map_err(|e| format!("Failed to parse Cargo.toml: {}", e))? }; let metadata = cargo_toml @@ -41,31 +40,12 @@ pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result } .into()); } - Some(metadata) => metadata.as_table().ok_or(format_err!( + Some(metadata) => metadata.as_table().ok_or(format!( "Bootimage configuration invalid: {:?}", metadata ))?, }; - /* - * The user shouldn't specify any features if they're using a precompiled bootloader, as we - * don't actually compile it. - */ - if cargo_toml - .get("dependencies") - .and_then(|table| table.get("bootloader_precompiled")) - .and_then(|table| { - table - .get("features") - .or_else(|| table.get("default-features")) - }) - .is_some() - { - return Err(format_err!( - "Can't change features of precompiled bootloader!" - )); - } - let mut config = ConfigBuilder { manifest_path: Some(manifest_path), ..Default::default() @@ -79,12 +59,12 @@ pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result for value in array { match value { Value::String(s) => command.push(s), - _ => Err(format_err!("run-command must be a list of strings"))?, + _ => Err(format!("run-command must be a list of strings"))?, } } config.run_command = Some(command); } - (key, value) => Err(format_err!( + (key, value) => Err(format!( "unexpected `package.metadata.bootimage` \ key `{}` with value `{}`", key, diff --git a/src/main.rs b/src/main.rs index 70dd72f..2ec34de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,3 @@ -#[macro_use] -extern crate failure; - use args::Args; use std::{fmt, process}; @@ -44,7 +41,7 @@ fn run() -> Result<(), ErrorString> { } } -struct ErrorString(Box); +struct ErrorString(Box); impl ErrorString { fn display(&self) -> &dyn fmt::Display { @@ -60,7 +57,7 @@ impl fmt::Debug for ErrorString { impl From for ErrorString where - T: fmt::Display + 'static, + T: fmt::Display + Send + 'static, { fn from(err: T) -> Self { ErrorString(Box::new(err)) diff --git a/src/subcommand/test.rs b/src/subcommand/test.rs index bd51062..6dee868 100644 --- a/src/subcommand/test.rs +++ b/src/subcommand/test.rs @@ -1,15 +1,9 @@ -use crate::args::Args; -use crate::config; -use crate::subcommand::build; -use failure::{Error, ResultExt}; +use crate::{args::Args, config, subcommand::build, ErrorString}; +use std::{io::Write, path::PathBuf, time::Duration, fs, io, process}; use rayon::prelude::*; -use std::io::Write; -use std::path::PathBuf; -use std::time::Duration; -use std::{fs, io, process}; use wait_timeout::ChildExt; -pub(crate) fn test(mut args: Args) -> Result<(), crate::ErrorString> { +pub(crate) fn test(mut args: Args) -> Result<(), ErrorString> { let builder = bootimage::Builder::new(args.manifest_path().clone())?; let config = config::read_config(builder.kernel_manifest_path().to_owned())?; args.apply_default_target(&config, builder.kernel_root()); @@ -56,25 +50,25 @@ pub(crate) fn test(mut args: Args) -> Result<(), crate::ErrorString> { command.stderr(process::Stdio::null()); let mut child = command .spawn() - .with_context(|e| format_err!("Failed to launch QEMU: {:?}\n{}", command, e))?; + .map_err(|e| format!("Failed to launch QEMU: {:?}\n{}", command, e))?; let timeout = Duration::from_secs(60); match child .wait_timeout(timeout) - .with_context(|e| format!("Failed to wait with timeout: {}", e))? + .map_err(|e| format!("Failed to wait with timeout: {}", e))? { None => { child .kill() - .with_context(|e| format!("Failed to kill QEMU: {}", e))?; + .map_err(|e| format!("Failed to kill QEMU: {}", e))?; child .wait() - .with_context(|e| format!("Failed to wait for QEMU process: {}", e))?; + .map_err(|e| format!("Failed to wait for QEMU process: {}", e))?; test_result = TestResult::TimedOut; writeln!(io::stderr(), "Timed Out")?; } Some(exit_status) => { - let output = fs::read_to_string(&output_file).with_context(|e| { - format_err!("Failed to read test output file {}: {}", output_file, e) + let output = fs::read_to_string(&output_file).map_err(|e| { + format!("Failed to read test output file {}: {}", output_file, e) })?; test_result = handle_exit_status(exit_status, &output, &target.name)?; } @@ -82,7 +76,7 @@ pub(crate) fn test(mut args: Args) -> Result<(), crate::ErrorString> { Ok((target.name.clone(), test_result)) }) - .collect::, Error>>()?; + .collect::, ErrorString>>()?; println!(""); if tests.iter().all(|t| t.1 == TestResult::Ok) { @@ -101,7 +95,7 @@ fn handle_exit_status( exit_status: process::ExitStatus, output: &str, target_name: &str, -) -> Result { +) -> Result { match exit_status.code() { None => { writeln!(io::stderr(), "FAIL: No Exit Code.")?; From 2e98cbeced380c293df6415d7067a0624080160c Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 27 Mar 2019 10:05:53 +0100 Subject: [PATCH 05/50] Update help and Readme --- Readme.md | 12 ++++-------- src/help/build_help.txt | 6 ------ 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/Readme.md b/Readme.md index 817eb30..0def8db 100644 --- a/Readme.md +++ b/Readme.md @@ -16,16 +16,18 @@ First you need to add a dependency on the `bootloader` crate: # in your Cargo.toml [dependencies] -bootloader = "0.2.0-alpha" +bootloader = "0.5.0" ``` +**Note**: At least bootloader version `0.5.0` is required. + Now you can build the kernel project and create a bootable disk image from it by running: ``` > bootimage build --target your_custom_target.json [other_args] ``` -The command will invoke [`cargo xbuild`](https://github.com/rust-osdev/cargo-xbuild), forwarding all passed options. Then it will download and build a bootloader, by default the [rust-osdev/bootloader](https://github.com/rust-osdev/bootloader). Finally, it combines the kernel and the bootloader into a bootable disk image. +The command will invoke [`cargo xbuild`](https://github.com/rust-osdev/cargo-xbuild), forwarding all passed options. Then it will build the specified bootloader together with the kernel to create a bootable disk image. ## Configuration @@ -34,15 +36,9 @@ Configuration is done through a through a `[package.metadata.bootimage]` table i ```toml [package.metadata.bootimage] default-target = "" # This target is used if no `--target` is passed - output = "bootimage.bin" # The output file name - minimum-image-size = 0 # The minimum output file size (in MiB) # The command invoked on `bootimage run` # (the "{}" will be replaced with the path to the bootable disk image) run-command = ["qemu-system-x86_64", "-drive", "format=raw,file={}"] - - [package.metadata.bootimage.bootloader] - name = "bootloader" # The bootloader crate name - target = "x86_64-bootloader.json" # Target triple for compiling the bootloader ``` ## License diff --git a/src/help/build_help.txt b/src/help/build_help.txt index 5477d81..e92d588 100644 --- a/src/help/build_help.txt +++ b/src/help/build_help.txt @@ -18,9 +18,3 @@ CONFIGURATION: [package.metadata.bootimage] default-target = "" This target is used if no `--target` is passed - output = "bootimage.bin" The output file name - minimum-image-size = 0 The minimum output file size (in MiB) - - [package.metadata.bootimage.bootloader] - name = "bootloader" The bootloader crate name - target = "x86_64-bootloader.json" Target triple for compiling the bootloader From 935dacc2ee69934c66e8f1fe2c32a20e4c9230f1 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 27 Mar 2019 10:32:38 +0100 Subject: [PATCH 06/50] Add example kernels and azure pipelines CI script --- azure-pipelines.yml | 127 +++++++ example-kernels/basic/.gitignore | 2 + example-kernels/basic/Cargo.lock | 297 ++++++++++++++++ example-kernels/basic/Cargo.toml | 9 + example-kernels/basic/src/main.rs | 28 ++ example-kernels/basic/x86_64-basic.json | 15 + .../default-target-bootimage/.gitignore | 2 + .../default-target-bootimage/Cargo.lock | 328 ++++++++++++++++++ .../default-target-bootimage/Cargo.toml | 14 + .../default-target-bootimage/src/main.rs | 28 ++ .../x86_64-default-target.json | 15 + .../default-target-cargo/.cargo/config | 2 + .../default-target-cargo/.gitignore | 2 + .../default-target-cargo/Cargo.lock | 328 ++++++++++++++++++ .../default-target-cargo/Cargo.toml | 11 + .../default-target-cargo/src/main.rs | 28 ++ .../x86_64-default-target.json | 15 + example-kernels/rust-toolchain | 1 + example-kernels/testing/.gitignore | 2 + example-kernels/testing/Cargo.lock | 328 ++++++++++++++++++ example-kernels/testing/Cargo.toml | 14 + .../testing/src/bin/test-basic-boot.rs | 33 ++ example-kernels/testing/src/bin/test-panic.rs | 23 ++ example-kernels/testing/src/lib.rs | 58 ++++ example-kernels/testing/src/main.rs | 28 ++ example-kernels/testing/x86_64-testing.json | 15 + 26 files changed, 1753 insertions(+) create mode 100644 azure-pipelines.yml create mode 100644 example-kernels/basic/.gitignore create mode 100644 example-kernels/basic/Cargo.lock create mode 100644 example-kernels/basic/Cargo.toml create mode 100644 example-kernels/basic/src/main.rs create mode 100644 example-kernels/basic/x86_64-basic.json create mode 100644 example-kernels/default-target-bootimage/.gitignore create mode 100644 example-kernels/default-target-bootimage/Cargo.lock create mode 100644 example-kernels/default-target-bootimage/Cargo.toml create mode 100644 example-kernels/default-target-bootimage/src/main.rs create mode 100644 example-kernels/default-target-bootimage/x86_64-default-target.json create mode 100644 example-kernels/default-target-cargo/.cargo/config create mode 100644 example-kernels/default-target-cargo/.gitignore create mode 100644 example-kernels/default-target-cargo/Cargo.lock create mode 100644 example-kernels/default-target-cargo/Cargo.toml create mode 100644 example-kernels/default-target-cargo/src/main.rs create mode 100644 example-kernels/default-target-cargo/x86_64-default-target.json create mode 100644 example-kernels/rust-toolchain create mode 100644 example-kernels/testing/.gitignore create mode 100644 example-kernels/testing/Cargo.lock create mode 100644 example-kernels/testing/Cargo.toml create mode 100644 example-kernels/testing/src/bin/test-basic-boot.rs create mode 100644 example-kernels/testing/src/bin/test-panic.rs create mode 100644 example-kernels/testing/src/lib.rs create mode 100644 example-kernels/testing/src/main.rs create mode 100644 example-kernels/testing/x86_64-testing.json diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000..d1cab8e --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,127 @@ +# Documentation: https://aka.ms/yaml + +trigger: + batch: true + branches: + include: + # This is where pull requests from "bors r+" are built. + - staging + # This is where pull requests from "bors try" are built. + - trying + # Build pull requests. + - master + +strategy: + matrix: + linux: + image_name: 'ubuntu-16.04' + rustup_toolchain: stable + mac: + image_name: 'macos-10.13' + rustup_toolchain: stable + windows: + image_name: 'vs2017-win2016' + rustup_toolchain: stable + +pool: + vmImage: $(image_name) + +steps: +- bash: | + echo "Hello world from $AGENT_NAME running on $AGENT_OS" + echo "Reason: $BUILD_REASON" + case "$BUILD_REASON" in + "Manual") echo "$BUILD_REQUESTEDFOR manually queued the build." ;; + "PullRequest") echo "This is a CI build for a pull request on $BUILD_REQUESTEDFOR." ;; + "IndividualCI") echo "This is a CI build for $BUILD_REQUESTEDFOR." ;; + "BatchedCI") echo "This is a batched CI build for $BUILD_REQUESTEDFOR." ;; + *) "$BUILD_REASON" ;; + esac + displayName: 'Build Info' + continueOnError: true + +- script: | + set -euxo pipefail + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUSTUP_TOOLCHAIN + echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + condition: or(eq( variables['Agent.OS'], 'Linux' ), eq( variables['Agent.OS'], 'Darwin' )) + displayName: 'Install Rust (Linux/macOS)' + +- script: curl -sSf -o rustup-init.exe https://win.rustup.rs && rustup-init.exe -y --default-toolchain %RUSTUP_TOOLCHAIN% + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + displayName: 'Install Rust (Windows)' + +- script: | + echo ##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + displayName: 'Add ~/.cargo/bin to PATH (Windows)' + +- script: | + rustc -Vv + cargo -V + displayName: 'Print Rust Version' + continueOnError: true + +- script: cargo build + displayName: 'Build' + +- script: cargo test + displayName: 'Test' + +- script: rustup component add rust-src llvm-tools-preview + displayName: 'Install Rustup Components' + +- script: cargo install cargo-xbuild --debug + displayName: 'Install cargo-xbuild' + +- script: sudo apt update && sudo apt install qemu-system-x86 + condition: eq( variables['Agent.OS'], 'Linux' ) + displayName: 'Install QEMU (Linux)' + +- script: | + set -euxo pipefail + export HOMEBREW_NO_AUTO_UPDATE=1 + export HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK=1 + export HOMEBREW_NO_INSTALL_CLEANUP=1 + brew install qemu + condition: eq( variables['Agent.OS'], 'Darwin' ) + displayName: 'Install QEMU (macOS)' + +- script: | + choco install qemu --limit-output --no-progress + echo ##vso[task.setvariable variable=PATH;]%PATH%;C:\Program Files\qemu + set PATH=%PATH%;C:\Program Files\qemu + qemu-system-x86_64 --version + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + failOnStderr: true + displayName: 'Install QEMU (Windows)' + +- script: cargo install --path . --force --debug + displayName: 'Install this bootimage version' + +- script: rustup toolchain add nightly + displayName: 'Install Rust Nightly' + +- script: bootimage build --target x86_64-basic.json && file target/x86_64-basic/debug/bootimage-basic.bin + workingDirectory: example-kernels/basic + displayName: 'Build Example Kernel "Basic"' + +- script: bootimage run --target x86_64-basic.json + workingDirectory: example-kernels/basic + displayName: 'Run Example Kernel "basic"' + +- script: bootimage build && file target/x86_64-default-target/debug/bootimage-default-target-bootimage.bin + workingDirectory: example-kernels/default-target-bootimage + displayName: 'Build Example Kernel "default-target-bootimage"' + +- script: bootimage run + workingDirectory: example-kernels/default-target-bootimage + displayName: 'Run Example Kernel "default-target-bootimage"' + +- script: bootimage build && file target/x86_64-default-target/debug/bootimage-default-target-cargo.bin + workingDirectory: example-kernels/default-target-cargo + displayName: 'Build Example Kernel "default-target-cargo"' + +- script: bootimage run + workingDirectory: example-kernels/default-target-cargo + displayName: 'Run Example Kernel "default-target-cargo"' diff --git a/example-kernels/basic/.gitignore b/example-kernels/basic/.gitignore new file mode 100644 index 0000000..eccd7b4 --- /dev/null +++ b/example-kernels/basic/.gitignore @@ -0,0 +1,2 @@ +/target/ +**/*.rs.bk diff --git a/example-kernels/basic/Cargo.lock b/example-kernels/basic/Cargo.lock new file mode 100644 index 0000000..dd4ef6b --- /dev/null +++ b/example-kernels/basic/Cargo.lock @@ -0,0 +1,297 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "array-init" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "basic" +version = "0.1.0" +dependencies = [ + "bootloader 0.4.0", + "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bit_field" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bootloader" +version = "0.4.0" +dependencies = [ + "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cc" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fixedvec" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "font8x8" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "getopts" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.50" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "llvm-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "nodrop" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "os_bootinfo" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pulldown-cmark" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "raw-cpuid" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "skeptic" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "usize_conversions" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ux" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "x86_64" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "x86_64" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "xmas-elf" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zero" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" +"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" +"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ad0daef304fa0b4238f5f7ed7178774b43b06f6a9b6509f6642bef4ff1f7b9b2" +"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0" +"checksum font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b81d84c3c978af7d05d31a2198af4b9ba956d819d15d8f6d58fc150e33f8dc1f" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" +"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" +"checksum llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "955be5d0ca0465caf127165acb47964f911e2bc26073e865deb8be7189302faf" +"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" +"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c" +"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" +"checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f9258d7e2dd25008d69e8c9e9ee37865887a5e1e3d06a62f1cb3f6c209e6f177" +"checksum x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8f7e92e985f4052118fd69f2b366c67e91288c0f01f4ae52610dce236425dfa0" +"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" +"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/example-kernels/basic/Cargo.toml b/example-kernels/basic/Cargo.toml new file mode 100644 index 0000000..331b235 --- /dev/null +++ b/example-kernels/basic/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "basic" +version = "0.1.0" +authors = ["Philipp Oppermann "] +edition = "2018" + +[dependencies] +bootloader = "0.5.0" +x86_64 = "0.5.3" diff --git a/example-kernels/basic/src/main.rs b/example-kernels/basic/src/main.rs new file mode 100644 index 0000000..f0352e2 --- /dev/null +++ b/example-kernels/basic/src/main.rs @@ -0,0 +1,28 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use core::panic::PanicInfo; + +/// This function is called on panic. +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} +} + +#[no_mangle] // don't mangle the name of this function +pub extern "C" fn _start() -> ! { + // this function is the entry point, since the linker looks for a function + // named `_start` by default + + // exit QEMU (see https://os.phil-opp.com/integration-tests/#shutting-down-qemu) + unsafe { exit_qemu(); } + + loop {} +} + +pub unsafe fn exit_qemu() { + use x86_64::instructions::port::Port; + + let mut port = Port::::new(0xf4); + port.write(61); // exit code is (61 << 1) | 1 = 123 +} diff --git a/example-kernels/basic/x86_64-basic.json b/example-kernels/basic/x86_64-basic.json new file mode 100644 index 0000000..9afe809 --- /dev/null +++ b/example-kernels/basic/x86_64-basic.json @@ -0,0 +1,15 @@ +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float" + } diff --git a/example-kernels/default-target-bootimage/.gitignore b/example-kernels/default-target-bootimage/.gitignore new file mode 100644 index 0000000..eccd7b4 --- /dev/null +++ b/example-kernels/default-target-bootimage/.gitignore @@ -0,0 +1,2 @@ +/target/ +**/*.rs.bk diff --git a/example-kernels/default-target-bootimage/Cargo.lock b/example-kernels/default-target-bootimage/Cargo.lock new file mode 100644 index 0000000..06cfb07 --- /dev/null +++ b/example-kernels/default-target-bootimage/Cargo.lock @@ -0,0 +1,328 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "array-init" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "basic" +version = "0.1.0" +dependencies = [ + "bootloader 0.4.0", + "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bit_field" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bootloader" +version = "0.4.0" +dependencies = [ + "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cc" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fixedvec" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "font8x8" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "getopts" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.50" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "llvm-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "nodrop" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "os_bootinfo" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pulldown-cmark" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "raw-cpuid" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "skeptic" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "spin" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "uart_16550" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "usize_conversions" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ux" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "x86_64" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "x86_64" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "x86_64" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "xmas-elf" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zero" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" +"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" +"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ad0daef304fa0b4238f5f7ed7178774b43b06f6a9b6509f6642bef4ff1f7b9b2" +"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0" +"checksum font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b81d84c3c978af7d05d31a2198af4b9ba956d819d15d8f6d58fc150e33f8dc1f" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" +"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" +"checksum llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "955be5d0ca0465caf127165acb47964f911e2bc26073e865deb8be7189302faf" +"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" +"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c" +"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" +"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +"checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e" +"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" +"checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd647af1614659e1febec1d681231aea4ebda4818bf55a578aff02f3e4db4b4" +"checksum x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f9258d7e2dd25008d69e8c9e9ee37865887a5e1e3d06a62f1cb3f6c209e6f177" +"checksum x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8f7e92e985f4052118fd69f2b366c67e91288c0f01f4ae52610dce236425dfa0" +"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" +"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/example-kernels/default-target-bootimage/Cargo.toml b/example-kernels/default-target-bootimage/Cargo.toml new file mode 100644 index 0000000..f62b2ac --- /dev/null +++ b/example-kernels/default-target-bootimage/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "default-target-bootimage" +version = "0.1.0" +authors = ["Philipp Oppermann "] +edition = "2018" + +[dependencies] +bootloader = "0.5.0" +x86_64 = "0.5.3" +spin = "0.4.9" +uart_16550 = "0.1.0" + +[package.metadata.bootimage] +default-target = "x86_64-default-target.json" \ No newline at end of file diff --git a/example-kernels/default-target-bootimage/src/main.rs b/example-kernels/default-target-bootimage/src/main.rs new file mode 100644 index 0000000..f0352e2 --- /dev/null +++ b/example-kernels/default-target-bootimage/src/main.rs @@ -0,0 +1,28 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use core::panic::PanicInfo; + +/// This function is called on panic. +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} +} + +#[no_mangle] // don't mangle the name of this function +pub extern "C" fn _start() -> ! { + // this function is the entry point, since the linker looks for a function + // named `_start` by default + + // exit QEMU (see https://os.phil-opp.com/integration-tests/#shutting-down-qemu) + unsafe { exit_qemu(); } + + loop {} +} + +pub unsafe fn exit_qemu() { + use x86_64::instructions::port::Port; + + let mut port = Port::::new(0xf4); + port.write(61); // exit code is (61 << 1) | 1 = 123 +} diff --git a/example-kernels/default-target-bootimage/x86_64-default-target.json b/example-kernels/default-target-bootimage/x86_64-default-target.json new file mode 100644 index 0000000..9afe809 --- /dev/null +++ b/example-kernels/default-target-bootimage/x86_64-default-target.json @@ -0,0 +1,15 @@ +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float" + } diff --git a/example-kernels/default-target-cargo/.cargo/config b/example-kernels/default-target-cargo/.cargo/config new file mode 100644 index 0000000..35c3b41 --- /dev/null +++ b/example-kernels/default-target-cargo/.cargo/config @@ -0,0 +1,2 @@ +[build] +target = "x86_64-default-target.json" \ No newline at end of file diff --git a/example-kernels/default-target-cargo/.gitignore b/example-kernels/default-target-cargo/.gitignore new file mode 100644 index 0000000..eccd7b4 --- /dev/null +++ b/example-kernels/default-target-cargo/.gitignore @@ -0,0 +1,2 @@ +/target/ +**/*.rs.bk diff --git a/example-kernels/default-target-cargo/Cargo.lock b/example-kernels/default-target-cargo/Cargo.lock new file mode 100644 index 0000000..06cfb07 --- /dev/null +++ b/example-kernels/default-target-cargo/Cargo.lock @@ -0,0 +1,328 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "array-init" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "basic" +version = "0.1.0" +dependencies = [ + "bootloader 0.4.0", + "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bit_field" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bootloader" +version = "0.4.0" +dependencies = [ + "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cc" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fixedvec" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "font8x8" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "getopts" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.50" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "llvm-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "nodrop" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "os_bootinfo" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pulldown-cmark" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "raw-cpuid" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "skeptic" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "spin" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "uart_16550" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "usize_conversions" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ux" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "x86_64" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "x86_64" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "x86_64" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "xmas-elf" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zero" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" +"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" +"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ad0daef304fa0b4238f5f7ed7178774b43b06f6a9b6509f6642bef4ff1f7b9b2" +"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0" +"checksum font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b81d84c3c978af7d05d31a2198af4b9ba956d819d15d8f6d58fc150e33f8dc1f" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" +"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" +"checksum llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "955be5d0ca0465caf127165acb47964f911e2bc26073e865deb8be7189302faf" +"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" +"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c" +"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" +"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +"checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e" +"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" +"checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd647af1614659e1febec1d681231aea4ebda4818bf55a578aff02f3e4db4b4" +"checksum x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f9258d7e2dd25008d69e8c9e9ee37865887a5e1e3d06a62f1cb3f6c209e6f177" +"checksum x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8f7e92e985f4052118fd69f2b366c67e91288c0f01f4ae52610dce236425dfa0" +"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" +"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/example-kernels/default-target-cargo/Cargo.toml b/example-kernels/default-target-cargo/Cargo.toml new file mode 100644 index 0000000..8c1a298 --- /dev/null +++ b/example-kernels/default-target-cargo/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "default-target-cargo" +version = "0.1.0" +authors = ["Philipp Oppermann "] +edition = "2018" + +[dependencies] +bootloader = "0.5.0" +x86_64 = "0.5.3" +spin = "0.4.9" +uart_16550 = "0.1.0" diff --git a/example-kernels/default-target-cargo/src/main.rs b/example-kernels/default-target-cargo/src/main.rs new file mode 100644 index 0000000..f0352e2 --- /dev/null +++ b/example-kernels/default-target-cargo/src/main.rs @@ -0,0 +1,28 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use core::panic::PanicInfo; + +/// This function is called on panic. +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} +} + +#[no_mangle] // don't mangle the name of this function +pub extern "C" fn _start() -> ! { + // this function is the entry point, since the linker looks for a function + // named `_start` by default + + // exit QEMU (see https://os.phil-opp.com/integration-tests/#shutting-down-qemu) + unsafe { exit_qemu(); } + + loop {} +} + +pub unsafe fn exit_qemu() { + use x86_64::instructions::port::Port; + + let mut port = Port::::new(0xf4); + port.write(61); // exit code is (61 << 1) | 1 = 123 +} diff --git a/example-kernels/default-target-cargo/x86_64-default-target.json b/example-kernels/default-target-cargo/x86_64-default-target.json new file mode 100644 index 0000000..9afe809 --- /dev/null +++ b/example-kernels/default-target-cargo/x86_64-default-target.json @@ -0,0 +1,15 @@ +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float" + } diff --git a/example-kernels/rust-toolchain b/example-kernels/rust-toolchain new file mode 100644 index 0000000..07ade69 --- /dev/null +++ b/example-kernels/rust-toolchain @@ -0,0 +1 @@ +nightly \ No newline at end of file diff --git a/example-kernels/testing/.gitignore b/example-kernels/testing/.gitignore new file mode 100644 index 0000000..eccd7b4 --- /dev/null +++ b/example-kernels/testing/.gitignore @@ -0,0 +1,2 @@ +/target/ +**/*.rs.bk diff --git a/example-kernels/testing/Cargo.lock b/example-kernels/testing/Cargo.lock new file mode 100644 index 0000000..06cfb07 --- /dev/null +++ b/example-kernels/testing/Cargo.lock @@ -0,0 +1,328 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "array-init" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "basic" +version = "0.1.0" +dependencies = [ + "bootloader 0.4.0", + "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bit_field" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bootloader" +version = "0.4.0" +dependencies = [ + "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cc" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fixedvec" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "font8x8" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "getopts" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.50" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "llvm-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "nodrop" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "os_bootinfo" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pulldown-cmark" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "raw-cpuid" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "skeptic" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "spin" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "uart_16550" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "usize_conversions" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ux" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "x86_64" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "x86_64" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "x86_64" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "xmas-elf" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "zero" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" +"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" +"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ad0daef304fa0b4238f5f7ed7178774b43b06f6a9b6509f6642bef4ff1f7b9b2" +"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0" +"checksum font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b81d84c3c978af7d05d31a2198af4b9ba956d819d15d8f6d58fc150e33f8dc1f" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" +"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" +"checksum llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "955be5d0ca0465caf127165acb47964f911e2bc26073e865deb8be7189302faf" +"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" +"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c" +"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" +"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +"checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e" +"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" +"checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd647af1614659e1febec1d681231aea4ebda4818bf55a578aff02f3e4db4b4" +"checksum x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f9258d7e2dd25008d69e8c9e9ee37865887a5e1e3d06a62f1cb3f6c209e6f177" +"checksum x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8f7e92e985f4052118fd69f2b366c67e91288c0f01f4ae52610dce236425dfa0" +"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" +"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/example-kernels/testing/Cargo.toml b/example-kernels/testing/Cargo.toml new file mode 100644 index 0000000..9b5541f --- /dev/null +++ b/example-kernels/testing/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "testing" +version = "0.1.0" +authors = ["Philipp Oppermann "] +edition = "2018" + +[dependencies] +bootloader = "0.5.0" +x86_64 = "0.5.3" +spin = "0.4.9" +uart_16550 = "0.1.0" + +[package.metadata.bootimage] +default-target = "x86_64-testing.json" \ No newline at end of file diff --git a/example-kernels/testing/src/bin/test-basic-boot.rs b/example-kernels/testing/src/bin/test-basic-boot.rs new file mode 100644 index 0000000..f77d4a0 --- /dev/null +++ b/example-kernels/testing/src/bin/test-basic-boot.rs @@ -0,0 +1,33 @@ +#![cfg_attr(not(test), no_std)] +#![cfg_attr(not(test), no_main)] // disable all Rust-level entry points +#![cfg_attr(test, allow(unused_imports))] + +use blog_os::{exit_qemu, serial_println}; +use core::panic::PanicInfo; + +/// This function is the entry point, since the linker looks for a function +/// named `_start` by default. +#[cfg(not(test))] +#[no_mangle] // don't mangle the name of this function +pub extern "C" fn _start() -> ! { + serial_println!("ok"); + + unsafe { + exit_qemu(); + } + loop {} +} + +/// This function is called on panic. +#[cfg(not(test))] +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + serial_println!("failed"); + + serial_println!("{}", info); + + unsafe { + exit_qemu(); + } + loop {} +} diff --git a/example-kernels/testing/src/bin/test-panic.rs b/example-kernels/testing/src/bin/test-panic.rs new file mode 100644 index 0000000..c68ac51 --- /dev/null +++ b/example-kernels/testing/src/bin/test-panic.rs @@ -0,0 +1,23 @@ +#![cfg_attr(not(test), no_std)] +#![cfg_attr(not(test), no_main)] +#![cfg_attr(test, allow(unused_imports))] + +use blog_os::{exit_qemu, serial_println}; +use core::panic::PanicInfo; + +#[cfg(not(test))] +#[no_mangle] +pub extern "C" fn _start() -> ! { + panic!(); +} + +#[cfg(not(test))] +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + serial_println!("ok"); + + unsafe { + exit_qemu(); + } + loop {} +} diff --git a/example-kernels/testing/src/lib.rs b/example-kernels/testing/src/lib.rs new file mode 100644 index 0000000..6bd2578 --- /dev/null +++ b/example-kernels/testing/src/lib.rs @@ -0,0 +1,58 @@ +#![cfg_attr(not(test), no_std)] +#![feature(abi_x86_interrupt)] + +pub unsafe fn exit_qemu() { + use x86_64::instructions::port::Port; + + let mut port = Port::::new(0xf4); + port.write(0); +} + +pub fn hlt_loop() -> ! { + loop { + x86_64::instructions::hlt(); + } +} + +pub mod serial { + use lazy_static::lazy_static; + use spin::Mutex; + use uart_16550::SerialPort; + + lazy_static! { + pub static ref SERIAL1: Mutex = { + let mut serial_port = SerialPort::new(0x3F8); + serial_port.init(); + Mutex::new(serial_port) + }; + } + + #[doc(hidden)] + pub fn _print(args: ::core::fmt::Arguments) { + use core::fmt::Write; + use x86_64::instructions::interrupts; + + interrupts::without_interrupts(|| { + SERIAL1 + .lock() + .write_fmt(args) + .expect("Printing to serial failed"); + }); + } + + /// Prints to the host through the serial interface. + #[macro_export] + macro_rules! serial_print { + ($($arg:tt)*) => { + $crate::serial::_print(format_args!($($arg)*)); + }; + } + + /// Prints to the host through the serial interface, appending a newline. + #[macro_export] + macro_rules! serial_println { + () => ($crate::serial_print!("\n")); + ($fmt:expr) => ($crate::serial_print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => ($crate::serial_print!(concat!($fmt, "\n"), $($arg)*)); + } +} \ No newline at end of file diff --git a/example-kernels/testing/src/main.rs b/example-kernels/testing/src/main.rs new file mode 100644 index 0000000..f0352e2 --- /dev/null +++ b/example-kernels/testing/src/main.rs @@ -0,0 +1,28 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use core::panic::PanicInfo; + +/// This function is called on panic. +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} +} + +#[no_mangle] // don't mangle the name of this function +pub extern "C" fn _start() -> ! { + // this function is the entry point, since the linker looks for a function + // named `_start` by default + + // exit QEMU (see https://os.phil-opp.com/integration-tests/#shutting-down-qemu) + unsafe { exit_qemu(); } + + loop {} +} + +pub unsafe fn exit_qemu() { + use x86_64::instructions::port::Port; + + let mut port = Port::::new(0xf4); + port.write(61); // exit code is (61 << 1) | 1 = 123 +} diff --git a/example-kernels/testing/x86_64-testing.json b/example-kernels/testing/x86_64-testing.json new file mode 100644 index 0000000..9afe809 --- /dev/null +++ b/example-kernels/testing/x86_64-testing.json @@ -0,0 +1,15 @@ +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float" + } From 7515dee2a8b7d5638d19c81c75703ef0a384823d Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 27 Mar 2019 11:28:04 +0100 Subject: [PATCH 07/50] Add a new `bootimage runner` subcommand for use as `target.runner` --- Cargo.lock | 85 ++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/args.rs | 39 ++++++++++++++++++ src/main.rs | 26 ++++++------ src/subcommand.rs | 1 + src/subcommand/runner.rs | 42 ++++++++++++++++++++ 6 files changed, 183 insertions(+), 11 deletions(-) create mode 100644 src/subcommand/runner.rs diff --git a/Cargo.lock b/Cargo.lock index 94a0846..d94e047 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,7 @@ dependencies = [ "llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "locate-cargo-manifest 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -90,6 +91,11 @@ name = "error-chain" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "itoa" version = "0.4.2" @@ -157,6 +163,31 @@ dependencies = [ "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rayon" version = "1.0.3" @@ -178,6 +209,22 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "scopeguard" version = "0.3.3" @@ -232,6 +279,15 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "toml" version = "0.5.0" @@ -253,6 +309,25 @@ dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "winapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "xmas-elf" version = "0.6.2" @@ -277,6 +352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606" "checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" @@ -288,8 +364,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c65b1ea15bb859d922cade2d1765b4b88beac339cbfad545ef2d2ef8c8215ee6" "checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" @@ -297,8 +378,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c" "checksum serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c6908c7b925cd6c590358a4034de93dbddb20c45e1d021931459fd419bf0e2" "checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" +"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c5890a989fa47ecdc7bcb4c63a77a82c18f306714104b1decfd722db17b39e" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" "checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/Cargo.toml b/Cargo.toml index 4bd9804..28bf2fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ wait-timeout = "0.2" xmas-elf = "0.6.2" llvm-tools = "0.1.1" locate-cargo-manifest = "0.1.0" +tempdir = "0.3.7" [dependencies.cargo_metadata] version = "0.7.4" diff --git a/src/args.rs b/src/args.rs index e4c0041..494ad1a 100644 --- a/src/args.rs +++ b/src/args.rs @@ -23,6 +23,7 @@ pub(crate) fn parse_args() -> Command { Command::BuildHelp => Command::TestHelp, cmd => cmd, }, + Some("runner") => parse_runner_args(args), Some("--help") | Some("-h") => Command::Help, Some("--version") => Command::Version, _ => Command::NoSubcommand, @@ -194,3 +195,41 @@ impl Args { } } } + +fn parse_runner_args(args: A) -> Command +where + A: Iterator, +{ + let mut arg_iter = args.into_iter().fuse(); + let executable = PathBuf::from(arg_iter.next().expect("excepted path to kernel executable as first argument")).canonicalize().expect("Failed to canonicalize executable path"); + let mut run_command = None; + + loop { + match arg_iter.next().as_ref().map(|s| s.as_str()) { + Some("--command") => { + let old = mem::replace(&mut run_command, Some(arg_iter.collect())); + assert!(old.is_none(), "multiple `--command` arguments"); + break; + } + Some("--help") | Some("-h") => { + return Command::RunnerHelp; + } + Some("--version") => { + return Command::Version; + } + None => break, + Some(arg) => panic!("unexpected argument `{}`", arg), + } + } + + Command::Runner(RunnerArgs { + executable, + run_command, + }) +} + +#[derive(Debug, Clone)] +pub struct RunnerArgs { + pub executable: PathBuf, + pub run_command: Option>, +} diff --git a/src/main.rs b/src/main.rs index 2ec34de..8a9e2d4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use args::Args; +use args::{Args, RunnerArgs}; use std::{fmt, process}; mod args; @@ -12,17 +12,19 @@ enum Command { Build(Args), Run(Args), Test(Args), + Runner(RunnerArgs), Help, BuildHelp, RunHelp, TestHelp, + RunnerHelp, Version, } pub fn main() { if let Err(err) = run() { - eprintln!("Error: {}", err.display()); - process::exit(1); + eprintln!("Error: {}", err.message); + process::exit(err.exit_code); } } @@ -32,26 +34,25 @@ fn run() -> Result<(), ErrorString> { Command::Build(args) => subcommand::build::build(args), Command::Run(args) => subcommand::run::run(args), Command::Test(args) => subcommand::test::test(args), + Command::Runner(args) => subcommand::runner::runner(args), Command::NoSubcommand => help::no_subcommand(), Command::Help => Ok(help::help()), Command::BuildHelp => Ok(help::build_help()), Command::RunHelp => Ok(help::run_help()), Command::TestHelp => Ok(help::test_help()), + Command::RunnerHelp => unimplemented!(), Command::Version => Ok(println!("bootimage {}", env!("CARGO_PKG_VERSION"))), } } -struct ErrorString(Box); - -impl ErrorString { - fn display(&self) -> &dyn fmt::Display { - &self.0 - } +struct ErrorString { + pub message: Box, + pub exit_code: i32, } impl fmt::Debug for ErrorString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.display().fmt(f) + self.message.fmt(f) } } @@ -60,6 +61,9 @@ where T: fmt::Display + Send + 'static, { fn from(err: T) -> Self { - ErrorString(Box::new(err)) + ErrorString { + message: Box::new(err), + exit_code: 1, + } } } diff --git a/src/subcommand.rs b/src/subcommand.rs index 34bfd46..f848c46 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -1,3 +1,4 @@ pub mod build; pub mod run; +pub mod runner; pub mod test; diff --git a/src/subcommand/runner.rs b/src/subcommand/runner.rs new file mode 100644 index 0000000..7e3a386 --- /dev/null +++ b/src/subcommand/runner.rs @@ -0,0 +1,42 @@ +use crate::{args::RunnerArgs, ErrorString}; +use std::process; + +pub(crate) fn runner(args: RunnerArgs) -> Result<(), ErrorString> { + let out_dir = tempdir::TempDir::new("bootimage-runner")?; + let bootimage_bin = out_dir.path().join("bootimage.bin"); + + let builder = bootimage::Builder::new(None)?; + builder.create_bootimage(&args.executable, &bootimage_bin, false)?; + + let run_cmd = args.run_command.unwrap_or(vec![ + "qemu-system-x86_64".into(), + "-drive".into(), + "format=raw,file={bootimage}".into(), + ]); + + println!("Running {:?}", run_cmd); + + let mut command = process::Command::new(&run_cmd[0]); + for arg in &run_cmd[1..] { + command.arg(arg.replace("{bootimage}", &format!("{}", bootimage_bin.display()))); + } + let output = command + .output() + .map_err(|e| format!("Failed to execute `{:?}`: {}", command, e))?; + + if !output.status.success() { + return Err(ErrorString { + exit_code: output.status.code().unwrap_or(1), + message: Box::new(format!( + "Command `{:?}` failed:\n{}", + command, + String::from_utf8_lossy(&output.stderr) + )), + }); + } + + drop(bootimage_bin); + out_dir.close()?; + + Ok(()) +} From 83282120fb7e85923ef8dd1b0c78b11234d87e26 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 27 Mar 2019 11:28:20 +0100 Subject: [PATCH 08/50] Run cargo fmt --- src/args.rs | 8 +++++++- src/config.rs | 10 ++++------ src/subcommand/test.rs | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/args.rs b/src/args.rs index 494ad1a..3d97978 100644 --- a/src/args.rs +++ b/src/args.rs @@ -201,7 +201,13 @@ where A: Iterator, { let mut arg_iter = args.into_iter().fuse(); - let executable = PathBuf::from(arg_iter.next().expect("excepted path to kernel executable as first argument")).canonicalize().expect("Failed to canonicalize executable path"); + let executable = PathBuf::from( + arg_iter + .next() + .expect("excepted path to kernel executable as first argument"), + ) + .canonicalize() + .expect("Failed to canonicalize executable path"); let mut run_command = None; loop { diff --git a/src/config.rs b/src/config.rs index 5acd6e0..73a3de7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -40,10 +40,9 @@ pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result metadata.as_table().ok_or(format!( - "Bootimage configuration invalid: {:?}", - metadata - ))?, + Some(metadata) => metadata + .as_table() + .ok_or(format!("Bootimage configuration invalid: {:?}", metadata))?, }; let mut config = ConfigBuilder { @@ -67,8 +66,7 @@ pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result Err(format!( "unexpected `package.metadata.bootimage` \ key `{}` with value `{}`", - key, - value + key, value ))?, } } diff --git a/src/subcommand/test.rs b/src/subcommand/test.rs index 6dee868..b381356 100644 --- a/src/subcommand/test.rs +++ b/src/subcommand/test.rs @@ -1,6 +1,6 @@ use crate::{args::Args, config, subcommand::build, ErrorString}; -use std::{io::Write, path::PathBuf, time::Duration, fs, io, process}; use rayon::prelude::*; +use std::{fs, io, io::Write, path::PathBuf, process, time::Duration}; use wait_timeout::ChildExt; pub(crate) fn test(mut args: Args) -> Result<(), ErrorString> { From acfc0b2708db12e8d2465bc7746aed154a0c4a82 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 27 Mar 2019 12:11:00 +0100 Subject: [PATCH 09/50] Refactor: Move everything to library --- src/builder.rs | 371 ++++++++++++++++++++++++++++++ src/cargo_config.rs | 61 +++++ src/lib.rs | 470 +++++---------------------------------- src/main.rs | 65 +----- src/subcommand/build.rs | 10 +- src/subcommand/run.rs | 4 +- src/subcommand/runner.rs | 4 +- src/subcommand/test.rs | 4 +- 8 files changed, 494 insertions(+), 495 deletions(-) create mode 100644 src/builder.rs create mode 100644 src/cargo_config.rs diff --git a/src/builder.rs b/src/builder.rs new file mode 100644 index 0000000..546d3af --- /dev/null +++ b/src/builder.rs @@ -0,0 +1,371 @@ +use std::{ + fmt, io, + path::{Path, PathBuf}, + process::{self, Command}, +}; + +pub struct Builder { + kernel_manifest_path: PathBuf, + kernel_metadata: cargo_metadata::Metadata, +} + +impl Builder { + pub fn new(manifest_path: Option) -> Result { + let kernel_manifest_path = + manifest_path.unwrap_or(locate_cargo_manifest::locate_manifest()?); + let kernel_metadata = cargo_metadata::MetadataCommand::new() + .manifest_path(&kernel_manifest_path) + .exec()?; + Ok(Builder { + kernel_manifest_path, + kernel_metadata, + }) + } + + pub fn kernel_manifest_path(&self) -> &Path { + &self.kernel_manifest_path + } + + pub fn kernel_root(&self) -> &Path { + self.kernel_manifest_path + .parent() + .expect("kernel manifest has no parent directory") + } + + pub fn kernel_metadata(&self) -> &cargo_metadata::Metadata { + &self.kernel_metadata + } + + pub fn kernel_package(&self) -> Result<&cargo_metadata::Package, String> { + let mut packages = self.kernel_metadata.packages.iter(); + let kernel_package = packages.find(|p| &p.manifest_path == &self.kernel_manifest_path); + kernel_package.ok_or(format!( + "packages[manifest_path = `{}`]", + &self.kernel_manifest_path.display() + )) + } + + pub fn build_kernel(&self, args: &[String], quiet: bool) -> Result<(), BuildKernelError> { + if !quiet { + println!("Building kernel"); + } + + let cargo = std::env::var("CARGO").unwrap_or("cargo".to_owned()); + let mut cmd = process::Command::new(cargo); + cmd.arg("xbuild"); + cmd.args(args); + if !quiet { + cmd.stdout(process::Stdio::inherit()); + cmd.stderr(process::Stdio::inherit()); + } + let output = cmd.output().map_err(|err| BuildKernelError::Io { + message: "failed to execute kernel build", + error: err, + })?;; + if !output.status.success() { + let mut help_command = process::Command::new("cargo"); + help_command.arg("xbuild").arg("--help"); + help_command.stdout(process::Stdio::null()); + help_command.stderr(process::Stdio::null()); + if let Ok(help_exit_status) = help_command.status() { + if !help_exit_status.success() { + return Err(BuildKernelError::XbuildNotFound); + } + } + return Err(BuildKernelError::XbuildFailed { + stderr: output.stderr, + }); + } + + Ok(()) + } + + pub fn create_bootimage( + &self, + kernel_bin_path: &Path, + output_bin_path: &Path, + quiet: bool, + ) -> Result<(), CreateBootimageError> { + let metadata = self.kernel_metadata(); + + let bootloader_name = { + let kernel_package = self + .kernel_package() + .map_err(|key| CreateBootimageError::CargoMetadataIncomplete { key })?; + let mut dependencies = kernel_package.dependencies.iter(); + let bootloader_package = dependencies + .find(|p| p.rename.as_ref().unwrap_or(&p.name) == "bootloader") + .ok_or(CreateBootimageError::BootloaderNotFound)?; + bootloader_package.name.clone() + }; + let target_dir = metadata + .target_directory + .join("bootimage") + .join(&bootloader_name); + + let bootloader_pkg = metadata + .packages + .iter() + .find(|p| p.name == bootloader_name) + .ok_or(CreateBootimageError::CargoMetadataIncomplete { + key: format!("packages[name = `{}`", &bootloader_name), + })?; + let bootloader_root = bootloader_pkg.manifest_path.parent().ok_or( + CreateBootimageError::BootloaderInvalid( + "bootloader manifest has no target directory".into(), + ), + )?; + let bootloader_features = + { + let resolve = metadata.resolve.as_ref().ok_or( + CreateBootimageError::CargoMetadataIncomplete { + key: "resolve".into(), + }, + )?; + let bootloader_resolve = resolve + .nodes + .iter() + .find(|n| n.id == bootloader_pkg.id) + .ok_or(CreateBootimageError::CargoMetadataIncomplete { + key: format!("resolve[\"{}\"]", bootloader_name), + })?; + bootloader_resolve.features.clone() + }; + let bootloader_target_triple = + crate::cargo_config::default_target_triple(&bootloader_root, false) + .map_err(CreateBootimageError::BootloaderInvalid)? + .ok_or(CreateBootimageError::BootloaderInvalid(format!( + "bootloader must have a default target" + )))?; + + // build bootloader + if !quiet { + println!("Building bootloader"); + } + + let cargo = std::env::var("CARGO").unwrap_or("cargo".to_owned()); + let mut cmd = process::Command::new(cargo); + cmd.arg("xbuild"); + cmd.arg("--manifest-path"); + cmd.arg(&bootloader_pkg.manifest_path); + cmd.arg("--target-dir").arg(&target_dir); + cmd.arg("--features") + .arg(bootloader_features.as_slice().join(" ")); + cmd.arg("--release"); + cmd.current_dir(bootloader_root); + cmd.env("KERNEL", kernel_bin_path); + cmd.env_remove("RUSTFLAGS"); + if !quiet { + cmd.stdout(process::Stdio::inherit()); + cmd.stderr(process::Stdio::inherit()); + } + let output = cmd.output().map_err(|err| CreateBootimageError::Io { + message: "failed to execute bootloader build command", + error: err, + })?; + if !output.status.success() { + return Err(CreateBootimageError::BootloaderBuildFailed { + stderr: output.stderr, + }); + } + + let bootloader_elf_path = target_dir + .join(&bootloader_target_triple) + .join("release") + .join(&bootloader_name); + + let llvm_tools = llvm_tools::LlvmTools::new()?; + let objcopy = llvm_tools + .tool(&llvm_tools::exe("llvm-objcopy")) + .ok_or(CreateBootimageError::LlvmObjcopyNotFound)?; + + // convert bootloader to binary + let mut cmd = Command::new(objcopy); + cmd.arg("-I").arg("elf64-x86-64"); + cmd.arg("-O").arg("binary"); + cmd.arg("--binary-architecture=i386:x86-64"); + cmd.arg(&bootloader_elf_path); + cmd.arg(&output_bin_path); + let output = cmd.output().map_err(|err| CreateBootimageError::Io { + message: "failed to execute llvm-objcopy command", + error: err, + })?; + if !output.status.success() { + return Err(CreateBootimageError::ObjcopyFailed { + stderr: output.stderr, + }); + } + + Ok(()) + } +} + +#[derive(Debug)] +pub enum BuilderError { + /// Failed to locate cargo manifest + LocateCargoManifest(locate_cargo_manifest::LocateManifestError), + /// Error while running `cargo metadata` + CargoMetadata(cargo_metadata::Error), +} + +impl fmt::Display for BuilderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + BuilderError::LocateCargoManifest(err) => writeln!( + f, + "Could not find Cargo.toml file starting from current folder: {:?}", + err + ), + BuilderError::CargoMetadata(err) => writeln!( + f, + "Error while running `cargo metadata` for current project: {:?}", + err + ), + } + } +} + +#[derive(Debug)] +pub enum BuildKernelError { + /// Could not find kernel package in cargo metadata, required for retrieving kernel crate name + KernelPackageNotFound, + /// An unexpected I/O error occurred + Io { + /// Desciption of the failed I/O operation + message: &'static str, + /// The I/O error that occured + error: io::Error, + }, + XbuildNotFound, + XbuildFailed { + stderr: Vec, + }, + CargoConfigInvalid { + path: PathBuf, + error: String, + }, +} + +impl fmt::Display for BuildKernelError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + BuildKernelError::KernelPackageNotFound => { + writeln!(f, "Could not find kernel package in cargo metadata, required for retrieving kernel crate name") + } + BuildKernelError::Io {message, error} => { + writeln!(f, "I/O error: {}: {}", message, error) + } + BuildKernelError::XbuildNotFound => { + writeln!(f, "Failed to run `cargo xbuild`. Perhaps it is not installed?\n\ + Run `cargo install cargo-xbuild` to install it.") + } + BuildKernelError::XbuildFailed{stderr} => { + writeln!(f, "Kernel build failed: {}", String::from_utf8_lossy(stderr)) + } + BuildKernelError::CargoConfigInvalid{path,error} => { + writeln!(f, "Failed to read cargo config at {}: {}", path.display(), error) + }, + } + } +} + +#[derive(Debug)] +pub enum CreateBootimageError { + /// Could not find some required information in the `cargo metadata` output + CargoMetadataIncomplete { + /// The required key that was not found + key: String, + }, + /// Bootloader dependency not found + BootloaderNotFound, + /// Bootloader dependency has not the right format + BootloaderInvalid(String), + BootloaderBuildFailed { + stderr: Vec, + }, + /// An unexpected I/O error occurred + Io { + /// Desciption of the failed I/O operation + message: &'static str, + /// The I/O error that occured + error: io::Error, + }, + /// There was a problem retrieving the `llvm-tools-preview` rustup component + LlvmTools(llvm_tools::Error), + /// The llvm-tools component did not contain the required `llvm-objcopy` executable + LlvmObjcopyNotFound, + /// The `llvm-objcopy` command failed + ObjcopyFailed { + stderr: Vec, + }, +} + +impl fmt::Display for CreateBootimageError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + CreateBootimageError::CargoMetadataIncomplete { key } => writeln!( + f, + "Could not find required key `{}` in cargo metadata output", + key + ), + CreateBootimageError::BootloaderNotFound => { + writeln!(f, "Bootloader dependency not found\n\n\ + You need to add a dependency on a crate named `bootloader` in your Cargo.toml.") + } + CreateBootimageError::BootloaderInvalid(err) => writeln!( + f, + "The `bootloader` dependency has not the right format: {}", + err + ), + CreateBootimageError::BootloaderBuildFailed { stderr } => writeln!( + f, + "Bootloader build failed:\n\n{}", + String::from_utf8_lossy(stderr) + ), + CreateBootimageError::Io { message, error } => { + writeln!(f, "I/O error: {}: {}", message, error) + } + CreateBootimageError::LlvmTools(err) => match err { + llvm_tools::Error::NotFound => writeln!( + f, + "Could not find the `llvm-tools-preview` rustup component.\n\n\ + You can install by executing `rustup component add llvm-tools-preview`." + ), + err => writeln!( + f, + "Failed to locate the `llvm-tools-preview` rustup component: {:?}", + err + ), + }, + CreateBootimageError::LlvmObjcopyNotFound => writeln!( + f, + "Could not find `llvm-objcopy` in the `llvm-tools-preview` rustup component." + ), + CreateBootimageError::ObjcopyFailed { stderr } => writeln!( + f, + "Failed to run `llvm-objcopy`: {}", + String::from_utf8_lossy(stderr) + ), + } + } +} + +// from implementations + +impl From for BuilderError { + fn from(err: locate_cargo_manifest::LocateManifestError) -> Self { + BuilderError::LocateCargoManifest(err) + } +} + +impl From for BuilderError { + fn from(err: cargo_metadata::Error) -> Self { + BuilderError::CargoMetadata(err) + } +} + +impl From for CreateBootimageError { + fn from(err: llvm_tools::Error) -> Self { + CreateBootimageError::LlvmTools(err) + } +} diff --git a/src/cargo_config.rs b/src/cargo_config.rs new file mode 100644 index 0000000..4e57ad7 --- /dev/null +++ b/src/cargo_config.rs @@ -0,0 +1,61 @@ +use std::{ + fs, + path::{Path, PathBuf}, +}; + +pub fn default_target_triple(crate_root: &Path, walk_up: bool) -> Result, String> { + let default_triple = default_target(crate_root, walk_up)?; + default_triple + .map(|(target, crate_root)| { + if target.ends_with(".json") { + crate_root + .join(target) + .file_stem() + .ok_or(String::from( + "The target path specfied in `build.target` has no file stem", + ))? + .to_os_string() + .into_string() + .map_err(|err| format!("Default target triple not valid UTF-8: {:?}", err)) + } else { + Ok(target) + } + }) + .transpose() +} + +fn default_target(crate_root: &Path, walk_up: bool) -> Result, String> { + let mut parent_dir = crate_root; + + loop { + let config_path = parent_dir.join(".cargo/config"); + if config_path.exists() { + let config_content = fs::read_to_string(config_path).map_err(|err| { + format!("Failed to read `.cargo/config` file of crate: {:?}", err) + })?; + let config = config_content.parse::().map_err(|err| { + format!( + "Failed to parse `.cargo/config` of crate as toml: {:?}", + err + ) + })?; + let target = config + .get("build") + .and_then(|v| v.get("target")) + .and_then(|v| v.as_str()) + .map(String::from); + if let Some(target) = target { + return Ok(Some((target, parent_dir.to_owned()))); + } + } + if walk_up { + parent_dir = match parent_dir.parent() { + Some(parent) => parent, + None => break, + } + } else { + break; + } + } + Ok(None) +} diff --git a/src/lib.rs b/src/lib.rs index 73876cd..9fa9559 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,434 +1,64 @@ -use std::{ - fmt, fs, io, - path::{Path, PathBuf}, - process::{self, Command}, -}; - -pub struct Builder { - kernel_manifest_path: PathBuf, - kernel_metadata: cargo_metadata::Metadata, +use args::{Args, RunnerArgs}; +use std::fmt; + +pub mod args; +pub mod builder; +pub mod cargo_config; +pub mod config; +pub mod help; + +mod subcommand; + +enum Command { + NoSubcommand, + Build(Args), + Run(Args), + Test(Args), + Runner(RunnerArgs), + Help, + BuildHelp, + RunHelp, + TestHelp, + RunnerHelp, + Version, } -impl Builder { - pub fn new(manifest_path: Option) -> Result { - let kernel_manifest_path = - manifest_path.unwrap_or(locate_cargo_manifest::locate_manifest()?); - let kernel_metadata = cargo_metadata::MetadataCommand::new() - .manifest_path(&kernel_manifest_path) - .exec()?; - Ok(Builder { - kernel_manifest_path, - kernel_metadata, - }) - } - - pub fn kernel_manifest_path(&self) -> &Path { - &self.kernel_manifest_path - } - - pub fn kernel_root(&self) -> &Path { - self.kernel_manifest_path - .parent() - .expect("kernel manifest has no parent directory") - } - - pub fn kernel_metadata(&self) -> &cargo_metadata::Metadata { - &self.kernel_metadata - } - - pub fn kernel_package(&self) -> Result<&cargo_metadata::Package, String> { - let mut packages = self.kernel_metadata.packages.iter(); - let kernel_package = packages.find(|p| &p.manifest_path == &self.kernel_manifest_path); - kernel_package.ok_or(format!( - "packages[manifest_path = `{}`]", - &self.kernel_manifest_path.display() - )) - } - - pub fn build_kernel(&self, args: &[String], quiet: bool) -> Result<(), BuildKernelError> { - if !quiet { - println!("Building kernel"); - } - - let cargo = std::env::var("CARGO").unwrap_or("cargo".to_owned()); - let mut cmd = process::Command::new(cargo); - cmd.arg("xbuild"); - cmd.args(args); - if !quiet { - cmd.stdout(process::Stdio::inherit()); - cmd.stderr(process::Stdio::inherit()); - } - let output = cmd.output().map_err(|err| BuildKernelError::Io { - message: "failed to execute kernel build", - error: err, - })?;; - if !output.status.success() { - let mut help_command = process::Command::new("cargo"); - help_command.arg("xbuild").arg("--help"); - help_command.stdout(process::Stdio::null()); - help_command.stderr(process::Stdio::null()); - if let Ok(help_exit_status) = help_command.status() { - if !help_exit_status.success() { - return Err(BuildKernelError::XbuildNotFound); - } - } - return Err(BuildKernelError::XbuildFailed { - stderr: output.stderr, - }); - } - - Ok(()) - } - - pub fn create_bootimage( - &self, - kernel_bin_path: &Path, - output_bin_path: &Path, - quiet: bool, - ) -> Result<(), CreateBootimageError> { - let metadata = self.kernel_metadata(); - - let bootloader_name = { - let kernel_package = self - .kernel_package() - .map_err(|key| CreateBootimageError::CargoMetadataIncomplete { key })?; - let mut dependencies = kernel_package.dependencies.iter(); - let bootloader_package = dependencies - .find(|p| p.rename.as_ref().unwrap_or(&p.name) == "bootloader") - .ok_or(CreateBootimageError::BootloaderNotFound)?; - bootloader_package.name.clone() - }; - let target_dir = metadata - .target_directory - .join("bootimage") - .join(&bootloader_name); - - let bootloader_pkg = metadata - .packages - .iter() - .find(|p| p.name == bootloader_name) - .ok_or(CreateBootimageError::CargoMetadataIncomplete { - key: format!("packages[name = `{}`", &bootloader_name), - })?; - let bootloader_root = bootloader_pkg.manifest_path.parent().ok_or( - CreateBootimageError::BootloaderInvalid( - "bootloader manifest has no target directory".into(), - ), - )?; - let bootloader_features = - { - let resolve = metadata.resolve.as_ref().ok_or( - CreateBootimageError::CargoMetadataIncomplete { - key: "resolve".into(), - }, - )?; - let bootloader_resolve = resolve - .nodes - .iter() - .find(|n| n.id == bootloader_pkg.id) - .ok_or(CreateBootimageError::CargoMetadataIncomplete { - key: format!("resolve[\"{}\"]", bootloader_name), - })?; - bootloader_resolve.features.clone() - }; - let bootloader_target_triple = - default_target_triple_from_cargo_config(&bootloader_root, false) - .map_err(CreateBootimageError::BootloaderInvalid)? - .ok_or(CreateBootimageError::BootloaderInvalid(format!( - "bootloader must have a default target" - )))?; - - // build bootloader - if !quiet { - println!("Building bootloader"); - } - - let cargo = std::env::var("CARGO").unwrap_or("cargo".to_owned()); - let mut cmd = process::Command::new(cargo); - cmd.arg("xbuild"); - cmd.arg("--manifest-path"); - cmd.arg(&bootloader_pkg.manifest_path); - cmd.arg("--target-dir").arg(&target_dir); - cmd.arg("--features") - .arg(bootloader_features.as_slice().join(" ")); - cmd.arg("--release"); - cmd.current_dir(bootloader_root); - cmd.env("KERNEL", kernel_bin_path); - cmd.env_remove("RUSTFLAGS"); - if !quiet { - cmd.stdout(process::Stdio::inherit()); - cmd.stderr(process::Stdio::inherit()); - } - let output = cmd.output().map_err(|err| CreateBootimageError::Io { - message: "failed to execute bootloader build command", - error: err, - })?; - if !output.status.success() { - return Err(CreateBootimageError::BootloaderBuildFailed { - stderr: output.stderr, - }); - } - - let bootloader_elf_path = target_dir - .join(&bootloader_target_triple) - .join("release") - .join(&bootloader_name); - - let llvm_tools = llvm_tools::LlvmTools::new()?; - let objcopy = llvm_tools - .tool(&llvm_tools::exe("llvm-objcopy")) - .ok_or(CreateBootimageError::LlvmObjcopyNotFound)?; - - // convert bootloader to binary - let mut cmd = Command::new(objcopy); - cmd.arg("-I").arg("elf64-x86-64"); - cmd.arg("-O").arg("binary"); - cmd.arg("--binary-architecture=i386:x86-64"); - cmd.arg(&bootloader_elf_path); - cmd.arg(&output_bin_path); - let output = cmd.output().map_err(|err| CreateBootimageError::Io { - message: "failed to execute llvm-objcopy command", - error: err, - })?; - if !output.status.success() { - return Err(CreateBootimageError::ObjcopyFailed { - stderr: output.stderr, - }); - } - - Ok(()) +pub fn run() -> Result<(), ErrorString> { + let command = args::parse_args(); + match command { + Command::Build(args) => subcommand::build::build(args), + Command::Run(args) => subcommand::run::run(args), + Command::Test(args) => subcommand::test::test(args), + Command::Runner(args) => subcommand::runner::runner(args), + Command::NoSubcommand => help::no_subcommand(), + Command::Help => Ok(help::help()), + Command::BuildHelp => Ok(help::build_help()), + Command::RunHelp => Ok(help::run_help()), + Command::TestHelp => Ok(help::test_help()), + Command::RunnerHelp => unimplemented!(), + Command::Version => Ok(println!("bootimage {}", env!("CARGO_PKG_VERSION"))), } } -pub fn default_target_triple_from_cargo_config( - crate_root: &Path, - walk_up: bool, -) -> Result, String> { - let default_triple = default_target_from_cargo_config(crate_root, walk_up)?; - default_triple - .map(|(target, crate_root)| { - if target.ends_with(".json") { - crate_root - .join(target) - .file_stem() - .ok_or(String::from( - "The target path specfied in `build.target` has no file stem", - ))? - .to_os_string() - .into_string() - .map_err(|err| format!("Default target triple not valid UTF-8: {:?}", err)) - } else { - Ok(target) - } - }) - .transpose() +pub struct ErrorString { + pub message: Box, + pub exit_code: i32, } -fn default_target_from_cargo_config( - crate_root: &Path, - walk_up: bool, -) -> Result, String> { - let mut parent_dir = crate_root; - - loop { - let config_path = parent_dir.join(".cargo/config"); - if config_path.exists() { - let config_content = fs::read_to_string(config_path).map_err(|err| { - format!("Failed to read `.cargo/config` file of crate: {:?}", err) - })?; - let config = config_content.parse::().map_err(|err| { - format!( - "Failed to parse `.cargo/config` of crate as toml: {:?}", - err - ) - })?; - let target = config - .get("build") - .and_then(|v| v.get("target")) - .and_then(|v| v.as_str()) - .map(String::from); - if let Some(target) = target { - return Ok(Some((target, parent_dir.to_owned()))); - } - } - if walk_up { - parent_dir = match parent_dir.parent() { - Some(parent) => parent, - None => break, - } - } else { - break; - } - } - Ok(None) -} - -#[derive(Debug)] -pub enum BuilderError { - /// Failed to locate cargo manifest - LocateCargoManifest(locate_cargo_manifest::LocateManifestError), - /// Error while running `cargo metadata` - CargoMetadata(cargo_metadata::Error), -} - -impl fmt::Display for BuilderError { +impl fmt::Debug for ErrorString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - BuilderError::LocateCargoManifest(err) => writeln!( - f, - "Could not find Cargo.toml file starting from current folder: {:?}", - err - ), - BuilderError::CargoMetadata(err) => writeln!( - f, - "Error while running `cargo metadata` for current project: {:?}", - err - ), - } + self.message.fmt(f) } } -#[derive(Debug)] -pub enum BuildKernelError { - /// Could not find kernel package in cargo metadata, required for retrieving kernel crate name - KernelPackageNotFound, - /// An unexpected I/O error occurred - Io { - /// Desciption of the failed I/O operation - message: &'static str, - /// The I/O error that occured - error: io::Error, - }, - XbuildNotFound, - XbuildFailed { - stderr: Vec, - }, - CargoConfigInvalid { - path: PathBuf, - error: String, - }, -} - -impl fmt::Display for BuildKernelError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - BuildKernelError::KernelPackageNotFound => { - writeln!(f, "Could not find kernel package in cargo metadata, required for retrieving kernel crate name") - } - BuildKernelError::Io {message, error} => { - writeln!(f, "I/O error: {}: {}", message, error) - } - BuildKernelError::XbuildNotFound => { - writeln!(f, "Failed to run `cargo xbuild`. Perhaps it is not installed?\n\ - Run `cargo install cargo-xbuild` to install it.") - } - BuildKernelError::XbuildFailed{stderr} => { - writeln!(f, "Kernel build failed: {}", String::from_utf8_lossy(stderr)) - } - BuildKernelError::CargoConfigInvalid{path,error} => { - writeln!(f, "Failed to read cargo config at {}: {}", path.display(), error) - }, +impl From for ErrorString +where + T: fmt::Display + Send + 'static, +{ + fn from(err: T) -> Self { + ErrorString { + message: Box::new(err), + exit_code: 1, } } } - -#[derive(Debug)] -pub enum CreateBootimageError { - /// Could not find some required information in the `cargo metadata` output - CargoMetadataIncomplete { - /// The required key that was not found - key: String, - }, - /// Bootloader dependency not found - BootloaderNotFound, - /// Bootloader dependency has not the right format - BootloaderInvalid(String), - BootloaderBuildFailed { - stderr: Vec, - }, - /// An unexpected I/O error occurred - Io { - /// Desciption of the failed I/O operation - message: &'static str, - /// The I/O error that occured - error: io::Error, - }, - /// There was a problem retrieving the `llvm-tools-preview` rustup component - LlvmTools(llvm_tools::Error), - /// The llvm-tools component did not contain the required `llvm-objcopy` executable - LlvmObjcopyNotFound, - /// The `llvm-objcopy` command failed - ObjcopyFailed { - stderr: Vec, - }, -} - -impl fmt::Display for CreateBootimageError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - CreateBootimageError::CargoMetadataIncomplete { key } => writeln!( - f, - "Could not find required key `{}` in cargo metadata output", - key - ), - CreateBootimageError::BootloaderNotFound => { - writeln!(f, "Bootloader dependency not found\n\n\ - You need to add a dependency on a crate named `bootloader` in your Cargo.toml.") - } - CreateBootimageError::BootloaderInvalid(err) => writeln!( - f, - "The `bootloader` dependency has not the right format: {}", - err - ), - CreateBootimageError::BootloaderBuildFailed { stderr } => writeln!( - f, - "Bootloader build failed:\n\n{}", - String::from_utf8_lossy(stderr) - ), - CreateBootimageError::Io { message, error } => { - writeln!(f, "I/O error: {}: {}", message, error) - } - CreateBootimageError::LlvmTools(err) => match err { - llvm_tools::Error::NotFound => writeln!( - f, - "Could not find the `llvm-tools-preview` rustup component.\n\n\ - You can install by executing `rustup component add llvm-tools-preview`." - ), - err => writeln!( - f, - "Failed to locate the `llvm-tools-preview` rustup component: {:?}", - err - ), - }, - CreateBootimageError::LlvmObjcopyNotFound => writeln!( - f, - "Could not find `llvm-objcopy` in the `llvm-tools-preview` rustup component." - ), - CreateBootimageError::ObjcopyFailed { stderr } => writeln!( - f, - "Failed to run `llvm-objcopy`: {}", - String::from_utf8_lossy(stderr) - ), - } - } -} - -// from implementations - -impl From for BuilderError { - fn from(err: locate_cargo_manifest::LocateManifestError) -> Self { - BuilderError::LocateCargoManifest(err) - } -} - -impl From for BuilderError { - fn from(err: cargo_metadata::Error) -> Self { - BuilderError::CargoMetadata(err) - } -} - -impl From for CreateBootimageError { - fn from(err: llvm_tools::Error) -> Self { - CreateBootimageError::LlvmTools(err) - } -} diff --git a/src/main.rs b/src/main.rs index 8a9e2d4..d6e09a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,69 +1,8 @@ -use args::{Args, RunnerArgs}; -use std::{fmt, process}; - -mod args; -mod config; -mod help; - -mod subcommand; - -enum Command { - NoSubcommand, - Build(Args), - Run(Args), - Test(Args), - Runner(RunnerArgs), - Help, - BuildHelp, - RunHelp, - TestHelp, - RunnerHelp, - Version, -} +use std::process; pub fn main() { - if let Err(err) = run() { + if let Err(err) = bootimage::run() { eprintln!("Error: {}", err.message); process::exit(err.exit_code); } } - -fn run() -> Result<(), ErrorString> { - let command = args::parse_args(); - match command { - Command::Build(args) => subcommand::build::build(args), - Command::Run(args) => subcommand::run::run(args), - Command::Test(args) => subcommand::test::test(args), - Command::Runner(args) => subcommand::runner::runner(args), - Command::NoSubcommand => help::no_subcommand(), - Command::Help => Ok(help::help()), - Command::BuildHelp => Ok(help::build_help()), - Command::RunHelp => Ok(help::run_help()), - Command::TestHelp => Ok(help::test_help()), - Command::RunnerHelp => unimplemented!(), - Command::Version => Ok(println!("bootimage {}", env!("CARGO_PKG_VERSION"))), - } -} - -struct ErrorString { - pub message: Box, - pub exit_code: i32, -} - -impl fmt::Debug for ErrorString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.message.fmt(f) - } -} - -impl From for ErrorString -where - T: fmt::Display + Send + 'static, -{ - fn from(err: T) -> Self { - ErrorString { - message: Box::new(err), - exit_code: 1, - } - } -} diff --git a/src/subcommand/build.rs b/src/subcommand/build.rs index 014e069..6db5f3c 100644 --- a/src/subcommand/build.rs +++ b/src/subcommand/build.rs @@ -1,12 +1,11 @@ -use crate::{args::Args, config, ErrorString}; -use bootimage::Builder; +use crate::{args::Args, builder::Builder, cargo_config, config, ErrorString}; use std::{ path::{Path, PathBuf}, process, }; pub(crate) fn build(mut args: Args) -> Result<(), ErrorString> { - let builder = bootimage::Builder::new(args.manifest_path().clone())?; + let builder = Builder::new(args.manifest_path().clone())?; let config = config::read_config(builder.kernel_manifest_path().to_owned())?; args.apply_default_target(&config, builder.kernel_root()); @@ -34,14 +33,13 @@ pub(crate) fn build_impl( Ok(bootimage_path) } -fn out_dir(args: &Args, builder: &bootimage::Builder) -> Result { +fn out_dir(args: &Args, builder: &Builder) -> Result { let target_dir = PathBuf::from(&builder.kernel_metadata().target_directory); let mut out_dir = target_dir; if let &Some(ref target) = args.target() { out_dir.push(Path::new(target).file_stem().unwrap().to_str().unwrap()); } else { - let default_triple = - bootimage::default_target_triple_from_cargo_config(builder.kernel_root(), true)?; + let default_triple = cargo_config::default_target_triple(builder.kernel_root(), true)?; if let Some(triple) = default_triple { out_dir.push(triple); } diff --git a/src/subcommand/run.rs b/src/subcommand/run.rs index 0804275..92eddd5 100644 --- a/src/subcommand/run.rs +++ b/src/subcommand/run.rs @@ -1,10 +1,10 @@ -use crate::{args::Args, config, ErrorString}; +use crate::{args::Args, builder::Builder, config, ErrorString}; use std::process; pub(crate) fn run(mut args: Args) -> Result<(), ErrorString> { use crate::subcommand::build; - let builder = bootimage::Builder::new(args.manifest_path().clone())?; + let builder = Builder::new(args.manifest_path().clone())?; let config = config::read_config(builder.kernel_manifest_path().to_owned())?; args.apply_default_target(&config, builder.kernel_root()); diff --git a/src/subcommand/runner.rs b/src/subcommand/runner.rs index 7e3a386..bbb6a16 100644 --- a/src/subcommand/runner.rs +++ b/src/subcommand/runner.rs @@ -1,11 +1,11 @@ -use crate::{args::RunnerArgs, ErrorString}; +use crate::{args::RunnerArgs, builder::Builder, ErrorString}; use std::process; pub(crate) fn runner(args: RunnerArgs) -> Result<(), ErrorString> { let out_dir = tempdir::TempDir::new("bootimage-runner")?; let bootimage_bin = out_dir.path().join("bootimage.bin"); - let builder = bootimage::Builder::new(None)?; + let builder = Builder::new(None)?; builder.create_bootimage(&args.executable, &bootimage_bin, false)?; let run_cmd = args.run_command.unwrap_or(vec![ diff --git a/src/subcommand/test.rs b/src/subcommand/test.rs index b381356..0f82acc 100644 --- a/src/subcommand/test.rs +++ b/src/subcommand/test.rs @@ -1,10 +1,10 @@ -use crate::{args::Args, config, subcommand::build, ErrorString}; +use crate::{args::Args, builder::Builder, config, subcommand::build, ErrorString}; use rayon::prelude::*; use std::{fs, io, io::Write, path::PathBuf, process, time::Duration}; use wait_timeout::ChildExt; pub(crate) fn test(mut args: Args) -> Result<(), ErrorString> { - let builder = bootimage::Builder::new(args.manifest_path().clone())?; + let builder = Builder::new(args.manifest_path().clone())?; let config = config::read_config(builder.kernel_manifest_path().to_owned())?; args.apply_default_target(&config, builder.kernel_root()); From e3b7f7556c1037a8bd24d4b06f1026eb8f09cf1f Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 27 Mar 2019 12:32:40 +0100 Subject: [PATCH 10/50] Add a `cargo-bootimage` executable (equivalent to `bootimage build`) --- src/args.rs | 80 +++++++++++++++++++++----------------- src/bin/cargo-bootimage.rs | 8 ++++ src/lib.rs | 5 ++- 3 files changed, 55 insertions(+), 38 deletions(-) create mode 100644 src/bin/cargo-bootimage.rs diff --git a/src/args.rs b/src/args.rs index 3d97978..e68a753 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,18 +1,24 @@ -use crate::{config::Config, Command}; +use crate::{config::Config, Command, ErrorString}; use std::path::{Path, PathBuf}; use std::{env, mem}; -pub(crate) fn parse_args() -> Command { - let mut args = env::args().skip(1); +pub(crate) fn parse_args() -> Result { + let mut args = env::args(); + let executable_name = args.next().ok_or("no first argument (executable name)")?; let first = args.next(); match first.as_ref().map(|s| s.as_str()) { Some("build") => parse_build_args(args), - Some("run") => match parse_build_args(args) { + Some("bootimage") if executable_name.ends_with("cargo-bootimage") => parse_build_args(args) + .map(|cmd| match cmd { + Command::BuildHelp => Command::CargoBootimageHelp, + cmd => cmd, + }), + Some("run") => parse_build_args(args).map(|cmd| match cmd { Command::Build(args) => Command::Run(args), Command::BuildHelp => Command::RunHelp, cmd => cmd, - }, - Some("test") => match parse_build_args(args) { + }), + Some("test") => parse_build_args(args).map(|cmd| match cmd { Command::Build(args) => { assert_eq!( args.bin_name, None, @@ -22,15 +28,15 @@ pub(crate) fn parse_args() -> Command { } Command::BuildHelp => Command::TestHelp, cmd => cmd, - }, + }), Some("runner") => parse_runner_args(args), - Some("--help") | Some("-h") => Command::Help, - Some("--version") => Command::Version, - _ => Command::NoSubcommand, + Some("--help") | Some("-h") => Ok(Command::Help), + Some("--version") => Ok(Command::Version), + _ => Ok(Command::NoSubcommand), } } -fn parse_build_args(args: A) -> Command +fn parse_build_args(args: A) -> Result where A: Iterator, { @@ -42,12 +48,12 @@ where let mut run_args = Vec::new(); let mut run_args_started = false; { - fn set(arg: &mut Option, value: Option) { + fn set(arg: &mut Option, value: Option) -> Result<(), ErrorString> { let previous = mem::replace(arg, value); - assert!( - previous.is_none(), - "multiple arguments of same type provided" - ) + if previous.is_some() { + Err("multiple arguments of same type provided")? + } + Ok(()) }; let mut arg_iter = args.into_iter(); @@ -58,14 +64,14 @@ where } match arg.as_ref() { "--help" | "-h" => { - return Command::BuildHelp; + return Ok(Command::BuildHelp); } "--version" => { - return Command::Version; + return Ok(Command::Version); } "--bin" => { let next = arg_iter.next(); - set(&mut bin_name, next.clone()); + set(&mut bin_name, next.clone())?; cargo_args.push(arg); if let Some(next) = next { cargo_args.push(next); @@ -75,12 +81,12 @@ where set( &mut bin_name, Some(String::from(arg.trim_start_matches("--bin="))), - ); + )?; cargo_args.push(arg); } "--target" => { let next = arg_iter.next(); - set(&mut target, next.clone()); + set(&mut target, next.clone())?; cargo_args.push(arg); if let Some(next) = next { cargo_args.push(next); @@ -90,7 +96,7 @@ where set( &mut target, Some(String::from(arg.trim_start_matches("--target="))), - ); + )?; cargo_args.push(arg); } "--manifest-path" => { @@ -102,7 +108,7 @@ where .canonicalize() .expect("--manifest-path invalid") }), - ); + )?; cargo_args.push(arg); if let Some(next) = next { cargo_args.push(next); @@ -112,11 +118,11 @@ where let path = Path::new(arg.trim_start_matches("--manifest-path=")) .canonicalize() .expect("--manifest-path invalid"); - set(&mut manifest_path, Some(path)); + set(&mut manifest_path, Some(path))?; cargo_args.push(arg); } "--release" => { - set(&mut release, Some(true)); + set(&mut release, Some(true))?; cargo_args.push(arg); } "--" => { @@ -129,14 +135,14 @@ where } } - Command::Build(Args { + Ok(Command::Build(Args { cargo_args, run_args, bin_name, target, manifest_path, release: release.unwrap_or(false), - }) + })) } #[derive(Debug, Clone)] @@ -196,7 +202,7 @@ impl Args { } } -fn parse_runner_args(args: A) -> Command +fn parse_runner_args(args: A) -> Result where A: Iterator, { @@ -204,34 +210,36 @@ where let executable = PathBuf::from( arg_iter .next() - .expect("excepted path to kernel executable as first argument"), + .ok_or("excepted path to kernel executable as first argument")?, ) .canonicalize() - .expect("Failed to canonicalize executable path"); + .map_err(|err| format!("Failed to canonicalize executable path: {}", err))?; let mut run_command = None; loop { match arg_iter.next().as_ref().map(|s| s.as_str()) { Some("--command") => { let old = mem::replace(&mut run_command, Some(arg_iter.collect())); - assert!(old.is_none(), "multiple `--command` arguments"); + if !old.is_none() { + Err("multiple `--command` arguments")?; + } break; } Some("--help") | Some("-h") => { - return Command::RunnerHelp; + return Ok(Command::RunnerHelp); } Some("--version") => { - return Command::Version; + return Ok(Command::Version); } None => break, - Some(arg) => panic!("unexpected argument `{}`", arg), + Some(arg) => Err(format!("unexpected argument `{}`", arg))?, } } - Command::Runner(RunnerArgs { + Ok(Command::Runner(RunnerArgs { executable, run_command, - }) + })) } #[derive(Debug, Clone)] diff --git a/src/bin/cargo-bootimage.rs b/src/bin/cargo-bootimage.rs new file mode 100644 index 0000000..d6e09a5 --- /dev/null +++ b/src/bin/cargo-bootimage.rs @@ -0,0 +1,8 @@ +use std::process; + +pub fn main() { + if let Err(err) = bootimage::run() { + eprintln!("Error: {}", err.message); + process::exit(err.exit_code); + } +} diff --git a/src/lib.rs b/src/lib.rs index 9fa9559..0a1a976 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,12 +19,13 @@ enum Command { BuildHelp, RunHelp, TestHelp, + CargoBootimageHelp, RunnerHelp, Version, } pub fn run() -> Result<(), ErrorString> { - let command = args::parse_args(); + let command = args::parse_args()?; match command { Command::Build(args) => subcommand::build::build(args), Command::Run(args) => subcommand::run::run(args), @@ -35,8 +36,8 @@ pub fn run() -> Result<(), ErrorString> { Command::BuildHelp => Ok(help::build_help()), Command::RunHelp => Ok(help::run_help()), Command::TestHelp => Ok(help::test_help()), - Command::RunnerHelp => unimplemented!(), Command::Version => Ok(println!("bootimage {}", env!("CARGO_PKG_VERSION"))), + Command::RunnerHelp | Command::CargoBootimageHelp => unimplemented!(), } } From 1fc4abdba63fa4ce11de5dc9a6e8b25d17ac9fe9 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 27 Mar 2019 12:37:58 +0100 Subject: [PATCH 11/50] Avoid newlines between `BUILD` lines in output of `bootimage test` --- src/subcommand/test.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/subcommand/test.rs b/src/subcommand/test.rs index 0f82acc..f60b1b2 100644 --- a/src/subcommand/test.rs +++ b/src/subcommand/test.rs @@ -24,7 +24,6 @@ pub(crate) fn test(mut args: Args) -> Result<(), ErrorString> { target_args.set_bin_name(target.name.clone()); let test_bin_path = build::build_impl(&builder, &mut target_args, true) .expect(&format!("Failed to build test: {}", target.name)); - println!(""); (target, test_bin_path) }) From 9287964c157f8a0638be6dea8e64450796fd82cf Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 27 Mar 2019 12:39:31 +0100 Subject: [PATCH 12/50] Increase test timeout to 5 minutes to allow for longer tests --- src/subcommand/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/subcommand/test.rs b/src/subcommand/test.rs index f60b1b2..866f8a8 100644 --- a/src/subcommand/test.rs +++ b/src/subcommand/test.rs @@ -50,7 +50,7 @@ pub(crate) fn test(mut args: Args) -> Result<(), ErrorString> { let mut child = command .spawn() .map_err(|e| format!("Failed to launch QEMU: {:?}\n{}", command, e))?; - let timeout = Duration::from_secs(60); + let timeout = Duration::from_secs(60 * 5); match child .wait_timeout(timeout) .map_err(|e| format!("Failed to wait with timeout: {}", e))? From 4c3bca0137fdc5fffb62caacc714dae6494c6cc0 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 27 Mar 2019 12:46:10 +0100 Subject: [PATCH 13/50] Make `test_timeout` configurable --- Readme.md | 7 ++++++- src/config.rs | 10 +++++++++- src/help/test_help.txt | 9 +++++++++ src/subcommand/test.rs | 2 +- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index 0def8db..ba964f7 100644 --- a/Readme.md +++ b/Readme.md @@ -35,10 +35,15 @@ Configuration is done through a through a `[package.metadata.bootimage]` table i ```toml [package.metadata.bootimage] - default-target = "" # This target is used if no `--target` is passed + # This target is used if no `--target` is passed + default-target = "" + # The command invoked on `bootimage run` # (the "{}" will be replaced with the path to the bootable disk image) run-command = ["qemu-system-x86_64", "-drive", "format=raw,file={}"] + + # The timeout for running an integration test in seconds + test-timeout = 300 ``` ## License diff --git a/src/config.rs b/src/config.rs index 73a3de7..93a4833 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,6 +7,7 @@ pub struct Config { pub manifest_path: PathBuf, pub default_target: Option, pub run_command: Vec, + pub test_timeout: u64, } pub(crate) fn read_config(manifest_path: PathBuf) -> Result { @@ -16,7 +17,7 @@ pub(crate) fn read_config(manifest_path: PathBuf) -> Result } pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result { - use std::{fs::File, io::Read}; + use std::{convert::TryFrom, fs::File, io::Read}; let cargo_toml: Value = { let mut content = String::new(); File::open(&manifest_path) @@ -53,6 +54,11 @@ pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result config.default_target = From::from(s), + ("test-timeout", Value::Integer(s)) => { + config.test_timeout = u64::try_from(s) + .map_err(|err| format!("test-timeout is not valid: {}", err))? + .into() + } ("run-command", Value::Array(array)) => { let mut command = Vec::new(); for value in array { @@ -78,6 +84,7 @@ struct ConfigBuilder { manifest_path: Option, default_target: Option, run_command: Option>, + test_timeout: Option, } impl Into for ConfigBuilder { @@ -90,6 +97,7 @@ impl Into for ConfigBuilder { "-drive".into(), "format=raw,file={}".into(), ]), + test_timeout: self.test_timeout.unwrap_or(60 * 5), } } } diff --git a/src/help/test_help.txt b/src/help/test_help.txt index 18c5b91..a9fa8e1 100644 --- a/src/help/test_help.txt +++ b/src/help/test_help.txt @@ -15,3 +15,12 @@ USAGE: (for other forms of usage see `bootimage --help`) (for BUILD_OPTS see `bootimage build --help`) + +CONFIGURATION: + The behavior of `bootimage test` can be configured through a + `[package.metadata.bootimage]` table in the `Cargo.toml`. The + following options are available to configure test behavior: + + [package.metadata.bootimage] + # The timeout for running an integration test in seconds + test-timeout = 300 \ No newline at end of file diff --git a/src/subcommand/test.rs b/src/subcommand/test.rs index 866f8a8..dbb8845 100644 --- a/src/subcommand/test.rs +++ b/src/subcommand/test.rs @@ -50,7 +50,7 @@ pub(crate) fn test(mut args: Args) -> Result<(), ErrorString> { let mut child = command .spawn() .map_err(|e| format!("Failed to launch QEMU: {:?}\n{}", command, e))?; - let timeout = Duration::from_secs(60 * 5); + let timeout = Duration::from_secs(config.test_timeout); match child .wait_timeout(timeout) .map_err(|e| format!("Failed to wait with timeout: {}", e))? From 60f050665698f01243cbb3a52522e3ac443410c3 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 27 Mar 2019 10:06:05 +0100 Subject: [PATCH 14/50] Update changelog --- Changelog.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Changelog.md b/Changelog.md index f0fa753..160b0c4 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,26 @@ + +## Breaking + +- Rewrite for new bootloader build system + - Compatible with bootloader 0.5.0+ +- Remove the following config options: `output`, `bootloader.*`, `minimum_image_size`, and `package_filepath` + - The bootloader is now fully controlled through cargo dependencies. + - For using a bootloader crate with name different than `bootloader` use [cargo's rename feature](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml). +- Remove support for `bootloader_precompiled` + - The `bootloader` crate compiles fine on all architectures for some time and should be prefered +- Require the `llvm-tools-preview` rustup component + +## Other + +- Add support for default targets declared in `.cargo/config` files +- Add a `cargo-bootimage` executable that is equivalent to `bootimage build` and can be used as cargo subcommand (`cargo bootimage`) +- Add a new `bootimage runner` subcommand that can be used as `target.[…].runner` in `.cargo/config` files +- Make test timeout configurable and increase default to 5 minutes +- Move crate to 2018 edition +- Refactor and cleanup the code +- Remove the dependency on `failure` + - Use a custom `ErrorString` type instead + # 0.6.6 - Update dependencies From 3d1bbcb5af6969a58fe4c957e4df6e3a3a376443 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Wed, 27 Mar 2019 14:11:23 +0100 Subject: [PATCH 15/50] Add a tester subcommand that can be used to run integration tests --- src/args.rs | 20 ++++ src/lib.rs | 7 +- src/subcommand.rs | 1 + src/subcommand/tester.rs | 201 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 src/subcommand/tester.rs diff --git a/src/args.rs b/src/args.rs index e68a753..ea98206 100644 --- a/src/args.rs +++ b/src/args.rs @@ -30,6 +30,11 @@ pub(crate) fn parse_args() -> Result { cmd => cmd, }), Some("runner") => parse_runner_args(args), + Some("tester") => parse_runner_args(args).map(|cmd| match cmd { + Command::Runner(args) => Command::Tester(TesterArgs::from(args)), + Command::RunnerHelp => Command::TesterHelp, + other => other, + }), Some("--help") | Some("-h") => Ok(Command::Help), Some("--version") => Ok(Command::Version), _ => Ok(Command::NoSubcommand), @@ -247,3 +252,18 @@ pub struct RunnerArgs { pub executable: PathBuf, pub run_command: Option>, } + +#[derive(Debug, Clone)] +pub struct TesterArgs { + pub test_path: PathBuf, + pub run_command: Option>, +} + +impl From for TesterArgs { + fn from(args: RunnerArgs) -> Self { + Self { + test_path: args.executable, + run_command: args.run_command, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 0a1a976..8ec0ef8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -use args::{Args, RunnerArgs}; +use args::{Args, RunnerArgs, TesterArgs}; use std::fmt; pub mod args; @@ -15,12 +15,14 @@ enum Command { Run(Args), Test(Args), Runner(RunnerArgs), + Tester(TesterArgs), Help, BuildHelp, RunHelp, TestHelp, CargoBootimageHelp, RunnerHelp, + TesterHelp, Version, } @@ -31,13 +33,14 @@ pub fn run() -> Result<(), ErrorString> { Command::Run(args) => subcommand::run::run(args), Command::Test(args) => subcommand::test::test(args), Command::Runner(args) => subcommand::runner::runner(args), + Command::Tester(args) => subcommand::tester::tester(args), Command::NoSubcommand => help::no_subcommand(), Command::Help => Ok(help::help()), Command::BuildHelp => Ok(help::build_help()), Command::RunHelp => Ok(help::run_help()), Command::TestHelp => Ok(help::test_help()), Command::Version => Ok(println!("bootimage {}", env!("CARGO_PKG_VERSION"))), - Command::RunnerHelp | Command::CargoBootimageHelp => unimplemented!(), + Command::RunnerHelp | Command::TesterHelp | Command::CargoBootimageHelp => unimplemented!(), } } diff --git a/src/subcommand.rs b/src/subcommand.rs index f848c46..0e49f4f 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -2,3 +2,4 @@ pub mod build; pub mod run; pub mod runner; pub mod test; +pub mod tester; diff --git a/src/subcommand/tester.rs b/src/subcommand/tester.rs new file mode 100644 index 0000000..4b246d5 --- /dev/null +++ b/src/subcommand/tester.rs @@ -0,0 +1,201 @@ +use crate::{args::TesterArgs, builder::Builder, config, ErrorString}; +use std::{ + fs, + io::{self, Write}, + path::Path, + process, + process::Command, + time::Duration, +}; +use wait_timeout::ChildExt; + +pub(crate) fn tester(args: TesterArgs) -> Result<(), ErrorString> { + let builder = Builder::new(None)?; + let config = config::read_config(builder.kernel_manifest_path().to_owned())?; + + let test_name = args + .test_path + .file_stem() + .expect("no file stem") + .to_os_string() + .into_string() + .expect("test name invalid utf8"); + + let kernel_manifest_path = locate_cargo_manifest::locate_manifest().unwrap_or( + Path::new("Cargo.toml") + .canonicalize() + .expect("failed to canonicalize manifest path"), + ); + let kernel_root_path = kernel_manifest_path + .parent() + .expect("kernel manifest path has no parent"); + let kernel_manifest_content = + fs::read_to_string(&kernel_manifest_path).expect("failed to read kernel manifest"); + let kernel_manifest: toml::Value = kernel_manifest_content + .parse() + .expect("failed to parse Cargo.toml"); + + let kernel_name = kernel_manifest + .get("package") + .and_then(|p| p.get("name")) + .expect("no package.name found in Cargo.toml") + .as_str() + .expect("package name must be a string"); + let dependency_table = { + let mut table = toml::value::Table::new(); + let mut dependencies = kernel_manifest + .get("dependencies") + .map(|v| { + v.as_table() + .expect("`dependencies` must be a table in Cargo.toml") + .clone() + }) + .unwrap_or(toml::value::Table::new()); + dependencies.insert( + kernel_name.to_owned(), + toml::from_str(&format!(r#"path = "{}""#, kernel_root_path.display())).unwrap(), + ); + for (key, entry) in kernel_manifest + .get("dev-dependencies") + .map(|v| { + v.as_table() + .expect("`dev-dependencies` must be a table in Cargo.toml") + .clone() + }) + .unwrap_or(toml::value::Table::new()) + { + dependencies.insert(key, entry); + } + table.insert("dependencies".to_owned(), toml::Value::Table(dependencies)); + toml::Value::Table(table) + }; + let kernel_target_dir = Path::new("target") + .canonicalize() + .expect("failed to canonicalize target dir"); // TODO + let kernel_target_json = Path::new("x86_64-blog_os.json") + .canonicalize() + .expect("failed to canonicalize target.json"); // TODO + let kernel_target_json_triple = kernel_target_json + .file_stem() + .expect("kernel target json has no valid file stem"); + + let out_dir = kernel_target_dir.join("integration-tests").join(&test_name); + fs::create_dir_all(&out_dir).expect("failed to create out dir"); + + let manifest_path = out_dir.join("Cargo.toml"); + let manifest_content = format!( + r#" +[package] +authors = ["Bootimage Tester "] +name = "{test_name}" +version = "0.0.0" +edition = "2018" + +[[bin]] +name = "{test_name}" +path = "{test_path}" + +{dependency_table} +"#, + test_name = test_name, + test_path = args.test_path.display(), + dependency_table = dependency_table + ); + + fs::write(&manifest_path, manifest_content)?; + + let cargo = std::env::var("CARGO").unwrap_or("cargo".to_owned()); + let mut cmd = Command::new(cargo); + cmd.arg("xbuild"); + cmd.arg("--manifest-path").arg(&manifest_path); + cmd.arg("--target-dir").arg(&kernel_target_dir); + cmd.env("SYSROOT_DIR", &kernel_target_dir.join("sysroot")); // for cargo-xbuild + cmd.arg("--target").arg(&kernel_target_json); // TODO remove when default targets are canonicalized properly + let output = cmd.output().expect("failed to run cargo xbuild"); + if !output.status.success() { + io::stderr() + .write_all(&output.stderr) + .expect("failed to write to stderr"); + process::exit(1); + } + + let executable = kernel_target_dir + .join(&kernel_target_json_triple) + .join("debug") + .join(&test_name); + let bootimage_bin_path = out_dir.join(format!("bootimage-{}.bin", test_name)); + + builder.create_bootimage(&executable, &bootimage_bin_path, true)?; + + let run_cmd = args.run_command.clone().unwrap_or( + [ + "qemu-system-x86_64", + "-drive", + "format=raw,file={bootimage}", + "-device", + "isa-debug-exit,iobase=0xf4,iosize=0x04", + "-display", + "none", + "-serial", + "file:{output_file}", + ] + .into_iter() + .map(|&s| String::from(s)) + .collect(), + ); + + let output_file = out_dir.join(format!("output-{}.txt", test_name)); + + let mut command = process::Command::new(&run_cmd[0]); + for arg in &run_cmd[1..] { + command.arg( + arg.replace("{bootimage}", &format!("{}", bootimage_bin_path.display())) + .replace("{output_file}", &format!("{}", output_file.display())), + ); + } + command.stderr(process::Stdio::null()); + let mut child = command + .spawn() + .map_err(|e| format!("Failed to launch QEMU: {:?}\n{}", command, e))?; + let timeout = Duration::from_secs(config.test_timeout); + let (exit_status, output) = match child + .wait_timeout(timeout) + .map_err(|e| format!("Failed to wait with timeout: {}", e))? + { + None => { + child + .kill() + .map_err(|e| format!("Failed to kill QEMU: {}", e))?; + child + .wait() + .map_err(|e| format!("Failed to wait for QEMU process: {}", e))?; + Err("Timed Out") + } + Some(exit_status) => { + let output = fs::read_to_string(&output_file).map_err(|e| { + format!( + "Failed to read test output file {}: {}", + output_file.display(), + e + ) + })?; + Ok((exit_status, output)) + } + }?; + + match exit_status.code() { + None => Err("No QEMU Exit Code")?, + Some(5) => {} // 2 << 1 | 1 + Some(7) => { + // 3 << 1 | 1 + let fail_index = output.rfind("bootimage:stderr\n"); + if let Some(index) = fail_index { + Err(format!("Test Failed:\n{}", &output[index..]))? + } else { + Err("Test Failed")? + } + } + Some(c) => Err(format!("Test returned with unexpected exit code {}", c))?, + } + Ok(()) +} From 6b53e04890ac217d4178afe689b1d8e08e798d18 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Mon, 1 Apr 2019 16:07:48 +0200 Subject: [PATCH 16/50] Avoid TryFrom, since it is not in stable yet --- src/config.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/config.rs b/src/config.rs index 93a4833..301e630 100644 --- a/src/config.rs +++ b/src/config.rs @@ -17,7 +17,7 @@ pub(crate) fn read_config(manifest_path: PathBuf) -> Result } pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result { - use std::{convert::TryFrom, fs::File, io::Read}; + use std::{fs::File, io::Read}; let cargo_toml: Value = { let mut content = String::new(); File::open(&manifest_path) @@ -54,10 +54,11 @@ pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result config.default_target = From::from(s), - ("test-timeout", Value::Integer(s)) => { - config.test_timeout = u64::try_from(s) - .map_err(|err| format!("test-timeout is not valid: {}", err))? - .into() + ("test-timeout", Value::Integer(timeout)) if timeout.is_negative() => { + Err(format!("test-timeout must not be negative"))? + } + ("test-timeout", Value::Integer(timeout)) => { + config.test_timeout = Some(timeout as u64); } ("run-command", Value::Array(array)) => { let mut command = Vec::new(); From bf405e3dd34f3592d4993d8a0e214e3d275b7abc Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Mon, 1 Apr 2019 16:10:48 +0200 Subject: [PATCH 17/50] We don't need u64 for the test timeout A timeout greater than 2^32 seconds (~136 years) does not make much sense, so we can use u32 instead of u64. --- src/config.rs | 6 +++--- src/subcommand/test.rs | 2 +- src/subcommand/tester.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/config.rs b/src/config.rs index 301e630..5ccf1d4 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,7 +7,7 @@ pub struct Config { pub manifest_path: PathBuf, pub default_target: Option, pub run_command: Vec, - pub test_timeout: u64, + pub test_timeout: u32, } pub(crate) fn read_config(manifest_path: PathBuf) -> Result { @@ -58,7 +58,7 @@ pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result { - config.test_timeout = Some(timeout as u64); + config.test_timeout = Some(timeout as u32); } ("run-command", Value::Array(array)) => { let mut command = Vec::new(); @@ -85,7 +85,7 @@ struct ConfigBuilder { manifest_path: Option, default_target: Option, run_command: Option>, - test_timeout: Option, + test_timeout: Option, } impl Into for ConfigBuilder { diff --git a/src/subcommand/test.rs b/src/subcommand/test.rs index dbb8845..418a28f 100644 --- a/src/subcommand/test.rs +++ b/src/subcommand/test.rs @@ -50,7 +50,7 @@ pub(crate) fn test(mut args: Args) -> Result<(), ErrorString> { let mut child = command .spawn() .map_err(|e| format!("Failed to launch QEMU: {:?}\n{}", command, e))?; - let timeout = Duration::from_secs(config.test_timeout); + let timeout = Duration::from_secs(config.test_timeout.into()); match child .wait_timeout(timeout) .map_err(|e| format!("Failed to wait with timeout: {}", e))? diff --git a/src/subcommand/tester.rs b/src/subcommand/tester.rs index 4b246d5..2f1beb4 100644 --- a/src/subcommand/tester.rs +++ b/src/subcommand/tester.rs @@ -157,7 +157,7 @@ path = "{test_path}" let mut child = command .spawn() .map_err(|e| format!("Failed to launch QEMU: {:?}\n{}", command, e))?; - let timeout = Duration::from_secs(config.test_timeout); + let timeout = Duration::from_secs(config.test_timeout.into()); let (exit_status, output) = match child .wait_timeout(timeout) .map_err(|e| format!("Failed to wait with timeout: {}", e))? From c8e7bf745df47aecd0a085e919e73aae1e059c34 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Mon, 1 Apr 2019 17:50:24 +0200 Subject: [PATCH 18/50] Add a `--run-args` argument --- src/args.rs | 10 ++++++++++ src/subcommand/runner.rs | 3 +++ 2 files changed, 13 insertions(+) diff --git a/src/args.rs b/src/args.rs index ea98206..9f512cc 100644 --- a/src/args.rs +++ b/src/args.rs @@ -220,6 +220,7 @@ where .canonicalize() .map_err(|err| format!("Failed to canonicalize executable path: {}", err))?; let mut run_command = None; + let mut run_args = None; loop { match arg_iter.next().as_ref().map(|s| s.as_str()) { @@ -230,6 +231,13 @@ where } break; } + Some("--args") => { + let old = mem::replace(&mut run_args, Some(arg_iter.collect())); + if !old.is_none() { + Err("multiple `--args` arguments")?; + } + break; + } Some("--help") | Some("-h") => { return Ok(Command::RunnerHelp); } @@ -244,6 +252,7 @@ where Ok(Command::Runner(RunnerArgs { executable, run_command, + run_args: run_args, })) } @@ -251,6 +260,7 @@ where pub struct RunnerArgs { pub executable: PathBuf, pub run_command: Option>, + pub run_args: Option>, } #[derive(Debug, Clone)] diff --git a/src/subcommand/runner.rs b/src/subcommand/runner.rs index bbb6a16..1a38c41 100644 --- a/src/subcommand/runner.rs +++ b/src/subcommand/runner.rs @@ -20,6 +20,9 @@ pub(crate) fn runner(args: RunnerArgs) -> Result<(), ErrorString> { for arg in &run_cmd[1..] { command.arg(arg.replace("{bootimage}", &format!("{}", bootimage_bin.display()))); } + if let Some(run_args) = args.run_args { + command.args(run_args); + } let output = command .output() .map_err(|e| format!("Failed to execute `{:?}`: {}", command, e))?; From e1d59cd7c6104cb9ca4d0e82f6eae54bb98986c2 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Mon, 1 Apr 2019 18:41:51 +0200 Subject: [PATCH 19/50] Add a separate `parse_tester_args` function and add add a `--target` argument --- src/args.rs | 66 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/src/args.rs b/src/args.rs index 9f512cc..c7e462e 100644 --- a/src/args.rs +++ b/src/args.rs @@ -30,11 +30,7 @@ pub(crate) fn parse_args() -> Result { cmd => cmd, }), Some("runner") => parse_runner_args(args), - Some("tester") => parse_runner_args(args).map(|cmd| match cmd { - Command::Runner(args) => Command::Tester(TesterArgs::from(args)), - Command::RunnerHelp => Command::TesterHelp, - other => other, - }), + Some("tester") => parse_tester_args(args), Some("--help") | Some("-h") => Ok(Command::Help), Some("--version") => Ok(Command::Version), _ => Ok(Command::NoSubcommand), @@ -252,7 +248,7 @@ where Ok(Command::Runner(RunnerArgs { executable, run_command, - run_args: run_args, + run_args, })) } @@ -263,17 +259,59 @@ pub struct RunnerArgs { pub run_args: Option>, } +fn parse_tester_args(args: A) -> Result +where + A: Iterator, +{ + let mut arg_iter = args.into_iter().fuse(); + let test_path = PathBuf::from( + arg_iter + .next() + .ok_or("excepted path to test source file as first argument")?, + ) + .canonicalize() + .map_err(|err| format!("Failed to canonicalize test path: {}", err))?; + let mut run_command = None; + let mut target = None; + + loop { + match arg_iter.next().as_ref().map(|s| s.as_str()) { + Some("--command") => { + let old = mem::replace(&mut run_command, Some(arg_iter.collect())); + if !old.is_none() { + Err("multiple `--command` arguments")?; + } + break; + } + Some("--target") => { + let old = mem::replace(&mut target, arg_iter.next()); + if !old.is_none() { + Err("multiple `--target` arguments")?; + } + break; + } + Some("--help") | Some("-h") => { + return Ok(Command::TesterHelp); + } + Some("--version") => { + return Ok(Command::Version); + } + None => break, + Some(arg) => Err(format!("unexpected argument `{}`", arg))?, + } + } + + Ok(Command::Tester(TesterArgs { + test_path, + run_command, + target, + })) +} + #[derive(Debug, Clone)] pub struct TesterArgs { pub test_path: PathBuf, pub run_command: Option>, + pub target: Option, } -impl From for TesterArgs { - fn from(args: RunnerArgs) -> Self { - Self { - test_path: args.executable, - run_command: args.run_command, - } - } -} From 9ccaf9f15526df09e6da9569e37eda953a4b5348 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Mon, 1 Apr 2019 18:42:46 +0200 Subject: [PATCH 20/50] Use correct target for tester and respect default targets --- src/subcommand/tester.rs | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/subcommand/tester.rs b/src/subcommand/tester.rs index 2f1beb4..49b9200 100644 --- a/src/subcommand/tester.rs +++ b/src/subcommand/tester.rs @@ -1,4 +1,4 @@ -use crate::{args::TesterArgs, builder::Builder, config, ErrorString}; +use crate::{cargo_config, args::TesterArgs, builder::Builder, config, ErrorString}; use std::{ fs, io::{self, Write}, @@ -72,14 +72,8 @@ pub(crate) fn tester(args: TesterArgs) -> Result<(), ErrorString> { let kernel_target_dir = Path::new("target") .canonicalize() .expect("failed to canonicalize target dir"); // TODO - let kernel_target_json = Path::new("x86_64-blog_os.json") - .canonicalize() - .expect("failed to canonicalize target.json"); // TODO - let kernel_target_json_triple = kernel_target_json - .file_stem() - .expect("kernel target json has no valid file stem"); - let out_dir = kernel_target_dir.join("integration-tests").join(&test_name); + let out_dir = kernel_target_dir.join("bootimage").join("integration-tests").join(&test_name); fs::create_dir_all(&out_dir).expect("failed to create out dir"); let manifest_path = out_dir.join("Cargo.toml"); @@ -110,7 +104,9 @@ path = "{test_path}" cmd.arg("--manifest-path").arg(&manifest_path); cmd.arg("--target-dir").arg(&kernel_target_dir); cmd.env("SYSROOT_DIR", &kernel_target_dir.join("sysroot")); // for cargo-xbuild - cmd.arg("--target").arg(&kernel_target_json); // TODO remove when default targets are canonicalized properly + if let Some(target) = args.target.as_ref().or(config.default_target.as_ref()) { + cmd.arg("--target").arg(target); + } let output = cmd.output().expect("failed to run cargo xbuild"); if !output.status.success() { io::stderr() @@ -119,10 +115,25 @@ path = "{test_path}" process::exit(1); } - let executable = kernel_target_dir - .join(&kernel_target_json_triple) - .join("debug") - .join(&test_name); + let kernel_target_triple = { + match args.target.or(config.default_target) { + None => cargo_config::default_target_triple(kernel_root_path, true)?, + Some(ref target) if target.ends_with(".json") => { + Some(Path::new(target).file_stem().expect("kernel target json has no valid file stem").to_str().expect("invalid unicode").to_owned()) + } + Some(triple) => Some(triple), + } + }; + + let executable = { + let mut path = kernel_target_dir.clone(); + if let Some(triple) = kernel_target_triple { + path.push(triple); + } + path.push("debug"); + path.push(&test_name); + path + }; let bootimage_bin_path = out_dir.join(format!("bootimage-{}.bin", test_name)); builder.create_bootimage(&executable, &bootimage_bin_path, true)?; From 5aad6cd1c17c53b83b2dc5aa76a67eec1daf03c2 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 13:20:10 +0200 Subject: [PATCH 21/50] Run build command with --message-format=json to find out binary paths This frees us from walking the `.cargo/config` files manually since cargo just tells us where it placed the executables. We run the command a second time to provide the user with human readable output in case the compilation fails. This commit also improves a few other things: - Don't change current_dir when building bootloader so that rustup overrides are respected. Instead read the bootloader target manually from the bootloader's `.cargo/config` file. - Place bootimage.bin for running inside target/bootimage instead of a temp dir - Print the replaced command on `bootimage runner` (no {bootimage} placeholders) - Remove unneeded dependencies --- Cargo.lock | 109 +-------------------------------- Cargo.toml | 4 +- src/args.rs | 1 - src/builder.rs | 128 +++++++++++++++++++++++++++++++-------- src/cargo_config.rs | 61 ------------------- src/lib.rs | 1 - src/subcommand/build.rs | 53 ++++++---------- src/subcommand/run.rs | 6 +- src/subcommand/runner.rs | 46 +++++++++++--- src/subcommand/test.rs | 32 ++++++---- src/subcommand/tester.rs | 86 +++++++++++++++----------- 11 files changed, 235 insertions(+), 292 deletions(-) delete mode 100644 src/cargo_config.rs diff --git a/Cargo.lock b/Cargo.lock index d94e047..56481c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,22 +12,15 @@ dependencies = [ name = "bootimage" version = "0.6.6" dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)", "llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "locate-cargo-manifest 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "byteorder" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "cargo_metadata" version = "0.7.4" @@ -91,11 +84,6 @@ name = "error-chain" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "itoa" version = "0.4.2" @@ -163,31 +151,6 @@ dependencies = [ "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rayon" version = "1.0.3" @@ -209,22 +172,6 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "scopeguard" version = "0.3.3" @@ -279,15 +226,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tempdir" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "toml" version = "0.5.0" @@ -309,41 +247,8 @@ dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "winapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "xmas-elf" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zero" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [metadata] "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" -"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" "checksum cargo_metadata 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "178d62b240c34223f265a4c1e275e37d62da163d421fc8d7f7e3ee340f803c57" "checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" @@ -352,7 +257,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606" "checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" @@ -364,13 +268,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c65b1ea15bb859d922cade2d1765b4b88beac339cbfad545ef2d2ef8c8215ee6" "checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" @@ -378,12 +277,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c" "checksum serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c6908c7b925cd6c590358a4034de93dbddb20c45e1d021931459fd419bf0e2" "checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" -"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c5890a989fa47ecdc7bcb4c63a77a82c18f306714104b1decfd722db17b39e" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" -"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/Cargo.toml b/Cargo.toml index 28bf2fc..efc90fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,14 +8,12 @@ repository = "https://github.com/rust-osdev/bootimage" edition = "2018" [dependencies] -byteorder = "1.3.1" rayon = "1.0" toml = "0.5.0" wait-timeout = "0.2" -xmas-elf = "0.6.2" llvm-tools = "0.1.1" locate-cargo-manifest = "0.1.0" -tempdir = "0.3.7" +json = "0.11.13" [dependencies.cargo_metadata] version = "0.7.4" diff --git a/src/args.rs b/src/args.rs index c7e462e..ac33bc9 100644 --- a/src/args.rs +++ b/src/args.rs @@ -314,4 +314,3 @@ pub struct TesterArgs { pub run_command: Option>, pub target: Option, } - diff --git a/src/builder.rs b/src/builder.rs index 546d3af..fe19b21 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,5 +1,5 @@ use std::{ - fmt, io, + fmt, fs, io, path::{Path, PathBuf}, process::{self, Command}, }; @@ -45,13 +45,17 @@ impl Builder { )) } - pub fn build_kernel(&self, args: &[String], quiet: bool) -> Result<(), BuildKernelError> { + pub fn build_kernel( + &self, + args: &[String], + quiet: bool, + ) -> Result, BuildKernelError> { if !quiet { println!("Building kernel"); } let cargo = std::env::var("CARGO").unwrap_or("cargo".to_owned()); - let mut cmd = process::Command::new(cargo); + let mut cmd = process::Command::new(&cargo); cmd.arg("xbuild"); cmd.args(args); if !quiet { @@ -61,7 +65,7 @@ impl Builder { let output = cmd.output().map_err(|err| BuildKernelError::Io { message: "failed to execute kernel build", error: err, - })?;; + })?; if !output.status.success() { let mut help_command = process::Command::new("cargo"); help_command.arg("xbuild").arg("--help"); @@ -77,7 +81,29 @@ impl Builder { }); } - Ok(()) + // Retrieve binary paths + let mut cmd = process::Command::new(cargo); + cmd.arg("xbuild"); + cmd.args(args); + cmd.arg("--message-format").arg("json"); + let output = cmd.output().map_err(|err| BuildKernelError::Io { + message: "failed to execute kernel build with json output", + error: err, + })?; + if !output.status.success() { + return Err(BuildKernelError::XbuildFailed { + stderr: output.stderr, + }); + } + let mut executables = Vec::new(); + for line in String::from_utf8(output.stdout).unwrap().lines() { + let mut artifact = json::parse(line).unwrap(); + if let Some(executable) = artifact["executable"].take_string() { + executables.push(PathBuf::from(executable)); + } + } + + Ok(executables) } pub fn create_bootimage( @@ -115,6 +141,31 @@ impl Builder { "bootloader manifest has no target directory".into(), ), )?; + let bootloader_target = { + let cargo_config_content = match fs::read_to_string( + bootloader_root.join(".cargo").join("config"), + ) { + Err(ref err) if err.kind() == io::ErrorKind::NotFound => { + return Err(CreateBootimageError::BootloaderInvalid("No `.cargo/config` file found in bootloader crate\n\n\ + (If you're using the official bootloader crate, you need at least version 0.5.0.)".into())); + } + Err(err) => { + return Err(CreateBootimageError::Io { + message: "Failed to read `cargo/config` file of bootloader crate", + error: err, + }); + } + Ok(content) => content, + }; + let cargo_config: toml::Value = cargo_config_content.parse().map_err(|err| { + CreateBootimageError::BootloaderInvalid(format!( + "The `.cargo/config` file of the bootloader crate is not valid TOML: {}", + err + )) + })?; + let target = cargo_config.get("build").and_then(|v| v.get("target")).and_then(|v| v.as_str()).ok_or(CreateBootimageError::BootloaderInvalid("The `.cargo/config` file of the bootloader crate contains no build.target key or it is not valid".into()))?; + bootloader_root.join(target) + }; let bootloader_features = { let resolve = metadata.resolve.as_ref().ok_or( @@ -131,12 +182,6 @@ impl Builder { })?; bootloader_resolve.features.clone() }; - let bootloader_target_triple = - crate::cargo_config::default_target_triple(&bootloader_root, false) - .map_err(CreateBootimageError::BootloaderInvalid)? - .ok_or(CreateBootimageError::BootloaderInvalid(format!( - "bootloader must have a default target" - )))?; // build bootloader if !quiet { @@ -144,17 +189,23 @@ impl Builder { } let cargo = std::env::var("CARGO").unwrap_or("cargo".to_owned()); - let mut cmd = process::Command::new(cargo); - cmd.arg("xbuild"); - cmd.arg("--manifest-path"); - cmd.arg(&bootloader_pkg.manifest_path); - cmd.arg("--target-dir").arg(&target_dir); - cmd.arg("--features") - .arg(bootloader_features.as_slice().join(" ")); - cmd.arg("--release"); - cmd.current_dir(bootloader_root); - cmd.env("KERNEL", kernel_bin_path); - cmd.env_remove("RUSTFLAGS"); + let build_command = || { + let mut cmd = process::Command::new(&cargo); + cmd.arg("xbuild"); + cmd.arg("--manifest-path"); + cmd.arg(&bootloader_pkg.manifest_path); + cmd.arg("--target-dir").arg(&target_dir); + cmd.arg("--features") + .arg(bootloader_features.as_slice().join(" ")); + cmd.arg("--target").arg(&bootloader_target); + cmd.arg("--release"); + cmd.env("KERNEL", kernel_bin_path); + cmd.env_remove("RUSTFLAGS"); + cmd.env("SYSROOT_DIR", target_dir.join("sysroot")); // for cargo-xbuild + cmd + }; + + let mut cmd = build_command(); if !quiet { cmd.stdout(process::Stdio::inherit()); cmd.stderr(process::Stdio::inherit()); @@ -169,10 +220,35 @@ impl Builder { }); } - let bootloader_elf_path = target_dir - .join(&bootloader_target_triple) - .join("release") - .join(&bootloader_name); + // Retrieve binary path + let mut cmd = build_command(); + cmd.arg("--message-format").arg("json"); + let output = cmd.output().map_err(|err| CreateBootimageError::Io { + message: "failed to execute bootloader build command with json output", + error: err, + })?; + if !output.status.success() { + return Err(CreateBootimageError::BootloaderBuildFailed { + stderr: output.stderr, + }); + } + let mut bootloader_elf_path = None; + for line in String::from_utf8(output.stdout).unwrap().lines() { + let mut artifact = json::parse(line).unwrap(); + if let Some(executable) = artifact["executable"].take_string() { + if bootloader_elf_path + .replace(PathBuf::from(executable)) + .is_some() + { + return Err(CreateBootimageError::BootloaderInvalid( + "bootloader has multiple executables".into(), + )); + } + } + } + let bootloader_elf_path = bootloader_elf_path.ok_or( + CreateBootimageError::BootloaderInvalid("bootloader has no executable".into()), + )?; let llvm_tools = llvm_tools::LlvmTools::new()?; let objcopy = llvm_tools diff --git a/src/cargo_config.rs b/src/cargo_config.rs deleted file mode 100644 index 4e57ad7..0000000 --- a/src/cargo_config.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::{ - fs, - path::{Path, PathBuf}, -}; - -pub fn default_target_triple(crate_root: &Path, walk_up: bool) -> Result, String> { - let default_triple = default_target(crate_root, walk_up)?; - default_triple - .map(|(target, crate_root)| { - if target.ends_with(".json") { - crate_root - .join(target) - .file_stem() - .ok_or(String::from( - "The target path specfied in `build.target` has no file stem", - ))? - .to_os_string() - .into_string() - .map_err(|err| format!("Default target triple not valid UTF-8: {:?}", err)) - } else { - Ok(target) - } - }) - .transpose() -} - -fn default_target(crate_root: &Path, walk_up: bool) -> Result, String> { - let mut parent_dir = crate_root; - - loop { - let config_path = parent_dir.join(".cargo/config"); - if config_path.exists() { - let config_content = fs::read_to_string(config_path).map_err(|err| { - format!("Failed to read `.cargo/config` file of crate: {:?}", err) - })?; - let config = config_content.parse::().map_err(|err| { - format!( - "Failed to parse `.cargo/config` of crate as toml: {:?}", - err - ) - })?; - let target = config - .get("build") - .and_then(|v| v.get("target")) - .and_then(|v| v.as_str()) - .map(String::from); - if let Some(target) = target { - return Ok(Some((target, parent_dir.to_owned()))); - } - } - if walk_up { - parent_dir = match parent_dir.parent() { - Some(parent) => parent, - None => break, - } - } else { - break; - } - } - Ok(None) -} diff --git a/src/lib.rs b/src/lib.rs index 8ec0ef8..054087f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,6 @@ use std::fmt; pub mod args; pub mod builder; -pub mod cargo_config; pub mod config; pub mod help; diff --git a/src/subcommand/build.rs b/src/subcommand/build.rs index 6db5f3c..4b496b8 100644 --- a/src/subcommand/build.rs +++ b/src/subcommand/build.rs @@ -1,8 +1,5 @@ -use crate::{args::Args, builder::Builder, cargo_config, config, ErrorString}; -use std::{ - path::{Path, PathBuf}, - process, -}; +use crate::{args::Args, builder::Builder, config, ErrorString}; +use std::{path::PathBuf, process}; pub(crate) fn build(mut args: Args) -> Result<(), ErrorString> { let builder = Builder::new(args.manifest_path().clone())?; @@ -16,40 +13,30 @@ pub(crate) fn build_impl( builder: &Builder, args: &Args, quiet: bool, -) -> Result { +) -> Result, ErrorString> { run_cargo_fetch(&args); - builder.build_kernel(&args.cargo_args, quiet)?; + let executables = builder.build_kernel(&args.cargo_args, quiet)?; + if executables.len() == 0 { + Err("no executables built")?; + } - let out_dir = out_dir(&args, &builder)?; - let kernel_package = builder - .kernel_package() - .map_err(|key| format!("Kernel package not found in cargo metadata (`{}`)", key))?; - let kernel_bin_name = args.bin_name().as_ref().unwrap_or(&kernel_package.name); - let kernel_path = out_dir.join(kernel_bin_name); + let mut bootimages = Vec::new(); - let bootimage_path = out_dir.join(format!("bootimage-{}.bin", kernel_bin_name)); - builder.create_bootimage(&kernel_path, &bootimage_path, quiet)?; - Ok(bootimage_path) -} + for executable in executables { + let out_dir = executable.parent().ok_or("executable has no parent path")?; + let file_stem = executable + .file_stem() + .ok_or("executable has no file stem")? + .to_str() + .ok_or("executable file stem not valid utf8")?; -fn out_dir(args: &Args, builder: &Builder) -> Result { - let target_dir = PathBuf::from(&builder.kernel_metadata().target_directory); - let mut out_dir = target_dir; - if let &Some(ref target) = args.target() { - out_dir.push(Path::new(target).file_stem().unwrap().to_str().unwrap()); - } else { - let default_triple = cargo_config::default_target_triple(builder.kernel_root(), true)?; - if let Some(triple) = default_triple { - out_dir.push(triple); - } + let bootimage_path = out_dir.join(format!("bootimage-{}.bin", file_stem)); + builder.create_bootimage(&executable, &bootimage_path, quiet)?; + bootimages.push(bootimage_path); } - if args.release() { - out_dir.push("release"); - } else { - out_dir.push("debug"); - } - Ok(out_dir) + + Ok(bootimages) } fn run_cargo_fetch(args: &Args) { diff --git a/src/subcommand/run.rs b/src/subcommand/run.rs index 92eddd5..d62e8f3 100644 --- a/src/subcommand/run.rs +++ b/src/subcommand/run.rs @@ -8,7 +8,11 @@ pub(crate) fn run(mut args: Args) -> Result<(), ErrorString> { let config = config::read_config(builder.kernel_manifest_path().to_owned())?; args.apply_default_target(&config, builder.kernel_root()); - let bootimage_path = build::build_impl(&builder, &mut args, false)?; + let bootimages = build::build_impl(&builder, &mut args, false)?; + let bootimage_path = bootimages.first().ok_or("no bootimages created")?; + if bootimages.len() > 1 { + Err("more than one bootimage created")?; + } let command = &config.run_command[0]; let mut command = process::Command::new(command); diff --git a/src/subcommand/runner.rs b/src/subcommand/runner.rs index 1a38c41..668a37c 100644 --- a/src/subcommand/runner.rs +++ b/src/subcommand/runner.rs @@ -1,11 +1,41 @@ use crate::{args::RunnerArgs, builder::Builder, ErrorString}; -use std::process; +use std::{fs, process}; pub(crate) fn runner(args: RunnerArgs) -> Result<(), ErrorString> { - let out_dir = tempdir::TempDir::new("bootimage-runner")?; - let bootimage_bin = out_dir.path().join("bootimage.bin"); - let builder = Builder::new(None)?; + + let bootimage_bin = { + let kernel_target_dir = &builder.kernel_metadata().target_directory; + let bootimage_target_dir = kernel_target_dir.join("bootimage").join("runner"); + + let parent = args + .executable + .parent() + .ok_or("kernel executable has no parent")?; + let file_stem = args + .executable + .file_stem() + .ok_or("kernel executable has no file stem")? + .to_str() + .ok_or("kernel executable file stem is not valid UTF-8")?; + let sub_path = parent.strip_prefix(kernel_target_dir).map_err(|err| { + format!( + "kernel executable does not live in kernel target directory: {}", + err + ) + })?; + + let out_dir = bootimage_target_dir.join(sub_path); + fs::create_dir_all(&out_dir).map_err(|err| { + format!( + "failed to create output directory {}: {}", + out_dir.display(), + err + ) + })?; + out_dir.join(format!("bootimage-{}.bin", file_stem)) + }; + builder.create_bootimage(&args.executable, &bootimage_bin, false)?; let run_cmd = args.run_command.unwrap_or(vec![ @@ -14,8 +44,6 @@ pub(crate) fn runner(args: RunnerArgs) -> Result<(), ErrorString> { "format=raw,file={bootimage}".into(), ]); - println!("Running {:?}", run_cmd); - let mut command = process::Command::new(&run_cmd[0]); for arg in &run_cmd[1..] { command.arg(arg.replace("{bootimage}", &format!("{}", bootimage_bin.display()))); @@ -23,6 +51,9 @@ pub(crate) fn runner(args: RunnerArgs) -> Result<(), ErrorString> { if let Some(run_args) = args.run_args { command.args(run_args); } + + println!("Running: {:?}", command); + let output = command .output() .map_err(|e| format!("Failed to execute `{:?}`: {}", command, e))?; @@ -38,8 +69,5 @@ pub(crate) fn runner(args: RunnerArgs) -> Result<(), ErrorString> { }); } - drop(bootimage_bin); - out_dir.close()?; - Ok(()) } diff --git a/src/subcommand/test.rs b/src/subcommand/test.rs index 418a28f..b93f1e0 100644 --- a/src/subcommand/test.rs +++ b/src/subcommand/test.rs @@ -1,6 +1,6 @@ use crate::{args::Args, builder::Builder, config, subcommand::build, ErrorString}; use rayon::prelude::*; -use std::{fs, io, io::Write, path::PathBuf, process, time::Duration}; +use std::{fs, io, io::Write, process, time::Duration}; use wait_timeout::ChildExt; pub(crate) fn test(mut args: Args) -> Result<(), ErrorString> { @@ -13,21 +13,29 @@ pub(crate) fn test(mut args: Args) -> Result<(), ErrorString> { let kernel_package = builder .kernel_package() .map_err(|key| format!("Kernel package not found it cargo metadata (`{}`)", key))?; - let test_targets = kernel_package + let test_target_iter = kernel_package .targets .iter() - .filter(|t| t.kind == ["bin"] && t.name.starts_with("test-")) - .map(|target| { - println!("BUILD: {}", target.name); + .filter(|t| t.kind == ["bin"] && t.name.starts_with("test-")); - let mut target_args = test_args.clone(); - target_args.set_bin_name(target.name.clone()); - let test_bin_path = build::build_impl(&builder, &mut target_args, true) - .expect(&format!("Failed to build test: {}", target.name)); + let mut test_targets = Vec::new(); + for target in test_target_iter { + println!("BUILD: {}", target.name); - (target, test_bin_path) - }) - .collect::>(); + let mut target_args = test_args.clone(); + target_args.set_bin_name(target.name.clone()); + let executables = build::build_impl(&builder, &mut target_args, true) + .expect(&format!("Failed to build test: {}", target.name)); + let test_bin_path = executables + .first() + .ok_or("no test executable built")? + .to_owned(); + if executables.len() > 1 { + Err("more than one test executables built")?; + } + + test_targets.push((target, test_bin_path)); + } let tests = test_targets .par_iter() diff --git a/src/subcommand/tester.rs b/src/subcommand/tester.rs index 49b9200..a48e6cc 100644 --- a/src/subcommand/tester.rs +++ b/src/subcommand/tester.rs @@ -1,8 +1,7 @@ -use crate::{cargo_config, args::TesterArgs, builder::Builder, config, ErrorString}; +use crate::{args::TesterArgs, builder::Builder, config, ErrorString}; use std::{ fs, - io::{self, Write}, - path::Path, + path::{Path, PathBuf}, process, process::Command, time::Duration, @@ -69,11 +68,10 @@ pub(crate) fn tester(args: TesterArgs) -> Result<(), ErrorString> { table.insert("dependencies".to_owned(), toml::Value::Table(dependencies)); toml::Value::Table(table) }; - let kernel_target_dir = Path::new("target") - .canonicalize() - .expect("failed to canonicalize target dir"); // TODO - let out_dir = kernel_target_dir.join("bootimage").join("integration-tests").join(&test_name); + let kernel_target_dir = &builder.kernel_metadata().target_directory; + let integration_test_dir = kernel_target_dir.join("bootimage").join("tester"); + let out_dir = integration_test_dir.join(&test_name); fs::create_dir_all(&out_dir).expect("failed to create out dir"); let manifest_path = out_dir.join("Cargo.toml"); @@ -99,43 +97,57 @@ path = "{test_path}" fs::write(&manifest_path, manifest_content)?; let cargo = std::env::var("CARGO").unwrap_or("cargo".to_owned()); - let mut cmd = Command::new(cargo); - cmd.arg("xbuild"); - cmd.arg("--manifest-path").arg(&manifest_path); - cmd.arg("--target-dir").arg(&kernel_target_dir); - cmd.env("SYSROOT_DIR", &kernel_target_dir.join("sysroot")); // for cargo-xbuild - if let Some(target) = args.target.as_ref().or(config.default_target.as_ref()) { - cmd.arg("--target").arg(target); - } - let output = cmd.output().expect("failed to run cargo xbuild"); + let build_command = || { + let mut cmd = Command::new(&cargo); + cmd.arg("xbuild"); + cmd.arg("--manifest-path").arg(&manifest_path); + cmd.arg("--target-dir") + .arg(&integration_test_dir.join("target")); + cmd.env("SYSROOT_DIR", &integration_test_dir.join("sysroot")); // for cargo-xbuild + + if let Some(target) = args.target.as_ref().or(config.default_target.as_ref()) { + cmd.arg("--target").arg(target); + } + cmd + }; + + let mut cmd = build_command(); + let output = cmd + .output() + .map_err(|err| format!("failed to run cargo xbuild: {}", err))?; if !output.status.success() { - io::stderr() - .write_all(&output.stderr) - .expect("failed to write to stderr"); - process::exit(1); + Err(format!( + "Test build failed:\n{}", + String::from_utf8_lossy(&output.stderr) + ))?; } - let kernel_target_triple = { - match args.target.or(config.default_target) { - None => cargo_config::default_target_triple(kernel_root_path, true)?, - Some(ref target) if target.ends_with(".json") => { - Some(Path::new(target).file_stem().expect("kernel target json has no valid file stem").to_str().expect("invalid unicode").to_owned()) + let mut cmd_json = build_command(); + cmd_json.arg("--message-format").arg("json"); + let output = cmd_json.output().map_err(|err| { + format!( + "failed to execute bootloader build command with json output: {}", + err + ) + })?; + if !output.status.success() { + Err(format!( + "Test build (with json output) failed:\n{}", + String::from_utf8_lossy(&output.stderr) + ))?; + } + let mut test_executable = None; + for line in String::from_utf8(output.stdout).unwrap().lines() { + let mut artifact = json::parse(line).unwrap(); + if let Some(executable) = artifact["executable"].take_string() { + if test_executable.replace(PathBuf::from(executable)).is_some() { + Err("integration test has multiple executables")?; } - Some(triple) => Some(triple), } - }; + } - let executable = { - let mut path = kernel_target_dir.clone(); - if let Some(triple) = kernel_target_triple { - path.push(triple); - } - path.push("debug"); - path.push(&test_name); - path - }; + let executable = test_executable.ok_or("no test executable")?; let bootimage_bin_path = out_dir.join(format!("bootimage-{}.bin", test_name)); - builder.create_bootimage(&executable, &bootimage_bin_path, true)?; let run_cmd = args.run_command.clone().unwrap_or( From 675c8acc015129b4f000304fd9c1db6137c4d537 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 14:27:23 +0200 Subject: [PATCH 22/50] Pass through exit code of run commands --- src/bin/cargo-bootimage.rs | 7 +------ src/lib.rs | 38 ++++++++++++++++++++++++++------------ src/main.rs | 7 +------ src/subcommand/run.rs | 6 +++--- src/subcommand/runner.rs | 15 ++------------- 5 files changed, 33 insertions(+), 40 deletions(-) diff --git a/src/bin/cargo-bootimage.rs b/src/bin/cargo-bootimage.rs index d6e09a5..5349675 100644 --- a/src/bin/cargo-bootimage.rs +++ b/src/bin/cargo-bootimage.rs @@ -1,8 +1,3 @@ -use std::process; - pub fn main() { - if let Err(err) = bootimage::run() { - eprintln!("Error: {}", err.message); - process::exit(err.exit_code); - } + bootimage::lib_main(); } diff --git a/src/lib.rs b/src/lib.rs index 054087f..c166502 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ use args::{Args, RunnerArgs, TesterArgs}; -use std::fmt; +use std::{fmt, process}; pub mod args; pub mod builder; @@ -25,20 +25,34 @@ enum Command { Version, } -pub fn run() -> Result<(), ErrorString> { +pub fn lib_main() { + match run() { + Err(err) => { + eprintln!("Error: {}", err.message); + process::exit(err.exit_code); + } + Ok(Some(exit_code)) => { + process::exit(exit_code); + } + Ok(None) => {} + } +} + +pub fn run() -> Result, ErrorString> { let command = args::parse_args()?; + let none = |()| None; match command { - Command::Build(args) => subcommand::build::build(args), - Command::Run(args) => subcommand::run::run(args), - Command::Test(args) => subcommand::test::test(args), - Command::Runner(args) => subcommand::runner::runner(args), - Command::Tester(args) => subcommand::tester::tester(args), + Command::Build(args) => subcommand::build::build(args).map(none), + Command::Run(args) => subcommand::run::run(args).map(Some), + Command::Test(args) => subcommand::test::test(args).map(none), + Command::Runner(args) => subcommand::runner::runner(args).map(Some), + Command::Tester(args) => subcommand::tester::tester(args).map(none), Command::NoSubcommand => help::no_subcommand(), - Command::Help => Ok(help::help()), - Command::BuildHelp => Ok(help::build_help()), - Command::RunHelp => Ok(help::run_help()), - Command::TestHelp => Ok(help::test_help()), - Command::Version => Ok(println!("bootimage {}", env!("CARGO_PKG_VERSION"))), + Command::Help => Ok(help::help()).map(none), + Command::BuildHelp => Ok(help::build_help()).map(none), + Command::RunHelp => Ok(help::run_help()).map(none), + Command::TestHelp => Ok(help::test_help()).map(none), + Command::Version => Ok(println!("bootimage {}", env!("CARGO_PKG_VERSION"))).map(none), Command::RunnerHelp | Command::TesterHelp | Command::CargoBootimageHelp => unimplemented!(), } } diff --git a/src/main.rs b/src/main.rs index d6e09a5..5349675 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,3 @@ -use std::process; - pub fn main() { - if let Err(err) = bootimage::run() { - eprintln!("Error: {}", err.message); - process::exit(err.exit_code); - } + bootimage::lib_main(); } diff --git a/src/subcommand/run.rs b/src/subcommand/run.rs index d62e8f3..287b195 100644 --- a/src/subcommand/run.rs +++ b/src/subcommand/run.rs @@ -1,7 +1,7 @@ use crate::{args::Args, builder::Builder, config, ErrorString}; use std::process; -pub(crate) fn run(mut args: Args) -> Result<(), ErrorString> { +pub(crate) fn run(mut args: Args) -> Result { use crate::subcommand::build; let builder = Builder::new(args.manifest_path().clone())?; @@ -27,11 +27,11 @@ pub(crate) fn run(mut args: Args) -> Result<(), ErrorString> { ); } command.args(&args.run_args); - command.status().map_err(|err| { + let exit_status = command.status().map_err(|err| { ErrorString::from(format!( "Failed to execute run command `{:?}`: {}", command, err )) })?; - Ok(()) + Ok(exit_status.code().unwrap_or(1)) } diff --git a/src/subcommand/runner.rs b/src/subcommand/runner.rs index 668a37c..4bbbe74 100644 --- a/src/subcommand/runner.rs +++ b/src/subcommand/runner.rs @@ -1,7 +1,7 @@ use crate::{args::RunnerArgs, builder::Builder, ErrorString}; use std::{fs, process}; -pub(crate) fn runner(args: RunnerArgs) -> Result<(), ErrorString> { +pub(crate) fn runner(args: RunnerArgs) -> Result { let builder = Builder::new(None)?; let bootimage_bin = { @@ -58,16 +58,5 @@ pub(crate) fn runner(args: RunnerArgs) -> Result<(), ErrorString> { .output() .map_err(|e| format!("Failed to execute `{:?}`: {}", command, e))?; - if !output.status.success() { - return Err(ErrorString { - exit_code: output.status.code().unwrap_or(1), - message: Box::new(format!( - "Command `{:?}` failed:\n{}", - command, - String::from_utf8_lossy(&output.stderr) - )), - }); - } - - Ok(()) + Ok(output.status.code().unwrap_or(1)) } From 2e6c48f1974614f33ba3a76c4f6d8c9fb7622349 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 15:00:02 +0200 Subject: [PATCH 23/50] Print newlines before errors --- src/builder.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index fe19b21..7ae70af 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -329,17 +329,17 @@ impl fmt::Display for BuildKernelError { writeln!(f, "Could not find kernel package in cargo metadata, required for retrieving kernel crate name") } BuildKernelError::Io {message, error} => { - writeln!(f, "I/O error: {}: {}", message, error) + writeln!(f, "I/O error: {}:\n{}", message, error) } BuildKernelError::XbuildNotFound => { writeln!(f, "Failed to run `cargo xbuild`. Perhaps it is not installed?\n\ Run `cargo install cargo-xbuild` to install it.") } BuildKernelError::XbuildFailed{stderr} => { - writeln!(f, "Kernel build failed: {}", String::from_utf8_lossy(stderr)) + writeln!(f, "Kernel build failed:\n{}", String::from_utf8_lossy(stderr)) } BuildKernelError::CargoConfigInvalid{path,error} => { - writeln!(f, "Failed to read cargo config at {}: {}", path.display(), error) + writeln!(f, "Failed to read cargo config at {}:\n{}", path.display(), error) }, } } From 3739e4e90671d80dcf5e4f4e14af54729b31726c Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Mon, 1 Apr 2019 18:43:27 +0200 Subject: [PATCH 24/50] Update test suite --- azure-pipelines.yml | 303 ++++++++++------ example-kernels/{testing => }/.gitignore | 0 .../{default-target-bootimage => }/Cargo.lock | 90 ++++- example-kernels/Cargo.toml | 10 + example-kernels/basic/Cargo.lock | 297 ---------------- example-kernels/basic/src/main.rs | 2 +- .../default-target-bootimage/Cargo.toml | 4 +- .../default-target-bootimage/src/main.rs | 2 +- .../x86_64-default-target.json | 15 - .../default-target-cargo/.cargo/config | 2 +- .../default-target-cargo/Cargo.lock | 328 ------------------ .../default-target-cargo/Cargo.toml | 2 - .../default-target-cargo/src/main.rs | 2 +- .../x86_64-default-target.json | 15 - example-kernels/runner/.cargo/config | 5 + example-kernels/runner/.gitignore | 2 + example-kernels/runner/Cargo.toml | 9 + example-kernels/runner/src/main.rs | 28 ++ example-kernels/tester/.gitignore | 2 + example-kernels/tester/Cargo.toml | 9 + example-kernels/tester/build.rs | 27 ++ example-kernels/tester/src/lib.rs | 21 ++ .../tester/tests/integration_tests.rs | 14 + .../integration_tests/test-basic-boot.rs | 27 ++ .../tests/integration_tests/test-panic.rs | 21 ++ .../testing-qemu-exit-code/.gitignore | 2 + .../Cargo.toml | 6 +- .../src/bin/test-basic-boot.rs | 27 ++ .../src/bin/test-panic.rs | 21 ++ .../testing-qemu-exit-code/src/lib.rs | 21 ++ .../testing-serial-result/.gitignore | 2 + .../testing-serial-result/Cargo.toml | 18 + .../src/bin/test-basic-boot-serial.rs} | 2 +- .../src/bin/test-panic-serial.rs} | 2 +- .../src/lib.rs | 0 .../src/main.rs | 0 example-kernels/testing/Cargo.lock | 328 ------------------ example-kernels/testing/x86_64-testing.json | 15 - ... => x86_64-bootimage-example-kernels.json} | 0 39 files changed, 542 insertions(+), 1139 deletions(-) rename example-kernels/{testing => }/.gitignore (100%) rename example-kernels/{default-target-bootimage => }/Cargo.lock (82%) create mode 100644 example-kernels/Cargo.toml delete mode 100644 example-kernels/basic/Cargo.lock delete mode 100644 example-kernels/default-target-bootimage/x86_64-default-target.json delete mode 100644 example-kernels/default-target-cargo/Cargo.lock delete mode 100644 example-kernels/default-target-cargo/x86_64-default-target.json create mode 100644 example-kernels/runner/.cargo/config create mode 100644 example-kernels/runner/.gitignore create mode 100644 example-kernels/runner/Cargo.toml create mode 100644 example-kernels/runner/src/main.rs create mode 100644 example-kernels/tester/.gitignore create mode 100644 example-kernels/tester/Cargo.toml create mode 100644 example-kernels/tester/build.rs create mode 100644 example-kernels/tester/src/lib.rs create mode 100644 example-kernels/tester/tests/integration_tests.rs create mode 100644 example-kernels/tester/tests/integration_tests/test-basic-boot.rs create mode 100644 example-kernels/tester/tests/integration_tests/test-panic.rs create mode 100644 example-kernels/testing-qemu-exit-code/.gitignore rename example-kernels/{testing => testing-qemu-exit-code}/Cargo.toml (66%) create mode 100644 example-kernels/testing-qemu-exit-code/src/bin/test-basic-boot.rs create mode 100644 example-kernels/testing-qemu-exit-code/src/bin/test-panic.rs create mode 100644 example-kernels/testing-qemu-exit-code/src/lib.rs create mode 100644 example-kernels/testing-serial-result/.gitignore create mode 100644 example-kernels/testing-serial-result/Cargo.toml rename example-kernels/{testing/src/bin/test-basic-boot.rs => testing-serial-result/src/bin/test-basic-boot-serial.rs} (92%) rename example-kernels/{testing/src/bin/test-panic.rs => testing-serial-result/src/bin/test-panic-serial.rs} (86%) rename example-kernels/{testing => testing-serial-result}/src/lib.rs (100%) rename example-kernels/{testing => testing-serial-result}/src/main.rs (100%) delete mode 100644 example-kernels/testing/Cargo.lock delete mode 100644 example-kernels/testing/x86_64-testing.json rename example-kernels/{basic/x86_64-basic.json => x86_64-bootimage-example-kernels.json} (100%) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d1cab8e..5c85131 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -11,117 +11,192 @@ trigger: # Build pull requests. - master -strategy: - matrix: - linux: - image_name: 'ubuntu-16.04' - rustup_toolchain: stable - mac: - image_name: 'macos-10.13' - rustup_toolchain: stable - windows: - image_name: 'vs2017-win2016' - rustup_toolchain: stable - -pool: - vmImage: $(image_name) - -steps: -- bash: | - echo "Hello world from $AGENT_NAME running on $AGENT_OS" - echo "Reason: $BUILD_REASON" - case "$BUILD_REASON" in - "Manual") echo "$BUILD_REQUESTEDFOR manually queued the build." ;; - "PullRequest") echo "This is a CI build for a pull request on $BUILD_REQUESTEDFOR." ;; - "IndividualCI") echo "This is a CI build for $BUILD_REQUESTEDFOR." ;; - "BatchedCI") echo "This is a batched CI build for $BUILD_REQUESTEDFOR." ;; - *) "$BUILD_REASON" ;; - esac - displayName: 'Build Info' - continueOnError: true - -- script: | - set -euxo pipefail - curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUSTUP_TOOLCHAIN - echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" - condition: or(eq( variables['Agent.OS'], 'Linux' ), eq( variables['Agent.OS'], 'Darwin' )) - displayName: 'Install Rust (Linux/macOS)' - -- script: curl -sSf -o rustup-init.exe https://win.rustup.rs && rustup-init.exe -y --default-toolchain %RUSTUP_TOOLCHAIN% - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - displayName: 'Install Rust (Windows)' - -- script: | - echo ##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - displayName: 'Add ~/.cargo/bin to PATH (Windows)' - -- script: | - rustc -Vv - cargo -V - displayName: 'Print Rust Version' - continueOnError: true - -- script: cargo build - displayName: 'Build' - -- script: cargo test - displayName: 'Test' - -- script: rustup component add rust-src llvm-tools-preview - displayName: 'Install Rustup Components' - -- script: cargo install cargo-xbuild --debug - displayName: 'Install cargo-xbuild' - -- script: sudo apt update && sudo apt install qemu-system-x86 - condition: eq( variables['Agent.OS'], 'Linux' ) - displayName: 'Install QEMU (Linux)' - -- script: | - set -euxo pipefail - export HOMEBREW_NO_AUTO_UPDATE=1 - export HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK=1 - export HOMEBREW_NO_INSTALL_CLEANUP=1 - brew install qemu - condition: eq( variables['Agent.OS'], 'Darwin' ) - displayName: 'Install QEMU (macOS)' - -- script: | - choco install qemu --limit-output --no-progress - echo ##vso[task.setvariable variable=PATH;]%PATH%;C:\Program Files\qemu - set PATH=%PATH%;C:\Program Files\qemu - qemu-system-x86_64 --version - condition: eq( variables['Agent.OS'], 'Windows_NT' ) - failOnStderr: true - displayName: 'Install QEMU (Windows)' - -- script: cargo install --path . --force --debug - displayName: 'Install this bootimage version' - -- script: rustup toolchain add nightly - displayName: 'Install Rust Nightly' - -- script: bootimage build --target x86_64-basic.json && file target/x86_64-basic/debug/bootimage-basic.bin - workingDirectory: example-kernels/basic - displayName: 'Build Example Kernel "Basic"' - -- script: bootimage run --target x86_64-basic.json - workingDirectory: example-kernels/basic - displayName: 'Run Example Kernel "basic"' - -- script: bootimage build && file target/x86_64-default-target/debug/bootimage-default-target-bootimage.bin - workingDirectory: example-kernels/default-target-bootimage - displayName: 'Build Example Kernel "default-target-bootimage"' - -- script: bootimage run - workingDirectory: example-kernels/default-target-bootimage - displayName: 'Run Example Kernel "default-target-bootimage"' - -- script: bootimage build && file target/x86_64-default-target/debug/bootimage-default-target-cargo.bin - workingDirectory: example-kernels/default-target-cargo - displayName: 'Build Example Kernel "default-target-cargo"' - -- script: bootimage run - workingDirectory: example-kernels/default-target-cargo - displayName: 'Run Example Kernel "default-target-cargo"' +jobs: +- job: build + displayName: Build + strategy: + matrix: + linux: + image_name: 'ubuntu-16.04' + rustup_toolchain: stable + mac: + image_name: 'macos-10.13' + rustup_toolchain: stable + windows: + image_name: 'vs2017-win2016' + rustup_toolchain: stable + + pool: + vmImage: $(image_name) + + steps: + - bash: | + echo "Hello world from $AGENT_NAME running on $AGENT_OS" + echo "Reason: $BUILD_REASON" + case "$BUILD_REASON" in + "Manual") echo "$BUILD_REQUESTEDFOR manually queued the build." ;; + "PullRequest") echo "This is a CI build for a pull request on $BUILD_REQUESTEDFOR." ;; + "IndividualCI") echo "This is a CI build for $BUILD_REQUESTEDFOR." ;; + "BatchedCI") echo "This is a batched CI build for $BUILD_REQUESTEDFOR." ;; + *) "$BUILD_REASON" ;; + esac + displayName: 'Build Info' + continueOnError: true + + - script: | + set -euxo pipefail + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUSTUP_TOOLCHAIN + echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + condition: or(eq( variables['Agent.OS'], 'Linux' ), eq( variables['Agent.OS'], 'Darwin' )) + displayName: 'Install Rust (Linux/macOS)' + + - script: curl -sSf -o rustup-init.exe https://win.rustup.rs && rustup-init.exe -y --default-toolchain %RUSTUP_TOOLCHAIN% + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + displayName: 'Install Rust (Windows)' + + - script: | + echo ##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + displayName: 'Add ~/.cargo/bin to PATH (Windows)' + + - script: | + rustc -Vv + cargo -V + displayName: 'Print Rust Version' + continueOnError: true + + - script: cargo build + displayName: 'Build' + + - script: cargo test + displayName: 'Test' + + +- job: test + displayName: Test + + strategy: + matrix: + linux: + image_name: 'ubuntu-16.04' + rustup_toolchain: nightly + mac: + image_name: 'macos-10.13' + rustup_toolchain: nightly + windows: + image_name: 'vs2017-win2016' + rustup_toolchain: nightly + + pool: + vmImage: $(image_name) + + steps: + - bash: | + echo "Hello world from $AGENT_NAME running on $AGENT_OS" + echo "Reason: $BUILD_REASON" + case "$BUILD_REASON" in + "Manual") echo "$BUILD_REQUESTEDFOR manually queued the build." ;; + "PullRequest") echo "This is a CI build for a pull request on $BUILD_REQUESTEDFOR." ;; + "IndividualCI") echo "This is a CI build for $BUILD_REQUESTEDFOR." ;; + "BatchedCI") echo "This is a batched CI build for $BUILD_REQUESTEDFOR." ;; + *) "$BUILD_REASON" ;; + esac + displayName: 'Build Info' + continueOnError: true + + - script: | + set -euxo pipefail + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $RUSTUP_TOOLCHAIN + echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + condition: or(eq( variables['Agent.OS'], 'Linux' ), eq( variables['Agent.OS'], 'Darwin' )) + displayName: 'Install Rust (Linux/macOS)' + + - script: curl -sSf -o rustup-init.exe https://win.rustup.rs && rustup-init.exe -y --default-toolchain %RUSTUP_TOOLCHAIN% + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + displayName: 'Install Rust (Windows)' + + - script: | + echo ##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + displayName: 'Add ~/.cargo/bin to PATH (Windows)' + + - script: | + rustc -Vv + cargo -V + displayName: 'Print Rust Version' + continueOnError: true + + - script: rustup component add rust-src llvm-tools-preview + displayName: 'Install Rustup Components' + + - script: cargo install cargo-xbuild --debug + displayName: 'Install cargo-xbuild' + + - script: sudo apt update && sudo apt install qemu-system-x86 + condition: eq( variables['Agent.OS'], 'Linux' ) + displayName: 'Install QEMU (Linux)' + + - script: | + set -euxo pipefail + export HOMEBREW_NO_AUTO_UPDATE=1 + export HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK=1 + export HOMEBREW_NO_INSTALL_CLEANUP=1 + brew install qemu + condition: eq( variables['Agent.OS'], 'Darwin' ) + displayName: 'Install QEMU (macOS)' + + - script: | + choco install qemu --limit-output --no-progress + echo ##vso[task.setvariable variable=PATH;]%PATH%;C:\Program Files\qemu + set PATH=%PATH%;C:\Program Files\qemu + qemu-system-x86_64 --version + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + failOnStderr: true + displayName: 'Install QEMU (Windows)' + + - script: cargo install --path . --force --debug + displayName: 'Install this bootimage version' + + - script: bootimage build --target ../x86_64-bootimage-example-kernels.json + workingDirectory: example-kernels/basic + displayName: 'Build "basic" Kernel' + + - bash: | + qemu-system-x86_64 -drive format=raw,file=target/x86_64-bootimage-example-kernels/debug/bootimage-basic.bin -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none + if [ $? -eq 103 ]; then (exit 0); else (exit 1); fi + workingDirectory: example-kernels + displayName: 'Run QEMU with "basic" Kernel' + + - bash: | + bootimage run --target ../x86_64-bootimage-example-kernels.json -- -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none + if [ $? -eq 103 ]; then (exit 0); else (exit 1); fi + workingDirectory: example-kernels/basic + displayName: 'Check Exit Code of `bootimage run` for "basic" kernel' + + - bash: | + bootimage run -- -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none + if [ $? -eq 105 ]; then (exit 0); else (exit 1); fi + workingDirectory: example-kernels/default-target-bootimage + displayName: 'Check Exit Code of `bootimage run` for "default-target-bootimage" kernel' + + - bash: | + bootimage run -- -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none + if [ $? -eq 107 ]; then (exit 0); else (exit 1); fi + workingDirectory: example-kernels/default-target-cargo + displayName: 'Check Exit Code of `bootimage run` for "default-target-cargo" kernel' + + - script: bootimage test + workingDirectory: example-kernels/testing-serial-result + displayName: 'Run `bootimage test` for "testing-serial-result" kernel' + + - script: bootimage test + workingDirectory: example-kernels/testing-qemu-exit-code + displayName: 'Run `bootimage test` for "testing-qemu-exit-code" kernel' + + - script: cargo xrun + workingDirectory: example-kernels/runner + displayName: 'Run `cargo xrun` for "runner" kernel' + + - script: cargo test + workingDirectory: example-kernels/tester + displayName: 'Run `cargo test` for "tester" kernel' diff --git a/example-kernels/testing/.gitignore b/example-kernels/.gitignore similarity index 100% rename from example-kernels/testing/.gitignore rename to example-kernels/.gitignore diff --git a/example-kernels/default-target-bootimage/Cargo.lock b/example-kernels/Cargo.lock similarity index 82% rename from example-kernels/default-target-bootimage/Cargo.lock rename to example-kernels/Cargo.lock index 06cfb07..cd749b3 100644 --- a/example-kernels/default-target-bootimage/Cargo.lock +++ b/example-kernels/Cargo.lock @@ -12,9 +12,7 @@ dependencies = [ name = "basic" version = "0.1.0" dependencies = [ - "bootloader 0.4.0", - "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bootloader 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -30,7 +28,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bootloader" -version = "0.4.0" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -45,6 +44,22 @@ name = "cc" version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "default-target-bootimage" +version = "0.1.0" +dependencies = [ + "bootloader 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "default-target-cargo" +version = "0.1.0" +dependencies = [ + "bootloader 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fixedvec" version = "0.2.3" @@ -71,9 +86,17 @@ dependencies = [ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lazy_static" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libc" -version = "0.2.50" +version = "0.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -105,7 +128,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -150,6 +173,14 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "runner" +version = "0.1.0" +dependencies = [ + "bootloader 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -185,6 +216,11 @@ name = "spin" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "spin" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "tempdir" version = "0.3.7" @@ -194,6 +230,33 @@ dependencies = [ "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tester" +version = "0.1.0" +dependencies = [ + "bootloader 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "testing-qemu-exit-code" +version = "0.1.0" +dependencies = [ + "bootloader 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "testing-serial-result" +version = "0.1.0" +dependencies = [ + "bootloader 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "uart_16550" version = "0.1.0" @@ -215,7 +278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ux" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -246,7 +309,7 @@ dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -259,7 +322,7 @@ dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -272,7 +335,7 @@ dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -292,12 +355,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" "checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum bootloader 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8668a7d724534aba1c3f2509eea122fcf611c31101662ecb947d502cc3cb96ae" "checksum cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ad0daef304fa0b4238f5f7ed7178774b43b06f6a9b6509f6642bef4ff1f7b9b2" "checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0" "checksum font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b81d84c3c978af7d05d31a2198af4b9ba956d819d15d8f6d58fc150e33f8dc1f" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" -"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" +"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917" "checksum llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "955be5d0ca0465caf127165acb47964f911e2bc26073e865deb8be7189302faf" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" @@ -313,11 +378,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" +"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" -"checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41" +"checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/example-kernels/Cargo.toml b/example-kernels/Cargo.toml new file mode 100644 index 0000000..03cc7ed --- /dev/null +++ b/example-kernels/Cargo.toml @@ -0,0 +1,10 @@ +[workspace] +members = [ + "basic", + "default-target-bootimage", + "default-target-cargo", + "runner", + "tester", + "testing-qemu-exit-code", + "testing-serial-result", +] \ No newline at end of file diff --git a/example-kernels/basic/Cargo.lock b/example-kernels/basic/Cargo.lock deleted file mode 100644 index dd4ef6b..0000000 --- a/example-kernels/basic/Cargo.lock +++ /dev/null @@ -1,297 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "array-init" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "basic" -version = "0.1.0" -dependencies = [ - "bootloader 0.4.0", - "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bit_field" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bootloader" -version = "0.4.0" -dependencies = [ - "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cc" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fixedvec" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "font8x8" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "getopts" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libc" -version = "0.2.50" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "llvm-tools" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "nodrop" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "os_bootinfo" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "pulldown-cmark" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raw-cpuid" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "skeptic" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tempdir" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-width" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "usize_conversions" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ux" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "x86_64" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "x86_64" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "xmas-elf" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zero" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" -"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ad0daef304fa0b4238f5f7ed7178774b43b06f6a9b6509f6642bef4ff1f7b9b2" -"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0" -"checksum font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b81d84c3c978af7d05d31a2198af4b9ba956d819d15d8f6d58fc150e33f8dc1f" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" -"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" -"checksum llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "955be5d0ca0465caf127165acb47964f911e2bc26073e865deb8be7189302faf" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" -"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c" -"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" -"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" -"checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f9258d7e2dd25008d69e8c9e9ee37865887a5e1e3d06a62f1cb3f6c209e6f177" -"checksum x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8f7e92e985f4052118fd69f2b366c67e91288c0f01f4ae52610dce236425dfa0" -"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" -"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/example-kernels/basic/src/main.rs b/example-kernels/basic/src/main.rs index f0352e2..0acc995 100644 --- a/example-kernels/basic/src/main.rs +++ b/example-kernels/basic/src/main.rs @@ -24,5 +24,5 @@ pub unsafe fn exit_qemu() { use x86_64::instructions::port::Port; let mut port = Port::::new(0xf4); - port.write(61); // exit code is (61 << 1) | 1 = 123 + port.write(51); // exit code is (51 << 1) | 1 = 103 } diff --git a/example-kernels/default-target-bootimage/Cargo.toml b/example-kernels/default-target-bootimage/Cargo.toml index f62b2ac..5825f0a 100644 --- a/example-kernels/default-target-bootimage/Cargo.toml +++ b/example-kernels/default-target-bootimage/Cargo.toml @@ -7,8 +7,6 @@ edition = "2018" [dependencies] bootloader = "0.5.0" x86_64 = "0.5.3" -spin = "0.4.9" -uart_16550 = "0.1.0" [package.metadata.bootimage] -default-target = "x86_64-default-target.json" \ No newline at end of file +default-target = "../x86_64-bootimage-example-kernels.json" \ No newline at end of file diff --git a/example-kernels/default-target-bootimage/src/main.rs b/example-kernels/default-target-bootimage/src/main.rs index f0352e2..44b77a9 100644 --- a/example-kernels/default-target-bootimage/src/main.rs +++ b/example-kernels/default-target-bootimage/src/main.rs @@ -24,5 +24,5 @@ pub unsafe fn exit_qemu() { use x86_64::instructions::port::Port; let mut port = Port::::new(0xf4); - port.write(61); // exit code is (61 << 1) | 1 = 123 + port.write(52); // exit code is (52 << 1) | 1 = 105 } diff --git a/example-kernels/default-target-bootimage/x86_64-default-target.json b/example-kernels/default-target-bootimage/x86_64-default-target.json deleted file mode 100644 index 9afe809..0000000 --- a/example-kernels/default-target-bootimage/x86_64-default-target.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "llvm-target": "x86_64-unknown-none", - "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", - "arch": "x86_64", - "target-endian": "little", - "target-pointer-width": "64", - "target-c-int-width": "32", - "os": "none", - "executables": true, - "linker-flavor": "ld.lld", - "linker": "rust-lld", - "panic-strategy": "abort", - "disable-redzone": true, - "features": "-mmx,-sse,+soft-float" - } diff --git a/example-kernels/default-target-cargo/.cargo/config b/example-kernels/default-target-cargo/.cargo/config index 35c3b41..79fdf34 100644 --- a/example-kernels/default-target-cargo/.cargo/config +++ b/example-kernels/default-target-cargo/.cargo/config @@ -1,2 +1,2 @@ [build] -target = "x86_64-default-target.json" \ No newline at end of file +target = "../x86_64-bootimage-example-kernels.json" \ No newline at end of file diff --git a/example-kernels/default-target-cargo/Cargo.lock b/example-kernels/default-target-cargo/Cargo.lock deleted file mode 100644 index 06cfb07..0000000 --- a/example-kernels/default-target-cargo/Cargo.lock +++ /dev/null @@ -1,328 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "array-init" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "basic" -version = "0.1.0" -dependencies = [ - "bootloader 0.4.0", - "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bit_field" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bootloader" -version = "0.4.0" -dependencies = [ - "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cc" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fixedvec" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "font8x8" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "getopts" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libc" -version = "0.2.50" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "llvm-tools" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "nodrop" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "os_bootinfo" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "pulldown-cmark" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raw-cpuid" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "skeptic" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "spin" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "tempdir" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "uart_16550" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-width" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "usize_conversions" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ux" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "x86_64" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "x86_64" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "x86_64" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "xmas-elf" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zero" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" -"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ad0daef304fa0b4238f5f7ed7178774b43b06f6a9b6509f6642bef4ff1f7b9b2" -"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0" -"checksum font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b81d84c3c978af7d05d31a2198af4b9ba956d819d15d8f6d58fc150e33f8dc1f" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" -"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" -"checksum llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "955be5d0ca0465caf127165acb47964f911e2bc26073e865deb8be7189302faf" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" -"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c" -"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" -"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e" -"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" -"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" -"checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd647af1614659e1febec1d681231aea4ebda4818bf55a578aff02f3e4db4b4" -"checksum x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f9258d7e2dd25008d69e8c9e9ee37865887a5e1e3d06a62f1cb3f6c209e6f177" -"checksum x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8f7e92e985f4052118fd69f2b366c67e91288c0f01f4ae52610dce236425dfa0" -"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" -"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/example-kernels/default-target-cargo/Cargo.toml b/example-kernels/default-target-cargo/Cargo.toml index 8c1a298..737b944 100644 --- a/example-kernels/default-target-cargo/Cargo.toml +++ b/example-kernels/default-target-cargo/Cargo.toml @@ -7,5 +7,3 @@ edition = "2018" [dependencies] bootloader = "0.5.0" x86_64 = "0.5.3" -spin = "0.4.9" -uart_16550 = "0.1.0" diff --git a/example-kernels/default-target-cargo/src/main.rs b/example-kernels/default-target-cargo/src/main.rs index f0352e2..14aead9 100644 --- a/example-kernels/default-target-cargo/src/main.rs +++ b/example-kernels/default-target-cargo/src/main.rs @@ -24,5 +24,5 @@ pub unsafe fn exit_qemu() { use x86_64::instructions::port::Port; let mut port = Port::::new(0xf4); - port.write(61); // exit code is (61 << 1) | 1 = 123 + port.write(53); // exit code is (53 << 1) | 1 = 107 } diff --git a/example-kernels/default-target-cargo/x86_64-default-target.json b/example-kernels/default-target-cargo/x86_64-default-target.json deleted file mode 100644 index 9afe809..0000000 --- a/example-kernels/default-target-cargo/x86_64-default-target.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "llvm-target": "x86_64-unknown-none", - "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", - "arch": "x86_64", - "target-endian": "little", - "target-pointer-width": "64", - "target-c-int-width": "32", - "os": "none", - "executables": true, - "linker-flavor": "ld.lld", - "linker": "rust-lld", - "panic-strategy": "abort", - "disable-redzone": true, - "features": "-mmx,-sse,+soft-float" - } diff --git a/example-kernels/runner/.cargo/config b/example-kernels/runner/.cargo/config new file mode 100644 index 0000000..ece5e24 --- /dev/null +++ b/example-kernels/runner/.cargo/config @@ -0,0 +1,5 @@ +[build] +target = "../x86_64-bootimage-example-kernels.json" + +[target.'cfg(target_os = "none")'] +runner = "bootimage runner --args -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none" diff --git a/example-kernels/runner/.gitignore b/example-kernels/runner/.gitignore new file mode 100644 index 0000000..eccd7b4 --- /dev/null +++ b/example-kernels/runner/.gitignore @@ -0,0 +1,2 @@ +/target/ +**/*.rs.bk diff --git a/example-kernels/runner/Cargo.toml b/example-kernels/runner/Cargo.toml new file mode 100644 index 0000000..d095399 --- /dev/null +++ b/example-kernels/runner/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "runner" +version = "0.1.0" +authors = ["Philipp Oppermann "] +edition = "2018" + +[dependencies] +bootloader = "0.5.0" +x86_64 = "0.5.3" diff --git a/example-kernels/runner/src/main.rs b/example-kernels/runner/src/main.rs new file mode 100644 index 0000000..033f446 --- /dev/null +++ b/example-kernels/runner/src/main.rs @@ -0,0 +1,28 @@ +#![no_std] // don't link the Rust standard library +#![no_main] // disable all Rust-level entry points + +use core::panic::PanicInfo; + +/// This function is called on panic. +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} +} + +#[no_mangle] // don't mangle the name of this function +pub extern "C" fn _start() -> ! { + // this function is the entry point, since the linker looks for a function + // named `_start` by default + + // exit QEMU (see https://os.phil-opp.com/integration-tests/#shutting-down-qemu) + unsafe { exit_qemu(); } + + loop {} +} + +pub unsafe fn exit_qemu() { + use x86_64::instructions::port::Port; + + let mut port = Port::::new(0xf4); + port.write(54); // exit code is (54 << 1) | 1 = 109 +} diff --git a/example-kernels/tester/.gitignore b/example-kernels/tester/.gitignore new file mode 100644 index 0000000..eccd7b4 --- /dev/null +++ b/example-kernels/tester/.gitignore @@ -0,0 +1,2 @@ +/target/ +**/*.rs.bk diff --git a/example-kernels/tester/Cargo.toml b/example-kernels/tester/Cargo.toml new file mode 100644 index 0000000..73c86fc --- /dev/null +++ b/example-kernels/tester/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "tester" +version = "0.1.0" +authors = ["Philipp Oppermann "] +edition = "2018" + +[dependencies] +bootloader = "0.5.0" +x86_64 = "0.5.3" diff --git a/example-kernels/tester/build.rs b/example-kernels/tester/build.rs new file mode 100644 index 0000000..ee98612 --- /dev/null +++ b/example-kernels/tester/build.rs @@ -0,0 +1,27 @@ +use std::{env, fs::File, io::Write, path::Path}; + +fn main() { + let out_dir = env::var("OUT_DIR").unwrap(); + let dest_path = Path::new(&out_dir).join("generated_tests.rs"); + let mut tests = File::create(&dest_path).unwrap(); + for entry in Path::new("tests/integration_tests").read_dir().expect("failed to read tests/integration tests") { + let entry = entry.expect("failed to read dir entry"); + assert!(entry.file_type().unwrap().is_file()); + let test_path = entry.path(); + let test_name = test_path.file_stem().expect("no file stem").to_os_string().into_string().expect("file name not valid utf8"); + + let content = format!(r#" +#[test] +fn {test_name}() {{ + run_test("{test_path}"); +}} +"#, test_name = test_name.replace("-", "_"), test_path = test_path.display()); + + tests.write_all(content.as_bytes()).expect("failed to write test"); + + println!("cargo:rerun-if-changed={}", entry.path().display()); + } + + println!("cargo:rustc-env=GENERATED_TESTS={}", dest_path.display()); + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/example-kernels/tester/src/lib.rs b/example-kernels/tester/src/lib.rs new file mode 100644 index 0000000..cdc0ba8 --- /dev/null +++ b/example-kernels/tester/src/lib.rs @@ -0,0 +1,21 @@ +#![cfg_attr(not(test), no_std)] +#![feature(abi_x86_interrupt)] + +#[repr(u32)] +pub enum ExitCode { + Success = 2, + Failure = 3, +} + +pub unsafe fn exit_qemu(exit_code: ExitCode) { + use x86_64::instructions::port::Port; + + let mut port = Port::::new(0xf4); + port.write(exit_code as u32); +} + +pub fn hlt_loop() -> ! { + loop { + x86_64::instructions::hlt(); + } +} diff --git a/example-kernels/tester/tests/integration_tests.rs b/example-kernels/tester/tests/integration_tests.rs new file mode 100644 index 0000000..4db5e2d --- /dev/null +++ b/example-kernels/tester/tests/integration_tests.rs @@ -0,0 +1,14 @@ +include!(env!("GENERATED_TESTS")); + +fn run_test(test_path: &str) { + let mut cmd = std::process::Command::new("bootimage"); + cmd.arg("tester"); + cmd.arg(test_path); + cmd.arg("--target"); + cmd.arg("../x86_64-bootimage-example-kernels.json"); + let output = cmd.output().expect("failed to run bootimage"); + if !output.status.success() { + eprintln!("{}", String::from_utf8_lossy(&output.stderr)); + panic!("test failed"); + } +} \ No newline at end of file diff --git a/example-kernels/tester/tests/integration_tests/test-basic-boot.rs b/example-kernels/tester/tests/integration_tests/test-basic-boot.rs new file mode 100644 index 0000000..e870449 --- /dev/null +++ b/example-kernels/tester/tests/integration_tests/test-basic-boot.rs @@ -0,0 +1,27 @@ +#![cfg_attr(not(test), no_std)] +#![cfg_attr(not(test), no_main)] // disable all Rust-level entry points +#![cfg_attr(test, allow(unused_imports))] + +use testing::{exit_qemu, ExitCode}; +use core::panic::PanicInfo; + +/// This function is the entry point, since the linker looks for a function +/// named `_start` by default. +#[cfg(not(test))] +#[no_mangle] // don't mangle the name of this function +pub extern "C" fn _start() -> ! { + unsafe { + exit_qemu(ExitCode::Success); + } + loop {} +} + +/// This function is called on panic. +#[cfg(not(test))] +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + unsafe { + exit_qemu(ExitCode::Failure); + } + loop {} +} diff --git a/example-kernels/tester/tests/integration_tests/test-panic.rs b/example-kernels/tester/tests/integration_tests/test-panic.rs new file mode 100644 index 0000000..ef8e768 --- /dev/null +++ b/example-kernels/tester/tests/integration_tests/test-panic.rs @@ -0,0 +1,21 @@ +#![cfg_attr(not(test), no_std)] +#![cfg_attr(not(test), no_main)] +#![cfg_attr(test, allow(unused_imports))] + +use testing::{exit_qemu, ExitCode}; +use core::panic::PanicInfo; + +#[cfg(not(test))] +#[no_mangle] +pub extern "C" fn _start() -> ! { + panic!(); +} + +#[cfg(not(test))] +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + unsafe { + exit_qemu(ExitCode::Success); + } + loop {} +} diff --git a/example-kernels/testing-qemu-exit-code/.gitignore b/example-kernels/testing-qemu-exit-code/.gitignore new file mode 100644 index 0000000..eccd7b4 --- /dev/null +++ b/example-kernels/testing-qemu-exit-code/.gitignore @@ -0,0 +1,2 @@ +/target/ +**/*.rs.bk diff --git a/example-kernels/testing/Cargo.toml b/example-kernels/testing-qemu-exit-code/Cargo.toml similarity index 66% rename from example-kernels/testing/Cargo.toml rename to example-kernels/testing-qemu-exit-code/Cargo.toml index 9b5541f..6efb450 100644 --- a/example-kernels/testing/Cargo.toml +++ b/example-kernels/testing-qemu-exit-code/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "testing" +name = "testing-qemu-exit-code" version = "0.1.0" authors = ["Philipp Oppermann "] edition = "2018" @@ -7,8 +7,6 @@ edition = "2018" [dependencies] bootloader = "0.5.0" x86_64 = "0.5.3" -spin = "0.4.9" -uart_16550 = "0.1.0" [package.metadata.bootimage] -default-target = "x86_64-testing.json" \ No newline at end of file +default-target = "../x86_64-bootimage-example-kernels.json" \ No newline at end of file diff --git a/example-kernels/testing-qemu-exit-code/src/bin/test-basic-boot.rs b/example-kernels/testing-qemu-exit-code/src/bin/test-basic-boot.rs new file mode 100644 index 0000000..1a506f1 --- /dev/null +++ b/example-kernels/testing-qemu-exit-code/src/bin/test-basic-boot.rs @@ -0,0 +1,27 @@ +#![cfg_attr(not(test), no_std)] +#![cfg_attr(not(test), no_main)] // disable all Rust-level entry points +#![cfg_attr(test, allow(unused_imports))] + +use testing_qemu_exit_code::{exit_qemu, ExitCode}; +use core::panic::PanicInfo; + +/// This function is the entry point, since the linker looks for a function +/// named `_start` by default. +#[cfg(not(test))] +#[no_mangle] // don't mangle the name of this function +pub extern "C" fn _start() -> ! { + unsafe { + exit_qemu(ExitCode::Success); + } + loop {} +} + +/// This function is called on panic. +#[cfg(not(test))] +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + unsafe { + exit_qemu(ExitCode::Failure); + } + loop {} +} diff --git a/example-kernels/testing-qemu-exit-code/src/bin/test-panic.rs b/example-kernels/testing-qemu-exit-code/src/bin/test-panic.rs new file mode 100644 index 0000000..a1c05f8 --- /dev/null +++ b/example-kernels/testing-qemu-exit-code/src/bin/test-panic.rs @@ -0,0 +1,21 @@ +#![cfg_attr(not(test), no_std)] +#![cfg_attr(not(test), no_main)] +#![cfg_attr(test, allow(unused_imports))] + +use testing_qemu_exit_code::{exit_qemu, ExitCode}; +use core::panic::PanicInfo; + +#[cfg(not(test))] +#[no_mangle] +pub extern "C" fn _start() -> ! { + panic!(); +} + +#[cfg(not(test))] +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + unsafe { + exit_qemu(ExitCode::Success); + } + loop {} +} diff --git a/example-kernels/testing-qemu-exit-code/src/lib.rs b/example-kernels/testing-qemu-exit-code/src/lib.rs new file mode 100644 index 0000000..cdc0ba8 --- /dev/null +++ b/example-kernels/testing-qemu-exit-code/src/lib.rs @@ -0,0 +1,21 @@ +#![cfg_attr(not(test), no_std)] +#![feature(abi_x86_interrupt)] + +#[repr(u32)] +pub enum ExitCode { + Success = 2, + Failure = 3, +} + +pub unsafe fn exit_qemu(exit_code: ExitCode) { + use x86_64::instructions::port::Port; + + let mut port = Port::::new(0xf4); + port.write(exit_code as u32); +} + +pub fn hlt_loop() -> ! { + loop { + x86_64::instructions::hlt(); + } +} diff --git a/example-kernels/testing-serial-result/.gitignore b/example-kernels/testing-serial-result/.gitignore new file mode 100644 index 0000000..eccd7b4 --- /dev/null +++ b/example-kernels/testing-serial-result/.gitignore @@ -0,0 +1,2 @@ +/target/ +**/*.rs.bk diff --git a/example-kernels/testing-serial-result/Cargo.toml b/example-kernels/testing-serial-result/Cargo.toml new file mode 100644 index 0000000..bbe84a2 --- /dev/null +++ b/example-kernels/testing-serial-result/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "testing-serial-result" +version = "0.1.0" +authors = ["Philipp Oppermann "] +edition = "2018" + +[dependencies] +bootloader = "0.5.0" +x86_64 = "0.5.3" +spin = "0.4.9" +uart_16550 = "0.1.0" + +[dependencies.lazy_static] +version = "1.3.0" +features = ["spin_no_std"] + +[package.metadata.bootimage] +default-target = "../x86_64-bootimage-example-kernels.json" diff --git a/example-kernels/testing/src/bin/test-basic-boot.rs b/example-kernels/testing-serial-result/src/bin/test-basic-boot-serial.rs similarity index 92% rename from example-kernels/testing/src/bin/test-basic-boot.rs rename to example-kernels/testing-serial-result/src/bin/test-basic-boot-serial.rs index f77d4a0..d6982d0 100644 --- a/example-kernels/testing/src/bin/test-basic-boot.rs +++ b/example-kernels/testing-serial-result/src/bin/test-basic-boot-serial.rs @@ -2,7 +2,7 @@ #![cfg_attr(not(test), no_main)] // disable all Rust-level entry points #![cfg_attr(test, allow(unused_imports))] -use blog_os::{exit_qemu, serial_println}; +use testing_serial_result::{exit_qemu, serial_println}; use core::panic::PanicInfo; /// This function is the entry point, since the linker looks for a function diff --git a/example-kernels/testing/src/bin/test-panic.rs b/example-kernels/testing-serial-result/src/bin/test-panic-serial.rs similarity index 86% rename from example-kernels/testing/src/bin/test-panic.rs rename to example-kernels/testing-serial-result/src/bin/test-panic-serial.rs index c68ac51..324a28f 100644 --- a/example-kernels/testing/src/bin/test-panic.rs +++ b/example-kernels/testing-serial-result/src/bin/test-panic-serial.rs @@ -2,7 +2,7 @@ #![cfg_attr(not(test), no_main)] #![cfg_attr(test, allow(unused_imports))] -use blog_os::{exit_qemu, serial_println}; +use testing_serial_result::{exit_qemu, serial_println}; use core::panic::PanicInfo; #[cfg(not(test))] diff --git a/example-kernels/testing/src/lib.rs b/example-kernels/testing-serial-result/src/lib.rs similarity index 100% rename from example-kernels/testing/src/lib.rs rename to example-kernels/testing-serial-result/src/lib.rs diff --git a/example-kernels/testing/src/main.rs b/example-kernels/testing-serial-result/src/main.rs similarity index 100% rename from example-kernels/testing/src/main.rs rename to example-kernels/testing-serial-result/src/main.rs diff --git a/example-kernels/testing/Cargo.lock b/example-kernels/testing/Cargo.lock deleted file mode 100644 index 06cfb07..0000000 --- a/example-kernels/testing/Cargo.lock +++ /dev/null @@ -1,328 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "array-init" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "basic" -version = "0.1.0" -dependencies = [ - "bootloader 0.4.0", - "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bit_field" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bootloader" -version = "0.4.0" -dependencies = [ - "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cc" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fixedvec" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "font8x8" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "getopts" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libc" -version = "0.2.50" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "llvm-tools" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "nodrop" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "os_bootinfo" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "pulldown-cmark" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "raw-cpuid" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "skeptic" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "spin" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "tempdir" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "uart_16550" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-width" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "usize_conversions" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ux" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "x86_64" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "x86_64" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "x86_64" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "xmas-elf" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "zero" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" -"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ad0daef304fa0b4238f5f7ed7178774b43b06f6a9b6509f6642bef4ff1f7b9b2" -"checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0" -"checksum font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b81d84c3c978af7d05d31a2198af4b9ba956d819d15d8f6d58fc150e33f8dc1f" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" -"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" -"checksum llvm-tools 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "955be5d0ca0465caf127165acb47964f911e2bc26073e865deb8be7189302faf" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" -"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30a9d219c32c9132f7be513c18be77c9881c7107d2ab5569d205a6a0f0e6dc7d" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum skeptic 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "061203a849117b0f7090baf8157aa91dac30545208fbb85166ac58b4ca33d89c" -"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" -"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e" -"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" -"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" -"checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd647af1614659e1febec1d681231aea4ebda4818bf55a578aff02f3e4db4b4" -"checksum x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f9258d7e2dd25008d69e8c9e9ee37865887a5e1e3d06a62f1cb3f6c209e6f177" -"checksum x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8f7e92e985f4052118fd69f2b366c67e91288c0f01f4ae52610dce236425dfa0" -"checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" -"checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/example-kernels/testing/x86_64-testing.json b/example-kernels/testing/x86_64-testing.json deleted file mode 100644 index 9afe809..0000000 --- a/example-kernels/testing/x86_64-testing.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "llvm-target": "x86_64-unknown-none", - "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", - "arch": "x86_64", - "target-endian": "little", - "target-pointer-width": "64", - "target-c-int-width": "32", - "os": "none", - "executables": true, - "linker-flavor": "ld.lld", - "linker": "rust-lld", - "panic-strategy": "abort", - "disable-redzone": true, - "features": "-mmx,-sse,+soft-float" - } diff --git a/example-kernels/basic/x86_64-basic.json b/example-kernels/x86_64-bootimage-example-kernels.json similarity index 100% rename from example-kernels/basic/x86_64-basic.json rename to example-kernels/x86_64-bootimage-example-kernels.json From 13b3998a44d3cb7655e644531a658dea22eb85f1 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 15:38:45 +0200 Subject: [PATCH 25/50] Convert runner args to config keys Variable length args are not possible since the executable name is appended at the end --- example-kernels/runner/.cargo/config | 2 +- example-kernels/runner/Cargo.toml | 3 ++ src/args.rs | 43 +++++++++------------------- src/config.rs | 13 +++++++++ src/subcommand/runner.rs | 17 ++++------- 5 files changed, 37 insertions(+), 41 deletions(-) diff --git a/example-kernels/runner/.cargo/config b/example-kernels/runner/.cargo/config index ece5e24..3b4d89e 100644 --- a/example-kernels/runner/.cargo/config +++ b/example-kernels/runner/.cargo/config @@ -2,4 +2,4 @@ target = "../x86_64-bootimage-example-kernels.json" [target.'cfg(target_os = "none")'] -runner = "bootimage runner --args -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none" +runner = "bootimage runner" diff --git a/example-kernels/runner/Cargo.toml b/example-kernels/runner/Cargo.toml index d095399..966cce4 100644 --- a/example-kernels/runner/Cargo.toml +++ b/example-kernels/runner/Cargo.toml @@ -7,3 +7,6 @@ edition = "2018" [dependencies] bootloader = "0.5.0" x86_64 = "0.5.3" + +[package.metadata.bootimage] +run-args = ["-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-display", "none"] diff --git a/src/args.rs b/src/args.rs index ac33bc9..c8823bf 100644 --- a/src/args.rs +++ b/src/args.rs @@ -207,56 +207,41 @@ fn parse_runner_args(args: A) -> Result where A: Iterator, { + let mut executable = None; let mut arg_iter = args.into_iter().fuse(); - let executable = PathBuf::from( - arg_iter - .next() - .ok_or("excepted path to kernel executable as first argument")?, - ) - .canonicalize() - .map_err(|err| format!("Failed to canonicalize executable path: {}", err))?; - let mut run_command = None; - let mut run_args = None; loop { match arg_iter.next().as_ref().map(|s| s.as_str()) { - Some("--command") => { - let old = mem::replace(&mut run_command, Some(arg_iter.collect())); - if !old.is_none() { - Err("multiple `--command` arguments")?; - } - break; - } - Some("--args") => { - let old = mem::replace(&mut run_args, Some(arg_iter.collect())); - if !old.is_none() { - Err("multiple `--args` arguments")?; - } - break; - } Some("--help") | Some("-h") => { return Ok(Command::RunnerHelp); } Some("--version") => { return Ok(Command::Version); } - None => break, + Some(exe) if executable.is_none() => { + let path = Path::new(exe); + let path_canonicalized = path.canonicalize().map_err(|err| { + format!( + "Failed to canonicalize executable path `{}`: {}", + path.display(), + err + ) + })?; + executable = Some(path_canonicalized); + } Some(arg) => Err(format!("unexpected argument `{}`", arg))?, + None => break, } } Ok(Command::Runner(RunnerArgs { - executable, - run_command, - run_args, + executable: executable.ok_or("excepted path to kernel executable as first argument")?, })) } #[derive(Debug, Clone)] pub struct RunnerArgs { pub executable: PathBuf, - pub run_command: Option>, - pub run_args: Option>, } fn parse_tester_args(args: A) -> Result diff --git a/src/config.rs b/src/config.rs index 5ccf1d4..6f10e20 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,6 +7,7 @@ pub struct Config { pub manifest_path: PathBuf, pub default_target: Option, pub run_command: Vec, + pub run_args: Option>, pub test_timeout: u32, } @@ -70,6 +71,16 @@ pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result { + let mut args = Vec::new(); + for value in array { + match value { + Value::String(s) => args.push(s), + _ => Err(format!("run-args must be a list of strings"))?, + } + } + config.run_args = Some(args); + } (key, value) => Err(format!( "unexpected `package.metadata.bootimage` \ key `{}` with value `{}`", @@ -85,6 +96,7 @@ struct ConfigBuilder { manifest_path: Option, default_target: Option, run_command: Option>, + run_args: Option>, test_timeout: Option, } @@ -98,6 +110,7 @@ impl Into for ConfigBuilder { "-drive".into(), "format=raw,file={}".into(), ]), + run_args: self.run_args, test_timeout: self.test_timeout.unwrap_or(60 * 5), } } diff --git a/src/subcommand/runner.rs b/src/subcommand/runner.rs index 4bbbe74..326b911 100644 --- a/src/subcommand/runner.rs +++ b/src/subcommand/runner.rs @@ -1,8 +1,9 @@ -use crate::{args::RunnerArgs, builder::Builder, ErrorString}; +use crate::{args::RunnerArgs, builder::Builder, config, ErrorString}; use std::{fs, process}; pub(crate) fn runner(args: RunnerArgs) -> Result { let builder = Builder::new(None)?; + let config = config::read_config(builder.kernel_manifest_path().to_owned())?; let bootimage_bin = { let kernel_target_dir = &builder.kernel_metadata().target_directory; @@ -38,17 +39,11 @@ pub(crate) fn runner(args: RunnerArgs) -> Result { builder.create_bootimage(&args.executable, &bootimage_bin, false)?; - let run_cmd = args.run_command.unwrap_or(vec![ - "qemu-system-x86_64".into(), - "-drive".into(), - "format=raw,file={bootimage}".into(), - ]); - - let mut command = process::Command::new(&run_cmd[0]); - for arg in &run_cmd[1..] { - command.arg(arg.replace("{bootimage}", &format!("{}", bootimage_bin.display()))); + let mut command = process::Command::new(&config.run_command[0]); + for arg in &config.run_command[1..] { + command.arg(arg.replace("{}", &format!("{}", bootimage_bin.display()))); } - if let Some(run_args) = args.run_args { + if let Some(run_args) = config.run_args { command.args(run_args); } From c73be6fafe48e494b1f0b601b10f8874c713c3e3 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 15:50:13 +0200 Subject: [PATCH 26/50] Check for correct exit code of `cargo xrun` in CI script --- azure-pipelines.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5c85131..18c0e0e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -193,7 +193,9 @@ jobs: workingDirectory: example-kernels/testing-qemu-exit-code displayName: 'Run `bootimage test` for "testing-qemu-exit-code" kernel' - - script: cargo xrun + - bash: | + cargo xrun + if [ $? -eq 109 ]; then (exit 0); else (exit 1); fi workingDirectory: example-kernels/runner displayName: 'Run `cargo xrun` for "runner" kernel' From 81860b3c4563e0268d2890832d8e69a647f1c449 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 16:05:07 +0200 Subject: [PATCH 27/50] Exclude generated test crates from parent workspace --- src/subcommand/tester.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/subcommand/tester.rs b/src/subcommand/tester.rs index a48e6cc..401ebb4 100644 --- a/src/subcommand/tester.rs +++ b/src/subcommand/tester.rs @@ -83,6 +83,8 @@ name = "{test_name}" version = "0.0.0" edition = "2018" +[workspace] # exclude this crate from parent workspaces + [[bin]] name = "{test_name}" path = "{test_path}" From 03528dd3790a807cba1bf6644fd0249fabf888c4 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 16:06:51 +0200 Subject: [PATCH 28/50] Fix imports in tester tests --- .../tester/tests/integration_tests/test-basic-boot.rs | 2 +- example-kernels/tester/tests/integration_tests/test-panic.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example-kernels/tester/tests/integration_tests/test-basic-boot.rs b/example-kernels/tester/tests/integration_tests/test-basic-boot.rs index e870449..02de359 100644 --- a/example-kernels/tester/tests/integration_tests/test-basic-boot.rs +++ b/example-kernels/tester/tests/integration_tests/test-basic-boot.rs @@ -2,7 +2,7 @@ #![cfg_attr(not(test), no_main)] // disable all Rust-level entry points #![cfg_attr(test, allow(unused_imports))] -use testing::{exit_qemu, ExitCode}; +use tester::{exit_qemu, ExitCode}; use core::panic::PanicInfo; /// This function is the entry point, since the linker looks for a function diff --git a/example-kernels/tester/tests/integration_tests/test-panic.rs b/example-kernels/tester/tests/integration_tests/test-panic.rs index ef8e768..5a7d176 100644 --- a/example-kernels/tester/tests/integration_tests/test-panic.rs +++ b/example-kernels/tester/tests/integration_tests/test-panic.rs @@ -2,7 +2,7 @@ #![cfg_attr(not(test), no_main)] #![cfg_attr(test, allow(unused_imports))] -use testing::{exit_qemu, ExitCode}; +use tester::{exit_qemu, ExitCode}; use core::panic::PanicInfo; #[cfg(not(test))] From 80aeb7cf835ecc3f9deb60f9f74406101c1a3e80 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 16:54:32 +0200 Subject: [PATCH 29/50] Place bootimage-*.bin in default target directory for `runner` This is the same behavior as `bootimage run`. --- src/subcommand/runner.rs | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/subcommand/runner.rs b/src/subcommand/runner.rs index 326b911..6c0dc6b 100644 --- a/src/subcommand/runner.rs +++ b/src/subcommand/runner.rs @@ -1,14 +1,11 @@ use crate::{args::RunnerArgs, builder::Builder, config, ErrorString}; -use std::{fs, process}; +use std::process; pub(crate) fn runner(args: RunnerArgs) -> Result { let builder = Builder::new(None)?; let config = config::read_config(builder.kernel_manifest_path().to_owned())?; let bootimage_bin = { - let kernel_target_dir = &builder.kernel_metadata().target_directory; - let bootimage_target_dir = kernel_target_dir.join("bootimage").join("runner"); - let parent = args .executable .parent() @@ -19,22 +16,7 @@ pub(crate) fn runner(args: RunnerArgs) -> Result { .ok_or("kernel executable has no file stem")? .to_str() .ok_or("kernel executable file stem is not valid UTF-8")?; - let sub_path = parent.strip_prefix(kernel_target_dir).map_err(|err| { - format!( - "kernel executable does not live in kernel target directory: {}", - err - ) - })?; - - let out_dir = bootimage_target_dir.join(sub_path); - fs::create_dir_all(&out_dir).map_err(|err| { - format!( - "failed to create output directory {}: {}", - out_dir.display(), - err - ) - })?; - out_dir.join(format!("bootimage-{}.bin", file_stem)) + parent.join(format!("bootimage-{}.bin", file_stem)) }; builder.create_bootimage(&args.executable, &bootimage_bin, false)?; From 976289a685da0c73d42bf1d4ccd19143e9ca8b99 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 17:06:02 +0200 Subject: [PATCH 30/50] Use kernel target dir for tester to improve performance --- src/subcommand/tester.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/subcommand/tester.rs b/src/subcommand/tester.rs index 401ebb4..7fbd0ad 100644 --- a/src/subcommand/tester.rs +++ b/src/subcommand/tester.rs @@ -86,7 +86,7 @@ edition = "2018" [workspace] # exclude this crate from parent workspaces [[bin]] -name = "{test_name}" +name = "bootimage-tester-{test_name}" path = "{test_path}" {dependency_table} @@ -103,8 +103,7 @@ path = "{test_path}" let mut cmd = Command::new(&cargo); cmd.arg("xbuild"); cmd.arg("--manifest-path").arg(&manifest_path); - cmd.arg("--target-dir") - .arg(&integration_test_dir.join("target")); + cmd.arg("--target-dir").arg(&kernel_target_dir); cmd.env("SYSROOT_DIR", &integration_test_dir.join("sysroot")); // for cargo-xbuild if let Some(target) = args.target.as_ref().or(config.default_target.as_ref()) { From 841d2ec54b9c1d51bc722e95ec58078c7c59676b Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 17:25:23 +0200 Subject: [PATCH 31/50] Print path in error message when canonicalization fails --- src/args.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/args.rs b/src/args.rs index c8823bf..23950c3 100644 --- a/src/args.rs +++ b/src/args.rs @@ -249,13 +249,18 @@ where A: Iterator, { let mut arg_iter = args.into_iter().fuse(); - let test_path = PathBuf::from( + let test_path_arg = PathBuf::from( arg_iter .next() .ok_or("excepted path to test source file as first argument")?, - ) - .canonicalize() - .map_err(|err| format!("Failed to canonicalize test path: {}", err))?; + ); + let test_path = test_path_arg.canonicalize().map_err(|err| { + format!( + "Failed to canonicalize test path `{}`: {}", + test_path_arg.display(), + err + ) + })?; let mut run_command = None; let mut target = None; From a01c22cbf2bdfc02044020b1885197b8627f3d8b Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 17:43:13 +0200 Subject: [PATCH 32/50] Try to fix test error on Windows --- example-kernels/tester/build.rs | 2 +- example-kernels/tester/tests/integration_tests.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/example-kernels/tester/build.rs b/example-kernels/tester/build.rs index ee98612..fd1c011 100644 --- a/example-kernels/tester/build.rs +++ b/example-kernels/tester/build.rs @@ -4,7 +4,7 @@ fn main() { let out_dir = env::var("OUT_DIR").unwrap(); let dest_path = Path::new(&out_dir).join("generated_tests.rs"); let mut tests = File::create(&dest_path).unwrap(); - for entry in Path::new("tests/integration_tests").read_dir().expect("failed to read tests/integration tests") { + for entry in Path::new("tests").join("integration_tests").read_dir().expect("failed to read tests/integration tests") { let entry = entry.expect("failed to read dir entry"); assert!(entry.file_type().unwrap().is_file()); let test_path = entry.path(); diff --git a/example-kernels/tester/tests/integration_tests.rs b/example-kernels/tester/tests/integration_tests.rs index 4db5e2d..352e413 100644 --- a/example-kernels/tester/tests/integration_tests.rs +++ b/example-kernels/tester/tests/integration_tests.rs @@ -1,9 +1,11 @@ +use std::path::Path; + include!(env!("GENERATED_TESTS")); fn run_test(test_path: &str) { let mut cmd = std::process::Command::new("bootimage"); cmd.arg("tester"); - cmd.arg(test_path); + cmd.arg(Path::new(test_path)); cmd.arg("--target"); cmd.arg("../x86_64-bootimage-example-kernels.json"); let output = cmd.output().expect("failed to run bootimage"); From ee987a1333104afb474bba906027ce6d71dafd9f Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 18:41:43 +0200 Subject: [PATCH 33/50] Remove `tester` subcommand again This functionality is better implemented manually on top of `bootimage run`. Such a manual implementation can be a proper workspace member and correctly share the sysroot and the target artifacts (with the `bootimage tester` we don't achieve sharing because the dependency fingerprints differ). --- azure-pipelines.yml | 4 - src/args.rs | 61 ----------- src/lib.rs | 7 +- src/subcommand.rs | 1 - src/subcommand/tester.rs | 225 --------------------------------------- 5 files changed, 2 insertions(+), 296 deletions(-) delete mode 100644 src/subcommand/tester.rs diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 18c0e0e..f750360 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -198,7 +198,3 @@ jobs: if [ $? -eq 109 ]; then (exit 0); else (exit 1); fi workingDirectory: example-kernels/runner displayName: 'Run `cargo xrun` for "runner" kernel' - - - script: cargo test - workingDirectory: example-kernels/tester - displayName: 'Run `cargo test` for "tester" kernel' diff --git a/src/args.rs b/src/args.rs index 23950c3..4c9ffd4 100644 --- a/src/args.rs +++ b/src/args.rs @@ -30,7 +30,6 @@ pub(crate) fn parse_args() -> Result { cmd => cmd, }), Some("runner") => parse_runner_args(args), - Some("tester") => parse_tester_args(args), Some("--help") | Some("-h") => Ok(Command::Help), Some("--version") => Ok(Command::Version), _ => Ok(Command::NoSubcommand), @@ -244,63 +243,3 @@ pub struct RunnerArgs { pub executable: PathBuf, } -fn parse_tester_args(args: A) -> Result -where - A: Iterator, -{ - let mut arg_iter = args.into_iter().fuse(); - let test_path_arg = PathBuf::from( - arg_iter - .next() - .ok_or("excepted path to test source file as first argument")?, - ); - let test_path = test_path_arg.canonicalize().map_err(|err| { - format!( - "Failed to canonicalize test path `{}`: {}", - test_path_arg.display(), - err - ) - })?; - let mut run_command = None; - let mut target = None; - - loop { - match arg_iter.next().as_ref().map(|s| s.as_str()) { - Some("--command") => { - let old = mem::replace(&mut run_command, Some(arg_iter.collect())); - if !old.is_none() { - Err("multiple `--command` arguments")?; - } - break; - } - Some("--target") => { - let old = mem::replace(&mut target, arg_iter.next()); - if !old.is_none() { - Err("multiple `--target` arguments")?; - } - break; - } - Some("--help") | Some("-h") => { - return Ok(Command::TesterHelp); - } - Some("--version") => { - return Ok(Command::Version); - } - None => break, - Some(arg) => Err(format!("unexpected argument `{}`", arg))?, - } - } - - Ok(Command::Tester(TesterArgs { - test_path, - run_command, - target, - })) -} - -#[derive(Debug, Clone)] -pub struct TesterArgs { - pub test_path: PathBuf, - pub run_command: Option>, - pub target: Option, -} diff --git a/src/lib.rs b/src/lib.rs index c166502..1e00d15 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -use args::{Args, RunnerArgs, TesterArgs}; +use args::{Args, RunnerArgs}; use std::{fmt, process}; pub mod args; @@ -14,14 +14,12 @@ enum Command { Run(Args), Test(Args), Runner(RunnerArgs), - Tester(TesterArgs), Help, BuildHelp, RunHelp, TestHelp, CargoBootimageHelp, RunnerHelp, - TesterHelp, Version, } @@ -46,14 +44,13 @@ pub fn run() -> Result, ErrorString> { Command::Run(args) => subcommand::run::run(args).map(Some), Command::Test(args) => subcommand::test::test(args).map(none), Command::Runner(args) => subcommand::runner::runner(args).map(Some), - Command::Tester(args) => subcommand::tester::tester(args).map(none), Command::NoSubcommand => help::no_subcommand(), Command::Help => Ok(help::help()).map(none), Command::BuildHelp => Ok(help::build_help()).map(none), Command::RunHelp => Ok(help::run_help()).map(none), Command::TestHelp => Ok(help::test_help()).map(none), Command::Version => Ok(println!("bootimage {}", env!("CARGO_PKG_VERSION"))).map(none), - Command::RunnerHelp | Command::TesterHelp | Command::CargoBootimageHelp => unimplemented!(), + Command::RunnerHelp | Command::CargoBootimageHelp => unimplemented!(), } } diff --git a/src/subcommand.rs b/src/subcommand.rs index 0e49f4f..f848c46 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -2,4 +2,3 @@ pub mod build; pub mod run; pub mod runner; pub mod test; -pub mod tester; diff --git a/src/subcommand/tester.rs b/src/subcommand/tester.rs deleted file mode 100644 index 7fbd0ad..0000000 --- a/src/subcommand/tester.rs +++ /dev/null @@ -1,225 +0,0 @@ -use crate::{args::TesterArgs, builder::Builder, config, ErrorString}; -use std::{ - fs, - path::{Path, PathBuf}, - process, - process::Command, - time::Duration, -}; -use wait_timeout::ChildExt; - -pub(crate) fn tester(args: TesterArgs) -> Result<(), ErrorString> { - let builder = Builder::new(None)?; - let config = config::read_config(builder.kernel_manifest_path().to_owned())?; - - let test_name = args - .test_path - .file_stem() - .expect("no file stem") - .to_os_string() - .into_string() - .expect("test name invalid utf8"); - - let kernel_manifest_path = locate_cargo_manifest::locate_manifest().unwrap_or( - Path::new("Cargo.toml") - .canonicalize() - .expect("failed to canonicalize manifest path"), - ); - let kernel_root_path = kernel_manifest_path - .parent() - .expect("kernel manifest path has no parent"); - let kernel_manifest_content = - fs::read_to_string(&kernel_manifest_path).expect("failed to read kernel manifest"); - let kernel_manifest: toml::Value = kernel_manifest_content - .parse() - .expect("failed to parse Cargo.toml"); - - let kernel_name = kernel_manifest - .get("package") - .and_then(|p| p.get("name")) - .expect("no package.name found in Cargo.toml") - .as_str() - .expect("package name must be a string"); - let dependency_table = { - let mut table = toml::value::Table::new(); - let mut dependencies = kernel_manifest - .get("dependencies") - .map(|v| { - v.as_table() - .expect("`dependencies` must be a table in Cargo.toml") - .clone() - }) - .unwrap_or(toml::value::Table::new()); - dependencies.insert( - kernel_name.to_owned(), - toml::from_str(&format!(r#"path = "{}""#, kernel_root_path.display())).unwrap(), - ); - for (key, entry) in kernel_manifest - .get("dev-dependencies") - .map(|v| { - v.as_table() - .expect("`dev-dependencies` must be a table in Cargo.toml") - .clone() - }) - .unwrap_or(toml::value::Table::new()) - { - dependencies.insert(key, entry); - } - table.insert("dependencies".to_owned(), toml::Value::Table(dependencies)); - toml::Value::Table(table) - }; - - let kernel_target_dir = &builder.kernel_metadata().target_directory; - let integration_test_dir = kernel_target_dir.join("bootimage").join("tester"); - let out_dir = integration_test_dir.join(&test_name); - fs::create_dir_all(&out_dir).expect("failed to create out dir"); - - let manifest_path = out_dir.join("Cargo.toml"); - let manifest_content = format!( - r#" -[package] -authors = ["Bootimage Tester "] -name = "{test_name}" -version = "0.0.0" -edition = "2018" - -[workspace] # exclude this crate from parent workspaces - -[[bin]] -name = "bootimage-tester-{test_name}" -path = "{test_path}" - -{dependency_table} -"#, - test_name = test_name, - test_path = args.test_path.display(), - dependency_table = dependency_table - ); - - fs::write(&manifest_path, manifest_content)?; - - let cargo = std::env::var("CARGO").unwrap_or("cargo".to_owned()); - let build_command = || { - let mut cmd = Command::new(&cargo); - cmd.arg("xbuild"); - cmd.arg("--manifest-path").arg(&manifest_path); - cmd.arg("--target-dir").arg(&kernel_target_dir); - cmd.env("SYSROOT_DIR", &integration_test_dir.join("sysroot")); // for cargo-xbuild - - if let Some(target) = args.target.as_ref().or(config.default_target.as_ref()) { - cmd.arg("--target").arg(target); - } - cmd - }; - - let mut cmd = build_command(); - let output = cmd - .output() - .map_err(|err| format!("failed to run cargo xbuild: {}", err))?; - if !output.status.success() { - Err(format!( - "Test build failed:\n{}", - String::from_utf8_lossy(&output.stderr) - ))?; - } - - let mut cmd_json = build_command(); - cmd_json.arg("--message-format").arg("json"); - let output = cmd_json.output().map_err(|err| { - format!( - "failed to execute bootloader build command with json output: {}", - err - ) - })?; - if !output.status.success() { - Err(format!( - "Test build (with json output) failed:\n{}", - String::from_utf8_lossy(&output.stderr) - ))?; - } - let mut test_executable = None; - for line in String::from_utf8(output.stdout).unwrap().lines() { - let mut artifact = json::parse(line).unwrap(); - if let Some(executable) = artifact["executable"].take_string() { - if test_executable.replace(PathBuf::from(executable)).is_some() { - Err("integration test has multiple executables")?; - } - } - } - - let executable = test_executable.ok_or("no test executable")?; - let bootimage_bin_path = out_dir.join(format!("bootimage-{}.bin", test_name)); - builder.create_bootimage(&executable, &bootimage_bin_path, true)?; - - let run_cmd = args.run_command.clone().unwrap_or( - [ - "qemu-system-x86_64", - "-drive", - "format=raw,file={bootimage}", - "-device", - "isa-debug-exit,iobase=0xf4,iosize=0x04", - "-display", - "none", - "-serial", - "file:{output_file}", - ] - .into_iter() - .map(|&s| String::from(s)) - .collect(), - ); - - let output_file = out_dir.join(format!("output-{}.txt", test_name)); - - let mut command = process::Command::new(&run_cmd[0]); - for arg in &run_cmd[1..] { - command.arg( - arg.replace("{bootimage}", &format!("{}", bootimage_bin_path.display())) - .replace("{output_file}", &format!("{}", output_file.display())), - ); - } - command.stderr(process::Stdio::null()); - let mut child = command - .spawn() - .map_err(|e| format!("Failed to launch QEMU: {:?}\n{}", command, e))?; - let timeout = Duration::from_secs(config.test_timeout.into()); - let (exit_status, output) = match child - .wait_timeout(timeout) - .map_err(|e| format!("Failed to wait with timeout: {}", e))? - { - None => { - child - .kill() - .map_err(|e| format!("Failed to kill QEMU: {}", e))?; - child - .wait() - .map_err(|e| format!("Failed to wait for QEMU process: {}", e))?; - Err("Timed Out") - } - Some(exit_status) => { - let output = fs::read_to_string(&output_file).map_err(|e| { - format!( - "Failed to read test output file {}: {}", - output_file.display(), - e - ) - })?; - Ok((exit_status, output)) - } - }?; - - match exit_status.code() { - None => Err("No QEMU Exit Code")?, - Some(5) => {} // 2 << 1 | 1 - Some(7) => { - // 3 << 1 | 1 - let fail_index = output.rfind("bootimage:stderr\n"); - if let Some(index) = fail_index { - Err(format!("Test Failed:\n{}", &output[index..]))? - } else { - Err("Test Failed")? - } - } - Some(c) => Err(format!("Test returned with unexpected exit code {}", c))?, - } - Ok(()) -} From 9598497a3404889405bce676babba19b314df31f Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 18:42:00 +0200 Subject: [PATCH 34/50] Apply config.run_args for `bootimage run` too --- src/subcommand/run.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/subcommand/run.rs b/src/subcommand/run.rs index 287b195..fee5247 100644 --- a/src/subcommand/run.rs +++ b/src/subcommand/run.rs @@ -26,6 +26,9 @@ pub(crate) fn run(mut args: Args) -> Result { ), ); } + if let Some(run_args) = config.run_args { + command.args(run_args); + } command.args(&args.run_args); let exit_status = command.status().map_err(|err| { ErrorString::from(format!( From 683b3ee84ca67e009f3da3492b1a56aed4392890 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 21:17:45 +0200 Subject: [PATCH 35/50] Add a `--quiet` argument --- src/args.rs | 15 +++++++++++++++ src/subcommand/build.rs | 3 ++- src/subcommand/run.rs | 3 ++- src/subcommand/runner.rs | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/args.rs b/src/args.rs index 4c9ffd4..f40104e 100644 --- a/src/args.rs +++ b/src/args.rs @@ -47,6 +47,7 @@ where let mut cargo_args = Vec::new(); let mut run_args = Vec::new(); let mut run_args_started = false; + let mut quiet = false; { fn set(arg: &mut Option, value: Option) -> Result<(), ErrorString> { let previous = mem::replace(arg, value); @@ -69,6 +70,9 @@ where "--version" => { return Ok(Command::Version); } + "--quiet" => { + quiet = true; + } "--bin" => { let next = arg_iter.next(); set(&mut bin_name, next.clone())?; @@ -142,6 +146,7 @@ where target, manifest_path, release: release.unwrap_or(false), + quiet, })) } @@ -151,6 +156,8 @@ pub struct Args { pub cargo_args: Vec, /// All arguments that are passed to the runner. pub run_args: Vec, + /// Suppress any output to stdout. + pub quiet: bool, /// The manifest path (also present in `cargo_args`). manifest_path: Option, /// The name of the binary (passed `--bin` argument) (also present in `cargo_args`). @@ -207,6 +214,8 @@ where A: Iterator, { let mut executable = None; + let mut quiet = false; + let mut arg_iter = args.into_iter().fuse(); loop { @@ -217,6 +226,9 @@ where Some("--version") => { return Ok(Command::Version); } + Some("--quiet") => { + quiet = true; + } Some(exe) if executable.is_none() => { let path = Path::new(exe); let path_canonicalized = path.canonicalize().map_err(|err| { @@ -235,11 +247,14 @@ where Ok(Command::Runner(RunnerArgs { executable: executable.ok_or("excepted path to kernel executable as first argument")?, + quiet, })) } #[derive(Debug, Clone)] pub struct RunnerArgs { pub executable: PathBuf, + /// Suppress any output to stdout. + pub quiet: bool, } diff --git a/src/subcommand/build.rs b/src/subcommand/build.rs index 4b496b8..ea6bc54 100644 --- a/src/subcommand/build.rs +++ b/src/subcommand/build.rs @@ -6,7 +6,8 @@ pub(crate) fn build(mut args: Args) -> Result<(), ErrorString> { let config = config::read_config(builder.kernel_manifest_path().to_owned())?; args.apply_default_target(&config, builder.kernel_root()); - build_impl(&builder, &mut args, false).map(|_| ()) + let quiet = args.quiet; + build_impl(&builder, &mut args, quiet).map(|_| ()) } pub(crate) fn build_impl( diff --git a/src/subcommand/run.rs b/src/subcommand/run.rs index fee5247..b505b80 100644 --- a/src/subcommand/run.rs +++ b/src/subcommand/run.rs @@ -8,7 +8,8 @@ pub(crate) fn run(mut args: Args) -> Result { let config = config::read_config(builder.kernel_manifest_path().to_owned())?; args.apply_default_target(&config, builder.kernel_root()); - let bootimages = build::build_impl(&builder, &mut args, false)?; + let quiet = args.quiet; + let bootimages = build::build_impl(&builder, &mut args, quiet)?; let bootimage_path = bootimages.first().ok_or("no bootimages created")?; if bootimages.len() > 1 { Err("more than one bootimage created")?; diff --git a/src/subcommand/runner.rs b/src/subcommand/runner.rs index 6c0dc6b..1815b52 100644 --- a/src/subcommand/runner.rs +++ b/src/subcommand/runner.rs @@ -19,7 +19,7 @@ pub(crate) fn runner(args: RunnerArgs) -> Result { parent.join(format!("bootimage-{}.bin", file_stem)) }; - builder.create_bootimage(&args.executable, &bootimage_bin, false)?; + builder.create_bootimage(&args.executable, &bootimage_bin, args.quiet)?; let mut command = process::Command::new(&config.run_command[0]); for arg in &config.run_command[1..] { From cd7d510dd8a728f481724928e469684689e51508 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 21:18:17 +0200 Subject: [PATCH 36/50] Update changelog --- Changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.md b/Changelog.md index 160b0c4..34684ed 100644 --- a/Changelog.md +++ b/Changelog.md @@ -9,6 +9,7 @@ - Remove support for `bootloader_precompiled` - The `bootloader` crate compiles fine on all architectures for some time and should be prefered - Require the `llvm-tools-preview` rustup component +- Pass the QEMU exit code in `bootimage run` ## Other @@ -20,6 +21,8 @@ - Refactor and cleanup the code - Remove the dependency on `failure` - Use a custom `ErrorString` type instead +- Add a new `run-args` config key +- Add a new `--quiet` argument to suppress output # 0.6.6 From a703656e584f56c6a264f849086fbae5505d30a8 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 21:19:25 +0200 Subject: [PATCH 37/50] Remove travis CI script --- .travis.yml | 46 ---------------------------------------------- bors.toml | 2 +- 2 files changed, 1 insertion(+), 47 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9ed6fec..0000000 --- a/.travis.yml +++ /dev/null @@ -1,46 +0,0 @@ -language: rust - -sudo: false - -notifications: - email: - on_success: never - on_failure: change - -rust: - - nightly - - stable - - beta - -os: - - linux - - osx - - windows - -cache: - cargo: true - directories: - - $HOME/Library/Caches/Homebrew - -addons: - apt: - packages: - - qemu-system-x86 - homebrew: - packages: - - qemu - -install: - - if [ $TRAVIS_OS_NAME = windows ]; then choco install qemu; export PATH="/c/Program Files/qemu:$PATH"; fi - -before_script: - - rustup component add rust-src - - (test -x $HOME/.cargo/bin/cargo-update-installed || cargo install cargo-update-installed) - - (test -x $HOME/.cargo/bin/cargo-xbuild || cargo install cargo-xbuild) - - cargo update-installed - -script: -- cargo test -- cargo install --debug --force -- git clone https://github.com/phil-opp/blog_os.git --branch post-10 -- if [ $TRAVIS_RUST_VERSION = nightly ]; then bootimage test --manifest-path blog_os/Cargo.toml; fi diff --git a/bors.toml b/bors.toml index 574c563..9c47331 100644 --- a/bors.toml +++ b/bors.toml @@ -1,4 +1,4 @@ status = [ - "continuous-integration/travis-ci/push", + "rust-osdev.bootimage", ] delete_merged_branches = true From 2517b94bc686e52f57a04216ead68883625ffac2 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 21:31:18 +0200 Subject: [PATCH 38/50] Update Readme --- Readme.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/Readme.md b/Readme.md index ba964f7..03fa576 100644 --- a/Readme.md +++ b/Readme.md @@ -10,7 +10,7 @@ Creates a bootable disk image from a Rust OS kernel. ## Usage -First you need to add a dependency on the `bootloader` crate: +First you need to add a dependency on the [`bootloader`](https://github.com/rust-osdev/bootloader) crate: ```toml # in your Cargo.toml @@ -21,30 +21,72 @@ bootloader = "0.5.0" **Note**: At least bootloader version `0.5.0` is required. +If you want to use a custom bootloader with a different name, you can use Cargo's [rename functionality](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml). + +### Building + Now you can build the kernel project and create a bootable disk image from it by running: ``` -> bootimage build --target your_custom_target.json [other_args] +bootimage build --target your_custom_target.json [other_args] ``` The command will invoke [`cargo xbuild`](https://github.com/rust-osdev/cargo-xbuild), forwarding all passed options. Then it will build the specified bootloader together with the kernel to create a bootable disk image. +If you prefer a cargo subcommand, you can use the equivalent `cargo bootimage` command: + +``` +cargo bootimage --target your_custom_target.json [other_args] +``` + +### Running + +To run your kernel in QEMU, you can use `bootimage run`: + +``` +bootimage run --target your_custom_target.json [other_args] -- [qemu args] +``` + +All arguments after `--` are passed to QEMU. If you want to use a custom run command, see the _Configuration_ section below. + +If you prefer working directly with cargo, you can use `bootimage runner` as a custom runner in your `.cargo/config`: + +```toml +[target.'cfg(target_os = "none")'] +runner = "bootimage runner" +``` + +Now you can run your kernel through `cargo xrun --target […]`. + ## Configuration -Configuration is done through a through a `[package.metadata.bootimage]` table in the `Cargo.toml`. The following options are available: +Configuration is done through a through a `[package.metadata.bootimage]` table in the `Cargo.toml` of your kernel. The following options are available: ```toml [package.metadata.bootimage] # This target is used if no `--target` is passed default-target = "" - # The command invoked on `bootimage run` + # The command invoked on `bootimage run` or `bootimage runner` # (the "{}" will be replaced with the path to the bootable disk image) run-command = ["qemu-system-x86_64", "-drive", "format=raw,file={}"] - # The timeout for running an integration test in seconds + # Additional arguments passed to the runner on `bootimage run` or `bootimage runner` + # (this is useful when you want to add some arguments to the default QEMU command) + run-args = [] + + # The timeout for running an integration test through `bootimage test` in seconds test-timeout = 300 ``` ## License -Dual-licensed under MIT or the Apache License (Version 2.0). + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. From 2e892808a5b0736c66db3d5df6d4f4e626183d55 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 21:39:32 +0200 Subject: [PATCH 39/50] Remove unused `ExitCode` field of `ErrorString` --- src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1e00d15..681f181 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,7 @@ pub fn lib_main() { match run() { Err(err) => { eprintln!("Error: {}", err.message); - process::exit(err.exit_code); + process::exit(1); } Ok(Some(exit_code)) => { process::exit(exit_code); @@ -56,7 +56,6 @@ pub fn run() -> Result, ErrorString> { pub struct ErrorString { pub message: Box, - pub exit_code: i32, } impl fmt::Debug for ErrorString { @@ -72,7 +71,6 @@ where fn from(err: T) -> Self { ErrorString { message: Box::new(err), - exit_code: 1, } } } From 667bb265da6ac8db00f09295be642d7348ae4f00 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 21:41:11 +0200 Subject: [PATCH 40/50] Rename `ErrorString` to `ErrorMessage` --- Changelog.md | 2 +- src/args.rs | 11 +++++------ src/config.rs | 6 +++--- src/lib.rs | 10 +++++----- src/subcommand/build.rs | 6 +++--- src/subcommand/run.rs | 8 ++++---- src/subcommand/runner.rs | 4 ++-- src/subcommand/test.rs | 8 ++++---- 8 files changed, 27 insertions(+), 28 deletions(-) diff --git a/Changelog.md b/Changelog.md index 34684ed..2b3c486 100644 --- a/Changelog.md +++ b/Changelog.md @@ -20,7 +20,7 @@ - Move crate to 2018 edition - Refactor and cleanup the code - Remove the dependency on `failure` - - Use a custom `ErrorString` type instead + - Use a custom `ErrorMessage` type instead - Add a new `run-args` config key - Add a new `--quiet` argument to suppress output diff --git a/src/args.rs b/src/args.rs index f40104e..b65aa3b 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,8 +1,8 @@ -use crate::{config::Config, Command, ErrorString}; +use crate::{config::Config, Command, ErrorMessage}; use std::path::{Path, PathBuf}; use std::{env, mem}; -pub(crate) fn parse_args() -> Result { +pub(crate) fn parse_args() -> Result { let mut args = env::args(); let executable_name = args.next().ok_or("no first argument (executable name)")?; let first = args.next(); @@ -36,7 +36,7 @@ pub(crate) fn parse_args() -> Result { } } -fn parse_build_args(args: A) -> Result +fn parse_build_args(args: A) -> Result where A: Iterator, { @@ -49,7 +49,7 @@ where let mut run_args_started = false; let mut quiet = false; { - fn set(arg: &mut Option, value: Option) -> Result<(), ErrorString> { + fn set(arg: &mut Option, value: Option) -> Result<(), ErrorMessage> { let previous = mem::replace(arg, value); if previous.is_some() { Err("multiple arguments of same type provided")? @@ -209,7 +209,7 @@ impl Args { } } -fn parse_runner_args(args: A) -> Result +fn parse_runner_args(args: A) -> Result where A: Iterator, { @@ -257,4 +257,3 @@ pub struct RunnerArgs { /// Suppress any output to stdout. pub quiet: bool, } - diff --git a/src/config.rs b/src/config.rs index 6f10e20..2b3f4fc 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,4 @@ -use crate::ErrorString; +use crate::ErrorMessage; use std::path::PathBuf; use toml::Value; @@ -11,13 +11,13 @@ pub struct Config { pub test_timeout: u32, } -pub(crate) fn read_config(manifest_path: PathBuf) -> Result { +pub(crate) fn read_config(manifest_path: PathBuf) -> Result { let config = read_config_inner(manifest_path) .map_err(|err| format!("Failed to read bootimage configuration: {:?}", err))?; Ok(config) } -pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result { +pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result { use std::{fs::File, io::Read}; let cargo_toml: Value = { let mut content = String::new(); diff --git a/src/lib.rs b/src/lib.rs index 681f181..e66f392 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,7 +36,7 @@ pub fn lib_main() { } } -pub fn run() -> Result, ErrorString> { +pub fn run() -> Result, ErrorMessage> { let command = args::parse_args()?; let none = |()| None; match command { @@ -54,22 +54,22 @@ pub fn run() -> Result, ErrorString> { } } -pub struct ErrorString { +pub struct ErrorMessage { pub message: Box, } -impl fmt::Debug for ErrorString { +impl fmt::Debug for ErrorMessage { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.message.fmt(f) } } -impl From for ErrorString +impl From for ErrorMessage where T: fmt::Display + Send + 'static, { fn from(err: T) -> Self { - ErrorString { + ErrorMessage { message: Box::new(err), } } diff --git a/src/subcommand/build.rs b/src/subcommand/build.rs index ea6bc54..c96b0d3 100644 --- a/src/subcommand/build.rs +++ b/src/subcommand/build.rs @@ -1,7 +1,7 @@ -use crate::{args::Args, builder::Builder, config, ErrorString}; +use crate::{args::Args, builder::Builder, config, ErrorMessage}; use std::{path::PathBuf, process}; -pub(crate) fn build(mut args: Args) -> Result<(), ErrorString> { +pub(crate) fn build(mut args: Args) -> Result<(), ErrorMessage> { let builder = Builder::new(args.manifest_path().clone())?; let config = config::read_config(builder.kernel_manifest_path().to_owned())?; args.apply_default_target(&config, builder.kernel_root()); @@ -14,7 +14,7 @@ pub(crate) fn build_impl( builder: &Builder, args: &Args, quiet: bool, -) -> Result, ErrorString> { +) -> Result, ErrorMessage> { run_cargo_fetch(&args); let executables = builder.build_kernel(&args.cargo_args, quiet)?; diff --git a/src/subcommand/run.rs b/src/subcommand/run.rs index b505b80..df42e51 100644 --- a/src/subcommand/run.rs +++ b/src/subcommand/run.rs @@ -1,7 +1,7 @@ -use crate::{args::Args, builder::Builder, config, ErrorString}; +use crate::{args::Args, builder::Builder, config, ErrorMessage}; use std::process; -pub(crate) fn run(mut args: Args) -> Result { +pub(crate) fn run(mut args: Args) -> Result { use crate::subcommand::build; let builder = Builder::new(args.manifest_path().clone())?; @@ -23,7 +23,7 @@ pub(crate) fn run(mut args: Args) -> Result { "{}", bootimage_path .to_str() - .ok_or(ErrorString::from("bootimage path is not valid unicode"))?, + .ok_or(ErrorMessage::from("bootimage path is not valid unicode"))?, ), ); } @@ -32,7 +32,7 @@ pub(crate) fn run(mut args: Args) -> Result { } command.args(&args.run_args); let exit_status = command.status().map_err(|err| { - ErrorString::from(format!( + ErrorMessage::from(format!( "Failed to execute run command `{:?}`: {}", command, err )) diff --git a/src/subcommand/runner.rs b/src/subcommand/runner.rs index 1815b52..4cb72db 100644 --- a/src/subcommand/runner.rs +++ b/src/subcommand/runner.rs @@ -1,7 +1,7 @@ -use crate::{args::RunnerArgs, builder::Builder, config, ErrorString}; +use crate::{args::RunnerArgs, builder::Builder, config, ErrorMessage}; use std::process; -pub(crate) fn runner(args: RunnerArgs) -> Result { +pub(crate) fn runner(args: RunnerArgs) -> Result { let builder = Builder::new(None)?; let config = config::read_config(builder.kernel_manifest_path().to_owned())?; diff --git a/src/subcommand/test.rs b/src/subcommand/test.rs index b93f1e0..858ecc2 100644 --- a/src/subcommand/test.rs +++ b/src/subcommand/test.rs @@ -1,9 +1,9 @@ -use crate::{args::Args, builder::Builder, config, subcommand::build, ErrorString}; +use crate::{args::Args, builder::Builder, config, subcommand::build, ErrorMessage}; use rayon::prelude::*; use std::{fs, io, io::Write, process, time::Duration}; use wait_timeout::ChildExt; -pub(crate) fn test(mut args: Args) -> Result<(), ErrorString> { +pub(crate) fn test(mut args: Args) -> Result<(), ErrorMessage> { let builder = Builder::new(args.manifest_path().clone())?; let config = config::read_config(builder.kernel_manifest_path().to_owned())?; args.apply_default_target(&config, builder.kernel_root()); @@ -83,7 +83,7 @@ pub(crate) fn test(mut args: Args) -> Result<(), ErrorString> { Ok((target.name.clone(), test_result)) }) - .collect::, ErrorString>>()?; + .collect::, ErrorMessage>>()?; println!(""); if tests.iter().all(|t| t.1 == TestResult::Ok) { @@ -102,7 +102,7 @@ fn handle_exit_status( exit_status: process::ExitStatus, output: &str, target_name: &str, -) -> Result { +) -> Result { match exit_status.code() { None => { writeln!(io::stderr(), "FAIL: No Exit Code.")?; From c6f5afdd22b25d38d34b0784910f6d088e226875 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 23:04:15 +0200 Subject: [PATCH 41/50] Make args module private and remove unused methods --- src/args.rs | 8 -------- src/lib.rs | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/args.rs b/src/args.rs index b65aa3b..80ea78e 100644 --- a/src/args.rs +++ b/src/args.rs @@ -173,18 +173,10 @@ impl Args { &self.manifest_path } - pub fn bin_name(&self) -> &Option { - &self.bin_name - } - pub fn target(&self) -> &Option { &self.target } - pub fn release(&self) -> bool { - self.release - } - pub fn set_target(&mut self, target: String) { assert!(self.target.is_none()); self.target = Some(target.clone()); diff --git a/src/lib.rs b/src/lib.rs index e66f392..86f2a3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ use args::{Args, RunnerArgs}; use std::{fmt, process}; -pub mod args; pub mod builder; +mod args; pub mod config; pub mod help; From 211415dfae0c98d66a670b597d88a48dfe3ccac9 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 23:05:12 +0200 Subject: [PATCH 42/50] Remove remaining unwraps in builder module --- src/builder.rs | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 7ae70af..6a4ee3a 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -96,8 +96,12 @@ impl Builder { }); } let mut executables = Vec::new(); - for line in String::from_utf8(output.stdout).unwrap().lines() { - let mut artifact = json::parse(line).unwrap(); + for line in String::from_utf8(output.stdout) + .map_err(BuildKernelError::XbuildJsonOutputInvalidUtf8)? + .lines() + { + let mut artifact = + json::parse(line).map_err(BuildKernelError::XbuildJsonOutputInvalidJson)?; if let Some(executable) = artifact["executable"].take_string() { executables.push(PathBuf::from(executable)); } @@ -233,8 +237,12 @@ impl Builder { }); } let mut bootloader_elf_path = None; - for line in String::from_utf8(output.stdout).unwrap().lines() { - let mut artifact = json::parse(line).unwrap(); + for line in String::from_utf8(output.stdout) + .map_err(CreateBootimageError::XbuildJsonOutputInvalidUtf8)? + .lines() + { + let mut artifact = + json::parse(line).map_err(CreateBootimageError::XbuildJsonOutputInvalidJson)?; if let Some(executable) = artifact["executable"].take_string() { if bootloader_elf_path .replace(PathBuf::from(executable)) @@ -316,10 +324,8 @@ pub enum BuildKernelError { XbuildFailed { stderr: Vec, }, - CargoConfigInvalid { - path: PathBuf, - error: String, - }, + XbuildJsonOutputInvalidUtf8(std::string::FromUtf8Error), + XbuildJsonOutputInvalidJson(json::Error), } impl fmt::Display for BuildKernelError { @@ -338,9 +344,12 @@ impl fmt::Display for BuildKernelError { BuildKernelError::XbuildFailed{stderr} => { writeln!(f, "Kernel build failed:\n{}", String::from_utf8_lossy(stderr)) } - BuildKernelError::CargoConfigInvalid{path,error} => { - writeln!(f, "Failed to read cargo config at {}:\n{}", path.display(), error) - }, + BuildKernelError::XbuildJsonOutputInvalidUtf8(err) => { + writeln!(f, "Output of kernel build with --message-format=json is not valid UTF-8:\n{}", err) + } + BuildKernelError::XbuildJsonOutputInvalidJson(err) => { + writeln!(f, "Output of kernel build with --message-format=json is not valid JSON:\n{}", err) + } } } } @@ -374,6 +383,8 @@ pub enum CreateBootimageError { ObjcopyFailed { stderr: Vec, }, + XbuildJsonOutputInvalidUtf8(std::string::FromUtf8Error), + XbuildJsonOutputInvalidJson(json::Error), } impl fmt::Display for CreateBootimageError { @@ -422,6 +433,16 @@ impl fmt::Display for CreateBootimageError { "Failed to run `llvm-objcopy`: {}", String::from_utf8_lossy(stderr) ), + CreateBootimageError::XbuildJsonOutputInvalidUtf8(err) => writeln!( + f, + "Output of bootloader build with --message-format=json is not valid UTF-8:\n{}", + err + ), + CreateBootimageError::XbuildJsonOutputInvalidJson(err) => writeln!( + f, + "Output of bootloader build with --message-format=json is not valid JSON:\n{}", + err + ), } } } From 48d7b803f2c229a8083b5b158a7d37f50d48f38a Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 23:13:23 +0200 Subject: [PATCH 43/50] Make BuildKernelError and CreateBootimageError non-exhaustive --- src/builder.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/builder.rs b/src/builder.rs index 6a4ee3a..f23f8e2 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -326,6 +326,8 @@ pub enum BuildKernelError { }, XbuildJsonOutputInvalidUtf8(std::string::FromUtf8Error), XbuildJsonOutputInvalidJson(json::Error), + #[doc(hidden)] + __NonExhaustive, } impl fmt::Display for BuildKernelError { @@ -350,6 +352,7 @@ impl fmt::Display for BuildKernelError { BuildKernelError::XbuildJsonOutputInvalidJson(err) => { writeln!(f, "Output of kernel build with --message-format=json is not valid JSON:\n{}", err) } + BuildKernelError::__NonExhaustive => panic!("__NonExhaustive variant constructed"), } } } @@ -385,6 +388,8 @@ pub enum CreateBootimageError { }, XbuildJsonOutputInvalidUtf8(std::string::FromUtf8Error), XbuildJsonOutputInvalidJson(json::Error), + #[doc(hidden)] + __NonExhaustive, } impl fmt::Display for CreateBootimageError { @@ -443,6 +448,7 @@ impl fmt::Display for CreateBootimageError { "Output of bootloader build with --message-format=json is not valid JSON:\n{}", err ), + CreateBootimageError::__NonExhaustive => panic!("__NonExhaustive variant constructed"), } } } From 1e8306bddb4a09fa59e426aaa756c862610b1ced Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 23:22:54 +0200 Subject: [PATCH 44/50] Remove unused config.manifest_path field --- src/config.rs | 22 ++++++---------------- src/subcommand/build.rs | 2 +- src/subcommand/run.rs | 2 +- src/subcommand/runner.rs | 2 +- src/subcommand/test.rs | 2 +- 5 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/config.rs b/src/config.rs index 2b3f4fc..3c3b3be 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,27 +1,26 @@ use crate::ErrorMessage; -use std::path::PathBuf; +use std::path::Path; use toml::Value; #[derive(Debug, Clone)] pub struct Config { - pub manifest_path: PathBuf, pub default_target: Option, pub run_command: Vec, pub run_args: Option>, pub test_timeout: u32, } -pub(crate) fn read_config(manifest_path: PathBuf) -> Result { +pub(crate) fn read_config(manifest_path: &Path) -> Result { let config = read_config_inner(manifest_path) .map_err(|err| format!("Failed to read bootimage configuration: {:?}", err))?; Ok(config) } -pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result { +pub(crate) fn read_config_inner(manifest_path: &Path) -> Result { use std::{fs::File, io::Read}; let cargo_toml: Value = { let mut content = String::new(); - File::open(&manifest_path) + File::open(manifest_path) .map_err(|e| format!("Failed to open Cargo.toml: {}", e))? .read_to_string(&mut content) .map_err(|e| format!("Failed to read Cargo.toml: {}", e))?; @@ -36,21 +35,14 @@ pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result { - return Ok(ConfigBuilder { - manifest_path: Some(manifest_path), - ..Default::default() - } - .into()); + return Ok(ConfigBuilder::default().into()); } Some(metadata) => metadata .as_table() .ok_or(format!("Bootimage configuration invalid: {:?}", metadata))?, }; - let mut config = ConfigBuilder { - manifest_path: Some(manifest_path), - ..Default::default() - }; + let mut config = ConfigBuilder::default(); for (key, value) in metadata { match (key.as_str(), value.clone()) { @@ -93,7 +85,6 @@ pub(crate) fn read_config_inner(manifest_path: PathBuf) -> Result, default_target: Option, run_command: Option>, run_args: Option>, @@ -103,7 +94,6 @@ struct ConfigBuilder { impl Into for ConfigBuilder { fn into(self) -> Config { Config { - manifest_path: self.manifest_path.expect("manifest path must be set"), default_target: self.default_target, run_command: self.run_command.unwrap_or(vec![ "qemu-system-x86_64".into(), diff --git a/src/subcommand/build.rs b/src/subcommand/build.rs index c96b0d3..0a86d2d 100644 --- a/src/subcommand/build.rs +++ b/src/subcommand/build.rs @@ -3,7 +3,7 @@ use std::{path::PathBuf, process}; pub(crate) fn build(mut args: Args) -> Result<(), ErrorMessage> { let builder = Builder::new(args.manifest_path().clone())?; - let config = config::read_config(builder.kernel_manifest_path().to_owned())?; + let config = config::read_config(builder.kernel_manifest_path())?; args.apply_default_target(&config, builder.kernel_root()); let quiet = args.quiet; diff --git a/src/subcommand/run.rs b/src/subcommand/run.rs index df42e51..e83b8dd 100644 --- a/src/subcommand/run.rs +++ b/src/subcommand/run.rs @@ -5,7 +5,7 @@ pub(crate) fn run(mut args: Args) -> Result { use crate::subcommand::build; let builder = Builder::new(args.manifest_path().clone())?; - let config = config::read_config(builder.kernel_manifest_path().to_owned())?; + let config = config::read_config(builder.kernel_manifest_path())?; args.apply_default_target(&config, builder.kernel_root()); let quiet = args.quiet; diff --git a/src/subcommand/runner.rs b/src/subcommand/runner.rs index 4cb72db..f00e4de 100644 --- a/src/subcommand/runner.rs +++ b/src/subcommand/runner.rs @@ -3,7 +3,7 @@ use std::process; pub(crate) fn runner(args: RunnerArgs) -> Result { let builder = Builder::new(None)?; - let config = config::read_config(builder.kernel_manifest_path().to_owned())?; + let config = config::read_config(builder.kernel_manifest_path())?; let bootimage_bin = { let parent = args diff --git a/src/subcommand/test.rs b/src/subcommand/test.rs index 858ecc2..6373959 100644 --- a/src/subcommand/test.rs +++ b/src/subcommand/test.rs @@ -5,7 +5,7 @@ use wait_timeout::ChildExt; pub(crate) fn test(mut args: Args) -> Result<(), ErrorMessage> { let builder = Builder::new(args.manifest_path().clone())?; - let config = config::read_config(builder.kernel_manifest_path().to_owned())?; + let config = config::read_config(builder.kernel_manifest_path())?; args.apply_default_target(&config, builder.kernel_root()); let test_args = args.clone(); From 3d9e95c98484471b30e94a6e691b38875e944d6e Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 23:23:52 +0200 Subject: [PATCH 45/50] Make config::Config struct non-exhaustive --- src/config.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/config.rs b/src/config.rs index 3c3b3be..6b80a55 100644 --- a/src/config.rs +++ b/src/config.rs @@ -8,6 +8,7 @@ pub struct Config { pub run_command: Vec, pub run_args: Option>, pub test_timeout: u32, + non_exhaustive: (), } pub(crate) fn read_config(manifest_path: &Path) -> Result { @@ -102,6 +103,7 @@ impl Into for ConfigBuilder { ]), run_args: self.run_args, test_timeout: self.test_timeout.unwrap_or(60 * 5), + non_exhaustive: (), } } } From df26d3e48bbbec8424b090e88e059bcac467cdc4 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 23:29:05 +0200 Subject: [PATCH 46/50] Remove now unused `tester` example crate --- example-kernels/Cargo.lock | 8 ------ example-kernels/Cargo.toml | 1 - example-kernels/tester/.gitignore | 2 -- example-kernels/tester/Cargo.toml | 9 ------- example-kernels/tester/build.rs | 27 ------------------- example-kernels/tester/src/lib.rs | 21 --------------- .../tester/tests/integration_tests.rs | 16 ----------- .../integration_tests/test-basic-boot.rs | 27 ------------------- .../tests/integration_tests/test-panic.rs | 21 --------------- 9 files changed, 132 deletions(-) delete mode 100644 example-kernels/tester/.gitignore delete mode 100644 example-kernels/tester/Cargo.toml delete mode 100644 example-kernels/tester/build.rs delete mode 100644 example-kernels/tester/src/lib.rs delete mode 100644 example-kernels/tester/tests/integration_tests.rs delete mode 100644 example-kernels/tester/tests/integration_tests/test-basic-boot.rs delete mode 100644 example-kernels/tester/tests/integration_tests/test-panic.rs diff --git a/example-kernels/Cargo.lock b/example-kernels/Cargo.lock index cd749b3..01c75f4 100644 --- a/example-kernels/Cargo.lock +++ b/example-kernels/Cargo.lock @@ -230,14 +230,6 @@ dependencies = [ "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tester" -version = "0.1.0" -dependencies = [ - "bootloader 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "testing-qemu-exit-code" version = "0.1.0" diff --git a/example-kernels/Cargo.toml b/example-kernels/Cargo.toml index 03cc7ed..ede58ed 100644 --- a/example-kernels/Cargo.toml +++ b/example-kernels/Cargo.toml @@ -4,7 +4,6 @@ members = [ "default-target-bootimage", "default-target-cargo", "runner", - "tester", "testing-qemu-exit-code", "testing-serial-result", ] \ No newline at end of file diff --git a/example-kernels/tester/.gitignore b/example-kernels/tester/.gitignore deleted file mode 100644 index eccd7b4..0000000 --- a/example-kernels/tester/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target/ -**/*.rs.bk diff --git a/example-kernels/tester/Cargo.toml b/example-kernels/tester/Cargo.toml deleted file mode 100644 index 73c86fc..0000000 --- a/example-kernels/tester/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "tester" -version = "0.1.0" -authors = ["Philipp Oppermann "] -edition = "2018" - -[dependencies] -bootloader = "0.5.0" -x86_64 = "0.5.3" diff --git a/example-kernels/tester/build.rs b/example-kernels/tester/build.rs deleted file mode 100644 index fd1c011..0000000 --- a/example-kernels/tester/build.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::{env, fs::File, io::Write, path::Path}; - -fn main() { - let out_dir = env::var("OUT_DIR").unwrap(); - let dest_path = Path::new(&out_dir).join("generated_tests.rs"); - let mut tests = File::create(&dest_path).unwrap(); - for entry in Path::new("tests").join("integration_tests").read_dir().expect("failed to read tests/integration tests") { - let entry = entry.expect("failed to read dir entry"); - assert!(entry.file_type().unwrap().is_file()); - let test_path = entry.path(); - let test_name = test_path.file_stem().expect("no file stem").to_os_string().into_string().expect("file name not valid utf8"); - - let content = format!(r#" -#[test] -fn {test_name}() {{ - run_test("{test_path}"); -}} -"#, test_name = test_name.replace("-", "_"), test_path = test_path.display()); - - tests.write_all(content.as_bytes()).expect("failed to write test"); - - println!("cargo:rerun-if-changed={}", entry.path().display()); - } - - println!("cargo:rustc-env=GENERATED_TESTS={}", dest_path.display()); - println!("cargo:rerun-if-changed=build.rs"); -} diff --git a/example-kernels/tester/src/lib.rs b/example-kernels/tester/src/lib.rs deleted file mode 100644 index cdc0ba8..0000000 --- a/example-kernels/tester/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![cfg_attr(not(test), no_std)] -#![feature(abi_x86_interrupt)] - -#[repr(u32)] -pub enum ExitCode { - Success = 2, - Failure = 3, -} - -pub unsafe fn exit_qemu(exit_code: ExitCode) { - use x86_64::instructions::port::Port; - - let mut port = Port::::new(0xf4); - port.write(exit_code as u32); -} - -pub fn hlt_loop() -> ! { - loop { - x86_64::instructions::hlt(); - } -} diff --git a/example-kernels/tester/tests/integration_tests.rs b/example-kernels/tester/tests/integration_tests.rs deleted file mode 100644 index 352e413..0000000 --- a/example-kernels/tester/tests/integration_tests.rs +++ /dev/null @@ -1,16 +0,0 @@ -use std::path::Path; - -include!(env!("GENERATED_TESTS")); - -fn run_test(test_path: &str) { - let mut cmd = std::process::Command::new("bootimage"); - cmd.arg("tester"); - cmd.arg(Path::new(test_path)); - cmd.arg("--target"); - cmd.arg("../x86_64-bootimage-example-kernels.json"); - let output = cmd.output().expect("failed to run bootimage"); - if !output.status.success() { - eprintln!("{}", String::from_utf8_lossy(&output.stderr)); - panic!("test failed"); - } -} \ No newline at end of file diff --git a/example-kernels/tester/tests/integration_tests/test-basic-boot.rs b/example-kernels/tester/tests/integration_tests/test-basic-boot.rs deleted file mode 100644 index 02de359..0000000 --- a/example-kernels/tester/tests/integration_tests/test-basic-boot.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![cfg_attr(not(test), no_std)] -#![cfg_attr(not(test), no_main)] // disable all Rust-level entry points -#![cfg_attr(test, allow(unused_imports))] - -use tester::{exit_qemu, ExitCode}; -use core::panic::PanicInfo; - -/// This function is the entry point, since the linker looks for a function -/// named `_start` by default. -#[cfg(not(test))] -#[no_mangle] // don't mangle the name of this function -pub extern "C" fn _start() -> ! { - unsafe { - exit_qemu(ExitCode::Success); - } - loop {} -} - -/// This function is called on panic. -#[cfg(not(test))] -#[panic_handler] -fn panic(info: &PanicInfo) -> ! { - unsafe { - exit_qemu(ExitCode::Failure); - } - loop {} -} diff --git a/example-kernels/tester/tests/integration_tests/test-panic.rs b/example-kernels/tester/tests/integration_tests/test-panic.rs deleted file mode 100644 index 5a7d176..0000000 --- a/example-kernels/tester/tests/integration_tests/test-panic.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![cfg_attr(not(test), no_std)] -#![cfg_attr(not(test), no_main)] -#![cfg_attr(test, allow(unused_imports))] - -use tester::{exit_qemu, ExitCode}; -use core::panic::PanicInfo; - -#[cfg(not(test))] -#[no_mangle] -pub extern "C" fn _start() -> ! { - panic!(); -} - -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - unsafe { - exit_qemu(ExitCode::Success); - } - loop {} -} From 2e73c32908f0c8d6db8f882d08627ef7a0eb3478 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 23:30:11 +0200 Subject: [PATCH 47/50] Document all library types --- src/args.rs | 2 ++ src/builder.rs | 34 ++++++++++++++++++++++++++++++++++ src/config.rs | 13 +++++++++++++ src/lib.rs | 27 ++++++++++++++++++++++++++- 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/args.rs b/src/args.rs index 80ea78e..05ea511 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,3 +1,5 @@ +//! Parses command line arguments. + use crate::{config::Config, Command, ErrorMessage}; use std::path::{Path, PathBuf}; use std::{env, mem}; diff --git a/src/builder.rs b/src/builder.rs index f23f8e2..f0e78ad 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,15 +1,21 @@ +//! Provides functions to build the kernel and the bootloader. + use std::{ fmt, fs, io, path::{Path, PathBuf}, process::{self, Command}, }; +/// Abstracts a build environment and provides methods for building the kernel and creating a +/// bootimage. pub struct Builder { kernel_manifest_path: PathBuf, kernel_metadata: cargo_metadata::Metadata, } impl Builder { + /// Creates a new Builder by searching for the kernel's Cargo manifest and running + /// `cargo metadata` on it. pub fn new(manifest_path: Option) -> Result { let kernel_manifest_path = manifest_path.unwrap_or(locate_cargo_manifest::locate_manifest()?); @@ -22,20 +28,24 @@ impl Builder { }) } + /// Returns the path to the `Cargo.toml` file of the kernel. pub fn kernel_manifest_path(&self) -> &Path { &self.kernel_manifest_path } + /// Returns the directory that contains the `Cargo.toml` of the kernel. pub fn kernel_root(&self) -> &Path { self.kernel_manifest_path .parent() .expect("kernel manifest has no parent directory") } + /// Returns a reference to the cargo metadata object. pub fn kernel_metadata(&self) -> &cargo_metadata::Metadata { &self.kernel_metadata } + /// Returns a reference to the kernel package in the `cargo metadata` output. pub fn kernel_package(&self) -> Result<&cargo_metadata::Package, String> { let mut packages = self.kernel_metadata.packages.iter(); let kernel_package = packages.find(|p| &p.manifest_path == &self.kernel_manifest_path); @@ -45,6 +55,12 @@ impl Builder { )) } + /// Builds the kernel by executing `cargo xbuild` with the given arguments. + /// + /// Returns a list of paths to all built executables. For crates with only a single binary, + /// the returned list contains only a single element. + /// + /// If the quiet argument is set to true, all output to stdout is suppressed. pub fn build_kernel( &self, args: &[String], @@ -110,6 +126,11 @@ impl Builder { Ok(executables) } + /// Creates a bootimage by combining the given kernel binary with the bootloader. + /// + /// Places the resulting bootable disk image at the given `output_bin_path`. + /// + /// If the quiet argument is set to true, all output to stdout is suppressed. pub fn create_bootimage( &self, kernel_bin_path: &Path, @@ -284,6 +305,7 @@ impl Builder { } } +/// Represents an error that occurred while creating a new `Builder`. #[derive(Debug)] pub enum BuilderError { /// Failed to locate cargo manifest @@ -309,6 +331,7 @@ impl fmt::Display for BuilderError { } } +/// Represents an error that occurred when building the kernel. #[derive(Debug)] pub enum BuildKernelError { /// Could not find kernel package in cargo metadata, required for retrieving kernel crate name @@ -320,11 +343,16 @@ pub enum BuildKernelError { /// The I/O error that occured error: io::Error, }, + /// Could not find the `cargo xbuild` tool. Perhaps it is not installed? XbuildNotFound, + /// Running `cargo xbuild` failed. XbuildFailed { + /// The standard error output. stderr: Vec, }, + /// The output of `cargo xbuild --message-format=json` was not valid UTF-8 XbuildJsonOutputInvalidUtf8(std::string::FromUtf8Error), + /// The output of `cargo xbuild --message-format=json` was not valid JSON XbuildJsonOutputInvalidJson(json::Error), #[doc(hidden)] __NonExhaustive, @@ -357,6 +385,7 @@ impl fmt::Display for BuildKernelError { } } +/// Represents an error that occurred when creating a bootimage. #[derive(Debug)] pub enum CreateBootimageError { /// Could not find some required information in the `cargo metadata` output @@ -368,7 +397,9 @@ pub enum CreateBootimageError { BootloaderNotFound, /// Bootloader dependency has not the right format BootloaderInvalid(String), + /// Building the bootloader failed BootloaderBuildFailed { + /// The `cargo xbuild` output to standard error stderr: Vec, }, /// An unexpected I/O error occurred @@ -384,9 +415,12 @@ pub enum CreateBootimageError { LlvmObjcopyNotFound, /// The `llvm-objcopy` command failed ObjcopyFailed { + /// The output of `llvm-objcopy` to standard error stderr: Vec, }, + /// The output of `cargo xbuild --message-format=json` was not valid UTF-8 XbuildJsonOutputInvalidUtf8(std::string::FromUtf8Error), + /// The output of `cargo xbuild --message-format=json` was not valid JSON XbuildJsonOutputInvalidJson(json::Error), #[doc(hidden)] __NonExhaustive, diff --git a/src/config.rs b/src/config.rs index 6b80a55..6c80bfd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,12 +1,25 @@ +//! Parses the `package.metadata.bootimage` configuration table + use crate::ErrorMessage; use std::path::Path; use toml::Value; +/// Represents the `package.metadata.bootimage` configuration table +/// +/// The bootimage crate can be configured through a `package.metadata.bootimage` table +/// in the `Cargo.toml` file of the kernel. This struct represents the parsed configuration +/// options. #[derive(Debug, Clone)] pub struct Config { + /// This target is used if no `--target` argument is passed pub default_target: Option, + /// The run command that is invoked on `bootimage run` or `bootimage runner` + /// + /// The substring "{}" will be replaced with the path to the bootable disk image. pub run_command: Vec, + /// Additional arguments passed to the runner on `bootimage run` or `bootimage runner` pub run_args: Option>, + /// The timeout for running an integration test through `bootimage test` in seconds pub test_timeout: u32, non_exhaustive: (), } diff --git a/src/lib.rs b/src/lib.rs index 86f2a3a..29f2163 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,14 @@ +//! Provides functions to create a bootable OS image from a kernel binary. +//! +//! This crate is mainly built as a binary tool. Run `cargo install bootimage` to install it. + +#![warn(missing_docs)] + use args::{Args, RunnerArgs}; use std::{fmt, process}; -pub mod builder; mod args; +pub mod builder; pub mod config; pub mod help; @@ -23,6 +29,13 @@ enum Command { Version, } +/// The entry point for the binaries. +/// +/// We support two binaries, `bootimage` and `cargo-bootimage` that both just +/// call into this function. +/// +/// This function is just a small wrapper around [`run`] that prints error messages +/// and exits with the correct exit code. pub fn lib_main() { match run() { Err(err) => { @@ -36,6 +49,13 @@ pub fn lib_main() { } } +/// Run the invoked command. +/// +/// This function parses the arguments and invokes the chosen subcommand. +/// +/// On success, it optionally returns an exit code. This feature is used by the +/// `run` and `runner` subcommand to pass through the exit code of the invoked +/// run command. pub fn run() -> Result, ErrorMessage> { let command = args::parse_args()?; let none = |()| None; @@ -54,7 +74,12 @@ pub fn run() -> Result, ErrorMessage> { } } +/// A simple error message that can be created from every type that implements `fmt::Display`. +/// +/// We use this error type for the CLI interface, where text based, human readable error messages +/// make sense. For the library part of this crate, we use custom error enums. pub struct ErrorMessage { + /// The actual error message pub message: Box, } From 04cdce283eea9acd2bc7866d02240c29a18abed6 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 23:30:30 +0200 Subject: [PATCH 48/50] Make help module private --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 29f2163..f99af11 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ use std::{fmt, process}; mod args; pub mod builder; pub mod config; -pub mod help; +mod help; mod subcommand; From a94c1c32245736cc227747ede05b56f111d5961e Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 23:46:12 +0200 Subject: [PATCH 49/50] Update --help output --- src/help/build_help.txt | 6 +++--- src/help/cargo_bootimage_help.txt | 20 ++++++++++++++++++++ src/help/help.txt | 4 ++++ src/help/mod.rs | 10 ++++++++++ src/help/run_help.txt | 5 ++++- src/help/runner_help.txt | 25 +++++++++++++++++++++++++ src/lib.rs | 3 ++- 7 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 src/help/cargo_bootimage_help.txt create mode 100644 src/help/runner_help.txt diff --git a/src/help/build_help.txt b/src/help/build_help.txt index e92d588..e623053 100644 --- a/src/help/build_help.txt +++ b/src/help/build_help.txt @@ -12,9 +12,9 @@ BUILD_OPTS: disk image. CONFIGURATION: - The bootloader and the behavior of `bootimage build` can be configured - through a `[package.metadata.bootimage]` table in the `Cargo.toml`. The - following options are available to configure the build: + The behavior of `bootimage build` can be configured through a + `[package.metadata.bootimage]` table in the `Cargo.toml`. The following + options are available to configure the build: [package.metadata.bootimage] default-target = "" This target is used if no `--target` is passed diff --git a/src/help/cargo_bootimage_help.txt b/src/help/cargo_bootimage_help.txt new file mode 100644 index 0000000..b257c10 --- /dev/null +++ b/src/help/cargo_bootimage_help.txt @@ -0,0 +1,20 @@ +Creates a bootable disk image from a Rust kernel + +USAGE: + cargo bootimage [BUILD_OPTS] Create a bootable disk image + + (for other forms of usage see `bootimage --help`) + +BUILD_OPTS: + Any options are directly passed to `cargo build` (see + `cargo build --help` for possible options). After building, a bootloader + is downloaded and built, and then combined with the kernel into a bootable + disk image. + +CONFIGURATION: + The behavior of `cargo bootimage` can be configured through a + `[package.metadata.bootimage]` table in the `Cargo.toml`. The following + options are available to configure the build: + + [package.metadata.bootimage] + default-target = "" This target is used if no `--target` is passed diff --git a/src/help/help.txt b/src/help/help.txt index 4d594ea..3d265b9 100644 --- a/src/help/help.txt +++ b/src/help/help.txt @@ -5,6 +5,10 @@ USAGE: bootimage build [BUILD_OPTS] Create a bootable disk image bootimage run [BUILD_OPTS] -- [RUN_OPTS] Build and run a disk image bootimage test [BUILD_OPTS] Runs integration tests + bootimage runner EXECUTABLE Convert and run an executable + + cargo bootimage [BUILD_OPTS] Create a bootable disk image + (equivalent to bootimage build) For more information about a subcommand run `bootimage [subcommand] --help`. diff --git a/src/help/mod.rs b/src/help/mod.rs index 63bd8a1..31ff920 100644 --- a/src/help/mod.rs +++ b/src/help/mod.rs @@ -2,7 +2,9 @@ use std::process; const HELP: &str = include_str!("help.txt"); const BUILD_HELP: &str = include_str!("build_help.txt"); +const CARGO_BOOTIMAGE_HELP: &str = include_str!("cargo_bootimage_help.txt"); const RUN_HELP: &str = include_str!("run_help.txt"); +const RUNNER_HELP: &str = include_str!("runner_help.txt"); const TEST_HELP: &str = include_str!("test_help.txt"); pub(crate) fn help() { @@ -13,10 +15,18 @@ pub(crate) fn build_help() { print!("{}", BUILD_HELP); } +pub(crate) fn cargo_bootimage_help() { + print!("{}", CARGO_BOOTIMAGE_HELP); +} + pub(crate) fn run_help() { print!("{}", RUN_HELP); } +pub(crate) fn runner_help() { + print!("{}", RUNNER_HELP); +} + pub(crate) fn test_help() { print!("{}", TEST_HELP); } diff --git a/src/help/run_help.txt b/src/help/run_help.txt index 09dfdce..4056ae3 100644 --- a/src/help/run_help.txt +++ b/src/help/run_help.txt @@ -16,6 +16,9 @@ CONFIGURATION: following options are available to configure run behavior: [package.metadata.bootimage] - # The command invoked on `bootimage run` + # The command invoked on `bootimage run` or `bootimage runner` # (the "{}" will be replaced with the path to the bootable disk image) run-command = ["qemu-system-x86_64", "-drive", "format=raw,file={}"] + # Additional arguments passed to the runner on `bootimage run` or `bootimage runner` + # (this is useful when you want to add some arguments to the default QEMU command) + run-args = [] \ No newline at end of file diff --git a/src/help/runner_help.txt b/src/help/runner_help.txt new file mode 100644 index 0000000..d2bf3ed --- /dev/null +++ b/src/help/runner_help.txt @@ -0,0 +1,25 @@ +Creates a bootable disk image from a Rust kernel and launches it in QEMU + +USAGE: + bootimage runner EXECUTABLE Convert and run the given EXECUTABLE + + (for other forms of usage see `bootimage --help`) + + This subcommand can be used as a target runner in a `.cargo/config` file: + ``` + [target.'cfg(target_os = "none")'] + runner = "bootimage runner" + ``` + +CONFIGURATION: + The behavior of `bootimage runner` can be configured through a + `[package.metadata.bootimage]` table in the `Cargo.toml`. The + following options are available to configure run behavior: + + [package.metadata.bootimage] + # The command invoked on `bootimage run` or `bootimage runner` + # (the "{}" will be replaced with the path to the bootable disk image) + run-command = ["qemu-system-x86_64", "-drive", "format=raw,file={}"] + # Additional arguments passed to the runner on `bootimage run` or `bootimage runner` + # (this is useful when you want to add some arguments to the default QEMU command) + run-args = [] \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index f99af11..70f2ea6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,10 +67,11 @@ pub fn run() -> Result, ErrorMessage> { Command::NoSubcommand => help::no_subcommand(), Command::Help => Ok(help::help()).map(none), Command::BuildHelp => Ok(help::build_help()).map(none), + Command::CargoBootimageHelp => Ok(help::cargo_bootimage_help()).map(none), Command::RunHelp => Ok(help::run_help()).map(none), + Command::RunnerHelp => Ok(help::runner_help()).map(none), Command::TestHelp => Ok(help::test_help()).map(none), Command::Version => Ok(println!("bootimage {}", env!("CARGO_PKG_VERSION"))).map(none), - Command::RunnerHelp | Command::CargoBootimageHelp => unimplemented!(), } } From bfd385804ac5837bc0482a300d9290e4b6e68b4c Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Tue, 2 Apr 2019 23:53:58 +0200 Subject: [PATCH 50/50] Replace remaining early exits with proper ErrorMessage returns --- src/help/mod.rs | 10 ++++------ src/lib.rs | 2 +- src/subcommand/build.rs | 10 ++++++---- src/subcommand/test.rs | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/help/mod.rs b/src/help/mod.rs index 31ff920..9af62e7 100644 --- a/src/help/mod.rs +++ b/src/help/mod.rs @@ -1,4 +1,4 @@ -use std::process; +use crate::ErrorMessage; const HELP: &str = include_str!("help.txt"); const BUILD_HELP: &str = include_str!("build_help.txt"); @@ -31,9 +31,7 @@ pub(crate) fn test_help() { print!("{}", TEST_HELP); } -pub(crate) fn no_subcommand() -> ! { - println!("Please invoke `bootimage` with a subcommand (e.g. `bootimage build`)."); - println!(); - println!("See `bootimage --help` for more information."); - process::exit(1); +pub(crate) fn no_subcommand() -> ErrorMessage { + "Please invoke `bootimage` with a subcommand (e.g. `bootimage build`).\n\n\ + See `bootimage --help` for more information.".into() } diff --git a/src/lib.rs b/src/lib.rs index 70f2ea6..6d6ce73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,7 +64,6 @@ pub fn run() -> Result, ErrorMessage> { Command::Run(args) => subcommand::run::run(args).map(Some), Command::Test(args) => subcommand::test::test(args).map(none), Command::Runner(args) => subcommand::runner::runner(args).map(Some), - Command::NoSubcommand => help::no_subcommand(), Command::Help => Ok(help::help()).map(none), Command::BuildHelp => Ok(help::build_help()).map(none), Command::CargoBootimageHelp => Ok(help::cargo_bootimage_help()).map(none), @@ -72,6 +71,7 @@ pub fn run() -> Result, ErrorMessage> { Command::RunnerHelp => Ok(help::runner_help()).map(none), Command::TestHelp => Ok(help::test_help()).map(none), Command::Version => Ok(println!("bootimage {}", env!("CARGO_PKG_VERSION"))).map(none), + Command::NoSubcommand => Err(help::no_subcommand()), } } diff --git a/src/subcommand/build.rs b/src/subcommand/build.rs index 0a86d2d..1cc118e 100644 --- a/src/subcommand/build.rs +++ b/src/subcommand/build.rs @@ -15,7 +15,7 @@ pub(crate) fn build_impl( args: &Args, quiet: bool, ) -> Result, ErrorMessage> { - run_cargo_fetch(&args); + run_cargo_fetch(&args).map_err(|()| "cargo fetch failed")?; let executables = builder.build_kernel(&args.cargo_args, quiet)?; if executables.len() == 0 { @@ -40,14 +40,16 @@ pub(crate) fn build_impl( Ok(bootimages) } -fn run_cargo_fetch(args: &Args) { +fn run_cargo_fetch(args: &Args) -> Result<(), ()> { let mut command = process::Command::new("cargo"); command.arg("fetch"); if let Some(manifest_path) = args.manifest_path() { command.arg("--manifest-path"); command.arg(manifest_path); } - if !command.status().map(|s| s.success()).unwrap_or(false) { - process::exit(1); + if command.status().map(|s| s.success()).unwrap_or(false) { + Ok(()) + } else { + Err(()) } } diff --git a/src/subcommand/test.rs b/src/subcommand/test.rs index 6373959..7bf06b1 100644 --- a/src/subcommand/test.rs +++ b/src/subcommand/test.rs @@ -94,7 +94,7 @@ pub(crate) fn test(mut args: Args) -> Result<(), ErrorMessage> { for test in tests.iter().filter(|t| t.1 != TestResult::Ok) { writeln!(io::stderr(), " {}: {:?}", test.0, test.1)?; } - process::exit(1); + Err("Some tests failed".into()) } }