This patch implements support for the ivshmem device
in QEMU.
Example from this xml:
<shmem name='ivshmem0' model='ivshmem'>
<server path='/tmp/socket-ivshmem0'/>
<size unit='M'>32</size>
<msi vectors='32' ioeventfd='on'/>
</shmem>
The following QEMU line is built:
-device ivshmem,size=32m,vectors=32,chardev=charshmem0,msi=on,
ioeventfd=on,role=master
-chardev socket,path=/tmp/socket-ivshmem0,id=charshmem0
Note: PCI hotpluging is not implemented.
Signed-off-by: Maxime Leroy <maxime.leroy(a)6wind.com>
---
src/qemu/qemu_command.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++-
src/qemu/qemu_command.h | 4 ++
src/qemu/qemu_hotplug.c | 1 +
3 files changed, 109 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 0d7b12d..9fcceae 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1019,6 +1019,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;
@@ -5043,6 +5047,100 @@ qemuBuildRedirdevDevStr(virDomainDefPtr def,
return NULL;
}
+static char *
+qemuBuildIvshmemDevStr(virDomainDefPtr def,
+ virDomainShmemDefPtr dev,
+ virQEMUCapsPtr qemuCaps)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ virDomainIvshmemDefPtr ivshmem = &dev->data.ivshmem;
+
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("ivshmem device is not supported by QEMU"));
+ goto error;
+ }
+
+ virBufferAddLit(&buf, "ivshmem");
+ if (ivshmem->size)
+ virBufferAsprintf(&buf, ",size=%llum", ivshmem->size / (1024 *
1024));
+
+ if (!ivshmem->server.enabled)
+ virBufferAsprintf(&buf, ",shm=%s", dev->name);
+ else {
+ virBufferAsprintf(&buf, ",chardev=char%s", dev->info.alias);
+ if (ivshmem->msi.enabled) {
+ virBufferAddLit(&buf, ",msi=on");
+ if (ivshmem->msi.vectors)
+ virBufferAsprintf(&buf, ",vectors=%u",
ivshmem->msi.vectors);
+ if (ivshmem->msi.ioeventfd)
+ virBufferAsprintf(&buf, ",ioeventfd=%s",
+
virTristateSwitchTypeToString(ivshmem->msi.ioeventfd));
+ }
+ }
+
+ if (qemuBuildDeviceAddressStr(&buf, def, &dev->info, qemuCaps) < 0)
+ goto error;
+
+ if (virBufferCheckError(&buf) < 0)
+ goto error;
+
+ return virBufferContentAndReset(&buf);
+
+ error:
+ virBufferFreeAndReset(&buf);
+ return NULL;
+}
+
+static int
+qemuBuildIvshmemCommandLine(virCommandPtr cmd,
+ virDomainDefPtr def,
+ virDomainShmemDefPtr dev,
+ virQEMUCapsPtr qemuCaps)
+{
+ char *devstr;
+ virDomainIvshmemDefPtr ivshmem = &dev->data.ivshmem;
+
+ virCommandAddArg(cmd, "-device");
+ if (!(devstr = qemuBuildIvshmemDevStr(def, dev, qemuCaps)))
+ return -1;
+ virCommandAddArg(cmd, devstr);
+ VIR_FREE(devstr);
+
+ if (ivshmem->server.enabled) {
+ virDomainChrSourceDef source;
+
+ source.type = VIR_DOMAIN_CHR_TYPE_UNIX;
+ source.data.nix.path = ivshmem->server.path;
+ source.data.nix.listen = false;
+
+ virCommandAddArg(cmd, "-chardev");
+ if (!(devstr = qemuBuildChrChardevStr(&source, dev->info.alias,
+ qemuCaps)))
+ return -1;
+ virCommandAddArg(cmd, devstr);
+ VIR_FREE(devstr);
+ }
+
+ return 0;
+}
+
+static int
+qemuBuildShmemCommandLine(virCommandPtr cmd,
+ virDomainDefPtr def,
+ virDomainShmemDefPtr dev,
+ virQEMUCapsPtr qemuCaps)
+{
+ switch (dev->model) {
+ case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM:
+ return qemuBuildIvshmemCommandLine(cmd, def, dev, qemuCaps);
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unexpected shem model %d"), dev->model);
+ }
+ return -1;
+}
+
char *
qemuBuildUSBHostdevDevStr(virDomainDefPtr def,
virDomainHostdevDefPtr dev,
@@ -5299,7 +5397,7 @@ qemuBuildSCSIHostdevDevStr(virDomainDefPtr def,
/* This function outputs a -chardev command line option which describes only the
* host side of the character device */
-static char *
+char *
qemuBuildChrChardevStr(virDomainChrSourceDefPtr dev, const char *alias,
virQEMUCapsPtr qemuCaps)
{
@@ -9332,6 +9430,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/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 633ff71..3373a59 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -130,6 +130,10 @@ char *qemuBuildDriveDevStr(virDomainDefPtr def,
char *qemuBuildFSDevStr(virDomainDefPtr domainDef,
virDomainFSDefPtr fs,
virQEMUCapsPtr qemuCaps);
+
+char * qemuBuildChrChardevStr(virDomainChrSourceDefPtr dev,
+ const char *alias,
+ virQEMUCapsPtr qemuCaps);
/* Current, best practice */
char *qemuBuildControllerDevStr(virDomainDefPtr domainDef,
virDomainControllerDefPtr def,
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index a364c52..def442b 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -2858,6 +2858,7 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver,
case VIR_DOMAIN_DEVICE_MEMBALLOON:
case VIR_DOMAIN_DEVICE_NVRAM:
case VIR_DOMAIN_DEVICE_RNG:
+ case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_LAST:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("don't know how to remove a %s device"),
--
1.9.3