Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Create FAT file system image from .efi image
Can be run in QEMU through `qemu-system-x86_64 -drive file=bootimage-uefi-blog_os.fat -bios ovmf/OVMF_CODE.fd`.
  • Loading branch information
phil-opp committed Jan 13, 2021
1 parent dc1267b commit 2ac0c82
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 4 deletions.
102 changes: 102 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Expand Up @@ -46,6 +46,7 @@ llvm-tools = { version = "0.1.1", optional = true }
thiserror = { version = "1.0.20", optional = true }
json = { version = "0.12.4", optional = true }
rsdp = { version = "1.0.0", optional = true }
fatfs = { version = "0.3.4", optional = true }

[dependencies.font8x8]
version = "0.2.5"
Expand All @@ -60,7 +61,7 @@ serde = { version = "1.0", features = ["derive"], optional = true}

[features]
default = []
builder = ["argh", "thiserror", "displaydoc", "anyhow", "llvm-tools", "json"]
builder = ["argh", "thiserror", "displaydoc", "anyhow", "llvm-tools", "json", "fatfs"]
runner = ["anyhow"]
bios_bin = ["binary", "vga_320x200", "rsdp"]
uefi_bin = ["binary", "uefi", "font8x8"]
Expand Down
94 changes: 91 additions & 3 deletions src/bin/builder.rs
Expand Up @@ -2,7 +2,7 @@ use anyhow::{anyhow, Context};
use argh::FromArgs;
use bootloader::disk_image::create_disk_image;
use std::{
fs,
fs, io,
path::{Path, PathBuf},
process::Command,
str::FromStr,
Expand Down Expand Up @@ -66,14 +66,30 @@ impl FromStr for Firmware {
}
}

impl Firmware {
fn uefi(&self) -> bool {
match self {
Firmware::Bios => false,
Firmware::Uefi | Firmware::All => true,
}
}

fn bios(&self) -> bool {
match self {
Firmware::Bios | Firmware::All => true,
Firmware::Uefi => false,
}
}
}

/// Firmware must be one of `uefi`, `bios`, or `all`.
#[derive(Debug, displaydoc::Display, Eq, PartialEq, Copy, Clone)]
struct FirmwareParseError;

fn main() -> anyhow::Result<()> {
let args: BuildArguments = argh::from_env();

if args.firmware == Firmware::Uefi || args.firmware == Firmware::All {
if args.firmware.uefi() {
let build_or_run = if args.run { "run" } else { "build" };
let mut cmd = Command::new(env!("CARGO"));
cmd.arg(build_or_run).arg("--bin").arg("uefi");
Expand All @@ -91,9 +107,81 @@ fn main() -> anyhow::Result<()> {
cmd.env("KERNEL", &args.kernel_binary);
cmd.env("KERNEL_MANIFEST", &args.kernel_manifest);
assert!(cmd.status()?.success());

// Retrieve binary paths
cmd.arg("--message-format").arg("json");
let output = cmd
.output()
.context("failed to execute kernel build with json output")?;
if !output.status.success() {
return Err(anyhow!("{}", String::from_utf8_lossy(&output.stderr)));
}
let mut executables = Vec::new();
for line in String::from_utf8(output.stdout)
.context("build JSON output is not valid UTF-8")?
.lines()
{
let mut artifact = json::parse(line).context("build JSON output is not valid JSON")?;
if let Some(executable) = artifact["executable"].take_string() {
executables.push(PathBuf::from(executable));
}
}

assert_eq!(executables.len(), 1);
let executable_path = executables.pop().unwrap();
let executable_name = executable_path.file_stem().unwrap().to_str().unwrap();
let kernel_name = args.kernel_binary.file_name().unwrap().to_str().unwrap();

if let Some(out_dir) = &args.out_dir {
let efi_file =
out_dir.join(format!("bootimage-{}-{}.efi", executable_name, kernel_name));
fs::copy(&executable_path, &efi_file).context("failed to copy efi file to out dir")?;

let efi_size = fs::metadata(&efi_file)
.context("failed to read metadata of efi file")?
.len();

// create fat partition
{
const MB: u64 = 1024 * 1024;

let fat_path = efi_file.with_extension("fat");
dbg!(&fat_path);
let fat_file = fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(true)
.open(&fat_path)
.context("Failed to create UEFI FAT file")?;
let efi_size_rounded = ((efi_size - 1) / MB + 1) * MB;
fat_file
.set_len(dbg!(efi_size_rounded))
.context("failed to set UEFI FAT file length")?;

// create new FAT partition
fatfs::format_volume(&fat_file, fatfs::FormatVolumeOptions::new())
.context("Failed to format UEFI FAT file")?;

// copy EFI file to FAT filesystem
let partition = fatfs::FileSystem::new(&fat_file, fatfs::FsOptions::new())
.context("Failed to open FAT file system of UEFI FAT file")?;
let root_dir = partition.root_dir();
root_dir.create_dir("efi")?;
root_dir.create_dir("efi/boot")?;
let mut bootx64 = root_dir.create_file("efi/boot/bootx64.efi")?;
bootx64.truncate()?;
io::copy(&mut fs::File::open(&executable_path)?, &mut bootx64)?;
}

// create gpt disk
{
//todo!()
}
}
}

if args.firmware == Firmware::Bios || args.firmware == Firmware::All {
if args.firmware.bios() {
let mut cmd = Command::new(env!("CARGO"));
cmd.arg("build").arg("--bin").arg("bios");
cmd.arg("--profile").arg("release");
Expand Down

0 comments on commit 2ac0c82

Please sign in to comment.