diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b74782f42f..6c07ed6086 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -9758,7 +9758,7 @@ virDomainShmemDefParseXML(xmlNodePtr node,
1, ULLONG_MAX, false) < 0)
goto cleanup;
- if ((server = virXPathNode("./server", ctxt))) {
+ if ((server = virXPathNode("./server[1]", ctxt))) {
def->server.enabled = true;
if ((tmp = virXMLPropString(server, "path")))
@@ -9766,7 +9766,7 @@ virDomainShmemDefParseXML(xmlNodePtr node,
VIR_FREE(tmp);
}
- if ((msi = virXPathNode("./msi", ctxt))) {
+ if ((msi = virXPathNode("./msi[1]", ctxt))) {
def->msi.enabled = true;
if ((tmp = virXMLPropString(msi, "vectors")) &&
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index cd3444574f..6c22630bb3 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1029,6 +1029,10 @@ qemuAssignDeviceAliases(virDomainDefPtr def, virQEMUCapsPtr qemuCaps)
if (virAsprintf(&def->hubs[i]->info.alias, "hub%zu", i) < 0)
return -1;
}
+ for (i = 0; i < def->nshmems; i++) {
+ if (virAsprintf(&def->shmems[i]->info.alias, "shmem%zu", i) < 0)
+ return -1;
+ }
for (i = 0; i < def->nsmartcards; i++) {
if (virAsprintf(&def->smartcards[i]->info.alias, "smartcard%zu", i) < 0)
return -1;
@@ -7525,6 +7529,114 @@ qemuBuildInterfaceCommandLine(virCommandPtr cmd,
return ret;
}
+static int
+qemuBuildShmemDevCmd(virCommandPtr cmd,
+ virDomainDefPtr def,
+ virDomainShmemDefPtr shmem,
+ virQEMUCapsPtr qemuCaps)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("ivshmem device is not supported "
+ "with this QEMU binary"));
+ goto error;
+ }
+
+ virBufferAddLit(&buf, "ivshmem");
+ if (shmem->size) {
+ /*
+ * Thanks to our parsing code, we have a guarantee that the
+ * size is power of two and is at least a mebibyte in size.
+ * But because it may change inthe future, the checks are
+ * doubled in here.
+ */
+ if (shmem->size & (shmem->size - 1)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("shmem size must be a power of two"));
+ goto error;
+ }
+ if (shmem->size < 1024 * 1024) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("shmem size must be at least 1 MiB"));
+ goto error;
+ }
+ virBufferAsprintf(&buf, ",size=%llum",
+ VIR_DIV_UP(shmem->size, 1024 * 1024));
+ }
+
+ if (!shmem->server.enabled) {
+ virBufferAsprintf(&buf, ",shm=%s", shmem->name);
+ } else {
+ virBufferAsprintf(&buf, ",chardev=char%s", shmem->info.alias);
+ if (shmem->msi.enabled) {
+ virBufferAddLit(&buf, ",msi=on");
+ if (shmem->msi.vectors)
+ virBufferAsprintf(&buf, ",vectors=%u", shmem->msi.vectors);
+ if (shmem->msi.ioeventfd)
+ virBufferAsprintf(&buf, ",ioeventfd=%s",
+ virTristateSwitchTypeToString(shmem->msi.ioeventfd));
+ }
+ }
+
+ if (qemuBuildDeviceAddressStr(&buf, def, &shmem->info, qemuCaps) < 0)
+ goto error;
+
+ if (virBufferCheckError(&buf) < 0)
+ goto error;
+
+ virCommandAddArg(cmd, "-device");
+ virCommandAddArgBuffer(cmd, &buf);
+
+ return 0;
+
+ error:
+ virBufferFreeAndReset(&buf);
+ return -1;
+}
+
+static int
+qemuBuildShmemCommandLine(virCommandPtr cmd,
+ virDomainDefPtr def,
+ virDomainShmemDefPtr shmem,
+ virQEMUCapsPtr qemuCaps)
+{
+ if (qemuBuildShmemDevCmd(cmd, def, shmem, qemuCaps) < 0)
+ return -1;
+
+ if (shmem->server.enabled) {
+ char *devstr = NULL;
+ virDomainChrSourceDef source = {
+ .type = VIR_DOMAIN_CHR_TYPE_UNIX,
+ .data.nix = {
+ .path = shmem->server.path,
+ .listen = false,
+ }
+ };
+
+ if (!shmem->server.path &&
+ virAsprintf(&source.data.nix.path,
+ "/var/lib/libvirt/shmem-%s-sock",
+ shmem->name) < 0)
+ return -1;
+
+ devstr = qemuBuildChrChardevStr(&source, shmem->info.alias, qemuCaps);
+
+ if (!shmem->server.path)
+ VIR_FREE(source.data.nix.path);
+
+ if (!devstr)
+ return -1;
+
+ virCommandAddArg(cmd, "-chardev");
+ virCommandAddArg(cmd, devstr);
+ VIR_FREE(devstr);
+ }
+
+ return 0;
+}
+
static int
qemuBuildChrDeviceCommandLine(virCommandPtr cmd,
virDomainDefPtr def,
@@ -9720,6 +9832,11 @@ qemuBuildCommandLine(virConnectPtr conn,
}
}
+ for (i = 0; i < def->nshmems; i++) {
+ if (qemuBuildShmemCommandLine(cmd, def, def->shmems[i], qemuCaps))
+ goto error;
+ }
+
if (mlock) {
unsigned long long memKB;
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem-invalid-size.xml b/tests/qemuxml2argvdata/qemuxml2argv-shmem-invalid-size.xml
new file mode 100644
index 0000000000..992f8fd2b5
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem-invalid-size.xml
@@ -0,0 +1,24 @@
+
+ QEMUGuest1
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219136
+ 219136
+ 1
+
+ hvm
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu
+
+
+
+
+ 12345
+
+
+
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem-small-size.xml b/tests/qemuxml2argvdata/qemuxml2argv-shmem-small-size.xml
new file mode 100644
index 0000000000..8f99b14207
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem-small-size.xml
@@ -0,0 +1,24 @@
+
+ QEMUGuest1
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219136
+ 219136
+ 1
+
+ hvm
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu
+
+
+
+
+ 16
+
+
+
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem.args b/tests/qemuxml2argvdata/qemuxml2argv-shmem.args
new file mode 100644
index 0000000000..a3d3cc82d8
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem.args
@@ -0,0 +1,16 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \
+/usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -nodefaults \
+-monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb \
+-device ivshmem,shm=shmem0 \
+-device ivshmem,size=128m,shm=shmem1 \
+-device ivshmem,size=256m,shm=shmem2 \
+-device ivshmem,size=512m,chardev=charshmem3 \
+-chardev socket,id=charshmem3,path=/var/lib/libvirt/shmem-shmem3-sock \
+-device ivshmem,size=1024m,chardev=charshmem4 \
+-chardev socket,id=charshmem4,path=/tmp/shmem4-sock \
+-device ivshmem,size=2048m,chardev=charshmem5,msi=on,ioeventfd=off \
+-chardev socket,id=charshmem5,path=/tmp/shmem5-sock \
+-device ivshmem,size=4096m,chardev=charshmem6,msi=on,vectors=16 \
+-chardev socket,id=charshmem6,path=/tmp/shmem6-sock \
+-device ivshmem,size=8192m,chardev=charshmem7,msi=on,vectors=32,ioeventfd=on \
+-chardev socket,id=charshmem7,path=/tmp/shmem7-sock
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 58153db0df..c13aa99028 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1466,6 +1466,11 @@ mymain(void)
DO_TEST("fips-enabled", QEMU_CAPS_ENABLE_FIPS);
+ DO_TEST("shmem", QEMU_CAPS_PCIDEVICE,
+ QEMU_CAPS_DEVICE, QEMU_CAPS_DEVICE_IVSHMEM);
+ DO_TEST_FAILURE("shmem", NONE);
+ DO_TEST_FAILURE("shmem-invalid-size", NONE);
+ DO_TEST_FAILURE("shmem-small-size", NONE);
DO_TEST_PARSE_ERROR("shmem-msi-only", NONE);
virObjectUnref(driver.config);