use std::{ fs::{File, OpenOptions}, io::{self, BufReader, BufWriter}, path::{Path, PathBuf}, }; use fscommon::BufStream; use crate::{build::cargo::CargoBuilder, env::BuildEnv, error::Error, util}; use super::{ImageBuilt, InitrdGenerated, KernelProcessed}; pub struct YbootBuilt(PathBuf); fn build_yboot(env: &BuildEnv) -> Result { log::info!("Building yboot"); CargoBuilder::Host(env.verbose).build("boot/yboot")?; let binary = env.workspace_root.join(format!( "boot/yboot/target/x86_64-unknown-uefi/debug/yboot.efi" )); Ok(YbootBuilt(binary)) } fn copy_into_fat( dir: &fatfs::Dir<'_, BufStream>, src: impl AsRef, dst: impl AsRef, ) -> Result<(), Error> { let src = src.as_ref(); let dst = dst.as_ref(); log::debug!("{} -> {}", src.display(), dst); let mut dst = dir.create_file(dst)?; let mut src = BufReader::new(File::open(src)?); dst.truncate()?; let mut dst = BufWriter::new(dst); io::copy(&mut src, &mut dst)?; Ok(()) } fn build_uefi_image( env: &BuildEnv, yboot: YbootBuilt, kernel: KernelProcessed, initrd: InitrdGenerated, ) -> Result { log::info!("Building x86-64 UEFI image"); let image_path = env.kernel_output_dir.join("image.fat32"); if !image_path.exists() { util::run_external_command( "dd", [ "if=/dev/zero", &format!("of={}", image_path.display()), "bs=1M", "count=256", ], false, )?; util::run_external_command( "mkfs.vfat", ["-F32".as_ref(), image_path.as_os_str()], false, )?; } let image_file = OpenOptions::new() .read(true) .write(true) .open(&image_path)?; let buf_stream = fscommon::BufStream::new(image_file); let fs = fatfs::FileSystem::new(buf_stream, fatfs::FsOptions::new())?; let root_dir = fs.root_dir(); let boot_dir = root_dir.create_dir("EFI")?.create_dir("Boot")?; copy_into_fat(&boot_dir, &yboot.0, "BootX64.efi")?; copy_into_fat(&root_dir, &kernel.0 .0, "kernel.elf")?; copy_into_fat(&root_dir, &initrd.0, "initrd.img")?; Ok(ImageBuilt(image_path)) } pub fn build_image( env: &BuildEnv, kernel: KernelProcessed, initrd: InitrdGenerated, ) -> Result { let yboot = build_yboot(env)?; let image = build_uefi_image(env, yboot, kernel, initrd)?; Ok(image) }