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 <[email protected]>
Signed-off-by: Nathan Chen <[email protected]>
---
 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 92b863a826..3fc8fee4b3 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -755,6 +755,7 @@ VIR_ENUM_IMPL(virQEMUCaps,
               "disk-timed-stats", /* QEMU_CAPS_DISK_TIMED_STATS */
               "query-accelerators", /* QEMU_CAPS_QUERY_ACCELERATORS */
               "mshv", /* QEMU_CAPS_MSHV */
+              "acpi-egm-memory", /* QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY */
     );
 
 
@@ -1462,6 +1463,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 f180844e66..3eb12235f4 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -730,6 +730,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for 
syntax-check */
     QEMU_CAPS_DISK_TIMED_STATS, /* timed stats support ('stats-intervals' 
property of disk frontends) */
     QEMU_CAPS_QUERY_ACCELERATORS, /* query-accelerators command */
     QEMU_CAPS_MSHV, /* -accel mshv */
+    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 b69fe23236..33848aa781 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;
@@ -3162,6 +3178,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;
@@ -3362,6 +3379,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;
@@ -3573,12 +3593,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",
@@ -3588,19 +3613,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;
 }
@@ -3671,6 +3742,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:
@@ -7104,6 +7176,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;
@@ -7821,6 +7894,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;
@@ -7835,6 +7910,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);
 
@@ -7870,8 +7976,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],
@@ -7901,7 +8017,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);
             }
@@ -7965,7 +8089,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) {
@@ -7985,6 +8112,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 ac56fc7cb4..14f2b3ec5d 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -7219,6 +7219,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;
@@ -7453,7 +7454,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,
@@ -7941,6 +7943,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;
@@ -7999,6 +8007,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;
@@ -8046,6 +8055,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 f2e024dae3..e0ee056b92 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 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 494d7ef515..081f0cedfd 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -7213,6 +7213,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 dc5ade829a..3c2867edb3 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 0e50cd1ccc..d451c12dd0 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4156,6 +4156,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:
@@ -4245,6 +4246,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 da08fd17cd..e026e2fdd0 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -5861,6 +5861,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

Reply via email to