Re: [PATCH] test/qtest/launchupdate: add another test to exercise load and set host igvm
Ani Sinha <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <[email protected]> |
> On 15 Aug 2026, at 10:39 AM, Ani Sinha <[email protected]> wrote: > > On Sat, Aug 15, 2026 at 9:59 AM Ani Sinha <[email protected]> wrote: >> >> A new test is added that loads a new IGVM bundle and sets host igvm >> ctrl at the same time. The expected behavior is that first reset will load >> the passed IGVM. The second reset will restore the original host provided IGVM. >> This test exercizes this functionality. >> >> Some refactoring is also done at the same time to re-use common operations from >> within multiple test routines. > > This applies on top of the v5 patchset here > https://lists.gnu.org/archive/html/qemu-devel/2026-08/msg02509.html Tested this patch on CoCo and the test runs fine there … serial console file is /tmp/launchupdate-qtest-serial-sKLAJU3 # starting QEMU: exec ./qemu-system-x86_64 -qtest unix:/tmp/qtest-896542.sock -qtest-log /dev/null -chardev socket,path=/tmp/qtest-896542.qmp,id=char0 -object monitor-qmp,id=qmp0,chardev=char0 -display none -audio none -run-with exit-with-parent=on -machine q35,igvm-cfg=igvm0,confidential-guest-support=lsec0 -m 1G -accel kvm -device vm-launch-update -chardev file,id=serial0,path=/tmp/launchupdate-qtest-serial-sKLAJU3 -serial chardev:serial0 -object igvm-cfg,id=igvm0,file=tests/data/igvm/snptest-nohello.igvm -object '{"qom-type":"sev-snp-guest","id":"lsec0","cbitpos":51,"reduced-phys-bits":1,"policy":196608}' -accel qtest initially booted with host igvm guest paddr: 100000 igvm size: 195048 writing igvm file into the guest memory tell hypervisor where igvm is loaded in guest memory qemu-system-x86_64: info: vmlaunchupdate: new IGVM context set. resetting the virtual machine. This should load user provided igvm. qemu-system-x86_64: info: virtual machine state has been rebuilt with new guest file handle. qemu-system-x86_64: info: vmlaunchupdate: next reset will use host igvm hello world found on console Now resetting again in order to reset to host igvm qemu-system-x86_64: info: virtual machine state has been rebuilt with new guest file handle. qemu-system-x86_64: info: restoring original host IGVM: tests/data/igvm/snptest-nohello.igvm qemu-system-x86_64: info: vmlaunchupdate: host IGVM context set. booted with host igvm ok 5 /vm-launch-update/ctrl_set_once # slow test /vm-launch-update/ctrl_set_once executed in 4.81 secs # End of vm-launch-update tests > >> >> Signed-off-by: Ani Sinha <[email protected]> >> --- >> tests/qtest/launchupdate-test.c | 245 +++++++++++++++++++++++++++----- >> 1 file changed, 210 insertions(+), 35 deletions(-) >> >> diff --git a/tests/qtest/launchupdate-test.c b/tests/qtest/launchupdate-test.c >> index 89a117dfe4..de780eac62 100644 >> --- a/tests/qtest/launchupdate-test.c >> +++ b/tests/qtest/launchupdate-test.c >> @@ -248,6 +248,68 @@ static int wait_for_match(char *serial_f, >> return ret; >> } >> >> +static void set_test_params(const char **igvm_f, const char **igvm_init, >> + const char **snp, const char **cgs) >> +{ >> + if (confidential) { >> + *snp = "-object \'{\"qom-type\":\"sev-snp-guest\",\"id\":\"lsec0\"," >> + "\"cbitpos\":51,\"reduced-phys-bits\":1,\"policy\":196608}\'"; >> + *cgs = "confidential-guest-support=lsec0"; >> + /* >> + * The following two IGVM files can be built from the source >> + * present in https://gitlab.com/anisinha/virt-firmware-rs . >> + * Typing 'make' from the top of this repository will build the >> + * IGVM files for both confidential and >> + * non-confidential tests. The IGVM files for the non-coco >> + * case has been checked-in into the QEMU repository for >> + * convenience and easy CI pipeline testing. >> + */ >> + *igvm_f = "tests/data/igvm/snptest.igvm"; /* prints 'hello world' */ >> + *igvm_init = "tests/data/igvm/snptest-nohello.igvm"; >> + } else { >> + *igvm_f = "tests/data/igvm/hello.igvm"; >> + *igvm_init = "tests/data/igvm/qemuinit.igvm"; >> + *snp = ""; >> + *cgs = ""; >> + } >> + >> + return; >> +} >> + >> +static void set_expected_out(const char **exp_out, const char **exp_out2, >> + const char **exp_out3) >> +{ >> + *exp_out = "Hello world!"; >> + *exp_out2 = "Test succeeded!"; >> + *exp_out3 = "boot process complete with initial igvm"; >> + >> + return; >> +} >> + >> +static QOSState *set_qemu_args(const char *cgs, const char *tp, char *serialf, >> + const char *igvm_init, const char *snp) >> +{ >> + QOSState *qs; >> + >> + if (tp) { >> + qs = qtest_pc_boot("-machine q35,igvm-cfg=igvm0,%s -m 1G -accel kvm " >> + "-device vm-launch-update %s " >> + "-chardev file,id=serial0,path=%s " >> + "-serial chardev:serial0 " >> + "-object igvm-cfg,id=igvm0,file=%s %s", >> + cgs, tp, serialf, igvm_init, snp); >> + } else { >> + qs = qtest_pc_boot("-machine q35,igvm-cfg=igvm0,%s -m 1G -accel kvm " >> + "-device vm-launch-update " >> + "-chardev file,id=serial0,path=%s " >> + "-serial chardev:serial0 " >> + "-object igvm-cfg,id=igvm0,file=%s %s", >> + cgs, serialf, igvm_init, snp); >> + } >> + >> + return qs; >> +} >> + >> static void test_load_igvm(void) >> { >> const char *igvm_f; >> @@ -255,9 +317,9 @@ static void test_load_igvm(void) >> int ser_fd; >> g_autofree void *igvm_blob = NULL; >> g_autofree char *serialtmp = NULL; >> - const char exp_out[] = "Hello world!"; >> - const char exp_out2[] = "Test succeeded!"; >> - const char exp_out3[] = "boot process complete with initial igvm"; >> + const char *exp_out; >> + const char *exp_out2; >> + const char *exp_out3; >> const char *tracepoints = "--trace memory_region_finalize " >> "--trace qigvm_cleanup_memory -D /tmp/qemu-debug.log "; >> const char *snp, *cgs; >> @@ -268,35 +330,13 @@ static void test_load_igvm(void) >> QOSState *qs; >> VMLaunchUpdate launch_update; >> >> - if (confidential) { >> - snp = "-object \'{\"qom-type\":\"sev-snp-guest\",\"id\":\"lsec0\"," >> - "\"cbitpos\":51,\"reduced-phys-bits\":1,\"policy\":196608}\'"; >> - cgs = "confidential-guest-support=lsec0"; >> - /* >> - * The following two IGVM files can be built from the source >> - * present in https://gitlab.com/anisinha/virt-firmware-rs . >> - * Typing 'make' from the top of this repository will build the >> - * IGVM files for both confidential and >> - * non-confidential tests. The IGVM files for the non-coco >> - * case has been checked-in into the QEMU repository for >> - * convenience and easy CI pipeline testing. >> - */ >> - igvm_f = "tests/data/igvm/snptest.igvm"; /* >> - * this prints 'hello world' >> - * on console >> - */ >> - igvm_init = "tests/data/igvm/snptest-nohello.igvm"; >> - } else { >> - igvm_f = "tests/data/igvm/hello.igvm"; >> - igvm_init = "tests/data/igvm/qemuinit.igvm"; >> - snp = ""; >> - cgs = ""; >> - } >> - >> if (!trace) { >> tracepoints = ""; >> } >> >> + set_test_params(&igvm_f, &igvm_init, &snp, &cgs); >> + set_expected_out(&exp_out, &exp_out2, &exp_out3); >> + >> if (!g_file_test(igvm_f, G_FILE_TEST_EXISTS) || >> !g_file_test(igvm_init, G_FILE_TEST_EXISTS)) { >> g_test_skip("igvm file bundle(s) does not exist!"); >> @@ -326,12 +366,7 @@ static void test_load_igvm(void) >> fprintf(stderr, "serial console file is %s\n", serialtmp); >> } >> >> - qs = qtest_pc_boot("-machine q35,igvm-cfg=igvm0,%s -m 1G -accel kvm " >> - "-device vm-launch-update %s " >> - "-chardev file,id=serial0,path=%s " >> - "-serial chardev:serial0 " >> - "-object igvm-cfg,id=igvm0,file=%s %s", >> - cgs, tracepoints, serialtmp, igvm_init, snp); >> + qs = set_qemu_args(cgs, tracepoints, serialtmp, igvm_init, snp); >> >> fw_cfg = pc_fw_cfg_init(qs->qts); >> >> @@ -342,6 +377,11 @@ static void test_load_igvm(void) >> >> /* exp_out3 should be printed once from initial boot */ >> g_assert_true(wait_for_match(serialtmp, exp_out3, WAIT_SEC, 1) == 0); >> + >> + if (debug) { >> + fprintf(stderr, "initially booted with host igvm\n"); >> + } >> + >> g_assert_true(load_image(igvm_f, &igvm_blob, &igvm_sz) == igvm_sz); >> >> /* create a data buffer in guest memory */ >> @@ -389,7 +429,7 @@ static void test_load_igvm(void) >> >> /* check if VM_LAUNCHUPDATE_CTL_HOST_IGVM function works */ >> >> - /* set VM_LAUNCHUPDATE_CTL_HOST_IGVM control */ >> + /* set only VM_LAUNCHUPDATE_CTL_HOST_IGVM control without IGVM bundle */ >> memset(&launch_update, 0, sizeof(launch_update)); >> launch_update.control |= VM_LAUNCHUPDATE_CTL_HOST_IGVM; >> >> @@ -410,6 +450,139 @@ static void test_load_igvm(void) >> */ >> g_assert_true(wait_for_match(serialtmp, exp_out3, WAIT_SEC, 2) == 0); >> >> + if (debug) { >> + fprintf(stderr, "booted with host igvm again\n"); >> + } >> + >> + close(ser_fd); >> + guest_free(&qs->alloc, gaddr); >> + pc_fw_cfg_uninit(fw_cfg); >> + /* qtest_quit() kils QEMU, first by sending SIGTERM, then SIGKILL */ >> + qtest_quit(qs->qts); >> +} >> + >> +static void test_set_ctrl_once_and_reset_to_host_igvm(void) >> +{ >> + const char *igvm_f; >> + const char *igvm_init; >> + int ser_fd; >> + g_autofree void *igvm_blob = NULL; >> + g_autofree char *serialtmp = NULL; >> + const char *exp_out; >> + const char *exp_out2; >> + const char *exp_out3; >> + const char *snp, *cgs; >> + uint64_t gaddr; >> + size_t igvm_sz; >> + size_t filesize; >> + QFWCFG *fw_cfg; >> + QOSState *qs; >> + VMLaunchUpdate launch_update; >> + >> + set_test_params(&igvm_f, &igvm_init, &snp, &cgs); >> + set_expected_out(&exp_out, &exp_out2, &exp_out3); >> + >> + if (!g_file_test(igvm_f, G_FILE_TEST_EXISTS) || >> + !g_file_test(igvm_init, G_FILE_TEST_EXISTS)) { >> + g_test_skip("igvm file bundle(s) does not exist!"); >> + return; >> + } >> + >> + if (!qtest_has_machine("q35")) { >> + g_test_skip("q35 machine not available"); >> + return; >> + } >> + >> + if (!qtest_has_accel("kvm")) { >> + g_test_skip("No KVM accelerator available"); >> + return; >> + } >> + >> + if (!qtest_has_device("vm-launch-update")) { >> + g_test_skip("Device vm-launch-update is not available"); >> + return; >> + } >> + >> + ser_fd = g_file_open_tmp("launchupdate-qtest-serial-sXXXXXX", >> + &serialtmp, NULL); >> + g_assert_true(ser_fd != -1); >> + >> + if (debug) { >> + fprintf(stderr, "serial console file is %s\n", serialtmp); >> + } >> + >> + qs = set_qemu_args(cgs, NULL, serialtmp, igvm_init, snp); >> + >> + fw_cfg = pc_fw_cfg_init(qs->qts); >> + >> + g_assert_true(wait_for_match(serialtmp, exp_out3, WAIT_SEC, 1) == 0); >> + >> + if (debug) { >> + fprintf(stderr, "initially booted with host igvm\n"); >> + } >> + >> + g_assert_true(load_image(igvm_f, &igvm_blob, &igvm_sz) == igvm_sz); >> + >> + /* create a data buffer in guest memory */ >> + gaddr = guest_alloc(&qs->alloc, igvm_sz); >> + >> + if (debug) { >> + fprintf(stderr, "guest paddr: %"PRIx64 " igvm size: %lu\n", >> + gaddr, igvm_sz); >> + } >> + >> + if (debug) { >> + fprintf(stderr, "writing igvm file into the guest memory\n"); >> + } >> + >> + qtest_bufwrite(qs->qts, gaddr, igvm_blob, igvm_sz); >> + >> + if (debug) { >> + fprintf(stderr, >> + "tell hypervisor where igvm is loaded in guest memory\n"); >> + } >> + >> + /* now tell hypervisor where we loaded the bios */ >> + memset(&launch_update, 0, sizeof(launch_update)); >> + launch_update.fw_image_size = cpu_to_le64(igvm_sz); >> + launch_update.fw_image_addr = cpu_to_le64(gaddr); >> + >> + /* set both host ctrl and format_igvm ctrl once */ >> + launch_update.control |= VM_LAUNCHUPDATE_FORMAT_IGVM; >> + launch_update.control |= VM_LAUNCHUPDATE_CTL_HOST_IGVM; >> + >> + filesize = qfw_cfg_write_file(fw_cfg, qs, FILE_VMLAUNCHUPDATE, >> + &launch_update, sizeof(launch_update)); >> + g_assert_cmpint(filesize, ==, sizeof(launch_update)); >> + >> + if (debug) { >> + fprintf(stderr, "resetting the virtual machine. This should load " >> + "user provided igvm.\n"); >> + } >> + >> + qtest_system_reset(qs->qts); >> + >> + /* expected string should be printed on the console */ >> + g_assert_true(wait_for_match(serialtmp, exp_out, WAIT_SEC, 1) == 0); >> + g_assert_true(wait_for_match(serialtmp, exp_out2, WAIT_SEC, 1) == 0); >> + >> + if (debug) { >> + fprintf(stderr, "hello world found on console\n"); >> + fprintf(stderr, "Now resetting again in order to reset to host igvm\n"); >> + } >> + >> + qtest_system_reset(qs->qts); >> + >> + /* >> + * exp_out3 should be printed twice, once from initial boot, >> + * once from restoring host igvm. >> + */ >> + g_assert_true(wait_for_match(serialtmp, exp_out3, WAIT_SEC, 2) == 0); >> + >> + if (debug) { >> + fprintf(stderr, "booted with host igvm\n"); >> + } >> + >> close(ser_fd); >> guest_free(&qs->alloc, gaddr); >> pc_fw_cfg_uninit(fw_cfg); >> @@ -435,6 +608,8 @@ int main(int argc, char **argv) >> g_test_add_func("/vm-launch-update/errorcheck", check_error); >> g_test_add_func("/vm-launch-update/load_igvm", >> test_load_igvm); >> + g_test_add_func("/vm-launch-update/ctrl_set_once", >> + test_set_ctrl_once_and_reset_to_host_igvm); >> >> if (getenv("LAUNCHUPDATE_DEBUG")) { >> debug = true; >> -- >> 2.54.0 >>