From 2e4160ede8cd71bd67e9fbb468e9acf7427cb104 Mon Sep 17 00:00:00 2001 From: Alex Mohr Date: Mon, 2 Jan 2023 09:22:09 -0800 Subject: [PATCH 1/8] Add bios and uefi features Both features are enabled by default. mbrman and gpt are now optional, and are pulled in by the bios and uefi features respectively. --- Cargo.toml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4bea9b23..d48889fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,12 +37,17 @@ bootloader_api = { version = "0.11.0", path = "api" } bootloader-x86_64-common = { version = "0.11.0", path = "common" } bootloader-x86_64-bios-common = { version = "0.11.0", path = "bios/common" } +[features] +default = ["bios", "uefi"] +bios = ["mbrman"] +uefi = ["gpt"] + [dependencies] anyhow = "1.0.32" fatfs = "0.3.4" -gpt = "3.0.0" -mbrman = "0.5.1" tempfile = "3.3.0" +mbrman = { version = "0.5.1", optional = true } +gpt = { version = "3.0.0", optional = true } [dev-dependencies] bootloader_test_runner = { path = "tests/runner" } From eb9081e42b6d50d81689942ca4bc000aade3770f Mon Sep 17 00:00:00 2001 From: Alex Mohr Date: Mon, 2 Jan 2023 09:26:40 -0800 Subject: [PATCH 2/8] move bios and uefi specific code into submodules gated by features --- build.rs | 16 +++-- src/{ => bios}/mbr.rs | 0 src/bios/mod.rs | 67 +++++++++++++++++++++ src/lib.rs | 134 +++--------------------------------------- src/{ => uefi}/gpt.rs | 0 src/uefi/mod.rs | 69 ++++++++++++++++++++++ src/{ => uefi}/pxe.rs | 0 7 files changed, 156 insertions(+), 130 deletions(-) rename src/{ => bios}/mbr.rs (100%) create mode 100644 src/bios/mod.rs rename src/{ => uefi}/gpt.rs (100%) create mode 100644 src/uefi/mod.rs rename src/{ => uefi}/pxe.rs (100%) diff --git a/build.rs b/build.rs index 7f04dddf..7bb1f12b 100644 --- a/build.rs +++ b/build.rs @@ -44,6 +44,7 @@ fn main() { } #[cfg(not(docsrs_dummy_build))] +#[cfg(feature = "uefi")] fn build_uefi_bootloader(out_dir: &Path) -> PathBuf { let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into()); let mut cmd = Command::new(cargo); @@ -78,6 +79,7 @@ fn build_uefi_bootloader(out_dir: &Path) -> PathBuf { } #[cfg(not(docsrs_dummy_build))] +#[cfg(feature = "bios")] fn build_bios_boot_sector(out_dir: &Path) -> PathBuf { let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into()); let mut cmd = Command::new(cargo); @@ -121,6 +123,7 @@ fn build_bios_boot_sector(out_dir: &Path) -> PathBuf { } #[cfg(not(docsrs_dummy_build))] +#[cfg(feature = "bios")] fn build_bios_stage_2(out_dir: &Path) -> PathBuf { let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into()); let mut cmd = Command::new(cargo); @@ -162,6 +165,7 @@ fn build_bios_stage_2(out_dir: &Path) -> PathBuf { } #[cfg(not(docsrs_dummy_build))] +#[cfg(feature = "bios")] fn build_bios_stage_3(out_dir: &Path) -> PathBuf { let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into()); let mut cmd = Command::new(cargo); @@ -203,6 +207,7 @@ fn build_bios_stage_3(out_dir: &Path) -> PathBuf { } #[cfg(not(docsrs_dummy_build))] +#[cfg(feature = "bios")] fn build_bios_stage_4(out_dir: &Path) -> PathBuf { let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into()); let mut cmd = Command::new(cargo); @@ -244,6 +249,7 @@ fn build_bios_stage_4(out_dir: &Path) -> PathBuf { convert_elf_to_bin(elf_path) } +#[cfg(feature = "bios")] fn convert_elf_to_bin(elf_path: PathBuf) -> PathBuf { let flat_binary_path = elf_path.with_extension("bin"); @@ -273,23 +279,23 @@ fn convert_elf_to_bin(elf_path: PathBuf) -> PathBuf { // dummy implementations because docsrs builds have no network access -#[cfg(docsrs_dummy_build)] +#[cfg(any(docsrs_dummy_build, not(feature = "uefi")))] fn build_uefi_bootloader(_out_dir: &Path) -> PathBuf { PathBuf::new() } -#[cfg(docsrs_dummy_build)] +#[cfg(any(docsrs_dummy_build, not(feature = "bios")))] fn build_bios_boot_sector(_out_dir: &Path) -> PathBuf { PathBuf::new() } -#[cfg(docsrs_dummy_build)] +#[cfg(any(docsrs_dummy_build, not(feature = "bios")))] fn build_bios_stage_2(_out_dir: &Path) -> PathBuf { PathBuf::new() } -#[cfg(docsrs_dummy_build)] +#[cfg(any(docsrs_dummy_build, not(feature = "bios")))] fn build_bios_stage_3(_out_dir: &Path) -> PathBuf { PathBuf::new() } -#[cfg(docsrs_dummy_build)] +#[cfg(any(docsrs_dummy_build, not(feature = "bios")))] fn build_bios_stage_4(_out_dir: &Path) -> PathBuf { PathBuf::new() } diff --git a/src/mbr.rs b/src/bios/mbr.rs similarity index 100% rename from src/mbr.rs rename to src/bios/mbr.rs diff --git a/src/bios/mod.rs b/src/bios/mod.rs new file mode 100644 index 00000000..03952152 --- /dev/null +++ b/src/bios/mod.rs @@ -0,0 +1,67 @@ +use crate::fat; +use anyhow::Context; +use std::{ + collections::BTreeMap, + path::{Path, PathBuf}, +}; +use tempfile::NamedTempFile; + +mod mbr; + +const BIOS_STAGE_3: &str = "boot-stage-3"; +const BIOS_STAGE_4: &str = "boot-stage-4"; + +/// Create disk images for booting on legacy BIOS systems. +pub struct BiosBoot { + kernel: PathBuf, +} + +impl BiosBoot { + /// Start creating a disk image for the given bootloader ELF executable. + pub fn new(kernel_path: &Path) -> Self { + Self { + kernel: kernel_path.to_owned(), + } + } + + /// Create a bootable UEFI disk image at the given path. + pub fn create_disk_image(&self, out_path: &Path) -> anyhow::Result<()> { + let bootsector_path = Path::new(env!("BIOS_BOOT_SECTOR_PATH")); + let stage_2_path = Path::new(env!("BIOS_STAGE_2_PATH")); + + let fat_partition = self + .create_fat_partition() + .context("failed to create FAT partition")?; + + mbr::create_mbr_disk( + bootsector_path, + stage_2_path, + fat_partition.path(), + out_path, + ) + .context("failed to create BIOS MBR disk image")?; + + fat_partition + .close() + .context("failed to delete FAT partition after disk image creation")?; + + Ok(()) + } + + /// Creates an BIOS-bootable FAT partition with the kernel. + fn create_fat_partition(&self) -> anyhow::Result { + let stage_3_path = Path::new(env!("BIOS_STAGE_3_PATH")); + let stage_4_path = Path::new(env!("BIOS_STAGE_4_PATH")); + + let mut files = BTreeMap::new(); + files.insert(crate::KERNEL_FILE_NAME, self.kernel.as_path()); + files.insert(BIOS_STAGE_3, stage_3_path); + files.insert(BIOS_STAGE_4, stage_4_path); + + let out_file = NamedTempFile::new().context("failed to create temp file")?; + fat::create_fat_filesystem(files, out_file.path()) + .context("failed to create BIOS FAT filesystem")?; + + Ok(out_file) + } +} diff --git a/src/lib.rs b/src/lib.rs index 11d1ebf0..cd41805a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,132 +4,16 @@ An experimental x86_64 bootloader that works on both BIOS and UEFI systems. #![warn(missing_docs)] -use anyhow::Context; -use std::{ - collections::BTreeMap, - path::{Path, PathBuf}, -}; -use tempfile::NamedTempFile; - +#[cfg(feature = "bios")] +mod bios; mod fat; -mod gpt; -mod mbr; -mod pxe; - -const KERNEL_FILE_NAME: &str = "kernel-x86_64"; -const BIOS_STAGE_3: &str = "boot-stage-3"; -const BIOS_STAGE_4: &str = "boot-stage-4"; - -/// Create disk images for booting on legacy BIOS systems. -pub struct BiosBoot { - kernel: PathBuf, -} - -impl BiosBoot { - /// Start creating a disk image for the given bootloader ELF executable. - pub fn new(kernel_path: &Path) -> Self { - Self { - kernel: kernel_path.to_owned(), - } - } - - /// Create a bootable UEFI disk image at the given path. - pub fn create_disk_image(&self, out_path: &Path) -> anyhow::Result<()> { - let bootsector_path = Path::new(env!("BIOS_BOOT_SECTOR_PATH")); - let stage_2_path = Path::new(env!("BIOS_STAGE_2_PATH")); - - let fat_partition = self - .create_fat_partition() - .context("failed to create FAT partition")?; - - mbr::create_mbr_disk( - bootsector_path, - stage_2_path, - fat_partition.path(), - out_path, - ) - .context("failed to create BIOS MBR disk image")?; - - fat_partition - .close() - .context("failed to delete FAT partition after disk image creation")?; - - Ok(()) - } - - /// Creates an BIOS-bootable FAT partition with the kernel. - fn create_fat_partition(&self) -> anyhow::Result { - let stage_3_path = Path::new(env!("BIOS_STAGE_3_PATH")); - let stage_4_path = Path::new(env!("BIOS_STAGE_4_PATH")); - - let mut files = BTreeMap::new(); - files.insert(KERNEL_FILE_NAME, self.kernel.as_path()); - files.insert(BIOS_STAGE_3, stage_3_path); - files.insert(BIOS_STAGE_4, stage_4_path); - - let out_file = NamedTempFile::new().context("failed to create temp file")?; - fat::create_fat_filesystem(files, out_file.path()) - .context("failed to create BIOS FAT filesystem")?; +#[cfg(feature = "uefi")] +mod uefi; - Ok(out_file) - } -} +#[cfg(feature = "bios")] +pub use bios::BiosBoot; -/// Create disk images for booting on UEFI systems. -pub struct UefiBoot { - kernel: PathBuf, -} +#[cfg(feature = "uefi")] +pub use uefi::UefiBoot; -impl UefiBoot { - /// Start creating a disk image for the given bootloader ELF executable. - pub fn new(kernel_path: &Path) -> Self { - Self { - kernel: kernel_path.to_owned(), - } - } - - /// Create a bootable BIOS disk image at the given path. - pub fn create_disk_image(&self, out_path: &Path) -> anyhow::Result<()> { - let fat_partition = self - .create_fat_partition() - .context("failed to create FAT partition")?; - - gpt::create_gpt_disk(fat_partition.path(), out_path) - .context("failed to create UEFI GPT disk image")?; - - fat_partition - .close() - .context("failed to delete FAT partition after disk image creation")?; - - Ok(()) - } - - /// Prepare a folder for use with booting over UEFI_PXE. - /// - /// This places the bootloader executable under the path "bootloader". The - /// DHCP server should set the filename option to that path, otherwise the - /// bootloader won't be found. - pub fn create_pxe_tftp_folder(&self, out_path: &Path) -> anyhow::Result<()> { - let bootloader_path = Path::new(env!("UEFI_BOOTLOADER_PATH")); - - pxe::create_uefi_tftp_folder(bootloader_path, self.kernel.as_path(), out_path) - .context("failed to create UEFI PXE tftp folder")?; - - Ok(()) - } - - /// Creates an UEFI-bootable FAT partition with the kernel. - fn create_fat_partition(&self) -> anyhow::Result { - let bootloader_path = Path::new(env!("UEFI_BOOTLOADER_PATH")); - - let mut files = BTreeMap::new(); - files.insert("efi/boot/bootx64.efi", bootloader_path); - files.insert(KERNEL_FILE_NAME, self.kernel.as_path()); - - let out_file = NamedTempFile::new().context("failed to create temp file")?; - fat::create_fat_filesystem(files, out_file.path()) - .context("failed to create UEFI FAT filesystem")?; - - Ok(out_file) - } -} +const KERNEL_FILE_NAME: &str = "kernel-x86_64"; diff --git a/src/gpt.rs b/src/uefi/gpt.rs similarity index 100% rename from src/gpt.rs rename to src/uefi/gpt.rs diff --git a/src/uefi/mod.rs b/src/uefi/mod.rs new file mode 100644 index 00000000..cfbc8c9f --- /dev/null +++ b/src/uefi/mod.rs @@ -0,0 +1,69 @@ +use crate::fat; +use anyhow::Context; +use std::{ + collections::BTreeMap, + path::{Path, PathBuf}, +}; +use tempfile::NamedTempFile; + +mod gpt; +mod pxe; + +/// Create disk images for booting on UEFI systems. +pub struct UefiBoot { + kernel: PathBuf, +} + +impl UefiBoot { + /// Start creating a disk image for the given bootloader ELF executable. + pub fn new(kernel_path: &Path) -> Self { + Self { + kernel: kernel_path.to_owned(), + } + } + + /// Create a bootable BIOS disk image at the given path. + pub fn create_disk_image(&self, out_path: &Path) -> anyhow::Result<()> { + let fat_partition = self + .create_fat_partition() + .context("failed to create FAT partition")?; + + gpt::create_gpt_disk(fat_partition.path(), out_path) + .context("failed to create UEFI GPT disk image")?; + + fat_partition + .close() + .context("failed to delete FAT partition after disk image creation")?; + + Ok(()) + } + + /// Prepare a folder for use with booting over UEFI_PXE. + /// + /// This places the bootloader executable under the path "bootloader". The + /// DHCP server should set the filename option to that path, otherwise the + /// bootloader won't be found. + pub fn create_pxe_tftp_folder(&self, out_path: &Path) -> anyhow::Result<()> { + let bootloader_path = Path::new(env!("UEFI_BOOTLOADER_PATH")); + + pxe::create_uefi_tftp_folder(bootloader_path, self.kernel.as_path(), out_path) + .context("failed to create UEFI PXE tftp folder")?; + + Ok(()) + } + + /// Creates an UEFI-bootable FAT partition with the kernel. + fn create_fat_partition(&self) -> anyhow::Result { + let bootloader_path = Path::new(env!("UEFI_BOOTLOADER_PATH")); + + let mut files = BTreeMap::new(); + files.insert("efi/boot/bootx64.efi", bootloader_path); + files.insert(crate::KERNEL_FILE_NAME, self.kernel.as_path()); + + let out_file = NamedTempFile::new().context("failed to create temp file")?; + fat::create_fat_filesystem(files, out_file.path()) + .context("failed to create UEFI FAT filesystem")?; + + Ok(out_file) + } +} diff --git a/src/pxe.rs b/src/uefi/pxe.rs similarity index 100% rename from src/pxe.rs rename to src/uefi/pxe.rs From c6396222626b1f1ab8ceb4a33824dc0c659489ef Mon Sep 17 00:00:00 2001 From: Alex Mohr Date: Mon, 2 Jan 2023 09:27:12 -0800 Subject: [PATCH 3/8] merge BOOTLOADER_*_VERSION contants into BOOTLOADER_VERSION They all had the same value anway --- build.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/build.rs b/build.rs index 7bb1f12b..e3900b92 100644 --- a/build.rs +++ b/build.rs @@ -3,12 +3,7 @@ use std::{ process::Command, }; -const BOOTLOADER_X86_64_UEFI_VERSION: &str = env!("CARGO_PKG_VERSION"); - -const BOOTLOADER_X86_64_BIOS_BOOT_SECTOR_VERSION: &str = env!("CARGO_PKG_VERSION"); -const BOOTLOADER_X86_64_BIOS_STAGE_2_VERSION: &str = env!("CARGO_PKG_VERSION"); -const BOOTLOADER_X86_64_BIOS_STAGE_3_VERSION: &str = env!("CARGO_PKG_VERSION"); -const BOOTLOADER_X86_64_BIOS_STAGE_4_VERSION: &str = env!("CARGO_PKG_VERSION"); +const BOOTLOADER_VERSION: &str = env!("CARGO_PKG_VERSION"); fn main() { let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); @@ -54,7 +49,7 @@ fn build_uefi_bootloader(out_dir: &Path) -> PathBuf { cmd.arg("--path").arg("uefi"); println!("cargo:rerun-if-changed=uefi"); } else { - cmd.arg("--version").arg(BOOTLOADER_X86_64_UEFI_VERSION); + cmd.arg("--version").arg(BOOTLOADER_VERSION); } cmd.arg("--locked"); cmd.arg("--target").arg("x86_64-unknown-uefi"); @@ -92,8 +87,7 @@ fn build_bios_boot_sector(out_dir: &Path) -> PathBuf { cmd.arg("--path").arg(&local_path); println!("cargo:rerun-if-changed={}", local_path.display()); } else { - cmd.arg("--version") - .arg(BOOTLOADER_X86_64_BIOS_BOOT_SECTOR_VERSION); + cmd.arg("--version").arg(BOOTLOADER_VERSION); } cmd.arg("--locked"); cmd.arg("--target").arg("i386-code16-boot-sector.json"); @@ -136,8 +130,7 @@ fn build_bios_stage_2(out_dir: &Path) -> PathBuf { cmd.arg("--path").arg(&local_path); println!("cargo:rerun-if-changed={}", local_path.display()); } else { - cmd.arg("--version") - .arg(BOOTLOADER_X86_64_BIOS_STAGE_2_VERSION); + cmd.arg("--version").arg(BOOTLOADER_VERSION); } cmd.arg("--locked"); cmd.arg("--target").arg("i386-code16-stage-2.json"); @@ -178,8 +171,7 @@ fn build_bios_stage_3(out_dir: &Path) -> PathBuf { cmd.arg("--path").arg(&local_path); println!("cargo:rerun-if-changed={}", local_path.display()); } else { - cmd.arg("--version") - .arg(BOOTLOADER_X86_64_BIOS_STAGE_3_VERSION); + cmd.arg("--version").arg(BOOTLOADER_VERSION); } cmd.arg("--locked"); cmd.arg("--target").arg("i686-stage-3.json"); @@ -220,8 +212,7 @@ fn build_bios_stage_4(out_dir: &Path) -> PathBuf { cmd.arg("--path").arg(&local_path); println!("cargo:rerun-if-changed={}", local_path.display()); } else { - cmd.arg("--version") - .arg(BOOTLOADER_X86_64_BIOS_STAGE_4_VERSION); + cmd.arg("--version").arg(BOOTLOADER_VERSION); } cmd.arg("--locked"); cmd.arg("--target").arg("x86_64-stage-4.json"); From fb59bc9daa9f4baab799829cda90c8dd8e38f7d7 Mon Sep 17 00:00:00 2001 From: Alex Mohr Date: Mon, 2 Jan 2023 11:59:01 -0800 Subject: [PATCH 4/8] build: check features in main instead of conditional definition --- build.rs | 66 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/build.rs b/build.rs index e3900b92..e752d28f 100644 --- a/build.rs +++ b/build.rs @@ -8,34 +8,40 @@ const BOOTLOADER_VERSION: &str = env!("CARGO_PKG_VERSION"); fn main() { let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); - let uefi_path = build_uefi_bootloader(&out_dir); - println!( - "cargo:rustc-env=UEFI_BOOTLOADER_PATH={}", - uefi_path.display() - ); + #[cfg(feature = "uefi")] + { + let uefi_path = build_uefi_bootloader(&out_dir); + println!( + "cargo:rustc-env=UEFI_BOOTLOADER_PATH={}", + uefi_path.display() + ); + } - let bios_boot_sector_path = build_bios_boot_sector(&out_dir); - println!( - "cargo:rustc-env=BIOS_BOOT_SECTOR_PATH={}", - bios_boot_sector_path.display() - ); - let bios_stage_2_path = build_bios_stage_2(&out_dir); - println!( - "cargo:rustc-env=BIOS_STAGE_2_PATH={}", - bios_stage_2_path.display() - ); + #[cfg(feature = "bios")] + { + let bios_boot_sector_path = build_bios_boot_sector(&out_dir); + println!( + "cargo:rustc-env=BIOS_BOOT_SECTOR_PATH={}", + bios_boot_sector_path.display() + ); + let bios_stage_2_path = build_bios_stage_2(&out_dir); + println!( + "cargo:rustc-env=BIOS_STAGE_2_PATH={}", + bios_stage_2_path.display() + ); - let bios_stage_3_path = build_bios_stage_3(&out_dir); - println!( - "cargo:rustc-env=BIOS_STAGE_3_PATH={}", - bios_stage_3_path.display() - ); + let bios_stage_3_path = build_bios_stage_3(&out_dir); + println!( + "cargo:rustc-env=BIOS_STAGE_3_PATH={}", + bios_stage_3_path.display() + ); - let bios_stage_4_path = build_bios_stage_4(&out_dir); - println!( - "cargo:rustc-env=BIOS_STAGE_4_PATH={}", - bios_stage_4_path.display() - ); + let bios_stage_4_path = build_bios_stage_4(&out_dir); + println!( + "cargo:rustc-env=BIOS_STAGE_4_PATH={}", + bios_stage_4_path.display() + ); + } } #[cfg(not(docsrs_dummy_build))] @@ -270,23 +276,23 @@ fn convert_elf_to_bin(elf_path: PathBuf) -> PathBuf { // dummy implementations because docsrs builds have no network access -#[cfg(any(docsrs_dummy_build, not(feature = "uefi")))] +#[cfg(docsrs_dummy_build)] fn build_uefi_bootloader(_out_dir: &Path) -> PathBuf { PathBuf::new() } -#[cfg(any(docsrs_dummy_build, not(feature = "bios")))] +#[cfg(docsrs_dummy_build)] fn build_bios_boot_sector(_out_dir: &Path) -> PathBuf { PathBuf::new() } -#[cfg(any(docsrs_dummy_build, not(feature = "bios")))] +#[cfg(docsrs_dummy_build)] fn build_bios_stage_2(_out_dir: &Path) -> PathBuf { PathBuf::new() } -#[cfg(any(docsrs_dummy_build, not(feature = "bios")))] +#[cfg(docsrs_dummy_build)] fn build_bios_stage_3(_out_dir: &Path) -> PathBuf { PathBuf::new() } -#[cfg(any(docsrs_dummy_build, not(feature = "bios")))] +#[cfg(docsrs_dummy_build)] fn build_bios_stage_4(_out_dir: &Path) -> PathBuf { PathBuf::new() } From 0417bbd533ef4deb34bd3786e4d828055bcd2255 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 5 Jan 2023 12:07:26 +0100 Subject: [PATCH 5/8] Allow running tests only with uefi or bios --- Cargo.toml | 4 ++-- tests/runner/Cargo.toml | 8 ++++++-- tests/runner/src/lib.rs | 42 +++++++++++++++++++++++++---------------- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d48889fa..bfef10bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,8 +39,8 @@ bootloader-x86_64-bios-common = { version = "0.11.0", path = "bios/common" } [features] default = ["bios", "uefi"] -bios = ["mbrman"] -uefi = ["gpt"] +bios = ["mbrman", "bootloader_test_runner/bios"] +uefi = ["gpt", "bootloader_test_runner/uefi"] [dependencies] anyhow = "1.0.32" diff --git a/tests/runner/Cargo.toml b/tests/runner/Cargo.toml index 51421aa0..4c9d161e 100644 --- a/tests/runner/Cargo.toml +++ b/tests/runner/Cargo.toml @@ -6,7 +6,11 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +bios = ["bootloader/bios"] +uefi = ["bootloader/uefi", "ovmf-prebuilt"] + [dependencies] -bootloader = { path = "../.." } +bootloader = { path = "../..", default-features = false } strip-ansi-escapes = "0.1.1" -ovmf-prebuilt = "0.1.0-alpha.1" +ovmf-prebuilt = { version = "0.1.0-alpha.1", optional = true } diff --git a/tests/runner/src/lib.rs b/tests/runner/src/lib.rs index 7f50cd42..3b580173 100644 --- a/tests/runner/src/lib.rs +++ b/tests/runner/src/lib.rs @@ -13,27 +13,35 @@ const QEMU_ARGS: &[&str] = &[ pub fn run_test_kernel(kernel_binary_path: &str) { let kernel_path = Path::new(kernel_binary_path); - // create an MBR disk image for legacy BIOS booting - let mbr_path = kernel_path.with_extension("mbr"); - bootloader::BiosBoot::new(kernel_path) - .create_disk_image(&mbr_path) - .unwrap(); + #[cfg(feature = "uefi")] + { + // create a GPT disk image for UEFI booting + let gpt_path = kernel_path.with_extension("gpt"); + let uefi_builder = bootloader::UefiBoot::new(kernel_path); + uefi_builder.create_disk_image(&gpt_path).unwrap(); + + // create a TFTP folder with the kernel executable and UEFI bootloader for + // UEFI PXE booting + let tftp_path = kernel_path.with_extension(".tftp"); + uefi_builder.create_pxe_tftp_folder(&tftp_path).unwrap(); - // create a GPT disk image for UEFI booting - let gpt_path = kernel_path.with_extension("gpt"); - let uefi_builder = bootloader::UefiBoot::new(kernel_path); - uefi_builder.create_disk_image(&gpt_path).unwrap(); + run_test_kernel_on_uefi(&gpt_path); + run_test_kernel_on_uefi_pxe(&tftp_path); + } - // create a TFTP folder with the kernel executable and UEFI bootloader for - // UEFI PXE booting - let tftp_path = kernel_path.with_extension(".tftp"); - uefi_builder.create_pxe_tftp_folder(&tftp_path).unwrap(); + #[cfg(feature = "bios")] + { + // create an MBR disk image for legacy BIOS booting + let mbr_path = kernel_path.with_extension("mbr"); + bootloader::BiosBoot::new(kernel_path) + .create_disk_image(&mbr_path) + .unwrap(); - run_test_kernel_on_uefi(&gpt_path); - run_test_kernel_on_bios(&mbr_path); - run_test_kernel_on_uefi_pxe(&tftp_path); + run_test_kernel_on_bios(&mbr_path); + } } +#[cfg(feature = "uefi")] pub fn run_test_kernel_on_uefi(out_gpt_path: &Path) { let mut run_cmd = Command::new("qemu-system-x86_64"); run_cmd @@ -57,6 +65,7 @@ pub fn run_test_kernel_on_uefi(out_gpt_path: &Path) { } } +#[cfg(feature = "bios")] pub fn run_test_kernel_on_bios(out_mbr_path: &Path) { let mut run_cmd = Command::new("qemu-system-x86_64"); run_cmd @@ -79,6 +88,7 @@ pub fn run_test_kernel_on_bios(out_mbr_path: &Path) { } } +#[cfg(feature = "uefi")] pub fn run_test_kernel_on_uefi_pxe(out_tftp_path: &Path) { let mut run_cmd = Command::new("qemu-system-x86_64"); run_cmd.arg("-netdev").arg(format!( From 1a42f8e76301367cda69b8424d2d7eb22e5ccfc7 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 5 Jan 2023 12:07:39 +0100 Subject: [PATCH 6/8] Test the feature gates on CI --- .github/workflows/ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec952c33..db938864 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,6 +62,14 @@ jobs: - name: Run integration tests run: cargo test + # test feature gates (only on one OS is enough) + - name: Test with only UEFI feature + if: runner.os == 'Linux' + run: cargo test --no-default-features --features uefi + - name: Test with only BIOS feature + if: runner.os == 'Linux' + run: cargo test --no-default-features --features bios + fmt: name: Check Formatting runs-on: ubuntu-latest From ef907ffafa3b66880be9a72d4c856a939109678e Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 5 Jan 2023 13:02:23 +0100 Subject: [PATCH 7/8] Avoid creating implicit dependency features See https://doc.rust-lang.org/cargo/reference/features.html#optional-dependencies Co-authored-by: Tom Dohrmann --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bfef10bb..e1364c64 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,8 +39,8 @@ bootloader-x86_64-bios-common = { version = "0.11.0", path = "bios/common" } [features] default = ["bios", "uefi"] -bios = ["mbrman", "bootloader_test_runner/bios"] -uefi = ["gpt", "bootloader_test_runner/uefi"] +bios = ["dep:mbrman", "bootloader_test_runner/bios"] +uefi = ["dep:gpt", "bootloader_test_runner/uefi"] [dependencies] anyhow = "1.0.32" From 2e4a54431fcee2b9d6d6b0381caa8c57c086846b Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Thu, 5 Jan 2023 13:03:06 +0100 Subject: [PATCH 8/8] Use `dep:` prefix for runner features too --- tests/runner/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runner/Cargo.toml b/tests/runner/Cargo.toml index 4c9d161e..127184a6 100644 --- a/tests/runner/Cargo.toml +++ b/tests/runner/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [features] bios = ["bootloader/bios"] -uefi = ["bootloader/uefi", "ovmf-prebuilt"] +uefi = ["bootloader/uefi", "dep:ovmf-prebuilt"] [dependencies] bootloader = { path = "../..", default-features = false }