Index: qemu-0.9.1/Makefile.target =================================================================== --- qemu-0.9.1.orig/Makefile.target 2008-02-07 13:36:37.000000000 +0000 +++ qemu-0.9.1/Makefile.target 2008-02-07 13:38:53.000000000 +0000 @@ -437,7 +437,7 @@ VL_OBJS += rtl8139.o # virtio devices -VL_OBJS += virtio.o virtio-net.o +VL_OBJS += virtio.o virtio-net.o virtio-blk.o ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support Index: qemu-0.9.1/hw/pc.c =================================================================== --- qemu-0.9.1.orig/hw/pc.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1/hw/pc.c 2008-02-07 13:38:53.000000000 +0000 @@ -1008,6 +1008,18 @@ } } } + + /* Add virtio block devices */ + if (pci_enabled) { + int index; + int unit_id = 0; + + while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) { + virtio_blk_init(pci_bus, 0x5002, 0x2258, + drives_table[index].bdrv); + unit_id++; + } + } } static void pc_init_pci(int ram_size, int vga_ram_size, Index: qemu-0.9.1/hw/pc.h =================================================================== --- qemu-0.9.1.orig/hw/pc.h 2008-02-07 13:36:37.000000000 +0000 +++ qemu-0.9.1/hw/pc.h 2008-02-07 13:38:53.000000000 +0000 @@ -147,4 +147,8 @@ void *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn); +/* virtio-blk.h */ +void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device, + BlockDriverState *bs); + #endif Index: qemu-0.9.1/hw/virtio-blk.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ qemu-0.9.1/hw/virtio-blk.c 2008-02-07 13:38:53.000000000 +0000 @@ -0,0 +1,163 @@ +/* + * Virtio Block Device + * + * Copyright IBM, Corp. 2007 + * + * Authors: + * Anthony Liguori
+ * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "virtio.h" +#include "block.h" +#include "pc.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 */ + +struct virtio_blk_config +{ + uint64_t capacity; + uint32_t size_max; + uint32_t seg_max; +}; + +/* 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); + struct virtio_blk_config blkcfg; + int64_t capacity; + + bdrv_get_geometry(s->bs, &capacity); + blkcfg.capacity = capacity; + blkcfg.seg_max = 128 - 2; + memcpy(config, &blkcfg, sizeof(blkcfg)); +} + +static uint32_t virtio_blk_get_features(VirtIODevice *vdev) +{ + return (1 << VIRTIO_BLK_F_SEG_MAX); +} + +void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device, + BlockDriverState *bs) +{ + VirtIOBlock *s; + + s = (VirtIOBlock *)virtio_init_pci(bus, "virtio-blk", 6900, 0x1001, + 0, VIRTIO_ID_BLOCK, + 0x01, 0x80, 0x00, + 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, 128, virtio_blk_handle_output); + + return &s->vdev; +} Index: qemu-0.9.1/sysemu.h =================================================================== --- qemu-0.9.1.orig/sysemu.h 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1/sysemu.h 2008-02-07 13:38:53.000000000 +0000 @@ -117,7 +117,7 @@ #endif typedef enum { - IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD + IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO } BlockInterfaceType; typedef struct DriveInfo { Index: qemu-0.9.1/vl.c =================================================================== --- qemu-0.9.1.orig/vl.c 2008-01-06 19:38:42.000000000 +0000 +++ qemu-0.9.1/vl.c 2008-02-07 13:40:52.000000000 +0000 @@ -4953,6 +4953,9 @@ } else if (!strcmp(buf, "sd")) { type = IF_SD; max_devs = 0; + } else if (!strcmp(buf, "virtio")) { + type = IF_VIRTIO; + max_devs = 0; } else { fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf); return -1; @@ -5141,6 +5144,7 @@ break; case IF_PFLASH: case IF_MTD: + case IF_VIRTIO: break; } if (!file[0])