From patchwork Thu Mar 25 16:43:09 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Aneesh Kumar K.V" X-Patchwork-Id: 48549 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 567D5B7CEF for ; Fri, 26 Mar 2010 04:32:16 +1100 (EST) Received: from localhost ([127.0.0.1]:48873 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NuquL-0000ao-LE for incoming@patchwork.ozlabs.org; Thu, 25 Mar 2010 13:31:49 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NuqAB-000701-9d for qemu-devel@nongnu.org; Thu, 25 Mar 2010 12:44:07 -0400 Received: from [140.186.70.92] (port=50337 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NuqA4-0006wR-SV for qemu-devel@nongnu.org; Thu, 25 Mar 2010 12:44:06 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1Nuq9u-00050v-Ay for qemu-devel@nongnu.org; Thu, 25 Mar 2010 12:44:00 -0400 Received: from e23smtp07.au.ibm.com ([202.81.31.140]:51493) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1Nuq9s-00050O-Rd for qemu-devel@nongnu.org; Thu, 25 Mar 2010 12:43:50 -0400 Received: from d23relay03.au.ibm.com (d23relay03.au.ibm.com [202.81.31.245]) by e23smtp07.au.ibm.com (8.14.3/8.13.1) with ESMTP id o2PGhl6P029686 for ; Fri, 26 Mar 2010 03:43:47 +1100 Received: from d23av03.au.ibm.com (d23av03.au.ibm.com [9.190.234.97]) by d23relay03.au.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o2PGhlGw1679468 for ; Fri, 26 Mar 2010 03:43:47 +1100 Received: from d23av03.au.ibm.com (loopback [127.0.0.1]) by d23av03.au.ibm.com (8.14.3/8.13.1/NCO v10.0 AVout) with ESMTP id o2PGhlOh030970 for ; Fri, 26 Mar 2010 03:43:47 +1100 Received: from localhost.localdomain ([9.77.125.24]) by d23av03.au.ibm.com (8.14.3/8.13.1/NCO v10.0 AVin) with ESMTP id o2PGhgOa030935; Fri, 26 Mar 2010 03:43:45 +1100 From: "Aneesh Kumar K.V" To: qemu-devel@nongnu.org Date: Thu, 25 Mar 2010 22:13:09 +0530 Message-Id: <1269535420-31206-2-git-send-email-aneesh.kumar@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.0.2.323.g0d092 In-Reply-To: <1269535420-31206-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com> References: <1269535420-31206-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) Cc: ericvh@gmail.com, aliguori@us.ibm.com, "Aneesh Kumar K.V" Subject: [Qemu-devel] [PATCH -V3 01/32] vitio-9p: Add a virtio 9p device to qemu X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Anthony Liguori This patch doesn't implement the 9p protocol handling code. It add a simple device which dump the protocl data Signed-off-by: Anthony Liguori Signed-off-by: Aneesh Kumar K.V --- Makefile.target | 1 + hw/virtio-9p-debug.c | 442 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/virtio-9p.c | 275 +++++++++++++++++++++++++++++++ hw/virtio-9p.h | 70 ++++++++ hw/virtio-pci.c | 25 +++ hw/virtio.h | 1 + 6 files changed, 814 insertions(+), 0 deletions(-) create mode 100644 hw/virtio-9p-debug.c create mode 100644 hw/virtio-9p.c create mode 100644 hw/virtio-9p.h diff --git a/Makefile.target b/Makefile.target index eb4d010..178ddce 100644 --- a/Makefile.target +++ b/Makefile.target @@ -166,6 +166,7 @@ obj-y += qemu-timer.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-serial-bus.o +obj-y += virtio-9p.o virtio-9p-debug.o obj-y += rwhandler.o obj-$(CONFIG_KVM) += kvm.o kvm-all.o LIBS+=-lz diff --git a/hw/virtio-9p-debug.c b/hw/virtio-9p-debug.c new file mode 100644 index 0000000..9230659 --- /dev/null +++ b/hw/virtio-9p-debug.c @@ -0,0 +1,442 @@ +/* + * Virtio 9p PDU debug + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Anthony Liguori + * + * 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 +#include + +#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"); +} diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c new file mode 100644 index 0000000..115c93b --- /dev/null +++ b/hw/virtio-9p.c @@ -0,0 +1,275 @@ +/* + * Virtio 9p backend + * + * Copyright IBM, Corp. 2010 + * + * Authors: + * Anthony Liguori + * + * 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 + +/* 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; +} diff --git a/hw/virtio-9p.h b/hw/virtio-9p.h new file mode 100644 index 0000000..2aa67d0 --- /dev/null +++ b/hw/virtio-9p.h @@ -0,0 +1,70 @@ +#ifndef _QEMU_VIRTIO_9P_H +#define _QEMU_VIRTIO_9P_H + +#include +#include +#include +#include + +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 diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 6eb19cd..85879fb 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -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 */ } }; diff --git a/hw/virtio.h b/hw/virtio.h index 3baa2a3..4032a96 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -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);