Skip to content

Commit 9583eaf

Browse files
committed
Create BIOS disk image from first stage with single FAT partition
1 parent a28bbf1 commit 9583eaf

File tree

2 files changed

+85
-13
lines changed

2 files changed

+85
-13
lines changed

src/bin/builder.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,9 @@ fn main() -> anyhow::Result<()> {
156156

157157
if args.firmware.bios() {
158158
let mut cmd = Command::new(env!("CARGO"));
159-
cmd.arg("build").arg("--bin").arg("bios");
160-
cmd.arg("--profile").arg("release");
161-
cmd.arg("-Z").arg("unstable-options");
162-
cmd.arg("--target").arg("x86_64-bootloader.json");
163-
cmd.arg("--features")
164-
.arg(args.features.join(" ") + " bios_bin");
159+
cmd.arg("build").arg("-p").arg("bootloader_first_stage");
160+
cmd.arg("--profile").arg("first-stage");
161+
cmd.arg("--target").arg("bios/first_stage/x86-16bit.json");
165162
cmd.arg("-Zbuild-std=core");
166163
cmd.arg("-Zbuild-std-features=compiler-builtins-mem");
167164
if let Some(target_dir) = &args.target_dir {
@@ -170,7 +167,6 @@ fn main() -> anyhow::Result<()> {
170167
if args.quiet {
171168
cmd.arg("--quiet");
172169
}
173-
cmd.env("RUSTFLAGS", "-C opt-level=s");
174170
assert!(cmd.status()?.success());
175171

176172
// Retrieve binary paths
@@ -201,7 +197,7 @@ fn main() -> anyhow::Result<()> {
201197
.unwrap()
202198
.join(format!("boot-{}-{}.img", executable_name, kernel_name));
203199

204-
create_disk_image(&executable_path, &output_bin_path)
200+
create_disk_image(&executable_path, &output_bin_path, &args.kernel_binary)
205201
.context("Failed to create bootable disk image")?;
206202

207203
if let Some(out_dir) = &args.out_dir {

src/disk_image.rs

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
1-
use std::{io, path::Path, process::Command};
1+
use anyhow::Context;
2+
use std::{
3+
fs,
4+
io::{self, Seek, Write},
5+
path::Path,
6+
process::Command,
7+
};
28
use thiserror::Error;
39

410
/// Creates a bootable disk image from the given bootloader executable.
511
pub fn create_disk_image(
612
bootloader_elf_path: &Path,
713
output_bin_path: &Path,
8-
) -> Result<(), DiskImageError> {
9-
let llvm_tools = llvm_tools::LlvmTools::new()?;
14+
kernel_binary: &Path,
15+
) -> anyhow::Result<()> {
16+
let llvm_tools =
17+
llvm_tools::LlvmTools::new().map_err(|err| anyhow::anyhow!("failed to get llvm tools"))?;
1018
let objcopy = llvm_tools
1119
.tool(&llvm_tools::exe("llvm-objcopy"))
1220
.ok_or(DiskImageError::LlvmObjcopyNotFound)?;
1321

14-
// convert bootloader to binary
22+
// convert first stage to binary
1523
let mut cmd = Command::new(objcopy);
1624
cmd.arg("-I").arg("elf64-x86-64");
1725
cmd.arg("-O").arg("binary");
@@ -25,9 +33,77 @@ pub fn create_disk_image(
2533
if !output.status.success() {
2634
return Err(DiskImageError::ObjcopyFailed {
2735
stderr: output.stderr,
28-
});
36+
})
37+
.context("objcopy failed");
2938
}
3039

40+
use std::fs::OpenOptions;
41+
let mut disk_image = OpenOptions::new()
42+
.write(true)
43+
.open(&output_bin_path)
44+
.map_err(|err| DiskImageError::Io {
45+
message: "failed to open boot image",
46+
error: err,
47+
})?;
48+
let file_size = disk_image
49+
.metadata()
50+
.map_err(|err| DiskImageError::Io {
51+
message: "failed to get size of boot image",
52+
error: err,
53+
})?
54+
.len();
55+
const BLOCK_SIZE: u64 = 512;
56+
assert_eq!(file_size, BLOCK_SIZE);
57+
58+
let kernel_size = fs::metadata(&kernel_binary)
59+
.context("failed to read metadata of kernel binary")?
60+
.len();
61+
62+
// create fat partition
63+
const MB: u64 = 1024 * 1024;
64+
let fat_size = kernel_size; // TODO plus second stage size
65+
let fat_size_padded_and_rounded = ((fat_size + 1024 * 64 - 1) / MB + 1) * MB;
66+
let fat_file_path = {
67+
let fat_path = output_bin_path.with_extension("fat");
68+
let fat_file = fs::OpenOptions::new()
69+
.read(true)
70+
.write(true)
71+
.create(true)
72+
.truncate(true)
73+
.open(&fat_path)
74+
.context("Failed to create UEFI FAT file")?;
75+
fat_file
76+
.set_len(fat_size_padded_and_rounded)
77+
.context("failed to set UEFI FAT file length")?;
78+
79+
// create new FAT partition
80+
let format_options = fatfs::FormatVolumeOptions::new().volume_label(*b"BOOT ");
81+
fatfs::format_volume(&fat_file, format_options)
82+
.context("Failed to format UEFI FAT file")?;
83+
84+
// copy kernel to FAT filesystem
85+
let partition = fatfs::FileSystem::new(&fat_file, fatfs::FsOptions::new())
86+
.context("Failed to open FAT file system of UEFI FAT file")?;
87+
let root_dir = partition.root_dir();
88+
let mut kernel_file = root_dir.create_file("kernel-x86_64")?;
89+
kernel_file.truncate()?;
90+
io::copy(&mut fs::File::open(&kernel_binary)?, &mut kernel_file)?;
91+
92+
fat_path
93+
};
94+
95+
disk_image.seek(io::SeekFrom::Start(446))?;
96+
disk_image.write_all(&[0x80, 0, 0, 0, 0x04, 0, 0, 0])?;
97+
let start_sector = 1u32.to_le_bytes();
98+
let size_sectors = u32::try_from(&fat_size_padded_and_rounded / 512)
99+
.unwrap()
100+
.to_le_bytes();
101+
disk_image.write_all(&start_sector)?;
102+
disk_image.write_all(&size_sectors)?;
103+
104+
disk_image.seek(io::SeekFrom::Start(512))?;
105+
io::copy(&mut fs::File::open(&kernel_binary)?, &mut disk_image)?;
106+
31107
pad_to_nearest_block_size(output_bin_path)?;
32108
Ok(())
33109
}

0 commit comments

Comments
 (0)