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

Reply via email to