Skip to content

Commit 5e42ad0

Browse files
authored
Merge pull request #304 from AlexJMohr/cargo-features
Add bios and uefi cargo features (closes #287)
2 parents 94c71d5 + caf05fb commit 5e42ad0

File tree

11 files changed

+235
-185
lines changed

11 files changed

+235
-185
lines changed

Diff for: .github/workflows/ci.yml

+8
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ jobs:
6262
- name: Run integration tests
6363
run: cargo test
6464

65+
# test feature gates (only on one OS is enough)
66+
- name: Test with only UEFI feature
67+
if: runner.os == 'Linux'
68+
run: cargo test --no-default-features --features uefi
69+
- name: Test with only BIOS feature
70+
if: runner.os == 'Linux'
71+
run: cargo test --no-default-features --features bios
72+
6573
fmt:
6674
name: Check Formatting
6775
runs-on: ubuntu-latest

Diff for: Cargo.toml

+7-2
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,17 @@ bootloader_api = { version = "0.11.0", path = "api" }
3737
bootloader-x86_64-common = { version = "0.11.0", path = "common" }
3838
bootloader-x86_64-bios-common = { version = "0.11.0", path = "bios/common" }
3939

40+
[features]
41+
default = ["bios", "uefi"]
42+
bios = ["dep:mbrman", "bootloader_test_runner/bios"]
43+
uefi = ["dep:gpt", "bootloader_test_runner/uefi"]
44+
4045
[dependencies]
4146
anyhow = "1.0.32"
4247
fatfs = "0.3.4"
43-
gpt = "3.0.0"
44-
mbrman = "0.5.1"
4548
tempfile = "3.3.0"
49+
mbrman = { version = "0.5.1", optional = true }
50+
gpt = { version = "3.0.0", optional = true }
4651

4752
[dev-dependencies]
4853
bootloader_test_runner = { path = "tests/runner" }

Diff for: build.rs

+43-40
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,49 @@ use std::{
33
process::Command,
44
};
55

6-
const BOOTLOADER_X86_64_UEFI_VERSION: &str = env!("CARGO_PKG_VERSION");
7-
8-
const BOOTLOADER_X86_64_BIOS_BOOT_SECTOR_VERSION: &str = env!("CARGO_PKG_VERSION");
9-
const BOOTLOADER_X86_64_BIOS_STAGE_2_VERSION: &str = env!("CARGO_PKG_VERSION");
10-
const BOOTLOADER_X86_64_BIOS_STAGE_3_VERSION: &str = env!("CARGO_PKG_VERSION");
11-
const BOOTLOADER_X86_64_BIOS_STAGE_4_VERSION: &str = env!("CARGO_PKG_VERSION");
6+
const BOOTLOADER_VERSION: &str = env!("CARGO_PKG_VERSION");
127

138
fn main() {
149
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
1510

16-
let uefi_path = build_uefi_bootloader(&out_dir);
17-
println!(
18-
"cargo:rustc-env=UEFI_BOOTLOADER_PATH={}",
19-
uefi_path.display()
20-
);
11+
#[cfg(feature = "uefi")]
12+
{
13+
let uefi_path = build_uefi_bootloader(&out_dir);
14+
println!(
15+
"cargo:rustc-env=UEFI_BOOTLOADER_PATH={}",
16+
uefi_path.display()
17+
);
18+
}
2119

22-
let bios_boot_sector_path = build_bios_boot_sector(&out_dir);
23-
println!(
24-
"cargo:rustc-env=BIOS_BOOT_SECTOR_PATH={}",
25-
bios_boot_sector_path.display()
26-
);
27-
let bios_stage_2_path = build_bios_stage_2(&out_dir);
28-
println!(
29-
"cargo:rustc-env=BIOS_STAGE_2_PATH={}",
30-
bios_stage_2_path.display()
31-
);
20+
#[cfg(feature = "bios")]
21+
{
22+
let bios_boot_sector_path = build_bios_boot_sector(&out_dir);
23+
println!(
24+
"cargo:rustc-env=BIOS_BOOT_SECTOR_PATH={}",
25+
bios_boot_sector_path.display()
26+
);
27+
let bios_stage_2_path = build_bios_stage_2(&out_dir);
28+
println!(
29+
"cargo:rustc-env=BIOS_STAGE_2_PATH={}",
30+
bios_stage_2_path.display()
31+
);
3232

33-
let bios_stage_3_path = build_bios_stage_3(&out_dir);
34-
println!(
35-
"cargo:rustc-env=BIOS_STAGE_3_PATH={}",
36-
bios_stage_3_path.display()
37-
);
33+
let bios_stage_3_path = build_bios_stage_3(&out_dir);
34+
println!(
35+
"cargo:rustc-env=BIOS_STAGE_3_PATH={}",
36+
bios_stage_3_path.display()
37+
);
3838

39-
let bios_stage_4_path = build_bios_stage_4(&out_dir);
40-
println!(
41-
"cargo:rustc-env=BIOS_STAGE_4_PATH={}",
42-
bios_stage_4_path.display()
43-
);
39+
let bios_stage_4_path = build_bios_stage_4(&out_dir);
40+
println!(
41+
"cargo:rustc-env=BIOS_STAGE_4_PATH={}",
42+
bios_stage_4_path.display()
43+
);
44+
}
4445
}
4546

4647
#[cfg(not(docsrs_dummy_build))]
48+
#[cfg(feature = "uefi")]
4749
fn build_uefi_bootloader(out_dir: &Path) -> PathBuf {
4850
let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into());
4951
let mut cmd = Command::new(cargo);
@@ -53,7 +55,7 @@ fn build_uefi_bootloader(out_dir: &Path) -> PathBuf {
5355
cmd.arg("--path").arg("uefi");
5456
println!("cargo:rerun-if-changed=uefi");
5557
} else {
56-
cmd.arg("--version").arg(BOOTLOADER_X86_64_UEFI_VERSION);
58+
cmd.arg("--version").arg(BOOTLOADER_VERSION);
5759
}
5860
cmd.arg("--locked");
5961
cmd.arg("--target").arg("x86_64-unknown-uefi");
@@ -78,6 +80,7 @@ fn build_uefi_bootloader(out_dir: &Path) -> PathBuf {
7880
}
7981

8082
#[cfg(not(docsrs_dummy_build))]
83+
#[cfg(feature = "bios")]
8184
fn build_bios_boot_sector(out_dir: &Path) -> PathBuf {
8285
let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into());
8386
let mut cmd = Command::new(cargo);
@@ -90,8 +93,7 @@ fn build_bios_boot_sector(out_dir: &Path) -> PathBuf {
9093
cmd.arg("--path").arg(&local_path);
9194
println!("cargo:rerun-if-changed={}", local_path.display());
9295
} else {
93-
cmd.arg("--version")
94-
.arg(BOOTLOADER_X86_64_BIOS_BOOT_SECTOR_VERSION);
96+
cmd.arg("--version").arg(BOOTLOADER_VERSION);
9597
}
9698
cmd.arg("--locked");
9799
cmd.arg("--target").arg("i386-code16-boot-sector.json");
@@ -121,6 +123,7 @@ fn build_bios_boot_sector(out_dir: &Path) -> PathBuf {
121123
}
122124

123125
#[cfg(not(docsrs_dummy_build))]
126+
#[cfg(feature = "bios")]
124127
fn build_bios_stage_2(out_dir: &Path) -> PathBuf {
125128
let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into());
126129
let mut cmd = Command::new(cargo);
@@ -133,8 +136,7 @@ fn build_bios_stage_2(out_dir: &Path) -> PathBuf {
133136
cmd.arg("--path").arg(&local_path);
134137
println!("cargo:rerun-if-changed={}", local_path.display());
135138
} else {
136-
cmd.arg("--version")
137-
.arg(BOOTLOADER_X86_64_BIOS_STAGE_2_VERSION);
139+
cmd.arg("--version").arg(BOOTLOADER_VERSION);
138140
}
139141
cmd.arg("--locked");
140142
cmd.arg("--target").arg("i386-code16-stage-2.json");
@@ -162,6 +164,7 @@ fn build_bios_stage_2(out_dir: &Path) -> PathBuf {
162164
}
163165

164166
#[cfg(not(docsrs_dummy_build))]
167+
#[cfg(feature = "bios")]
165168
fn build_bios_stage_3(out_dir: &Path) -> PathBuf {
166169
let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into());
167170
let mut cmd = Command::new(cargo);
@@ -174,8 +177,7 @@ fn build_bios_stage_3(out_dir: &Path) -> PathBuf {
174177
cmd.arg("--path").arg(&local_path);
175178
println!("cargo:rerun-if-changed={}", local_path.display());
176179
} else {
177-
cmd.arg("--version")
178-
.arg(BOOTLOADER_X86_64_BIOS_STAGE_3_VERSION);
180+
cmd.arg("--version").arg(BOOTLOADER_VERSION);
179181
}
180182
cmd.arg("--locked");
181183
cmd.arg("--target").arg("i686-stage-3.json");
@@ -203,6 +205,7 @@ fn build_bios_stage_3(out_dir: &Path) -> PathBuf {
203205
}
204206

205207
#[cfg(not(docsrs_dummy_build))]
208+
#[cfg(feature = "bios")]
206209
fn build_bios_stage_4(out_dir: &Path) -> PathBuf {
207210
let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into());
208211
let mut cmd = Command::new(cargo);
@@ -215,8 +218,7 @@ fn build_bios_stage_4(out_dir: &Path) -> PathBuf {
215218
cmd.arg("--path").arg(&local_path);
216219
println!("cargo:rerun-if-changed={}", local_path.display());
217220
} else {
218-
cmd.arg("--version")
219-
.arg(BOOTLOADER_X86_64_BIOS_STAGE_4_VERSION);
221+
cmd.arg("--version").arg(BOOTLOADER_VERSION);
220222
}
221223
cmd.arg("--locked");
222224
cmd.arg("--target").arg("x86_64-stage-4.json");
@@ -244,6 +246,7 @@ fn build_bios_stage_4(out_dir: &Path) -> PathBuf {
244246
convert_elf_to_bin(elf_path)
245247
}
246248

249+
#[cfg(feature = "bios")]
247250
fn convert_elf_to_bin(elf_path: PathBuf) -> PathBuf {
248251
let flat_binary_path = elf_path.with_extension("bin");
249252

Diff for: src/mbr.rs renamed to src/bios/mbr.rs

File renamed without changes.

Diff for: src/bios/mod.rs

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use crate::fat;
2+
use anyhow::Context;
3+
use std::{
4+
collections::BTreeMap,
5+
path::{Path, PathBuf},
6+
};
7+
use tempfile::NamedTempFile;
8+
9+
mod mbr;
10+
11+
const BIOS_STAGE_3: &str = "boot-stage-3";
12+
const BIOS_STAGE_4: &str = "boot-stage-4";
13+
14+
/// Create disk images for booting on legacy BIOS systems.
15+
pub struct BiosBoot {
16+
kernel: PathBuf,
17+
}
18+
19+
impl BiosBoot {
20+
/// Start creating a disk image for the given bootloader ELF executable.
21+
pub fn new(kernel_path: &Path) -> Self {
22+
Self {
23+
kernel: kernel_path.to_owned(),
24+
}
25+
}
26+
27+
/// Create a bootable UEFI disk image at the given path.
28+
pub fn create_disk_image(&self, out_path: &Path) -> anyhow::Result<()> {
29+
let bootsector_path = Path::new(env!("BIOS_BOOT_SECTOR_PATH"));
30+
let stage_2_path = Path::new(env!("BIOS_STAGE_2_PATH"));
31+
32+
let fat_partition = self
33+
.create_fat_partition()
34+
.context("failed to create FAT partition")?;
35+
36+
mbr::create_mbr_disk(
37+
bootsector_path,
38+
stage_2_path,
39+
fat_partition.path(),
40+
out_path,
41+
)
42+
.context("failed to create BIOS MBR disk image")?;
43+
44+
fat_partition
45+
.close()
46+
.context("failed to delete FAT partition after disk image creation")?;
47+
48+
Ok(())
49+
}
50+
51+
/// Creates an BIOS-bootable FAT partition with the kernel.
52+
fn create_fat_partition(&self) -> anyhow::Result<NamedTempFile> {
53+
let stage_3_path = Path::new(env!("BIOS_STAGE_3_PATH"));
54+
let stage_4_path = Path::new(env!("BIOS_STAGE_4_PATH"));
55+
56+
let mut files = BTreeMap::new();
57+
files.insert(crate::KERNEL_FILE_NAME, self.kernel.as_path());
58+
files.insert(BIOS_STAGE_3, stage_3_path);
59+
files.insert(BIOS_STAGE_4, stage_4_path);
60+
61+
let out_file = NamedTempFile::new().context("failed to create temp file")?;
62+
fat::create_fat_filesystem(files, out_file.path())
63+
.context("failed to create BIOS FAT filesystem")?;
64+
65+
Ok(out_file)
66+
}
67+
}

0 commit comments

Comments
 (0)