@@ -172,6 +172,7 @@ obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o
# virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly
obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-pci.o virtio-serial-bus.o
+obj-y += virtio-9p.o virtio-9p-debug.o
obj-y += rwhandler.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
new file mode 100644
@@ -0,0 +1,442 @@
+/*
+ * Virtio 9p PDU debug
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include "virtio.h"
+#include "pc.h"
+#include "virtio-9p.h"
+
+#include <assert.h>
+#include <sys/uio.h>
+
+#define BUG_ON(cond) assert(!(cond))
+
+extern int dotu;
+static FILE *llogfile;
+
+static struct iovec *get_sg(V9fsPDU *pdu, int rx)
+{
+ if (rx)
+ return pdu->elem.in_sg;
+ return pdu->elem.out_sg;
+}
+
+static void pprint_int8(V9fsPDU *pdu, int rx, size_t *offsetp,
+ const char *name)
+{
+ struct iovec *sg = get_sg(pdu, rx);
+ size_t offset = *offsetp;
+ int8_t value;
+
+ BUG_ON((offset + sizeof(value)) > sg[0].iov_len);
+
+ memcpy(&value, sg[0].iov_base + offset, sizeof(value));
+ offset += sizeof(value);
+
+ fprintf(llogfile, "%s=0x%x", name, value);
+
+ *offsetp = offset;
+}
+
+static void pprint_int16(V9fsPDU *pdu, int rx, size_t *offsetp,
+ const char *name)
+{
+ struct iovec *sg = get_sg(pdu, rx);
+ size_t offset = *offsetp;
+ int16_t value;
+
+ BUG_ON((offset + sizeof(value)) > sg[0].iov_len);
+
+ memcpy(&value, sg[0].iov_base + offset, sizeof(value));
+ offset += sizeof(value);
+
+ fprintf(llogfile, "%s=0x%x", name, value);
+
+ *offsetp = offset;
+}
+
+static void pprint_int32(V9fsPDU *pdu, int rx, size_t *offsetp,
+ const char *name)
+{
+ struct iovec *sg = get_sg(pdu, rx);
+ size_t offset = *offsetp;
+ int32_t value;
+
+ BUG_ON((offset + sizeof(value)) > sg[0].iov_len);
+
+ memcpy(&value, sg[0].iov_base + offset, sizeof(value));
+ offset += sizeof(value);
+
+ fprintf(llogfile, "%s=0x%x", name, value);
+
+ *offsetp = offset;
+}
+
+static void pprint_int64(V9fsPDU *pdu, int rx, size_t *offsetp,
+ const char *name)
+{
+ struct iovec *sg = get_sg(pdu, rx);
+ size_t offset = *offsetp;
+ int64_t value;
+
+ BUG_ON((offset + sizeof(value)) > sg[0].iov_len);
+
+ memcpy(&value, sg[0].iov_base + offset, sizeof(value));
+ offset += sizeof(value);
+
+ fprintf(llogfile, "%s=0x%" PRIx64, name, value);
+
+ *offsetp = offset;
+}
+
+static void pprint_str(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+ struct iovec *sg = get_sg(pdu, rx);
+ size_t offset = *offsetp;
+ int16_t size;
+ size_t result;
+
+ BUG_ON((offset + 2) > sg[0].iov_len);
+ memcpy(&size, sg[0].iov_base + offset, 2);
+ offset += 2;
+
+ BUG_ON((offset + size) > sg[0].iov_len);
+ fprintf(llogfile, "%s=", name);
+ result = fwrite(sg[0].iov_base + offset, 1, size, llogfile);
+ BUG_ON(result != size);
+ offset += size;
+
+ *offsetp = offset;
+}
+
+static void pprint_qid(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+ fprintf(llogfile, "%s={", name);
+ pprint_int8(pdu, rx, offsetp, "type");
+ pprint_int32(pdu, rx, offsetp, ", version");
+ pprint_int64(pdu, rx, offsetp, ", path");
+ fprintf(llogfile, "}");
+}
+
+static void pprint_stat(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+ fprintf(llogfile, "%s={", name);
+ pprint_int16(pdu, rx, offsetp, "size");
+ pprint_int16(pdu, rx, offsetp, ", type");
+ pprint_int32(pdu, rx, offsetp, ", dev");
+ pprint_qid(pdu, rx, offsetp, ", qid");
+ pprint_int32(pdu, rx, offsetp, ", mode");
+ pprint_int32(pdu, rx, offsetp, ", atime");
+ pprint_int32(pdu, rx, offsetp, ", mtime");
+ pprint_int64(pdu, rx, offsetp, ", length");
+ pprint_str(pdu, rx, offsetp, ", name");
+ pprint_str(pdu, rx, offsetp, ", uid");
+ pprint_str(pdu, rx, offsetp, ", gid");
+ pprint_str(pdu, rx, offsetp, ", muid");
+ if (dotu) {
+ pprint_str(pdu, rx, offsetp, ", extension");
+ pprint_int32(pdu, rx, offsetp, ", uid");
+ pprint_int32(pdu, rx, offsetp, ", gid");
+ pprint_int32(pdu, rx, offsetp, ", muid");
+ }
+ fprintf(llogfile, "}");
+}
+
+static void pprint_strs(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+ struct iovec *sg = get_sg(pdu, rx);
+ size_t offset = *offsetp;
+ int16_t count, i;
+
+ fprintf(llogfile, "%s={", name);
+
+ BUG_ON((offset + 2) > sg[0].iov_len);
+ memcpy(&count, sg[0].iov_base + offset, 2);
+ offset += 2;
+
+ for (i = 0; i < count; i++) {
+ char str[512];
+ if (i)
+ fprintf(llogfile, ", ");
+ snprintf(str, sizeof(str), "[%d]", i);
+ pprint_str(pdu, rx, &offset, str);
+ }
+
+ fprintf(llogfile, "}");
+
+ *offsetp = offset;
+}
+
+static void pprint_qids(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+ struct iovec *sg = get_sg(pdu, rx);
+ size_t offset = *offsetp;
+ int16_t count, i;
+
+ fprintf(llogfile, "%s={", name);
+
+ BUG_ON((offset + 2) > sg[0].iov_len);
+ memcpy(&count, sg[0].iov_base + offset, 2);
+ offset += 2;
+
+ for (i = 0; i < count; i++) {
+ char str[512];
+ if (i)
+ fprintf(llogfile, ", ");
+ snprintf(str, sizeof(str), "[%d]", i);
+ pprint_qid(pdu, rx, &offset, str);
+ }
+
+ fprintf(llogfile, "}");
+
+ *offsetp = offset;
+}
+
+static void pprint_sg(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+ struct iovec *sg = get_sg(pdu, rx);
+ unsigned int count;
+ int i;
+
+ if (rx)
+ count = pdu->elem.in_num;
+ else
+ count = pdu->elem.out_num;
+
+ fprintf(llogfile, "%s={", name);
+ for (i = 0; i < count; i++) {
+ if (i)
+ fprintf(llogfile, ", ");
+ fprintf(llogfile, "(%p, 0x%zx)", sg[i].iov_base, sg[i].iov_len);
+ }
+ fprintf(llogfile, "}");
+}
+
+/* FIXME: read from a directory fid returns serialized stat_t's */
+#ifdef DEBUG_DATA
+static void pprint_data(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
+{
+ struct iovec *sg = get_sg(pdu, rx);
+ size_t offset = *offsetp;
+ unsigned int count;
+ int32_t size;
+ int total, i, j;
+ ssize_t len;
+
+ if (rx)
+ count = pdu->elem.in_num;
+ else
+ count = pdu->elem.out_num;
+
+ BUG_ON((offset + sizeof(size)) > sg[0].iov_len);
+
+ memcpy(&size, sg[0].iov_base + offset, sizeof(size));
+ offset += sizeof(size);
+
+ fprintf(llogfile, "size: %x\n", size);
+
+ sg[0].iov_base += 11; /* skip header */
+ sg[0].iov_len -= 11;
+
+ total = 0;
+ for (i = 0; i < count; i++) {
+ total += sg[i].iov_len;
+ if (total >= size) {
+ /* trim sg list so writev does the right thing */
+ sg[i].iov_len -= (total - size);
+ i++;
+ break;
+ }
+ }
+
+ fprintf(llogfile, "%s={\"", name);
+ fflush(llogfile);
+ for (j = 0; j < i; j++) {
+ if (j) {
+ fprintf(llogfile, "\", \"");
+ fflush(llogfile);
+ }
+
+ do {
+ len = writev(fileno(llogfile), &sg[j], 1);
+ } while (len == -1 && errno == EINTR);
+ fprintf(llogfile, "len == %ld: %m\n", len);
+ BUG_ON(len != sg[j].iov_len);
+ }
+ fprintf(llogfile, "\"}");
+
+ sg[0].iov_base -= 11;
+ sg[0].iov_len += 11;
+
+}
+#endif
+
+void pprint_pdu(V9fsPDU *pdu);
+
+void pprint_pdu(V9fsPDU *pdu)
+{
+ size_t offset = 7;
+
+ if (llogfile == NULL)
+ llogfile = fopen("/tmp/pdu.log", "w");
+
+ switch (pdu->id) {
+ case P9_TVERSION: {
+ fprintf(llogfile, "TVERSION: (");
+ pprint_int32(pdu, 0, &offset, "msize");
+ pprint_str(pdu, 0, &offset, ", version");
+ break;
+ }
+ case P9_RVERSION:
+ fprintf(llogfile, "RVERSION: (");
+ pprint_int32(pdu, 1, &offset, "msize");
+ pprint_str(pdu, 1, &offset, ", version");
+ break;
+ case P9_TAUTH:
+ fprintf(llogfile, "TAUTH: (");
+ pprint_int32(pdu, 0, &offset, "afid");
+ pprint_str(pdu, 0, &offset, ", uname");
+ pprint_str(pdu, 0, &offset, ", aname");
+ if (dotu)
+ pprint_int32(pdu, 0, &offset, ", n_uname");
+ break;
+ case P9_RAUTH:
+ fprintf(llogfile, "RAUTH: (");
+ pprint_qid(pdu, 1, &offset, "qid");
+ break;
+ case P9_TATTACH:
+ fprintf(llogfile, "TATTACH: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_int32(pdu, 0, &offset, ", afid");
+ pprint_str(pdu, 0, &offset, ", uname");
+ pprint_str(pdu, 0, &offset, ", aname");
+ if (dotu)
+ pprint_int32(pdu, 0, &offset, ", n_uname");
+ break;
+ case P9_RATTACH:
+ fprintf(llogfile, "RATTACH: (");
+ pprint_qid(pdu, 1, &offset, "qid");
+ break;
+ case P9_TERROR:
+ fprintf(llogfile, "TERROR: (");
+ break;
+ case P9_RERROR:
+ fprintf(llogfile, "RERROR: (");
+ pprint_str(pdu, 1, &offset, "ename");
+ if (dotu)
+ pprint_int32(pdu, 1, &offset, ", ecode");
+ break;
+ case P9_TFLUSH:
+ fprintf(llogfile, "TFLUSH: (");
+ pprint_int16(pdu, 0, &offset, "oldtag");
+ break;
+ case P9_RFLUSH:
+ fprintf(llogfile, "RFLUSH: (");
+ break;
+ case P9_TWALK:
+ fprintf(llogfile, "TWALK: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_int32(pdu, 0, &offset, ", newfid");
+ pprint_strs(pdu, 0, &offset, ", wnames");
+ break;
+ case P9_RWALK:
+ fprintf(llogfile, "RWALK: (");
+ pprint_qids(pdu, 1, &offset, "wqids");
+ break;
+ case P9_TOPEN:
+ fprintf(llogfile, "TOPEN: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_int8(pdu, 0, &offset, ", mode");
+ break;
+ case P9_ROPEN:
+ fprintf(llogfile, "ROPEN: (");
+ pprint_qid(pdu, 1, &offset, "qid");
+ pprint_int32(pdu, 1, &offset, ", iounit");
+ break;
+ case P9_TCREATE:
+ fprintf(llogfile, "TCREATE: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_str(pdu, 0, &offset, ", name");
+ pprint_int32(pdu, 0, &offset, ", perm");
+ pprint_int8(pdu, 0, &offset, ", mode");
+ if (dotu)
+ pprint_str(pdu, 0, &offset, ", extension");
+ break;
+ case P9_RCREATE:
+ fprintf(llogfile, "RCREATE: (");
+ pprint_qid(pdu, 1, &offset, "qid");
+ pprint_int32(pdu, 1, &offset, ", iounit");
+ break;
+ case P9_TREAD:
+ fprintf(llogfile, "TREAD: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_int64(pdu, 0, &offset, ", offset");
+ pprint_int32(pdu, 0, &offset, ", count");
+ pprint_sg(pdu, 0, &offset, ", sg");
+ break;
+ case P9_RREAD:
+ fprintf(llogfile, "RREAD: (");
+ pprint_int32(pdu, 1, &offset, "count");
+ pprint_sg(pdu, 1, &offset, ", sg");
+ offset = 7;
+#ifdef DEBUG_DATA
+ pprint_data(pdu, 1, &offset, ", data");
+#endif
+ break;
+ case P9_TWRITE:
+ fprintf(llogfile, "TWRITE: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_int64(pdu, 0, &offset, ", offset");
+ pprint_int32(pdu, 0, &offset, ", count");
+ break;
+ case P9_RWRITE:
+ fprintf(llogfile, "RWRITE: (");
+ pprint_int32(pdu, 1, &offset, "count");
+ break;
+ case P9_TCLUNK:
+ fprintf(llogfile, "TCLUNK: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ break;
+ case P9_RCLUNK:
+ fprintf(llogfile, "RCLUNK: (");
+ break;
+ case P9_TREMOVE:
+ fprintf(llogfile, "TREMOVE: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ break;
+ case P9_RREMOVE:
+ fprintf(llogfile, "RREMOVE: (");
+ break;
+ case P9_TSTAT:
+ fprintf(llogfile, "TSTAT: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ break;
+ case P9_RSTAT:
+ fprintf(llogfile, "RSTAT: (");
+ offset += 2; /* ignored */
+ pprint_stat(pdu, 1, &offset, "stat");
+ break;
+ case P9_TWSTAT:
+ fprintf(llogfile, "TWSTAT: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ offset += 2; /* ignored */
+ pprint_stat(pdu, 0, &offset, ", stat");
+ break;
+ case P9_RWSTAT:
+ fprintf(llogfile, "RWSTAT: (");
+ break;
+ default:
+ fprintf(llogfile, "unknown(%d): (", pdu->id);
+ break;
+ }
+
+ fprintf(llogfile, ")\n");
+}
new file mode 100644
@@ -0,0 +1,275 @@
+/*
+ * Virtio 9p backend
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "virtio.h"
+#include "pc.h"
+#include "qemu_socket.h"
+#include "virtio-9p.h"
+
+#include <assert.h>
+
+/* from Linux's linux/virtio_9p.h */
+
+/* The ID for virtio console */
+#define VIRTIO_ID_9P 9
+/* Maximum number of virtio channels per partition (1 for now) */
+#define MAX_9P_CHAN 1
+
+#define MAX_REQ 128
+
+#define BUG_ON(cond) assert(!(cond))
+
+typedef struct V9fsFidState V9fsFidState;
+
+typedef struct V9fsString
+{
+ int16_t size;
+ char *data;
+} V9fsString;
+
+typedef struct V9fsQID
+{
+ int8_t type;
+ int32_t version;
+ int64_t path;
+} V9fsQID;
+
+typedef struct V9fsStat
+{
+ int16_t size;
+ int16_t type;
+ int32_t dev;
+ V9fsQID qid;
+ int32_t mode;
+ int32_t atime;
+ int32_t mtime;
+ int64_t length;
+ V9fsString name;
+ V9fsString uid;
+ V9fsString gid;
+ V9fsString muid;
+ /* 9p2000.u */
+ V9fsString extension;
+ int32_t n_uid;
+ int32_t n_gid;
+ int32_t n_muid;
+} V9fsStat;
+
+struct V9fsFidState
+{
+ int32_t fid;
+ V9fsString path;
+ int fd;
+ DIR *dir;
+ uid_t uid;
+ V9fsFidState *next;
+};
+
+typedef struct V9fsState
+{
+ VirtIODevice vdev;
+ VirtQueue *vq;
+ V9fsPDU pdus[MAX_REQ];
+ V9fsPDU *free_pdu;
+ V9fsFidState *fid_list;
+ char *root;
+ uid_t uid;
+} V9fsState;
+
+int dotu = 1;
+int debug_9p_pdu = 1;
+
+extern void pprint_pdu(V9fsPDU *pdu);
+
+static V9fsPDU *alloc_pdu(V9fsState *s)
+{
+ V9fsPDU *pdu = NULL;
+
+ if (s->free_pdu) {
+ pdu = s->free_pdu;
+ s->free_pdu = pdu->next;
+ }
+
+ return pdu;
+}
+
+static void free_pdu(V9fsState *s, V9fsPDU *pdu)
+{
+ if (pdu) {
+ pdu->next = s->free_pdu;
+ s->free_pdu = pdu;
+ }
+}
+
+static void v9fs_version(V9fsState *s, V9fsPDU *pdu)
+{
+ if (debug_9p_pdu)
+ pprint_pdu(pdu);
+}
+
+static void v9fs_attach(V9fsState *s, V9fsPDU *pdu)
+{
+ if (debug_9p_pdu)
+ pprint_pdu(pdu);
+}
+
+static void v9fs_stat(V9fsState *s, V9fsPDU *pdu)
+{
+ if (debug_9p_pdu)
+ pprint_pdu(pdu);
+}
+
+static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
+{
+ if (debug_9p_pdu)
+ pprint_pdu(pdu);
+}
+
+static void v9fs_clunk(V9fsState *s, V9fsPDU *pdu)
+{
+ if (debug_9p_pdu)
+ pprint_pdu(pdu);
+}
+
+ static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
+{ if (debug_9p_pdu)
+ pprint_pdu(pdu);
+}
+
+static void v9fs_read(V9fsState *s, V9fsPDU *pdu)
+{
+ if (debug_9p_pdu)
+ pprint_pdu(pdu);
+}
+
+static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
+{
+ if (debug_9p_pdu)
+ pprint_pdu(pdu);
+}
+
+static void v9fs_create(V9fsState *s, V9fsPDU *pdu)
+{
+ if (debug_9p_pdu)
+ pprint_pdu(pdu);
+}
+
+static void v9fs_flush(V9fsState *s, V9fsPDU *pdu)
+{
+ if (debug_9p_pdu)
+ pprint_pdu(pdu);
+}
+
+static void v9fs_remove(V9fsState *s, V9fsPDU *pdu)
+{
+ if (debug_9p_pdu)
+ pprint_pdu(pdu);
+}
+
+static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
+{
+ if (debug_9p_pdu)
+ pprint_pdu(pdu);
+}
+
+typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
+
+static pdu_handler_t *pdu_handlers[] = {
+ [P9_TVERSION] = v9fs_version,
+ [P9_TATTACH] = v9fs_attach,
+ [P9_TSTAT] = v9fs_stat,
+ [P9_TWALK] = v9fs_walk,
+ [P9_TCLUNK] = v9fs_clunk,
+ [P9_TOPEN] = v9fs_open,
+ [P9_TREAD] = v9fs_read,
+#if 0
+ [P9_TAUTH] = v9fs_auth,
+#endif
+ [P9_TFLUSH] = v9fs_flush,
+ [P9_TCREATE] = v9fs_create,
+ [P9_TWRITE] = v9fs_write,
+ [P9_TWSTAT] = v9fs_wstat,
+ [P9_TREMOVE] = v9fs_remove,
+};
+
+static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
+{
+ pdu_handler_t *handler;
+
+ if (debug_9p_pdu)
+ pprint_pdu(pdu);
+
+ BUG_ON(pdu->id >= ARRAY_SIZE(pdu_handlers));
+
+ handler = pdu_handlers[pdu->id];
+ BUG_ON(handler == NULL);
+
+ handler(s, pdu);
+}
+
+static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+ V9fsState *s = (V9fsState *)vdev;
+ V9fsPDU *pdu;
+ ssize_t len;
+
+ while ((pdu = alloc_pdu(s)) &&
+ (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
+ uint8_t *ptr;
+
+ BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
+ BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
+
+ ptr = pdu->elem.out_sg[0].iov_base;
+
+ memcpy(&pdu->size, ptr, 4);
+ pdu->id = ptr[4];
+ memcpy(&pdu->tag, ptr + 5, 2);
+
+ submit_pdu(s, pdu);
+ }
+
+ free_pdu(s, pdu);
+}
+
+static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
+{
+ return features;
+}
+
+VirtIODevice *virtio_9p_init(DeviceState *dev, const char *path)
+{
+ V9fsState *s;
+ int i;
+
+ s = (V9fsState *)virtio_common_init("virtio-9p",
+ VIRTIO_ID_9P,
+ 0, sizeof(V9fsState));
+
+ /* initialize pdu allocator */
+ s->free_pdu = &s->pdus[0];
+ for (i = 0; i < (MAX_REQ - 1); i++)
+ s->pdus[i].next = &s->pdus[i + 1];
+ s->pdus[i].next = NULL;
+
+ s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
+ BUG_ON(s->vq == NULL);
+
+ s->root = strdup("/");
+ BUG_ON(s->root == NULL);
+ s->uid = -1;
+
+ s->vdev.get_features = virtio_9p_get_features;
+
+ return &s->vdev;
+}
new file mode 100644
@@ -0,0 +1,70 @@
+#ifndef _QEMU_VIRTIO_9P_H
+#define _QEMU_VIRTIO_9P_H
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <utime.h>
+
+enum {
+ P9_TVERSION = 100,
+ P9_RVERSION,
+ P9_TAUTH = 102,
+ P9_RAUTH,
+ P9_TATTACH = 104,
+ P9_RATTACH,
+ P9_TERROR = 106,
+ P9_RERROR,
+ P9_TFLUSH = 108,
+ P9_RFLUSH,
+ P9_TWALK = 110,
+ P9_RWALK,
+ P9_TOPEN = 112,
+ P9_ROPEN,
+ P9_TCREATE = 114,
+ P9_RCREATE,
+ P9_TREAD = 116,
+ P9_RREAD,
+ P9_TWRITE = 118,
+ P9_RWRITE,
+ P9_TCLUNK = 120,
+ P9_RCLUNK,
+ P9_TREMOVE = 122,
+ P9_RREMOVE,
+ P9_TSTAT = 124,
+ P9_RSTAT,
+ P9_TWSTAT = 126,
+ P9_RWSTAT,
+};
+
+
+/* qid.types */
+enum {
+ P9_QTDIR = 0x80,
+ P9_QTAPPEND = 0x40,
+ P9_QTEXCL = 0x20,
+ P9_QTMOUNT = 0x10,
+ P9_QTAUTH = 0x08,
+ P9_QTTMP = 0x04,
+ P9_QTSYMLINK = 0x02,
+ P9_QTLINK = 0x01,
+ P9_QTFILE = 0x00,
+};
+
+#define P9_NOTAG (u16)(~0)
+#define P9_NOFID (u32)(~0)
+#define P9_MAXWELEM 16
+
+typedef struct V9fsPDU V9fsPDU;
+
+struct V9fsPDU
+{
+ uint32_t size;
+ uint16_t tag;
+ uint8_t id;
+ VirtQueueElement elem;
+ V9fsPDU *next;
+};
+
+
+#endif
@@ -96,6 +96,7 @@ typedef struct {
BlockConf block;
NICConf nic;
uint32_t host_features;
+ char *share_path;
/* Max. number of ports we can have for a the virtio-serial device */
uint32_t max_virtserial_ports;
} VirtIOPCIProxy;
@@ -552,6 +553,21 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev)
return 0;
}
+static int virtio_9p_init_pci(PCIDevice *pci_dev)
+{
+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+ VirtIODevice *vdev;
+
+ vdev = virtio_9p_init(&pci_dev->qdev, proxy->share_path);
+ virtio_init_pci(proxy, vdev,
+ PCI_VENDOR_ID_REDHAT_QUMRANET,
+ 0x1009,
+ 0x2,
+ 0x00);
+
+ return 0;
+}
+
static PCIDeviceInfo virtio_info[] = {
{
.qdev.name = "virtio-blk-pci",
@@ -606,6 +622,15 @@ static PCIDeviceInfo virtio_info[] = {
},
.qdev.reset = virtio_pci_reset,
},{
+ .qdev.name = "virtio-9p-pci",
+ .qdev.size = sizeof(VirtIOPCIProxy),
+ .init = virtio_9p_init_pci,
+ .qdev.props = (Property[]) {
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_STRING("share_path", VirtIOPCIProxy, share_path),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+ },{
/* end of list */
}
};
@@ -174,6 +174,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf);
VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf);
VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports);
VirtIODevice *virtio_balloon_init(DeviceState *dev);
+VirtIODevice *virtio_9p_init(DeviceState *dev, const char *path);
void virtio_net_exit(VirtIODevice *vdev);