This patch implements a very naive virtio block device backend in QEMU. There's a lot of room for future optimization. We need to merge a -disk patch before we can provide a mechanism to expose this to users.
Signed-off-by: Anthony Liguori <[EMAIL PROTECTED]> diff --git a/qemu/Makefile.target b/qemu/Makefile.target index c7686b2..49c0fc7 100644 --- a/qemu/Makefile.target +++ b/qemu/Makefile.target @@ -449,7 +449,7 @@ VL_OBJS += rtl8139.o VL_OBJS+= hypercall.o # virtio devices -VL_OBJS += virtio.o +VL_OBJS += virtio.o virtio-blk.o ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support diff --git a/qemu/hw/pc.c b/qemu/hw/pc.c index 8aae814..c7483e8 100644 --- a/qemu/hw/pc.c +++ b/qemu/hw/pc.c @@ -943,6 +943,14 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, int boot_device, #ifdef USE_HYPERCALL pci_hypercall_init(pci_bus); #endif + + if (1) { + BlockDriverState *bs = bdrv_new("vda"); + if (bdrv_open(bs, "/home/anthony/images/linux.img", BDRV_O_SNAPSHOT)) + exit(1); + virtio_blk_init(pci_bus, 0x5002, 0x2258, bs); + } + if (pci_enabled) { pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1, i8259); } else { diff --git a/qemu/hw/virtio-blk.c b/qemu/hw/virtio-blk.c new file mode 100644 index 0000000..a1d5ea6 --- /dev/null +++ b/qemu/hw/virtio-blk.c @@ -0,0 +1,162 @@ +/* + * Virtio Block Device + * + * Copyright IBM, Corp. 2007 + * + * Authors: + * Anthony Liguori <[EMAIL PROTECTED]> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "vl.h" +#include "virtio.h" + +/* from Linux's linux/virtio_blk.h */ + +/* The ID for virtio_block */ +#define VIRTIO_ID_BLOCK 2 + +/* Feature bits */ +#define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */ +#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */ +#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */ + +/* The capacity (in 512-byte sectors). 8 bytes. */ +#define VIRTIO_CONFIG_BLK_F_CAPACITY 0 +/* The maximum segment size. 4 bytes. */ +#define VIRTIO_CONFIG_BLK_F_SIZE_MAX 0x08 +/* The maximum number of segments. 4 bytes. */ +#define VIRTIO_CONFIG_BLK_F_SEG_MAX 0x0A + +/* These two define direction. */ +#define VIRTIO_BLK_T_IN 0 +#define VIRTIO_BLK_T_OUT 1 + +/* This bit says it's a scsi command, not an actual read or write. */ +#define VIRTIO_BLK_T_SCSI_CMD 2 + +/* Barrier before this op. */ +#define VIRTIO_BLK_T_BARRIER 0x80000000 + +/* This is the first element of the read scatter-gather list. */ +struct virtio_blk_outhdr +{ + /* VIRTIO_BLK_T* */ + uint32_t type; + /* io priority. */ + uint32_t ioprio; + /* Sector (ie. 512 byte offset) */ + uint64_t sector; + /* Where to put reply. */ + uint64_t id; +}; + +#define VIRTIO_BLK_S_OK 0 +#define VIRTIO_BLK_S_IOERR 1 +#define VIRTIO_BLK_S_UNSUPP 2 + +/* This is the first element of the write scatter-gather list */ +struct virtio_blk_inhdr +{ + unsigned char status; +}; + +typedef struct VirtIOBlock +{ + VirtIODevice vdev; + BlockDriverState *bs; +} VirtIOBlock; + +static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev) +{ + return (VirtIOBlock *)vdev; +} + +static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOBlock *s = to_virtio_blk(vdev); + VirtQueueElement elem; + unsigned int count; + + while ((count = virtqueue_pop(vq, &elem)) != 0) { + struct virtio_blk_inhdr *in; + struct virtio_blk_outhdr *out; + unsigned int wlen; + off_t off; + int i; + + out = (void *)elem.out_sg[0].iov_base; + in = (void *)elem.in_sg[elem.in_num - 1].iov_base; + off = out->sector; + + if (out->type & VIRTIO_BLK_T_SCSI_CMD) { + wlen = sizeof(*in); + in->status = VIRTIO_BLK_S_UNSUPP; + } else if (out->type & VIRTIO_BLK_T_OUT) { + wlen = sizeof(*in); + + for (i = 1; i < elem.out_num; i++) { + bdrv_write(s->bs, off, + elem.out_sg[i].iov_base, + elem.out_sg[i].iov_len / 512); + off += elem.out_sg[i].iov_len / 512; + } + + in->status = VIRTIO_BLK_S_OK; + } else { + wlen = sizeof(*in); + + for (i = 0; i < elem.in_num - 1; i++) { + bdrv_read(s->bs, off, + elem.in_sg[i].iov_base, + elem.in_sg[i].iov_len / 512); + off += elem.in_sg[i].iov_len / 512; + wlen += elem.in_sg[i].iov_len; + } + + in->status = VIRTIO_BLK_S_OK; + } + + virtqueue_push(vq, &elem, wlen); + virtio_notify(vdev, vq); + } +} + +static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) +{ + VirtIOBlock *s = to_virtio_blk(vdev); + int64_t capacity; + uint32_t v; + + bdrv_get_geometry(s->bs, &capacity); + memcpy(config + VIRTIO_CONFIG_BLK_F_CAPACITY, &capacity, sizeof(capacity)); + + v = VIRTQUEUE_MAX_SIZE - 2; + memcpy(config + VIRTIO_CONFIG_BLK_F_SEG_MAX, &v, sizeof(v)); +} + +static uint32_t virtio_blk_get_features(VirtIODevice *vdev) +{ + return (1 << VIRTIO_BLK_F_SEG_MAX); +} + +VirtIODevice *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device, + BlockDriverState *bs) +{ + VirtIOBlock *s; + + s = (VirtIOBlock *)virtio_init_pci(bus, "virtio-blk", vendor, device, + vendor, VIRTIO_ID_BLOCK, + 16, sizeof(VirtIOBlock)); + + s->vdev.update_config = virtio_blk_update_config; + s->vdev.get_features = virtio_blk_get_features; + s->bs = bs; + + virtio_add_queue(&s->vdev, virtio_blk_handle_output); + + return &s->vdev; +} diff --git a/qemu/vl.h b/qemu/vl.h index fafcf09..249ede2 100644 --- a/qemu/vl.h +++ b/qemu/vl.h @@ -1396,6 +1396,9 @@ void vmchannel_init(CharDriverState *hd, uint32_t deviceid, uint32_t index); typedef struct VirtIODevice VirtIODevice; +VirtIODevice *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device, + BlockDriverState *bs); + /* buf = NULL means polling */ typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out, const uint8_t *buf, int len); ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel