aboutsummaryrefslogtreecommitdiff
path: root/lib/libvirtio
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libvirtio')
-rw-r--r--lib/libvirtio/Makefile53
-rw-r--r--lib/libvirtio/virtio-blk.c158
-rw-r--r--lib/libvirtio/virtio-blk.h60
-rw-r--r--lib/libvirtio/virtio.c191
-rw-r--r--lib/libvirtio/virtio.code53
-rw-r--r--lib/libvirtio/virtio.h84
-rw-r--r--lib/libvirtio/virtio.in18
7 files changed, 617 insertions, 0 deletions
diff --git a/lib/libvirtio/Makefile b/lib/libvirtio/Makefile
new file mode 100644
index 0000000..e4fb34e
--- /dev/null
+++ b/lib/libvirtio/Makefile
@@ -0,0 +1,53 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2008 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+TOPCMNDIR ?= ../..
+
+ASFLAGS = $(FLAG) $(RELEASE) $(CPUARCHDEF) -Wa,-mregnames
+CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \
+ -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH)
+LDFLAGS = -nostdlib
+
+TARGET = ../libvirtio.a
+
+
+all: $(TARGET)
+
+SRCS = virtio.c virtio-blk.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+$(TARGET): $(OBJS)
+ $(AR) -rc $@ $(OBJS)
+ $(RANLIB) $@
+
+%.o: %.S
+ $(CC) $(CPPFLAGS) $(ASFLAGS) -c $< -o $@
+
+clean:
+ $(RM) $(TARGET) $(OBJS)
+
+distclean: clean
+ $(RM) Makefile.dep
+
+
+# Rules for creating the dependency file:
+depend:
+ $(RM) Makefile.dep
+ $(MAKE) Makefile.dep
+
+Makefile.dep: Makefile
+ $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep
+
+# Include dependency file if available:
+-include Makefile.dep
+
diff --git a/lib/libvirtio/virtio-blk.c b/lib/libvirtio/virtio-blk.c
new file mode 100644
index 0000000..7b1e795
--- /dev/null
+++ b/lib/libvirtio/virtio-blk.c
@@ -0,0 +1,158 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <stdio.h>
+#include "virtio.h"
+#include "virtio-blk.h"
+
+#define sync() asm volatile (" sync \n" ::: "memory")
+
+
+/**
+ * Initialize virtio-block device.
+ * @param dev pointer to virtio device information
+ */
+int
+virtioblk_init(struct virtio_device *dev)
+{
+ struct vring_avail *vq_avail;
+
+ /* Reset device */
+ // virtio_reset_device(dev);
+
+ /* Acknowledge device. */
+ virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE);
+
+ /* Tell HV that we know how to drive the device. */
+ virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER);
+
+ /* Device specific setup - we do not support special features right now */
+ virtio_set_guest_features(dev, 0);
+
+ vq_avail = virtio_get_vring_avail(dev, 0);
+ vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
+ vq_avail->idx = 0;
+
+ /* Tell HV that setup succeeded */
+ virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER
+ |VIRTIO_STAT_DRIVER_OK);
+
+ return 0;
+}
+
+
+/**
+ * Shutdown the virtio-block device.
+ * @param dev pointer to virtio device information
+ */
+void
+virtioblk_shutdown(struct virtio_device *dev)
+{
+ /* Quiesce device */
+ virtio_set_status(dev, VIRTIO_STAT_FAILED);
+
+ /* Reset device */
+ virtio_reset_device(dev);
+}
+
+
+/**
+ * Read blocks
+ * @param reg pointer to "reg" property
+ * @param buf pointer to destination buffer
+ * @param blocknum block number of the first block that should be read
+ * @param cnt amount of blocks that should be read
+ * @return number of blocks that have been read successfully
+ */
+int
+virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt)
+{
+ struct vring_desc *desc;
+ int id, i;
+ static struct virtio_blk_req blkhdr;
+ //struct virtio_blk_config *blkconf;
+ uint64_t capacity;
+ uint32_t vq_size;
+ struct vring_desc *vq_desc; /* Descriptor vring */
+ struct vring_avail *vq_avail; /* "Available" vring */
+ struct vring_used *vq_used; /* "Used" vring */
+ volatile uint8_t status = -1;
+ volatile uint16_t *current_used_idx;
+ uint16_t last_used_idx;
+
+ //printf("virtioblk_read: dev=%p buf=%p blocknum=%li count=%li\n",
+ // dev, buf, blocknum, cnt);
+
+ /* Check whether request is within disk capacity */
+ capacity = virtio_get_config(dev, 0, sizeof(capacity));
+ if (blocknum + cnt - 1 > capacity) {
+ puts("virtioblk_read: Access beyond end of device!");
+ return 0;
+ }
+
+ vq_size = virtio_get_qsize(dev, 0);
+ vq_desc = virtio_get_vring_desc(dev, 0);
+ vq_avail = virtio_get_vring_avail(dev, 0);
+ vq_used = virtio_get_vring_used(dev, 0);
+
+ last_used_idx = vq_used->idx;
+ current_used_idx = &vq_used->idx;
+
+ /* Set up header */
+ blkhdr.type = VIRTIO_BLK_T_IN | VIRTIO_BLK_T_BARRIER;
+ blkhdr.ioprio = 1;
+ blkhdr.sector = blocknum;
+
+ /* Determine descriptor index */
+ id = (vq_avail->idx * 3) % vq_size;
+
+ /* Set up virtqueue descriptor for header */
+ desc = &vq_desc[id];
+ desc->addr = (uint64_t)&blkhdr;
+ desc->len = sizeof(struct virtio_blk_req);
+ desc->flags = VRING_DESC_F_NEXT;
+ desc->next = (id + 1) % vq_size;
+
+ /* Set up virtqueue descriptor for data */
+ desc = &vq_desc[(id + 1) % vq_size];
+ desc->addr = (uint64_t)buf;
+ desc->len = cnt * 512;
+ desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
+ desc->next = (id + 2) % vq_size;
+
+ /* Set up virtqueue descriptor for status */
+ desc = &vq_desc[(id + 2) % vq_size];
+ desc->addr = (uint64_t)&status;
+ desc->len = 1;
+ desc->flags = VRING_DESC_F_WRITE;
+ desc->next = 0;
+
+ vq_avail->ring[vq_avail->idx % vq_size] = id;
+ sync();
+ vq_avail->idx += 1;
+
+ /* Tell HV that the queue is ready */
+ virtio_queue_notify(dev, 0);
+
+ /* Wait for host to consume the descriptor */
+ i = 10000000;
+ while (*current_used_idx == last_used_idx && i-- > 0) {
+ sync();
+ }
+
+ if (status == 0)
+ return cnt;
+
+ printf("virtioblk_read failed! status = %i\n", status);
+
+ return 0;
+}
diff --git a/lib/libvirtio/virtio-blk.h b/lib/libvirtio/virtio-blk.h
new file mode 100644
index 0000000..7c2b7e0
--- /dev/null
+++ b/lib/libvirtio/virtio-blk.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+/*
+ * Virtio block device definitions.
+ * See Virtio Spec, Appendix D, for details
+ */
+
+#ifndef _VIRTIO_BLK_H
+#define _VIRTIO_BLK_H
+
+#include <stdint.h>
+
+
+/* Device configuration layout */
+/*
+struct virtio_blk_config {
+ uint64_t capacity;
+ uint32_t size_max;
+ uint32_t seg_max;
+ struct virtio_blk_geometry {
+ uint16_t cylinders;
+ uint8_t heads;
+ uint8_t sectors;
+ } geometry;
+ uint32_t blk_size;
+ uint32_t sectors_max;
+};
+*/
+
+/* Block request */
+struct virtio_blk_req {
+ uint32_t type ;
+ uint32_t ioprio ;
+ uint64_t sector ;
+};
+
+/* Block request types */
+#define VIRTIO_BLK_T_IN 0
+#define VIRTIO_BLK_T_OUT 1
+#define VIRTIO_BLK_T_SCSI_CMD 2
+#define VIRTIO_BLK_T_SCSI_CMD_OUT 3
+#define VIRTIO_BLK_T_FLUSH 4
+#define VIRTIO_BLK_T_FLUSH_OUT 5
+#define VIRTIO_BLK_T_BARRIER 0x80000000
+
+extern int virtioblk_init(struct virtio_device *dev);
+extern void virtioblk_shutdown(struct virtio_device *dev);
+extern int virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt);
+
+#endif /* _VIRTIO_BLK_H */
diff --git a/lib/libvirtio/virtio.c b/lib/libvirtio/virtio.c
new file mode 100644
index 0000000..4e70053
--- /dev/null
+++ b/lib/libvirtio/virtio.c
@@ -0,0 +1,191 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <cpu.h>
+#include <cache.h>
+#include <byteorder.h>
+#include "virtio.h"
+
+/* PCI virtio header offsets */
+#define VIRTIOHDR_DEVICE_FEATURES 0
+#define VIRTIOHDR_GUEST_FEATURES 4
+#define VIRTIOHDR_QUEUE_ADDRESS 8
+#define VIRTIOHDR_QUEUE_SIZE 12
+#define VIRTIOHDR_QUEUE_SELECT 14
+#define VIRTIOHDR_QUEUE_NOTIFY 16
+#define VIRTIOHDR_DEVICE_STATUS 18
+#define VIRTIOHDR_ISR_STATUS 19
+#define VIRTIOHDR_DEVICE_CONFIG 20
+
+
+/**
+ * Calculate ring size according to queue size number
+ */
+unsigned long virtio_vring_size(unsigned int qsize)
+{
+ return VQ_ALIGN(sizeof(struct vring_desc) * qsize + 2 * (2 + qsize))
+ + VQ_ALIGN(sizeof(struct vring_used_elem) * qsize);
+}
+
+
+/**
+ * Get number of elements in a vring
+ * @param dev pointer to virtio device information
+ * @param queue virtio queue number
+ * @return number of elements
+ */
+int virtio_get_qsize(struct virtio_device *dev, int queue)
+{
+ int size = 0;
+
+ if (dev->type == VIRTIO_TYPE_PCI) {
+ ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
+ cpu_to_le16(queue));
+ eieio();
+ size = le16_to_cpu(ci_read_16(dev->base+VIRTIOHDR_QUEUE_SIZE));
+ }
+
+ return size;
+}
+
+
+/**
+ * Get address of descriptor vring
+ * @param dev pointer to virtio device information
+ * @param queue virtio queue number
+ * @return pointer to the descriptor ring
+ */
+struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue)
+{
+ struct vring_desc *desc = 0;
+
+ if (dev->type == VIRTIO_TYPE_PCI) {
+ ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
+ cpu_to_le16(queue));
+ eieio();
+ desc = (void*)(4096L *
+ le32_to_cpu(ci_read_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS)));
+ }
+
+ return desc;
+}
+
+
+/**
+ * Get address of "available" vring
+ * @param dev pointer to virtio device information
+ * @param queue virtio queue number
+ * @return pointer to the "available" ring
+ */
+struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue)
+{
+ return (void*)((uint64_t)virtio_get_vring_desc(dev, queue)
+ + virtio_get_qsize(dev, queue) * sizeof(struct vring_desc));
+}
+
+
+/**
+ * Get address of "used" vring
+ * @param dev pointer to virtio device information
+ * @param queue virtio queue number
+ * @return pointer to the "used" ring
+ */
+struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue)
+{
+ return (void*)VQ_ALIGN((uint64_t)virtio_get_vring_avail(dev, queue)
+ + virtio_get_qsize(dev, queue)
+ * sizeof(struct vring_avail));
+}
+
+
+/**
+ * Reset virtio device
+ */
+void virtio_reset_device(struct virtio_device *dev)
+{
+ if (dev->type == VIRTIO_TYPE_PCI) {
+ ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, 0);
+ }
+}
+
+
+/**
+ * Notify hypervisor about queue update
+ */
+void virtio_queue_notify(struct virtio_device *dev, int queue)
+{
+ if (dev->type == VIRTIO_TYPE_PCI) {
+ ci_write_16(dev->base+VIRTIOHDR_QUEUE_NOTIFY, cpu_to_le16(queue));
+ }
+}
+
+
+/**
+ * Set device status bits
+ */
+void virtio_set_status(struct virtio_device *dev, int status)
+{
+ if (dev->type == VIRTIO_TYPE_PCI) {
+ ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, status);
+ }
+}
+
+
+/**
+ * Set guest feature bits
+ */
+void virtio_set_guest_features(struct virtio_device *dev, int features)
+
+{
+ if (dev->type == VIRTIO_TYPE_PCI) {
+ ci_write_32(dev->base+VIRTIOHDR_GUEST_FEATURES, features);
+ }
+}
+
+
+/**
+ * Get additional config values
+ */
+uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size)
+{
+ uint64_t val = ~0ULL;
+ void *confbase;
+
+ switch (dev->type) {
+ case VIRTIO_TYPE_PCI:
+ confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG;
+ break;
+ default:
+ return ~0ULL;
+ }
+ switch (size) {
+ case 1:
+ val = ci_read_8(confbase+offset);
+ break;
+ case 2:
+ val = ci_read_16(confbase+offset);
+ break;
+ case 4:
+ val = ci_read_32(confbase+offset);
+ break;
+ case 8:
+ /* We don't support 8 bytes PIO accesses
+ * in qemu and this is all PIO
+ */
+ val = ci_read_32(confbase+offset);
+ val <<= 32;
+ val |= ci_read_32(confbase+offset+4);
+ break;
+ }
+
+ return val;
+}
diff --git a/lib/libvirtio/virtio.code b/lib/libvirtio/virtio.code
new file mode 100644
index 0000000..0ed3dc7
--- /dev/null
+++ b/lib/libvirtio/virtio.code
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <virtio.h>
+#include <virtio-blk.h>
+
+// : virtio-vring-size ( queuesize -- ringsize )
+PRIM(virtio_X2d_vring_X2d_size)
+ TOS.u = virtio_vring_size(TOS.u);
+MIRP
+
+// : virtio-get-qsize ( dev queue -- queuesize )
+PRIM(virtio_X2d_get_X2d_qsize)
+ int queue = TOS.u; POP;
+ TOS.u = virtio_get_qsize(TOS.a, queue);
+MIRP
+
+// : virtio-get-config ( dev offset size -- val )
+PRIM(virtio_X2d_get_X2d_config)
+ int size = TOS.u; POP;
+ int offset = TOS.u; POP;
+ TOS.u = virtio_get_config(TOS.a, offset, size);
+MIRP
+
+// : virtio-blk-init ( dev -- )
+PRIM(virtio_X2d_blk_X2d_init)
+ void *dev = TOS.a; POP;
+ virtioblk_init(dev);
+MIRP
+
+// : virtio-blk-shutdown ( dev -- )
+PRIM(virtio_X2d_blk_X2d_shutdown)
+ void *dev = TOS.a; POP;
+ virtioblk_shutdown(dev);
+MIRP
+
+// : virtio-blk-read ( dev blkno cnt reg -- #read )
+PRIM(virtio_X2d_blk_X2d_read)
+ void *dev = TOS.a; POP;
+ long cnt = TOS.n; POP;
+ long blkno = TOS.n; POP;
+ void *buf = TOS.a;
+ TOS.n = virtioblk_read(dev, buf, blkno, cnt);
+MIRP
diff --git a/lib/libvirtio/virtio.h b/lib/libvirtio/virtio.h
new file mode 100644
index 0000000..7355043
--- /dev/null
+++ b/lib/libvirtio/virtio.h
@@ -0,0 +1,84 @@
+/******************************************************************************
+ * Copyright (c) 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#ifndef _LIBVIRTIO_H
+#define _LIBVIRTIO_H
+
+#include <stdint.h>
+
+/* Device status bits */
+#define VIRTIO_STAT_ACKNOWLEDGE 1
+#define VIRTIO_STAT_DRIVER 2
+#define VIRTIO_STAT_DRIVER_OK 4
+#define VIRTIO_STAT_FAILED 128
+
+/* Definitions for vring_desc.flags */
+#define VRING_DESC_F_NEXT 1 /* buffer continues via the next field */
+#define VRING_DESC_F_WRITE 2 /* buffer is write-only (otherwise read-only) */
+#define VRING_DESC_F_INDIRECT 4 /* buffer contains a list of buffer descriptors */
+
+/* Descriptor table entry - see Virtio Spec chapter 2.3.2 */
+struct vring_desc {
+ uint64_t addr; /* Address (guest-physical) */
+ uint32_t len; /* Length */
+ uint16_t flags; /* The flags as indicated above */
+ uint16_t next; /* Next field if flags & NEXT */
+};
+
+/* Definitions for vring_avail.flags */
+#define VRING_AVAIL_F_NO_INTERRUPT 1
+
+/* Available ring - see Virtio Spec chapter 2.3.4 */
+struct vring_avail {
+ uint16_t flags;
+ uint16_t idx;
+ uint16_t ring[];
+};
+
+
+/* Definitions for vring_used.flags */
+#define VRING_USED_F_NO_NOTIFY 1
+
+struct vring_used_elem {
+ uint32_t id; /* Index of start of used descriptor chain */
+ uint32_t len; /* Total length of the descriptor chain which was used */
+};
+
+struct vring_used {
+ uint16_t flags;
+ uint16_t idx;
+ struct vring_used_elem ring[];
+};
+
+#define VIRTIO_TYPE_PCI 0 /* For virtio-pci interface */
+struct virtio_device {
+ void *base; /* base address */
+ int type; /* VIRTIO_TYPE_PCI or VIRTIO_TYPE_VIO */
+};
+
+/* Parts of the virtqueue are aligned on a 4096 byte page boundary */
+#define VQ_ALIGN(addr) (((addr) + 0xfff) & ~0xfff)
+
+extern unsigned long virtio_vring_size(unsigned int qsize);
+extern int virtio_get_qsize(struct virtio_device *dev, int queue);
+extern struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue);
+extern struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue);
+extern struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue);
+
+extern void virtio_reset_device(struct virtio_device *dev);
+extern void virtio_queue_notify(struct virtio_device *dev, int queue);
+extern void virtio_set_status(struct virtio_device *dev, int status);
+extern void virtio_set_guest_features(struct virtio_device *dev, int features);
+extern uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size);
+
+
+#endif /* _LIBVIRTIO_H */
diff --git a/lib/libvirtio/virtio.in b/lib/libvirtio/virtio.in
new file mode 100644
index 0000000..1f2cfd1
--- /dev/null
+++ b/lib/libvirtio/virtio.in
@@ -0,0 +1,18 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2011 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+cod(virtio-vring-size)
+cod(virtio-get-qsize)
+cod(virtio-get-config)
+cod(virtio-blk-init)
+cod(virtio-blk-shutdown)
+cod(virtio-blk-read)