@samitouri / QOSamiQemu / commits / da4ba40695

tests/functional/x86_64: add functional test to exercise vm fd change on reset

A new functional test is added that exercises the code changes related to closing of the old KVM VM file descriptor and opening a new one upon VM reset. This normally happens when confidential guests are reset but for non-confidential guests, we use a special machine specific debug/test parameter 'x-change-vmfd-on-reset' to enable this behavior. Only specific code changes related to re-initialisation of SEV-ES, SEV-SNP and TDX platforms are not exercised in this test as they require hardware that supports running confidential guests. Signed-off-by: Ani Sinha <anisinha@redhat.com> Link: https://lore.kernel.org/r/20260225035000.385950-34-anisinha@redhat.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Ani Sinha committed Feb 25, 2026 at 09:19 UTC da4ba40695beb4df4907b9ce7e88a8beb8dc9c37
3 files changed +138
MAINTAINERS
+1
@@ -157,6 +157,7 @@ M: Ani Sinha <anisinha@redhat.com>
157 M: Paolo Bonzini <pbonzini@redhat.com>
158 S: Maintained
159 F: stubs/kvm.c
160 +F: tests/functional/x86_64/test_rebuild_vmfd.py
161
162 Guest CPU cores (TCG)
163 ---------------------
tests/functional/x86_64/meson.build
+1
@@ -37,4 +37,5 @@ tests_x86_64_system_thorough = [
37 'vhost_user_bridge',
38 'virtio_balloon',
39 'virtio_gpu',
40 + 'rebuild_vmfd',
41 ]
tests/functional/x86_64/test_rebuild_vmfd.py new
+136
@@ -0,0 +1,136 @@
1 +#!/usr/bin/env python3
2 +#
3 +# Functional tests exercising guest KVM file descriptor change on reset.
4 +#
5 +# Copyright © 2026 Red Hat, Inc.
6 +#
7 +# Author:
8 +# Ani Sinha <anisinha@redhat.com>
9 +#
10 +# SPDX-License-Identifier: GPL-2.0-or-later
11 +
12 +import os
13 +from qemu.machine import machine
14 +
15 +from qemu_test import QemuSystemTest, Asset, exec_command_and_wait_for_pattern
16 +from qemu_test import wait_for_console_pattern
17 +
18 +class KVMGuest(QemuSystemTest):
19 +
20 + # ASSET UKI was generated using
21 + # https://gitlab.com/kraxel/edk2-tests/-/blob/unittest/tools/make-supermin.sh
22 + ASSET_UKI = Asset('https://gitlab.com/anisinha/misc-artifacts/'
23 + '-/raw/main/uki.x86-64.efi?ref_type=heads',
24 + 'e0f806bd1fa24111312e1fe849d2ee69808d4343930a5'
25 + 'dc8c1688da17c65f576')
26 + # ASSET_OVMF comes from /usr/share/edk2/ovmf/OVMF.stateless.fd of a
27 + # fedora core 43 distribution which in turn comes from the
28 + # edk2-ovmf-20251119-3.fc43.noarch rpm of that distribution.
29 + ASSET_OVMF = Asset('https://gitlab.com/anisinha/misc-artifacts/'
30 + '-/raw/main/OVMF.stateless.fd?ref_type=heads',
31 + '58a4275aafa8774bd6b1540adceae4ea434b8db75b476'
32 + '11839ff47be88cfcf22')
33 +
34 + def common_vm_setup(self, kvm_args=None, cpu_args=None):
35 + self.set_machine('q35')
36 + self.require_accelerator("kvm")
37 +
38 + self.vm.set_console()
39 + if kvm_args:
40 + self.vm.add_args("-accel", "kvm,%s" %kvm_args)
41 + else:
42 + self.vm.add_args("-accel", "kvm")
43 + self.vm.add_args("-smp", "2")
44 + if cpu_args:
45 + self.vm.add_args("-cpu", "host,%s" %cpu_args)
46 + else:
47 + self.vm.add_args("-cpu", "host")
48 + self.vm.add_args("-m", "2G")
49 + self.vm.add_args("-nographic", "-nodefaults")
50 +
51 +
52 + self.uki_path = self.ASSET_UKI.fetch()
53 + self.ovmf_path = self.ASSET_OVMF.fetch()
54 +
55 + self.vm.add_args('-kernel', self.uki_path)
56 + self.vm.add_args("-bios", self.ovmf_path)
57 + # enable KVM VMFD change on reset for a non-coco VM
58 + self.vm.add_args("-machine", "q35,x-change-vmfd-on-reset=on")
59 +
60 + # enable tracing of basic vmfd change function
61 + self.vm.add_args("--trace", "kvm_reset_vmfd")
62 +
63 + def launch_vm(self):
64 + try:
65 + self.vm.launch()
66 + except machine.VMLaunchFailure as e:
67 + if "Xen HVM guest support not present" in e.output:
68 + self.skipTest("KVM Xen support is not present "
69 + "(need v5.12+ kernel with CONFIG_KVM_XEN)")
70 + elif "Property 'kvm-accel.xen-version' not found" in e.output:
71 + self.skipTest("QEMU not built with CONFIG_XEN_EMU support")
72 + else:
73 + raise e
74 +
75 + self.log.info('VM launched')
76 + console_pattern = 'bash-5.1#'
77 + wait_for_console_pattern(self, console_pattern)
78 + self.log.info('VM ready with a bash prompt')
79 +
80 + def vm_console_reset(self):
81 + exec_command_and_wait_for_pattern(self, '/usr/sbin/reboot -f',
82 + 'reboot: machine restart')
83 + console_pattern = '# --- Hello world ---'
84 + wait_for_console_pattern(self, console_pattern)
85 + self.vm.shutdown()
86 +
87 + def vm_qmp_reset(self):
88 + self.vm.qmp('system_reset')
89 + console_pattern = '# --- Hello world ---'
90 + wait_for_console_pattern(self, console_pattern)
91 + self.vm.shutdown()
92 +
93 + def check_logs(self):
94 + self.assertRegex(self.vm.get_log(),
95 + r'kvm_reset_vmfd')
96 + self.assertRegex(self.vm.get_log(),
97 + r'virtual machine state has been rebuilt')
98 +
99 + def test_reset_console(self):
100 + self.common_vm_setup()
101 + self.launch_vm()
102 + self.vm_console_reset()
103 + self.check_logs()
104 +
105 + def test_reset_qmp(self):
106 + self.common_vm_setup()
107 + self.launch_vm()
108 + self.vm_qmp_reset()
109 + self.check_logs()
110 +
111 + def test_reset_kvmpit(self):
112 + self.common_vm_setup()
113 + self.vm.add_args("--trace", "kvmpit_post_vmfd_change")
114 + self.launch_vm()
115 + self.vm_console_reset()
116 + self.assertRegex(self.vm.get_log(),
117 + r'kvmpit_post_vmfd_change')
118 +
119 + def test_reset_xen_emulation(self):
120 + self.common_vm_setup("xen-version=0x4000a,kernel-irqchip=split")
121 + self.launch_vm()
122 + self.vm_console_reset()
123 + self.check_logs()
124 +
125 + def test_reset_hyperv_vmbus(self):
126 + self.common_vm_setup(None, "hv-syndbg,hv-relaxed,hv_time,hv-synic,"
127 + "hv-vpindex,hv-runtime,hv-stimer")
128 + self.vm.add_args("-device", "vmbus-bridge,irq=15")
129 + self.vm.add_args("-trace", "vmbus_handle_vmfd_change")
130 + self.launch_vm()
131 + self.vm_console_reset()
132 + self.assertRegex(self.vm.get_log(),
133 + r'vmbus_handle_vmfd_change')
134 +
135 +if __name__ == '__main__':
136 + QemuSystemTest.main()