};
+errors virtio VIRTIO_ERR_ {
+ failure SIZE_INVALID "Size of the ringe is zero or not a power of two",
+ failure MAX_INDIRECT "Too much indirect descriptors",
+ failure CAP_SIZE "Supplied cap is too small",
+ failure QUEUE_FULL "The queue was full",
+ failure QUEUE_EMPTY "The queue was empty",
+};
k1om/sbin/spawnd \
k1om/sbin/startd \
k1om/sbin/xeon_phi \
- k1om/sbin/xeon_phi_test
+ k1om/sbin/xeon_phi_test \
+ k1om/sbin/virtio_blk
menu.lst.k1om: $(SRCDIR)/hake/menu.lst.k1om
#include <barrelfish/barrelfish.h>
-/*
- * 2.1 Device Status Field
- */
-
-/// The device is in the reset state (not discovered by the guest)
-#define VIRTIO_DEVICE_STATUS_RESET 0x00
-
-/// Guest OS has found the device and recognized it as a valid virtio device.
-#define VIRTIO_DEVICE_STATUS_ACKNOWLEDGE 0x01
-
-/// Guest OS knows how to drive the device i.e. recognized as valid virtio device.
-#define VIRTIO_DEVICE_STATUS_DRIVER 0x02
-
-/// Driver is set up and ready to drive the device.
-#define VIRTIO_DEVICE_STATUS_DRIVER_OK 0x04
-
-/// Driver has acknowledged all the features it understands
-#define VIRTIO_DEVICE_STATUS_FEATURES_OK 0x08
-
-/// Something went wrong in the guest, and it has given up on the device.
-#define VIRTIO_DEVICE_STATUS_FAILED 0x80
-
-/*
- * 5.0 Device Types
- * The following device IDs are used to identify different types of virtio
- * devices. Some device IDs are reserved for devices which are not currently
- * defined in this standard.
- */
-
-/// Invalid device identifier
-#define VIRTIO_DEVICE_TYPE_INVALID 0x00
-
-/// Device type for network interface cards
-#define VIRTIO_DEVICE_TYPE_NET 0x01
-
-/// Device type for block devices
-#define VIRTIO_DEVICE_TYPE_BLOCK 0x02
-
-/// Device type for console devices
-#define VIRTIO_DEVICE_TYPE_CONSOLE 0x03
-
-/// Device type for entorpy devices
-#define VIRTIO_DEVICE_TYPE_ENTORPY 0x04
-
-//#define VIRTIO_DEVICE_TYPE_LEGACY_BALLOON 5
-
-/// Device type for IO memory devices
-#define VIRTIO_DEVICE_TYPE_IOMEM 0x06
-
-/// Device type for rpmgs devices
-#define VIRTIO_DEVICE_TYPE_RPMSG 0x07
-
-/// Device type for SCSI host devices
-#define VIRTIO_DEVICE_TYPE_SCSIHOST 0x08
-
-/// Device type for 9P transport devices
-#define VIRTIO_DEVICE_TYPE_9PTRANSP 0x09
-
-/// Device type for MAC 802.11 WLAn devices
-#define VIRTIO_DEVICE_TYPE_WLAN 0x0A
-
-/// Device type for RPROC serial devices
-#define VIRTIO_DEVICE_TYPE_SERIAL 0x0B
-
-/// Device type for virtio CAIF devices
-#define VIRTIO_DEVICE_TYPE_CAIF 0x0C
-
-/// Device type for memory ballooning devices
-#define VIRTIO_DEVICE_TYPE_BALLOON 0x0D
-
-/// Device type for GPU devices
-#define VIRTIO_DEVICE_TYPE_GPU 0x0E
-
-/// Device type for timer / clock devices
-#define VIRTIO_DEVICE_TYPE_TIMER 0x0F
-
/*
* Generic Feature Bits
*/
+
/// Generate interrupt if queue is completely used
#define VIRTIO_F_NOTIFY_ON_EMPTY (1 << 24)
#define VIRTIO_TRANSPORT_F_END 32
+
+
/**
- * \brief this struct represents a virtio device
+ * \brief this struct represents a virtio driver
*
- * This can be seen as on the host side of the virtio channel
+ * This can be seen as on the guest side of the virtio channel
*/
-struct virtio_device
+struct virtio_driver
{
- struct virtio_device_id id; ///< the virtio device id
-
- struct virtio_fn fn; ///< backend specific implementation
-
void *device_config;
- size_t num_queues; ///< number of vqueues associated with the dev
- struct vring vqueues; ///< the
};
/**
- * \brief this struct represents a virtio driver
- *
- * This can be seen as on the guest side of the virtio channel
+ * VirtIO Memory segment
*/
-struct virtio_driver
+struct virtio_buffer
{
- void *device_config;
+};
+struct virtio_buffer_allocator
+{
+ struct virtio_buffer *buffers;
+ uint16_t size;
+ uint16_t top;
};
-/**
- * \brief adds a buffer to the available ring
- */
-errval_t virtio_add_buffer();
+errval_t virtio_buffer_alloc_init(struct virtio_buffer_allocator *alloc,
+ uint16_t nbufs);
+
+errval_t virtio_buffer_alloc(void);
+errval_t virtio_buffer_free(void);
+
+
+errval_t virtio_buffer_list_reset(void);
+errval_t virtio_buffer_list_append(void);
-/**
- * \brief gets the next used buffer
- */
-errval_t virtio_get_buffer();
-/**
- * \brief
- */
-void virtio_disable_callback(void);
-/**
- * \brief
- */
-void virtio_enable_callback();
#endif // VIRTIO_H
--- /dev/null
+/*
+ * 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_VIRTIO_DEVICE_H
+#define VIRTIO_VIRTIO_DEVICE_H
+
+
+struct virtio_device;
+
+/*
+ * 2.1 Device Status Field
+ */
+
+/// The device is in the reset state (not discovered by the guest)
+#define VIRTIO_DEVICE_STATUS_RESET 0x00
+
+/// Guest OS has found the device and recognized it as a valid virtio device.
+#define VIRTIO_DEVICE_STATUS_ACKNOWLEDGE 0x01
+
+/// Guest OS knows how to drive the device i.e. recognized as valid virtio device.
+#define VIRTIO_DEVICE_STATUS_DRIVER 0x02
+
+/// Driver is set up and ready to drive the device.
+#define VIRTIO_DEVICE_STATUS_DRIVER_OK 0x04
+
+/// Driver has acknowledged all the features it understands
+#define VIRTIO_DEVICE_STATUS_FEATURES_OK 0x08
+
+/// Something went wrong in the guest, and it has given up on the device.
+#define VIRTIO_DEVICE_STATUS_FAILED 0x80
+
+/*
+ * 5.0 Device Types
+ * The following device IDs are used to identify different types of virtio
+ * devices. Some device IDs are reserved for devices which are not currently
+ * defined in this standard.
+ */
+
+/// Invalid device identifier
+#define VIRTIO_DEVICE_TYPE_INVALID 0x00
+
+/// Device type for network interface cards
+#define VIRTIO_DEVICE_TYPE_NET 0x01
+
+/// Device type for block devices
+#define VIRTIO_DEVICE_TYPE_BLOCK 0x02
+
+/// Device type for console devices
+#define VIRTIO_DEVICE_TYPE_CONSOLE 0x03
+
+/// Device type for entorpy devices
+#define VIRTIO_DEVICE_TYPE_ENTORPY 0x04
+
+//#define VIRTIO_DEVICE_TYPE_LEGACY_BALLOON 5
+
+/// Device type for IO memory devices
+#define VIRTIO_DEVICE_TYPE_IOMEM 0x06
+
+/// Device type for rpmgs devices
+#define VIRTIO_DEVICE_TYPE_RPMSG 0x07
+
+/// Device type for SCSI host devices
+#define VIRTIO_DEVICE_TYPE_SCSIHOST 0x08
+
+/// Device type for 9P transport devices
+#define VIRTIO_DEVICE_TYPE_9PTRANSP 0x09
+
+/// Device type for MAC 802.11 WLAn devices
+#define VIRTIO_DEVICE_TYPE_WLAN 0x0A
+
+/// Device type for RPROC serial devices
+#define VIRTIO_DEVICE_TYPE_SERIAL 0x0B
+
+/// Device type for virtio CAIF devices
+#define VIRTIO_DEVICE_TYPE_CAIF 0x0C
+
+/// Device type for memory ballooning devices
+#define VIRTIO_DEVICE_TYPE_BALLOON 0x0D
+
+/// Device type for GPU devices
+#define VIRTIO_DEVICE_TYPE_GPU 0x0E
+
+/// Device type for timer / clock devices
+#define VIRTIO_DEVICE_TYPE_TIMER 0x0F
+
+/**
+ * specifies the possible virtio backends to be used
+ */
+enum virtio_device_backend {
+ VIRTIO_DEVICE_BACKEND_INVALID,
+ VIRTIO_DEVICE_BACKEND_PCI,
+ VIRTIO_DEVICE_BACKEND_MMIO,
+};
+
+/*
+ * 4.1.2 PCI Device Discovery
+ *
+ * Any PCI device with Vendor ID 0x1AF4, and Device ID 0x1000 through 0x103F
+ * inclusive is a virtio device. The Subsystem Device ID indicates which virtio
+ * device is supported by the device.
+ */
+
+#define VIRTIO_PCI_VENDOR_ID 0x1AF4
+#define VIRTIO_PCI_DEVICE_ID 0x1000
+#define VIRTIO_PCI_DEVICE_ID2 0x103F
+
+
+/**
+ * contains necessary values for the device initialization process
+ */
+struct virtio_device_init
+{
+ uint8_t type; ///< expected type of the device
+ enum virtio_device_backend backend; ///< which backend to use
+};
+
+/**
+ * contains function pointers to backend specific functions
+ */
+struct virtio_device_fn
+{
+ errval_t(*virtio_dev_init_t)(struct virtio_device *dev);
+};
+
+/**
+ * represents a virtio device
+ */
+struct virtio_device
+{
+ uint8_t type;
+ enum virtio_device_backend backend;
+ struct virtio_device_fn *f;
+};
+
+/**
+ * \brief initializes the common part of the virtio device structure
+ *
+ * \param dev device structure to initialize
+ * \param init additional information passed for the init process
+ * \param dev_regs memory location of the device registers
+ */
+errval_t virtio_device_init(struct virtio_device **dev,
+ struct virtio_device_init *init,
+ void *dev_regs);
+
+/**
+ * \brief initializes the common part of the virtio device structure based on
+ * a supplied cap which gets mapped
+ *
+ * \param dev device structure to initialize
+ * \param init additional information passed for the init process
+ * \param dev_cap capability representing the device registers
+ */
+errval_t virtio_device_init_with_cap(struct virtio_device **dev,
+ struct capref dev_cap);
+
+
+#endif // VIRTIO_VIRTIO_DEVICE_H
+++ /dev/null
-/*
- * 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_VIRTIO_MMIO_H
-#define VIRTIO_VIRTIO_MMIO_H
-
-#include <barrelfish/barrelfish.h>
-#include <virtio/virtio.h>
-
-/**
- * \brief initializes a new virtio device structure
- */
-errval_t virtio_mmio_device_init(struct virtio_device **vdev,
- void *device_config,
- struct capref mmio);
-
-/**
- * \brief de-initialization of the device structure and freeing of resources
- */
-errval_t virtio_mmio_device_free(struct virtio_device **vdev);
-
-/**
- * \brief initializes a new virtio driver structure
- */
-errval_t virtio_mmio_driver_init(struct virtio_driver **vdrv,
- struct capref mmio);
-
-/**
- * \brief de-initialization of the driver structure and freeing of resources
- */
-errval_t virtio_mmio_driver_free(struct virtio_driver **vdrv);
-
-#endif // VIRTIO_VIRTIO_MMIO_H
+++ /dev/null
-/*
- * 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_VIRTIO_PCI_H
-#define VIRTIO_VIRTIO_PCI_H
-
-#include <barrelfish/barrelfish.h>
-
-/*
- * 4.1.2 PCI Device Discovery
- *
- * Any PCI device with Vendor ID 0x1AF4, and Device ID 0x1000 through 0x103F
- * inclusive is a virtio device. The Subsystem Device ID indicates which virtio
- * device is supported by the device.
- */
-
-#define VIRTIO_PCI_VENDOR_ID 0x1AF4
-#define VIRTIO_PCI_DEVICE_ID 0x1000
-#define VIRTIO_PCI_DEVICE_ID2 0x103F
-
-
-
-/**
- * \brief initializes a new virtio device structure
- */
-errval_t virtio_pci_device_init(struct virtio_device **vdev,
- struct capref mmio);
-
-/**
- * \brief de-initialization of the device structure and freeing of resources
- */
-errval_t virtio_pci_device_free(struct virtio_device **vdev);
-
-/**
- * \brief initializes a new virtio driver structure
- */
-errval_t virtio_pci_driver_init(struct virtio_driver **vdrv,
- struct capref mmio);
-
-/**
- * \brief de-initialization of the driver structure and freeing of resources
- */
-errval_t virtio_pci_driver_free(struct virtio_driver **vdrv);
-
-
-#endif // VIRTIO_VIRTIO_PCI_H
#include <barrelfish/barrelfish.h>
+/*
+ * This file contains the Virtio VRing description as defined in the VirtIO
+ * specification.
+ *
+ * Extracted from the Virtio Specification 1.0
+ * http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf
+ */
+
/**
* 2.4.5 The Virtqueue Descriptor Table
*
+ * The descriptor table refers to the buffers the driver is using for the device.
+ *
* Alignment Constraint: 16 byte boundary
*/
struct vring_desc
{
lpaddr_t addr; ///< Address (guest-physical).
- uint32_t length; ///< Length
- uint16_t flags; ///< The flags, see VIRTQ_DESC_F_*
- uint16_t next; ///< Next field if flags & NEXT
+ uint32_t length; ///< Length of the data in the buffer
+ uint16_t flags; ///< The flags, see VRING_DESC_F_*
+ uint16_t next; ///< Next field used for chaining if flags & NEXT
};
/// This marks a buffer as continuing via the next field.
-#define VIRTQ_DESC_F_NEXT 0x01
+#define VIRTIO_RING_DESC_F_NEXT 0x01
/// This marks a buffer as device write-only (otherwise device read-only).
-#define VIRTQ_DESC_F_WRITE 0x02
+#define VIRTIO_RING_DESC_F_WRITE 0x02
+
+/// This means the buffer contains a list of buffer descriptors.
+#define VIRTIO_RING_DESC_F_INDIRECT 0x04
+
-/// This means the buffer contains a list of buffer descriptors. */
-#define VIRTQ_DESC_F_INDIRECT 0x04
/**
* 2.4.5.3 Indirect Descriptors
*/
struct indirect_vring_desc
{
- struct vring_desc desc[]; ///< The actual descriptors (16 bytes each)
+ struct vring_desc desc[0]; ///< The actual descriptors (16 bytes each)
};
/// gets the number of Virtqueue descriptors of the table
-#define VIRTQ_NUM_INDIRECT(vdesc) \
+#define VIRTIO_RING_NUM_INDIRECT(vdesc) \
((vdesc)->length)/16;
-#define VIRTIO_MAX_INDIRECT ((uint32_t) (PAGE_SIZE / 16))
+#define VIRTIO_RING_MAX_INDIRECT ((uint32_t) (BASE_PAGE_SIZE / 16))
/**
* 2.4.6 The Virtqueue Available Ring
struct vring_avail
{
- uint16_t flags; ///< Ring flags for disabling interrupts
+ uint16_t flags; ///< Ring flags see VRING_AVAIL_F_*
uint16_t idx; ///< where the driver would put the next descriptor
- uint16_t ring[]; ///< refers to a head of descriptor chain
- /* Only if VIRTIO_F_EVENT_IDX uint16_t used_event; */
+ uint16_t ring[0]; ///< refers to a head of descriptor chain
+ /* Only if VIRTIO_RING_F_EVENT_IDX uint16_t used_event; */
};
-/// disable interrupts on this queue
-#define VIRTQ_AVAIL_F_NO_INTERRUPT 1
+/// disable sending interrupts when the host consumes a buffer
+#define VIRTIO_RING_AVAIL_F_NO_INTERRUPT 1
+
+/**
+ * is an element of the used ring
+ */
+struct vring_used_elem
+{
+ uint32_t id; ///< index of start of used descriptor chain
+ uint32_t length; ///< total length of descriptor chain
+};
/**
* 2.4.8 The Virtqueue Used Ring
*/
struct vring_used
{
- uint16_t flags; ///< disabling the notification
+ uint16_t flags; ///< see VRING_USED_F*
uint16_t idx; ///< where the driver would put next desc
- struct virtq_used_elem ring[]; ///< refers to a head of a descriptor chain
- /* Only if VIRTIO_F_EVENT_IDX uint16_t avail_event; */
+ struct vring_used_elem ring[0]; ///< refers to a head of a descriptor chain
+ /* Only if VIRTIO_RING_F_EVENT_IDX uint16_t avail_event; */
};
-struct virtq_used_elem
-{
- uint32_t id; ///< index of start of used descriptor chain
- uint32_t length; ///< total length of descriptor chain
-};
-/// disable the notification
-#define VIRTQ_USED_F_NO_NOTIFY 1
+
+/// disable the notification when the guest adds a buffer
+#define VIRTIO_RING_USED_F_NO_NOTIFY 1
/**
* 2.4 Virtqueues
struct vring_desc *desc; ///< the actual descriptors (16 bytes each)
struct vring_avail *avail; ///< ring of available descriptor heads
struct vring_used *used; ///< ring of used descriptor heads
- struct capref desc_cap; ///< capability for the descriptor table
- struct capref avail_cap; ///< capability for the available ring
- struct capref used_cap; ///< capability for the used ring
- struct capref buf_cap[]; ///< capabilities for the used buffers
};
/**
- * \brief Calculates the size of a virtqueue structure in memory aligned
+ * \brief Calculates the size of a vring structure in memory aligned
*
* \param num the queue size
* \param align the alignment constraints
*/
-static inline uintptr_t
-virtq_size(uint16_t num,
- uintptr_t align)
+static inline size_t vring_size(uint16_t num, uintptr_t align)
{
- return ((sizeof(struct vring_desc) * num + sizeof(uint16_t) * (2 + num) + align
- - 1)
- & ~(align - 1))
- + sizeof(uint16_t) * 2 + sizeof(struct vring_used_elem) * num;
+ // calcualte the size of the descriptor table
+ size_t size = num * sizeof(struct vring_desc);
+
+ // calculate the size of the available ring:
+ // flags + idx + num * ring + used_event
+ size += sizeof(uint16_t) * (2 + num + 1);
+
+ // do the alignment
+ size = (size + align - 1) & ~(align - 1);
+
+ // calculate the size of the used ring:
+ // flags + idx + num * used_element + avail_event
+ size += sizeof(uint16_t) * 3 + sizeof(struct vring_used_elem) * num;
+
+ return size;
}
/**
*
*/
-static inline int
-vring_need_event(uint16_t event_idx,
- uint16_t new_idx,
- uint16_t old_idx)
+static inline uint16_t vring_need_event(uint16_t event_idx,
+ uint16_t new_idx,
+ uint16_t old_idx)
{
return (uint16_t) (new_idx - event_idx - 1) < (uint16_t) (new_idx - old_idx);
}
* Note: This field is located at the very end of of the available ring data
* structure.
*/
-static inline uint16_t *
-vring_used_event(struct vring *vr)
+static inline uint16_t *vring_get_used_event(struct vring *vr)
{
return &vr->avail->ring[vr->num];
}
* Note: This field is located at the very end of of the used ring data
* structure.
*/
-static inline uint16_t *
-vring_avail_event(struct vring *vr)
+static inline uint16_t *vring_get_avail_event(struct vring *vr)
{
return (uint16_t *) &vr->used->ring[vr->num];
}
+/*
+ * We layout the vring structure in memory as follows:
+ *
+ * struct vring {
+ * // The actual descriptors (16 bytes each)
+ * struct vring_desc desc[num];
+ *
+ * // A ring of available descriptor heads with free-running index.
+ * uint16_t avail_flags;
+ * uint16_t avail_idx;
+ * uint16_t available[num];
+ * uint16_t used_event_idx;
+ *
+ * // Padding to the next align boundary.
+ * char pad[];
+ *
+ * // A ring of used descriptor heads with free-running index.
+ * uint16_t used_flags;
+ * uint16_t used_idx;
+ * struct vring_used_elem used[num];
+ * uint16_t avail_event_idx;
+ * };
+ */
+
/**
- * \brief allocates a new vring structure
+ * \brief Initializes a vring structure
+ *
+ * \param vr vring structure to initialize
+ * \param num the number of vring descriptors
+ * \param addr pointer to a contiguous memory range for the rings
+ * \param align alignment constraints for the vring
*
- * \param vr pointer to the vring structure
- * \param num the number of queue elements
- * \param align the alignment constraints for the vring
*/
-errval_t
-vring_alloc(struct vring *vr,
- uint16_t num,
- uintptr_t align);
+static inline void vring_init(struct vring *vr,
+ uint16_t num,
+ uintptr_t align,
+ void *addr)
+{
+ /* num must be a power of two */
+ assert(((num != 0) && ((num & (~num + 1)) == num)));
+
+ uintptr_t p = (uintptr_t)addr;
+
+ vr->num = num;
+ vr->desc = (struct vring_desc *) p;
+
+ vr->avail = (struct vring_avail *) (p + num * sizeof(struct vring_desc));
+
+ p = (uintptr_t)&vr->avail->ring[num];
+ vr->used = (void *) ((p + align-1) & ~(align-1));
+
+}
/**
- * \brief frees the resources used by the vring structure
+ * \brief Maps the given capability and initializes the vring on the memory
+ * backed by the supplied capability
+ *
+ * \param vr pointer to the vring structure to be initialized
+ * \param num the number of elements in the ring
+ * \param align alignment constraints for the vring
+ * \param cap frame capability used as backing memory for the structure
+ *
+ * \return SYS_ERR_OK on success
+ * errno on failure
+ */
+errval_t vring_init_from_cap(struct vring *vr,
+ uint16_t num,
+ uintptr_t align,
+ struct capref cap);
+
+/**
+ * \brief allocates a new vring structure
+ *
+ * \param vr pointer to the vring structure
+ * \param num the number of queue elements
+ * \param align the alignment constraints for the vring
+ * \param ret_frame returned frame capability
+ *
+ * \return SYS_ERR_OK on success
+ * errno on failure
*/
-errval_t
-vring_free(struct vring *vr);
+errval_t vring_alloc(struct vring *vr,
+ uint16_t num,
+ uintptr_t align,
+ struct capref *ret_frame);
/**
- * \brief Initializes a vring structure with the given caps
+ * \brief frees the resources used by the vring structure
*
- * \param vr The vring to initialize
+ * \param vr the vring to be freed
*
- * The capabilities must already been set in the vring structure. The caps
- * will be mapped into the vspace and the addresses set accordingly
+ * \return SYS_ERR_OK on success
+ * errno on failure
*/
-errval_t
-vring_init(struct vring *vr);
+errval_t vring_free(struct vring *vr);
+
#endif // VIRTIO_VIRTIO_RING_H
--- /dev/null
+/*
+ * 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_VIRTQUEUE_H
+#define VIRTIO_VIRTQUEUE_H
+
+#include <barrelfish/barrelfish.h>
+
+/*
+ * Extracted from the Virtio Specification 1.0
+ * http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf
+ *
+ * VIRQUEUES:
+ *
+ * Size is determined by a 16bit integer.
+ * The queue consists of a descriptor table, available ring, used ring
+ * Each of the three parts are physically-contiguous in guest memory.
+ *
+ */
+
+// forward definition
+struct virtqueue;
+
+/// interrupt handler for virtqueue interrupts
+typedef void (*virtq_intr_hander_t)(struct virtqueue *, void *);
+
+/// the maximum length of the name field
+#define VIRTQUEUE_NAME_SIZE 32
+
+/// the maximum number of elements in a vring
+#define VIRTQUEUE_SIZE_MAX (1<<15)
+
+/// this value marks the end of a descriptor chain
+#define VIRTQUEUE_CHAIN_END VIRTQUEUE_SIZE_MAX
+
+/// Feature flag indicating that the ring supports indirect descriptors
+#define VIRTIO_RING_F_INDIRECT_DESC (1 << 28)
+
+/// Feature flag indicating that the ring supports interrupt suppression
+#define VIRTIO_RING_F_EVENT_IDX (1 << 29)
+
+
+/**
+ * this structure holds necessary data to allocate a new virtqueue
+ */
+struct virtqueue_setup {
+ char name[VIRTQUEUE_NAME_SIZE]; ///< the name of the queue
+ struct virtio_device *device; ///< device this queue belongs to
+ uint16_t queue_id; ///< queue id of this queue
+ uint16_t vring_ndesc; ///< size of the vring
+ lvaddr_t vring_align; ///< alignment of the vring
+ virtq_intr_hander_t intr_handler; ///< interrupt handler function
+ void *intr_arg; ///< argument for the interrupt handler
+ uint16_t max_indirect; ///< maximum indirect descriptors
+};
+
+/**
+ *
+ */
+enum virtqueue_intr_postpone {
+ VIRTQUEUE_INTR_POSTPONE_SHORT,
+ VIRTQUEUE_INTR_POSTPONE_LONG,
+ VIRTQUEUE_INTR_POSTPONE_EMPTIED,
+};
+
+
+/**
+ * \brief allocates and initiates a new virtqueue structure
+ *
+ * \param setup pointer to the setup information
+ * \param vq pointer where to store the new virtqueue pointer
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_virtqueue_alloc(struct virtqueue_setup *setup,
+ struct virtqueue **vq);
+
+/**
+ * \brief allocates and initiates a new virtqueue structure
+ *
+ * \param setup pointer to the setup information
+ * \param vring_cap capability to be used for the vring
+ * \param vq pointer where to store the new virtqueue pointer
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_virtqueue_alloc_with_caps(struct virtqueue_setup *setup,
+ struct capref vring_cap,
+ struct virtqueue **vq);
+
+/**
+ * \brief frees the resources of previously allocated virtqueues
+ *
+ * \param vq pointer to the virtqueue memory to be freed
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_virtqueue_free(struct virtqueue *vq);
+
+/*
+void *virtqueue_drain(struct virtqueue *vq, int *last);
+int virtqueue_reinit(struct virtqueue *vq, uint16_t size);
+*/
+
+
+/*
+ * ===========================================================================
+ * Getter functions for certain values of the virtqueue structure
+ */
+
+/**
+ * \brief Returns the physical address of the vring.
+ *
+ * \param vq pointer to the virtqueue structure
+ *
+ * \returns the physical address of the vring
+ */
+lpaddr_t virtio_virtqueue_get_vring_paddr(struct virtqueue *vq);
+
+
+/**
+ * \brief Returns the frame capability of the vring
+ *
+ * \param vq pointer to the virtqueue structure
+ * \param ret_cap memory location where to store the capref
+ */
+void virtio_virtqueue_get_vring_cap(struct virtqueue *vq,
+ struct capref *ret_cap);
+
+
+/**
+ * \brief Returns the number of elements (number of descriptors)in the vring of
+ * this virtqueue
+ *
+ * \param vq pointer to the virtqueue structure
+ *
+ * \returns number of elements in the vring
+ */
+uint16_t virtio_virtqueue_get_num_desc(struct virtqueue *vq);
+
+/**
+ * \brief Checks if the virtqueue is empty
+ *
+ * \param vq pointer to the virtqueue structure
+ *
+ * \returns 0 the queue is not empty
+ * 1 the queue is empty
+ */
+bool virtio_virtqueue_is_empty(struct virtqueue *vq);
+
+/**
+ * \brief Checks if the virtqueue is full
+ *
+ * \param vq pointer to the virtqueue structure
+ *
+ * \returns 0 the queue is not full
+ * 1 the queue is full
+ */
+bool virtio_virtqueue_is_full(struct virtqueue *vq);
+
+/**
+ * \brief Calculates the number of used descriptors in this queue
+ *
+ * \param vq pointer to the virtqueue structure
+ *
+ * \returns number of used descriptors
+ */
+uint16_t virtio_virtqueue_get_num_used(struct virtqueue *vq);
+
+
+/*
+ * ===========================================================================
+ * Interrupt handling
+ */
+
+/**
+ * \brief enables the interrupts on the next descriptor processed
+ *
+ * \param vq the virtqueue to enable the interrupts
+ *
+ * \returns 1 if the interrupts have been enabled
+ * 0 if the interrupts have not been enabled
+ */
+bool virtio_virtqueue_intr_enable(struct virtqueue *vq);
+
+/**
+ * \brief postpones the interrupt to a later point of time
+ *
+ * \param vq the virtqueue to enable the interrupts
+ * \param
+ *
+ * \returns 1 if the interrupts have been enabled
+ * 0 if the interrupts have not been enabled
+ */
+bool virtio_virtqueue_intr_postpone(struct virtqueue *vq,
+ enum virtqueue_intr_postpone hint);
+
+/**
+ * \brief checks if the interrupts can be disabled
+ *
+ * \param vq virtual queue to check
+ *
+ * \returns 1 if the interrupts have been disabled
+ * 0 if the interrupts are not changed
+ *
+ */
+bool virtio_virtqueue_intr_filter(struct virtqueue *vq);
+
+/**
+ * \brief calls the interrupt handler for this virtqueue
+ *
+ * \param vq virtqueue to call the intr handler for
+ */
+void virtio_virtqueue_intr_handle(struct virtqueue *vq);
+
+/**
+ * \brief disables the interrupts for the given virtqueue by giving a hint
+ * to the host
+ *
+ * \param vq virtqueue to disable the interrupts
+ */
+void virtio_virtqueue_intr_disable(struct virtqueue *vq);
+
+
+/**
+ * \brief notifies the host about the new queued descriptors
+ *
+ * \param vq virtqueue to notify the host
+ */
+void virtio_virtqueue_notify_host(struct virtqueue *vq);
+
+
+/**
+ * \brief masks the ring features out of a features bit mask
+ *
+ * \param features the features to mask
+ *
+ * \returns bitmask of masked features
+ */
+static inline uint64_t virtio_virtqueue_mask_features(uint64_t features)
+{
+ uint64_t mask;
+
+ mask = (1 << VIRTIO_TRANSPORT_F_START) - 1;
+ mask |= VIRTIO_RING_F_INDIRECT_DESC;
+ mask |= VIRTIO_RING_F_EVENT_IDX;
+
+ return (features & mask);
+}
+
+/*
+ * ===========================================================================
+ * Virtqueue Queue Management
+ */
+
+errval_t virtio_virtqueue_desc_enqueue(struct virtqueue *vq,
+ struct virtio_buffer *buf,
+ void *vaddr,
+ uint16_t writeable,
+ uint16_t readable);
+
+#if 0
+int virtqueue_enqueue(struct virtqueue *vq, void *cookie,
+ struct sglist *sg, int readable, int writable);
+void *virtqueue_dequeue(struct virtqueue *vq, uint32_t *len);
+void *virtqueue_poll(struct virtqueue *vq, uint32_t *len);
+
+
+
+uint64_t virtqueue_filter_features(uint64_t features);
+
+void virtqueue_dump(struct virtqueue *vq);
+#endif
+
+
+#endif // VIRTIO_VIRTQUEUE_H
--------------------------------------------------------------------------
[ build library { target = "virtio",
- cFiles = [ "virtio_ring.c" ],
- mackerelDevices = [ "virtio/virtio_mmio", "virtio/virtio_blk" ]
+ cFiles = [ "virtio_ring.c",
+ "virtqueue.c",
+ "virtio_device.c",
+ "backends/virtio_device_mmio.c",
+ "backends/virtio_device_pci.c" ],
+ mackerelDevices = [ "virtio/virtio_mmio" ]
}
]
--- /dev/null
+/*
+ * 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 "backends/virtio_mmio.h"
+
+/**
+ * \brief initializes and allocates a VirtIO device structure for the MMIO backend
+ */
+errval_t virtio_device_mmio_init(struct virtio_device **dev,
+ struct virtio_device_init *info)
+{
+ return SYS_ERR_OK;
+}
+
+
+
--- /dev/null
+/*
+ * 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 "backends/virtio_pci.h"
+
+
+errval_t virtio_device_pci_alloc(struct virtio_device **dev)
+{
+ return SYS_ERR_OK;
+}
+
+errval_t virtio_device_pci_free(struct virtio_device **dev)
+{
+ return SYS_ERR_OK;
+}
+
+
+
--- /dev/null
+/*
+ * 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_VIRTIO_MMIO_H
+#define VIRTIO_VIRTIO_MMIO_H
+
+#include <barrelfish/barrelfish.h>
+
+#include <virtio/virtio.h>
+#include <virtio/virtio_device.h>
+
+struct virtio_device_mmio
+{
+ struct virtio_device dev;
+
+};
+
+/**
+ * \brief initializes and allocates a VirtIO device structure for the MMIO backend
+ *
+ * \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(struct virtio_device **dev,
+ struct virtio_device_init *info);
+
+#endif // VIRTIO_VIRTIO_MMIO_H
-/**
- * \file
- * \brief Driver for booting the Xeon Phi Coprocessor card on a Barrelfish Host
- */
-
/*
* Copyright (c) 2014 ETH Zurich.
* All rights reserved.
* ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
*/
+#ifndef VIRTIO_VIRTIO_PCI_H
+#define VIRTIO_VIRTIO_PCI_H
+
+#include <barrelfish/barrelfish.h>
+
+
+
+#define VIRTIO_PCI_VRING_ALIGNMENT 4096
+
+errval_t virtio_device_pci_alloc(struct virtio_device **dev);
+
+errval_t virtio_device_pci_free(struct virtio_device **dev);
+
+#endif // VIRTIO_VIRTIO_PCI_H
--- /dev/null
+/*
+ * 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_DEBUG_H_
+#define VIRTIO_DEBUG_H_
+
+#define VIRTIO_DEBUG_ENABLED 1
+#define VIRTIO_DEBUG_VQ_ENABLED 1
+
+#if VIRTIO_DEBUG_ENABLED
+#define VIRTIO_DEBUG_PRINT(msg...) debug_printf(msg)
+#else
+#define VIRTIO_DEBUG_PRINT(msg...)
+#endif
+
+#ifdef VIRTIO_DEBUG_VQ_ENABLED
+#define VIRTIO_DEBUG_VQ(msg...) VIRTIO_DEBUG_PRINT("[VIRTQUEUE] " msg)
+#else
+#define VIRTIO_DEBUG_VQ(msg...)
+#endif
+
+
+#endif /* VIRTIO_DEBUG_H_ */
--- /dev/null
+/*
+ * 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>
+
+#if 0
+
+void stack_alloc_init(struct stack_allocator *alloc, size_t size)
+{
+ alloc->size = size;
+ alloc->top = 0;
+ alloc->stack = calloc(size, sizeof(void *));
+}
+
+bool stack_alloc_free(struct stack_allocator *alloc, void *el)
+{
+ if (alloc->top >= alloc->size) {
+ return false;
+ }
+
+ alloc->stack[alloc->top++] = el;
+ return true;
+}
+
+void *stack_alloc_alloc(struct stack_allocator *alloc)
+{
+ if (alloc->top == 0) {
+ return NULL;
+ }
+ return alloc->stack[--alloc->top];
+}
+
+
+#endif
+
--- /dev/null
+/*
+ * 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_VIRTIO_BUFFER_H
+#define VIRTIO_VIRTIO_BUFFER_H
+
+/**
+ * library internal representation of a buffer allocator
+ */
+struct virtio_buffer_allocator
+{
+ struct virtio_buffer *buffers; ///< array of virtio_buffers
+ uint16_t size; ///< number of buffers in this allocator
+ uint16_t top; ///< pointer to the top slot
+ struct capref cap; ///< frame capability backing this allocator
+ struct virtqueue *queue; ///< the virtqueue this allocator belongs to
+};
+
+/**
+ * \brief initializes the buffer allocator and allocates memory for the
+ * buffers
+ *
+ * \param alloc the allocator struct to initialize
+ * \param nbufs number of buffers to allocate
+ * \param bufsz size of each buffer to allocate
+ *
+ * \return SYS_ERR_OK on success
+ */
+errval_t virtio_buffer_alloc_init(struct virtio_buffer_allocator *alloc,
+ size_t nbufs,
+ size_t bufsz);
+
+/**
+ * \brief destroys a buffer allocator by freeing up all the resources used
+ * by the buffers
+ *
+ * \param alloc the allocator to destroy
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_buffer_alloc_destroy(struct virtio_buffer_allocator *alloc);
+
+
+struct virtio_buffer *virtio_buffer_alloc(struct virtio_buffer_allocator *alloc);
+
+/**
+ * \brief frees up a unused buffer by returning it to the allocator
+ *
+ * \param buf the buffer to be freed
+ */
+errval_t virtio_buffer_free(struct virtio_buffer_allocator *alloc,
+ struct virtio_buffer *buf);
+
+/**
+ * \brief returns the backing frame capability of a buffer allocator
+ */
+errval_t virtio_buffer_alloc_get_cap(struct virtio_buffer_allocator *alloc,
+ struct capref *ret_cap);
+
+
+#endif // VIRTIO_VIRTIO_BUFFER_H
-/**
- * \file
- * \brief Driver for booting the Xeon Phi Coprocessor card on a Barrelfish Host
- */
-
/*
* Copyright (c) 2014 ETH Zurich.
* All rights reserved.
* 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 "backends/virtio_mmio.h"
+#include "backends/virtio_pci.h"
+
+
#include <virtio/virtio_ring.h>
-
+/*
+ * We layout the vring structure in memory as follows:
+ *
+ * struct vring {
+ * // The actual descriptors (16 bytes each)
+ * struct vring_desc desc[num];
+ *
+ * // A ring of available descriptor heads with free-running index.
+ * uint16_t avail_flags;
+ * uint16_t avail_idx;
+ * uint16_t available[num];
+ * uint16_t used_event_idx;
+ *
+ * // Padding to the next align boundary.
+ * char pad[];
+ *
+ * // A ring of used descriptor heads with free-running index.
+ * uint16_t used_flags;
+ * uint16_t used_idx;
+ * struct vring_used_elem used[num];
+ * uint16_t avail_event_idx;
+ * };
+ */
/**
- * \brief allocates a new vring structure
+ * \brief Maps the given capability and initializes the vring on the memory
+ * backed by the supplied capability
+ *
+ * \param vr pointer to the vring structure to be initialized
+ * \param num the number of elements in the ring
+ * \param align alignment constraints for the vring
+ * \param cap frame capability used as backing memory for the structure
*
- * \param vr pointer to the vring structure
- * \param num the number of queue elements
- * \param align the alignment constraints for the vring
+ * \return SYS_ERR_OK on success
+ * errno on failure
*/
-errval_t
-vring_alloc(struct vring *vr,
- uint16_t num,
- uintptr_t align)
+errval_t vring_init_from_cap(struct vring *vr,
+ uint16_t num,
+ uintptr_t align,
+ struct capref cap)
{
+ errval_t err;
+
+ /* num must be a power of two */
+ assert(((num != 0) && ((num & (~num + 1)) == num)));
+
+ size_t size = vring_size(num, align);
+
+ struct frame_identity id;
+ err = invoke_frame_identify(cap, &id);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_FRAME_IDENTIFY);
+ }
+ /* check if we have enough space in the given cap */
+ if ((1UL << id.bits) < size) {
+ return SYS_ERR_INVALID_SIZE_BITS;
+ }
+ void *addr;
+ err = vspace_map_one_frame(&addr, (1UL << id.bits), cap, NULL, NULL);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_VSPACE_MAP);
+ }
+ vring_init(vr, num, align, addr);
+
+ return SYS_ERR_OK;
}
/**
- * \brief frees the resources used by the vring structure
+ * \brief allocates a new vring structure
+ *
+ * \param vr pointer to the vring structure
+ * \param num the number of queue elements
+ * \param align the alignment constraints for the vring
+ * \param ret_frame returned frame capability
+ *
+ * \return SYS_ERR_OK on success
+ * errno on failure
*/
-errval_t
-vring_free(struct vring *vr)
+errval_t vring_alloc(struct vring *vr,
+ uint16_t num,
+ uintptr_t align,
+ struct capref *ret_frame)
{
+ errval_t err;
+
+ /* num must be a power of two */
+ assert(((num != 0) && ((num & (~num + 1)) == num)));
+ size_t size = vring_size(num, align);
+ struct capref frame;
+ err = frame_alloc(&frame, size, &size);
+ if (err_is_fail(err)) {
+ return err;
+ }
+
+ err = vring_init_from_cap(vr, num, align, frame);
+ if (err_is_fail(err)) {
+ return err;
+ }
+
+ if (ret_frame) {
+ *ret_frame = frame;
+ }
+
+ return SYS_ERR_OK;
}
/**
- * \brief Initializes a vring structure with the given caps
+ * \brief frees the resources used by the vring structure
*
- * \param vr The vring to initialize
+ * \param vr the vring to be freed
*
- * The capabilities must already been set in the vring structure. The caps
- * will be mapped into the vspace and the addresses set accordingly
+ * \return SYS_ERR_OK on success
+ * errno on failure
*/
-errval_t
-vring_init(struct vring *vr)
+errval_t vring_free(struct vring *vr)
{
+ errval_t err;
+ err = vspace_unmap(vr->desc);
+ if (err_is_fail(err)) {
+ return err;
+ }
+ assert(!"NYI: returning the cap to the origin");
+ return SYS_ERR_OK;
}
+
--- /dev/null
+/*
+ * 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 <string.h>
+
+#include <barrelfish/barrelfish.h>
+
+#include <virtio/virtio.h>
+#include <virtio/virtio_ring.h>
+#include <virtio/virtqueue.h>
+
+#include "debug.h"
+
+
+#define IS_POW2(num) (((num) != 0) && (((num) & (~(num) + 1)) == (num)))
+
+
+#define VIRTQUEUE_FLAG_INDIRECT 0x0001
+#define VIRTQUEUE_FLAG_EVENT_IDX 0x0002
+
+/**
+ * this data structure stores additional information to the descriptors
+ */
+struct vring_desc_info
+{
+ void *buf; ///< virtual address of this descriptor
+ struct capref cap; ///< capability of this descriptor
+ size_t size; ///< the size of the capability in bytes
+ lpaddr_t paddr; ///< physical address of this descriptor
+ lpaddr_t offset; ///< offset into the capability for mapping
+};
+
+/**
+ * this data structure represents a VirtIO queue. It contains additional
+ * information not stored with the vring structure
+ */
+struct virtqueue
+{
+ /* device information */
+ struct virtio_device *device; ///< pointer to to the virtio device
+ uint16_t queue_index; ///< index of this queue in the device
+ char name[VIRTQUEUE_NAME_SIZE]; ///< name of the queue for debugging
+
+ /* vring information */
+ struct vring vring; ///< vring data structure
+ uint16_t vring_ndesc; ///< number of descriptors of this vring
+ uint32_t flags; ///< flags
+ uint16_t free_head; ///< head of the free descriptor chain
+ uint16_t free_count; ///< number of available free descriptors
+ uint16_t used_tail; ///< last consumed descriptor used table
+ uint16_t used_count; ///< number of queued used descriptors
+
+ /* vring memory information */
+ struct capref vring_cap; ///< capability of the vring data structure
+ lvaddr_t vring_vaddr; ///< virtual address of the vring in memory
+ lpaddr_t vring_paddr; ///< physical address of the vring
+ size_t vring_size; ///< the size of the vring in memory
+ lvaddr_t vring_align; ///< the alignment of the vring
+
+ /* interrupt handling */
+ virtq_intr_hander_t intr_handler; ///< interrupt handler
+ void *intr_arg; ///< user argument for the handler
+
+ struct vring_desc_info vring_di[0]; ///< array of additional desc information
+#if 0
+ /* indirect descriptors */
+ uint16_t max_indirect;
+ size_t indirect_size;
+ struct vq_desc_extra {
+ void *cookie; << virtual address?
+ struct vring_desc *indirect;
+ vm_paddr_t indirect_paddr;
+ uint16_t ndescs;
+ } vq_descx[0];
+#endif
+};
+
+/**
+ * \brief sets the interrupt threshold to num_desc processed descriptors
+ *
+ * \param vq virtqueue to enable the interrupts
+ * \param num_desc the interrupt threshold
+ *
+ * \returns 1 if the interrupts have been enabled
+ * 0 if the interrupts have not been enabled
+ */
+static bool virtqueue_interrupt_enable(struct virtqueue *vq,
+ uint16_t num_desc)
+{
+ if (vq->flags & VIRTQUEUE_FLAG_EVENT_IDX) {
+ uint16_t *used_event = vring_get_used_event(&vq->vring);
+ *used_event = vq->used_tail + num_desc;
+ } else {
+ vq->vring.avail->flags &= ~VIRTIO_RING_AVAIL_F_NO_INTERRUPT;
+ }
+
+ assert(!"NYI: memory barrier mb()");
+
+ if (virtio_virtqueue_get_num_used(vq) > num_desc) {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * \brief initializes the vring structure of the virtqueue
+ *
+ * \param vq virtqueue of the vring to initialize
+ */
+static void virtqueue_init_vring(struct virtqueue *vq)
+{
+ struct vring *vr = &vq->vring;
+
+ assert(vq);
+ assert(vq->vring_ndesc);
+ assert(vq->vring_vaddr);
+
+ /*
+ * initialize the vring structure in memory
+ */
+ vring_init(vr, vq->vring_ndesc, vq->vring_align, (void *)vq->vring_vaddr);
+
+ /*
+ * initialize the descriptor chains
+ */
+ uint32_t i;
+ for (i = 0; i < vq->vring_ndesc; ++i) {
+ vr->desc[i].next = i+1;
+ }
+ vr->desc[i].next = VIRTQUEUE_CHAIN_END;
+
+}
+
+
+/*
+ * ============================================================================
+ * Public Interface
+ * ============================================================================
+ */
+
+
+/*
+ * ----------------------------------------------------------------------------
+ * Virtqueue Allocation / Deallocation
+ */
+
+/**
+ * \brief allocates and initiates a new virtqueue structure
+ *
+ * \param setup pointer to the setup information
+ * \param vq pointer where to store the new virtqueue pointer
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_virtqueue_alloc(struct virtqueue_setup *setup,
+ struct virtqueue **vq)
+{
+ errval_t err;
+
+ assert(vq);
+
+ if (setup->vring_ndesc == 0 || !IS_POW2(setup->vring_ndesc)) {
+ VIRTIO_DEBUG_VQ("ERROR: invalid size: %u\n", setup->vring_ndesc);
+ return VIRTIO_ERR_SIZE_INVALID;
+ }
+
+ size_t size = vring_size(setup->vring_ndesc, setup->vring_align);
+ size = ROUND_UP(size, BASE_PAGE_SIZE);
+
+ struct capref vring_cap;
+ size_t framesize;
+ err = frame_alloc(&vring_cap, size, &framesize);
+ if (err_is_fail(err)) {
+ return err;
+ }
+
+ VIRTIO_DEBUG_VQ("Allocated memory for vring: [%lx & %lx]",
+ (uint64_t)size, (uint64_t)framesize);
+
+ err = virtio_virtqueue_alloc_with_caps(setup, vring_cap, vq);
+ if (err_is_fail(err)) {
+ cap_destroy(vring_cap);
+ return err;
+ }
+
+ return SYS_ERR_OK;
+}
+
+/**
+ * \brief allocates and initiates a new virtqueue structure
+ *
+ * \param setup pointer to the setup information
+ * \param vring_cap capability to be used for the vring
+ * \param vq pointer where to store the new virtqueue pointer
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_virtqueue_alloc_with_caps(struct virtqueue_setup *setup,
+ struct capref vring_cap,
+ struct virtqueue **ret_vq)
+{
+ errval_t err;
+
+ assert(ret_vq);
+
+ if (setup->vring_ndesc == 0 || !IS_POW2(setup->vring_ndesc)) {
+ VIRTIO_DEBUG_VQ("ERROR: invalid size: %u\n", setup->vring_ndesc);
+ return VIRTIO_ERR_SIZE_INVALID;
+ }
+
+ if (setup->max_indirect > VIRTIO_RING_MAX_INDIRECT) {
+ VIRTIO_DEBUG_VQ("ERROR: too many indirect descriptors requested: [%u / %u]\n", setup->vring_ndesc, VIRTIO_RING_MAX_INDIRECT);
+ return VIRTIO_ERR_MAX_INDIRECT;
+ }
+
+ assert(!capref_is_null(vring_cap));
+
+ struct frame_identity id;
+ err = invoke_frame_identify(vring_cap, &id);
+ if (err_is_fail(err)) {
+ return err;
+ }
+
+ size_t vring_mem_size = vring_size(setup->vring_ndesc, setup->vring_align);
+ vring_mem_size = ROUND_UP(vring_mem_size, BASE_PAGE_SIZE);
+
+ if (vring_mem_size > (1UL << id.bits)) {
+ VIRTIO_DEBUG_VQ("ERROR: supplied cap was too small %lx, needed %lx\n",
+ ((1UL << id.bits)), (uint64_t)vring_mem_size);
+ return VIRTIO_ERR_CAP_SIZE;
+ }
+
+ void *vring_addr;
+ err = vspace_map_one_frame(&vring_addr, vring_mem_size, vring_cap, NULL, NULL);
+ if (err_is_fail(err)) {
+ return err;
+ }
+
+ struct virtqueue *vq = calloc(1, sizeof(struct virtqueue)
+ + (setup->vring_ndesc * sizeof(struct vring_desc_info)));
+ if (vq == NULL) {
+ vspace_unmap(vring_addr);
+ return LIB_ERR_MALLOC_FAIL;
+ }
+
+ vq->device = setup->device;
+ strncpy(vq->name, setup->name, sizeof(vq->name));
+ vq->queue_index = setup->queue_id;
+ vq->vring_ndesc = setup->vring_ndesc;
+ vq->vring_align = setup->vring_align;
+ vq->vring_size = vring_mem_size;
+ vq->vring_cap = vring_cap;
+ vq->vring_paddr = id.base;
+ vq->vring_vaddr = (lvaddr_t)vring_addr;
+ vq->free_count = setup->vring_ndesc;
+
+
+ vq->intr_handler = setup->intr_handler;
+ vq->intr_arg = setup->intr_arg;
+
+ if (setup->max_indirect > 0) {
+ /*
+ * TODO: initialize indirect descriptors
+ */
+ }
+
+#if 0
+ if (VIRTIO_BUS_WITH_FEATURE(dev, VIRTIO_RING_F_EVENT_IDX) != 0)
+ vq->vq_flags |= VIRTQUEUE_FLAG_EVENT_IDX;
+#endif
+
+ virtqueue_init_vring(vq);
+ virtio_virtqueue_intr_disable(vq);
+
+ if (ret_vq) {
+ *ret_vq = vq;
+ }
+
+ return SYS_ERR_OK;
+}
+
+
+/**
+ * \brief frees the resources of previously allocated virtqueues
+ *
+ * \param vq pointer to the virtqueue memory to be freed
+ *
+ * \returns SYS_ERR_OK on success
+ */
+errval_t virtio_virtqueue_free(struct virtqueue *vq)
+{
+ assert(!"NYI: virtio_virtqueue_free");
+
+ return SYS_ERR_OK;
+}
+
+
+/*
+ * ----------------------------------------------------------------------------
+ * Virtqueue Getter Functions
+ */
+
+/**
+ * \brief Returns the physical address of the vring.
+ *
+ * \param vq pointer to the virtqueue structure
+ *
+ * \returns the physical address of the vring
+ */
+lpaddr_t virtio_virtqueue_get_vring_paddr(struct virtqueue *vq)
+{
+ return vq->vring_paddr;
+}
+
+/**
+ * \brief Returns the frame capability of the vring
+ *
+ * \param vq pointer to the virtqueue structure
+ * \param ret_cap memory location where to store the capref
+ */
+void virtio_virtqueue_get_vring_cap(struct virtqueue *vq,
+ struct capref *ret_cap)
+{
+ if (ret_cap) {
+ *ret_cap = vq->vring_cap;
+ }
+}
+
+/**
+ * \brief Returns the number of elements (number of descriptors)in the vring of
+ * this virtqueue
+ *
+ * \param vq pointer to the virtqueue structure
+ *
+ * \returns number of elements in the vring
+ */
+uint16_t virtio_virtqueue_get_num_desc(struct virtqueue *vq)
+{
+ return vq->vring_ndesc;
+}
+
+/**
+ * \brief Checks if the virtqueue is empty
+ *
+ * \param vq pointer to the virtqueue structure
+ *
+ * \returns 0 the queue is not empty
+ * 1 the queue is empty
+ */
+bool virtio_virtqueue_is_empty(struct virtqueue *vq)
+{
+ return (vq->vring_ndesc == vq->free_count);
+}
+
+/**
+ * \brief Checks if the virtqueue is full
+ *
+ * \param vq pointer to the virtqueue structure
+ *
+ * \returns 0 the queue is not full
+ * 1 the queue is full
+ */
+bool virtio_virtqueue_is_full(struct virtqueue *vq)
+{
+ return (vq->free_count == 0);
+}
+
+/**
+ * \brief Calculates the number of used descriptors in this queue
+ *
+ * \param vq pointer to the virtqueue structure
+ *
+ * \returns number of used descriptors
+ */
+uint16_t virtio_virtqueue_get_num_used(struct virtqueue *vq)
+{
+ uint16_t num_used;
+
+ num_used = vq->vring.used->idx - vq->used_tail;
+
+ /* sanity check */
+ assert(num_used <= vq->vring_ndesc);
+
+ return num_used;
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+/**
+ * \brief checks if the interrupts can be disabled
+ *
+ * \param vq virtual queue to check
+ *
+ * \returns 1 if the interrupts have been disabled
+ * 0 if the interrupts are not changed
+ *
+ */
+bool virtio_virtqueue_intr_filter(struct virtqueue *vq)
+{
+ if (vq->used_tail == vq->vring.used->idx) {
+ return 0;
+ }
+
+ virtio_virtqueue_intr_disable(vq);
+
+ return 1;
+}
+
+/**
+ * \brief calls the interrupt handler for this virtqueue
+ *
+ * \param vq virtqueue to call the intr handler for
+ */
+void virtio_virtqueue_intr_handle(struct virtqueue *vq)
+{
+ if (vq->intr_handler == NULL) {
+ VIRTIO_DEBUG_VQ("Notice: Interrupt handler is not set\n");
+ return;
+ }
+ vq->intr_handler(vq, vq->intr_arg);
+}
+
+
+/**
+ * \brief enables the interrupts on the next descriptor processed
+ *
+ * \param vq the virtqueue to enable the interrupts
+ *
+ * \returns 1 if the interrupts have been enabled
+ * 0 if the interrupts have not been enabled
+ */
+bool virtio_virtqueue_intr_enable(struct virtqueue *vq)
+{
+ return virtqueue_interrupt_enable(vq, 0);
+}
+
+/**
+ * \brief postpones the interrupt to a later point of time
+ *
+ * \param vq the virtqueue to enable the interrupts
+ * \param
+ *
+ * \returns 1 if the interrupts have been enabled
+ * 0 if the interrupts have not been enabled
+ */
+bool virtio_virtqueue_intr_postpone(struct virtqueue *vq,
+ enum virtqueue_intr_postpone hint)
+{
+ uint16_t ndesc = vq->vring.avail->idx - vq->used_tail;
+
+ switch (hint) {
+ case VIRTQUEUE_INTR_POSTPONE_SHORT:
+ ndesc = ndesc / 4;
+ break;
+ case VIRTQUEUE_INTR_POSTPONE_LONG:
+ ndesc = (ndesc * 3) / 4;
+ break;
+ case VIRTQUEUE_INTR_POSTPONE_EMPTIED:
+ break;
+ }
+
+ return virtqueue_interrupt_enable(vq, ndesc);
+}
+
+
+/**
+ * \brief disables the interrupts for the given virtqueue
+ *
+ * \param vq virtqueue to disable the interrupts
+ */
+void virtio_virtqueue_intr_disable(struct virtqueue *vq)
+{
+ if (vq->flags & VIRTQUEUE_FLAG_EVENT_IDX) {
+ uint16_t *used_event = vring_get_used_event(&vq->vring);
+ *used_event = vq->used_tail - vq->vring_ndesc - 1;
+ } else {
+ vq->vring.avail->flags |= VIRTIO_RING_AVAIL_F_NO_INTERRUPT;
+ }
+}
+
+/**
+ * \brief notifies the host about the new queued descriptors
+ *
+ * \param vq virtqueue to notify the host
+ */
+void virtio_virtqueue_notify_host(struct virtqueue *vq)
+{
+ assert(!"NYI: host notify");
+}
+
+
+/*
+ * ----------------------------------------------------------------------------
+ * Queue Management
+ */
+
+#if 0
+
+/**
+ *
+ */
+errval_t virtio_virtqueue_desc_alloc(struct virtqueue *vq,
+ size_t )
+
+errval_t virtio_virtqueue_desc_enq(struct virtqueue *vq,
+ )
+{
+ assert(!"NYI: virtio_virtqueue_enq");
+ return SYS_ERR_OK;
+}
+
+void *virtio_virtqueue_desc_deq(struct virtqueue *vq)
+{
+ return NULL;
+}
+
+
+
+void *virtio_virtqueue_poll(struct virtqueue *vq)
+{
+ return NULL;
+};
+
+#endif
+
--- /dev/null
+--------------------------------------------------------------------------
+-- Copyright (c) 2007-2010, 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.
+--
+-- Hakefile for /usr/drivers/virtio_net
+--
+--------------------------------------------------------------------------
+
+[ build application { target = "virtio_blk",
+ cFiles = [ "main_guest.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" ],
+ architectures= ["x86_64", "k1om"]
+ },
+ build application { target = "virtio_blk_host",
+ cFiles = [ "main_host.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" ],
+ architectures= ["x86_64"]
+ }
+]
+
+
+
+
+
+
\ No newline at end of file
*/
+int main(int argc, char *argv[])
+{
+
+}
--- /dev/null
+--------------------------------------------------------------------------
+-- Copyright (c) 2007-2010, 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.
+--
+-- Hakefile for /usr/drivers/virtio_net
+--
+--------------------------------------------------------------------------
+
+[ build application { target = "virtio_console",
+ cFiles = [ "main_guest.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 = [ "xeon_phi/xeon_phi_apic" ],
+ architectures= ["x86_64", "k1om"]
+
+ },
+ build application { target = "virtio_console_host",
+ cFiles = [ "main_host.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 = [ "xeon_phi/xeon_phi_apic" ],
+ architectures= ["x86_64"]
+
+ }
+]
+
+
+
+
+
+
\ No newline at end of file
--- /dev/null
+--------------------------------------------------------------------------
+-- Copyright (c) 2007-2010, 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.
+--
+-- Hakefile for /usr/drivers/virtio_net
+--
+--------------------------------------------------------------------------
+
+[ build application { target = "virtio_net",
+ cFiles = [ "main_guest.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 = [ "xeon_phi/xeon_phi_apic" ],
+ architectures= ["x86_64", "k1om"]
+ },
+ build application { target = "virtio_net_host",
+ cFiles = [ "main_host.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 = [ "xeon_phi/xeon_phi_apic" ],
+ architectures= ["x86_64"]
+ }
+]
+
+
+
+
+
+
\ No newline at end of file