libvirt/libvirt-qemu-Add-qemu-CLI-support-for-EGM.patch
Pavel Hrdina dd91c3be50 libvirt-11.10.0-10.7.el10nv
- conf: Support EGM memory device model (VOYAGER-13)
- qemu: Add cgroup, namespace, and seclabel setup for EGM memory device model (VOYAGER-13)
- qemu: Add qemu CLI support for EGM (VOYAGER-13)
- tests: Add qemuxmlconftest for ACPI EGM memory device (VOYAGER-13)

Resolves: VOYAGER-13
2026-05-18 12:07:41 +02:00

529 lines
21 KiB
Diff

From 9965f1b7b0fb1810fe32498f7892aa549a754d19 Mon Sep 17 00:00:00 2001
Message-ID: <9965f1b7b0fb1810fe32498f7892aa549a754d19.1779098642.git.phrdina@redhat.com>
From: Pavel Hrdina <phrdina@redhat.com>
Date: Tue, 25 Nov 2025 11:17:03 -0800
Subject: [PATCH] qemu: Add qemu CLI support for EGM
From: Nathan Chen via Devel <devel@lists.libvirt.org>
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
- Consolidate all acpi-egm-memory objects' memory into
a single memory-backend-file per EGM chardev
specified.
Signed-off-by: Ian May <ianm@nvidia.com>
Signed-off-by: Nathan Chen <nathanc@nvidia.com>
Resolves: https://redhat.atlassian.net/browse/VOYAGER-13
---
src/qemu/qemu_alias.c | 7 +-
src/qemu/qemu_capabilities.c | 2 +
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 158 ++++++++++++++++++++++++++++++---
src/qemu/qemu_domain.c | 13 ++-
src/qemu/qemu_domain_address.c | 3 +
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, 180 insertions(+), 16 deletions(-)
diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c
index 400ce73283..719224e1ba 100644
--- a/src/qemu/qemu_alias.c
+++ b/src/qemu/qemu_alias.c
@@ -504,7 +504,8 @@ qemuDeviceMemoryGetAliasID(virDomainDef *def,
* valid */
if (mem->model != VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM &&
mem->model != VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM &&
- mem->model != VIR_DOMAIN_MEMORY_MODEL_SGX_EPC)
+ mem->model != VIR_DOMAIN_MEMORY_MODEL_SGX_EPC &&
+ mem->model != VIR_DOMAIN_MEMORY_MODEL_EGM)
return mem->info.addr.dimm.slot;
for (i = 0; i < def->nmems; i++) {
@@ -553,6 +554,10 @@ qemuAssignDeviceMemoryAlias(virDomainDef *def,
case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
prefix = "epc";
break;
+ case VIR_DOMAIN_MEMORY_MODEL_EGM: {
+ 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 ed6aa86da2..010933bc4e 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -760,6 +760,7 @@ VIR_ENUM_IMPL(virQEMUCaps,
/* 490 */
"iommufd", /* QEMU_CAPS_OBJECT_IOMMUFD */
+ "acpi-egm-memory", /* QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY */
);
@@ -1468,6 +1469,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = {
{ "tpm-passthrough", QEMU_CAPS_DEVICE_TPM_PASSTHROUGH },
{ "acpi-generic-initiator", QEMU_CAPS_ACPI_GENERIC_INITIATOR },
{ "iommufd", QEMU_CAPS_OBJECT_IOMMUFD },
+ { "acpi-egm-memory", QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY },
};
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index f7c8680f94..85615b4524 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -734,6 +734,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */
/* 490 */
QEMU_CAPS_OBJECT_IOMMUFD, /* -object iommufd */
+ 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 a76f504e6f..63fd9885b7 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -135,6 +135,21 @@ VIR_ENUM_IMPL(qemuACPITableSIG,
"SLIC",
"MSDM");
+typedef struct _qemuEGMBackendInfo {
+ char *alias;
+ unsigned long long totalSize;
+ bool created;
+ virDomainMemoryDef *firstMem; /* Pointer to first device for this path */
+} qemuEGMBackendInfo;
+
+static void
+qemuEGMBackendInfoFree(qemuEGMBackendInfo *info)
+{
+ if (!info)
+ return;
+ g_free(info->alias);
+ g_free(info);
+}
const char *
qemuAudioDriverTypeToString(virDomainAudioType type)
@@ -992,6 +1007,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;
@@ -3166,6 +3182,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;
@@ -3366,6 +3383,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;
@@ -3577,12 +3597,17 @@ qemuBuildMemoryDimmBackendStr(virCommand *cmd,
virDomainMemoryDef *mem,
virDomainDef *def,
virQEMUDriverConfig *cfg,
- qemuDomainObjPrivate *priv)
+ qemuDomainObjPrivate *priv,
+ GHashTable *egmBackends)
{
g_autoptr(virJSONValue) props = NULL;
g_autoptr(virJSONValue) tcProps = NULL;
virBitmap *nodemask = NULL;
g_autofree char *alias = NULL;
+ unsigned long long originalSize = 0;
+ bool isEGM = (mem->model == VIR_DOMAIN_MEMORY_MODEL_EGM);
+ bool shouldCreateBackend = true;
+ qemuEGMBackendInfo *egmInfo = NULL;
if (!mem->info.alias) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -3592,19 +3617,65 @@ qemuBuildMemoryDimmBackendStr(virCommand *cmd,
alias = g_strdup_printf("mem%s", mem->info.alias);
- if (qemuBuildMemoryBackendProps(&props, alias, cfg, priv,
- def, mem, true, false, &nodemask) < 0)
- return -1;
+ /* Handle EGM shared backend logic */
+ if (isEGM && egmBackends) {
+ const char *egmPath = mem->source.egm.path;
+ egmInfo = g_hash_table_lookup(egmBackends, egmPath);
- if (qemuBuildThreadContextProps(&tcProps, &props, def, priv, nodemask) < 0)
- return -1;
+ if (egmInfo) {
+ alias = g_strdup(egmInfo->alias);
+ if (egmInfo->created) {
+ /* Backend already created, skip backend creation */
+ shouldCreateBackend = false;
+ } else {
+ /* First device for this path - temporarily use accumulated size */
+ originalSize = mem->size;
+ mem->size = egmInfo->totalSize;
+ egmInfo->created = true;
+ }
+ }
+ }
- if (tcProps &&
- qemuBuildObjectCommandlineFromJSON(cmd, tcProps) < 0)
- return -1;
+ if (shouldCreateBackend) {
+ /* Use existing function unchanged */
+ if (qemuBuildMemoryBackendProps(&props, alias, cfg, priv,
+ def, mem, true, false, &nodemask) < 0) {
+ if (originalSize > 0)
+ mem->size = originalSize; /* Restore on error */
+ return -1;
+ }
- if (qemuBuildObjectCommandlineFromJSON(cmd, props) < 0)
- return -1;
+ /* Restore original size after backend props are built */
+ if (originalSize > 0)
+ mem->size = originalSize;
+
+ if (qemuBuildThreadContextProps(&tcProps, &props, def, priv, nodemask) < 0)
+ return -1;
+
+ if (tcProps &&
+ qemuBuildObjectCommandlineFromJSON(cmd, tcProps) < 0)
+ return -1;
+
+ if (qemuBuildObjectCommandlineFromJSON(cmd, props) < 0)
+ return -1;
+ }
+
+ if (isEGM) {
+ g_autofree char *egmObjStr = NULL;
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, "acpi-egm-memory,id=%s", mem->info.alias);
+
+ 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;
}
@@ -3675,6 +3746,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:
@@ -7193,6 +7265,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;
@@ -7910,6 +7983,8 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg,
size_t ncells = virDomainNumaGetNodeCount(def->numa);
ssize_t masterInitiator = -1;
int rc;
+ g_autoptr(GHashTable) egmBackends = NULL;
+ size_t egmBackendCount = 0;
if (!virDomainNumatuneNodesetIsAvailable(def->numa, priv->autoNodeset))
goto cleanup;
@@ -7924,6 +7999,37 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg,
hmat = true;
}
+ /* Pre-scan EGM devices to group by path and calculate total sizes */
+ egmBackends = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify)qemuEGMBackendInfoFree);
+
+ for (i = 0; i < def->nmems; i++) {
+ if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM) {
+ const char *egmPath = def->mems[i]->source.egm.path;
+ qemuEGMBackendInfo *info = g_hash_table_lookup(egmBackends, egmPath);
+
+ if (!info) {
+ info = g_new0(qemuEGMBackendInfo, 1);
+ info->alias = g_strdup_printf("memegm%zu", egmBackendCount);
+ egmBackendCount++;
+ info->totalSize = def->mems[i]->size;
+ info->created = false;
+ info->firstMem = def->mems[i];
+ g_hash_table_insert(egmBackends, g_strdup(egmPath), info);
+ } else {
+ info->totalSize += def->mems[i]->size;
+ }
+ }
+ }
+
+ /* Build the actual backend and device objects */
+ 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, egmBackends) < 0)
+ goto cleanup;
+ }
+ }
+
nodeBackends = g_new0(virJSONValue *, ncells);
nodemask = g_new0(virBitmap *, ncells);
@@ -7959,8 +8065,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;
- if (needBackend && memSize > 0) {
+ 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 && !egmBacked) {
g_autoptr(virJSONValue) tcProps = NULL;
if (qemuBuildThreadContextProps(&tcProps, &nodeBackends[i],
@@ -7990,7 +8106,15 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg,
if (memSize > 0) {
if (needBackend) {
- virBufferAsprintf(&buf, ",memdev=ram-node%zu", i);
+ if (egmBacked) {
+ /* Look up the actual backend alias for EGM */
+ const char *egmPath = def->mems[k]->source.egm.path;
+ qemuEGMBackendInfo *egmInfo = g_hash_table_lookup(egmBackends, egmPath);
+ const char *backendAlias = egmInfo ? egmInfo->alias : def->mems[k]->info.alias;
+ virBufferAsprintf(&buf, ",memdev=%s", backendAlias);
+ } else {
+ virBufferAsprintf(&buf, ",memdev=ram-node%zu", i);
+ }
} else {
virBufferAsprintf(&buf, ",mem=%llu", memSize / 1024);
}
@@ -8054,7 +8178,10 @@ qemuBuildMemoryDeviceCommandLine(virCommand *cmd,
for (i = 0; i < def->nmems; i++) {
g_autoptr(virJSONValue) props = NULL;
- if (qemuBuildMemoryDimmBackendStr(cmd, def->mems[i], def, cfg, priv) < 0)
+ if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM)
+ continue;
+
+ if (qemuBuildMemoryDimmBackendStr(cmd, def->mems[i], def, cfg, priv, NULL) < 0)
return -1;
switch (def->mems[i]->model) {
@@ -8074,6 +8201,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 495cbd4f7d..c5e3d09360 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -7266,6 +7266,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;
@@ -7500,7 +7501,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,
@@ -7988,6 +7990,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;
@@ -8046,6 +8054,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;
@@ -8093,6 +8102,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 7233df888c..97e533bf9a 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -3124,6 +3124,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;
@@ -3151,6 +3152,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;
@@ -3185,6 +3187,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 5e63614b4a..247c98d84e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6712,6 +6712,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 8944062aa4..de47702bc5 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -7417,6 +7417,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 45f690d9e2..2bf9bb885e 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -7285,6 +7285,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 840d6a1174..c74824322a 100644
--- a/src/qemu/qemu_postparse.c
+++ b/src/qemu/qemu_postparse.c
@@ -1839,6 +1839,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 10a4a70f1c..8132f13791 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4158,6 +4158,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:
@@ -4247,6 +4248,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 c39d8c869f..e03da3e27e 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -5892,6 +5892,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.54.0