diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0dc8b93..86d7cf6d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,15 +45,20 @@ jobs: name: Run strategy: matrix: - target: [x86_64, aarch64, riscv64] + target: [x86_64, x86_64-uefi, aarch64, riscv64] os: [ubuntu-latest, macos-latest, windows-latest] + exclude: + - target: x86_64-uefi + os: macos-latest + - target: x86_64-uefi + os: windows-latest runs-on: ${{ matrix.os }} steps: - name: Install QEMU, NASM (ubuntu) if: matrix.os == 'ubuntu-latest' run: | sudo apt-get update - sudo apt-get install qemu-system-x86 qemu-system-arm qemu-system-misc nasm + sudo apt-get install qemu-system-x86 qemu-system-arm qemu-system-misc ovmf nasm - name: Install QEMU, NASM (macos) if: matrix.os == 'macos-latest' run: | @@ -89,7 +94,7 @@ jobs: - name: Install QEMU run: | sudo apt-get update - sudo apt-get install -y --no-install-recommends qemu-system-x86 + sudo apt-get install -y --no-install-recommends qemu-system-x86 ovmf - uses: actions/checkout@v4 with: lfs: true @@ -112,6 +117,10 @@ jobs: run: cargo xtask ci qemu --target x86_64 --accel - name: Run QEMU (hello_world, release) run: cargo xtask ci qemu --target x86_64 --accel --release + - name: Run UEFI (dev) + run: cargo xtask ci qemu --target x86_64-uefi --accel + - name: Run UEFI (release) + run: cargo xtask ci qemu --target x86_64-uefi --accel --release - name: Run Firecracker (hello_world, dev) run: cargo xtask ci firecracker --target x86_64-fc --features fc - name: Run Firecracker (hello_world, release) diff --git a/Cargo.lock b/Cargo.lock index 27583360..d32e6b1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -294,6 +294,7 @@ dependencies = [ "multiboot", "naked-function", "nasm-rs", + "qemu-exit", "riscv", "sbi", "spinning_top", @@ -430,6 +431,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "qemu-exit" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bb0fd6580eeed0103c054e3fba2c2618ff476943762f28a645b63b8692b21c9" + [[package]] name = "quote" version = "1.0.33" @@ -654,6 +661,7 @@ checksum = "a79fcb420624743c895bad0f9480fbc2f64e7c8d8611fb1ada6bdd799942feb4" dependencies = [ "cfg-if", "log", + "qemu-exit", "uefi", ] diff --git a/Cargo.toml b/Cargo.toml index a08c7229..389b2989 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,8 @@ spinning_top = "0.3" [target.'cfg(target_os = "uefi")'.dependencies] uefi = "0.26" -uefi-services = "0.23" +uefi-services = { version = "0.23", features = ["qemu"] } +qemu-exit = "3" [target.'cfg(target_arch = "riscv64")'.dependencies] fdt = "0.1" diff --git a/src/uefi.rs b/src/uefi.rs index fb70b7f5..1742dcce 100644 --- a/src/uefi.rs +++ b/src/uefi.rs @@ -1,3 +1,4 @@ +use qemu_exit::QEMUExit; use uefi::prelude::*; // Entry Point of the Uefi Loader @@ -5,5 +6,9 @@ use uefi::prelude::*; fn loader_main(_handle: Handle, mut system_table: SystemTable) -> Status { uefi_services::init(&mut system_table).unwrap(); - Status::SUCCESS + log::info!("Hello, UEFI!"); + + let custom_exit_success = 3; + let qemu_exit_handle = qemu_exit::X86::new(0xf4, custom_exit_success); + qemu_exit_handle.exit_success() } diff --git a/xtask/src/artifact.rs b/xtask/src/artifact.rs index e86298f2..e93f47f5 100644 --- a/xtask/src/artifact.rs +++ b/xtask/src/artifact.rs @@ -49,7 +49,7 @@ impl Artifact { self.target_dir(), self.target.triple().as_ref(), self.profile_path_component().as_ref(), - self.target.build_name().as_ref(), + self.target.image_name().as_ref(), ] .iter() .collect::() @@ -61,7 +61,7 @@ impl Artifact { self.target_dir(), self.target.name().as_ref(), self.profile_path_component().as_ref(), - self.target.dist_name().as_ref(), + self.target.image_name().as_ref(), ] .iter() .collect::() diff --git a/xtask/src/ci/qemu.rs b/xtask/src/ci/qemu.rs index 764c425d..96e0599a 100644 --- a/xtask/src/ci/qemu.rs +++ b/xtask/src/ci/qemu.rs @@ -41,16 +41,23 @@ impl Qemu { let sh = crate::sh()?; + if self.build.target() == Target::X86_64Uefi { + if super::in_ci() { + sh.copy_file("/usr/share/OVMF/OVMF_CODE.fd", "OVMF_CODE.fd")?; + sh.copy_file("/usr/share/OVMF/OVMF_VARS.fd", "OVMF_VARS.fd")?; + } + + sh.create_dir("target/esp/efi/boot")?; + sh.copy_file(self.build.dist_object(), "target/esp/efi/boot/bootx64.efi")?; + } + let target = self.build.target(); let arch = target.arch(); let qemu = env::var_os("QEMU").unwrap_or_else(|| format!("qemu-system-{arch}").into()); - let dist_object = self.build.dist_object(); let qemu = cmd!(sh, "{qemu}") .args(&["-display", "none"]) .args(&["-serial", "stdio"]) - .arg("-kernel") - .arg(&dist_object) .args(self.machine_args()) .args(self.cpu_args()) .args(self.memory_args()); @@ -86,7 +93,7 @@ impl Qemu { fn cpu_args(&self) -> Vec { match self.build.target() { - Target::X86_64 | Target::X86_64Fc | Target::X86_64Uefi => { + Target::X86_64 | Target::X86_64Uefi => { let mut cpu_args = if self.accel { if cfg!(target_os = "linux") { vec![ @@ -102,21 +109,55 @@ impl Qemu { }; cpu_args.push("-device".to_string()); cpu_args.push("isa-debug-exit,iobase=0xf4,iosize=0x04".to_string()); - cpu_args.push("-initrd".to_string()); - cpu_args.push( - self.build - .ci_image(&self.image) - .into_os_string() - .into_string() - .unwrap(), - ); + + match self.build.target() { + Target::X86_64 => { + cpu_args.push("-kernel".to_string()); + cpu_args.push( + self.build + .dist_object() + .into_os_string() + .into_string() + .unwrap(), + ); + cpu_args.push("-initrd".to_string()); + cpu_args.push( + self.build + .ci_image(&self.image) + .into_os_string() + .into_string() + .unwrap(), + ); + } + Target::X86_64Uefi => { + cpu_args.push("-drive".to_string()); + cpu_args + .push("if=pflash,format=raw,readonly=on,file=OVMF_CODE.fd".to_string()); + cpu_args.push("-drive".to_string()); + cpu_args + .push("if=pflash,format=raw,readonly=on,file=OVMF_VARS.fd".to_string()); + cpu_args.push("-drive".to_string()); + cpu_args.push("format=raw,file=fat:rw:target/esp".to_string()); + } + _ => unreachable!(), + } cpu_args } + Target::X86_64Fc => panic!("unsupported"), Target::Aarch64 => { let mut cpu_args = if self.accel { todo!() } else { - vec!["-cpu".to_string(), "cortex-a72".to_string()] + vec![ + "-cpu".to_string(), + "cortex-a72".to_string(), + "-kernel".to_string(), + self.build + .dist_object() + .into_os_string() + .into_string() + .unwrap(), + ] }; cpu_args.push("-semihosting".to_string()); cpu_args.push("-device".to_string()); @@ -130,7 +171,16 @@ impl Qemu { let mut cpu_args = if self.accel { todo!() } else { - vec!["-cpu".to_string(), "rv64".to_string()] + vec![ + "-cpu".to_string(), + "rv64".to_string(), + "-kernel".to_string(), + self.build + .dist_object() + .into_os_string() + .into_string() + .unwrap(), + ] }; cpu_args.push("-initrd".to_string()); cpu_args.push( @@ -150,8 +200,14 @@ impl Qemu { if self.image == "hello_c" { memory = memory.max(64); } - if self.build.target() == Target::Aarch64 { - memory = memory.max(256); + match self.build.target() { + Target::X86_64Uefi => { + memory = memory.max(64); + } + Target::Aarch64 => { + memory = memory.max(256); + } + _ => {} } memory } diff --git a/xtask/src/target.rs b/xtask/src/target.rs index 59da310b..c328dce0 100644 --- a/xtask/src/target.rs +++ b/xtask/src/target.rs @@ -89,19 +89,12 @@ impl Target { } } - pub fn build_name(&self) -> &'static str { + pub fn image_name(&self) -> &'static str { match self { Self::X86_64Uefi => "hermit-loader.efi", _ => "hermit-loader", } } - - pub fn dist_name(&self) -> &'static str { - match self { - Self::X86_64Uefi => "BootX64.efi", - _ => "hermit-loader", - } - } } impl FromStr for Target {