diff --git a/uefi-test-runner/Cargo.toml b/uefi-test-runner/Cargo.toml index 569efd3fa..2a94fe8b1 100644 --- a/uefi-test-runner/Cargo.toml +++ b/uefi-test-runner/Cargo.toml @@ -17,4 +17,4 @@ qemu-exit = "3.0.0" # This feature should only be enabled in our CI, it disables some tests # which currently fail in that environment (see #103 for discussion). ci = [] -qemu = ["uefi-services/qemu"] + diff --git a/uefi-test-runner/README.md b/uefi-test-runner/README.md index e82ed7fb0..56bfd6ad7 100644 --- a/uefi-test-runner/README.md +++ b/uefi-test-runner/README.md @@ -1,6 +1,9 @@ -# Running the tests +# uefi-test-runner -This file documents the process of building and running the test suite. +This package is a UEFI application for running tests. It is intended to +be run in a specially-configured QEMU VM. This allows us to test the +parts of the `uefi` package that depend on a UEFI environment, such as +various boot services and protocols. ## Prerequisites diff --git a/uefi-test-runner/src/main.rs b/uefi-test-runner/src/main.rs index 87e53278f..3dc638f00 100644 --- a/uefi-test-runner/src/main.rs +++ b/uefi-test-runner/src/main.rs @@ -8,7 +8,7 @@ extern crate log; #[macro_use] extern crate alloc; -use alloc::string::String; +use alloc::string::ToString; use uefi::prelude::*; use uefi::proto::console::serial::Serial; use uefi_services::{print, println}; @@ -24,10 +24,9 @@ fn efi_main(image: Handle, mut st: SystemTable) -> Status { // unit tests here - // output firmware-vendor (CStr16 to Rust string) - let mut buf = String::new(); - st.firmware_vendor().as_str_in_buf(&mut buf).unwrap(); - info!("Firmware Vendor: {}", buf.as_str()); + let firmware_vendor = st.firmware_vendor(); + info!("Firmware Vendor: {}", firmware_vendor); + assert_eq!(firmware_vendor.to_string(), "EDK II"); // Test print! and println! macros. let (print, println) = ("print!", "println!"); // necessary for clippy to ignore @@ -82,64 +81,51 @@ fn check_revision(rev: uefi::table::Revision) { /// of it, we just pause the tests for a couple of seconds to allow visual /// inspection of the output. fn check_screenshot(bt: &BootServices, name: &str) { - if cfg!(feature = "qemu") { - let serial_handles = bt - .find_handles::() - .expect("Failed to get serial handles"); - - // Use the second serial device handle. Opening a serial device - // in exclusive mode breaks the connection between stdout and - // the serial device, and we don't want that to happen to the - // first serial device since it's used for log transport. - let serial_handle = *serial_handles - .get(1) - .expect("Second serial device is missing"); - - let mut serial = bt - .open_protocol_exclusive::(serial_handle) - .expect("Could not open serial protocol"); - - // Set a large timeout to avoid problems with CI - let mut io_mode = *serial.io_mode(); - io_mode.timeout = 10_000_000; - serial - .set_attributes(&io_mode) - .expect("Failed to configure serial port timeout"); - - // Send a screenshot request to the host - serial - .write(b"SCREENSHOT: ") - .expect("Failed to send request"); - let name_bytes = name.as_bytes(); - serial.write(name_bytes).expect("Failed to send request"); - serial.write(b"\n").expect("Failed to send request"); - - // Wait for the host's acknowledgement before moving forward - let mut reply = [0; 3]; - serial - .read(&mut reply[..]) - .expect("Failed to read host reply"); - - assert_eq!(&reply[..], b"OK\n", "Unexpected screenshot request reply"); - } else { - // Outside of QEMU, give the user some time to inspect the output - bt.stall(3_000_000); - } + let serial_handles = bt + .find_handles::() + .expect("Failed to get serial handles"); + + // Use the second serial device handle. Opening a serial device + // in exclusive mode breaks the connection between stdout and + // the serial device, and we don't want that to happen to the + // first serial device since it's used for log transport. + let serial_handle = *serial_handles + .get(1) + .expect("Second serial device is missing"); + + let mut serial = bt + .open_protocol_exclusive::(serial_handle) + .expect("Could not open serial protocol"); + + // Set a large timeout to avoid problems with CI + let mut io_mode = *serial.io_mode(); + io_mode.timeout = 10_000_000; + serial + .set_attributes(&io_mode) + .expect("Failed to configure serial port timeout"); + + // Send a screenshot request to the host + serial + .write(b"SCREENSHOT: ") + .expect("Failed to send request"); + let name_bytes = name.as_bytes(); + serial.write(name_bytes).expect("Failed to send request"); + serial.write(b"\n").expect("Failed to send request"); + + // Wait for the host's acknowledgement before moving forward + let mut reply = [0; 3]; + serial + .read(&mut reply[..]) + .expect("Failed to read host reply"); + + assert_eq!(&reply[..], b"OK\n", "Unexpected screenshot request reply"); } fn shutdown(image: uefi::Handle, mut st: SystemTable) -> ! { - use uefi::table::runtime::ResetType; - // Get our text output back. st.stdout().reset(false).unwrap(); - // Inform the user, and give him time to read on real hardware - if cfg!(not(feature = "qemu")) { - info!("Testing complete, shutting down in 3 seconds..."); - st.boot_services().stall(3_000_000); - } else { - info!("Testing complete, shutting down..."); - } + info!("Testing complete, shutting down..."); // Exit boot services as a proof that it works :) let sizes = st.boot_services().memory_map_size(); @@ -151,15 +137,23 @@ fn shutdown(image: uefi::Handle, mut st: SystemTable) -> ! { #[cfg(target_arch = "x86_64")] { - if cfg!(feature = "qemu") { - use qemu_exit::QEMUExit; - let custom_exit_success = 3; - let qemu_exit_handle = qemu_exit::X86::new(0xF4, custom_exit_success); - qemu_exit_handle.exit_success(); - } + // Prevent unused variable warning. + let _ = st; + + use qemu_exit::QEMUExit; + let custom_exit_success = 3; + let qemu_exit_handle = qemu_exit::X86::new(0xF4, custom_exit_success); + qemu_exit_handle.exit_success(); } - // Shut down the system - let rt = unsafe { st.runtime_services() }; - rt.reset(ResetType::Shutdown, Status::SUCCESS, None); + #[cfg(not(target_arch = "x86_64"))] + { + // Shut down the system + let rt = unsafe { st.runtime_services() }; + rt.reset( + uefi::table::runtime::ResetType::Shutdown, + Status::SUCCESS, + None, + ); + } } diff --git a/uefi-test-runner/src/proto/media/known_disk.rs b/uefi-test-runner/src/proto/media/known_disk.rs index e63a9c5d8..c02674745 100644 --- a/uefi-test-runner/src/proto/media/known_disk.rs +++ b/uefi-test-runner/src/proto/media/known_disk.rs @@ -248,12 +248,6 @@ fn test_raw_disk_io2(handle: Handle, bt: &BootServices) { /// Run various file-system related tests on a special test disk. The disk is created by /// `xtask/src/disk.rs`. pub fn test_known_disk(bt: &BootServices) { - // This test is only valid when running in the specially-prepared - // qemu with the test disk. - if !cfg!(feature = "qemu") { - return; - } - let handles = bt .find_handles::() .expect("Failed to get handles for `SimpleFileSystem` protocol"); diff --git a/xtask/src/cargo.rs b/xtask/src/cargo.rs index 82691fb95..cb9f8f404 100644 --- a/xtask/src/cargo.rs +++ b/xtask/src/cargo.rs @@ -50,7 +50,6 @@ pub enum Feature { Logger, Ci, - Qemu, } impl Feature { @@ -61,7 +60,6 @@ impl Feature { Self::Logger => "logger", Self::Ci => "uefi-test-runner/ci", - Self::Qemu => "uefi-test-runner/qemu", } } diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 92255ef23..eec7e429c 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -86,7 +86,7 @@ fn run_miri() -> Result<()> { /// Build uefi-test-runner and run it in QEMU. fn run_vm_tests(opt: &QemuOpt) -> Result<()> { - let mut features = vec![Feature::Qemu]; + let mut features = vec![]; // Always enable the ci feature when not building on Linux so that // the MP test is skipped. That test doesn't work with kvm disabled