[RFC PATCH v2 0/4] qemu: Implement support for EGM
The Grace SOC introduces Extended GPU Memory (EGM) [3], a feature that enables GPUs to efficiently access system memory within and across nodes. This patch series adds support for virtualizing EGM (vEGM) in libvirt, allowing VMs to utilize dedicated EGM memory regions through ACPI. This patch series is submitted as a follow-up RFC to the first EGM RFC series [0], to gather feedback from the libvirt community on the overall approach and implementation details. While kernel EGM driver support and QEMU acpi-egm-memory device support are not yet upstream, reference implementations are available [1][2] to enable testing and validation of the libvirt integration. Any community feedback is appreciated. Background and Use Cases ========================= EGM allows host memory to be partitioned into two regions: 1. Standard memory for Host OS usage 2. EGM region assigned to VMs as their system memory This technology enables various high-performance computing scenarios [3]: - Large memory pools for AI/ML workloads - High-performance computing applications - Memory extension for systems with limited main memory - GPU-accelerated workloads requiring large addressable memory Implementation Overview ======================= This series adds a new memory device model VIR_DOMAIN_MEMORY_MODEL_EGM with 'path' source attribute and 'pciDev' target attribute to denote host EGM device backing path and PCI device alias to associate the vEGM with, respectively. For instance, given the XML stanzas below: <memory model='egm' access='shared'> <source> <path>/dev/egm4</path> </source> <target> <size unit='KiB'>8388608</size> <node>0</node> <pciDev>ua-hostdev0</pciDev> </target> </memory> <memory model='egm' access='shared'> <source> <path>/dev/egm5</path> </source> <target> <size unit='KiB'>8388608</size> <node>1</node> <pciDev>ua-hostdev1</pciDev> </target> </memory> The corresponding qemu command line will include the following arguments: -object '{"qom-type":"memory-backend-file","id":"memegm4","mem-path":"/dev/egm4","share":true,"prealloc":true,"size":8589934592}' \ -object acpi-egm-memory,id=egm4,pci-dev=ua-hostdev0,node=0 \ -object '{"qom-type":"memory-backend-file","id":"memegm5","mem-path":"/dev/egm5","share":true,"prealloc":true,"size":8589934592}' \ -object acpi-egm-memory,id=egm5,pci-dev=ua-hostdev1,node=1 \ -numa node,nodeid=0,cpus=0-1,memdev=memegm4 \ -numa node,nodeid=1,cpus=2-3,memdev=memegm5 \ Changes from RFCv1: - Use existing memory device infrastructure to represent EGM configuration - Added support for multiple EGM devices This series is on Github: https://github.com/NathanChenNVIDIA/libvirt/tree/egm-11-06-25 Thanks, Nathan [0] https://lists.libvirt.org/archives/list/devel@lists.libvirt.org/thread/4ZFLQ... [1] https://github.com/ianm-nv/qemu/tree/6.8_ghvirt_egm_may2025 [2] https://github.com/NVIDIA/QEMU/commit/32db1b74fb99c0571724c7e69485e89098c148... [3] https://developer.nvidia.com/blog/nvidia-grace-hopper-superchip-architecture... Ian May (1): tests: Add qemuxmlconftest for ACPI EGM memory device Nathan Chen (3): conf: Support EGM memory device model qemu: Add cgroup, namespace, and seclabel setup for EGM memory device model qemu: Add qemu CLI support for EGM docs/formatdomain.rst | 18 ++++- src/conf/domain_conf.c | 33 ++++++++- src/conf/domain_conf.h | 7 ++ src/conf/domain_postparse.c | 6 +- src/conf/domain_validate.c | 15 +++++ src/conf/schemas/domaincommon.rng | 6 ++ src/qemu/qemu_alias.c | 17 +++++ src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_cgroup.c | 10 +++ src/qemu/qemu_command.c | 66 +++++++++++++++++- src/qemu/qemu_domain.c | 15 ++++- src/qemu/qemu_domain_address.c | 6 ++ src/qemu/qemu_driver.c | 1 + src/qemu/qemu_hotplug.c | 1 + src/qemu/qemu_monitor_json.c | 1 + src/qemu/qemu_namespace.c | 3 + src/qemu/qemu_postparse.c | 1 + src/qemu/qemu_process.c | 2 + src/qemu/qemu_validate.c | 6 ++ src/security/security_apparmor.c | 2 + src/security/security_dac.c | 8 +++ src/security/security_selinux.c | 6 ++ src/security/virt-aa-helper.c | 4 ++ src/util/virfile.h | 2 +- tests/meson.build | 1 + tests/qemuegmmock.c | 67 +++++++++++++++++++ .../acpi-egm-memory.aarch64-latest.args | 36 ++++++++++ .../acpi-egm-memory.aarch64-latest.xml | 57 ++++++++++++++++ tests/qemuxmlconfdata/acpi-egm-memory.xml | 33 +++++++++ tests/qemuxmlconftest.c | 8 ++- 31 files changed, 433 insertions(+), 8 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 -- 2.43.0
Add support for EGM memory device model with 'path' source attribute and 'pciDev' target attribute to denote host EGM device backing path and PCI device alias to associate the vEGM with, respectively. Signed-off-by: Nathan Chen <nathanc@nvidia.com> --- docs/formatdomain.rst | 18 +++++++++++++++++- src/conf/domain_conf.c | 28 ++++++++++++++++++++++++++++ src/conf/domain_conf.h | 7 +++++++ src/conf/domain_postparse.c | 1 + src/conf/domain_validate.c | 15 +++++++++++++++ src/conf/schemas/domaincommon.rng | 6 ++++++ 6 files changed, 74 insertions(+), 1 deletion(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 39bdecf9a1..06e3580f37 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -9000,6 +9000,16 @@ Example: usage of the memory devices <size unit='KiB'>16384</size> </target> </memory> + <memory model='egm' access='shared'> + <source> + <path>/dev/egm0</path> + </source> + <target> + <size unit='KiB'>524288</size> + <node>0</node> + <pciDev>ua-hostdev0</pciDev> + </target> + </memory> </devices> ... @@ -9011,7 +9021,8 @@ Example: usage of the memory devices persistent memory device. :since:`Since 7.1.0` Provide ``virtio-mem`` model to add paravirtualized memory device. :since:`Since 7.9.0` Provide ``sgx-epc`` model to add a SGX enclave page cache (EPC) memory to the guest. - :since:`Since 8.10.0 and QEMU 7.0.0` + :since:`Since 8.10.0 and QEMU 7.0.0` Provide ``egm`` model to add a EGM + (Extended GPU Memory) device. ``access`` An optional attribute ``access`` ( :since:`since 3.2.0` ) that provides @@ -9146,6 +9157,11 @@ Example: usage of the memory devices The physical address in memory, where device is mapped. :since:`Since 9.4.0` + ``pciDev`` + For ``egm`` only. + The PCI device that is enabled to access the system memory via + association with the EGM device. + IOMMU devices ~~~~~~~~~~~~~ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 4737594487..ac97b44b9e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1522,6 +1522,7 @@ VIR_ENUM_IMPL(virDomainMemoryModel, "virtio-pmem", "virtio-mem", "sgx-epc", + "egm", ); VIR_ENUM_IMPL(virDomainShmemModel, @@ -3608,6 +3609,9 @@ void virDomainMemoryDefFree(virDomainMemoryDef *def) case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: virBitmapFree(def->source.sgx_epc.nodes); break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + g_free(def->source.egm.path); + g_free(def->target.egm.pciDev); case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -14048,6 +14052,10 @@ virDomainMemorySourceDefParseXML(xmlNodePtr node, } break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + def->source.egm.path = virXPathString("string(./path)", ctxt); + break; + case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -14124,6 +14132,10 @@ virDomainMemoryTargetDefParseXML(xmlNodePtr node, addr = &def->target.virtio_pmem.address; break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + def->target.egm.pciDev = virXPathString("string(./pciDev)", ctxt); + break; + case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: @@ -16183,6 +16195,12 @@ virDomainMemoryFindByDefInternal(virDomainDef *def, continue; break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + if (STRNEQ(tmp->source.egm.path, mem->source.egm.path)) + continue; + if (STRNEQ(tmp->target.egm.pciDev, mem->target.egm.pciDev)) + continue; + case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -22047,6 +22065,7 @@ virDomainMemoryDefCheckABIStability(virDomainMemoryDef *src, case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -26525,6 +26544,10 @@ virDomainMemorySourceDefFormat(virBuffer *buf, } break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + virBufferEscapeString(&childBuf, "<path>%s</path>\n", def->source.egm.path); + break; + case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -26589,6 +26612,11 @@ virDomainMemoryTargetDefFormat(virBuffer *buf, } break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + if (def->target.egm.pciDev) + virBufferAsprintf(&childBuf, "<pciDev>%s</pciDev>\n", def->target.egm.pciDev); + break; + case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_NONE: diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index a63d922853..461c855c0b 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2741,6 +2741,7 @@ typedef enum { VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM, /* virtio-pmem memory device */ VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM, /* virtio-mem memory device */ VIR_DOMAIN_MEMORY_MODEL_SGX_EPC, /* SGX enclave page cache */ + VIR_DOMAIN_MEMORY_MODEL_EGM, /* Extended GPU memory */ VIR_DOMAIN_MEMORY_MODEL_LAST } virDomainMemoryModel; @@ -2773,6 +2774,9 @@ struct _virDomainMemoryDef { struct { virBitmap *nodes; /* source NUMA nodes */ } sgx_epc; + struct { + char *path; + } egm; } source; union { @@ -2798,6 +2802,9 @@ struct _virDomainMemoryDef { } virtio_mem; struct { } sgx_epc; + struct { + char *pciDev; + } egm; } target; virDomainDeviceInfo info; diff --git a/src/conf/domain_postparse.c b/src/conf/domain_postparse.c index 38e731348d..0181d21f0e 100644 --- a/src/conf/domain_postparse.c +++ b/src/conf/domain_postparse.c @@ -632,6 +632,7 @@ virDomainMemoryDefPostParse(virDomainMemoryDef *mem, case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_DIMM: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index 93a2bc9b01..8986d8f390 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -2482,6 +2482,7 @@ virDomainMemoryDefCheckConflict(const virDomainMemoryDef *mem, } break; case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -2528,6 +2529,7 @@ virDomainMemoryDefCheckConflict(const virDomainMemoryDef *mem, switch (other->model) { case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_LAST: continue; break; @@ -2708,6 +2710,19 @@ virDomainMemoryDefValidate(const virDomainMemoryDef *mem, } break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + if (!mem->source.egm.path) { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("path is required for model 'egm'")); + return -1; + } + if (!mem->target.egm.pciDev) { + virReportError(VIR_ERR_XML_DETAIL, "%s", + _("pciDev is required for model 'egm'")); + return -1; + } + break; + case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: default: diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index ace74fee08..b2429cf5b4 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -7481,6 +7481,7 @@ <value>virtio-pmem</value> <value>virtio-mem</value> <value>sgx-epc</value> + <value>egm</value> </choice> </attribute> <optional> @@ -7607,6 +7608,11 @@ </attribute> </element> </optional> + <optional> + <element name="pciDev"> + <data type="string"/> + </element> + </optional> </interleave> </element> </define> -- 2.43.0
Implement proper isolation and access control for EGM memory devices: - Add device to cgroup for access control - Set up namespace mappings for device access - Ensure proper permissions in containerized environments - Allow EGM device path access to bypass SELinux, AppArmor, and DAC permissions Signed-off-by: Nathan Chen <nathanc@nvidia.com> --- src/qemu/qemu_cgroup.c | 10 ++++++++++ src/qemu/qemu_namespace.c | 3 +++ src/security/security_apparmor.c | 2 ++ src/security/security_dac.c | 8 ++++++++ src/security/security_selinux.c | 6 ++++++ src/security/virt-aa-helper.c | 4 ++++ 6 files changed, 33 insertions(+) diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index f10976c2b0..1526af8a87 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -578,6 +578,11 @@ qemuSetupMemoryDevicesCgroup(virDomainObj *vm, VIR_CGROUP_DEVICE_RW, false) < 0) return -1; break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + if (qemuCgroupAllowDevicePath(vm, mem->source.egm.path, + VIR_CGROUP_DEVICE_RW, false) < 0) + return -1; + break; case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: @@ -616,6 +621,11 @@ qemuTeardownMemoryDevicesCgroup(virDomainObj *vm, VIR_CGROUP_DEVICE_RW, false) < 0) return -1; break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + if (qemuCgroupDenyDevicePath(vm, mem->source.egm.path, + VIR_CGROUP_DEVICE_RWM, false) < 0) + return -1; + break; case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c index f72da83929..ef193a8399 100644 --- a/src/qemu/qemu_namespace.c +++ b/src/qemu/qemu_namespace.c @@ -386,6 +386,9 @@ qemuDomainSetupMemory(virDomainMemoryDef *mem, *paths = g_slist_prepend(*paths, g_strdup(QEMU_DEV_SGX_VEPVC)); *paths = g_slist_prepend(*paths, g_strdup(QEMU_DEV_SGX_PROVISION)); break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + *paths = g_slist_prepend(*paths, g_strdup(mem->source.egm.path)); + break; case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_DIMM: diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index 68ac39611f..ea04e756d6 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -631,6 +631,8 @@ AppArmorSetMemoryLabel(virSecurityManager *mgr, case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: + path = mem->source.egm.path; case VIR_DOMAIN_MEMORY_MODEL_LAST: break; } diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 2f788b872a..2d79009ee9 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -1890,6 +1890,9 @@ virSecurityDACRestoreMemoryLabel(virSecurityManager *mgr, * don't need to restore anything. */ break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + return virSecurityDACRestoreFileLabel(mgr, mem->source.egm.path); + case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: case VIR_DOMAIN_MEMORY_MODEL_LAST: @@ -2121,6 +2124,11 @@ virSecurityDACSetMemoryLabel(virSecurityManager *mgr, return -1; break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + return virSecurityDACSetOwnership(mgr, NULL, + mem->source.egm.path, + user, group, true); + case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: case VIR_DOMAIN_MEMORY_MODEL_LAST: diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index fa5d1568eb..33b8f65767 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -1650,6 +1650,9 @@ virSecuritySELinuxSetMemoryLabel(virSecurityManager *mgr, seclabel->imagelabel, true) < 0) return -1; break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + path = mem->source.egm.path; + break; case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_DIMM: @@ -1693,6 +1696,9 @@ virSecuritySELinuxRestoreMemoryLabel(virSecurityManager *mgr, if (virSecuritySELinuxRestoreFileLabel(mgr, DEV_SGX_PROVISION, true) < 0) ret = -1; return ret; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + path = mem->source.egm.path; + break; case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 8a297d4b54..b7f3fa2c5b 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -1194,6 +1194,10 @@ get_files(vahControl * ctl) return -1; } break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + if (vah_add_file(&buf, mem->source.egm.path, "rw") != 0) + return -1; + break; case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: -- 2.43.0
Add qemu CLI support for EGM memory device model: - Specify EGM device path to memory-backend-file object - Support acpi-egm-memory object with id, pci-dev, and node attributes Signed-off-by: Ian May <ianm@nvidia.com> Signed-off-by: Nathan Chen <nathanc@nvidia.com> --- src/qemu/qemu_alias.c | 17 +++++++++ src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 66 ++++++++++++++++++++++++++++++++-- src/qemu/qemu_domain.c | 13 ++++++- src/qemu/qemu_domain_address.c | 6 ++++ src/qemu/qemu_driver.c | 1 + src/qemu/qemu_hotplug.c | 1 + src/qemu/qemu_monitor_json.c | 1 + src/qemu/qemu_postparse.c | 1 + src/qemu/qemu_process.c | 2 ++ src/qemu/qemu_validate.c | 6 ++++ 12 files changed, 114 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c index b0bc057bd1..0e87968bf6 100644 --- a/src/qemu/qemu_alias.c +++ b/src/qemu/qemu_alias.c @@ -553,6 +553,23 @@ qemuAssignDeviceMemoryAlias(virDomainDef *def, case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: prefix = "epc"; break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: { + const char *egm_devname = NULL; + + if (mem->source.egm.path) { + egm_devname = strrchr(mem->source.egm.path, '/'); + if (egm_devname) + egm_devname++; + else + egm_devname = mem->source.egm.path; + + mem->info.alias = g_strdup(egm_devname); + return 0; + } + + prefix = "egm"; + break; + } case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: default: diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 83946123be..1344519074 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -746,6 +746,7 @@ VIR_ENUM_IMPL(virQEMUCaps, /* 485 */ "acpi-generic-initiator", /* QEMU_CAPS_ACPI_GENERIC_INITIATOR */ + "acpi-egm-memory", /* QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY */ ); @@ -1440,6 +1441,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "tpm-emulator", QEMU_CAPS_DEVICE_TPM_EMULATOR }, { "tpm-passthrough", QEMU_CAPS_DEVICE_TPM_PASSTHROUGH }, { "acpi-generic-initiator", QEMU_CAPS_ACPI_GENERIC_INITIATOR }, + { "acpi-egm-memory", QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY }, }; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 2b454e0352..61ffd7a8a8 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -727,6 +727,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ /* 485 */ QEMU_CAPS_ACPI_GENERIC_INITIATOR, /* -object acpi-generic-initiator */ + QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY, /* For using extended GPU memory */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index fcf5fc1935..d4e2fc8d7a 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -990,6 +990,7 @@ qemuBuildVirtioDevGetConfigDev(const virDomainDeviceDef *device, case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -3144,6 +3145,7 @@ qemuBuildMemoryGetPagesize(virQEMUDriverConfig *cfg, nvdimmPath = mem->source.virtio_pmem.path; break; case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -3344,6 +3346,9 @@ qemuBuildMemoryBackendProps(virJSONValue **backendProps, case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: nvdimmPath = mem->source.virtio_pmem.path; break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + nvdimmPath = mem->source.egm.path; + break; case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -3559,6 +3564,7 @@ qemuBuildMemoryDimmBackendStr(virCommand *cmd, { g_autoptr(virJSONValue) props = NULL; g_autoptr(virJSONValue) tcProps = NULL; + g_autoptr(virJSONValue) egmProps = NULL; virBitmap *nodemask = NULL; g_autofree char *alias = NULL; @@ -3584,6 +3590,33 @@ qemuBuildMemoryDimmBackendStr(virCommand *cmd, if (qemuBuildObjectCommandlineFromJSON(cmd, props) < 0) return -1; + if (mem->model == VIR_DOMAIN_MEMORY_MODEL_EGM) { + g_autofree char *egmId = NULL; + g_autofree char *egmObjStr = NULL; + g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; + const char *basename = NULL; + + /* Extract basename from host path under /dev/ */ + basename = strrchr(mem->source.egm.path, '/'); + if (basename && *(basename + 1)) { + egmId = g_strdup(basename + 1); + } else { + egmId = g_strdup(mem->source.egm.path); + } + + virBufferAsprintf(&buf, "acpi-egm-memory,id=%s", egmId); + + if (mem->target.egm.pciDev) + virBufferAsprintf(&buf, ",pci-dev=%s", mem->target.egm.pciDev); + + if (mem->targetNode >= 0) + virBufferAsprintf(&buf, ",node=%d", mem->targetNode); + + egmObjStr = virBufferContentAndReset(&buf); + + virCommandAddArgList(cmd, "-object", egmObjStr, NULL); + } + return 0; } @@ -3653,6 +3686,7 @@ qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg, dynamicMemslots = mem->target.virtio_mem.dynamicMemslots; break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: @@ -7053,6 +7087,7 @@ qemuAppendDomainMemoryMachineParams(virBuffer *buf, case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -7781,6 +7816,13 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg, hmat = true; } + for (i = 0; i < def->nmems; i++) { + if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM) { + if (qemuBuildMemoryDimmBackendStr(cmd, def->mems[i], def, cfg, priv) < 0) + goto cleanup; + } + } + nodeBackends = g_new0(virJSONValue *, ncells); nodemask = g_new0(virBitmap *, ncells); @@ -7816,8 +7858,18 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg, for (i = 0; i < ncells; i++) { ssize_t initiator = virDomainNumaGetNodeInitiator(def->numa, i); unsigned long long memSize = virDomainNumaGetNodeMemorySize(def->numa, i); + bool egmBacked = false; + size_t k; + + for (k = 0; k < def->nmems; k++) { + if (def->mems[k]->model == VIR_DOMAIN_MEMORY_MODEL_EGM && + def->mems[k]->targetNode == (int)i) { + egmBacked = true; + break; + } + } - if (needBackend && memSize > 0) { + if (needBackend && memSize > 0 && !egmBacked) { g_autoptr(virJSONValue) tcProps = NULL; if (qemuBuildThreadContextProps(&tcProps, &nodeBackends[i], @@ -7847,7 +7899,11 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg, if (memSize > 0) { if (needBackend) { - virBufferAsprintf(&buf, ",memdev=ram-node%zu", i); + if (egmBacked) { + virBufferAsprintf(&buf, ",memdev=mem%s", def->mems[k]->info.alias); + } else { + virBufferAsprintf(&buf, ",memdev=ram-node%zu", i); + } } else { virBufferAsprintf(&buf, ",mem=%llu", memSize / 1024); } @@ -7911,6 +7967,9 @@ qemuBuildMemoryDeviceCommandLine(virCommand *cmd, for (i = 0; i < def->nmems; i++) { g_autoptr(virJSONValue) props = NULL; + if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM) + continue; + if (qemuBuildMemoryDimmBackendStr(cmd, def->mems[i], def, cfg, priv) < 0) return -1; @@ -7931,6 +7990,9 @@ qemuBuildMemoryDeviceCommandLine(virCommand *cmd, case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: break; + /* EGM memory backing is via memory-backend-file object */ + case VIR_DOMAIN_MEMORY_MODEL_EGM: + break; case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 375e0e441a..75095b4de8 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -7220,6 +7220,7 @@ qemuDomainUpdateMemoryDeviceInfo(virDomainObj *vm, break; case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -7454,7 +7455,8 @@ qemuDomainAlignMemorySizes(virDomainDef *def) def->mems[i]->size = VIR_ROUND_UP(def->mems[i]->size, align); } - hotplugmem += def->mems[i]->size; + if (def->mems[i]->model != VIR_DOMAIN_MEMORY_MODEL_EGM) + hotplugmem += def->mems[i]->size; if (def->mems[i]->size > maxmemkb) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, @@ -7942,6 +7944,12 @@ qemuDomainDefValidateMemoryHotplugDevice(const virDomainMemoryDef *mem, virDomainMemoryModelTypeToString(mem->model)); return -1; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("hotplug is not supported for the %1$s device"), + virDomainMemoryModelTypeToString(mem->model)); + return -1; + case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: return -1; @@ -8000,6 +8008,7 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef *def, case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_LAST: case VIR_DOMAIN_MEMORY_MODEL_NONE: break; @@ -8047,6 +8056,8 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef *def, case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: /* sgx epc memory does not support hotplug, skip this check */ + case VIR_DOMAIN_MEMORY_MODEL_EGM: + /* egm memory does not support hotplug, skip this check */ case VIR_DOMAIN_MEMORY_MODEL_LAST: case VIR_DOMAIN_MEMORY_MODEL_NONE: break; diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 774541ca06..0d9f2b5649 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -303,6 +303,7 @@ qemuDomainPrimeVirtioDeviceAddresses(virDomainDef *def, case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; } @@ -1033,6 +1034,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDef *dev, case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_LAST: return 0; } @@ -2455,6 +2457,7 @@ qemuDomainAssignDevicePCISlots(virDomainDef *def, case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; } @@ -3151,6 +3154,7 @@ qemuDomainAssignMemoryDeviceSlot(virDomainObj *vm, return qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev); case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -3178,6 +3182,7 @@ qemuDomainReleaseMemoryDeviceSlot(virDomainObj *vm, break; case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; @@ -3212,6 +3217,7 @@ qemuDomainAssignMemorySlots(virDomainDef *def) /* handled in qemuDomainAssignPCIAddresses() */ break; case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b0eff443aa..9d17c159e4 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6704,6 +6704,7 @@ qemuDomainAttachMemoryConfig(virDomainDef *vmdef, case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: break; case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index fb426deb1a..890bb052b6 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -7348,6 +7348,7 @@ qemuDomainChangeMemoryLiveValidateChange(const virDomainMemoryDef *oldDef, case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_LAST: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("cannot modify memory of model '%1$s'"), diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index c121c05ffd..2c2273d927 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -7088,6 +7088,7 @@ qemuMonitorJSONGetMemoryDeviceInfo(qemuMonitor *mon, switch ((virDomainMemoryModel) model) { case VIR_DOMAIN_MEMORY_MODEL_DIMM: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: /* While 'id' attribute is marked as optional in QEMU's QAPI diff --git a/src/qemu/qemu_postparse.c b/src/qemu/qemu_postparse.c index fd27f8be27..b23dd94d2c 100644 --- a/src/qemu/qemu_postparse.c +++ b/src/qemu/qemu_postparse.c @@ -1838,6 +1838,7 @@ qemuDomainDefNumaAutoAdd(virDomainDef *def, case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 9926998f85..e41767a70f 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4066,6 +4066,7 @@ qemuProcessDomainMemoryDefNeedHugepagesPath(const virDomainMemoryDef *mem, case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM: pagesize = mem->source.virtio_mem.pagesize; break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: @@ -4155,6 +4156,7 @@ qemuProcessNeedMemoryBackingPath(virDomainDef *def, case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM: case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC: + case VIR_DOMAIN_MEMORY_MODEL_EGM: case VIR_DOMAIN_MEMORY_MODEL_LAST: /* Backed by user provided path. Not stored in memory * backing dir anyway. */ diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 3e8fdb2268..e8d6fe21cb 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -5812,6 +5812,12 @@ qemuValidateDomainDeviceDefMemory(const virDomainMemoryDef *mem, break; + case VIR_DOMAIN_MEMORY_MODEL_EGM: + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("ACPI EGM memory device is not supported with this QEMU binary")); + return -1; + } case VIR_DOMAIN_MEMORY_MODEL_NONE: case VIR_DOMAIN_MEMORY_MODEL_LAST: break; -- 2.43.0
From: Ian May <ianm@nvidia.com> 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. Filesystem validation is conditionally skipped in test environments while preserving full validation for production use. Signed-off-by: Ian May <ianm@nvidia.com> Signed-off-by: Nathan Chen <nathanc@nvidia.com> --- 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 | 36 ++++++++++ .../acpi-egm-memory.aarch64-latest.xml | 57 ++++++++++++++++ tests/qemuxmlconfdata/acpi-egm-memory.xml | 33 +++++++++ tests/qemuxmlconftest.c | 8 ++- 10 files changed, 212 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 ac97b44b9e..077303fc19 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -8781,8 +8781,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 75095b4de8..72b7fd7047 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -8039,6 +8039,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 0d76d37959..312c05a5f1 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..938b085d56 --- /dev/null +++ b/tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.args @@ -0,0 +1,36 @@ +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 1,sockets=1,dies=1,clusters=1,cores=1,threads=1 \ +-object '{"qom-type":"memory-backend-file","id":"memegm0","mem-path":"/dev/egm0","share":true,"size":536870912}' \ +-object acpi-egm-memory,id=egm0,pci-dev=ua-hostdev0,node=0 \ +-numa node,nodeid=0,cpus=0,memdev=memegm0 \ +-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"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-device '{"driver":"vfio-pci","host":"0000:01:00.0","id":"ua-hostdev0","bus":"pci.1","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..81928b316c --- /dev/null +++ b/tests/qemuxmlconfdata/acpi-egm-memory.aarch64-latest.xml @@ -0,0 +1,57 @@ +<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'>1</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='1' dies='1' clusters='1' cores='1' threads='1'/> + <numa> + <cell id='0' cpus='0' memory='524288' 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> + <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> + <memory model='egm' access='shared'> + <source> + <path>/dev/egm0</path> + </source> + <target> + <size unit='KiB'>524288</size> + <node>0</node> + <pciDev>ua-hostdev0</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..b35368bdcf --- /dev/null +++ b/tests/qemuxmlconfdata/acpi-egm-memory.xml @@ -0,0 +1,33 @@ +<domain type="kvm"> + <name>egm</name> + <maxMemory unit="MiB">512</maxMemory> + <memory unit="MiB">512</memory> + <vcpu>1</vcpu> + <os> + <type arch="aarch64" machine="virt">hvm</type> + </os> + <cpu mode="host-passthrough"> + <topology sockets="1" cores="1" threads="1"/> + <numa> + <cell id="0" cpus="0" memory="512" unit="MiB"/> + </numa> + </cpu> + <devices> + <hostdev mode="subsystem" type="pci" managed="yes"> + <alias name="ua-hostdev0"/> + <source> + <address domain="0x0000" bus="0x01" slot="0x00" function="0x0"/> + </source> + </hostdev> + <memory model='egm' access='shared'> + <source> + <path>/dev/egm0</path> + </source> + <target> + <size unit='KiB'>524288</size> + <node>0</node> + <pciDev>ua-hostdev0</pciDev> + </target> + </memory> + </devices> +</domain> diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c index e4d80faa99..68150aca8d 100644 --- a/tests/qemuxmlconftest.c +++ b/tests/qemuxmlconftest.c @@ -3204,6 +3204,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 */ @@ -3304,7 +3308,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
participants (1)
-
Nathan Chen