VirtIO:
authorReto Achermann <acreto@student.ethz.ch>
Sun, 15 Jun 2014 20:56:20 +0000 (22:56 +0200)
committerStefan Kaestle <stefan.kaestle@inf.ethz.ch>
Wed, 20 Aug 2014 20:19:38 +0000 (22:19 +0200)
extended library to distinguish between host and guest
added flounder / xeon phi channels for opening devices etc

Block Driver
Parts of an initiali implementation
Device initialization

38 files changed:
devices/virtio/virtio_blk.dev
errors/errno.fugu
hake/menu.lst.x86_64
hake/symbolic_targets.mk
if/Hakefile
if/virtio.if [new file with mode: 0644]
include/virtio/devices/virtio_block.h
include/virtio/virtio_device.h
include/virtio/virtio_guest.h [new file with mode: 0644]
include/virtio/virtio_host.h [new file with mode: 0644]
lib/virtio/Hakefile
lib/virtio/backends/virtio_device_mmio.c
lib/virtio/backends/virtio_mmio.h
lib/virtio/debug.h
lib/virtio/device.c
lib/virtio/device.h
lib/virtio/devices/virtio_block.c
lib/virtio/guest.c [new file with mode: 0644]
lib/virtio/guest/channel.h [new file with mode: 0644]
lib/virtio/guest/channel_flounder.c [new file with mode: 0644]
lib/virtio/guest/channel_xeon_phi.c [new file with mode: 0644]
lib/virtio/host.c [new file with mode: 0644]
lib/virtio/host/channel.h [new file with mode: 0644]
lib/virtio/host/channel_flounder.c [new file with mode: 0644]
lib/virtio/host/channel_xeon_phi.c [new file with mode: 0644]
usr/drivers/virtio/block/Hakefile
usr/drivers/virtio/block/debug.h [new file with mode: 0644]
usr/drivers/virtio/block/device.c [new file with mode: 0644]
usr/drivers/virtio/block/device.h [new file with mode: 0644]
usr/drivers/virtio/block/host.c [new file with mode: 0644]
usr/drivers/virtio/block/host.h [new file with mode: 0644]
usr/drivers/virtio/block/main_guest.c
usr/drivers/virtio/block/main_host.c
usr/drivers/virtio/block/request.c [new file with mode: 0644]
usr/drivers/virtio/block/request.h [new file with mode: 0644]
usr/drivers/virtio/block/service.c [new file with mode: 0644]
usr/drivers/virtio/block/service.h [new file with mode: 0644]
usr/drivers/xeon_phi/host_bootstrap.c

index 0e78645..0b3c7a6 100644 (file)
@@ -53,17 +53,11 @@ device virtio_blk lsbfirst ( addr base ) "Virtio Block Device Specification" {
      * separate device-readable buffer; command length can be derived from the 
      * length of this buffer.
      */
-    datatype scsi_req lsbfirst(32) "SCSI trailer"{
-        /* request header */
-        /* cmd */
-        /* data */
-        /* sense buffer */
+    datatype scsi_req lsbfirst(32) "SCSI trailer"{     
         errors      32  "Errors that may have occurred";
         data_len    32  "Deprecated: Should be ignored.";
         sense_len   32  "The number of bytes in the sense buffer";
         residual    32  "The residual size: total - transferred";
-        status       8  "Request status";
-        _           24  "To make mackerel happy";
     };
     
     constants req_type "Possible request types for the block device" {
index 5f42154..775f420 100755 (executable)
@@ -1011,8 +1011,10 @@ errors virtio VIRTIO_ERR_ {
     failure NOT_VIRTIO_DEVICE    "The device is not a VirtIO device",
     failure VERSION_MISMATCH     "The VirtIO versions do mismatch",
     failure DEVICE_STATUS        "VirtIO device has the wrong status",
+    failure DEVICE_TYPE                         "The VirtIO device is not of the expected type",
     failure QUEUE_ACTIVE         "The selected qeueue is already activated",
     failure QUEUE_INVALID        "The selected queue does not exist",
+    failure QUEUE_BUSY                  "The queue is busy.",
     failure BUFFER_SIZE          "The buffer size is invalid.",
     failure BUFFER_STATE         "The state of the buffer / buffer list is invalid",               
     failure ARG_INVALID          "The given argument is invalid.",
@@ -1022,4 +1024,6 @@ errors virtio VIRTIO_ERR_ {
     failure NO_DESC_AVAIL        "There is no descriptor availabe",
     failure DEQ_CHAIN            "Not the entire chain could be dequeued",
     failure INVALID_RING_INDEX   "The supplied index is not valid", 
+    failure BLK_REQ_IOERR               "The request ended in an IO error",
+    failure BLK_REQ_UNSUP               "The request type was not supported",
 };
index 3d9fdae..6b8f873 100644 (file)
@@ -24,8 +24,6 @@ module        /x86_64/sbin/monitor
 module  /x86_64/sbin/ramfsd boot
 module  /x86_64/sbin/skb boot
 modulenounzip /skb_ramfs.cpio.gz nospawn
-modulenounzip /xeon_phi_multiboot_ramfs.cpio.gz nospawn
-module  /weever nospawn
 module  /x86_64/sbin/kaluga boot
 module  /x86_64/sbin/acpi boot
 module  /x86_64/sbin/spawnd boot
@@ -37,7 +35,11 @@ module /x86_64/sbin/routing_setup boot
 # Drivers
 module /x86_64/sbin/pci auto
 module /x86_64/sbin/ahcid auto
-module  /x86_64/sbin/xeon_phi auto
+module /x86_64/sbin/xeon_phi 
+module /x86_64/sbin/xeon_phi_manager
+
+module /x86_64/sbin/virtio_blk
+module /x86_64/sbin/virtio_blk_host
 
 ## For networking
 ## For qemu, enable rtl8029
@@ -59,3 +61,4 @@ module  /x86_64/sbin/xeon_phi auto
 #module        /x86_64/sbin/serial
 #module  /x86_64/sbin/fish nospawn
 #module        /x86_64/sbin/angler serial0.terminal xterm
+
index fd2ceca..81466a2 100644 (file)
@@ -177,7 +177,9 @@ MODULES_x86_64= \
        sbin/xeon_phi \
        sbin/xeon_phi_manager \
        sbin/spin \
-       sbin/xeon_phi_test
+       sbin/xeon_phi_test \
+       sbin/virtio_blk_host \
+       sbin/virtio_blk
 #      sbin/block_server \
 #      sbin/block_server_client \
 #      sbin/bs_user \
index a485241..ef71253 100644 (file)
@@ -71,6 +71,7 @@
                "xeon_phi",
                "xeon_phi_manager",
                "xeon_phi_messaging",
+               "virtio",
                "block_service",
                "bulk_ctrl",
                "arrakis",
diff --git a/if/virtio.if b/if/virtio.if
new file mode 100644 (file)
index 0000000..3115686
--- /dev/null
@@ -0,0 +1,30 @@
+/** \file
+ *  \brief VirtIO shared memory interface
+ */
+
+/*
+ * Copyright (c) 2012, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+interface virtio "VirtIO Interface" {
+    
+    /* open a new VirtIO device */
+    rpc open(in uint8 backend, out errval err, out cap devframe);
+    
+    /* closes a VirtIO Device */
+    rpc close();
+    
+    /* adds a new vring to the device */
+    rpc add(in uint16 vq_id, in uint16 ndesc, in cap vring, out errval err);
+    
+    /* extends the shared memory by a new cap */
+    rpc extend(in uint16 vq_id, in cap vbuf, out errval err);
+    
+    /* requests memory from the host to be used as vring / vbufs */
+    rpc req(in uint64 size, out errval err, out cap vring);
+};
\ No newline at end of file
index d81a690..0758206 100644 (file)
 /// the size of the VirtIO block device configuration spaces
 #define VIRTIO_BLOCK_CONFIG_SIZE 0x20
 
+/// the number of virtqueues for this device type
+#define VIRTIO_BLOCK_NUM_VIRTQUEUES 1
+
+#define VIRTIO_BLOCK_FLOUNDER_IFACE "vblk_host"
 /*
  * --------------------------------------------------------------------------
  * 5.2.3 Feature Bits
@@ -167,10 +171,6 @@ struct virtio_block_reqhdr
     /* the data and status follow */
 };
 
-struct virtio_block_request
-{
-    void *foo;
-};
 
 struct virtio_device_blk
 {
@@ -244,8 +244,8 @@ static inline uint32_t virtio_block_get_segment_num(struct virtio_device_blk *de
 static inline uint32_t virtio_block_get_segment_size(struct virtio_device_blk *dev)
 {
     if (!virtio_device_has_feature(dev->vdev, VIRTIO_BLOCK_F_SIZE_MAX)) {
-                return 0;
-            }
+        return 0;
+    }
     return virtio_blk_seg_size_max_rdf(&dev->config_space);
 }
 
@@ -275,4 +275,28 @@ bool virtio_block_get_topology(struct virtio_device_blk *dev,
 bool virtio_block_get_geometry(struct virtio_device_blk *dev,
                                            struct virtio_block_geometry *geo);
 
+/**
+ * \brief   handles the VirtIO block device common initialization.
+ *
+ * \param   dev     the VirtIO block device
+ * \param   setup   the setup information
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_block_init_device(struct virtio_device_blk *dev,
+                                  struct virtio_device_setup *setup);
+
+/**
+ * \brief   handles the VirtIO block device common initialization.
+ *
+ * \param   dev     the VirtIO block device
+ * \param   setup   the setup information
+ * \param   dev_cap the frame capability backing the device registers
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_block_init_device_with_cap(struct virtio_device_blk *dev,
+                                           struct virtio_device_setup *setup,
+                                           struct capref dev_cap);
+
 #endif // VIRTIO_DEVICES_VIRTIO_BLOCK_H
index 7a189ca..123725e 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef VIRTIO_VIRTIO_DEVICE_H
 #define VIRTIO_VIRTIO_DEVICE_H
 
+#include <virtio/virtqueue.h>
 
 struct virtio_device;
 
@@ -99,6 +100,16 @@ enum virtio_device_backend {
     VIRTIO_DEVICE_BACKEND_IO,
 };
 
+/**
+ * driver specific device status
+ */
+enum virtio_device_status {
+    VIRTIO_DEVICE_S_INVALID,
+    VIRTIO_DEVICE_S_INITIALIZING,
+    VIRTIO_DEVICE_S_READY,
+    VIRTIO_DEVICE_S_TERMINATING,
+    VIRTIO_DEVICE_S_ERROR,
+};
 /*
  * 4.1.2 PCI Device Discovery
  *
@@ -113,18 +124,25 @@ enum virtio_device_backend {
 
 #define VIRTIO_DEVICE_NAME_MAX 32
 
+
+typedef void (*config_intr_handler_t)(struct virtio_device *dev);
+
 /**
  * contains necessary values for the device initialization process
  */
 struct virtio_device_setup
 {
     uint8_t type;                           ///< expected type of the device
+    void *device_type;
     char name[VIRTIO_DEVICE_NAME_MAX];
     enum virtio_device_backend  backend;    ///< which backend to use
     void *dev_reg;
     size_t dev_reg_size;
-    errval_t (*feature_negotiate)(struct virtio_device *dev);
-    errval_t (*device_setup)(struct virtio_device *dev);
+    uint64_t driver_features;
+
+    uint16_t vq_num;
+    struct virtqueue_setup *vq_setup;
+    config_intr_handler_t cfg_intr_handler;
 };
 
 
@@ -190,14 +208,19 @@ errval_t virtio_device_get_status(struct virtio_device *dev,
 errval_t virtio_device_set_status(struct virtio_device *dev,
                                   uint8_t status);
 
+errval_t virtio_device_set_driver_features(struct virtio_device *dev,
+                                           uint64_t features);
 
-errval_t virtio_device_feature_negotiate(struct virtio_device *dev);
+errval_t virtio_device_get_device_features(struct virtio_device *dev,
+                                           uint64_t *ret_features);
 
 errval_t virtio_device_specific_setup(struct virtio_device *dev);
 
 bool     virtio_device_has_feature(struct virtio_device *dev,
                                    uint8_t feature);
 
+errval_t virtio_device_feature_negotiate(struct virtio_device *dev,
+                                         uint64_t driver_features);
 
 /**
  * \brief reads the device configuration space and copies it into a local buffer
@@ -219,11 +242,44 @@ errval_t virtio_device_config_read(struct virtio_device *vdev,
  * \param len   the length of the buffer
  *
  * \returns SYS_ERR_OK on success
- *
- * xxx: this may be done at a certain offset/value combination
  */
 errval_t virtio_device_config_write(struct virtio_device *dev,
                                     void *config,
+                                    size_t offset,
                                     size_t length);
 
+
+/**
+ * \brief Returns the pointer to the device specific structure
+ *
+ * \param vdev to get the device specific pointer
+ *
+ * \returns device specific struct pointer
+ */
+void *virtio_device_get_struct(struct virtio_device *vdev);
+
+/**
+ * \brief allocates the virtqueues for this device based on the setup information
+ *
+ * \param vdev      virtio device to allocate the queues for
+ * \param vq_setup  setup information for the virtqueues
+ * \param vq_num    number of virtqueues to allocate
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_device_virtqueue_alloc(struct virtio_device *vdev,
+                                       struct virtqueue_setup *vq_setup,
+                                       uint16_t vq_num);
+
+/**
+ * \brief returns a pointer to a virtqueue of the device
+ *
+ * \param vdev   VirtIO device
+ * \param vq_idx the queue index of the queue we want
+ *
+ * \returns pointer to the requested virtqueue
+ *          NULL if no such virtqueue exists
+ */
+struct virtqueue *virtio_device_get_virtq(struct virtio_device *vdev,
+                                          uint16_t vq_idx);
 #endif // VIRTIO_VIRTIO_DEVICE_H
diff --git a/include/virtio/virtio_guest.h b/include/virtio/virtio_guest.h
new file mode 100644 (file)
index 0000000..d2046e9
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef VIRTIO_GUEST_H
+#define VIRTIO_GUEST_H
+
+/**
+ * represents the channel backend to be used for this VirtIO guest library
+ */
+enum virtio_guest_channel
+{
+    VIRTIO_GUEST_CHAN_INVALID,  ///< the channel type is invalid
+    VIRTIO_GUEST_CHAN_FLOUNDER, ///< the flounder RPC backend should be used
+    VIRTIO_GUEST_CHAN_XEON_PHI, ///< the xeon phi messaging backend should be used
+};
+
+/**
+ * holds the function pointers to the respective channel backends
+ */
+struct virtio_guest_chan_fn
+{
+    errval_t (*open)(uint8_t backend, struct capref *ret_frame);
+    errval_t (*close)(void);
+    errval_t (*add)(uint16_t vq_id, uint16_t ndesc, struct capref frame);
+    errval_t (*ext)(uint16_t vq_id, struct capref vbuf);
+    errval_t (*req)(uint64_t size, struct capref *cap);
+};
+
+extern struct virtio_guest_chan_fn *vguest_chan_fn;
+
+/**
+ *
+ */
+errval_t virtio_guest_init(enum virtio_guest_channel backend,
+                           char *iface);
+
+/**
+ *
+ */
+static inline errval_t virtio_guest_open_device(uint8_t backend,
+                                                struct capref *ret_frame)
+{
+    return vguest_chan_fn->open(backend, ret_frame);
+}
+
+/**
+ *
+ */
+static inline errval_t virtio_guest_close_device(void)
+{
+    return vguest_chan_fn->close();
+}
+
+/**
+ *
+ */
+static inline errval_t virtio_guest_add_vring(uint16_t vq_id,
+                                              uint16_t ndesc,
+                                              struct capref frame)
+{
+    return vguest_chan_fn->add(vq_id, ndesc, frame);
+}
+
+/**
+ *
+ */
+static inline errval_t virtio_guest_extend_vring(uint16_t vq_id,
+                                                 struct capref vbuf)
+{
+    return vguest_chan_fn->ext(vq_id, vbuf);
+}
+
+/**
+ *
+ */
+static inline errval_t virtio_guest_request_mem(uint64_t size,
+                                                struct capref *cap)
+{
+    return vguest_chan_fn->req(size, cap);
+}
+
+#endif // VIRTIO_GUEST_H
diff --git a/include/virtio/virtio_host.h b/include/virtio/virtio_host.h
new file mode 100644 (file)
index 0000000..c20606f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef VIRTIO_HOST_H
+#define VIRTIO_HOST_H
+
+struct virtio_host;
+
+/**
+ * represents the channel backend to be used for this VirtIO guest library
+ */
+enum virtio_host_channel
+{
+    VIRTIO_HOST_CHAN_INVALID,  ///< the channel type is invalid
+    VIRTIO_HOST_CHAN_FLOUNDER, ///< the flounder RPC backend should be used
+    VIRTIO_HOST_CHAN_XEON_PHI, ///< the xeon phi messaging backend should be used
+};
+
+
+struct virtio_host_cb
+{
+    errval_t (*open)(struct capref *ret_frame, void **st);
+};
+
+struct virtio_host_setup
+{
+    uint8_t device_type;
+    void *dev_reg;
+    lpaddr_t dev_size;
+    struct capref dev_cap;
+    enum virtio_host_channel channel_type;
+    enum virtio_device_backend backend;
+    char *iface;
+    struct virtio_host_cb *callback;
+};
+
+
+/**
+ *
+ */
+errval_t virtio_host_init(struct virtio_host **host,
+                          struct virtio_host_setup *setup);
+
+
+errval_t virtio_host_poll_device(struct virtio_host *host);
+
+errval_t virtio_host_get_device_cap(struct virtio_host *host,
+                                    struct capref *ret_cap);
+
+#endif // VIRTIO_GUEST_H
index 029a4fb..4bacb11 100644 (file)
                           "vbuffer.c",
                           "backends/virtio_device_mmio.c",
                           "backends/virtio_device_pci.c",
-                          "devices/virtio_block.c" ],
+                          "devices/virtio_block.c",
+                          "guest.c",
+                          "guest/channel_flounder.c",
+                          "guest/channel_xeon_phi.c"
+                           ],
                       mackerelDevices = [ "virtio/virtio_mmio",
-                                          "virtio/virtio_pci" ]
+                                          "virtio/virtio_pci" ],
+                  flounderBindings = [ "virtio" ],
+                  flounderExtraBindings = [ ("virtio", ["rpcclient"])]
                 },
   build library { target = "virtio_host",
                   addCFlags = [ "-DVIRTIO_HOST" ],
                                  "vbuffer.c",
                                  "backends/virtio_device_mmio.c",
                                  "backends/virtio_device_pci.c",
-                                 "devices/virtio_block.c" ],
+                                 "devices/virtio_block.c",
+                                 "host.c",
+                                    "host/channel_flounder.c",
+                                        "host/channel_xeon_phi.c" ],
                       mackerelDevices = [ "virtio/virtio_mmio",
-                                          "virtio/virtio_pci" ]
+                                          "virtio/virtio_pci" ],
+                    flounderBindings = [ "virtio" ]
                 }                
 ]
index af16f27..640ddc5 100644 (file)
@@ -14,6 +14,8 @@
 #include <virtio/virtio_ring.h>
 #include <virtio/virtio_device.h>
 
+#include <virtio/virtio_host.h>
+
 #include <dev/virtio/virtio_mmio_dev.h>
 
 
@@ -331,3 +333,76 @@ errval_t virtio_device_mmio_init(struct virtio_device **dev,
 
     return SYS_ERR_OK;
 }
+
+
+static errval_t virtio_device_mmio_poll_host(struct virtio_host *host)
+{
+    return SYS_ERR_OK;
+}
+
+/**
+ * \brief initializes a VirtIO device on the host side using the MMIO transpot
+ *
+ * \param dev   returns a pointer to the newly allocated device structure
+ * \param info  initialization parameters
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_device_mmio_init_host(struct virtio_host **host,
+                                      struct virtio_host_setup *setup)
+{
+    struct virtio_host_mmio *mmio_host;
+    errval_t err;
+
+    mmio_host = malloc(sizeof(*mmio_host));
+    if (mmio_host == NULL) {
+        return LIB_ERR_MALLOC_FAIL;
+    }
+
+    /*
+     * TODO> Check for minimum MMIO devie size
+     */
+
+    if (setup->dev_reg == NULL) {
+        setup->dev_size +=VIRTIO_MMIO_DEVICE_SIZE;
+        err = frame_alloc(&mmio_host->host.dev_frame,
+                          setup->dev_size,
+                          &setup->dev_size);
+        if (err_is_fail(err)) {
+            free(mmio_host);
+            return err;
+        }
+
+        err = vspace_map_one_frame_attr(&setup->dev_reg,
+                                        setup->dev_size,
+                                        mmio_host->host.dev_frame,
+                                        VIRTIO_VREGION_FLAGS_DEVICE,
+                                        NULL,
+                                        NULL);
+        if (err_is_fail(err)) {
+            cap_destroy(mmio_host->host.dev_frame);
+            free(mmio_host);
+            return err;
+        }
+    } else {
+        assert(setup->dev_size > VIRTIO_MMIO_DEVICE_SIZE);
+        mmio_host->host.dev_frame = setup->dev_cap;
+    }
+
+    mmio_host->host.device_base = setup->dev_reg;
+    mmio_host->host.dev_size = setup->dev_size;
+    virtio_mmio_initialize(&mmio_host->regs, (mackerel_addr_t) (setup->dev_reg));
+
+    /* initialize the device with values */
+    virtio_mmio_magic_value_wr(&mmio_host->regs, virtio_mmio_magic_value);
+    virtio_mmio_deviceid_id_wrf(&mmio_host->regs, setup->device_type);
+    virtio_mmio_version_version_wrf(&mmio_host->regs, virtio_mmio_version_virtio10);
+
+
+    mmio_host->host.poll = virtio_device_mmio_poll_host;
+
+    return SYS_ERR_OK;
+
+}
+
+
index c9c88a8..167fc56 100644 (file)
 
 #include <dev/virtio/virtio_mmio_dev.h>
 
-
+#define VIRTIO_MMIO_DEVICE_SIZE 0x100
 
 struct virtio_device_mmio
 {
     struct virtio_device dev;
     virtio_mmio_t regs;
+};
 
+struct virtio_host_mmio
+{
+    struct virtio_host host;
+    virtio_mmio_t regs;
 };
 
+
 /**
  * \brief initializes and allocates a VirtIO device structure for the MMIO backend
  *
@@ -35,6 +41,17 @@ errval_t virtio_device_mmio_init(struct virtio_device **dev,
                                  struct virtio_device_setup *info);
 
 
+/**
+ * \brief initializes a VirtIO device on the host side using the MMIO transpot
+ *
+ * \param dev   returns a pointer to the newly allocated device structure
+ * \param info  initialization parameters
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_device_mmio_init_host(struct virtio_host **host,
+                                      struct virtio_host_setup *setup);
+
 
 
 #endif // VIRTIO_VIRTIO_MMIO_H
index 2a90637..9135ab4 100644 (file)
 #ifndef VIRTIO_DEBUG_H_
 #define VIRTIO_DEBUG_H_
 
+/// Global VirtIO debug switch
 #define VIRTIO_DEBUG_ENABLED 1
+
+/// Enables the virtqueue debugging
 #define VIRTIO_DEBUG_VQ_ENABLED 1
+
+/// Enables the VirtIO general device debugging messages
 #define VIRTIO_DEBUG_DEV_ENABLED 1
 
+/// Enables the VirtIO device specific debugging messages
+#define VIRTIO_DEBUG_DT_ENABLED 1
+
+/// Enables the VirtIO transport layer debug messages
+#define VIRTIO_DEBUG_TL_ENABLED 1
+
+/// Enables the VirtIO management layer debug messages
+#define VIRTIO_DEBUG_CHAN_ENABLED 1
+
 #if VIRTIO_DEBUG_ENABLED
 #define VIRTIO_DEBUG_PRINT(msg...) debug_printf(msg)
 #else
 #endif
 
 #ifdef VIRTIO_DEBUG_VQ_ENABLED
-#define VIRTIO_DEBUG_VQ(msg...) VIRTIO_DEBUG_PRINT("[VIRTQUEUE] " msg)
+#define VIRTIO_DEBUG_VQ(msg...) VIRTIO_DEBUG_PRINT("[virtq] " msg)
 #else
 #define VIRTIO_DEBUG_VQ(msg...)
 #endif
 
 #ifdef VIRTIO_DEBUG_DEV_ENABLED
-#define VIRTIO_DEBUG_DEV(msg...) VIRTIO_DEBUG_PRINT("[VIRTIO DEV] " msg)
+#define VIRTIO_DEBUG_DEV(msg...) VIRTIO_DEBUG_PRINT("[virtio dev] " msg)
 #else
 #define VIRTIO_DEBUG_DEV(msg...)
 #endif
 
+#ifdef VIRTIO_DEBUG_DT_ENABLED
+#define VIRTIO_DEBUG_DT(msg...) VIRTIO_DEBUG_PRINT("[virtio type] " msg)
+#else
+#define VIRTIO_DEBUG_DT(msg...)
+#endif
+
+#ifdef VIRTIO_DEBUG_TL_ENABLED
+#define VIRTIO_DEBUG_TL(msg...) VIRTIO_DEBUG_PRINT("[virtio tl] " msg)
+#else
+#define VIRTIO_DEBUG_TL(msg...)
+#endif
+
+#ifdef VIRTIO_DEBUG_CHAN_ENABLED
+#define VIRTIO_DEBUG_CHAN(msg...) VIRTIO_DEBUG_PRINT("[virtio chan] " msg)
+#else
+#define VIRTIO_DEBUG_CHAN(msg...)
+#endif
 
 #endif /* VIRTIO_DEBUG_H_ */
index bf27a34..2562a7c 100644 (file)
@@ -31,6 +31,9 @@ errval_t virtio_device_open(struct virtio_device **dev,
 {
     errval_t err = SYS_ERR_OK;
 
+    VIRTIO_DEBUG_DEV("virtio_device_open: [%s] @ [%016lx]\n", init->name,
+                     (uintptr_t)init->dev_reg);
+
     if (init->dev_reg == NULL || init->dev_reg_size == 0) {
         /*
          * XXX: does this also hold for the PCI
@@ -56,6 +59,7 @@ errval_t virtio_device_open(struct virtio_device **dev,
             break;
         default:
             err = VIRTIO_ERR_BACKEND;
+            VIRTIO_DEBUG_DEV("ERROR: unsupported backend: %u\n", init->backend);
             break;
     }
 
@@ -65,6 +69,8 @@ errval_t virtio_device_open(struct virtio_device **dev,
 
     struct virtio_device *vdev = *dev;
 
+    vdev->state = VIRTIO_DEVICE_S_INITIALIZING;
+
     /* 1. Reset the device. */
     err = virtio_device_reset(vdev);
     if (err_is_fail(err)) {
@@ -86,7 +92,7 @@ errval_t virtio_device_open(struct virtio_device **dev,
     /* 4. Read device feature bits, and write the subset of feature bits understood by the OS and driver to the
      device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration
      fields to check that it can support the device before accepting it.*/
-    err = virtio_device_feature_negotiate(vdev);
+    err = virtio_device_feature_negotiate(vdev, init->driver_features);
     if (err_is_fail(err)) {
         goto failed;
     }
@@ -99,7 +105,7 @@ errval_t virtio_device_open(struct virtio_device **dev,
 
     /* 6. Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not
      support our subset of features and the device is unusable.*/
-    uint8_t status;
+    uint8_t status = 0;
     err = virtio_device_get_status(vdev, &status);
     assert(err_is_ok(err));
 
@@ -117,10 +123,6 @@ errval_t virtio_device_open(struct virtio_device **dev,
     err = virtio_device_set_status(vdev, VIRTIO_DEVICE_STATUS_DRIVER_OK);
     assert(err_is_ok(err));
 
-    if (init->device_setup) {
-        return init->device_setup(vdev);
-    }
-
     return SYS_ERR_OK;
 
     failed: virtio_device_set_status(vdev, VIRTIO_DEVICE_STATUS_FAILED);
@@ -191,10 +193,179 @@ bool     virtio_device_has_feature(struct virtio_device *dev,
     /*
      * if the device is not configured yet, we don't know the features
      */
-    if(dev->status & VIRTIO_DEVICE_STATUS_FEATURES_OK) {
+    if(dev->status_flags & VIRTIO_DEVICE_STATUS_FEATURES_OK) {
         return false;
     }
 
     return (dev->features & (1UL<<feature)) != 0;
 }
 
+
+/**
+ * \brief resets the virtio device
+ *
+ * \param dev   the device to reset
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_device_reset(struct virtio_device *dev)
+{
+    VIRTIO_DEBUG_DEV("resetting device: %s\n", dev->name);
+    assert(!"NYI:");
+    return SYS_ERR_OK;
+}
+
+/**
+ * \brief returns the status of a virtio device
+ *
+ * \param the device to query for status
+ * \param returned status
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_device_get_status(struct virtio_device *dev,
+                                  uint8_t *ret_status)
+{
+    assert(!"NYI:");
+    return SYS_ERR_OK;
+}
+
+/**
+ * \brief
+ *
+ * \param
+ */
+errval_t virtio_device_set_status(struct virtio_device *dev,
+                                  uint8_t status)
+{
+    assert(!"NYI:");
+    return SYS_ERR_OK;
+}
+
+/**
+ * \brief Returns the pointer to the device specific structure
+ *
+ * \param vdev to get the device specific pointer
+ *
+ * \returns device specific struct pointer
+ */
+void *virtio_device_get_struct(struct virtio_device *vdev)
+{
+    assert(!"NYI:");
+    return NULL;
+}
+
+
+/**
+ * \brief reads the device configuration space and copies it into a local buffer
+ *
+ * \param vdev  virtio device
+ * \param buf   pointer to the buffer to store the data
+ * \param len   the length of the buffer
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_device_config_read(struct virtio_device *vdev,
+                                  void *buf,
+                                  size_t len)
+{
+    assert(!"NYI:");
+    return SYS_ERR_OK;
+}
+
+/**
+ * \brief writes to the configuration space of a device
+ *
+ * \param vdev  virtio device
+ * \param buf   pointer to the buffer with data to update
+ * \param len   the length of the buffer
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_device_config_write(struct virtio_device *dev,
+                                    void *config,
+                                    size_t offset,
+                                    size_t length)
+{
+    assert(!"NYI:");
+    return SYS_ERR_OK;
+}
+
+
+errval_t virtio_device_set_driver_features(struct virtio_device *dev,
+                                           uint64_t features)
+{
+    assert(!"NYI:");
+    return SYS_ERR_OK;
+}
+
+errval_t virtio_device_get_device_features(struct virtio_device *dev,
+                                           uint64_t *ret_features)
+{
+    assert(!"NYI:");
+    return SYS_ERR_OK;
+}
+
+errval_t virtio_device_feature_negotiate(struct virtio_device *dev,
+                                         uint64_t driver_features)
+{
+    assert(!"NYI:");
+    return dev->f->negotiate_features(dev, driver_features);
+}
+
+/**
+ * \brief allocates the virtqueues for this device based on the setup information
+ *
+ * \param vdev      virtio device to allocate the queues for
+ * \param vq_setup  setup information for the virtqueues
+ * \param vq_num    number of virtqueues to allocate
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_device_virtqueue_alloc(struct virtio_device *vdev,
+                                       struct virtqueue_setup *vq_setup,
+                                       uint16_t vq_num)
+{
+    errval_t err;
+
+    vdev->vq = calloc(vq_num, sizeof(void *));
+    if (vdev->vq == NULL) {
+        return LIB_ERR_MALLOC_FAIL;
+    }
+
+    struct virtqueue_setup *setup;
+    for(uint16_t i = 0; i < vq_num; ++i) {
+        setup = &vq_setup[i];
+        setup->queue_id = i;
+        setup->device = vdev;
+        err = virtio_virtqueue_alloc(setup, &vdev->vq[i]);
+        if (err_is_fail(err)) {
+            for (uint16_t j = 0; j < i; ++j) {
+                virtio_virtqueue_free(vdev->vq[i]);
+            }
+            free(vdev->vq);
+            return err;
+        }
+    }
+
+    return SYS_ERR_OK;
+}
+
+/**
+ * \brief returns a pointer to a virtqueue of the device
+ *
+ * \param vdev   VirtIO device
+ * \param vq_idx the queue index of the queue we want
+ *
+ * \returns pointer to the requested virtqueue
+ *          NULL if no such virtqueue exists
+ */
+struct virtqueue *virtio_device_get_virtq(struct virtio_device *vdev,
+                                          uint16_t vq_idx)
+{
+    if (vq_idx < vdev->vq_num) {
+        return vdev->vq[vq_idx];
+    }
+
+    return NULL;
+}
index 0e8de37..ffed491 100644 (file)
 #define VIRTIO_DEVICE_H
 
 #include <virtio/virtio_device.h>
+#include <virtio/virtio_host.h>
 
 // forward declaration
 struct virtqueue;
 
+struct virtio_host
+{
+    uint8_t device_type;
+    struct capref dev_frame;
+    lpaddr_t dev_size;
+    void *device_base;
+    enum virtio_device_backend backend;
+    struct virtio_host_cb *callback;
+    errval_t (*poll)(struct virtio_host *);
+};
 
 /**
- * represents a virtio device
+ * represents a virtio device, this data structure is only valid with the
+ * backend specific extentions and should not be allocated directly
  */
 struct virtio_device
 {
     char name[VIRTIO_DEVICE_NAME_MAX];
     uint32_t devid;
+
     uint8_t type;
-    uint8_t status;
+    void *device_type;
+
+    uint8_t status_flags;
+    enum virtio_device_status state;
+
     uint64_t features;
     enum virtio_device_backend backend;
     struct virtio_device_fn *f;
+
+    uint16_t vq_num;
+    struct virtqueue **vq;
 };
 
 /**
index 4dd5ad6..0415aa8 100644 (file)
@@ -15,6 +15,9 @@
 
 #include <dev/virtio/virtio_blk_dev.h>
 
+#include "device.h"
+#include "debug.h"
+
 /**
  * \brief   returns the topology information
  *
@@ -96,3 +99,103 @@ errval_t virtio_block_config_read(struct virtio_device_blk *dev)
                                      dev->config_addr,
                                      VIRTIO_BLOCK_CONFIG_SIZE);
 }
+
+/**
+ * \brief   handles the VirtIO block device common initialization.
+ *
+ * \param   dev     the VirtIO block device
+ * \param   setup   the setup information
+ *
+ * \returns SYS_ERR_OK on success
+ */
+static errval_t virtio_block_init_common(struct virtio_device_blk *dev,
+                                         struct virtio_device_setup *setup)
+{
+    errval_t err;
+
+    /* read the device configuration */
+    err = virtio_block_config_read(dev);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    if (setup->vq_num != VIRTIO_BLOCK_NUM_VIRTQUEUES) {
+        /*
+         * TODO: handle this case.
+         */
+        assert(setup->vq_num == VIRTIO_BLOCK_NUM_VIRTQUEUES);
+    }
+
+    /*
+     * allocate the virtqueues
+     */
+    err = virtio_device_virtqueue_alloc(dev->vdev, setup->vq_setup, setup->vq_num);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    dev->vq = virtio_device_get_virtq(dev->vdev, 0);
+    assert(dev->vq);
+
+    dev->vdev->state = VIRTIO_DEVICE_S_READY;
+
+    return SYS_ERR_OK;
+}
+
+
+/**
+ * \brief   handles the VirtIO block device specific initialization.
+ *          with the device registers already mapped
+ *
+ * \param   dev     the VirtIO block device
+ * \param   setup   the setup information
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_block_init_device(struct virtio_device_blk *dev,
+                                  struct virtio_device_setup *setup)
+{
+    errval_t err;
+
+    if (setup->type != VIRTIO_DEVICE_TYPE_BLOCK) {
+        VIRTIO_DEBUG_DT("ERROR: Device type was not VIRTIO_DEVICE_TYPE_BLOCK\n");
+        return VIRTIO_ERR_DEVICE_TYPE;
+    }
+
+    /* initialize the VirtIO device */
+    err = virtio_device_open(&dev->vdev, setup);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    return virtio_block_init_common(dev, setup);
+}
+
+/**
+ * \brief   handles the VirtIO block device specific initialization.
+ *          the device registers are not mapped yet
+ *
+ * \param   dev     the VirtIO block device
+ * \param   setup   the setup information
+ * \param   dev_cap the frame capability backing the device registers
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_block_init_device_with_cap(struct virtio_device_blk *dev,
+                                           struct virtio_device_setup *setup,
+                                           struct capref dev_cap)
+{
+    errval_t err;
+
+    if (setup->type != VIRTIO_DEVICE_TYPE_BLOCK) {
+        return VIRTIO_ERR_DEVICE_TYPE;
+    }
+
+    /* initialize the VirtIO device */
+    err = virtio_device_open_with_cap(&dev->vdev, setup, dev_cap);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    return virtio_block_init_common(dev, setup);
+}
diff --git a/lib/virtio/guest.c b/lib/virtio/guest.c
new file mode 100644 (file)
index 0000000..01106fb
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <virtio/virtio_guest.h>
+
+#include "guest/channel.h"
+
+struct virtio_guest_chan_fn *vguest_chan_fn = NULL;
+
+/**
+ *
+ */
+errval_t virtio_guest_init(enum virtio_guest_channel backend,
+                           char *iface)
+{
+    errval_t err;
+
+    switch (backend) {
+    case VIRTIO_GUEST_CHAN_FLOUNDER:
+        err = virtio_guest_flounder_init(iface);
+        break;
+
+    case VIRTIO_GUEST_CHAN_XEON_PHI:
+        err = virtio_guest_xeon_phi_init();
+        break;
+    default:
+        err = -1;
+        break;
+    }
+
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    assert(vguest_chan_fn);
+
+    return SYS_ERR_OK;
+}
diff --git a/lib/virtio/guest/channel.h b/lib/virtio/guest/channel.h
new file mode 100644 (file)
index 0000000..8d51945
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef VIRTIO_GUEST_CHANNEL_H
+#define VIRTIO_GUEST_CHANNEL_H
+
+
+errval_t virtio_guest_flounder_init(char *iface);
+
+
+
+errval_t virtio_guest_xeon_phi_init(void);
+
+
+#endif // VIRTIO_GUEST_CHANNEL_H
diff --git a/lib/virtio/guest/channel_flounder.c b/lib/virtio/guest/channel_flounder.c
new file mode 100644 (file)
index 0000000..c1d730d
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/nameservice_client.h>
+#include <virtio/virtio_guest.h>
+
+#include <if/virtio_defs.h>
+#include <if/virtio_rpcclient_defs.h>
+
+#include "channel.h"
+#include "debug.h"
+
+
+static struct virtio_rpc_client virtio_rpc_client;
+
+static iref_t virtio_rpc_svc_iref;
+
+enum virtio_rpc_client_state {
+    RPC_CLIENT_STATE_INVALID,
+    RPC_CLIENT_STATE_BINDING,
+    RPC_CLIENT_STATE_FAILED,
+    RPC_CLIENT_STATE_READY
+};
+
+static enum virtio_rpc_client_state rpc_client_state = RPC_CLIENT_STATE_INVALID;
+
+
+/**
+ *
+ */
+static  errval_t open_device(uint8_t backend,
+                             struct capref *ret_frame)
+{
+    errval_t err, msg_err;
+
+    VIRTIO_DEBUG_CHAN("open device\n");
+
+    if (rpc_client_state != RPC_CLIENT_STATE_READY) {
+        /* TODO: error code */
+        return -1;
+    }
+
+    err = virtio_rpc_client.vtbl.open(&virtio_rpc_client,
+                                      backend,
+                                      &msg_err,
+                                      ret_frame);
+    if (err_is_fail(err)) {
+        return err;
+    }
+    return msg_err;
+}
+
+/**
+ *
+ */
+static  errval_t close_device(void)
+{
+    errval_t err;
+
+    if (rpc_client_state != RPC_CLIENT_STATE_READY) {
+        /* TODO: error code */
+        return -1;
+    }
+
+    err =  virtio_rpc_client.vtbl.close(&virtio_rpc_client);
+    if (err_is_fail(err)) {
+        return err;
+    }
+    return SYS_ERR_OK;
+}
+
+/**
+ *
+ */
+static  errval_t add_vring(uint16_t vq_id,
+                           uint16_t ndesc,
+                           struct capref frame)
+{
+    errval_t err, msg_err;
+
+    if (rpc_client_state != RPC_CLIENT_STATE_READY) {
+        /* TODO: error code */
+        return -1;
+    }
+
+    err =  virtio_rpc_client.vtbl.add(&virtio_rpc_client, vq_id, ndesc, frame, &msg_err);
+    if (err_is_fail(err)) {
+        return err;
+    }
+    return msg_err;
+}
+
+/**
+ *
+ */
+static  errval_t extend_vring(uint16_t vq_id,
+                              struct capref vbuf)
+{
+    errval_t err, msg_err;
+
+    if (rpc_client_state != RPC_CLIENT_STATE_READY) {
+        /* TODO: error code */
+        return -1;
+    }
+
+    err =  virtio_rpc_client.vtbl.extend(&virtio_rpc_client, vq_id, vbuf, &msg_err);
+    if (err_is_fail(err)) {
+        return err;
+    }
+    return msg_err;
+}
+
+/**
+ *
+ */
+static  errval_t request_mem(uint64_t size,
+                             struct capref *cap)
+{
+    errval_t err, msg_err;
+
+    if (rpc_client_state != RPC_CLIENT_STATE_READY) {
+        /* TODO: error code */
+        return -1;
+    }
+
+    err =  virtio_rpc_client.vtbl.req(&virtio_rpc_client, size, &msg_err, cap);
+    if (err_is_fail(err)) {
+        return err;
+    }
+    return msg_err;
+}
+
+
+static struct virtio_guest_chan_fn vguest_fc_fn =  {
+    .open = open_device,
+    .close = close_device,
+    .add = add_vring,
+    .ext = extend_vring,
+    .req = request_mem,
+};
+
+static void bind_cb(void *st, errval_t err, struct virtio_binding *b)
+{
+    if(err_is_fail(err)) {
+        rpc_client_state = RPC_CLIENT_STATE_FAILED;
+        return;
+    }
+
+    VIRTIO_DEBUG_CHAN("Initializing RPC client\n");
+    err = virtio_rpc_client_init(&virtio_rpc_client, b);
+    if (err_is_fail(err)) {
+        rpc_client_state = RPC_CLIENT_STATE_FAILED;
+    }
+
+    vguest_chan_fn = &vguest_fc_fn;
+
+    rpc_client_state = RPC_CLIENT_STATE_READY;
+}
+
+
+
+
+
+errval_t virtio_guest_flounder_init(char *iface)
+{
+    errval_t err;
+
+    VIRTIO_DEBUG_CHAN("looking up iface [%s]\n", iface);
+    err = nameservice_blocking_lookup(iface, &virtio_rpc_svc_iref);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    VIRTIO_DEBUG_CHAN("initiate binding to iref [%u]\n", virtio_rpc_svc_iref);
+
+    rpc_client_state = RPC_CLIENT_STATE_BINDING;
+
+    err = virtio_bind(virtio_rpc_svc_iref,
+                      bind_cb,
+                      NULL,
+                      get_default_waitset(),
+                      IDC_BIND_FLAGS_DEFAULT);
+
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    VIRTIO_DEBUG_CHAN("Waiting for binding reply\n");
+    while(rpc_client_state == RPC_CLIENT_STATE_BINDING) {
+        messages_wait_and_handle_next();
+    }
+
+    if (rpc_client_state == RPC_CLIENT_STATE_FAILED) {
+        VIRTIO_DEBUG_CHAN("Bind failed\n");
+        return FLOUNDER_ERR_BIND;
+    }
+
+    VIRTIO_DEBUG_CHAN("Host channel ready\n");
+
+    return SYS_ERR_OK;
+}
diff --git a/lib/virtio/guest/channel_xeon_phi.c b/lib/virtio/guest/channel_xeon_phi.c
new file mode 100644 (file)
index 0000000..97e187e
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+
+#include "channel.h"
+
+errval_t virtio_guest_xeon_phi_init(void)
+{
+    return SYS_ERR_OK;
+}
diff --git a/lib/virtio/host.c b/lib/virtio/host.c
new file mode 100644 (file)
index 0000000..25e819a
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+
+#include <virtio/virtio.h>
+#include <virtio/virtio_device.h>
+#include <virtio/virtio_host.h>
+
+#include "device.h"
+
+#include "backends/virtio_mmio.h"
+#include "backends/virtio_pci.h"
+
+#include "host/channel.h"
+
+
+/**
+ *
+ */
+/**
+ *
+ */
+errval_t virtio_host_init(struct virtio_host **host,
+                          struct virtio_host_setup *setup)
+{
+    errval_t err = SYS_ERR_OK;
+
+    switch(setup->backend) {
+    case  VIRTIO_DEVICE_BACKEND_PCI:
+        assert(!"NYI: PCI backend");
+    break;
+
+    case VIRTIO_DEVICE_BACKEND_MMIO:
+        err = virtio_device_mmio_init_host(host, setup);
+        break;
+    case VIRTIO_DEVICE_BACKEND_IO:
+        assert(!"NYI: IO backend");
+        break;
+    default:
+
+        break;
+    }
+
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    switch (setup->channel_type) {
+    case VIRTIO_HOST_CHAN_FLOUNDER:
+        err = virtio_host_flounder_init(setup->iface, setup->callback);
+        break;
+
+    case VIRTIO_HOST_CHAN_XEON_PHI:
+        err = virtio_host_xeon_phi_init();
+        break;
+    default:
+        err = -1;
+        break;
+    }
+
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    return SYS_ERR_OK;
+}
+
+errval_t virtio_host_poll_device(struct virtio_host *host)
+{
+    return SYS_ERR_OK;
+}
+
+errval_t virtio_host_get_device_cap(struct virtio_host *host,
+                                    struct capref *ret_cap)
+{
+    if(ret_cap) {
+        *ret_cap = host->dev_frame;
+    }
+    return SYS_ERR_OK;
+}
diff --git a/lib/virtio/host/channel.h b/lib/virtio/host/channel.h
new file mode 100644 (file)
index 0000000..06d3209
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef VIRTIO_HOST_CHANNEL_H
+#define VIRTIO_HOST_CHANNEL_H
+
+
+errval_t virtio_host_flounder_init(char *iface,
+                                   struct virtio_host_cb *callbacks);
+
+
+errval_t virtio_host_xeon_phi_init(void);
+
+
+#endif // VIRTIO_GUEST_CHANNEL_H
diff --git a/lib/virtio/host/channel_flounder.c b/lib/virtio/host/channel_flounder.c
new file mode 100644 (file)
index 0000000..d778218
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/nameservice_client.h>
+
+#include <virtio/virtio.h>
+#include <virtio/virtio_device.h>
+#include <virtio/virtio_host.h>
+
+#include <if/virtio_defs.h>
+#include <if/virtio_rpcclient_defs.h>
+
+#include "channel.h"
+#include "debug.h"
+
+
+static struct virtio_binding *virtio_binding = NULL;
+
+static iref_t virtio_rpc_svc_iref;
+
+struct virtio_host_cb *host_cb;
+
+enum virtio_rpc_host_state {
+    RPC_HOST_STATE_INVALID,
+    RPC_HOST_STATE_EXPORTING,
+    RPC_HOST_STATE_FAILED,
+    RPC_HOST_STATE_READY
+};
+
+static enum virtio_rpc_host_state rpc_client_state = RPC_HOST_STATE_INVALID;
+
+/* -------------------- virtio_open() --------------------------------------- */
+
+struct open_response_state
+{
+    struct virtio_binding *b;
+    errval_t err;
+    struct capref frame;
+};
+
+struct open_response_state err_st;
+
+
+static void virtio_open_response(void *a)
+{
+    errval_t err;
+    struct open_response_state *st = a;
+
+    struct event_closure txcont = MKCONT(free, st);
+    err = virtio_open_response__tx(st->b, txcont, st->err, st->frame);
+    if (err_is_fail(err)) {
+        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
+            txcont = MKCONT(virtio_open_response, st);
+            err = st->b->register_send(st->b, get_default_waitset(), txcont);
+            if (err_is_fail(err)) {
+                DEBUG_ERR(err, "register send failed\n");
+                free(st);
+            }
+        } else {
+            DEBUG_ERR(err, "sending reply failed\n");
+            free(st);
+        }
+    }
+}
+
+static void virtio_open_call__rx(struct virtio_binding *_binding,
+                                  uint8_t backend)
+{
+    errval_t err;
+
+    if (_binding->st) {
+        /* cannot open a device twice! */
+        err_st.err = VIRTIO_ERR_DEVICE_STATUS;
+        virtio_open_response(&err_st);
+        return;
+    }
+
+    struct open_response_state *st = malloc(sizeof(struct open_response_state));
+    if (st == NULL) {
+        err_st.err = LIB_ERR_MALLOC_FAIL;
+        virtio_open_response(&err_st);
+        return;
+    }
+
+    err = host_cb->open(&st->frame, &_binding->st);
+    if (err_is_fail(err)) {
+        err_st.err = err;
+        virtio_open_response(&err_st);
+    }
+
+    st->b = _binding;
+    st->err = SYS_ERR_OK;
+
+    virtio_open_response(st);
+}
+
+/* -------------------- virtio_close() -------------------------------------- */
+
+static void virtio_close_response(void *a)
+{
+
+}
+
+static  void virtio_close_call__rx(struct virtio_binding *_binding)
+{
+    virtio_close_response(_binding);
+}
+
+/* -------------------- virtio_add() ---------------------------------------- */
+
+static void virtio_add_response(void *a)
+{
+
+}
+
+static  void virtio_add_call__rx(struct virtio_binding *_binding,
+                                 uint16_t vq_id,
+                                 uint16_t ndesc,
+                                 struct capref vring)
+{
+    virtio_add_response(_binding);
+}
+
+
+/* -------------------- virtio_ext() ---------------------------------------- */
+
+static void virtio_ext_response(void *a)
+{
+
+}
+
+static  void virtio_extend_call__rx(struct virtio_binding *_binding,
+                                    uint16_t vq_id,
+                                    struct capref vbuf)
+{
+    virtio_ext_response(_binding);
+}
+
+/* -------------------- virtio_req() ---------------------------------------- */
+
+static void virtio_req_response(void *a)
+{
+
+}
+
+static  void virtio_req_call__rx(struct virtio_binding *_binding,
+                                 uint64_t size)
+{
+    virtio_req_response(_binding);
+}
+
+
+
+
+struct virtio_rx_vtbl s_rx_vtbl = {
+    .open_call = virtio_open_call__rx,
+    .close_call = virtio_close_call__rx,
+    .add_call = virtio_add_call__rx,
+    .extend_call = virtio_extend_call__rx,
+    .req_call = virtio_req_call__rx,
+};
+
+struct virtio_host_cb *cb;
+
+static errval_t connect_cb(void *st, struct virtio_binding *b)
+{
+    VIRTIO_DEBUG_CHAN("New guest connection\n");
+
+    virtio_binding = b;
+
+    b->rx_vtbl = s_rx_vtbl;
+
+    return SYS_ERR_OK;
+}
+
+static void export_cb(void *st, errval_t err, iref_t iref)
+{
+    if (err_is_fail(err)) {
+        rpc_client_state = RPC_HOST_STATE_FAILED;
+        DEBUG_ERR(err, "Export failed");
+        return;
+    }
+
+    char *iface = st;
+    virtio_rpc_svc_iref = iref;
+
+    VIRTIO_DEBUG_CHAN("Registering [%s] with iref [%u]\n", iface, iref);
+    err = nameservice_register(iface, iref);
+    if (err_is_fail(err)) {
+        DEBUG_ERR(err, "nameservice_register failed");
+        rpc_client_state = RPC_HOST_STATE_FAILED;
+        return;
+    }
+
+    rpc_client_state = RPC_HOST_STATE_READY;
+}
+
+
+
+
+errval_t virtio_host_flounder_init(char *iface,
+                                   struct virtio_host_cb *callbacks)
+{
+    errval_t err;
+
+    VIRTIO_DEBUG_CHAN("initiate exporting service\n");
+
+    rpc_client_state = RPC_HOST_STATE_EXPORTING;
+
+    host_cb = callbacks;
+
+    err = virtio_export(iface,
+                        export_cb, connect_cb,
+                        get_default_waitset(),
+                        IDC_BIND_FLAGS_DEFAULT);
+
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    VIRTIO_DEBUG_CHAN("Waiting for export reply\n");
+    while(rpc_client_state == RPC_HOST_STATE_EXPORTING) {
+        messages_wait_and_handle_next();
+    }
+
+    if (rpc_client_state == RPC_HOST_STATE_FAILED) {
+        VIRTIO_DEBUG_CHAN("Export failed\n");
+        return FLOUNDER_ERR_BIND;
+    }
+
+    VIRTIO_DEBUG_CHAN("Service ready\n");
+
+    return SYS_ERR_OK;
+}
diff --git a/lib/virtio/host/channel_xeon_phi.c b/lib/virtio/host/channel_xeon_phi.c
new file mode 100644 (file)
index 0000000..0066520
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+
+#include <virtio/virtio.h>
+#include <virtio/virtio_device.h>
+#include <virtio/virtio_host.h>
+
+#include "host/channel.h"
+
+errval_t virtio_host_xeon_phi_init(void)
+{
+    return SYS_ERR_OK;
+}
index fe92bab..0d9d81d 100644 (file)
 --------------------------------------------------------------------------
 
 [ build application { target = "virtio_blk",
-                      cFiles = [ "main_guest.c"
-                                ],
+                      cFiles = [ "main_guest.c",
+                                 "service.c",
+                                 "request.c",
+                                 "device.c"],
                       addLibraries = libDeps ["virtio"],
                       --flounderExtraDefs = [ ("monitor_blocking",["rpcclient"]) ],
                       --flounderDefs = ["monitor", "xeon_phi_manager", "xeon_phi", "xeon_phi_messaging"],
                       --flounderBindings = ["xeon_phi", "xeon_phi_messaging"],
                       mackerelDevices = [ "virtio/virtio_blk" ],
+                      flounderBindings = [ "virtio" ],
+                      flounderExtraBindings = [ ("virtio", ["rpcclient"]) ],
                       architectures= ["x86_64", "k1om"]
                     },
   build application { target = "virtio_blk_host",
                       cFiles = [ "main_host.c"
                                 ],
+                         addCFlags = [ "-DVIRTIO_HOST" ],
                       addLibraries = libDeps ["virtio_host"],
                       --flounderExtraDefs = [ ("monitor_blocking",["rpcclient"]) ],
                       --flounderDefs = ["monitor", "xeon_phi_manager", "xeon_phi", "xeon_phi_messaging"],
                       --flounderBindings = ["xeon_phi", "xeon_phi_messaging"],
                       mackerelDevices = [ "virtio/virtio_blk" ],
-                      architectures= ["x86_64"]
-                      }              
+                      architectures= ["x86_64"],                      
+                      flounderDefs = [ "virtio" ],
+                      flounderExtraBindings = [ ("virtio", ["loopback"]) ]
+                      }             
 ]
 
 
diff --git a/usr/drivers/virtio/block/debug.h b/usr/drivers/virtio/block/debug.h
new file mode 100644 (file)
index 0000000..79cfbc8
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef VBLOCK_DEBUG_H_
+#define VBLOCK_DEBUG_H_
+
+#define VBLOCK_DEBUG_HOST_ENABLED 1
+#define VBLOCK_DEBUG_GUEST_ENABLED 1
+
+#define VBLOCK_DEBUG_SVC_ENABLED 1
+#define VBLOCK_DEBUG_REQ_ENABLED 1
+#define VBLOCK_DEBUG_DEV_ENABLED 1
+
+
+#ifdef VIRTIO_HOST
+#define VBLOCK_DEBUG_HOST VBLOCK_DEBUG_HOST_ENABLED
+#define VBLOCK_DEBUG_GUEST 0
+#else
+#define VBLOCK_DEBUG_HOST 0
+#define VBLOCK_DEBUG_GUEST VBLOCK_DEBUG_GUEST_ENABLED
+#endif
+
+
+#if VBLOCK_DEBUG_HOST
+#define VBLOCK_DEBUG_PRINT_HOST(msg...) debug_printf(msg)
+#else
+#define VBLOCK_DEBUG_PRINT_HOST(msg...)
+#endif
+
+#if VBLOCK_DEBUG_GUEST
+#define VBLOCK_DEBUG_PRINT_GUEST(msg...) debug_printf(msg)
+#else
+#define VBLOCK_DEBUG_PRINT_GUEST(msg...)
+#endif
+
+#define VBLOCK_DEBUG_PRINT(msg...) VBLOCK_DEBUG_PRINT_HOST(msg) \
+                                   VBLOCK_DEBUG_PRINT_GUEST(msg)
+
+#ifdef VBLOCK_DEBUG_DEV_ENABLED
+#define VIRTIO_DEBUG_DEV(msg...) VBLOCK_DEBUG_PRINT("[dev] " msg)
+#else
+#define VIRTIO_DEBUG_DEV(msg...)
+#endif
+
+#ifdef VBLOCK_DEBUG_REQ_ENABLED
+#define VIRTIO_DEBUG_REQ(msg...) VBLOCK_DEBUG_PRINT("[req] " msg)
+#else
+#define VIRTIO_DEBUG_REQ(msg...)
+#endif
+
+#ifdef VBLOCK_DEBUG_SVC_ENABLED
+#define VIRTIO_DEBUG_SVC(msg...) VBLOCK_DEBUG_PRINT("[svc] " msg)
+#else
+#define VIRTIO_DEBUG_SVC(msg...)
+#endif
+
+#endif /* VBLOCK_DEBUG_H_ */
diff --git a/usr/drivers/virtio/block/device.c b/usr/drivers/virtio/block/device.c
new file mode 100644 (file)
index 0000000..eeae0b4
--- /dev/null
@@ -0,0 +1,108 @@
+/**
+ * \file
+ * \brief Driver for booting the Xeon Phi Coprocessor card on a Barrelfish Host
+ */
+
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <virtio/virtio.h>
+#include <virtio/virtqueue.h>
+#include <virtio/virtio_device.h>
+#include <virtio/devices/virtio_block.h>
+
+#include "device.h"
+#include "request.h"
+#include "debug.h"
+
+
+/**
+ * \brief handles the VirtIO config change interrupt
+ *
+ * \param pointer to the virtio device
+ *
+ * \returns SYS_ERR_OK on success
+ */
+void vblock_device_config_changed_intr(struct virtio_device *vdev)
+{
+    struct virtio_device_blk *bdev;
+
+    bdev = virtio_device_get_struct(vdev);
+    if (bdev == NULL) {
+        return;
+    }
+
+    virtio_block_config_read(bdev);
+}
+
+/**
+ * \brief handles the VirtIO interrupts
+ *
+ * \param arg the argument passed to the virtqueue when allocating it
+ */
+void vblock_device_virtqueue_intr(void *arg)
+{
+    errval_t err;
+
+    struct vblock_device *dev = arg;
+    struct virtqueue *vq = dev->blk.vq;
+
+    bool again = true;
+
+    while(again) {
+        err = vblock_request_finish_completed(dev);
+        if (err_is_fail(err)) {
+            /*todo error recovery */
+        }
+
+        again = !virtio_virtqueue_intr_enable(vq);
+        if (again) {
+            virtio_virtqueue_intr_disable(vq);
+        }
+    }
+}
+
+
+
+errval_t vblock_device_init(struct virtio_device_blk *blk,
+                            void *dev_regs,
+                            size_t reg_size)
+{
+    errval_t err;
+
+    VIRTIO_DEBUG_DEV("Initializing vblock device [%016lx, %lx]\n",
+                     (uintptr_t)dev_regs, (uint64_t)reg_size);
+
+    struct virtqueue_setup vq_setup =  {
+        .name = "Request Virtqueue",
+        .vring_ndesc = 0,
+        .vring_align = 0,
+        .intr_handler = 0,
+        .intr_arg = 0,
+        .max_indirect =0
+    };
+
+    struct virtio_device_setup setup = {
+        .name = "VirtIO Block Device",
+        .dev_reg = dev_regs,
+        .dev_reg_size = reg_size,
+        .driver_features = VBLOCK_DRIVER_FEATURES,
+        .backend = VBLOCK_DRIVER_BACKEND,
+        .type = VIRTIO_DEVICE_TYPE_BLOCK,
+        .vq_setup = &vq_setup,
+        .vq_num = 1
+    };
+
+    err = virtio_block_init_device(blk, &setup);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    return SYS_ERR_OK;
+}
diff --git a/usr/drivers/virtio/block/device.h b/usr/drivers/virtio/block/device.h
new file mode 100644 (file)
index 0000000..8766a0c
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef VBLOCK_DEVICE_H_
+#define VBLOCK_DEVICE_H_
+
+
+#define VBLOCK_DRIVER_BACKEND VIRTIO_DEVICE_BACKEND_MMIO
+
+// forward declaration
+struct vblock_req;
+
+/*
+ * VirtIO Block Device Flags
+ */
+/// The block device is read only
+#define VBLOCK_FLAGS_READONLY (1 << 1)
+
+enum vblock_device_state {
+    VBLOCK_DEVICE_STATE_RESET,
+    VBLOCK_DEVICE_STATE_READY,
+    VBLOCK_DEVICE_STATE_FAILURE
+};
+
+typedef void(*req_callback_t)(struct vblock_req *);
+
+ struct vblock_req {
+     struct virtio_block_reqhdr header;
+     struct virtio_buffer_list  *bl;
+     req_callback_t callback;
+     void *arg;
+     uint8_t ack;
+     /* TODO: flounder binding */
+
+     struct vblock_req *next;
+     struct vblock_req_queue *queue;
+ };
+
+struct vblock_req_queue
+{
+     uint32_t length;
+     struct vblock_req *head;
+     struct vblock_req *tail;
+     void (*op)(struct vblock_req *req);
+};
+
+#define VBLOCK_FEATURE_
+#define VBLOCK_DRIVER_FEATURES 0
+
+struct vblock_device
+{
+    struct virtio_device_blk blk;
+    uint32_t flags;
+    enum vblock_device_state state;
+
+
+    struct vblock_req_queue ready_queue;    ///< queue of executed requests
+    struct vblock_req_queue free_queue;     ///< queue of free requests
+
+    struct vblock_req *requests;
+
+    /* TODO; pointers to flounder states*/
+    iref_t svc_iref;
+};
+
+/**
+ * \brief handles the VirtIO config change interrupt
+ *
+ * \param pointer to the virtio device
+ *
+ */
+void vblock_device_config_changed_intr(struct virtio_device *vdev);
+
+/**
+ * \brief handles the VirtIO interrupts
+ *
+ * \param arg the argument passed to the virtqueue when allocating it
+ */
+void vblock_device_virtqueue_intr(void *arg);
+
+
+
+errval_t vblock_device_init(struct virtio_device_blk *blk,
+                            void *dev_regs,
+                            size_t ret_size);
+
+#endif /* VBLOCK_DEVICE_H_ */
diff --git a/usr/drivers/virtio/block/host.c b/usr/drivers/virtio/block/host.c
new file mode 100644 (file)
index 0000000..6aa3684
--- /dev/null
@@ -0,0 +1,20 @@
+/**
+ * \file
+ * \brief Driver for booting the Xeon Phi Coprocessor card on a Barrelfish Host
+ */
+
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <virtio/virtio.h>
+#include <virtio/virtio_device.h>
+#include <virtio/devices/virtio_block.h>
+
+
+
diff --git a/usr/drivers/virtio/block/host.h b/usr/drivers/virtio/block/host.h
new file mode 100644 (file)
index 0000000..1219b8b
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef VBLOCK_HOST_H_
+#define VBLOCK_HOST_H_
+
+
+
+/**
+ * \brief Initializes
+ */
+errval_t vblock_host_get_device_cap(struct capref *cap);
+
+errval_t vblock_host_device_poll(void);
+
+void *vblock_host_translate_phys2virt(lpaddr_t paddr);
+
+#endif /* VBLOCK_HOST_H_ */
index 64944a8..c803448 100644 (file)
  * If you do not find this file, copies can be found by writing to:
  * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
  */
+#include <barrelfish/barrelfish.h>
 
 #include <virtio/virtio.h>
 #include <virtio/virtio_device.h>
 #include <virtio/devices/virtio_block.h>
+#include <virtio/virtio_guest.h>
 
 #include <dev/virtio/virtio_blk_dev.h>
 
+#include "device.h"
+#include "request.h"
+#include "service.h"
+
+struct virtio_device_blk blk_dev;
+
 int main(int argc, char *argv[])
 {
+    errval_t err;
+
+    debug_printf("VirtIO block device driver started.\n");
+
+    err = virtio_guest_init(VIRTIO_GUEST_CHAN_FLOUNDER,
+                            VIRTIO_BLOCK_FLOUNDER_IFACE);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "Could not initialize the library\n");
+    }
+
+    struct capref dev_frame;
+    err = virtio_guest_open_device(VIRTIO_DEVICE_BACKEND_MMIO, &dev_frame);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "Could not initialize the library\n");
+    }
+
+    void *dev_regs = malloc(4096);
+
+    vblock_device_init(&blk_dev, dev_regs, 4096);
 
+    debug_printf("VirtIO block device driver terminated.\n");
 }
index 11da963..09a6c96 100644 (file)
  * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
  */
 
+#include <barrelfish/barrelfish.h>
+
+#include <virtio/virtio.h>
+#include <virtio/virtio_device.h>
+#include <virtio/virtio_host.h>
+#include <virtio/devices/virtio_block.h>
+
+#include "host.h"
+#include "device.h"
+#include "request.h"
+#include "service.h"
+
+struct virtio_host *host;
+
+static errval_t handle_open(struct capref *ret_frame, void **st)
+{
+    return SYS_ERR_OK;
+}
+
+
+static struct virtio_host_cb host_cb = {
+  .open = handle_open
+};
+
+int main(int argc, char *argv[])
+{
+    errval_t err;
+
+    debug_printf("VirtIO block device host started.\n");
+
+    struct virtio_host_setup setup = {
+        .callback = &host_cb,
+        .channel_type = VIRTIO_HOST_CHAN_FLOUNDER,
+        .iface = VIRTIO_BLOCK_FLOUNDER_IFACE
+    };
+
+    err = virtio_host_init(&host,
+                           &setup);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "Service initialization failed.\n");
+    }
+
+
+    messages_handler_loop();
+
+    debug_printf("VirtIO block device host terminated.\n");
+}
 
diff --git a/usr/drivers/virtio/block/request.c b/usr/drivers/virtio/block/request.c
new file mode 100644 (file)
index 0000000..3e4f5ce
--- /dev/null
@@ -0,0 +1,226 @@
+/**
+ * \file
+ * \brief Driver for booting the Xeon Phi Coprocessor card on a Barrelfish Host
+ */
+
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <virtio/virtio.h>
+#include <virtio/virtqueue.h>
+#include <virtio/virtio_device.h>
+#include <virtio/devices/virtio_block.h>
+
+#include "device.h"
+#include "request.h"
+
+static errval_t request_status(struct vblock_req *req)
+{
+    switch(req->ack) {
+    case VIRTIO_BLOCK_S_OK:
+        return SYS_ERR_OK;
+    case VIRTIO_BLOCK_S_IOERR:
+        return VIRTIO_ERR_BLK_REQ_IOERR;
+    case VIRTIO_BLOCK_S_UNSUPP:
+        return VIRTIO_ERR_BLK_REQ_UNSUP;
+    default:
+        return VIRTIO_ERR_BLK_REQ_UNSUP;
+    }
+
+    return VIRTIO_ERR_BLK_REQ_UNSUP;
+}
+
+/**
+ * \brief allocates the request structures based on the number of
+ *        descriptors on the virtqueue of the device
+ *
+ * \param dev   vblock device to allocate the requests for
+ *
+ * \returns SYS_ERR_OK on sucess
+ */
+errval_t vblock_request_queue_init(struct vblock_device *dev)
+{
+    uint16_t ndesc = virtio_virtqueue_get_num_desc(dev->blk.vq);
+
+    struct vblock_req *req = calloc(ndesc, sizeof(struct vblock_req));
+    if (req == NULL) {
+        return LIB_ERR_MALLOC_FAIL;
+    }
+
+    dev->free_queue.length = ndesc;
+    dev->free_queue.head = req;
+    dev->free_queue.tail = req+(ndesc-1);
+
+    for (uint32_t i = 0; i < ndesc-1; ++i) {
+        req->queue = &dev->free_queue;
+        req->next = req+1;
+    }
+
+    dev->requests = req;
+
+    return SYS_ERR_OK;
+}
+
+/**
+ * \brief frees the allocated requests
+ *
+ * \param dev   vblock device to free the requests
+ *
+ * \returns SYS_ERR_OK on success
+ */
+void vblock_request_queue_destroy(struct vblock_device *dev)
+{
+    /*
+     * TODO: check that every request is finished.
+     */
+    free(dev->requests);
+}
+
+/**
+ * \brief Dequeues a request from the request queue
+ *
+ * \param queue the queue to dequeue a request on
+ *
+ * \returns vblock_req on success
+ *          NULL if the queue was empty
+ */
+struct vblock_req *vblock_request_dequeue(struct vblock_req_queue *queue)
+{
+    struct vblock_req *req;
+
+    if (queue->length == 0) {
+        return NULL;
+    }
+
+    assert(queue->head);
+
+    req = queue->head;
+
+    if (queue->length == 1) {
+        queue->head = NULL;
+        queue->tail = NULL;
+    } else {
+        queue->head = req->next;
+    }
+
+    queue->length--;
+
+    req->queue = NULL;
+    req->next = NULL;
+
+    return req;
+}
+
+/**
+ * \brief enqueues a request into a request queue
+ *
+ * \param queue the queue to insert the request in
+ * \param req   the request to insert
+ */
+void vblock_request_enqueue(struct vblock_req_queue *queue,
+                            struct vblock_req *req)
+{
+    assert(req->queue == NULL);
+    assert(req->next == NULL);
+
+    if (queue->length == 0) {
+        queue->head = req;
+        queue->tail = req;
+    } else {
+        queue->tail->next = req;
+        queue->tail = req;
+    }
+
+    queue->length++;
+
+    req->queue = queue;
+}
+
+/**
+ * \brief executes a request on the VirtIO block device
+ *
+ * \param dev   the VirtIO block device
+ * \param req   the request to execute
+ *
+ * \return SYS_ERR_OK on success
+ */
+errval_t vblock_request_start(struct vblock_device *dev,
+                              struct vblock_req *req)
+{
+    assert(!"NYI: starting of device requests");
+    return SYS_ERR_OK;
+}
+
+/**
+ * \brief executes a request on the VirtIO block device and waits
+ *        for its completion by polling the queue
+ *
+ * \param dev   the VirtIO block device
+ * \param req   the request to execute
+ *
+ * \return SYS_ERR_OK on success
+ *
+ * NOTE: This is a blocking call. When the function returns, the device request
+ *       req has been executed and holds the data.
+ */
+errval_t vblock_request_exec(struct vblock_device *dev,
+                             struct vblock_req *req)
+{
+    errval_t err;
+    struct virtqueue *vq = dev->blk.vq;
+
+    /* when executing a request, there must be no other request in flight */
+    if (!virtio_virtqueue_is_empty(vq)) {
+        return VIRTIO_ERR_QUEUE_BUSY;
+    }
+
+    /* start the requst */
+    err = vblock_request_start(dev, req);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    /* notify the host and poll the list */
+    virtio_virtqueue_notify_host(vq);
+
+    err = virtio_virtqueue_poll(vq, &req->bl, &req->arg, 1);
+    if (err_is_fail(err)) {
+        return err;
+    }
+
+    return request_status(req);
+}
+
+/**
+ * \brief works through the virtqueue and handling all the completed descriptors
+ *
+ * \param dev VirtIO block device
+ *
+ * \return SYS_ERR_OK on success
+ */
+errval_t vblock_request_finish_completed(struct vblock_device *dev)
+{
+    assert(!"NYI");
+    return SYS_ERR_OK;
+}
+
+
+/**
+ * \brief   issues a get device identifier request on the device
+ *
+ * \param   dev VirtIO block device to issue the get ID request
+ */
+errval_t vblock_request_issue_get_id(struct virtio_device_blk *dev)
+{
+    assert(!"NYI");
+    return SYS_ERR_OK;
+}
+
+
+
diff --git a/usr/drivers/virtio/block/request.h b/usr/drivers/virtio/block/request.h
new file mode 100644 (file)
index 0000000..ec51fee
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef VBLOCK_REQUEST_H_
+#define VBLOCK_REQUEST_H_
+
+#include "device.h"
+
+/**
+ * \brief allocates the request structures based on the number of
+ *        descriptors on the virtqueue of the device
+ *
+ * \param dev   vblock device to allocate the requests for
+ *
+ * \returns SYS_ERR_OK on sucess
+ */
+errval_t vblock_request_queue_init(struct vblock_device *dev);
+
+/**
+ * \brief frees the allocated requests
+ *
+ * \param dev   vblock device to free the requests
+ *
+ * \returns SYS_ERR_OK on success
+ */
+void vblock_request_queue_destroy(struct vblock_device *dev);
+
+/**
+ * \brief Dequeues a request from the request queue
+ *
+ * \param queue the queue to dequeue a request on
+ *
+ * \returns vblock_req on success
+ *          NULL if the queue was empty
+ */
+struct vblock_req *vblock_request_dequeue(struct vblock_req_queue *queue);
+
+/**
+ * \brief Dequeues a request from the device's free queue
+ *
+ * \param queue the queue to dequeue a request on
+ *
+ * \returns vblock_req on success
+ *          NULL if the queue was empty
+ */
+static inline struct vblock_req *vblock_request_alloc(struct vblock_device *dev)
+{
+    return vblock_request_dequeue(&dev->free_queue);
+}
+
+/**
+ * \brief enqueues a request into a request queue
+ *
+ * \param queue the queue to insert the request in
+ * \param req   the request to insert
+ */
+void vblock_request_enqueue(struct vblock_req_queue *queue,
+                        struct vblock_req *req);
+
+/**
+ * \brief returns a previously allocated reqest by enqueueing it into the
+ *        device's free queue
+ *
+ * \param queue the queue to insert the request in
+ * \param req   the request to ins
+ */
+static inline void vblock_request_free(struct vblock_device *dev,
+                                       struct vblock_req *req)
+{
+    vblock_request_enqueue(&dev->free_queue, req);
+}
+
+/**
+ * \brief executes a request on the VirtIO block device
+ *
+ * \param dev   the VirtIO block device
+ * \param req   the request to execute
+ *
+ * \return SYS_ERR_OK on success
+ */
+errval_t vblock_request_start(struct vblock_device *dev,
+                              struct vblock_req *req);
+
+/**
+ * \brief executes a request on the VirtIO block device and waits
+ *        for its completion by polling the queue
+ *
+ * \param dev   the VirtIO block device
+ * \param req   the request to execute
+ *
+ * \return SYS_ERR_OK on success
+ *
+ * NOTE: This is a blocking call
+ */
+errval_t vblock_request_exec(struct vblock_device *dev,
+                             struct vblock_req *req);
+
+
+/**
+ * \brief works through the virtqueue and handling all the completed descriptors
+ *
+ * \param dev VirtIO block device
+ *
+ * \return SYS_ERR_OK on success
+ */
+errval_t vblock_request_finish_completed(struct vblock_device *dev);
+
+/**
+ * \brief   issues a get device identifier request on the device
+ *
+ * \param   dev VirtIO block device to issue the get ID request
+ */
+errval_t vblock_request_issue_get_id(struct virtio_device_blk *dev);
+
+errval_t vblock_request_issue_write(struct virtio_device_blk *dev);
+
+errval_t vblock_request_issue_read(struct virtio_device_blk *dev);
+
+errval_t vblock_request_issue_flush(struct virtio_device_blk *dev);
+
+errval_t vblock_request_issue_barrier(struct virtio_device_blk *dev);
+
+#endif /* VBLOCK_REQUEST_H_ */
diff --git a/usr/drivers/virtio/block/service.c b/usr/drivers/virtio/block/service.c
new file mode 100644 (file)
index 0000000..6aa3684
--- /dev/null
@@ -0,0 +1,20 @@
+/**
+ * \file
+ * \brief Driver for booting the Xeon Phi Coprocessor card on a Barrelfish Host
+ */
+
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <virtio/virtio.h>
+#include <virtio/virtio_device.h>
+#include <virtio/devices/virtio_block.h>
+
+
+
diff --git a/usr/drivers/virtio/block/service.h b/usr/drivers/virtio/block/service.h
new file mode 100644 (file)
index 0000000..ce1d171
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2014 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef VBLOCK_SERVICE_H_
+#define VBLOCK_SERVICE_H_
+
+
+#endif /* VBLOCK_SERVICE_H_ */
index c13ec4e..072a39e 100644 (file)
@@ -109,8 +109,11 @@ static void multiboot_cap_reply(struct monitor_binding *st,
  */
 errval_t host_bootstrap(void)
 {
+
     errval_t err;
 
+    return SYS_ERR_OK;
+if (0) {
     /* Create the module cnode */
     struct capref modulecn_cap = {
         .cnode = cnode_root,
@@ -135,6 +138,7 @@ errval_t host_bootstrap(void)
     if (err_is_fail(err)) {
         return err;
     }
+}
 
     return SYS_ERR_OK;
 }