From: Ian May <[email protected]> Add test coverage for the ACPI EGM memory device feature:
- Add test case to qemuxmlconftest.c for aarch64 architecture - Add acpi-egm-memory capability to QEMU 10.0.0 aarch64 capabilities - Create test input XML with EGM device configuration - Generate expected output XML and QEMU command line args - Update validation to skip filesystem checks during tests The test validates XML parsing, formatting, device validation, and QEMU command line generation for the EGM device. Signed-off-by: Ian May <[email protected]> Signed-off-by: Nathan Chen <[email protected]> --- src/conf/domain_conf.c | 5 +- src/conf/domain_postparse.c | 5 +- src/qemu/qemu_domain.c | 2 + src/util/virfile.h | 2 +- tests/meson.build | 1 + tests/qemuegmmock.c | 67 ++++++++++ .../acpi-egm-memory.aarch64-latest.args | 47 +++++++ .../acpi-egm-memory.aarch64-latest.xml | 124 ++++++++++++++++++ tests/qemuxmlconfdata/acpi-egm-memory.xml | 124 ++++++++++++++++++ tests/qemuxmlconftest.c | 8 +- 10 files changed, 381 insertions(+), 4 deletions(-) create mode 100644 tests/qemuegmmock.c create mode 100644 tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.args create mode 100644 tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.xml create mode 100644 tests/qemuxmlconfdata/acpi-egm-memory.xml diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 2cda32fa6e..3fba40476f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -8813,8 +8813,11 @@ virDomainDefGetMemoryInitial(const virDomainDef *def) size_t i; unsigned long long ret = def->mem.total_memory; - for (i = 0; i < def->nmems; i++) + for (i = 0; i < def->nmems; i++) { + if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM) + continue; ret -= def->mems[i]->size; + } return ret; } diff --git a/src/conf/domain_postparse.c b/src/conf/domain_postparse.c index 0181d21f0e..bb4a61b7d8 100644 --- a/src/conf/domain_postparse.c +++ b/src/conf/domain_postparse.c @@ -44,8 +44,11 @@ virDomainDefPostParseMemory(virDomainDef *def, numaMemory = virDomainNumaGetMemorySize(def->numa); /* calculate the sizes of hotplug memory */ - for (i = 0; i < def->nmems; i++) + for (i = 0; i < def->nmems; i++) { + if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM) + continue; hotplugMemory += def->mems[i]->size; + } if (numaMemory) { /* update the sizes in XML if nothing was set in the XML or ABI update diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 14f2b3ec5d..1b0b375a49 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -8038,6 +8038,8 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef *def, } for (i = 0; i < def->nmems; i++) { + if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM) + continue; hotplugMemory += def->mems[i]->size; switch (def->mems[i]->model) { diff --git a/src/util/virfile.h b/src/util/virfile.h index ce2ffb8ed4..5203ef4425 100644 --- a/src/util/virfile.h +++ b/src/util/virfile.h @@ -167,7 +167,7 @@ int virFileReadHeaderQuiet(const char *path, int maxlen, char **buf) int virFileReadLimFD(int fd, int maxlen, char **buf) G_GNUC_WARN_UNUSED_RESULT ATTRIBUTE_NONNULL(3); int virFileReadAll(const char *path, int maxlen, char **buf) - G_GNUC_WARN_UNUSED_RESULT ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); + G_GNUC_WARN_UNUSED_RESULT ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_MOCKABLE; int virFileReadAllQuiet(const char *path, int maxlen, char **buf) G_GNUC_WARN_UNUSED_RESULT ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); int virFileReadBufQuiet(const char *file, char *buf, int len) diff --git a/tests/meson.build b/tests/meson.build index bb6ee6b4ee..28ee8591a3 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -174,6 +174,7 @@ if conf.has('WITH_QEMU') { 'name': 'qemucaps2xmlmock' }, { 'name': 'qemucapsprobemock', 'link_with': [ test_qemu_driver_lib ] }, { 'name': 'qemucpumock' }, + { 'name': 'qemuegmmock' }, { 'name': 'qemuhotplugmock', 'link_with': [ test_qemu_driver_lib, test_utils_qemu_lib, test_utils_lib ] }, { 'name': 'qemuxml2argvmock' }, { 'name': 'virhostidmock' }, diff --git a/tests/qemuegmmock.c b/tests/qemuegmmock.c new file mode 100644 index 0000000000..c915212f45 --- /dev/null +++ b/tests/qemuegmmock.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2024 Red Hat, Inc. + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include <config.h> +#include <unistd.h> + +#include "internal.h" +#include "virfile.h" +#include "virmock.h" + +static bool (*real_virFileExists)(const char *path); +static int (*real_access)(const char *path, int mode); +static int (*real_virFileReadAll)(const char *path, int maxlen, char **buf); + +static void +init_syms(void) +{ + if (real_virFileExists && real_access && real_virFileReadAll) + return; + + VIR_MOCK_REAL_INIT(virFileExists); + VIR_MOCK_REAL_INIT(access); + VIR_MOCK_REAL_INIT(virFileReadAll); +} + +bool +virFileExists(const char *path) +{ + init_syms(); + + /* Mock EGM device paths for testing */ + if (g_str_has_prefix(path, "/dev/egm") || + g_str_has_prefix(path, "/sys/class/egm/")) + return true; + + return real_virFileExists(path); +} + +int +access(const char *path, int mode) +{ + init_syms(); + + /* Mock EGM device paths for testing */ + if (g_str_has_prefix(path, "/dev/egm") || + g_str_has_prefix(path, "/sys/class/egm/")) + return 0; /* success */ + + return real_access(path, mode); +} + +int +virFileReadAll(const char *path, int maxlen, char **buf) +{ + init_syms(); + + /* Mock EGM GPU device file for testing */ + if (g_str_has_prefix(path, "/sys/class/egm/") && + g_str_has_suffix(path, "/gpu_devices")) { + *buf = g_strdup("0000:01:00.0\n"); + return strlen(*buf); + } + + return real_virFileReadAll(path, maxlen, buf); +} diff --git a/tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.args b/tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.args new file mode 100644 index 0000000000..41d1fcc026 --- /dev/null +++ b/tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.args @@ -0,0 +1,47 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/var/lib/libvirt/qemu/domain--1-egm \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-egm/.local/share \ +XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-egm/.cache \ +XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-egm/.config \ +/usr/bin/qemu-system-aarch64 \ +-name guest=egm,debug-threads=on \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-egm/master-key.aes"}' \ +-machine virt,usb=off,gic-version=3,dump-guest-core=off,acpi=off \ +-accel kvm \ +-cpu host \ +-m size=524288k,maxmem=524288k \ +-overcommit mem-lock=off \ +-smp 4,sockets=2,dies=1,clusters=1,cores=2,threads=1 \ +-object '{"qom-type":"memory-backend-file","id":"memegm0","mem-path":"/dev/egm4","share":true,"size":268435456}' \ +-object acpi-egm-memory,id=egm0,pci-dev=ua-hostdev0,node=0 \ +-object acpi-egm-memory,id=egm1,pci-dev=ua-hostdev1,node=0 \ +-object '{"qom-type":"memory-backend-file","id":"memegm1","mem-path":"/dev/egm5","share":true,"size":268435456}' \ +-object acpi-egm-memory,id=egm2,pci-dev=ua-hostdev2,node=1 \ +-object acpi-egm-memory,id=egm3,pci-dev=ua-hostdev3,node=1 \ +-numa node,nodeid=0,cpus=0-1,memdev=memegm0 \ +-numa node,nodeid=1,cpus=2-3,memdev=memegm1 \ +-uuid 00010203-0405-4607-8809-0a0b0c0d0e0f \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-boot strict=on \ +-device '{"driver":"pcie-root-port","port":8,"chassis":1,"id":"pci.1","bus":"pcie.0","multifunction":true,"addr":"0x1"}' \ +-device '{"driver":"pcie-root-port","port":9,"chassis":2,"id":"pci.2","bus":"pcie.0","addr":"0x1.0x1"}' \ +-device '{"driver":"pcie-root-port","port":10,"chassis":3,"id":"pci.3","bus":"pcie.0","addr":"0x2"}' \ +-device '{"driver":"pcie-root-port","port":11,"chassis":4,"id":"pci.4","bus":"pcie.0","addr":"0x3"}' \ +-device '{"driver":"pcie-root-port","port":12,"chassis":5,"id":"pci.5","bus":"pcie.0","addr":"0x4"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-device '{"driver":"vfio-pci","host":"0000:01:00.0","id":"ua-hostdev0","bus":"pci.1","addr":"0x0"}' \ +-device '{"driver":"vfio-pci","host":"0000:02:00.0","id":"ua-hostdev1","bus":"pci.3","addr":"0x0"}' \ +-device '{"driver":"vfio-pci","host":"0000:03:00.0","id":"ua-hostdev2","bus":"pci.4","addr":"0x0"}' \ +-device '{"driver":"vfio-pci","host":"0000:04:00.0","id":"ua-hostdev3","bus":"pci.5","addr":"0x0"}' \ +-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ +-msg timestamp=on diff --git a/tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.xml b/tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.xml new file mode 100644 index 0000000000..bd73d613e5 --- /dev/null +++ b/tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.xml @@ -0,0 +1,124 @@ +<domain type='kvm'> + <name>egm</name> + <uuid>00010203-0405-4607-8809-0a0b0c0d0e0f</uuid> + <maxMemory unit='KiB'>524288</maxMemory> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>4</vcpu> + <os> + <type arch='aarch64' machine='virt'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <gic version='3'/> + </features> + <cpu mode='host-passthrough' check='none'> + <topology sockets='2' dies='1' clusters='1' cores='2' threads='1'/> + <numa> + <cell id='0' cpus='0-1' memory='262144' unit='KiB'/> + <cell id='1' cpus='2-3' memory='262144' unit='KiB'/> + </numa> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-aarch64</emulator> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x8'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='2' port='0x9'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='3' port='0xa'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='4' port='0xb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='5' port='0xc'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <audio id='1' type='none'/> + <hostdev mode='subsystem' type='pci' managed='yes'> + <source> + <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </source> + <alias name='ua-hostdev0'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <source> + <address domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> + </source> + <alias name='ua-hostdev1'/> + <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <source> + <address domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </source> + <alias name='ua-hostdev2'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <source> + <address domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </source> + <alias name='ua-hostdev3'/> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + </hostdev> + <memory model='egm' access='shared'> + <source> + <path>/dev/egm4</path> + </source> + <target> + <size unit='KiB'>131072</size> + <node>0</node> + <pciDev>ua-hostdev0</pciDev> + </target> + </memory> + <memory model='egm' access='shared'> + <source> + <path>/dev/egm4</path> + </source> + <target> + <size unit='KiB'>131072</size> + <node>0</node> + <pciDev>ua-hostdev1</pciDev> + </target> + </memory> + <memory model='egm' access='shared'> + <source> + <path>/dev/egm5</path> + </source> + <target> + <size unit='KiB'>131072</size> + <node>1</node> + <pciDev>ua-hostdev2</pciDev> + </target> + </memory> + <memory model='egm' access='shared'> + <source> + <path>/dev/egm5</path> + </source> + <target> + <size unit='KiB'>131072</size> + <node>1</node> + <pciDev>ua-hostdev3</pciDev> + </target> + </memory> + </devices> +</domain> diff --git a/tests/qemuxmlconfdata/acpi-egm-memory.xml b/tests/qemuxmlconfdata/acpi-egm-memory.xml new file mode 100644 index 0000000000..bd73d613e5 --- /dev/null +++ b/tests/qemuxmlconfdata/acpi-egm-memory.xml @@ -0,0 +1,124 @@ +<domain type='kvm'> + <name>egm</name> + <uuid>00010203-0405-4607-8809-0a0b0c0d0e0f</uuid> + <maxMemory unit='KiB'>524288</maxMemory> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>4</vcpu> + <os> + <type arch='aarch64' machine='virt'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <gic version='3'/> + </features> + <cpu mode='host-passthrough' check='none'> + <topology sockets='2' dies='1' clusters='1' cores='2' threads='1'/> + <numa> + <cell id='0' cpus='0-1' memory='262144' unit='KiB'/> + <cell id='1' cpus='2-3' memory='262144' unit='KiB'/> + </numa> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-aarch64</emulator> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x8'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='2' port='0x9'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='3' port='0xa'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='4' port='0xb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='5' port='0xc'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <audio id='1' type='none'/> + <hostdev mode='subsystem' type='pci' managed='yes'> + <source> + <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </source> + <alias name='ua-hostdev0'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <source> + <address domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> + </source> + <alias name='ua-hostdev1'/> + <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <source> + <address domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </source> + <alias name='ua-hostdev2'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <source> + <address domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </source> + <alias name='ua-hostdev3'/> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + </hostdev> + <memory model='egm' access='shared'> + <source> + <path>/dev/egm4</path> + </source> + <target> + <size unit='KiB'>131072</size> + <node>0</node> + <pciDev>ua-hostdev0</pciDev> + </target> + </memory> + <memory model='egm' access='shared'> + <source> + <path>/dev/egm4</path> + </source> + <target> + <size unit='KiB'>131072</size> + <node>0</node> + <pciDev>ua-hostdev1</pciDev> + </target> + </memory> + <memory model='egm' access='shared'> + <source> + <path>/dev/egm5</path> + </source> + <target> + <size unit='KiB'>131072</size> + <node>1</node> + <pciDev>ua-hostdev2</pciDev> + </target> + </memory> + <memory model='egm' access='shared'> + <source> + <path>/dev/egm5</path> + </source> + <target> + <size unit='KiB'>131072</size> + <node>1</node> + <pciDev>ua-hostdev3</pciDev> + </target> + </memory> + </devices> +</domain> diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c index de03c58c8a..07ffdf164c 100644 --- a/tests/qemuxmlconftest.c +++ b/tests/qemuxmlconftest.c @@ -3211,6 +3211,10 @@ mymain(void) DO_TEST_CAPS_LATEST("devices-acpi-index"); + DO_TEST_CAPS_ARCH_LATEST_FULL("acpi-egm-memory", "aarch64", + ARG_QEMU_CAPS, QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY, + ARG_END); + DO_TEST_CAPS_ARCH_LATEST_FULL("hvf-x86_64-q35-headless", "x86_64", ARG_CAPS_VARIANT, "+hvf", ARG_END); DO_TEST_CAPS_ARCH_LATEST_FULL("hvf-aarch64-virt-headless", "aarch64", ARG_CAPS_VARIANT, "+hvf", ARG_END); /* HVF guests should not work on Linux with KVM */ @@ -3317,7 +3321,9 @@ VIR_TEST_MAIN_PRELOAD(mymain, VIR_TEST_MOCK("domaincaps"), VIR_TEST_MOCK("virrandom"), VIR_TEST_MOCK("qemucpu"), - VIR_TEST_MOCK("virnuma")) + VIR_TEST_MOCK("virnuma"), + VIR_TEST_MOCK("virpci"), + VIR_TEST_MOCK("qemuegm")) #else -- 2.43.0
