Skip to content

Commit 7d2a579

Browse files
Embed bios and uefi binaries (#395)
1 parent 0fec6fd commit 7d2a579

File tree

4 files changed

+140
-48
lines changed

4 files changed

+140
-48
lines changed

build.rs

+100-13
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ async fn bios_main() {
2121
// BIOS crates don't have enough dependencies to utilize all cores on modern
2222
// CPUs. So by running the build commands in parallel, we increase the number
2323
// of utilized cores.)
24-
#[cfg(not(docsrs_dummy_build))]
2524
let (bios_boot_sector_path, bios_stage_2_path, bios_stage_3_path, bios_stage_4_path) = (
2625
build_bios_boot_sector(&out_dir),
2726
build_bios_stage_2(&out_dir),
@@ -30,14 +29,6 @@ async fn bios_main() {
3029
)
3130
.join()
3231
.await;
33-
// dummy implementations because docsrs builds have no network access
34-
#[cfg(docsrs_dummy_build)]
35-
let (bios_boot_sector_path, bios_stage_2_path, bios_stage_3_path, bios_stage_4_path) = (
36-
PathBuf::new(),
37-
PathBuf::new(),
38-
PathBuf::new(),
39-
PathBuf::new(),
40-
);
4132
println!(
4233
"cargo:rustc-env=BIOS_BOOT_SECTOR_PATH={}",
4334
bios_boot_sector_path.display()
@@ -60,11 +51,7 @@ async fn bios_main() {
6051
async fn uefi_main() {
6152
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
6253

63-
#[cfg(not(docsrs_dummy_build))]
6454
let uefi_path = build_uefi_bootloader(&out_dir).await;
65-
// dummy implementation because docsrs builds have no network access
66-
#[cfg(docsrs_dummy_build)]
67-
let uefi_path = PathBuf::new();
6855

6956
println!(
7057
"cargo:rustc-env=UEFI_BOOTLOADER_PATH={}",
@@ -109,6 +96,26 @@ async fn build_uefi_bootloader(out_dir: &Path) -> PathBuf {
10996
}
11097
}
11198

99+
// dummy implementation because docsrs builds have no network access.
100+
// This will put an empty file in out_dir and return its path.
101+
#[cfg(docsrs_dummy_build)]
102+
#[cfg(feature = "uefi")]
103+
async fn build_uefi_bootloader(out_dir: &Path) -> PathBuf {
104+
use std::fs::File;
105+
106+
let path = out_dir.join("bootloader-dummy-bootloader-uefi");
107+
108+
if File::create(&path).is_err() {
109+
panic!("Failed to create dummy uefi bootloader");
110+
}
111+
assert!(
112+
path.exists(),
113+
"uefi bootloader dummy file does not exist after file creation"
114+
);
115+
116+
path
117+
}
118+
112119
#[cfg(not(docsrs_dummy_build))]
113120
#[cfg(feature = "bios")]
114121
async fn build_bios_boot_sector(out_dir: &Path) -> PathBuf {
@@ -153,6 +160,26 @@ async fn build_bios_boot_sector(out_dir: &Path) -> PathBuf {
153160
convert_elf_to_bin(elf_path).await
154161
}
155162

163+
// dummy implementation because docsrs builds have no network access.
164+
// This will put an empty file in out_dir and return its path.
165+
#[cfg(docsrs_dummy_build)]
166+
#[cfg(feature = "bios")]
167+
async fn build_bios_boot_sector(out_dir: &Path) -> PathBuf {
168+
use std::fs::File;
169+
170+
let path = out_dir.join("bootloader-dummy-bios-boot-sector");
171+
172+
if File::create(&path).is_err() {
173+
panic!("Failed to create dummy bios boot sector");
174+
}
175+
assert!(
176+
path.exists(),
177+
"bios boot sector dummy file does not exist after file creation"
178+
);
179+
180+
path
181+
}
182+
156183
#[cfg(not(docsrs_dummy_build))]
157184
#[cfg(feature = "bios")]
158185
async fn build_bios_stage_2(out_dir: &Path) -> PathBuf {
@@ -199,6 +226,26 @@ async fn build_bios_stage_2(out_dir: &Path) -> PathBuf {
199226
convert_elf_to_bin(elf_path).await
200227
}
201228

229+
// dummy implementation because docsrs builds have no network access.
230+
// This will put an empty file in out_dir and return its path.
231+
#[cfg(docsrs_dummy_build)]
232+
#[cfg(feature = "bios")]
233+
async fn build_bios_stage_2(out_dir: &Path) -> PathBuf {
234+
use std::fs::File;
235+
236+
let path = out_dir.join("bootloader-dummy-bios-stage-2");
237+
238+
if File::create(&path).is_err() {
239+
panic!("Failed to create dummy bios second stage");
240+
}
241+
assert!(
242+
path.exists(),
243+
"bios second stage dummy file does not exist after file creation"
244+
);
245+
246+
path
247+
}
248+
202249
#[cfg(not(docsrs_dummy_build))]
203250
#[cfg(feature = "bios")]
204251
async fn build_bios_stage_3(out_dir: &Path) -> PathBuf {
@@ -241,6 +288,26 @@ async fn build_bios_stage_3(out_dir: &Path) -> PathBuf {
241288
convert_elf_to_bin(elf_path).await
242289
}
243290

291+
// dummy implementation because docsrs builds have no network access.
292+
// This will put an empty file in out_dir and return its path.
293+
#[cfg(docsrs_dummy_build)]
294+
#[cfg(feature = "bios")]
295+
async fn build_bios_stage_3(out_dir: &Path) -> PathBuf {
296+
use std::fs::File;
297+
298+
let path = out_dir.join("bootloader-dummy-bios-stage-3");
299+
300+
if File::create(&path).is_err() {
301+
panic!("Failed to create dummy bios stage-3");
302+
}
303+
assert!(
304+
path.exists(),
305+
"bios stage-3 dummy file does not exist after file creation"
306+
);
307+
308+
path
309+
}
310+
244311
#[cfg(not(docsrs_dummy_build))]
245312
#[cfg(feature = "bios")]
246313
async fn build_bios_stage_4(out_dir: &Path) -> PathBuf {
@@ -284,6 +351,26 @@ async fn build_bios_stage_4(out_dir: &Path) -> PathBuf {
284351
convert_elf_to_bin(elf_path).await
285352
}
286353

354+
// dummy implementation because docsrs builds have no network access.
355+
// This will put an empty file in out_dir and return its path.
356+
#[cfg(docsrs_dummy_build)]
357+
#[cfg(feature = "bios")]
358+
async fn build_bios_stage_4(out_dir: &Path) -> PathBuf {
359+
use std::fs::File;
360+
361+
let path = out_dir.join("bootloader-dummy-bios-stage-4");
362+
363+
if File::create(&path).is_err() {
364+
panic!("Failed to create dummy bios stage-4");
365+
}
366+
assert!(
367+
path.exists(),
368+
"bios stage-4 dummy file does not exist after file creation"
369+
);
370+
371+
path
372+
}
373+
287374
#[cfg(not(docsrs_dummy_build))]
288375
#[cfg(feature = "bios")]
289376
async fn convert_elf_to_bin(elf_path: PathBuf) -> PathBuf {

src/file_data_source.rs

+9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::{fs, io};
1111
pub enum FileDataSource {
1212
File(PathBuf),
1313
Data(Vec<u8>),
14+
Bytes(&'static [u8]),
1415
}
1516

1617
impl Debug for FileDataSource {
@@ -22,6 +23,9 @@ impl Debug for FileDataSource {
2223
FileDataSource::Data(d) => {
2324
f.write_fmt(format_args!("data source: {} raw bytes ", d.len()))
2425
}
26+
FileDataSource::Bytes(b) => {
27+
f.write_fmt(format_args!("data source: {} raw bytes ", b.len()))
28+
}
2529
}
2630
}
2731
}
@@ -34,6 +38,7 @@ impl FileDataSource {
3438
.with_context(|| format!("failed to read metadata of file `{}`", path.display()))?
3539
.len(),
3640
FileDataSource::Data(v) => v.len() as u64,
41+
FileDataSource::Bytes(s) => s.len() as u64,
3742
})
3843
}
3944
/// Copy this data source to the specified target that implements io::Write
@@ -51,6 +56,10 @@ impl FileDataSource {
5156
let mut cursor = Cursor::new(contents);
5257
io::copy(&mut cursor, target)?;
5358
}
59+
FileDataSource::Bytes(contents) => {
60+
let mut cursor = Cursor::new(contents);
61+
io::copy(&mut cursor, target)?;
62+
}
5463
};
5564

5665
Ok(())

src/lib.rs

+23-26
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ const KERNEL_FILE_NAME: &str = "kernel-x86_64";
4141
const RAMDISK_FILE_NAME: &str = "ramdisk";
4242
const CONFIG_FILE_NAME: &str = "boot.json";
4343

44+
#[cfg(feature = "uefi")]
45+
const UEFI_BOOTLOADER: &[u8] = include_bytes!(env!("UEFI_BOOTLOADER_PATH"));
46+
#[cfg(feature = "bios")]
47+
const BIOS_BOOT_SECTOR: &[u8] = include_bytes!(env!("BIOS_BOOT_SECTOR_PATH"));
48+
#[cfg(feature = "bios")]
49+
const BIOS_STAGE_2: &[u8] = include_bytes!(env!("BIOS_STAGE_2_PATH"));
50+
#[cfg(feature = "bios")]
51+
const BIOS_STAGE_3: &[u8] = include_bytes!(env!("BIOS_STAGE_3_PATH"));
52+
#[cfg(feature = "bios")]
53+
const BIOS_STAGE_4: &[u8] = include_bytes!(env!("BIOS_STAGE_4_PATH"));
54+
4455
/// Allows creating disk images for a specified set of files.
4556
///
4657
/// It can currently create `MBR` (BIOS), `GPT` (UEFI), and `TFTP` (UEFI) images.
@@ -98,28 +109,19 @@ impl DiskImageBuilder {
98109
#[cfg(feature = "bios")]
99110
/// Create an MBR disk image for booting on BIOS systems.
100111
pub fn create_bios_image(&self, image_path: &Path) -> anyhow::Result<()> {
101-
const BIOS_STAGE_3: &str = "boot-stage-3";
102-
const BIOS_STAGE_4: &str = "boot-stage-4";
103-
let bootsector_path = Path::new(env!("BIOS_BOOT_SECTOR_PATH"));
104-
let stage_2_path = Path::new(env!("BIOS_STAGE_2_PATH"));
105-
let stage_3_path = Path::new(env!("BIOS_STAGE_3_PATH"));
106-
let stage_4_path = Path::new(env!("BIOS_STAGE_4_PATH"));
112+
const BIOS_STAGE_3_NAME: &str = "boot-stage-3";
113+
const BIOS_STAGE_4_NAME: &str = "boot-stage-4";
114+
let stage_3 = FileDataSource::Bytes(BIOS_STAGE_3);
115+
let stage_4 = FileDataSource::Bytes(BIOS_STAGE_4);
107116
let mut internal_files = BTreeMap::new();
108-
internal_files.insert(
109-
BIOS_STAGE_3,
110-
FileDataSource::File(stage_3_path.to_path_buf()),
111-
);
112-
internal_files.insert(
113-
BIOS_STAGE_4,
114-
FileDataSource::File(stage_4_path.to_path_buf()),
115-
);
116-
117+
internal_files.insert(BIOS_STAGE_3_NAME, stage_3);
118+
internal_files.insert(BIOS_STAGE_4_NAME, stage_4);
117119
let fat_partition = self
118120
.create_fat_filesystem_image(internal_files)
119121
.context("failed to create FAT partition")?;
120122
mbr::create_mbr_disk(
121-
bootsector_path,
122-
stage_2_path,
123+
BIOS_BOOT_SECTOR,
124+
BIOS_STAGE_2,
123125
fat_partition.path(),
124126
image_path,
125127
)
@@ -135,12 +137,9 @@ impl DiskImageBuilder {
135137
/// Create a GPT disk image for booting on UEFI systems.
136138
pub fn create_uefi_image(&self, image_path: &Path) -> anyhow::Result<()> {
137139
const UEFI_BOOT_FILENAME: &str = "efi/boot/bootx64.efi";
138-
let bootloader_path = Path::new(env!("UEFI_BOOTLOADER_PATH"));
140+
139141
let mut internal_files = BTreeMap::new();
140-
internal_files.insert(
141-
UEFI_BOOT_FILENAME,
142-
FileDataSource::File(bootloader_path.to_path_buf()),
143-
);
142+
internal_files.insert(UEFI_BOOT_FILENAME, FileDataSource::Bytes(UEFI_BOOTLOADER));
144143
let fat_partition = self
145144
.create_fat_filesystem_image(internal_files)
146145
.context("failed to create FAT partition")?;
@@ -159,15 +158,13 @@ impl DiskImageBuilder {
159158
use std::{fs, ops::Deref};
160159

161160
const UEFI_TFTP_BOOT_FILENAME: &str = "bootloader";
162-
let bootloader_path = Path::new(env!("UEFI_BOOTLOADER_PATH"));
163161
fs::create_dir_all(tftp_path)
164162
.with_context(|| format!("failed to create out dir at {}", tftp_path.display()))?;
165163

166164
let to = tftp_path.join(UEFI_TFTP_BOOT_FILENAME);
167-
fs::copy(bootloader_path, &to).with_context(|| {
165+
fs::write(&to, UEFI_BOOTLOADER).with_context(|| {
168166
format!(
169-
"failed to copy bootloader from {} to {}",
170-
bootloader_path.display(),
167+
"failed to copy bootloader from the embedded binary to {}",
171168
to.display()
172169
)
173170
})?;

src/mbr.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@ use std::{
55
io::{self, Seek, SeekFrom},
66
path::Path,
77
};
8+
89
const SECTOR_SIZE: u32 = 512;
910

1011
pub fn create_mbr_disk(
11-
bootsector_path: &Path,
12-
second_stage_path: &Path,
12+
bootsector_binary: &[u8],
13+
second_stage_binary: &[u8],
1314
boot_partition_path: &Path,
1415
out_mbr_path: &Path,
1516
) -> anyhow::Result<()> {
16-
let mut boot_sector = File::open(bootsector_path).context("failed to open boot sector")?;
17+
use std::io::Cursor;
18+
let mut boot_sector = Cursor::new(bootsector_binary);
1719
let mut mbr =
1820
mbrman::MBR::read_from(&mut boot_sector, SECTOR_SIZE).context("failed to read MBR")?;
1921

@@ -23,12 +25,9 @@ pub fn create_mbr_disk(
2325
}
2426
}
2527

26-
let mut second_stage =
27-
File::open(second_stage_path).context("failed to open second stage binary")?;
28-
let second_stage_size = second_stage
29-
.metadata()
30-
.context("failed to read file metadata of second stage")?
31-
.len();
28+
let mut second_stage = Cursor::new(second_stage_binary);
29+
let second_stage_size = second_stage_binary.len() as u64;
30+
3231
let second_stage_start_sector = 1;
3332
let second_stage_sectors = ((second_stage_size - 1) / u64::from(SECTOR_SIZE) + 1)
3433
.try_into()

0 commit comments

Comments
 (0)