diff --git a/.github/workflows/qemu.yml b/.github/workflows/qemu.yml index 1d7e0d5054..2788afb356 100644 --- a/.github/workflows/qemu.yml +++ b/.github/workflows/qemu.yml @@ -17,7 +17,7 @@ env: jobs: check: - name: QEMU NOCC boot test + name: QEMU NOCC test-in-svsm runs-on: ubuntu-latest steps: @@ -106,20 +106,18 @@ jobs: ## TODO: We can replace the SVSM build step and download the IGVM file as an artifact # from the "Rust check" jobs instread to speed things up. - - name: Install Rust x86_64-unknown-none - run: | - rustup toolchain install \ - --profile minimal + - name: Install latest nightly + run: rustup toolchain install nightly -t x86_64-unknown-none --profile minimal --force -c rustfmt - name: Install TPM 2.0 Reference Implementation build dependencies run: sudo apt install -y autoconf autoconf-archive pkg-config build-essential automake - - name: Build SVSM - run: cargo xbuild configs/qemu-target.json + - name: Build test + run: make bin/coconut-test-qemu.igvm ######################## - - name: Run SVSM in QEMU + - name: Run test-in-svsm in QEMU run: | - QEMU=./tools/bin/qemu-system-x86_64 scripts/test-qemu-nocc-boot.sh + QEMU=./tools/bin/qemu-system-x86_64 scripts/test-qemu-nocc-svsm.sh diff --git a/Makefile b/Makefile index 8f277ec74f..4b258e737a 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,8 @@ ifneq ($(FEATURES_TEST),) SVSM_ARGS_TEST += --features ${FEATURES_TEST} endif +TEST_ARGS ?= + CLIPPY_OPTIONS ?= CLIPPY_ARGS ?= -D warnings @@ -115,7 +117,7 @@ test: test-igvm: bin/coconut-test-qemu.igvm bin/coconut-test-hyperv.igvm bin/coconut-test-vanadium.igvm test-in-svsm: utils/cbit bin/coconut-test-qemu.igvm $(IGVMMEASUREBIN) - ./scripts/test-in-svsm.sh + ./scripts/test-in-svsm.sh $(TEST_ARGS) test-in-hyperv: bin/coconut-test-hyperv.igvm diff --git a/kernel/src/cpu/vc.rs b/kernel/src/cpu/vc.rs index 1ef29d3ef4..c580390d47 100644 --- a/kernel/src/cpu/vc.rs +++ b/kernel/src/cpu/vc.rs @@ -338,6 +338,10 @@ mod tests { #[test] #[cfg_attr(not(test_in_svsm), ignore = "Can only be run inside guest")] fn test_has_memory_encryption_info_cpuid() { + if is_test_platform_type(SvsmPlatformType::Native) { + return; + } + const CPUID_EXTENDED_FUNCTION_INFO: u32 = 0x8000_0000; const CPUID_MEMORY_ENCRYPTION_INFO: u32 = 0x8000_001F; // SAFETY: CPUID does never affect safety. diff --git a/kernel/src/svsm.rs b/kernel/src/svsm.rs index 42f04ee1a4..6634bc5401 100755 --- a/kernel/src/svsm.rs +++ b/kernel/src/svsm.rs @@ -419,6 +419,8 @@ fn panic(info: &PanicInfo<'_>) -> ! { loop { debug_break(); + #[cfg(all(test, test_in_svsm))] + crate::testing::qemu_write_exit(crate::testing::QEMUExitValue::Fail); platform::halt(); } } diff --git a/kernel/src/testing.rs b/kernel/src/testing.rs index 82b1cdb1e5..7295b5e84e 100644 --- a/kernel/src/testing.rs +++ b/kernel/src/testing.rs @@ -3,11 +3,9 @@ use log::info; use test::ShouldPanic; use crate::{ - cpu::percpu::current_ghcb, locking::{LockGuard, SpinLock}, platform::SVSM_PLATFORM, serial::SerialPort, - sev::ghcb::GHCBIOSize, testutils::has_qemu_testdev, }; @@ -90,15 +88,26 @@ pub fn svsm_test_runner(test_cases: &[&test::TestDescAndFn]) { } fn exit() -> ! { - if has_qemu_testdev() { - const QEMU_EXIT_PORT: u16 = 0xf4; - current_ghcb() - .ioio_out(QEMU_EXIT_PORT, GHCBIOSize::Size32, 0) - .unwrap(); - } + qemu_write_exit(QEMUExitValue::Success); // SAFETY: HLT instruction does not affect memory. unsafe { asm!("hlt"); } unreachable!(); } + +#[repr(u32)] +#[derive(Debug)] +pub enum QEMUExitValue { + Success = 0x10, + Fail = 0x11, +} + +pub fn qemu_write_exit(value: QEMUExitValue) { + if has_qemu_testdev() { + const QEMU_EXIT_PORT: u16 = 0xf4; + SVSM_PLATFORM + .get_io_port() + .outl(QEMU_EXIT_PORT, value as u32); + } +} diff --git a/scripts/test-in-svsm.sh b/scripts/test-in-svsm.sh index bc13b1b3fb..4aa616b70c 100755 --- a/scripts/test-in-svsm.sh +++ b/scripts/test-in-svsm.sh @@ -47,9 +47,38 @@ dd if=/dev/urandom of="$TEST_DIR/svsm_state.raw" bs=512 count=1024 test_io $TEST_DIR/pipe.in $TEST_DIR/pipe.out & TEST_IO_PID=$! +LAUNCH_GUEST_ARGS="" + +while [[ $# -gt 0 ]]; do + case $1 in + --nocc) + LAUNCH_GUEST_ARGS+="--nocc " + shift + ;; + *) + echo "Invalid parameter $1" + exit 1 + ;; + esac +done + + $SCRIPT_DIR/launch_guest.sh --igvm $SCRIPT_DIR/../bin/coconut-test-qemu.igvm \ --state "$TEST_DIR/svsm_state.raw" \ - --unit-tests $TEST_DIR/pipe || true + --unit-tests $TEST_DIR/pipe \ + $LAUNCH_GUEST_ARGS || svsm_exit_code=$? + +# SVSM writes 0x10 to the QEMU exit port when all tests passed. +# This results in QEMU returning 0x21 ((0x10 << 1) | 1) +if [[ $svsm_exit_code -eq 0x21 ]]; then + echo "All tests passed" + exit_value=0 +else + echo "Test Failed" + exit_value=1 +fi kill $TEST_IO_PID 2> /dev/null || true rm -rf $TEST_DIR + +exit $exit_value diff --git a/scripts/test-qemu-nocc-boot.sh b/scripts/test-qemu-nocc-svsm.sh similarity index 87% rename from scripts/test-qemu-nocc-boot.sh rename to scripts/test-qemu-nocc-svsm.sh index 05f8608999..43c8dbf0a2 100755 --- a/scripts/test-qemu-nocc-boot.sh +++ b/scripts/test-qemu-nocc-svsm.sh @@ -10,10 +10,10 @@ SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) # When we see this string on the serial output, consider # SVSM booted and the test passed. -SUCCESS="Terminating task init" +SUCCESS="All tests passed" # Fail the test after this timeout -TIMEOUT=4s +TIMEOUT=180s # Clone STDOUT for live log reporting exec 3>&1 @@ -21,7 +21,7 @@ exec 3>&1 echo "================================================================================" timeout $TIMEOUT \ grep -q -m 1 "$SUCCESS" \ - <("$SCRIPT_DIR/launch_guest.sh" --nocc | tee /proc/self/fd/3) + <("$SCRIPT_DIR/test-in-svsm.sh" --nocc | tee /proc/self/fd/3) RES=$? echo "================================================================================"