Skip to content

uefi-test-runner: Assume that we're running in the special QEMU env #579

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion uefi-test-runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

7 changes: 5 additions & 2 deletions uefi-test-runner/README.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
126 changes: 60 additions & 66 deletions uefi-test-runner/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -24,10 +24,9 @@ fn efi_main(image: Handle, mut st: SystemTable<Boot>) -> 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
Expand Down Expand Up @@ -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::<Serial>()
.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>(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::<Serial>()
.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>(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<Boot>) -> ! {
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();
Expand All @@ -151,15 +137,23 @@ fn shutdown(image: uefi::Handle, mut st: SystemTable<Boot>) -> ! {

#[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,
);
}
}
6 changes: 0 additions & 6 deletions uefi-test-runner/src/proto/media/known_disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<SimpleFileSystem>()
.expect("Failed to get handles for `SimpleFileSystem` protocol");
Expand Down
2 changes: 0 additions & 2 deletions xtask/src/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ pub enum Feature {
Logger,

Ci,
Qemu,
}

impl Feature {
Expand All @@ -61,7 +60,6 @@ impl Feature {
Self::Logger => "logger",

Self::Ci => "uefi-test-runner/ci",
Self::Qemu => "uefi-test-runner/qemu",
}
}

Expand Down
2 changes: 1 addition & 1 deletion xtask/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down