Skip to content

Commit

Permalink
Merge pull request #304 from AlexJMohr/cargo-features
Browse files Browse the repository at this point in the history
 Add bios and uefi cargo features (closes #287)
  • Loading branch information
phil-opp committed Jan 9, 2023
2 parents 94c71d5 + caf05fb commit 5e42ad0
Show file tree
Hide file tree
Showing 11 changed files with 235 additions and 185 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ["dep:mbrman", "bootloader_test_runner/bios"]
uefi = ["dep:gpt", "bootloader_test_runner/uefi"]

[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" }
Expand Down
83 changes: 43 additions & 40 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,49 @@ 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());

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))]
#[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);
Expand All @@ -53,7 +55,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");
Expand All @@ -78,6 +80,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);
Expand All @@ -90,8 +93,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");
Expand Down Expand Up @@ -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);
Expand All @@ -133,8 +136,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");
Expand Down Expand Up @@ -162,6 +164,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);
Expand All @@ -174,8 +177,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");
Expand Down Expand Up @@ -203,6 +205,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);
Expand All @@ -215,8 +218,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");
Expand Down Expand Up @@ -244,6 +246,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");

Expand Down
File renamed without changes.
67 changes: 67 additions & 0 deletions src/bios/mod.rs
Original file line number Diff line number Diff line change
@@ -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<NamedTempFile> {
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)
}
}
Loading

0 comments on commit 5e42ad0

Please sign in to comment.