summaryrefslogtreecommitdiff
path: root/x/src/main.rs
blob: ef31f9dd4049ad03c5867f48c51c203038387e4d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use ovmf_prebuilt::{Arch, FileType, Prebuilt, Source};
use std::{
    env,
    process::{Command, exit},
};

fn main() {
    // read env variables that were set in build script
    let uefi_path = env!("UEFI_PATH");
    let bios_path = env!("BIOS_PATH");

    // parse mode from CLI
    let args: Vec<String> = env::args().collect();
    let prog = &args[0];

    // choose whether to start the UEFI or BIOS image
    let uefi = match args.get(1).map(|s| s.to_lowercase()) {
        Some(ref s) if s == "uefi" => true,
        Some(ref s) if s == "bios" => false,
        Some(ref s) if s == "-h" || s == "--help" => {
            println!("Usage: {prog} [uefi|bios]");
            println!("  uefi  - boot using OVMF (UEFI)");
            println!("  bios  - boot using legacy BIOS");
            exit(0);
        }
        _ => true,
    };

    let mut cmd = Command::new("qemu-system-x86_64");
    // print serial output to the shell
    cmd.arg("-serial").arg("mon:stdio");
    // don't display video output
    cmd.arg("-display").arg("none");
    // enable the guest to exit qemu
    cmd.arg("-device").arg("isa-debug-exit,iobase=0xf4,iosize=0x04");

    if uefi {
        let prebuilt = Prebuilt::fetch(
            Source::LATEST,
            "target/ovmf",
        )
        .expect("failed to update prebuilt");

        let code = prebuilt.get_file(
            Arch::X64,
            FileType::Code,
        );
        let vars = prebuilt.get_file(
            Arch::X64,
            FileType::Vars,
        );

        cmd.arg("-drive").arg(format!("format=raw,file={uefi_path}"));
        cmd.arg("-drive").arg(
            format!(
                "if=pflash,format=raw,unit=0,file={},readonly=on",
                code.display()
            ),
        );
        // copy vars and enable rw instead of snapshot if you want to store data
        // (e.g. enroll secure boot keys)
        cmd.arg("-drive").arg(
            format!(
                "if=pflash,format=raw,unit=1,file={},snapshot=on",
                vars.display()
            ),
        );
    } else {
        cmd.arg("-drive").arg(format!("format=raw,file={bios_path}"));
    }

    let mut child = cmd.spawn().expect("failed to start qemu-system-x86_64");
    let status = child.wait().expect("failed to wait on qemu");
    match status.code().unwrap_or(1) {
        0x10 => 0, // success
        0x11 => 1, // failure
        _ => 2,    // unknown fault
    };
}