From 1c91237cfcb71e1d5a21f362af18fe16be2fddbe Mon Sep 17 00:00:00 2001 From: Daniel Hilst <392820+dhilst@users.noreply.github.com> Date: Thu, 8 Oct 2026 12:14:41 -0300 Subject: [PATCH] test(kvm): cover the accelerator and CPU policy of an ARM guest The aarch64 domain of the branch was measured on one host and guest pair, an x86_64 hypervisor emulating aarch64. Three other pairs are not covered. An aarch64 guest on an aarch64 hypervisor must be a kvm domain that takes the host CPU, not a qemu domain pinned to cortex-a57. An aarch64 guest on a POWER hypervisor must take neither the POWER CPU model, nor the pseries CPU topology, nor the qemu-system-ppc64 emulator. A CPU mode from vm.othersettings must not reach an emulated domain, because TCG has no host CPU. The video assertion stated that the aarch64 virt machine has no virtio video model. libvirt reports virtio for a riscv64 virt machine and not for an aarch64 one on the same host, and the aarch64 emulator there has no virtio-gpu device, so the refusal came from that build and not from the machine type. The test now expects the virtio model, as it does for riscv64. The POWER controls now pass a hypervisor cputype, which is what builds the CPU model and the topology element. Ten of the new assertions fail on the unfixed tree. Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com> --- xCAT-test/unit/kvm_guest_arch.t | 100 +++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 14 deletions(-) diff --git a/xCAT-test/unit/kvm_guest_arch.t b/xCAT-test/unit/kvm_guest_arch.t index 0147f7182..5d3985e33 100644 --- a/xCAT-test/unit/kvm_guest_arch.t +++ b/xCAT-test/unit/kvm_guest_arch.t @@ -37,13 +37,22 @@ eval $harness . join("\n", @routines) . "\n1;\n"; ## no critic (BuiltinFuncti die("could not load the kvm domain builder: $@") if $@; # Build one domain for a node of $guest_arch on a hypervisor that reports $hyp_cpumodel. +# %opt carries the hypervisor cputype and the vm.othersettings of the node. sub domain_xml { - my ($guest_arch, $hyp_cpumodel) = @_; + my ($guest_arch, $hyp_cpumodel, %opt) = @_; local $KVMArch::node = 'cn1'; local $KVMArch::confdata = { - vm => { cn1 => [ { host => 'hyp1', memory => 8192, cpus => 4 } ] }, + vm => { + cn1 => [ { + host => 'hyp1', + memory => 8192, + cpus => 4, + (defined $opt{othersettings} + ? (othersettings => $opt{othersettings}) : ()), + } ] + }, nodetype => { cn1 => [ { arch => $guest_arch, os => 'rocky10.2' } ] }, - hyp1 => { cpumodel => $hyp_cpumodel }, + hyp1 => { cpumodel => $hyp_cpumodel, cputype => $opt{cputype} }, }; local $KVMArch::updatetable = {}; my $xml = KVMArch::build_xmldesc('cn1'); @@ -76,9 +85,9 @@ unlike($riscv, qr/ element libvirt passes -cpu max, which under TCG turns on SVE, and the -# guest then stays in its firmware. +# An aarch64 node on an x86_64 hypervisor. The guest arch is not the host arch, so the domain +# runs under emulation and needs a named CPU model: TCG has no host CPU, and with no +# element the emulator turns on SVE, which stops the guest in its firmware. my $arm = domain_xml('aarch64', 'x86_64'); like($arm, qr/]*\btype="qemu"/, 'an aarch64 guest on an x86_64 hypervisor is a qemu domain, not kvm'); @@ -88,10 +97,10 @@ like(os_type_element($arm), qr/\bmachine="virt"/, 'an aarch64 guest uses the virt machine type'); like($arm, qr/]*\bfirmware="efi"/, 'an aarch64 virt guest boots UEFI'); -like($arm, qr{]*>\s*cortex-a57}s, - 'an aarch64 guest states the cortex-a57 CPU model'); -like($arm, qr/]*\btype="vga"/, - 'an aarch64 guest keeps the vga video model: the aarch64 virt machine offers no virtio one'); +like($arm, qr{]*\bmode="custom"[^>]*>\s*cortex-a57}s, + 'an emulated aarch64 guest states cortex-a57 as a custom CPU model'); +like($arm, qr/]*\btype="virtio"/, + 'an aarch64 virt guest takes the virtio video model, as a riscv64 virt guest does'); unlike($arm, qr/<(?:pae|acpi|apic)\b/, 'pae, acpi and apic are x86 features and are left out of an aarch64 guest'); unlike($arm, qr/]*\btype="kvm"/, + 'an aarch64 guest on an aarch64 hypervisor is a kvm domain, not qemu'); +like($arm_native, qr/]*\bmode="host-passthrough"/, + 'a native aarch64 guest takes the host CPU'); +unlike($arm_native, qr{cortex-a57}, + 'a native aarch64 guest pins no cortex-a57 model'); +like(os_type_element($arm_native), qr/\barch="aarch64"/, + 'a native aarch64 guest states arch aarch64'); +like(os_type_element($arm_native), qr/\bmachine="virt"/, + 'a native aarch64 guest states machine virt'); +like($arm_native, qr/]*\bfirmware="efi"/, + 'a native aarch64 virt guest boots UEFI'); + +# An aarch64 node on a POWER hypervisor. The CPU model, the CPU topology and the emulator are +# settings of a pseries guest, and this guest is not one. +my $arm_on_power = domain_xml('aarch64', 'ppc64', cputype => 'POWER9'); +like($arm_on_power, qr/]*\btype="qemu"/, + 'an aarch64 guest on a POWER hypervisor is a qemu domain, not kvm'); +like(os_type_element($arm_on_power), qr/\barch="aarch64"/, + 'an aarch64 guest on a POWER hypervisor keeps arch aarch64'); +like(os_type_element($arm_on_power), qr/\bmachine="virt"/, + 'an aarch64 guest on a POWER hypervisor keeps machine virt'); +unlike($arm_on_power, qr/\bmodel="POWER9"/, + 'an aarch64 guest takes no POWER CPU model from the hypervisor'); +unlike($arm_on_power, qr/}, + 'libvirt resolves the emulator of an aarch64 guest on a POWER hypervisor'); +like($arm_on_power, qr{cortex-a57}, + 'an aarch64 guest on a POWER hypervisor still states cortex-a57'); + +# vm.othersettings can name a CPU mode. TCG has no host CPU, so libvirt refuses both +# host-passthrough and host-model on an emulated domain. +my $arm_passthrough = + domain_xml('aarch64', 'x86_64', othersettings => 'cpumode:host-passthrough'); +unlike($arm_passthrough, qr/\bmode="host-passthrough"/, + 'host-passthrough from vm.othersettings is left out of an emulated aarch64 domain'); +like($arm_passthrough, qr{cortex-a57}, + 'the emulated aarch64 guest keeps cortex-a57 when host-passthrough is left out'); + +my $arm_native_hostmodel = + domain_xml('aarch64', 'aarch64', othersettings => 'cpumode:host-model'); +like($arm_native_hostmodel, qr/]*\bmode="host-model"/, + 'host-model from vm.othersettings reaches a native aarch64 domain'); +unlike($arm_native_hostmodel, qr/\bmode="host-passthrough"/, + 'the mode from vm.othersettings replaces the host-passthrough default'); + +# POWER is unchanged: a pseries guest keeps the arch, the CPU model and the topology of the +# hypervisor. +my $power = domain_xml('ppc64le', 'ppc64le', cputype => 'POWER9'); like($power, qr/]*\btype="kvm"/, 'a POWER guest stays a kvm domain'); like(os_type_element($power), qr/\barch="ppc64"/, 'ppc64le hypervisors keep arch ppc64'); like(os_type_element($power), qr/\bmachine="pseries"/, 'ppc64le hypervisors keep machine pseries'); -like($power, qr/]*\bcores="4"/, 'a POWER guest keeps its CPU topology'); -unlike($power, qr/cortex-a57<\/model>/, 'a POWER guest states no aarch64 CPU model'); +like($power, qr/]*\bmodel="POWER9"/, 'a POWER guest keeps the hypervisor CPU model'); +like($power, qr/]*\bcores="4"/, 'a POWER guest keeps its CPU topology'); +unlike($power, qr{cortex-a57}, 'a POWER guest states no aarch64 CPU model'); + +# A ppc64 hypervisor names its own emulator, and a pseries guest still gets it. +my $power_ppc64 = domain_xml('ppc64', 'ppc64', cputype => 'POWER9'); +like($power_ppc64, qr{/usr/bin/qemu-system-ppc64}, + 'a pseries guest on a ppc64 hypervisor keeps the qemu-system-ppc64 emulator'); # x86_64 on x86_64 is unchanged: libvirt picks the arch and the machine type. my $x86 = domain_xml('x86_64', 'x86_64'); @@ -115,6 +182,11 @@ unlike(os_type_element($x86), qr/\bmachine=/, 'an x86_64 guest states no machine like($x86, qr/]*\bbus="usb"/, 'an x86_64 guest keeps the USB tablet'); unlike($x86, qr/ 'cpumode:host-passthrough'); +like($x86_passthrough, qr/]*\bmode="host-passthrough"/, + 'host-passthrough from vm.othersettings reaches a native x86_64 domain'); + # The disks of a riscv64 guest. The virt machine has no IDE controller, so an ide disk or an # hd* optical drive makes libvirt refuse the domain. sub disk_struct {