diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index e7b585cfed..8e50b8caac 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -5582,6 +5582,58 @@ qemu-kvm -net nic,model=? /dev/null
     </dd>
   </dl>
 
+  <h4><a name="elementsShmem">Shared memory device</a></h4>
+
+    <p>
+      A shared memory device allows to share a memory region between
+      different virtual machines and the host.
+      <span class="since">Since 1.2.9, QEMU and KVM only</span>
+    </p>
+
+<pre>
+  ...
+  &lt;devices&gt;
+    &lt;shmem name='my_shmem0'&gt;
+      &lt;size unit='M'&gt;4&lt;/size&gt;
+    &lt;/shmem&gt;
+    &lt;shmem name='shmem_server'&gt;
+      &lt;size unit='M'&gt;2&lt;/size&gt;
+      &lt;server path='/tmp/socket-shmem'/&gt;
+      &lt;msi vectors='32' ioeventfd='on'/&gt;
+    &lt;/shmem&gt;
+  &lt;/devices&gt;
+  ...
+</pre>
+
+  <dl>
+    <dt><code>shmem</code></dt>
+    <dd>
+      The <code>shmem</code> element has one mandatory attribute,
+      <code>name</code> to identify the shared memory.
+    </dd>
+    <dt><code>size</code></dt>
+    <dd>
+      The optional <code>size</code> element specifies the size of the shared
+      memory. This must be power of 2 and greater than or equal to 1 MiB.
+    </dd>
+    <dt><code>server</code></dt>
+    <dd>
+      The optional <code>server</code> element can be used to configure a server
+      socket the device is supposed to connect to.  The optional
+      <code>path</code> attribute specifies the path to the unix socket and
+      defaults to <code>/var/lib/libvirt/shmem/$shmem-$name-sock</code>.
+    </dd>
+    <dt><code>msi</code></dt>
+    <dd>
+      The optional <code>msi</code> element enables/disables (values "on"/"off",
+      respectively) MSI interrupts. This option can currently be used only
+      together with the <code>server</code> element. The <code>vectors</code>
+      attribute can be used to specify the number of interrupt
+      vectors. The <code>ioeventd</code> attribute enables/disables (values
+      "on"/"off", respectively) ioeventfd.
+    </dd>
+  </dl>
+
     <h3><a name="seclabel">Security label</a></h3>
 
     <p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 1a266e571c..6b69fd1bac 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3278,6 +3278,44 @@
       </optional>
     </element>
   </define>
+
+  <define name="shmem">
+    <element name="shmem">
+      <attribute name="name"/>
+      <interleave>
+        <optional>
+          <element name="size">
+            <ref name="scaledInteger"/>
+          </element>
+        </optional>
+        <optional>
+          <element name="server">
+            <optional>
+              <attribute name="path">
+                <ref name="absFilePath"/>
+              </attribute>
+            </optional>
+          </element>
+        </optional>
+        <optional>
+          <element name="msi">
+            <optional>
+              <ref name="ioeventfd"/>
+            </optional>
+            <optional>
+              <attribute name="vectors">
+                <ref name="unsignedInt"/>
+              </attribute>
+            </optional>
+          </element>
+        </optional>
+        <optional>
+          <ref name="address"/>
+        </optional>
+      </interleave>
+    </element>
+  </define>
+
   <define name="memballoon">
     <element name="memballoon">
       <attribute name="model">
@@ -3864,6 +3902,7 @@
             <ref name="redirfilter"/>
             <ref name="rng"/>
             <ref name="tpm"/>
+            <ref name="shmem"/>
           </choice>
         </zeroOrMore>
         <optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 6ea25df401..b74782f42f 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -255,7 +255,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
               "chr",
               "memballoon",
               "nvram",
-              "rng")
+              "rng",
+              "shmem")
 
 VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
               "none",
@@ -1720,6 +1721,17 @@ void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def)
     VIR_FREE(def);
 }
 
+void virDomainShmemDefFree(virDomainShmemDefPtr def)
+{
+    if (!def)
+        return;
+
+    virDomainDeviceInfoClear(&def->info);
+    VIR_FREE(def->server.path);
+    VIR_FREE(def->name);
+    VIR_FREE(def);
+}
+
 void virDomainVideoDefFree(virDomainVideoDefPtr def)
 {
     if (!def)
@@ -1921,6 +1933,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
     case VIR_DOMAIN_DEVICE_NVRAM:
         virDomainNVRAMDefFree(def->data.nvram);
         break;
+    case VIR_DOMAIN_DEVICE_SHMEM:
+        virDomainShmemDefFree(def->data.shmem);
+        break;
     case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_NONE:
         break;
@@ -2181,6 +2196,10 @@ void virDomainDefFree(virDomainDefPtr def)
 
     virDomainRedirFilterDefFree(def->redirfilter);
 
+    for (i = 0; i < def->nshmems; i++)
+        virDomainShmemDefFree(def->shmems[i]);
+    VIR_FREE(def->shmems);
+
     if (def->namespaceData && def->ns.free)
         (def->ns.free)(def->namespaceData);
 
@@ -2613,6 +2632,8 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device)
         return &device->data.memballoon->info;
     case VIR_DOMAIN_DEVICE_NVRAM:
         return &device->data.nvram->info;
+    case VIR_DOMAIN_DEVICE_SHMEM:
+        return &device->data.shmem->info;
     case VIR_DOMAIN_DEVICE_RNG:
         return &device->data.rng->info;
 
@@ -2828,6 +2849,12 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
         if (cb(def, &device, &def->hubs[i]->info, opaque) < 0)
             return -1;
     }
+    device.type = VIR_DOMAIN_DEVICE_SHMEM;
+    for (i = 0; i < def->nshmems; i++) {
+        device.data.shmem = def->shmems[i];
+        if (cb(def, &device, &def->shmems[i]->info, opaque) < 0)
+            return -1;
+    }
 
     /* Coverity is not very happy with this - all dead_error_condition */
 #if !STATIC_ANALYSIS
@@ -2856,6 +2883,7 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
     case VIR_DOMAIN_DEVICE_CHR:
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
     case VIR_DOMAIN_DEVICE_NVRAM:
+    case VIR_DOMAIN_DEVICE_SHMEM:
     case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_RNG:
         break;
@@ -9702,6 +9730,84 @@ virDomainNVRAMDefParseXML(xmlNodePtr node,
     return NULL;
 }
 
+static virDomainShmemDefPtr
+virDomainShmemDefParseXML(xmlNodePtr node,
+                          xmlXPathContextPtr ctxt,
+                          unsigned int flags)
+{
+    char *tmp = NULL;
+    virDomainShmemDefPtr def = NULL;
+    virDomainShmemDefPtr ret = NULL;
+    xmlNodePtr msi = NULL;
+    xmlNodePtr save = ctxt->node;
+    xmlNodePtr server = NULL;
+
+
+    if (VIR_ALLOC(def) < 0)
+        return NULL;
+
+    ctxt->node = node;
+
+    if (!(def->name = virXMLPropString(node, "name"))) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("shmem element must contain 'name' attribute"));
+        goto cleanup;
+    }
+
+    if (virDomainParseScaledValue("./size[1]", ctxt, &def->size,
+                                    1, ULLONG_MAX, false) < 0)
+        goto cleanup;
+
+    if ((server = virXPathNode("./server", ctxt))) {
+        def->server.enabled = true;
+
+        if ((tmp = virXMLPropString(server, "path")))
+            def->server.path = virFileSanitizePath(tmp);
+        VIR_FREE(tmp);
+    }
+
+    if ((msi = virXPathNode("./msi", ctxt))) {
+        def->msi.enabled = true;
+
+        if ((tmp = virXMLPropString(msi, "vectors")) &&
+            virStrToLong_uip(tmp, NULL, 0, &def->msi.vectors) < 0) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("invalid number of vectors for shmem: '%s'"),
+                           tmp);
+            goto cleanup;
+        }
+        VIR_FREE(tmp);
+
+        if ((tmp = virXMLPropString(msi, "ioeventfd")) &&
+            (def->msi.ioeventfd = virTristateSwitchTypeFromString(tmp)) <= 0) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("invalid msi ioeventfd setting for shmem: '%s'"),
+                           tmp);
+            goto cleanup;
+        }
+        VIR_FREE(tmp);
+    }
+
+    /* msi option is only relevant with a server */
+    if (def->msi.enabled && !def->server.enabled) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("msi option is only supported with a server"));
+        goto cleanup;
+    }
+
+    if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
+        goto cleanup;
+
+
+    ret = def;
+    def = NULL;
+ cleanup:
+    ctxt->node = save;
+    VIR_FREE(tmp);
+    virDomainShmemDefFree(def);
+    return ret;
+}
+
 static virSysinfoDefPtr
 virSysinfoParseXML(xmlNodePtr node,
                   xmlXPathContextPtr ctxt,
@@ -10558,6 +10664,10 @@ virDomainDeviceDefParse(const char *xmlStr,
         if (!(dev->data.nvram = virDomainNVRAMDefParseXML(node, flags)))
             goto error;
         break;
+    case VIR_DOMAIN_DEVICE_SHMEM:
+        if (!(dev->data.shmem = virDomainShmemDefParseXML(node, ctxt, flags)))
+            goto error;
+        break;
     case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_LAST:
         break;
@@ -13686,6 +13796,25 @@ virDomainDefParseXML(xmlDocPtr xml,
         VIR_FREE(nodes);
     }
 
+    /* analysis of the shmem devices */
+    if ((n = virXPathNodeSet("./devices/shmem", ctxt, &nodes)) < 0) {
+        goto error;
+    }
+    if (n && VIR_ALLOC_N(def->shmems, n) < 0)
+        goto error;
+
+    node = ctxt->node;
+    for (i = 0; i < n; i++) {
+        virDomainShmemDefPtr shmem;
+        ctxt->node = nodes[i];
+        shmem = virDomainShmemDefParseXML(nodes[i], ctxt, flags);
+        if (!shmem)
+            goto error;
+
+        def->shmems[def->nshmems++] = shmem;
+    }
+    ctxt->node = node;
+    VIR_FREE(nodes);
 
     /* analysis of the user namespace mapping */
     if ((n = virXPathNodeSet("./idmap/uid", ctxt, &nodes)) < 0)
@@ -17469,6 +17598,54 @@ static int virDomainPanicDefFormat(virBufferPtr buf,
     return 0;
 }
 
+static int
+virDomainShmemDefFormat(virBufferPtr buf,
+                        virDomainShmemDefPtr def,
+                        unsigned int flags)
+{
+    virBufferAsprintf(buf, "<shmem name='%s'", def->name);
+
+    if (!def->size &&
+        !def->server.enabled &&
+        !def->msi.enabled &&
+        !virDomainDeviceInfoIsSet(&def->info, flags)) {
+        virBufferAddLit(buf, "/>\n");
+        return 0;
+    } else {
+        virBufferAddLit(buf, ">\n");
+    }
+
+    virBufferAdjustIndent(buf, 2);
+
+    if (def->size)
+        virBufferAsprintf(buf, "<size unit='M'>%llu</size>\n",
+                          VIR_DIV_UP(def->size, 1024 * 1024));
+
+    if (def->server.enabled) {
+        virBufferAddLit(buf, "<server");
+        virBufferEscapeString(buf, " path='%s'", def->server.path);
+        virBufferAddLit(buf, "/>\n");
+    }
+
+    if (def->msi.enabled) {
+        virBufferAddLit(buf, "<msi");
+        if (def->msi.vectors)
+            virBufferAsprintf(buf, " vectors='%u'", def->msi.vectors);
+        if (def->msi.ioeventfd)
+            virBufferAsprintf(buf, " ioeventfd='%s'",
+                              virTristateSwitchTypeToString(def->msi.ioeventfd));
+        virBufferAddLit(buf, "/>\n");
+    }
+
+    if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
+        return -1;
+
+    virBufferAdjustIndent(buf, -2);
+    virBufferAddLit(buf, "</shmem>\n");
+
+    return 0;
+}
+
 static int
 virDomainRNGDefFormat(virBufferPtr buf,
                       virDomainRNGDefPtr def,
@@ -19089,6 +19266,10 @@ virDomainDefFormatInternal(virDomainDefPtr def,
         virDomainPanicDefFormat(buf, def->panic) < 0)
         goto error;
 
+    for (n = 0; n < def->nshmems; n++)
+        if (virDomainShmemDefFormat(buf, def->shmems[n], flags) < 0)
+            goto error;
+
     virBufferAdjustIndent(buf, -2);
     virBufferAddLit(buf, "</devices>\n");
 
@@ -20454,6 +20635,7 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
     case VIR_DOMAIN_DEVICE_SMARTCARD:
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
     case VIR_DOMAIN_DEVICE_NVRAM:
+    case VIR_DOMAIN_DEVICE_SHMEM:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Copying definition of '%d' type "
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index ea201b3a33..d73d654282 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -136,6 +136,9 @@ typedef virDomainPanicDef *virDomainPanicDefPtr;
 typedef struct _virDomainChrSourceDef virDomainChrSourceDef;
 typedef virDomainChrSourceDef *virDomainChrSourceDefPtr;
 
+typedef struct _virDomainShmemDef virDomainShmemDef;
+typedef virDomainShmemDef *virDomainShmemDefPtr;
+
 /* Flags for the 'type' field in virDomainDeviceDef */
 typedef enum {
     VIR_DOMAIN_DEVICE_NONE = 0,
@@ -157,6 +160,7 @@ typedef enum {
     VIR_DOMAIN_DEVICE_MEMBALLOON,
     VIR_DOMAIN_DEVICE_NVRAM,
     VIR_DOMAIN_DEVICE_RNG,
+    VIR_DOMAIN_DEVICE_SHMEM,
 
     VIR_DOMAIN_DEVICE_LAST
 } virDomainDeviceType;
@@ -184,6 +188,7 @@ struct _virDomainDeviceDef {
         virDomainMemballoonDefPtr memballoon;
         virDomainNVRAMDefPtr nvram;
         virDomainRNGDefPtr rng;
+        virDomainShmemDefPtr shmem;
     } data;
 };
 
@@ -1506,6 +1511,21 @@ struct _virDomainNVRAMDef {
     virDomainDeviceInfo info;
 };
 
+struct _virDomainShmemDef {
+    char *name;
+    unsigned long long size;
+    struct {
+        bool enabled;
+        char *path;
+    } server;
+    struct {
+        bool enabled;
+        unsigned vectors;
+        virTristateSwitch ioeventfd;
+    } msi;
+    virDomainDeviceInfo info;
+};
+
 typedef enum {
     VIR_DOMAIN_SMBIOS_NONE = 0,
     VIR_DOMAIN_SMBIOS_EMULATE,
@@ -2082,6 +2102,9 @@ struct _virDomainDef {
     size_t nrngs;
     virDomainRNGDefPtr *rngs;
 
+    size_t nshmems;
+    virDomainShmemDefPtr *shmems;
+
     /* Only 1 */
     virDomainWatchdogDefPtr watchdog;
     virDomainMemballoonDefPtr memballoon;
@@ -2279,6 +2302,7 @@ void virDomainHostdevDefFree(virDomainHostdevDefPtr def);
 void virDomainHubDefFree(virDomainHubDefPtr def);
 void virDomainRedirdevDefFree(virDomainRedirdevDefPtr def);
 void virDomainRedirFilterDefFree(virDomainRedirFilterDefPtr def);
+void virDomainShmemDefFree(virDomainShmemDefPtr def);
 void virDomainDeviceDefFree(virDomainDeviceDefPtr def);
 virDomainDeviceDefPtr virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
                                              const virDomainDef *def,
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index d63188749c..3a654e436f 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -2859,6 +2859,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"),
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem-msi-only.xml b/tests/qemuxml2argvdata/qemuxml2argv-shmem-msi-only.xml
new file mode 100644
index 0000000000..d70279c21f
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem-msi-only.xml
@@ -0,0 +1,24 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <memballoon model='none'/>
+    <shmem name='shmem0'>
+      <msi/>
+    </shmem>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml b/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml
new file mode 100644
index 0000000000..fd79c89c1a
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-shmem.xml
@@ -0,0 +1,51 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <controller type='usb' index='0'/>
+    <controller type='pci' index='0' model='pci-root'/>
+    <memballoon model='none'/>
+    <shmem name='shmem0'/>
+    <shmem name='shmem1'>
+      <size unit='M'>128</size>
+    </shmem>
+    <shmem name='shmem2'>
+      <size unit='M'>256</size>
+    </shmem>
+    <shmem name='shmem3'>
+      <size unit='M'>512</size>
+      <server/>
+    </shmem>
+    <shmem name='shmem4'>
+      <size unit='M'>1024</size>
+      <server path='/tmp/shmem4-sock'/>
+    </shmem>
+    <shmem name='shmem5'>
+      <size unit='M'>2048</size>
+      <server path='/tmp/shmem5-sock'/>
+      <msi ioeventfd='off'/>
+    </shmem>
+    <shmem name='shmem6'>
+      <size unit='M'>4096</size>
+      <server path='/tmp/shmem6-sock'/>
+      <msi vectors='16'/>
+    </shmem>
+    <shmem name='shmem7'>
+      <size unit='M'>8192</size>
+      <server path='/tmp/shmem7-sock'/>
+      <msi vectors='32' ioeventfd='on'/>
+    </shmem>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 483ca90324..58153db0df 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1466,6 +1466,8 @@ mymain(void)
 
     DO_TEST("fips-enabled", QEMU_CAPS_ENABLE_FIPS);
 
+    DO_TEST_PARSE_ERROR("shmem-msi-only", NONE);
+
     virObjectUnref(driver.config);
     virObjectUnref(driver.caps);
     virObjectUnref(driver.xmlopt);
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 9a568806d7..978e5f1c6a 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -404,6 +404,7 @@ mymain(void)
     DO_TEST("bios-nvram");
 
     DO_TEST("tap-vhost");
+    DO_TEST("shmem");
 
     virObjectUnref(driver.caps);
     virObjectUnref(driver.xmlopt);