From eee2f138829cf03a0a23a7be62691aa10a6eb6c0 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 8 Oct 2023 09:15:20 +0000 Subject: [PATCH 01/10] mm: use target_os = "none" instead of test Once we'll start running tests in the SVSM, we'll want to use the correct implementations and not the fake ones for tests outside the SVSM. Signed-off-by: Tom Dohrmann --- src/mm/address_space.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mm/address_space.rs b/src/mm/address_space.rs index 9636c06ed..84fb9b7c8 100644 --- a/src/mm/address_space.rs +++ b/src/mm/address_space.rs @@ -4,8 +4,6 @@ // // Author: Joerg Roedel -#[cfg(any(test, fuzzing))] -use crate::address::Address; use crate::address::{PhysAddr, VirtAddr}; use crate::utils::immut_after_init::ImmutAfterInitCell; @@ -30,7 +28,7 @@ pub fn init_kernel_mapping_info(vstart: VirtAddr, vend: VirtAddr, pstart: PhysAd .expect("Already initialized kernel mapping info"); } -#[cfg(not(any(test, fuzzing)))] +#[cfg(target_os = "none")] pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr { if vaddr < KERNEL_MAPPING.virt_start || vaddr >= KERNEL_MAPPING.virt_end { panic!("Invalid physical address {:#018x}", vaddr); @@ -41,7 +39,7 @@ pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr { KERNEL_MAPPING.phys_start + offset } -#[cfg(not(any(test, fuzzing)))] +#[cfg(target_os = "none")] pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { let size: usize = KERNEL_MAPPING.virt_end - KERNEL_MAPPING.virt_start; if paddr < KERNEL_MAPPING.phys_start || paddr >= KERNEL_MAPPING.phys_start + size { @@ -53,13 +51,15 @@ pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { KERNEL_MAPPING.virt_start + offset } -#[cfg(any(test, fuzzing))] +#[cfg(not(target_os = "none"))] pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr { + use crate::address::Address; PhysAddr::from(vaddr.bits()) } -#[cfg(any(test, fuzzing))] +#[cfg(not(target_os = "none"))] pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { + use crate::address::Address; VirtAddr::from(paddr.bits()) } From 20e7531c6c14330bbe74e1377133a13f28ba3689 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 8 Oct 2023 09:18:32 +0000 Subject: [PATCH 02/10] test: disable some tests inside SVSM For one reason or another some of the tests currently fail when run inside the SVSM. Signed-off-by: Tom Dohrmann --- src/fs/filesystem.rs | 6 ++++++ src/fs/ramfs.rs | 1 + src/mm/alloc.rs | 9 +++++++++ 3 files changed, 16 insertions(+) diff --git a/src/fs/filesystem.rs b/src/fs/filesystem.rs index 205d76ce1..216cc7bca 100644 --- a/src/fs/filesystem.rs +++ b/src/fs/filesystem.rs @@ -276,6 +276,7 @@ mod tests { use crate::mm::alloc::{TestRootMem, DEFAULT_TEST_MEMORY_SIZE}; #[test] + #[cfg_attr(test_in_svsm, ignore = "FIXME")] fn create_dir() { let _test_mem = TestRootMem::setup(DEFAULT_TEST_MEMORY_SIZE); initialize_fs(); @@ -300,6 +301,7 @@ mod tests { } #[test] + #[cfg_attr(test_in_svsm, ignore = "FIXME")] fn create_and_unlink_file() { let _test_mem = TestRootMem::setup(DEFAULT_TEST_MEMORY_SIZE); initialize_fs(); @@ -330,6 +332,7 @@ mod tests { } #[test] + #[cfg_attr(test_in_svsm, ignore = "FIXME")] fn create_sub_dir() { let _test_mem = TestRootMem::setup(DEFAULT_TEST_MEMORY_SIZE); initialize_fs(); @@ -358,6 +361,7 @@ mod tests { } #[test] + #[cfg_attr(test_in_svsm, ignore = "FIXME")] fn test_unlink() { let _test_mem = TestRootMem::setup(DEFAULT_TEST_MEMORY_SIZE); initialize_fs(); @@ -387,6 +391,7 @@ mod tests { } #[test] + #[cfg_attr(test_in_svsm, ignore = "FIXME")] fn test_open_read_write_seek() { let _test_mem = TestRootMem::setup(DEFAULT_TEST_MEMORY_SIZE); initialize_fs(); @@ -438,6 +443,7 @@ mod tests { } #[test] + #[cfg_attr(test_in_svsm, ignore = "FIXME")] fn test_multiple_file_handles() { let _test_mem = TestRootMem::setup(DEFAULT_TEST_MEMORY_SIZE); initialize_fs(); diff --git a/src/fs/ramfs.rs b/src/fs/ramfs.rs index fa4c423a0..b8d10a4c3 100644 --- a/src/fs/ramfs.rs +++ b/src/fs/ramfs.rs @@ -284,6 +284,7 @@ mod tests { use crate::mm::alloc::{TestRootMem, DEFAULT_TEST_MEMORY_SIZE}; #[test] + #[cfg_attr(test_in_svsm, ignore = "FIXME")] fn test_ramfs_file_read_write() { let _test_mem = TestRootMem::setup(DEFAULT_TEST_MEMORY_SIZE); diff --git a/src/mm/alloc.rs b/src/mm/alloc.rs index 83bcb0f4b..fb7783cf2 100644 --- a/src/mm/alloc.rs +++ b/src/mm/alloc.rs @@ -1332,12 +1332,14 @@ impl Drop for TestRootMem<'_> { } #[test] +#[cfg_attr(test_in_svsm, ignore = "FIXME")] fn test_root_mem_setup() { let test_mem_lock = TestRootMem::setup(DEFAULT_TEST_MEMORY_SIZE); drop(test_mem_lock); } #[test] +#[cfg_attr(test_in_svsm, ignore = "FIXME")] // Allocate one page and free it again, verify that memory_info() reflects it. fn test_page_alloc_one() { let _test_mem = TestRootMem::setup(DEFAULT_TEST_MEMORY_SIZE); @@ -1352,6 +1354,7 @@ fn test_page_alloc_one() { } #[test] +#[cfg_attr(test_in_svsm, ignore = "FIXME")] // Allocate and free all available compound pages, verify that memory_info() // reflects it. fn test_page_alloc_all_compound() { @@ -1384,6 +1387,7 @@ fn test_page_alloc_all_compound() { } #[test] +#[cfg_attr(test_in_svsm, ignore = "FIXME")] // Allocate and free all available 4k pages, verify that memory_info() // reflects it. fn test_page_alloc_all_single() { @@ -1416,6 +1420,7 @@ fn test_page_alloc_all_single() { } #[test] +#[cfg_attr(test_in_svsm, ignore = "FIXME")] // Allocate and free all available compound pages, verify that any subsequent // allocation fails. fn test_page_alloc_oom() { @@ -1453,6 +1458,7 @@ fn test_page_alloc_oom() { } #[test] +#[cfg_attr(test_in_svsm, ignore = "FIXME")] fn test_page_file() { let _mem_lock = TestRootMem::setup(DEFAULT_TEST_MEMORY_SIZE); let mut root_mem = ROOT_MEM.lock(); @@ -1486,6 +1492,7 @@ fn test_page_file() { const TEST_SLAB_SIZES: [usize; 7] = [32, 64, 128, 256, 512, 1024, 2048]; #[test] +#[cfg_attr(test_in_svsm, ignore = "FIXME")] // Allocate and free a couple of objects for each slab size. fn test_slab_alloc_free_many() { extern crate alloc; @@ -1525,6 +1532,7 @@ fn test_slab_alloc_free_many() { } #[test] +#[cfg_attr(test_in_svsm, ignore = "FIXME")] // Allocate enough objects so that the SlabPageSlab will need a SlabPage for // itself twice. fn test_slab_page_slab_for_self() { @@ -1561,6 +1569,7 @@ fn test_slab_page_slab_for_self() { } #[test] +#[cfg_attr(test_in_svsm, ignore = "FIXME")] // Allocate enough objects to hit an OOM situation and verify null gets // returned at some point. fn test_slab_oom() { From aecbe8c48c928f5c80edee53b198c80864e047ff Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 8 Oct 2023 09:21:51 +0000 Subject: [PATCH 03/10] Makefile: mark test as phony Signed-off-by: Tom Dohrmann --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f0a23b6ab..131fed03f 100644 --- a/Makefile +++ b/Makefile @@ -57,4 +57,4 @@ clean: cargo clean rm -f stage1/stage2.bin svsm.bin stage1/meta.bin stage1/kernel.elf stage1/stage1 stage1/svsm-fs.bin ${STAGE1_OBJS} utils/gen_meta utils/print-meta -.PHONY: stage1/stage2.bin stage1/kernel.elf svsm.bin clean stage1/svsm-fs.bin +.PHONY: stage1/stage2.bin stage1/kernel.elf svsm.bin clean stage1/svsm-fs.bin test From 251359dc9a0536d2be2cbe9ec5388f0ee8f68e70 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 8 Oct 2023 09:23:50 +0000 Subject: [PATCH 04/10] test: add no_std compatibly test crate Signed-off-by: Tom Dohrmann --- test/Cargo.toml | 6 ++++++ test/src/lib.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 test/Cargo.toml create mode 100644 test/src/lib.rs diff --git a/test/Cargo.toml b/test/Cargo.toml new file mode 100644 index 000000000..5a482d8ad --- /dev/null +++ b/test/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "test" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/test/src/lib.rs b/test/src/lib.rs new file mode 100644 index 000000000..32342580e --- /dev/null +++ b/test/src/lib.rs @@ -0,0 +1,46 @@ +//! This crate contains a very stripped down copy of the `test` crate. +//! `test` usually requires full `std` support, but we need to use it from a +//! `no_std` target. +//! The `test` crate is implicitly used by the `#[test]` attribute. +#![no_std] + +#[derive(Clone, Copy)] +pub struct TestDescAndFn { + pub testfn: StaticTestFn, + pub desc: TestDesc, +} + +#[derive(Clone, Copy)] +pub struct StaticTestFn(pub fn()); + +#[derive(Clone, Copy)] +pub struct TestDesc { + pub name: StaticTestName, + pub ignore: bool, + pub ignore_message: Option<&'static str>, + pub source_file: &'static str, + pub start_line: usize, + pub start_col: usize, + pub end_line: usize, + pub end_col: usize, + pub should_panic: ShouldPanic, + pub compile_fail: bool, + pub no_run: bool, + pub test_type: TestType, +} + +#[derive(Clone, Copy)] +pub struct StaticTestName(pub &'static str); + +#[derive(Clone, Copy)] +pub enum TestType { + UnitTest, +} + +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum ShouldPanic { + Yes, + No, +} + +pub fn assert_test_result(_: ()) {} From f672c5aa319296633d7fffef0aa360092ba8a5a3 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 15 Oct 2023 09:51:02 +0000 Subject: [PATCH 05/10] Makefile: remove kernel.elf dependency for stage1.o ... and move it to `all`. This way we can use the stage1/stage1.o target with another kernel (e.g. test kernel). Signed-off-by: Tom Dohrmann --- .github/workflows/rust.yml | 2 +- Makefile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index cd12cc059..81cf75537 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -32,7 +32,7 @@ jobs: # ld to work, so build all the objects without performing the # final linking step. - name: Build - run: make FEATURES="default,enable-gdb" stage1/stage1.o stage1/reset.o + run: make FEATURES="default,enable-gdb" stage1/kernel.elf stage1/stage1.o stage1/reset.o - name: Run tests run: make test diff --git a/Makefile b/Makefile index 131fed03f..4d8621477 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ FS_FILE ?= none STAGE1_OBJS = stage1/stage1.o stage1/reset.o -all: svsm.bin +all: stage1/kernel.elf svsm.bin test: cargo test --target=x86_64-unknown-linux-gnu @@ -42,7 +42,7 @@ ifneq ($(FS_FILE), none) endif touch stage1/svsm-fs.bin -stage1/stage1.o: stage1/stage1.S stage1/stage2.bin stage1/kernel.elf stage1/svsm-fs.bin +stage1/stage1.o: stage1/stage1.S stage1/stage2.bin stage1/svsm-fs.bin cc -c -o $@ stage1/stage1.S stage1/reset.o: stage1/reset.S stage1/meta.bin From 7c5521f5c09c6f664468c4d6807826a9873d92da Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 8 Oct 2023 09:24:58 +0000 Subject: [PATCH 06/10] test: make it possible to run tests inside SVSM To build and run a kernel that runs the tests use ``` QEMU=/path/to/qemu OVMF=/path/to/firmware/ make test-in-svsm ``` Signed-off-by: Tom Dohrmann --- Cargo.lock | 5 +++++ Cargo.toml | 3 ++- Makefile | 36 +++++++++++++++++++++++++++++++++--- build.rs | 11 +++++++++++ src/lib.rs | 16 ++++++++++++++++ src/svsm.rs | 7 +++++-- src/testing.rs | 33 +++++++++++++++++++++++++++++++++ 7 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 src/testing.rs diff --git a/Cargo.lock b/Cargo.lock index d181bb48b..1ce56a400 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -137,6 +137,7 @@ dependencies = [ "intrusive-collections", "log", "packit", + "test", ] [[package]] @@ -150,6 +151,10 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "test" +version = "0.1.0" + [[package]] name = "unicode-ident" version = "1.0.10" diff --git a/Cargo.toml b/Cargo.toml index b7b887224..568ceed01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,8 @@ intrusive-collections = "0.9.6" log = { version = "0.4.17", features = ["max_level_info", "release_max_level_info"] } packit = { git = "https://github.com/coconut-svsm/packit", version = "0.1.0" } -[build-dependencies] +[target."x86_64-unknown-none".dev-dependencies] +test = { version = "0.1.0", path = "test" } [features] default = ["enable-stacktrace"] diff --git a/Makefile b/Makefile index 4d8621477..711c65e2c 100644 --- a/Makefile +++ b/Makefile @@ -2,16 +2,19 @@ FEATURES ?= "default" CARGO_ARGS = --features ${FEATURES} ifdef RELEASE -TARGET_PATH="release" +TARGET_PATH=release CARGO_ARGS += --release else -TARGET_PATH="debug" +TARGET_PATH=debug endif STAGE2_ELF = "target/x86_64-unknown-none/${TARGET_PATH}/stage2" KERNEL_ELF = "target/x86_64-unknown-none/${TARGET_PATH}/svsm" +TEST_KERNEL_ELF = target/x86_64-unknown-none/${TARGET_PATH}/svsm-test FS_FILE ?= none +C_BIT_POS ?= 51 + STAGE1_OBJS = stage1/stage1.o stage1/reset.o all: stage1/kernel.elf svsm.bin @@ -19,6 +22,29 @@ all: stage1/kernel.elf svsm.bin test: cargo test --target=x86_64-unknown-linux-gnu +test-in-svsm: stage1/test-kernel.elf svsm.bin +ifndef QEMU + echo "Set QEMU environment variable to QEMU installation path" && exit 1 +endif +ifndef OVMF + echo "Set OVMFenvironment variable to a folder containing OVMF_CODE.fd and OVMF_VARS.fd" && exit 1 +endif + $(QEMU)/qemu-system-x86_64 \ + -enable-kvm \ + -cpu EPYC-v4 \ + -machine q35,confidential-guest-support=sev0,memory-backend=ram1,kvm-type=protected \ + -object memory-backend-memfd-private,id=ram1,size=1G,share=true \ + -object sev-snp-guest,id=sev0,cbitpos=$(C_BIT_POS),reduced-phys-bits=1,svsm=on \ + -smp 8 \ + -no-reboot \ + -drive if=pflash,format=raw,unit=0,file=$(OVMF)/OVMF_CODE.fd,readonly=on \ + -drive if=pflash,format=raw,unit=1,file=$(OVMF)/OVMF_VARS.fd,snapshot=on \ + -drive if=pflash,format=raw,unit=2,file=./svsm.bin,readonly=on \ + -nographic \ + -monitor none \ + -serial stdio \ + -device isa-debug-exit,iobase=0xf4,iosize=0x04 || true + utils/gen_meta: utils/gen_meta.c cc -O3 -Wall -o $@ $< @@ -36,6 +62,10 @@ stage1/kernel.elf: cargo build ${CARGO_ARGS} --bin svsm objcopy -O elf64-x86-64 --strip-unneeded ${KERNEL_ELF} $@ +stage1/test-kernel.elf: + LINK_TEST=1 cargo +nightly test --config 'target.x86_64-unknown-none.runner=["sh", "-c", "cp $$0 ${TEST_KERNEL_ELF}"]' + objcopy -O elf64-x86-64 --strip-unneeded ${TEST_KERNEL_ELF} stage1/kernel.elf + stage1/svsm-fs.bin: ifneq ($(FS_FILE), none) cp -f $(FS_FILE) stage1/svsm-fs.bin @@ -57,4 +87,4 @@ clean: cargo clean rm -f stage1/stage2.bin svsm.bin stage1/meta.bin stage1/kernel.elf stage1/stage1 stage1/svsm-fs.bin ${STAGE1_OBJS} utils/gen_meta utils/print-meta -.PHONY: stage1/stage2.bin stage1/kernel.elf svsm.bin clean stage1/svsm-fs.bin test +.PHONY: stage1/stage2.bin stage1/kernel.elf stage1/test-kernel.elf svsm.bin clean stage1/svsm-fs.bin test test-in-svsm diff --git a/build.rs b/build.rs index 9ca054b1c..18ef9efbc 100644 --- a/build.rs +++ b/build.rs @@ -17,4 +17,15 @@ fn main() { println!("cargo:rustc-link-arg-bin=svsm=--no-relax"); println!("cargo:rustc-link-arg-bin=svsm=-Tsvsm.lds"); println!("cargo:rustc-link-arg-bin=svsm=-no-pie"); + + // Extra linker args for tests. + println!("cargo:rerun-if-env-changed=LINK_TEST"); + if std::env::var("LINK_TEST").is_ok() { + println!("cargo:rustc-cfg=test_in_svsm"); + println!("cargo:rustc-link-arg=-nostdlib"); + println!("cargo:rustc-link-arg=--build-id=none"); + println!("cargo:rustc-link-arg=--no-relax"); + println!("cargo:rustc-link-arg=-Tsvsm.lds"); + println!("cargo:rustc-link-arg=-no-pie"); + } } diff --git a/src/lib.rs b/src/lib.rs index a7664c3bd..445420c19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,10 @@ // Author: Nicolai Stange #![no_std] +#![cfg_attr(all(test, test_in_svsm), no_main)] +#![cfg_attr(all(test, test_in_svsm), feature(custom_test_frameworks))] +#![cfg_attr(all(test, test_in_svsm), test_runner(crate::testing::svsm_test_runner))] +#![cfg_attr(all(test, test_in_svsm), reexport_test_harness_main = "test_main")] pub mod acpi; pub mod address; @@ -33,3 +37,15 @@ pub mod utils; #[test] fn test_nop() {} + +// When running tests inside the SVSM: +// Build the kernel entrypoint. +#[cfg(all(test, test_in_svsm))] +#[path = "svsm.rs"] +pub mod svsm_bin; +// The kernel expects to access this crate as svsm, so reexport. +#[cfg(all(test, test_in_svsm))] +extern crate self as svsm; +// Include a module containing the test runner. +#[cfg(all(test, test_in_svsm))] +pub mod testing; diff --git a/src/svsm.rs b/src/svsm.rs index 93f17fcb0..30122b427 100644 --- a/src/svsm.rs +++ b/src/svsm.rs @@ -4,8 +4,8 @@ // // Author: Joerg Roedel -#![no_std] -#![no_main] +#![cfg_attr(not(test), no_std)] +#![cfg_attr(not(test), no_main)] extern crate alloc; @@ -479,6 +479,9 @@ pub extern "C" fn svsm_main() { panic!("Failed to launch FW: {:#?}", e); } + #[cfg(test)] + crate::test_main(); + request_loop(); panic!("Road ends here!"); diff --git a/src/testing.rs b/src/testing.rs new file mode 100644 index 000000000..793967d61 --- /dev/null +++ b/src/testing.rs @@ -0,0 +1,33 @@ +use log::info; +use test::ShouldPanic; + +use crate::sev::msr_protocol::request_termination_msr; + +pub fn svsm_test_runner(test_cases: &[&test::TestDescAndFn]) { + info!("running {} tests", test_cases.len()); + for mut test_case in test_cases.iter().copied().copied() { + if test_case.desc.should_panic == ShouldPanic::Yes { + test_case.desc.ignore = true; + test_case + .desc + .ignore_message + .get_or_insert("#[should_panic] not supported"); + } + + if test_case.desc.ignore { + if let Some(message) = test_case.desc.ignore_message { + info!("test {} ... ignored, {message}", test_case.desc.name.0); + } else { + info!("test {} ... ignored", test_case.desc.name.0); + } + continue; + } + + info!("test {} ...", test_case.desc.name.0); + (test_case.testfn.0)(); + } + + info!("All tests passed!"); + + request_termination_msr(); +} From ad133e14f0fb4ae9105f884d606daf066e06b312 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 15 Oct 2023 08:58:43 +0000 Subject: [PATCH 07/10] test: exit using QEMU debug exit device This is cleaner than `request_terminator_msr` as that MSR is more commonly used to signal errors rather than clean exits. Signed-off-by: Tom Dohrmann --- src/testing.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/testing.rs b/src/testing.rs index 793967d61..8be8301e4 100644 --- a/src/testing.rs +++ b/src/testing.rs @@ -1,7 +1,7 @@ use log::info; use test::ShouldPanic; -use crate::sev::msr_protocol::request_termination_msr; +use crate::{cpu::percpu::this_cpu_mut, sev::ghcb::GHCBIOSize}; pub fn svsm_test_runner(test_cases: &[&test::TestDescAndFn]) { info!("running {} tests", test_cases.len()); @@ -29,5 +29,14 @@ pub fn svsm_test_runner(test_cases: &[&test::TestDescAndFn]) { info!("All tests passed!"); - request_termination_msr(); + exit(); +} + +fn exit() -> ! { + const QEMU_EXIT_PORT: u16 = 0xf4; + this_cpu_mut() + .ghcb() + .ioio_out(QEMU_EXIT_PORT, GHCBIOSize::Size32, 0) + .unwrap(); + unreachable!(); } From ad967caad58d5395e21e675d270c59130e55cf27 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 15 Oct 2023 09:42:38 +0000 Subject: [PATCH 08/10] docs: document how to run tests inside SVSM Signed-off-by: Tom Dohrmann --- INSTALL.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/INSTALL.md b/INSTALL.md index 6751423e6..477b4d1c9 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -205,6 +205,12 @@ The project also contains a number of unit-tests which can be run by $ make test ``` +Unit tests can be run inside the SVSM by + +``` +$ QEMU=/path/to/qemu OVMF=/path/to/firmware/ make test-in-svsm +``` + Putting it all together ----------------------- From 4f7ab7d1191e4bfd8021f6255d75a63a6970ff93 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 23 Oct 2023 12:25:07 +0200 Subject: [PATCH 09/10] utils: Add cbit helper Add a helper to print the C-bit position on the current platform. Signed-off-by: Joerg Roedel --- .gitignore | 1 + Makefile | 3 +++ utils/cbit.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 utils/cbit.c diff --git a/.gitignore b/.gitignore index ec410ace2..80f3268e3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ target/ gen_meta stage1/stage1 print-meta +cbit .idea/ diff --git a/Makefile b/Makefile index 711c65e2c..0e6b6ad18 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,9 @@ utils/gen_meta: utils/gen_meta.c utils/print-meta: utils/print-meta.c cc -O3 -Wall -o $@ $< +utils/cbit: utils/cbit.c + cc -O3 -Wall -o $@ $< + stage1/meta.bin: utils/gen_meta utils/print-meta ./utils/gen_meta $@ diff --git a/utils/cbit.c b/utils/cbit.c new file mode 100644 index 000000000..e87e52a16 --- /dev/null +++ b/utils/cbit.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// +// Copyright (c) 2023 SUSE LLC +// +// Author: Joerg Roedel +// +// vim: ts=4 sw=4 et + +#include + +struct cpuid_result { + unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; +}; + +static void cpuid(unsigned int fn, struct cpuid_result *result) +{ + asm volatile("cpuid" + : "=a" (result->eax), "=b" (result->ebx), "=c" (result->ecx), "=d" (result->edx) : "0" (fn) : "memory"); +} + +int main() { + struct cpuid_result r; + unsigned int bit; + + cpuid(0x80000000, &r); + if (r.eax < 0x8000001f) + return 1; + + cpuid(0x8000001f, &r); + + if ((r.eax & 2) == 0) + return 1; + + bit = r.ebx & (64 - 1); + + printf("%d\n", bit); + + return 0; +} From 845ec967e5c597012fddd5ad04f24c667cb4f974 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 23 Oct 2023 12:33:50 +0200 Subject: [PATCH 10/10] scripts: Add test-in-svsm.sh helper script Instead of having the full QEMU command line in the Makefile, extract the test-run into a separate script. Signed-off-by: Joerg Roedel --- Makefile | 24 ++---------------------- scripts/test-in-svsm.sh | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 22 deletions(-) create mode 100755 scripts/test-in-svsm.sh diff --git a/Makefile b/Makefile index 0e6b6ad18..990dd3d38 100644 --- a/Makefile +++ b/Makefile @@ -22,28 +22,8 @@ all: stage1/kernel.elf svsm.bin test: cargo test --target=x86_64-unknown-linux-gnu -test-in-svsm: stage1/test-kernel.elf svsm.bin -ifndef QEMU - echo "Set QEMU environment variable to QEMU installation path" && exit 1 -endif -ifndef OVMF - echo "Set OVMFenvironment variable to a folder containing OVMF_CODE.fd and OVMF_VARS.fd" && exit 1 -endif - $(QEMU)/qemu-system-x86_64 \ - -enable-kvm \ - -cpu EPYC-v4 \ - -machine q35,confidential-guest-support=sev0,memory-backend=ram1,kvm-type=protected \ - -object memory-backend-memfd-private,id=ram1,size=1G,share=true \ - -object sev-snp-guest,id=sev0,cbitpos=$(C_BIT_POS),reduced-phys-bits=1,svsm=on \ - -smp 8 \ - -no-reboot \ - -drive if=pflash,format=raw,unit=0,file=$(OVMF)/OVMF_CODE.fd,readonly=on \ - -drive if=pflash,format=raw,unit=1,file=$(OVMF)/OVMF_VARS.fd,snapshot=on \ - -drive if=pflash,format=raw,unit=2,file=./svsm.bin,readonly=on \ - -nographic \ - -monitor none \ - -serial stdio \ - -device isa-debug-exit,iobase=0xf4,iosize=0x04 || true +test-in-svsm: utils/cbit stage1/test-kernel.elf svsm.bin + ./scripts/test-in-svsm.sh utils/gen_meta: utils/gen_meta.c cc -O3 -Wall -o $@ $< diff --git a/scripts/test-in-svsm.sh b/scripts/test-in-svsm.sh new file mode 100755 index 000000000..16d7e3149 --- /dev/null +++ b/scripts/test-in-svsm.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# + +set -e + +if [ "$QEMU" == "" ]; then + echo "Set QEMU environment variable to QEMU installation path" && exit 1 +fi +if [ "$OVMF_PATH" == "" ]; then + echo "Set OVMF_PATH environment variable to a folder containing OVMF_CODE.fd and OVMF_VARS.fd" && exit 1 +fi +if [ "$SUDO" != "" ]; then + SUDO_CMD="sudo" +else + SUDO_CMD="" +fi + +C_BIT_POS=`utils/cbit` + +$SUDO_CMD $QEMU \ + -enable-kvm \ + -cpu EPYC-v4 \ + -machine q35,confidential-guest-support=sev0,memory-backend=ram1,kvm-type=protected \ + -object memory-backend-memfd-private,id=ram1,size=1G,share=true \ + -object sev-snp-guest,id=sev0,cbitpos=$C_BIT_POS,reduced-phys-bits=1,svsm=on \ + -smp 8 \ + -no-reboot \ + -drive if=pflash,format=raw,unit=0,file=$OVMF_PATH/OVMF_CODE.fd,readonly=on \ + -drive if=pflash,format=raw,unit=1,file=$OVMF_PATH/OVMF_VARS.fd,snapshot=on \ + -drive if=pflash,format=raw,unit=2,file=./svsm.bin,readonly=on \ + -nographic \ + -monitor none \ + -serial stdio \ + -device isa-debug-exit,iobase=0xf4,iosize=0x04 || true