diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs
index 3e2b175..e44feb8 100644
--- a/hw/virtio/Makefile.objs
+++ b/hw/virtio/Makefile.objs
@@ -2,6 +2,7 @@ common-obj-y += virtio-rng.o
 common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
 common-obj-y += virtio-bus.o
 common-obj-y += virtio-mmio.o
+common-obj-y += vhost-pci-server.o
 
 obj-y += virtio.o virtio-balloon.o 
 obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o
diff --git a/hw/virtio/vhost-pci-server.c b/hw/virtio/vhost-pci-server.c
new file mode 100644
index 0000000..6ce8516
--- /dev/null
+++ b/hw/virtio/vhost-pci-server.c
@@ -0,0 +1,469 @@
+/*
+ * Vhost-pci server
+ *
+ * Copyright Intel Corp. 2016
+ *
+ * Authors:
+ * Wei Wang    <wei.w.wang@intel.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <qemu/osdep.h>
+#include <qemu/thread.h>
+#include <qemu/main-loop.h>
+#include <qemu/bitops.h>
+#include <qemu/bitmap.h>
+#include <qemu/sockets.h>
+#include <linux/virtio_net.h>
+#include "sysemu/char.h"
+#include "qapi/error.h"
+#include "hw/virtio/vhost-pci-server.h"
+#include "qemu/option.h"
+#include "monitor/qdev.h"
+#include "hw/virtio/vhost-user.h"
+#include "hw/qdev.h"
+
+#define VHOST_PCI_FEATURE_BITS (1ULL << VIRTIO_F_VERSION_1)
+
+#define VHOST_PCI_NET_FEATURE_BITS (1ULL << VIRTIO_NET_F_MRG_RXBUF) | \
+                                   (1ULL << VIRTIO_NET_F_CTRL_VQ) | \
+                                   (1ULL << VIRTIO_NET_F_MQ)
+
+#define VHOST_USER_SET_PEER_CONNECTION_OFF  0
+#define VHOST_USER_SET_PEER_CONNECTION_ON   1
+#define VHOST_USER_SET_PEER_CONNECTION_INIT 2
+
+VhostPCIServer *vp_server;
+
+QemuOptsList qemu_vhost_pci_server_opts = {
+    .name = "vhost-pci-server",
+    .implied_opt_name = "chardev",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_vhost_pci_server_opts.head),
+    .desc = {
+        /*
+         * no elements => accept any
+         * sanity checking will happen later
+         * when setting device properties
+         */
+        { /* end of list */ }
+    },
+};
+
+static int vhost_pci_server_write(CharDriverState *chr, VhostUserMsg *msg)
+{
+    int size = msg->size + VHOST_USER_HDR_SIZE;
+
+    if (!msg)
+        return 0;
+
+    msg->flags &= ~VHOST_USER_VERSION_MASK;
+    msg->flags |= VHOST_USER_VERSION;
+
+    return qemu_chr_fe_write_all_n(chr, msg->conn_id,
+                                 (const uint8_t *)msg, size) == size ? 0 : -1;
+}
+
+PeerConnectionTable *vp_server_find_table_ent(const char *dev_id)
+{
+    int i;
+    PeerConnectionTable *ent;
+    uint64_t max_connections = vp_server->chr->max_connections;
+
+    for (i = 0; i < max_connections; i++) {
+        ent = &vp_server->peer_table[i];
+        if (!strcmp(dev_id, ent->dev_id))
+            return ent;
+    }
+    return NULL;
+}
+
+static void vhost_pci_init_peer_table(uint64_t id)
+{
+    PeerConnectionTable *ent = &vp_server->peer_table[id];
+
+    ent->peer_feature_bits |= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES;
+    QLIST_INIT(&ent->vq_list);
+    ent->vq_num = 0;
+}
+
+static int vhost_pci_get_conn_id(CharDriverState *chr, VhostUserMsg *msg)
+{
+    unsigned long *conn_bitmap = chr->conn_bitmap;
+    unsigned long *old_conn_bitmap = vp_server->old_conn_bitmap;
+    uint64_t nbits = chr->max_connections;
+    uint64_t id;
+    int r;
+
+    bitmap_xor(old_conn_bitmap, old_conn_bitmap, conn_bitmap, (long)nbits);
+
+    for (id = find_first_bit(old_conn_bitmap, nbits); id < nbits;
+         id = find_next_bit(old_conn_bitmap, nbits, id + 1)) {
+        vhost_pci_init_peer_table(id);
+        msg->conn_id = id;
+        msg->payload.u64 = id;
+        msg->size = sizeof(msg->payload.u64);
+        msg->flags |= VHOST_USER_REPLY_MASK;
+        r = vhost_pci_server_write(chr, msg);
+    }
+    bitmap_copy(old_conn_bitmap, conn_bitmap, (long)nbits);
+
+    return r;
+}
+
+static int vhost_pci_get_peer_features(CharDriverState *chr, VhostUserMsg *msg)
+{
+    PeerConnectionTable *ent = &vp_server->peer_table[msg->conn_id];
+    msg->payload.u64 = ent->peer_feature_bits;
+    msg->size = sizeof(msg->payload.u64);
+    msg->flags |= VHOST_USER_REPLY_MASK;
+    return vhost_pci_server_write(chr, msg);
+}
+
+static int vhost_pci_get_queue_num(CharDriverState *chr, VhostUserMsg *msg)
+{
+    PeerConnectionTable *ent = &vp_server->peer_table[msg->conn_id];
+    switch (ent->virtio_id) {
+    case VIRTIO_ID_NET:
+        msg->payload.u64 = VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX;
+        break;
+    default:
+        printf("%s: device type not supported yet..\n", __func__);
+    }
+    msg->size = sizeof(msg->payload.u64);
+    msg->flags |= VHOST_USER_REPLY_MASK;
+    return vhost_pci_server_write(chr, msg);
+}
+
+static int vhost_pci_get_protocol_features(CharDriverState *chr, VhostUserMsg *msg)
+{
+    msg->payload.u64 = VHOST_USER_PROTOCOL_FEATURES;
+    msg->size = sizeof(msg->payload.u64);
+    msg->flags |= VHOST_USER_REPLY_MASK;
+    return vhost_pci_server_write(chr, msg);
+}
+
+static void vhost_pci_set_protocol_features(VhostUserMsg *msg)
+{
+    vp_server->protocol_features = msg->payload.u64;
+}
+
+static int vhost_pci_device_create(uint64_t conn_id)
+{
+    PeerConnectionTable *ent = &vp_server->peer_table[conn_id];
+    Error *local_err = NULL;
+    QemuOpts *opts;
+    DeviceState *dev;
+    char params[50];
+
+    switch (ent->virtio_id) {
+    case VIRTIO_ID_NET:
+        sprintf(params, "driver=vhost-pci-net-pci,id=vhost-pci-%ld", conn_id);
+        sprintf(ent->dev_id, "vhost-pci-%ld", conn_id);
+        break;
+    default:
+         printf("%s: device type not supported yet..\n", __func__);
+    }
+
+    opts = qemu_opts_parse_noisily(qemu_find_opts("device"), params, true);
+    dev = qdev_device_add(opts, &local_err);
+    if (!dev) {
+        qemu_opts_del(opts);
+        return -1;
+    }
+    object_unref(OBJECT(dev));
+    return 0;
+}
+
+static void vhost_pci_set_device_info(VhostUserMsg *msg)
+{
+    PeerConnectionTable *ent = &vp_server->peer_table[msg->conn_id];
+    DeviceInfo *info = &msg->payload.dev_info;
+
+    memcpy(ent->uuid, info->uuid, sizeof(uuid_t));
+    ent->virtio_id = info->virtio_id;
+    switch (ent->virtio_id) {
+    case VIRTIO_ID_NET:
+        ent->peer_feature_bits |= (VHOST_PCI_FEATURE_BITS | VHOST_PCI_NET_FEATURE_BITS);
+        break;
+    default:
+        printf("%s: device type not supported yet..\n", __func__);
+    }
+}
+
+static void vhost_pci_set_peer_feature_bits(VhostUserMsg *msg)
+{
+    PeerConnectionTable *ent = &vp_server->peer_table[msg->conn_id];
+
+    ent->peer_feature_bits = msg->payload.u64;
+}
+
+static uint64_t vhost_pci_peer_mem_size_get(VhostUserMemory *peer_mem)
+{
+    int i;
+    uint64_t total_size;
+    uint32_t nregions = peer_mem->nregions;
+    VhostUserMemoryRegion *regions = peer_mem->regions;
+
+    for (i = 0; i < nregions; i++) {
+        total_size += regions[i].memory_size;
+    }
+
+    return total_size;
+}
+
+static int vhost_pci_set_mem_table(uint64_t conn_id, VhostUserMemory *peer_mem, int *fds)
+{
+    int i;
+    void *mr_qva;
+    PeerConnectionTable *ent = &vp_server->peer_table[conn_id];
+    uint32_t nregions = peer_mem->nregions;
+    VhostUserMemoryRegion *peer_mr = peer_mem->regions;
+    MemoryRegion *bar_mr = g_malloc(sizeof(MemoryRegion));
+    MemoryRegion *mr = g_malloc(nregions * sizeof(MemoryRegion));
+    uint64_t bar_size = 2 * vhost_pci_peer_mem_size_get(peer_mem);
+    uint64_t bar_map_offset = 0;
+
+    bar_size = pow2ceil(bar_size);
+    memory_region_init(bar_mr, NULL, "Peer Memory", bar_size);
+
+    for (i = 0; i < nregions; i++) {
+        mr_qva = mmap(NULL, peer_mr[i].memory_size + peer_mr[i].mmap_offset,
+                      PROT_READ | PROT_READ, MAP_SHARED, fds[i], 0);
+        if (mr_qva == MAP_FAILED) {
+            printf("%s called: map failed \n", __func__);
+            return -1;
+        }
+        mr_qva += peer_mr[i].mmap_offset;
+        memory_region_init_ram_ptr(&mr[i], NULL, "Peer Memory", peer_mr[i].memory_size, mr_qva);
+        memory_region_add_subregion(bar_mr, bar_map_offset, &mr[i]);
+        bar_map_offset += peer_mr[i].memory_size;
+    }
+    ent->bar_mr = bar_mr;
+    ent->bar_map_offset = bar_map_offset;
+
+    return 0;
+}
+
+static void vhost_pci_alloc_peer_vring_info(uint64_t conn_id)
+{
+    PeerConnectionTable *ent = &vp_server->peer_table[conn_id];
+    PeerVirtqInfo *virtq_info = g_malloc0(sizeof(PeerVirtqInfo));
+    QLIST_INSERT_HEAD(&ent->vq_list, virtq_info, node);
+    ent->vq_num++;
+}
+
+static void vhost_pci_set_vring_num(VhostUserMsg *msg)
+{
+    PeerConnectionTable *ent = &vp_server->peer_table[msg->conn_id];
+    PeerVirtqInfo *virtq_info = QLIST_FIRST(&ent->vq_list);
+
+    virtq_info->vring_num = msg->payload.u64;
+}
+
+static void vhost_pci_set_vring_base(VhostUserMsg *msg)
+{
+    PeerConnectionTable *ent = &vp_server->peer_table[msg->conn_id];
+    PeerVirtqInfo *virtq_info = QLIST_FIRST(&ent->vq_list);
+
+    virtq_info->last_avail_idx = msg->payload.u64;
+}
+
+static void vhost_pci_set_vring_addr(VhostUserMsg *msg)
+{
+    PeerConnectionTable *ent = &vp_server->peer_table[msg->conn_id];
+    PeerVirtqInfo *virtq_info = QLIST_FIRST(&ent->vq_list);
+    memcpy(&virtq_info->addr, &msg->payload.addr,
+           sizeof(struct vhost_vring_addr));
+}
+
+static void vhost_pci_set_vring_kick(uint64_t conn_id, int fd)
+{
+    PeerConnectionTable *ent = &vp_server->peer_table[conn_id];
+    PeerVirtqInfo *virtq_info = QLIST_FIRST(&ent->vq_list);
+    if (!virtq_info)
+        virtq_info->kickfd = fd;
+}
+
+static void vhost_pci_set_vring_call(uint64_t conn_id, int fd)
+{
+    PeerConnectionTable *ent = &vp_server->peer_table[conn_id];
+    PeerVirtqInfo *virtq_info = QLIST_FIRST(&ent->vq_list);
+    if (virtq_info)
+        virtq_info->callfd = fd;
+}
+
+static void vhost_pci_set_peer_connection(VhostUserMsg *msg)
+{
+    uint64_t cmd = msg->payload.u64;
+    uint64_t conn_id = msg->conn_id;
+
+    switch (cmd) {
+    case VHOST_USER_SET_PEER_CONNECTION_INIT:
+        vhost_pci_device_create(conn_id);
+        break;
+    default:
+        printf("%s called: cmd %lu not supported yet \n", __func__, cmd);
+    }
+}
+
+static void vhost_pci_server_read(void *opaque, const uint8_t *buf, int size)
+{
+    VhostUserMsg msg;
+    uint8_t *p = (uint8_t *) &msg;
+    CharDriverState *chr = (CharDriverState *)opaque;
+    int fds[8], fd_num;
+
+    if (size != VHOST_USER_HDR_SIZE) {
+        printf("Wrong message size received %d\n", size);
+        return;
+    }
+    memcpy(p, buf, VHOST_USER_HDR_SIZE);
+
+    if (msg.size) {
+        p += VHOST_USER_HDR_SIZE;
+        size = qemu_chr_fe_read_all_n(chr, msg.conn_id, p, msg.size);
+        if (size != msg.size) {
+            printf("Wrong message size received %d != %d\n",
+                           size, msg.size);
+            return;
+        }
+    }
+
+    if (msg.request > VHOST_USER_MAX)
+        printf("vhost read incorrect msg \n");
+
+    switch(msg.request) {
+    case VHOST_USER_GET_CONN_ID:
+        vhost_pci_get_conn_id(chr, &msg);
+        break;
+    case VHOST_USER_GET_FEATURES:
+        vhost_pci_get_peer_features(chr, &msg);
+        break;
+    case VHOST_USER_GET_PROTOCOL_FEATURES:
+        vhost_pci_get_protocol_features(chr, &msg);
+        break;
+    case VHOST_USER_SET_PROTOCOL_FEATURES:
+        vhost_pci_set_protocol_features(&msg);
+        break;
+    case VHOST_USER_SET_DEV_INFO:
+        vhost_pci_set_device_info(&msg);
+        break;
+    case VHOST_USER_GET_QUEUE_NUM:
+        vhost_pci_get_queue_num(chr, &msg);
+        break;
+    case VHOST_USER_SET_OWNER:
+        break;
+    case VHOST_USER_SET_FEATURES:
+        vhost_pci_set_peer_feature_bits(&msg);
+        break;
+    case VHOST_USER_SET_VRING_NUM:
+        vhost_pci_alloc_peer_vring_info(msg.conn_id);
+        vhost_pci_set_vring_num(&msg);
+        break;
+    case VHOST_USER_SET_VRING_BASE:
+        vhost_pci_set_vring_base(&msg);
+        break;
+    case VHOST_USER_SET_VRING_ADDR:
+        vhost_pci_set_vring_addr(&msg);
+        break;
+    case VHOST_USER_SET_VRING_KICK:
+        /* consume the fd */
+        qemu_chr_fe_get_msgfds_n(chr, msg.conn_id, fds, 1);
+        printf("VHOST_USER_SET_VRING_KICK called:..kickfd = %d\n", fds[0]);
+        vhost_pci_set_vring_kick(msg.conn_id, fds[0]);
+        /*
+         * This is a non-blocking eventfd.
+         * The receive function forces it to be blocking,
+         * so revert it back to non-blocking.
+         */
+        qemu_set_nonblock(fds[0]);
+        break;
+    case VHOST_USER_SET_VRING_CALL:
+        /* consume the fd */
+        qemu_chr_fe_get_msgfds_n(chr, msg.conn_id, fds, 1);
+        vhost_pci_set_vring_call(msg.conn_id, fds[0]);
+        /*
+         * This is a non-blocking eventfd.
+         * The receive function forces it to be blocking,
+         * so revert it back to non-blocking.
+         */
+        qemu_set_nonblock(fds[0]);
+        break;
+    case VHOST_USER_SET_MEM_TABLE:
+        fd_num = qemu_chr_fe_get_msgfds_n(chr, msg.conn_id,
+                                          fds, sizeof(fds) / sizeof(int));
+        printf("VHOST_USER_SET_MEM_TABLE: fd = %d \n", fd_num);
+        vhost_pci_set_mem_table(msg.conn_id, &msg.payload.memory, fds);
+        break;
+    case VHOST_USER_SET_PEER_CONNECTION:
+        vhost_pci_set_peer_connection(&msg);
+        break;
+    default:
+        printf("default called..msg->request = %d \n", msg.request);
+        break;
+    }
+}
+
+static int vhost_pci_server_can_read(void *opaque)
+{
+    return VHOST_USER_HDR_SIZE;
+}
+
+static void vhost_pci_server_event(void *opaque, int event)
+{
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        printf("vhost_pci_server_event called.. \n");
+        break;
+    case CHR_EVENT_CLOSED:
+        printf("vhost_pci_server_event called: event close..\n");
+        break;
+    }
+}
+
+static CharDriverState *vhost_pci_server_parse_chardev(const char *id)
+{
+    CharDriverState *chr = qemu_chr_find(id);
+    if (chr == NULL) {
+        printf("chardev \"%s\" not found", id);
+        return NULL;
+    }
+
+    qemu_chr_fe_claim_no_fail(chr);
+
+    return chr;
+}
+
+int vhost_pci_server_init(QemuOpts *opts)
+{
+    CharDriverState *chr;
+    const char *chardev_id = qemu_opt_get(opts, "chardev");
+    uint64_t max_connections;
+
+    vp_server = (VhostPCIServer *)malloc(sizeof(VhostPCIServer));
+
+    chr = vhost_pci_server_parse_chardev(chardev_id);
+    if (!chr) {
+        return -1;
+    }
+    max_connections = chr->max_connections;
+
+    qemu_chr_add_handlers(chr, vhost_pci_server_can_read, vhost_pci_server_read, vhost_pci_server_event, chr);
+
+    vp_server->chr = chr;
+
+    vp_server->peer_table = (PeerConnectionTable *)g_malloc0(max_connections * sizeof(PeerConnectionTable));
+
+    vp_server->old_conn_bitmap = bitmap_new(max_connections);
+
+    return 0;
+}
+
+int vhost_pci_server_cleanup(void)
+{
+    free(vp_server);
+    printf("vhost_pci_server_cleanup called.. \n");
+    return 0;
+}
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index b57454a..bce5181 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -13,6 +13,7 @@
 #include "hw/virtio/vhost.h"
 #include "hw/virtio/vhost-backend.h"
 #include "hw/virtio/virtio-net.h"
+#include "hw/virtio/vhost-user.h"
 #include "sysemu/char.h"
 #include "sysemu/kvm.h"
 #include "qemu/error-report.h"
@@ -24,91 +25,6 @@
 #include <sys/un.h>
 #include <linux/vhost.h>
 
-#define VHOST_MEMORY_MAX_NREGIONS    8
-#define VHOST_USER_F_PROTOCOL_FEATURES 30
-
-enum VhostUserProtocolFeature {
-    VHOST_USER_PROTOCOL_F_MQ = 0,
-    VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
-    VHOST_USER_PROTOCOL_F_RARP = 2,
-    VHOST_USER_PROTOCOL_F_REPLY_ACK = 3,
-
-    VHOST_USER_PROTOCOL_F_MAX
-};
-
-#define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1)
-
-typedef enum VhostUserRequest {
-    VHOST_USER_NONE = 0,
-    VHOST_USER_GET_FEATURES = 1,
-    VHOST_USER_SET_FEATURES = 2,
-    VHOST_USER_SET_OWNER = 3,
-    VHOST_USER_RESET_OWNER = 4,
-    VHOST_USER_SET_MEM_TABLE = 5,
-    VHOST_USER_SET_LOG_BASE = 6,
-    VHOST_USER_SET_LOG_FD = 7,
-    VHOST_USER_SET_VRING_NUM = 8,
-    VHOST_USER_SET_VRING_ADDR = 9,
-    VHOST_USER_SET_VRING_BASE = 10,
-    VHOST_USER_GET_VRING_BASE = 11,
-    VHOST_USER_SET_VRING_KICK = 12,
-    VHOST_USER_SET_VRING_CALL = 13,
-    VHOST_USER_SET_VRING_ERR = 14,
-    VHOST_USER_GET_PROTOCOL_FEATURES = 15,
-    VHOST_USER_SET_PROTOCOL_FEATURES = 16,
-    VHOST_USER_GET_QUEUE_NUM = 17,
-    VHOST_USER_SET_VRING_ENABLE = 18,
-    VHOST_USER_SEND_RARP = 19,
-    VHOST_USER_MAX
-} VhostUserRequest;
-
-typedef struct VhostUserMemoryRegion {
-    uint64_t guest_phys_addr;
-    uint64_t memory_size;
-    uint64_t userspace_addr;
-    uint64_t mmap_offset;
-} VhostUserMemoryRegion;
-
-typedef struct VhostUserMemory {
-    uint32_t nregions;
-    uint32_t padding;
-    VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
-} VhostUserMemory;
-
-typedef struct VhostUserLog {
-    uint64_t mmap_size;
-    uint64_t mmap_offset;
-} VhostUserLog;
-
-typedef struct VhostUserMsg {
-    VhostUserRequest request;
-
-#define VHOST_USER_VERSION_MASK     (0x3)
-#define VHOST_USER_REPLY_MASK       (0x1<<2)
-#define VHOST_USER_NEED_REPLY_MASK  (0x1 << 3)
-    uint32_t flags;
-    uint32_t size; /* the following payload size */
-    union {
-#define VHOST_USER_VRING_IDX_MASK   (0xff)
-#define VHOST_USER_VRING_NOFD_MASK  (0x1<<8)
-        uint64_t u64;
-        struct vhost_vring_state state;
-        struct vhost_vring_addr addr;
-        VhostUserMemory memory;
-        VhostUserLog log;
-    } payload;
-} QEMU_PACKED VhostUserMsg;
-
-static VhostUserMsg m __attribute__ ((unused));
-#define VHOST_USER_HDR_SIZE (sizeof(m.request) \
-                            + sizeof(m.flags) \
-                            + sizeof(m.size))
-
-#define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
-
-/* The version of the protocol we support */
-#define VHOST_USER_VERSION    (0x1)
-
 static bool ioeventfd_enabled(void)
 {
     return kvm_enabled() && kvm_eventfds_enabled();
diff --git a/include/hw/virtio/vhost-pci-server.h b/include/hw/virtio/vhost-pci-server.h
new file mode 100644
index 0000000..c9c4a69
--- /dev/null
+++ b/include/hw/virtio/vhost-pci-server.h
@@ -0,0 +1,45 @@
+#ifndef QEMU_VHOST_PCI_SERVER_H
+#define QEMU_VHOST_PCI_SERVER_H
+
+#include <uuid/uuid.h>
+#include <linux/vhost.h>
+
+typedef struct PeerVirtqInfo {
+    int kickfd;
+    int callfd;
+    uint32_t vring_num;
+    uint16_t last_avail_idx;
+    struct vhost_vring_addr addr;
+    QLIST_ENTRY(PeerVirtqInfo) node;
+} PeerVirtqInfo;
+
+typedef struct PeerConnectionTable {
+    char dev_id[30];
+    uuid_t uuid;
+    uint16_t virtio_id;
+    uint32_t bar_id;
+    MemoryRegion *bar_mr;
+    uint64_t bar_map_offset;
+    uint64_t peer_feature_bits;
+    void *opaque;
+    uint16_t vq_num;
+    QLIST_HEAD(, PeerVirtqInfo) vq_list;
+} PeerConnectionTable;
+
+typedef struct VhostPCIServer {
+    CharDriverState *chr;
+    uint64_t protocol_features;
+    unsigned long *old_conn_bitmap;
+    /* a table indexed by the peer connection id */
+    PeerConnectionTable *peer_table;
+} VhostPCIServer;
+
+extern VhostPCIServer *vp_server;
+
+extern int vhost_pci_server_init(QemuOpts *opts);
+
+extern int vhost_pci_server_cleanup(void);
+
+extern PeerConnectionTable *vp_server_find_table_ent(const char *dev_id);
+
+#endif
diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h
new file mode 100644
index 0000000..794a8d8
--- /dev/null
+++ b/include/hw/virtio/vhost-user.h
@@ -0,0 +1,110 @@
+#ifndef VHOST_USER_H
+#define VHOST_USER_H
+
+#include <linux/vhost.h>
+#include <uuid/uuid.h>
+
+#define VHOST_MEMORY_MAX_NREGIONS    8
+#define VHOST_USER_F_PROTOCOL_FEATURES 30
+
+enum VhostUserProtocolFeature {
+    VHOST_USER_PROTOCOL_F_MQ = 0,
+    VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
+    VHOST_USER_PROTOCOL_F_RARP = 2,
+    VHOST_USER_PROTOCOL_F_REPLY_ACK = 3,
+    VHOST_USER_PROTOCOL_F_VHOST_PCI =4,
+
+    VHOST_USER_PROTOCOL_F_MAX
+};
+
+#define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1)
+
+#define VHOST_USER_PROTOCOL_FEATURES ((1ULL << VHOST_USER_PROTOCOL_F_MQ) | \
+                                      (1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD) | \
+                                      (1ULL << VHOST_USER_PROTOCOL_F_RARP)) | \
+                                      (1ULL << VHOST_USER_PROTOCOL_F_VHOST_PCI)
+
+typedef enum VhostUserRequest {
+    VHOST_USER_NONE = 0,
+    VHOST_USER_GET_FEATURES = 1,
+    VHOST_USER_SET_FEATURES = 2,
+    VHOST_USER_SET_OWNER = 3,
+    VHOST_USER_RESET_OWNER = 4,
+    VHOST_USER_SET_MEM_TABLE = 5,
+    VHOST_USER_SET_LOG_BASE = 6,
+    VHOST_USER_SET_LOG_FD = 7,
+    VHOST_USER_SET_VRING_NUM = 8,
+    VHOST_USER_SET_VRING_ADDR = 9,
+    VHOST_USER_SET_VRING_BASE = 10,
+    VHOST_USER_GET_VRING_BASE = 11,
+    VHOST_USER_SET_VRING_KICK = 12,
+    VHOST_USER_SET_VRING_CALL = 13,
+    VHOST_USER_SET_VRING_ERR = 14,
+    VHOST_USER_GET_PROTOCOL_FEATURES = 15,
+    VHOST_USER_SET_PROTOCOL_FEATURES = 16,
+    VHOST_USER_GET_QUEUE_NUM = 17,
+    VHOST_USER_SET_VRING_ENABLE = 18,
+    VHOST_USER_SEND_RARP = 19,
+    VHOST_USER_GET_CONN_ID = 20,
+    VHOST_USER_SET_DEV_INFO = 21,
+    VHOST_USER_SET_PEER_CONNECTION = 22,
+    VHOST_USER_MAX
+} VhostUserRequest;
+
+typedef struct VhostUserMemoryRegion {
+    uint64_t guest_phys_addr;
+    uint64_t memory_size;
+    uint64_t userspace_addr;
+    uint64_t mmap_offset;
+} VhostUserMemoryRegion;
+
+typedef struct VhostUserMemory {
+    uint32_t nregions;
+    uint32_t padding;
+    VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
+} VhostUserMemory;
+
+typedef struct VhostUserLog {
+    uint64_t mmap_size;
+    uint64_t mmap_offset;
+} VhostUserLog;
+
+typedef struct DeviceInfo {
+    uuid_t uuid;
+    uint16_t virtio_id;
+} DeviceInfo;
+
+typedef struct VhostUserMsg {
+    VhostUserRequest request;
+
+#define VHOST_USER_VERSION_MASK     (0x3)
+#define VHOST_USER_REPLY_MASK       (0x1<<2)
+#define VHOST_USER_NEED_REPLY_MASK  (0x1 << 3)
+    uint32_t flags;
+    uint32_t size; /* the following payload size */
+    uint64_t conn_id;
+    union {
+#define VHOST_USER_VRING_IDX_MASK   (0xff)
+#define VHOST_USER_VRING_NOFD_MASK  (0x1<<8)
+        uint64_t u64;
+        struct vhost_vring_state state;
+        struct vhost_vring_addr addr;
+        VhostUserMemory memory;
+        VhostUserLog log;
+        DeviceInfo dev_info;
+    } payload;
+} QEMU_PACKED VhostUserMsg;
+
+static VhostUserMsg m __attribute__ ((unused));
+#define VHOST_USER_HDR_SIZE (sizeof(m.request) \
+                            + sizeof(m.flags) \
+                            + sizeof(m.size)) \
+                            + sizeof(m.conn_id)
+
+#define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
+
+/* The version of the protocol we support */
+#define VHOST_USER_VERSION    (0x2)
+
+#endif
+
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index ee7c760..7f8b25c 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -244,5 +244,6 @@ extern QemuOptsList qemu_netdev_opts;
 extern QemuOptsList qemu_net_opts;
 extern QemuOptsList qemu_global_opts;
 extern QemuOptsList qemu_mon_opts;
+extern QemuOptsList qemu_vhost_pci_server_opts;
 
 #endif
diff --git a/qemu-options.hx b/qemu-options.hx
index a71aaf8..1fdb820 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3968,6 +3968,10 @@ contents of @code{iv.b64} to the second secret
 
 ETEXI
 
+DEF("vhost-pci-server", HAS_ARG, QEMU_OPTION_vhost_pci_server,
+    "-vhost-pci-server socket,chrdev={id}\n"
+    "                  creates a vhost-pci-server",
+    QEMU_ARCH_I386)
 
 HXCOMM This is the last statement. Insert new options before this line!
 STEXI
diff --git a/vl.c b/vl.c
index b3c80d5..c1f038d 100644
--- a/vl.c
+++ b/vl.c
@@ -121,6 +121,7 @@ int main(int argc, char **argv)
 #include "crypto/init.h"
 #include "sysemu/replay.h"
 #include "qapi/qmp/qerror.h"
+#include "hw/virtio/vhost-pci-server.h"
 
 #define MAX_VIRTIO_CONSOLES 1
 #define MAX_SCLP_CONSOLES 1
@@ -178,6 +179,7 @@ bool boot_strict;
 uint8_t *boot_splash_filedata;
 size_t boot_splash_filedata_size;
 uint8_t qemu_extra_params_fw[2];
+bool vhost_pci_server_enabled;
 
 int icount_align_option;
 
@@ -2980,6 +2982,7 @@ int main(int argc, char **argv, char **envp)
     qemu_add_drive_opts(&qemu_drive_opts);
     qemu_add_opts(&qemu_chardev_opts);
     qemu_add_opts(&qemu_device_opts);
+    qemu_add_opts(&qemu_vhost_pci_server_opts);
     qemu_add_opts(&qemu_netdev_opts);
     qemu_add_opts(&qemu_net_opts);
     qemu_add_opts(&qemu_rtc_opts);
@@ -3970,6 +3973,13 @@ int main(int argc, char **argv, char **envp)
                     exit(1);
                 }
                 break;
+            case QEMU_OPTION_vhost_pci_server:
+                vhost_pci_server_enabled = true;
+                opts = qemu_opts_parse_noisily(qemu_find_opts("vhost-pci-server"), optarg, false);
+                if (!opts) {
+                    exit(1);
+                }
+                break;
             default:
                 os_parse_cmd_args(popt->index, optarg);
             }
@@ -4479,6 +4489,16 @@ int main(int argc, char **argv, char **envp)
         exit(1);
     }
 
+    /* check if the vhost-pci-server is enabled */
+    if (vhost_pci_server_enabled) {
+        int ret;
+        ret = vhost_pci_server_init(qemu_opts_find(
+                                    qemu_find_opts("vhost-pci-server"),
+                                    NULL));
+        if (ret < 0)
+            exit(1);
+    }
+
     /* init USB devices */
     if (machine_usb(current_machine)) {
         if (foreach_device_config(DEV_USB, usb_parse) < 0)
@@ -4607,6 +4627,12 @@ int main(int argc, char **argv, char **envp)
     bdrv_close_all();
     pause_all_vcpus();
     res_free();
+    if (vhost_pci_server_enabled) {
+        int ret;
+        ret = vhost_pci_server_cleanup();
+        if (ret < 0)
+            exit(1);
+    }
 #ifdef CONFIG_TPM
     tpm_cleanup();
 #endif
