ableos/repbuild/src/main.rs

172 lines
4.7 KiB
Rust
Raw Normal View History

2023-01-06 18:57:20 -06:00
use error_stack::{bail, report, Context, IntoReport, Result, ResultExt};
use fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek};
2023-01-07 15:18:47 -06:00
use std::{fmt::Display, fs::File, io, path::Path, process::Command};
2023-01-06 18:57:20 -06:00
fn main() -> Result<(), Error> {
env_logger::init();
let mut args = std::env::args();
args.next();
match args.next().as_deref() {
Some("build" | "b") => build(
args.next()
.map(|x| x == "-r" || x == "--release")
.unwrap_or_default(),
)
.change_context(Error::Build),
Some("run" | "r") => {
build(
args.next()
.map(|x| x == "-r" || x == "--release")
.unwrap_or_default(),
)?;
run()
}
Some("help" | "h") => {
println!(concat!(
"AbleOS RepBuild\n",
"Subcommands:\n",
" build (b): Build a bootable disk image\n",
" help (h): Print this message\n",
" run (r): Build and run AbleOS in QEMU\n\n",
"Options for build and run:\n",
" -r: build in release mode",
),);
2023-01-06 18:57:20 -06:00
Ok(())
2022-08-07 07:35:55 -05:00
}
2023-01-06 18:57:20 -06:00
_ => Err(report!(Error::InvalidSubCom)),
2022-08-07 07:35:55 -05:00
}
2022-08-03 02:11:51 -05:00
}
2023-01-06 18:57:20 -06:00
fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
let path = Path::new("target/disk.img");
match std::fs::metadata(path) {
Err(e) if e.kind() == io::ErrorKind::NotFound => (),
Err(e) => bail!(e),
Ok(_) => {
return FileSystem::new(
File::options().read(true).write(true).open(path)?,
FsOptions::new(),
)
.into_report()
2022-08-07 07:35:55 -05:00
}
2023-01-06 18:57:20 -06:00
}
2022-12-03 10:47:10 -06:00
2023-01-06 18:57:20 -06:00
let mut img = File::options()
.read(true)
.write(true)
.create(true)
.open(path)?;
img.set_len(1024 * 1024 * 64)?;
2022-12-03 10:47:10 -06:00
2023-01-06 18:57:20 -06:00
fatfs::format_volume(&mut img, FormatVolumeOptions::new())?;
2023-01-06 18:57:20 -06:00
let fs = FileSystem::new(img, FsOptions::new())?;
let bootdir = fs.root_dir().create_dir("efi")?.create_dir("boot")?;
2023-01-06 18:57:20 -06:00
io::copy(
&mut File::open("limine/BOOTX64.EFI")?,
&mut bootdir.create_file("bootx64.efi")?,
)?;
2023-01-06 18:57:20 -06:00
io::copy(
2023-01-14 18:00:43 -06:00
&mut File::open("repbuild/limine.cfg")?,
2023-01-06 18:57:20 -06:00
&mut fs.root_dir().create_file("limine.cfg")?,
)?;
2022-08-07 07:35:55 -05:00
2023-01-07 16:44:50 -06:00
io::copy(
2023-01-14 18:00:43 -06:00
&mut File::open("repbuild/background.bmp")?,
2023-01-07 16:44:50 -06:00
&mut fs.root_dir().create_file("background.bmp")?,
)?;
2023-01-06 18:57:20 -06:00
drop(bootdir);
Ok(fs)
}
2022-08-07 07:35:55 -05:00
2023-01-06 18:57:20 -06:00
fn build(release: bool) -> Result<(), Error> {
let fs = get_fs().change_context(Error::Io)?;
let mut com = Command::new("cargo");
com.current_dir("kernel");
com.args(["b"]);
if release {
com.arg("-r");
2022-08-07 07:35:55 -05:00
}
match com.status() {
Ok(s) if s.code() != Some(0) => bail!(Error::Build),
Err(e) => bail!(report!(e).change_context(Error::Build)),
_ => (),
}
2023-01-06 18:57:20 -06:00
(|| -> std::io::Result<_> {
io::copy(
&mut File::open(
Path::new("target/x86_64-ableos")
.join(if release { "release" } else { "debug" })
.join("kernel"),
)?,
&mut fs.root_dir().create_file("kernel")?,
)
.map(|_| ())
})()
.into_report()
.change_context(Error::Io)
2022-08-03 02:11:51 -05:00
}
2023-01-06 18:57:20 -06:00
fn run() -> Result<(), Error> {
let mut com = Command::new("qemu-system-x86_64");
2023-01-06 18:57:20 -06:00
#[rustfmt::skip]
com.args([
2023-01-09 08:27:10 -06:00
"-bios",
std::env::var("REPBUILD_QEMU_FIRMWARE_PATH")
.as_deref()
.unwrap_or("/usr/share/OVMF/OVMF_CODE.fd"),
2023-01-06 18:57:20 -06:00
"-drive", "file=target/disk.img,format=raw",
"-m", "4G",
"-serial", "stdio",
"-smp", "cores=2",
]);
#[cfg(target_os = "linux")]
{
com.args(["-enable-kvm", "-cpu", "host"]);
}
2023-01-06 18:57:20 -06:00
match com
2023-01-06 18:57:20 -06:00
.status()
.into_report()
.change_context(Error::ProcessSpawn)?
{
s if s.success() => Ok(()),
s => Err(report!(Error::Qemu(s.code()))),
2022-08-07 07:35:55 -05:00
}
2022-08-03 02:11:51 -05:00
}
2023-01-06 18:57:20 -06:00
#[derive(Debug)]
enum Error {
Build,
InvalidSubCom,
Io,
ProcessSpawn,
Qemu(Option<i32>),
2022-08-03 02:11:51 -05:00
}
2023-01-06 18:57:20 -06:00
impl Context for Error {}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Build => f.write_str("failed to build the kernel"),
Self::InvalidSubCom => {
f.write_str("missing or invalid subcommand (available: build, run)")
}
Self::Io => f.write_str("IO error"),
Self::ProcessSpawn => f.write_str("failed to spawn a process"),
Self::Qemu(Some(c)) => write!(f, "QEMU Error: {c}"),
Self::Qemu(None) => write!(f, "QEMU Error: interrupted by signal"),
}
}
2022-08-03 02:11:51 -05:00
}