mirror of
https://gitlab.com/qemu-project/qemu.git
synced 2026-08-26 22:23:12 -04:00
This patchset adds functional and unit tests that exercize various functions and behaviors of vm-launch-update device. It uses the IGVM files that were introduced in the previous patch for exercizing the hypervisor interface. CC: Alex Graf <graf@amazon.com> CC: Gerd Hoffman <kraxel@redhat.com> Reviewed-by: Alexander Graf <graf@amazon.com> Signed-off-by: Ani Sinha <anisinha@redhat.com> Message-ID: <20260817142010.80693-11-anisinha@redhat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
625 lines
19 KiB
C
625 lines
19 KiB
C
/*
|
|
* vmlaunchupdate device fwcfg test.
|
|
*
|
|
* Copyright (c) 2026 Red Hat, Inc.
|
|
*
|
|
* Author:
|
|
* Ani Sinha <anisinha@redhat.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "libqos/libqos-pc.h"
|
|
#include "libqtest.h"
|
|
#include "standard-headers/linux/qemu_fw_cfg.h"
|
|
#include "libqos/fw_cfg.h"
|
|
#include "qemu/bswap.h"
|
|
#include "hw/misc/vmlaunchupdate.h"
|
|
|
|
#define WAIT_SEC 10
|
|
static bool debug;
|
|
static bool trace;
|
|
static bool confidential;
|
|
|
|
static void test_vm_launch_update_capability(void)
|
|
{
|
|
QFWCFG *fw_cfg;
|
|
QTestState *s;
|
|
VMLaunchUpdate launch_update;
|
|
size_t filesize;
|
|
uint64_t capabilities;
|
|
|
|
if (!qtest_has_device("vm-launch-update")) {
|
|
g_test_skip("Device vm-launch-update is not available");
|
|
return;
|
|
}
|
|
|
|
s = qtest_init("-device vm-launch-update");
|
|
fw_cfg = pc_fw_cfg_init(s);
|
|
|
|
filesize = qfw_cfg_get_file(fw_cfg, FILE_VMLAUNCHUPDATE,
|
|
&launch_update, sizeof(launch_update));
|
|
g_assert_cmpint(filesize, ==, sizeof(launch_update));
|
|
capabilities = le64_to_cpu(launch_update.capabilities);
|
|
g_assert_cmpint(capabilities, ==, VM_LAUNCHUPDATE_FORMAT_IGVM);
|
|
pc_fw_cfg_uninit(fw_cfg);
|
|
qtest_quit(s);
|
|
}
|
|
|
|
|
|
static void test_vm_launch_update_disable(void)
|
|
{
|
|
QFWCFG *fw_cfg;
|
|
QOSState *qs;
|
|
VMLaunchUpdate launch_update;
|
|
uint64_t control;
|
|
size_t filesize;
|
|
|
|
if (!qtest_has_device("vm-launch-update")) {
|
|
g_test_skip("Device vm-launch-update is not available");
|
|
return;
|
|
}
|
|
|
|
/* use default accelerator */
|
|
qs = qtest_pc_boot("-device vm-launch-update");
|
|
|
|
fw_cfg = pc_fw_cfg_init(qs->qts);
|
|
|
|
filesize = qfw_cfg_get_file(fw_cfg, FILE_VMLAUNCHUPDATE,
|
|
&launch_update, sizeof(launch_update));
|
|
g_assert_cmpint(filesize, ==, sizeof(launch_update));
|
|
control = le64_to_cpu(launch_update.control);
|
|
g_assert_cmpint(VM_LAUNCHUPDATE_CTL_DISABLE & control, ==, 0);
|
|
|
|
/* disable the device */
|
|
memset(&launch_update, 0, sizeof(launch_update));
|
|
launch_update.control |= VM_LAUNCHUPDATE_CTL_DISABLE;
|
|
|
|
filesize = qfw_cfg_write_file(fw_cfg, qs, FILE_VMLAUNCHUPDATE,
|
|
&launch_update, sizeof(launch_update));
|
|
g_assert_cmpint(filesize, ==, sizeof(launch_update));
|
|
|
|
/* try to clear the dsable flag */
|
|
memset(&launch_update, 0, sizeof(launch_update));
|
|
|
|
filesize = qfw_cfg_write_file(fw_cfg, qs, FILE_VMLAUNCHUPDATE,
|
|
&launch_update, sizeof(launch_update));
|
|
g_assert_cmpint(filesize, ==, sizeof(launch_update));
|
|
|
|
/* check if the device is still disabled */
|
|
filesize = qfw_cfg_get_file(fw_cfg, FILE_VMLAUNCHUPDATE,
|
|
&launch_update, sizeof(launch_update));
|
|
g_assert_cmpint(filesize, ==, sizeof(launch_update));
|
|
control = le64_to_cpu(launch_update.control);
|
|
g_assert_cmpint(VM_LAUNCHUPDATE_CTL_DISABLE & control, ==, 1);
|
|
|
|
pc_fw_cfg_uninit(fw_cfg);
|
|
qtest_shutdown(qs);
|
|
}
|
|
|
|
static void check_error(void)
|
|
{
|
|
QFWCFG *fw_cfg;
|
|
QOSState *qs;
|
|
VMLaunchUpdate launch_update;
|
|
uint16_t status;
|
|
size_t filesize;
|
|
|
|
if (!qtest_has_device("vm-launch-update")) {
|
|
g_test_skip("Device vm-launch-update is not available");
|
|
return;
|
|
}
|
|
|
|
/* guest not started with IGVM and with default accelerator */
|
|
qs = qtest_pc_boot("-device vm-launch-update");
|
|
|
|
fw_cfg = pc_fw_cfg_init(qs->qts);
|
|
|
|
memset(&launch_update, 0, sizeof(launch_update));
|
|
launch_update.fw_image_size = 50;
|
|
launch_update.fw_image_addr = cpu_to_le64(0xdeadbeef);
|
|
launch_update.control |= VM_LAUNCHUPDATE_FORMAT_IGVM;
|
|
|
|
filesize = qfw_cfg_write_file(fw_cfg, qs, FILE_VMLAUNCHUPDATE,
|
|
&launch_update, sizeof(launch_update));
|
|
g_assert_cmpint(filesize, ==, sizeof(launch_update));
|
|
|
|
memset(&launch_update, 0, sizeof(launch_update));
|
|
filesize = qfw_cfg_get_file(fw_cfg, FILE_VMLAUNCHUPDATE,
|
|
&launch_update, sizeof(launch_update));
|
|
g_assert_cmpint(filesize, ==, sizeof(launch_update));
|
|
status = le64_to_cpu(launch_update.status);
|
|
/* should fail with NOT_IGVM_INIT */
|
|
g_assert_cmpint(status, ==, VM_LAUNCHUPDATE_NOT_IGVM_INIT);
|
|
|
|
memset(&launch_update, 0, sizeof(launch_update));
|
|
launch_update.fw_image_size = 50;
|
|
launch_update.fw_image_addr = cpu_to_le64(0xdeadbeef);
|
|
/* control set to 0, not VM_LAUNCHUPDATE_FORMAT_IGVM */
|
|
|
|
filesize = qfw_cfg_write_file(fw_cfg, qs, FILE_VMLAUNCHUPDATE,
|
|
&launch_update, sizeof(launch_update));
|
|
g_assert_cmpint(filesize, ==, sizeof(launch_update));
|
|
|
|
memset(&launch_update, 0, sizeof(launch_update));
|
|
filesize = qfw_cfg_get_file(fw_cfg, FILE_VMLAUNCHUPDATE,
|
|
&launch_update, sizeof(launch_update));
|
|
g_assert_cmpint(filesize, ==, sizeof(launch_update));
|
|
status = le64_to_cpu(launch_update.status);
|
|
/* should fail with LOAD_FAIL since it was not IGVM format */
|
|
g_assert_cmpint(status, ==, VM_LAUNCHUPDATE_LOAD_FAIL);
|
|
}
|
|
|
|
static int64_t get_image_size(const char *filename)
|
|
{
|
|
int fd;
|
|
int64_t size;
|
|
fd = open(filename, O_RDONLY | O_BINARY);
|
|
g_assert_true(fd > 0);
|
|
size = lseek(fd, 0, SEEK_END);
|
|
close(fd);
|
|
return size;
|
|
}
|
|
|
|
static ssize_t load_image(const char *igvm_f, void **addr, size_t *size)
|
|
{
|
|
ssize_t actsize = 0, l = 0;
|
|
int f_igvm_f;
|
|
size_t l_size;
|
|
|
|
f_igvm_f = open(igvm_f, O_RDONLY | O_BINARY);
|
|
g_assert_true(f_igvm_f);
|
|
l_size = get_image_size(igvm_f);
|
|
g_assert_true(l_size > 0);
|
|
*addr = g_malloc0(l_size);
|
|
g_assert_true(*addr);
|
|
|
|
while (l < l_size) {
|
|
actsize = read(f_igvm_f, *addr + l, 1);
|
|
if (actsize < 0) {
|
|
break;
|
|
}
|
|
l += actsize;
|
|
}
|
|
|
|
close(f_igvm_f);
|
|
*size = l_size;
|
|
return actsize < 0 ? -1 : l;
|
|
}
|
|
|
|
static guint32 match_string(char *serial_f, const char *exp_out)
|
|
{
|
|
GError *error = NULL;
|
|
g_autofree gchar *f_contents = NULL;
|
|
g_autofree GRegex *regex = NULL;
|
|
g_autofree GMatchInfo *match_info = NULL;
|
|
gsize len;
|
|
guint32 count = 0;
|
|
gboolean ret;
|
|
|
|
ret = g_file_get_contents(serial_f, &f_contents, &len, &error);
|
|
g_assert(ret);
|
|
g_assert_no_error(error);
|
|
|
|
regex = g_regex_new(exp_out, G_REGEX_CASELESS, 0, &error);
|
|
g_assert_no_error(error);
|
|
|
|
ret = g_regex_match_full(regex, f_contents, -1, 0, 0, &match_info, &error);
|
|
g_assert_no_error(error);
|
|
|
|
while (g_match_info_matches(match_info)) {
|
|
gchar *word = g_match_info_fetch(match_info, 0);
|
|
g_free(word);
|
|
g_match_info_next(match_info, &error);
|
|
count++;
|
|
}
|
|
g_regex_unref(regex);
|
|
return count;
|
|
}
|
|
|
|
static int wait_for_match(char *serial_f,
|
|
const char *exp_out, int64_t timeout_s,
|
|
guint32 count)
|
|
{
|
|
time_t start, delta;
|
|
int ret = -1;
|
|
|
|
start = time(NULL);
|
|
while (1) {
|
|
if (match_string(serial_f, exp_out) == count) {
|
|
ret = 0;
|
|
break;
|
|
}
|
|
|
|
delta = time(NULL) - start;
|
|
if (delta >= timeout_s) {
|
|
fprintf(stderr, "timed out waiting to read serial output\n");
|
|
break;
|
|
}
|
|
|
|
/* wait 20 ms before trying again */
|
|
if (false) {
|
|
fprintf(stderr,
|
|
"sleeping 20 ms before checking serial output again.\n");
|
|
}
|
|
g_usleep(20000);
|
|
}
|
|
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;
|
|
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 *tracepoints = "--trace memory_region_finalize "
|
|
"--trace qigvm_cleanup_memory -D /tmp/qemu-debug.log ";
|
|
const char *snp, *cgs;
|
|
uint64_t gaddr;
|
|
size_t igvm_sz;
|
|
size_t filesize;
|
|
QFWCFG *fw_cfg;
|
|
QOSState *qs;
|
|
VMLaunchUpdate launch_update;
|
|
|
|
if (!trace) {
|
|
tracepoints = "";
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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, tracepoints, serialtmp, igvm_init, snp);
|
|
|
|
fw_cfg = pc_fw_cfg_init(qs->qts);
|
|
|
|
if (debug) {
|
|
fprintf(stderr, "target endianness: %s\n",
|
|
qtest_big_endian(qs->qts) ? "big" : "little");
|
|
}
|
|
|
|
/* 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 */
|
|
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);
|
|
launch_update.control |= VM_LAUNCHUPDATE_FORMAT_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 now\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");
|
|
}
|
|
|
|
/* check if VM_LAUNCHUPDATE_CTL_HOST_IGVM function works */
|
|
|
|
/* 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;
|
|
|
|
filesize = qfw_cfg_write_file(fw_cfg, qs, FILE_VMLAUNCHUPDATE,
|
|
&launch_update, sizeof(launch_update));
|
|
g_assert_cmpint(filesize, ==, sizeof(launch_update));
|
|
|
|
/* now reset the guest */
|
|
if (debug) {
|
|
fprintf(stderr,
|
|
"resetting again in order to restore host provided 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 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;
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
/* qtest_quit() kils QEMU, first by sending SIGTERM, then SIGKILL */
|
|
qtest_quit(qs->qts);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
const char *arch = qtest_get_arch();
|
|
|
|
g_test_init(&argc, &argv, NULL);
|
|
|
|
if (strcmp(arch, "x86_64")) {
|
|
g_test_skip("vmlaunchupdate tests are only available on x86_64\n");
|
|
return 0;
|
|
}
|
|
|
|
g_test_add_func("/vm-launch-update/cap", test_vm_launch_update_capability);
|
|
g_test_add_func("/vm-launch-update/disabled",
|
|
test_vm_launch_update_disable);
|
|
|
|
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;
|
|
}
|
|
if (getenv("LAUNCHUPDATE_TRACE")) {
|
|
trace = true;
|
|
}
|
|
if (getenv("COCO")) {
|
|
confidential = true;
|
|
}
|
|
|
|
return g_test_run();
|
|
}
|