wok-6.x rev 698

qemu: add virtio support
author Pascal Bellard <pascal.bellard@slitaz.org>
date Mon Apr 28 11:41:08 2008 +0000 (2008-04-28)
parents 41832070af28
children 036b1f427445
files qemu/receipt qemu/stuff/virtio.u
line diff
     1.1 --- a/qemu/receipt	Sun Apr 27 12:33:42 2008 +0200
     1.2 +++ b/qemu/receipt	Mon Apr 28 11:41:08 2008 +0000
     1.3 @@ -15,6 +15,7 @@
     1.4  compile_rules()
     1.5  {
     1.6  	cd $src
     1.7 +	patch -p1 < ../stuff/virtio.u
     1.8  	#./configure --prefix=/usr --enable-alsa --disable-gfx-check \
     1.9  
    1.10  	./configure --prefix=/usr --enable-alsa \
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/qemu/stuff/virtio.u	Mon Apr 28 11:41:08 2008 +0000
     2.3 @@ -0,0 +1,1076 @@
     2.4 +Index: qemu-0.9.1/Makefile.target
     2.5 +===================================================================
     2.6 +--- qemu-0.9.1.orig/Makefile.target	2008-01-06 19:38:41.000000000 +0000
     2.7 ++++ qemu-0.9.1/Makefile.target	2008-02-07 13:36:23.000000000 +0000
     2.8 +@@ -436,6 +436,9 @@
     2.9 + VL_OBJS += pcnet.o
    2.10 + VL_OBJS += rtl8139.o
    2.11 + 
    2.12 ++# virtio devices
    2.13 ++VL_OBJS += virtio.o
    2.14 ++
    2.15 + ifeq ($(TARGET_BASE_ARCH), i386)
    2.16 + # Hardware support
    2.17 + VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o
    2.18 +Index: qemu-0.9.1/hw/virtio.c
    2.19 +===================================================================
    2.20 +--- /dev/null	1970-01-01 00:00:00.000000000 +0000
    2.21 ++++ qemu-0.9.1/hw/virtio.c	2008-02-07 13:36:23.000000000 +0000
    2.22 +@@ -0,0 +1,422 @@
    2.23 ++/*
    2.24 ++ * Virtio Support
    2.25 ++ *
    2.26 ++ * Copyright IBM, Corp. 2007
    2.27 ++ *
    2.28 ++ * Authors:
    2.29 ++ *  Anthony Liguori   <address@hidden>
    2.30 ++ *
    2.31 ++ * This work is licensed under the terms of the GNU GPL, version 2.  See
    2.32 ++ * the COPYING file in the top-level directory.
    2.33 ++ *
    2.34 ++ */
    2.35 ++
    2.36 ++#include <inttypes.h>
    2.37 ++#include <err.h>
    2.38 ++
    2.39 ++#include "virtio.h"
    2.40 ++#include "sysemu.h"
    2.41 ++
    2.42 ++/* from Linux's linux/virtio_pci.h */
    2.43 ++
    2.44 ++/* A 32-bit r/o bitmask of the features supported by the host */
    2.45 ++#define VIRTIO_PCI_HOST_FEATURES       0
    2.46 ++
    2.47 ++/* A 32-bit r/w bitmask of features activated by the guest */
    2.48 ++#define VIRTIO_PCI_GUEST_FEATURES      4
    2.49 ++
    2.50 ++/* A 32-bit r/w PFN for the currently selected queue */
    2.51 ++#define VIRTIO_PCI_QUEUE_PFN           8
    2.52 ++
    2.53 ++/* A 16-bit r/o queue size for the currently selected queue */
    2.54 ++#define VIRTIO_PCI_QUEUE_NUM           12
    2.55 ++
    2.56 ++/* A 16-bit r/w queue selector */
    2.57 ++#define VIRTIO_PCI_QUEUE_SEL           14
    2.58 ++
    2.59 ++/* A 16-bit r/w queue notifier */
    2.60 ++#define VIRTIO_PCI_QUEUE_NOTIFY                16
    2.61 ++
    2.62 ++/* An 8-bit device status register.  */
    2.63 ++#define VIRTIO_PCI_STATUS              18
    2.64 ++
    2.65 ++/* An 8-bit r/o interrupt status register.  Reading the value will return the
    2.66 ++ * current contents of the ISR and will also clear it.  This is effectively
    2.67 ++ * a read-and-acknowledge. */
    2.68 ++#define VIRTIO_PCI_ISR                 19
    2.69 ++
    2.70 ++#define VIRTIO_PCI_CONFIG              20
    2.71 ++
    2.72 ++/* QEMU doesn't strictly need write barriers since everything runs in
    2.73 ++ * lock-step.  We'll leave the calls to wmb() in though to make it obvious for
    2.74 ++ * KVM or if kqemu gets SMP support.
    2.75 ++ */
    2.76 ++#define wmb() do { } while (0)
    2.77 ++
    2.78 ++/* virt queue functions */
    2.79 ++
    2.80 ++static void virtqueue_init(VirtQueue *vq, void *p)
    2.81 ++{
    2.82 ++    vq->vring.desc = p;
    2.83 ++    vq->vring.avail = p + vq->vring.num * sizeof(VRingDesc);
    2.84 ++    vq->vring.used = (void *)TARGET_PAGE_ALIGN((unsigned long)&vq->vring.avail->ring[vq->vring.num]);
    2.85 ++}
    2.86 ++
    2.87 ++static unsigned virtqueue_next_desc(VirtQueue *vq, unsigned int i)
    2.88 ++{
    2.89 ++    unsigned int next;
    2.90 ++
    2.91 ++    /* If this descriptor says it doesn't chain, we're done. */
    2.92 ++    if (!(vq->vring.desc[i].flags & VRING_DESC_F_NEXT))
    2.93 ++       return vq->vring.num;
    2.94 ++
    2.95 ++    /* Check they're not leading us off end of descriptors. */
    2.96 ++    next = vq->vring.desc[i].next;
    2.97 ++    /* Make sure compiler knows to grab that: we don't want it changing! */
    2.98 ++    wmb();
    2.99 ++
   2.100 ++    if (next >= vq->vring.num)
   2.101 ++       errx(1, "Desc next is %u", next);
   2.102 ++
   2.103 ++    return next;
   2.104 ++}
   2.105 ++
   2.106 ++void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
   2.107 ++                   unsigned int len)
   2.108 ++{
   2.109 ++    VRingUsedElem *used;
   2.110 ++
   2.111 ++    /* Get a pointer to the next entry in the used ring. */
   2.112 ++    used = &vq->vring.used->ring[vq->vring.used->idx % vq->vring.num];
   2.113 ++    used->id = elem->index;
   2.114 ++    used->len = len;
   2.115 ++    /* Make sure buffer is written before we update index. */
   2.116 ++    wmb();
   2.117 ++    vq->vring.used->idx++;
   2.118 ++}
   2.119 ++
   2.120 ++int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
   2.121 ++{
   2.122 ++    unsigned int i, head;
   2.123 ++    unsigned int position;
   2.124 ++
   2.125 ++    /* Check it isn't doing very strange things with descriptor numbers. */
   2.126 ++    if ((uint16_t)(vq->vring.avail->idx - vq->last_avail_idx) > vq->vring.num)
   2.127 ++       errx(1, "Guest moved used index from %u to %u",
   2.128 ++            vq->last_avail_idx, vq->vring.avail->idx);
   2.129 ++
   2.130 ++    /* If there's nothing new since last we looked, return invalid. */
   2.131 ++    if (vq->vring.avail->idx == vq->last_avail_idx)
   2.132 ++       return 0;
   2.133 ++
   2.134 ++    /* Grab the next descriptor number they're advertising, and increment
   2.135 ++     * the index we've seen. */
   2.136 ++    head = vq->vring.avail->ring[vq->last_avail_idx++ % vq->vring.num];
   2.137 ++
   2.138 ++    /* If their number is silly, that's a fatal mistake. */
   2.139 ++    if (head >= vq->vring.num)
   2.140 ++       errx(1, "Guest says index %u is available", head);
   2.141 ++
   2.142 ++    /* When we start there are none of either input nor output. */
   2.143 ++    position = elem->out_num = elem->in_num = 0;
   2.144 ++
   2.145 ++    i = head;
   2.146 ++    do {
   2.147 ++       struct iovec *sg;
   2.148 ++
   2.149 ++       if ((vq->vring.desc[i].addr + vq->vring.desc[i].len) > ram_size)
   2.150 ++           errx(1, "Guest sent invalid pointer");
   2.151 ++
   2.152 ++       if (vq->vring.desc[i].flags & VRING_DESC_F_WRITE)
   2.153 ++           sg = &elem->in_sg[elem->in_num++];
   2.154 ++       else
   2.155 ++           sg = &elem->out_sg[elem->out_num++];
   2.156 ++
   2.157 ++       /* Grab the first descriptor, and check it's OK. */
   2.158 ++       sg->iov_len = vq->vring.desc[i].len;
   2.159 ++       sg->iov_base = phys_ram_base + vq->vring.desc[i].addr;
   2.160 ++
   2.161 ++       /* If we've got too many, that implies a descriptor loop. */
   2.162 ++       if ((elem->in_num + elem->out_num) > vq->vring.num)
   2.163 ++           errx(1, "Looped descriptor");
   2.164 ++    } while ((i = virtqueue_next_desc(vq, i)) != vq->vring.num);
   2.165 ++
   2.166 ++    elem->index = head;
   2.167 ++
   2.168 ++    return elem->in_num + elem->out_num;
   2.169 ++}
   2.170 ++
   2.171 ++/* virtio device */
   2.172 ++
   2.173 ++static VirtIODevice *to_virtio_device(PCIDevice *pci_dev)
   2.174 ++{
   2.175 ++    return (VirtIODevice *)pci_dev;
   2.176 ++}
   2.177 ++
   2.178 ++static void virtio_update_irq(VirtIODevice *vdev)
   2.179 ++{
   2.180 ++    qemu_set_irq(vdev->pci_dev.irq[0], vdev->isr & 1);
   2.181 ++}
   2.182 ++
   2.183 ++static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
   2.184 ++{
   2.185 ++    VirtIODevice *vdev = to_virtio_device(opaque);
   2.186 ++    ram_addr_t pa;
   2.187 ++
   2.188 ++    addr -= vdev->addr;
   2.189 ++
   2.190 ++    switch (addr) {
   2.191 ++    case VIRTIO_PCI_GUEST_FEATURES:
   2.192 ++       if (vdev->set_features)
   2.193 ++           vdev->set_features(vdev, val);
   2.194 ++       vdev->features = val;
   2.195 ++       break;
   2.196 ++    case VIRTIO_PCI_QUEUE_PFN:
   2.197 ++       pa = (ram_addr_t)val << TARGET_PAGE_BITS;
   2.198 ++       vdev->vq[vdev->queue_sel].pfn = val;
   2.199 ++       if (pa == 0) {
   2.200 ++           vdev->vq[vdev->queue_sel].vring.desc = NULL;
   2.201 ++           vdev->vq[vdev->queue_sel].vring.avail = NULL;
   2.202 ++           vdev->vq[vdev->queue_sel].vring.used = NULL;
   2.203 ++       } else if (pa < (ram_size - TARGET_PAGE_SIZE)) {
   2.204 ++           virtqueue_init(&vdev->vq[vdev->queue_sel], phys_ram_base + pa);
   2.205 ++           /* FIXME if pa == 0, deal with device tear down */
   2.206 ++       }
   2.207 ++       break;
   2.208 ++    case VIRTIO_PCI_QUEUE_SEL:
   2.209 ++       if (val < VIRTIO_PCI_QUEUE_MAX)
   2.210 ++           vdev->queue_sel = val;
   2.211 ++       break;
   2.212 ++    case VIRTIO_PCI_QUEUE_NOTIFY:
   2.213 ++       if (val < VIRTIO_PCI_QUEUE_MAX && vdev->vq[val].vring.desc)
   2.214 ++           vdev->vq[val].handle_output(vdev, &vdev->vq[val]);
   2.215 ++       break;
   2.216 ++    case VIRTIO_PCI_STATUS:
   2.217 ++       vdev->status = val & 0xFF;
   2.218 ++       break;
   2.219 ++    }
   2.220 ++}
   2.221 ++
   2.222 ++static uint32_t virtio_ioport_read(void *opaque, uint32_t addr)
   2.223 ++{
   2.224 ++    VirtIODevice *vdev = to_virtio_device(opaque);
   2.225 ++    uint32_t ret = 0xFFFFFFFF;
   2.226 ++
   2.227 ++    addr -= vdev->addr;
   2.228 ++
   2.229 ++    switch (addr) {
   2.230 ++    case VIRTIO_PCI_HOST_FEATURES:
   2.231 ++       ret = vdev->get_features(vdev);
   2.232 ++       break;
   2.233 ++    case VIRTIO_PCI_GUEST_FEATURES:
   2.234 ++       ret = vdev->features;
   2.235 ++       break;
   2.236 ++    case VIRTIO_PCI_QUEUE_PFN:
   2.237 ++       ret = vdev->vq[vdev->queue_sel].pfn;
   2.238 ++       break;
   2.239 ++    case VIRTIO_PCI_QUEUE_NUM:
   2.240 ++       ret = vdev->vq[vdev->queue_sel].vring.num;
   2.241 ++       break;
   2.242 ++    case VIRTIO_PCI_QUEUE_SEL:
   2.243 ++       ret = vdev->queue_sel;
   2.244 ++       break;
   2.245 ++    case VIRTIO_PCI_STATUS:
   2.246 ++       ret = vdev->status;
   2.247 ++       break;
   2.248 ++    case VIRTIO_PCI_ISR:
   2.249 ++       /* reading from the ISR also clears it. */
   2.250 ++       ret = vdev->isr;
   2.251 ++       vdev->isr = 0;
   2.252 ++       virtio_update_irq(vdev);
   2.253 ++       break;
   2.254 ++    default:
   2.255 ++       break;
   2.256 ++    }
   2.257 ++
   2.258 ++    return ret;
   2.259 ++}
   2.260 ++
   2.261 ++static uint32_t virtio_config_readb(void *opaque, uint32_t addr)
   2.262 ++{
   2.263 ++    VirtIODevice *vdev = opaque;
   2.264 ++    uint8_t val;
   2.265 ++
   2.266 ++    addr -= vdev->addr + VIRTIO_PCI_CONFIG;
   2.267 ++    if (addr > (vdev->config_len - sizeof(val)))
   2.268 ++       return (uint32_t)-1;
   2.269 ++
   2.270 ++    memcpy(&val, vdev->config + addr, sizeof(val));
   2.271 ++    return val;
   2.272 ++}
   2.273 ++
   2.274 ++static uint32_t virtio_config_readw(void *opaque, uint32_t addr)
   2.275 ++{
   2.276 ++    VirtIODevice *vdev = opaque;
   2.277 ++    uint16_t val;
   2.278 ++
   2.279 ++    addr -= vdev->addr + VIRTIO_PCI_CONFIG;
   2.280 ++    if (addr > (vdev->config_len - sizeof(val)))
   2.281 ++       return (uint32_t)-1;
   2.282 ++
   2.283 ++    memcpy(&val, vdev->config + addr, sizeof(val));
   2.284 ++    return val;
   2.285 ++}
   2.286 ++
   2.287 ++static uint32_t virtio_config_readl(void *opaque, uint32_t addr)
   2.288 ++{
   2.289 ++    VirtIODevice *vdev = opaque;
   2.290 ++    uint32_t val;
   2.291 ++
   2.292 ++    addr -= vdev->addr + VIRTIO_PCI_CONFIG;
   2.293 ++    if (addr > (vdev->config_len - sizeof(val)))
   2.294 ++       return (uint32_t)-1;
   2.295 ++
   2.296 ++    memcpy(&val, vdev->config + addr, sizeof(val));
   2.297 ++    return val;
   2.298 ++}
   2.299 ++
   2.300 ++static void virtio_config_writeb(void *opaque, uint32_t addr, uint32_t data)
   2.301 ++{
   2.302 ++    VirtIODevice *vdev = opaque;
   2.303 ++    uint8_t val = data;
   2.304 ++
   2.305 ++    addr -= vdev->addr + VIRTIO_PCI_CONFIG;
   2.306 ++    if (addr > (vdev->config_len - sizeof(val)))
   2.307 ++       return;
   2.308 ++
   2.309 ++    memcpy(vdev->config + addr, &val, sizeof(val));
   2.310 ++}
   2.311 ++
   2.312 ++static void virtio_config_writew(void *opaque, uint32_t addr, uint32_t data)
   2.313 ++{
   2.314 ++    VirtIODevice *vdev = opaque;
   2.315 ++    uint16_t val = data;
   2.316 ++
   2.317 ++    addr -= vdev->addr + VIRTIO_PCI_CONFIG;
   2.318 ++    if (addr > (vdev->config_len - sizeof(val)))
   2.319 ++       return;
   2.320 ++
   2.321 ++    memcpy(vdev->config + addr, &val, sizeof(val));
   2.322 ++}
   2.323 ++
   2.324 ++static void virtio_config_writel(void *opaque, uint32_t addr, uint32_t data)
   2.325 ++{
   2.326 ++    VirtIODevice *vdev = opaque;
   2.327 ++    uint32_t val = data;
   2.328 ++
   2.329 ++    addr -= vdev->addr + VIRTIO_PCI_CONFIG;
   2.330 ++    if (addr > (vdev->config_len - sizeof(val)))
   2.331 ++       return;
   2.332 ++
   2.333 ++    memcpy(vdev->config + addr, &val, sizeof(val));
   2.334 ++}
   2.335 ++
   2.336 ++static void virtio_map(PCIDevice *pci_dev, int region_num,
   2.337 ++                      uint32_t addr, uint32_t size, int type)
   2.338 ++{
   2.339 ++    VirtIODevice *vdev = to_virtio_device(pci_dev);
   2.340 ++    int i;
   2.341 ++
   2.342 ++    vdev->addr = addr;
   2.343 ++    for (i = 0; i < 3; i++) {
   2.344 ++       register_ioport_write(addr, 20, 1 << i, virtio_ioport_write, vdev);
   2.345 ++       register_ioport_read(addr, 20, 1 << i, virtio_ioport_read, vdev);
   2.346 ++    }
   2.347 ++
   2.348 ++    if (vdev->config_len) {
   2.349 ++       register_ioport_write(addr + 20, vdev->config_len, 1,
   2.350 ++                             virtio_config_writeb, vdev);
   2.351 ++       register_ioport_write(addr + 20, vdev->config_len, 2,
   2.352 ++                             virtio_config_writew, vdev);
   2.353 ++       register_ioport_write(addr + 20, vdev->config_len, 4,
   2.354 ++                             virtio_config_writel, vdev);
   2.355 ++       register_ioport_read(addr + 20, vdev->config_len, 1,
   2.356 ++                            virtio_config_readb, vdev);
   2.357 ++       register_ioport_read(addr + 20, vdev->config_len, 2,
   2.358 ++                            virtio_config_readw, vdev);
   2.359 ++       register_ioport_read(addr + 20, vdev->config_len, 4,
   2.360 ++                            virtio_config_readl, vdev);
   2.361 ++
   2.362 ++       vdev->update_config(vdev, vdev->config);
   2.363 ++    }
   2.364 ++}
   2.365 ++
   2.366 ++VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
   2.367 ++                           void (*handle_output)(VirtIODevice *, VirtQueue *))
   2.368 ++{
   2.369 ++    int i;
   2.370 ++
   2.371 ++    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
   2.372 ++       if (vdev->vq[i].vring.num == 0)
   2.373 ++           break;
   2.374 ++    }
   2.375 ++
   2.376 ++    if (i == VIRTIO_PCI_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
   2.377 ++       abort();
   2.378 ++
   2.379 ++    vdev->vq[i].vring.num = queue_size;
   2.380 ++    vdev->vq[i].handle_output = handle_output;
   2.381 ++    vdev->vq[i].index = i;
   2.382 ++
   2.383 ++    return &vdev->vq[i];
   2.384 ++}
   2.385 ++
   2.386 ++void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
   2.387 ++{
   2.388 ++    if (vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
   2.389 ++       return;
   2.390 ++
   2.391 ++    vdev->isr = 1;
   2.392 ++    virtio_update_irq(vdev);
   2.393 ++}
   2.394 ++
   2.395 ++VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name,
   2.396 ++                             uint16_t vendor, uint16_t device,
   2.397 ++                             uint16_t subvendor, uint16_t subdevice,
   2.398 ++                             uint8_t class_code, uint8_t subclass_code,
   2.399 ++                             uint8_t pif, size_t config_size,
   2.400 ++                             size_t struct_size)
   2.401 ++{
   2.402 ++    VirtIODevice *vdev;
   2.403 ++    PCIDevice *pci_dev;
   2.404 ++    uint8_t *config;
   2.405 ++
   2.406 ++    pci_dev = pci_register_device(bus, name, struct_size,
   2.407 ++                                 -1, NULL, NULL);
   2.408 ++    vdev = to_virtio_device(pci_dev);
   2.409 ++
   2.410 ++    vdev->status = 0;
   2.411 ++    vdev->isr = 0;
   2.412 ++    vdev->queue_sel = 0;
   2.413 ++    memset(vdev->vq, 0, sizeof(vdev->vq));
   2.414 ++
   2.415 ++    config = pci_dev->config;
   2.416 ++    config[0x00] = vendor & 0xFF;
   2.417 ++    config[0x01] = (vendor >> 8) & 0xFF;
   2.418 ++    config[0x02] = device & 0xFF;
   2.419 ++    config[0x03] = (device >> 8) & 0xFF;
   2.420 ++
   2.421 ++    config[0x09] = pif;
   2.422 ++    config[0x0a] = subclass_code;
   2.423 ++    config[0x0b] = class_code;
   2.424 ++    config[0x0e] = 0x00;
   2.425 ++
   2.426 ++    config[0x2c] = subvendor & 0xFF;
   2.427 ++    config[0x2d] = (subvendor >> 8) & 0xFF;
   2.428 ++    config[0x2e] = subdevice & 0xFF;
   2.429 ++    config[0x2f] = (subdevice >> 8) & 0xFF;
   2.430 ++
   2.431 ++    config[0x3d] = 1;
   2.432 ++
   2.433 ++    vdev->name = name;
   2.434 ++    vdev->config_len = config_size;
   2.435 ++    if (vdev->config_len)
   2.436 ++       vdev->config = qemu_mallocz(config_size);
   2.437 ++    else
   2.438 ++       vdev->config = NULL;
   2.439 ++
   2.440 ++    pci_register_io_region(pci_dev, 0, 20 + config_size, PCI_ADDRESS_SPACE_IO,
   2.441 ++                          virtio_map);
   2.442 ++
   2.443 ++    return vdev;
   2.444 ++}
   2.445 +Index: qemu-0.9.1/hw/virtio.h
   2.446 +===================================================================
   2.447 +--- /dev/null	1970-01-01 00:00:00.000000000 +0000
   2.448 ++++ qemu-0.9.1/hw/virtio.h	2008-02-07 13:36:23.000000000 +0000
   2.449 +@@ -0,0 +1,143 @@
   2.450 ++/*
   2.451 ++ * Virtio Support
   2.452 ++ *
   2.453 ++ * Copyright IBM, Corp. 2007
   2.454 ++ *
   2.455 ++ * Authors:
   2.456 ++ *  Anthony Liguori   <address@hidden>
   2.457 ++ *
   2.458 ++ * This work is licensed under the terms of the GNU GPL, version 2.  See
   2.459 ++ * the COPYING file in the top-level directory.
   2.460 ++ *
   2.461 ++ */
   2.462 ++
   2.463 ++#ifndef _QEMU_VIRTIO_H
   2.464 ++#define _QEMU_VIRTIO_H
   2.465 ++
   2.466 ++#include <sys/uio.h>
   2.467 ++#include "hw.h"
   2.468 ++#include "pci.h"
   2.469 ++
   2.470 ++/* from Linux's linux/virtio_config.h */
   2.471 ++
   2.472 ++/* Status byte for guest to report progress, and synchronize features. */
   2.473 ++/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
   2.474 ++#define VIRTIO_CONFIG_S_ACKNOWLEDGE    1
   2.475 ++/* We have found a driver for the device. */
   2.476 ++#define VIRTIO_CONFIG_S_DRIVER         2
   2.477 ++/* Driver has used its parts of the config, and is happy */
   2.478 ++#define VIRTIO_CONFIG_S_DRIVER_OK      4
   2.479 ++/* We've given up on this device. */
   2.480 ++#define VIRTIO_CONFIG_S_FAILED         0x80
   2.481 ++
   2.482 ++/* from Linux's linux/virtio_ring.h */
   2.483 ++
   2.484 ++/* This marks a buffer as continuing via the next field. */
   2.485 ++#define VRING_DESC_F_NEXT      1
   2.486 ++/* This marks a buffer as write-only (otherwise read-only). */
   2.487 ++#define VRING_DESC_F_WRITE     2
   2.488 ++
   2.489 ++/* This means don't notify other side when buffer added. */
   2.490 ++#define VRING_USED_F_NO_NOTIFY 1
   2.491 ++/* This means don't interrupt guest when buffer consumed. */
   2.492 ++#define VRING_AVAIL_F_NO_INTERRUPT     1
   2.493 ++
   2.494 ++typedef struct VirtQueue VirtQueue;
   2.495 ++typedef struct VirtIODevice VirtIODevice;
   2.496 ++
   2.497 ++typedef struct VRingDesc
   2.498 ++{
   2.499 ++    uint64_t addr;
   2.500 ++    uint32_t len;
   2.501 ++    uint16_t flags;
   2.502 ++    uint16_t next;
   2.503 ++} VRingDesc;
   2.504 ++
   2.505 ++typedef struct VRingAvail
   2.506 ++{
   2.507 ++    uint16_t flags;
   2.508 ++    uint16_t idx;
   2.509 ++    uint16_t ring[0];
   2.510 ++} VRingAvail;
   2.511 ++
   2.512 ++typedef struct VRingUsedElem
   2.513 ++{
   2.514 ++    uint32_t id;
   2.515 ++    uint32_t len;
   2.516 ++} VRingUsedElem;
   2.517 ++
   2.518 ++typedef struct VRingUsed
   2.519 ++{
   2.520 ++    uint16_t flags;
   2.521 ++    uint16_t idx;
   2.522 ++    VRingUsedElem ring[0];
   2.523 ++} VRingUsed;
   2.524 ++
   2.525 ++typedef struct VRing
   2.526 ++{
   2.527 ++    unsigned int num;
   2.528 ++    VRingDesc *desc;
   2.529 ++    VRingAvail *avail;
   2.530 ++    VRingUsed *used;
   2.531 ++} VRing;
   2.532 ++
   2.533 ++struct VirtQueue
   2.534 ++{
   2.535 ++    VRing vring;
   2.536 ++    uint32_t pfn;
   2.537 ++    uint16_t last_avail_idx;
   2.538 ++    void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
   2.539 ++    int index;
   2.540 ++};
   2.541 ++
   2.542 ++#define VIRTQUEUE_MAX_SIZE 1024
   2.543 ++
   2.544 ++typedef struct VirtQueueElement
   2.545 ++{
   2.546 ++    unsigned int index;
   2.547 ++    unsigned int out_num;
   2.548 ++    unsigned int in_num;
   2.549 ++    struct iovec in_sg[VIRTQUEUE_MAX_SIZE];
   2.550 ++    struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
   2.551 ++} VirtQueueElement;
   2.552 ++
   2.553 ++#define VIRTIO_PCI_QUEUE_MAX   16
   2.554 ++
   2.555 ++struct VirtIODevice
   2.556 ++{
   2.557 ++    PCIDevice pci_dev;
   2.558 ++    const char *name;
   2.559 ++    uint32_t addr;
   2.560 ++    uint16_t vendor;
   2.561 ++    uint16_t device;
   2.562 ++    uint8_t status;
   2.563 ++    uint8_t isr;
   2.564 ++    uint16_t queue_sel;
   2.565 ++    uint32_t features;
   2.566 ++    size_t config_len;
   2.567 ++    void *config;
   2.568 ++    uint32_t (*get_features)(VirtIODevice *vdev);
   2.569 ++    void (*set_features)(VirtIODevice *vdev, uint32_t val);
   2.570 ++    void (*update_config)(VirtIODevice *vdev, uint8_t *config);
   2.571 ++    VirtQueue vq[VIRTIO_PCI_QUEUE_MAX];
   2.572 ++};
   2.573 ++
   2.574 ++VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name,
   2.575 ++                             uint16_t vendor, uint16_t device,
   2.576 ++                             uint16_t subvendor, uint16_t subdevice,
   2.577 ++                             uint8_t class_code, uint8_t subclass_code,
   2.578 ++                             uint8_t pif, size_t config_size,
   2.579 ++                             size_t struct_size);
   2.580 ++
   2.581 ++VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
   2.582 ++                           void (*handle_output)(VirtIODevice *,
   2.583 ++                                                 VirtQueue *));
   2.584 ++
   2.585 ++void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
   2.586 ++                   unsigned int len);
   2.587 ++
   2.588 ++int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem);
   2.589 ++
   2.590 ++void virtio_notify(VirtIODevice *vdev, VirtQueue *vq);
   2.591 ++
   2.592 ++#endif
   2.593 +Index: qemu-0.9.1/Makefile.target
   2.594 +===================================================================
   2.595 +--- qemu-0.9.1.orig/Makefile.target	2008-02-07 13:36:23.000000000 +0000
   2.596 ++++ qemu-0.9.1/Makefile.target	2008-02-07 13:36:37.000000000 +0000
   2.597 +@@ -437,7 +437,7 @@
   2.598 + VL_OBJS += rtl8139.o
   2.599 + 
   2.600 + # virtio devices
   2.601 +-VL_OBJS += virtio.o
   2.602 ++VL_OBJS += virtio.o virtio-net.o
   2.603 + 
   2.604 + ifeq ($(TARGET_BASE_ARCH), i386)
   2.605 + # Hardware support
   2.606 +Index: qemu-0.9.1/hw/pc.h
   2.607 +===================================================================
   2.608 +--- qemu-0.9.1.orig/hw/pc.h	2008-01-06 19:38:42.000000000 +0000
   2.609 ++++ qemu-0.9.1/hw/pc.h	2008-02-07 13:36:37.000000000 +0000
   2.610 +@@ -142,4 +142,9 @@
   2.611 + 
   2.612 + void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd);
   2.613 + 
   2.614 ++/* virtio-net.c */
   2.615 ++
   2.616 ++void *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn);
   2.617 ++
   2.618 ++
   2.619 + #endif
   2.620 +Index: qemu-0.9.1/hw/pci.c
   2.621 +===================================================================
   2.622 +--- qemu-0.9.1.orig/hw/pci.c	2008-01-06 19:38:42.000000000 +0000
   2.623 ++++ qemu-0.9.1/hw/pci.c	2008-02-07 13:36:37.000000000 +0000
   2.624 +@@ -25,6 +25,7 @@
   2.625 + #include "pci.h"
   2.626 + #include "console.h"
   2.627 + #include "net.h"
   2.628 ++#include "pc.h"
   2.629 + 
   2.630 + //#define DEBUG_PCI
   2.631 + 
   2.632 +@@ -638,9 +639,11 @@
   2.633 +         pci_rtl8139_init(bus, nd, devfn);
   2.634 +     } else if (strcmp(nd->model, "pcnet") == 0) {
   2.635 +         pci_pcnet_init(bus, nd, devfn);
   2.636 ++    } else if (strcmp(nd->model, "virtio") == 0) {
   2.637 ++       virtio_net_init(bus, nd, devfn);
   2.638 +     } else if (strcmp(nd->model, "?") == 0) {
   2.639 +         fprintf(stderr, "qemu: Supported PCI NICs: i82551 i82557b i82559er"
   2.640 +-                        " ne2k_pci pcnet rtl8139\n");
   2.641 ++                        " ne2k_pci pcnet rtl8139 virtio\n");
   2.642 +         exit (1);
   2.643 +     } else {
   2.644 +         fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
   2.645 +Index: qemu-0.9.1/hw/virtio-net.c
   2.646 +===================================================================
   2.647 +--- /dev/null	1970-01-01 00:00:00.000000000 +0000
   2.648 ++++ qemu-0.9.1/hw/virtio-net.c	2008-02-07 13:36:37.000000000 +0000
   2.649 +@@ -0,0 +1,178 @@
   2.650 ++/*
   2.651 ++ * Virtio Network Device
   2.652 ++ *
   2.653 ++ * Copyright IBM, Corp. 2007
   2.654 ++ *
   2.655 ++ * Authors:
   2.656 ++ *  Anthony Liguori   <address@hidden>
   2.657 ++ *
   2.658 ++ * This work is licensed under the terms of the GNU GPL, version 2.  See
   2.659 ++ * the COPYING file in the top-level directory.
   2.660 ++ *
   2.661 ++ */
   2.662 ++
   2.663 ++#include "virtio.h"
   2.664 ++#include "net.h"
   2.665 ++#include "pc.h"
   2.666 ++
   2.667 ++/* from Linux's virtio_net.h */
   2.668 ++
   2.669 ++/* The ID for virtio_net */
   2.670 ++#define VIRTIO_ID_NET  1
   2.671 ++
   2.672 ++/* The feature bitmap for virtio net */
   2.673 ++#define VIRTIO_NET_F_NO_CSUM   0
   2.674 ++#define VIRTIO_NET_F_TSO4      1
   2.675 ++#define VIRTIO_NET_F_UFO       2
   2.676 ++#define VIRTIO_NET_F_TSO4_ECN  3
   2.677 ++#define VIRTIO_NET_F_TSO6      4
   2.678 ++#define VIRTIO_NET_F_MAC       5
   2.679 ++
   2.680 ++/* The config defining mac address (6 bytes) */
   2.681 ++struct virtio_net_config
   2.682 ++{
   2.683 ++    uint8_t mac[6];
   2.684 ++} __attribute__((packed));
   2.685 ++
   2.686 ++/* This is the first element of the scatter-gather list.  If you don't
   2.687 ++ * specify GSO or CSUM features, you can simply ignore the header. */
   2.688 ++struct virtio_net_hdr
   2.689 ++{
   2.690 ++#define VIRTIO_NET_HDR_F_NEEDS_CSUM    1       // Use csum_start, csum_offset
   2.691 ++    uint8_t flags;
   2.692 ++#define VIRTIO_NET_HDR_GSO_NONE                0       // Not a GSO frame
   2.693 ++#define VIRTIO_NET_HDR_GSO_TCPV4       1       // GSO frame, IPv4 TCP (TSO)
   2.694 ++/* FIXME: Do we need this?  If they said they can handle ECN, do they care? */
   2.695 ++#define VIRTIO_NET_HDR_GSO_TCPV4_ECN   2       // GSO frame, IPv4 TCP w/ ECN
   2.696 ++#define VIRTIO_NET_HDR_GSO_UDP         3       // GSO frame, IPv4 UDP (UFO)
   2.697 ++#define VIRTIO_NET_HDR_GSO_TCPV6       4       // GSO frame, IPv6 TCP
   2.698 ++    uint8_t gso_type;
   2.699 ++    uint16_t gso_size;
   2.700 ++    uint16_t csum_start;
   2.701 ++    uint16_t csum_offset;
   2.702 ++};
   2.703 ++
   2.704 ++typedef struct VirtIONet
   2.705 ++{
   2.706 ++    VirtIODevice vdev;
   2.707 ++    uint8_t mac[6];
   2.708 ++    VirtQueue *rx_vq;
   2.709 ++    VirtQueue *tx_vq;
   2.710 ++    VLANClientState *vc;
   2.711 ++    int can_receive;
   2.712 ++} VirtIONet;
   2.713 ++
   2.714 ++static VirtIONet *to_virtio_net(VirtIODevice *vdev)
   2.715 ++{
   2.716 ++    return (VirtIONet *)vdev;
   2.717 ++}
   2.718 ++
   2.719 ++static void virtio_net_update_config(VirtIODevice *vdev, uint8_t *config)
   2.720 ++{
   2.721 ++    VirtIONet *n = to_virtio_net(vdev);
   2.722 ++    struct virtio_net_config netcfg;
   2.723 ++
   2.724 ++    memcpy(netcfg.mac, n->mac, 6);
   2.725 ++    memcpy(config, &netcfg, sizeof(netcfg));
   2.726 ++}
   2.727 ++
   2.728 ++static uint32_t virtio_net_get_features(VirtIODevice *vdev)
   2.729 ++{
   2.730 ++    return (1 << VIRTIO_NET_F_MAC);
   2.731 ++}
   2.732 ++
   2.733 ++/* RX */
   2.734 ++
   2.735 ++static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
   2.736 ++{
   2.737 ++    VirtIONet *n = to_virtio_net(vdev);
   2.738 ++    n->can_receive = 1;
   2.739 ++}
   2.740 ++
   2.741 ++static int virtio_net_can_receive(void *opaque)
   2.742 ++{
   2.743 ++    VirtIONet *n = opaque;
   2.744 ++
   2.745 ++    return (n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) && n->can_receive;
   2.746 ++}
   2.747 ++
   2.748 ++static void virtio_net_receive(void *opaque, const uint8_t *buf, int size)
   2.749 ++{
   2.750 ++    VirtIONet *n = opaque;
   2.751 ++    VirtQueueElement elem;
   2.752 ++    struct virtio_net_hdr *hdr;
   2.753 ++    int offset, i;
   2.754 ++
   2.755 ++    /* FIXME: the drivers really need to set their status better */
   2.756 ++    if (n->rx_vq->vring.avail == NULL) {
   2.757 ++       n->can_receive = 0;
   2.758 ++       return;
   2.759 ++    }
   2.760 ++
   2.761 ++    if (virtqueue_pop(n->rx_vq, &elem) == 0) {
   2.762 ++       /* wait until the guest adds some rx bufs */
   2.763 ++       n->can_receive = 0;
   2.764 ++       return;
   2.765 ++    }
   2.766 ++
   2.767 ++    hdr = (void *)elem.in_sg[0].iov_base;
   2.768 ++    hdr->flags = 0;
   2.769 ++    hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
   2.770 ++
   2.771 ++    /* copy in packet.  ugh */
   2.772 ++    offset = 0;
   2.773 ++    i = 1;
   2.774 ++    while (offset < size && i < elem.in_num) {
   2.775 ++       int len = MIN(elem.in_sg[i].iov_len, size - offset);
   2.776 ++       memcpy(elem.in_sg[i].iov_base, buf + offset, len);
   2.777 ++       offset += len;
   2.778 ++       i++;
   2.779 ++    }
   2.780 ++
   2.781 ++    /* signal other side */
   2.782 ++    virtqueue_push(n->rx_vq, &elem, sizeof(*hdr) + offset);
   2.783 ++    virtio_notify(&n->vdev, n->rx_vq);
   2.784 ++}
   2.785 ++
   2.786 ++/* TX */
   2.787 ++static void virtio_net_handle_tx(VirtIODevice *vdev, VirtQueue *vq)
   2.788 ++{
   2.789 ++    VirtIONet *n = to_virtio_net(vdev);
   2.790 ++    VirtQueueElement elem;
   2.791 ++
   2.792 ++    while (virtqueue_pop(vq, &elem)) {
   2.793 ++       int i;
   2.794 ++       size_t len = 0;
   2.795 ++
   2.796 ++       /* ignore the header for now */
   2.797 ++       for (i = 1; i < elem.out_num; i++) {
   2.798 ++           qemu_send_packet(n->vc, elem.out_sg[i].iov_base,
   2.799 ++                            elem.out_sg[i].iov_len);
   2.800 ++           len += elem.out_sg[i].iov_len;
   2.801 ++       }
   2.802 ++
   2.803 ++       virtqueue_push(vq, &elem, sizeof(struct virtio_net_hdr) + len);
   2.804 ++       virtio_notify(&n->vdev, vq);
   2.805 ++    }
   2.806 ++}
   2.807 ++
   2.808 ++void *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn)
   2.809 ++{
   2.810 ++    VirtIONet *n;
   2.811 ++
   2.812 ++    n = (VirtIONet *)virtio_init_pci(bus, "virtio-net", 6900, 0x1000,
   2.813 ++                                    0, VIRTIO_ID_NET,
   2.814 ++                                    0x02, 0x00, 0x00,
   2.815 ++                                    6, sizeof(VirtIONet));
   2.816 ++
   2.817 ++    n->vdev.update_config = virtio_net_update_config;
   2.818 ++    n->vdev.get_features = virtio_net_get_features;
   2.819 ++    n->rx_vq = virtio_add_queue(&n->vdev, 512, virtio_net_handle_rx);
   2.820 ++    n->tx_vq = virtio_add_queue(&n->vdev, 128, virtio_net_handle_tx);
   2.821 ++    n->can_receive = 0;
   2.822 ++    memcpy(n->mac, nd->macaddr, 6);
   2.823 ++    n->vc = qemu_new_vlan_client(nd->vlan, virtio_net_receive,
   2.824 ++                                virtio_net_can_receive, n);
   2.825 ++
   2.826 ++    return &n->vdev;
   2.827 ++}
   2.828 +Index: qemu-0.9.1/Makefile.target
   2.829 +===================================================================
   2.830 +--- qemu-0.9.1.orig/Makefile.target	2008-02-07 13:36:37.000000000 +0000
   2.831 ++++ qemu-0.9.1/Makefile.target	2008-02-07 13:38:53.000000000 +0000
   2.832 +@@ -437,7 +437,7 @@
   2.833 + VL_OBJS += rtl8139.o
   2.834 + 
   2.835 + # virtio devices
   2.836 +-VL_OBJS += virtio.o virtio-net.o
   2.837 ++VL_OBJS += virtio.o virtio-net.o virtio-blk.o
   2.838 + 
   2.839 + ifeq ($(TARGET_BASE_ARCH), i386)
   2.840 + # Hardware support
   2.841 +Index: qemu-0.9.1/hw/pc.c
   2.842 +===================================================================
   2.843 +--- qemu-0.9.1.orig/hw/pc.c	2008-01-06 19:38:42.000000000 +0000
   2.844 ++++ qemu-0.9.1/hw/pc.c	2008-02-07 13:38:53.000000000 +0000
   2.845 +@@ -1008,6 +1008,18 @@
   2.846 + 	    }
   2.847 +         }
   2.848 +     }
   2.849 ++
   2.850 ++    /* Add virtio block devices */
   2.851 ++    if (pci_enabled) {
   2.852 ++       int index;
   2.853 ++       int unit_id = 0;
   2.854 ++
   2.855 ++       while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) {
   2.856 ++           virtio_blk_init(pci_bus, 0x5002, 0x2258,
   2.857 ++                           drives_table[index].bdrv);
   2.858 ++           unit_id++;
   2.859 ++       }
   2.860 ++    }
   2.861 + }
   2.862 + 
   2.863 + static void pc_init_pci(int ram_size, int vga_ram_size,
   2.864 +Index: qemu-0.9.1/hw/pc.h
   2.865 +===================================================================
   2.866 +--- qemu-0.9.1.orig/hw/pc.h	2008-02-07 13:36:37.000000000 +0000
   2.867 ++++ qemu-0.9.1/hw/pc.h	2008-02-07 13:38:53.000000000 +0000
   2.868 +@@ -147,4 +147,8 @@
   2.869 + void *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn);
   2.870 + 
   2.871 + 
   2.872 ++/* virtio-blk.h */
   2.873 ++void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device,
   2.874 ++                     BlockDriverState *bs);
   2.875 ++
   2.876 + #endif
   2.877 +Index: qemu-0.9.1/hw/virtio-blk.c
   2.878 +===================================================================
   2.879 +--- /dev/null	1970-01-01 00:00:00.000000000 +0000
   2.880 ++++ qemu-0.9.1/hw/virtio-blk.c	2008-02-07 13:38:53.000000000 +0000
   2.881 +@@ -0,0 +1,163 @@
   2.882 ++/*
   2.883 ++ * Virtio Block Device
   2.884 ++ *
   2.885 ++ * Copyright IBM, Corp. 2007
   2.886 ++ *
   2.887 ++ * Authors:
   2.888 ++ *  Anthony Liguori   <address@hidden>
   2.889 ++ *
   2.890 ++ * This work is licensed under the terms of the GNU GPL, version 2.  See
   2.891 ++ * the COPYING file in the top-level directory.
   2.892 ++ *
   2.893 ++ */
   2.894 ++
   2.895 ++#include "virtio.h"
   2.896 ++#include "block.h"
   2.897 ++#include "pc.h"
   2.898 ++
   2.899 ++/* from Linux's linux/virtio_blk.h */
   2.900 ++
   2.901 ++/* The ID for virtio_block */
   2.902 ++#define VIRTIO_ID_BLOCK        2
   2.903 ++
   2.904 ++/* Feature bits */
   2.905 ++#define VIRTIO_BLK_F_BARRIER   0       /* Does host support barriers? */
   2.906 ++#define VIRTIO_BLK_F_SIZE_MAX  1       /* Indicates maximum segment size */
   2.907 ++#define VIRTIO_BLK_F_SEG_MAX   2       /* Indicates maximum # of segments */
   2.908 ++
   2.909 ++struct virtio_blk_config
   2.910 ++{
   2.911 ++    uint64_t capacity;
   2.912 ++    uint32_t size_max;
   2.913 ++    uint32_t seg_max;
   2.914 ++};
   2.915 ++
   2.916 ++/* These two define direction. */
   2.917 ++#define VIRTIO_BLK_T_IN                0
   2.918 ++#define VIRTIO_BLK_T_OUT       1
   2.919 ++
   2.920 ++/* This bit says it's a scsi command, not an actual read or write. */
   2.921 ++#define VIRTIO_BLK_T_SCSI_CMD  2
   2.922 ++
   2.923 ++/* Barrier before this op. */
   2.924 ++#define VIRTIO_BLK_T_BARRIER   0x80000000
   2.925 ++
   2.926 ++/* This is the first element of the read scatter-gather list. */
   2.927 ++struct virtio_blk_outhdr
   2.928 ++{
   2.929 ++    /* VIRTIO_BLK_T* */
   2.930 ++    uint32_t type;
   2.931 ++    /* io priority. */
   2.932 ++    uint32_t ioprio;
   2.933 ++    /* Sector (ie. 512 byte offset) */
   2.934 ++    uint64_t sector;
   2.935 ++    /* Where to put reply. */
   2.936 ++    uint64_t id;
   2.937 ++};
   2.938 ++
   2.939 ++#define VIRTIO_BLK_S_OK                0
   2.940 ++#define VIRTIO_BLK_S_IOERR     1
   2.941 ++#define VIRTIO_BLK_S_UNSUPP    2
   2.942 ++
   2.943 ++/* This is the first element of the write scatter-gather list */
   2.944 ++struct virtio_blk_inhdr
   2.945 ++{
   2.946 ++    unsigned char status;
   2.947 ++};
   2.948 ++
   2.949 ++typedef struct VirtIOBlock
   2.950 ++{
   2.951 ++    VirtIODevice vdev;
   2.952 ++    BlockDriverState *bs;
   2.953 ++} VirtIOBlock;
   2.954 ++
   2.955 ++static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
   2.956 ++{
   2.957 ++    return (VirtIOBlock *)vdev;
   2.958 ++}
   2.959 ++
   2.960 ++static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
   2.961 ++{
   2.962 ++    VirtIOBlock *s = to_virtio_blk(vdev);
   2.963 ++    VirtQueueElement elem;
   2.964 ++    unsigned int count;
   2.965 ++
   2.966 ++    while ((count = virtqueue_pop(vq, &elem)) != 0) {
   2.967 ++       struct virtio_blk_inhdr *in;
   2.968 ++       struct virtio_blk_outhdr *out;
   2.969 ++       unsigned int wlen;
   2.970 ++       off_t off;
   2.971 ++       int i;
   2.972 ++
   2.973 ++       out = (void *)elem.out_sg[0].iov_base;
   2.974 ++       in = (void *)elem.in_sg[elem.in_num - 1].iov_base;
   2.975 ++       off = out->sector;
   2.976 ++
   2.977 ++       if (out->type & VIRTIO_BLK_T_SCSI_CMD) {
   2.978 ++           wlen = sizeof(*in);
   2.979 ++           in->status = VIRTIO_BLK_S_UNSUPP;
   2.980 ++       } else if (out->type & VIRTIO_BLK_T_OUT) {
   2.981 ++           wlen = sizeof(*in);
   2.982 ++
   2.983 ++           for (i = 1; i < elem.out_num; i++) {
   2.984 ++               bdrv_write(s->bs, off,
   2.985 ++                          elem.out_sg[i].iov_base,
   2.986 ++                          elem.out_sg[i].iov_len / 512);
   2.987 ++               off += elem.out_sg[i].iov_len / 512;
   2.988 ++           }
   2.989 ++
   2.990 ++           in->status = VIRTIO_BLK_S_OK;
   2.991 ++       } else {
   2.992 ++           wlen = sizeof(*in);
   2.993 ++
   2.994 ++           for (i = 0; i < elem.in_num - 1; i++) {
   2.995 ++               bdrv_read(s->bs, off,
   2.996 ++                         elem.in_sg[i].iov_base,
   2.997 ++                         elem.in_sg[i].iov_len / 512);
   2.998 ++               off += elem.in_sg[i].iov_len / 512;
   2.999 ++               wlen += elem.in_sg[i].iov_len;
  2.1000 ++           }
  2.1001 ++
  2.1002 ++           in->status = VIRTIO_BLK_S_OK;
  2.1003 ++       }
  2.1004 ++
  2.1005 ++       virtqueue_push(vq, &elem, wlen);
  2.1006 ++       virtio_notify(vdev, vq);
  2.1007 ++    }
  2.1008 ++}
  2.1009 ++
  2.1010 ++static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
  2.1011 ++{
  2.1012 ++    VirtIOBlock *s = to_virtio_blk(vdev);
  2.1013 ++    struct virtio_blk_config blkcfg;
  2.1014 ++    int64_t capacity;
  2.1015 ++
  2.1016 ++    bdrv_get_geometry(s->bs, &capacity);
  2.1017 ++    blkcfg.capacity = capacity;
  2.1018 ++    blkcfg.seg_max = 128 - 2;
  2.1019 ++    memcpy(config, &blkcfg, sizeof(blkcfg));
  2.1020 ++}
  2.1021 ++
  2.1022 ++static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
  2.1023 ++{
  2.1024 ++    return (1 << VIRTIO_BLK_F_SEG_MAX);
  2.1025 ++}
  2.1026 ++
  2.1027 ++void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device,
  2.1028 ++                     BlockDriverState *bs)
  2.1029 ++{
  2.1030 ++    VirtIOBlock *s;
  2.1031 ++
  2.1032 ++    s = (VirtIOBlock *)virtio_init_pci(bus, "virtio-blk", 6900, 0x1001,
  2.1033 ++                                      0, VIRTIO_ID_BLOCK,
  2.1034 ++                                      0x01, 0x80, 0x00,
  2.1035 ++                                      16, sizeof(VirtIOBlock));
  2.1036 ++
  2.1037 ++    s->vdev.update_config = virtio_blk_update_config;
  2.1038 ++    s->vdev.get_features = virtio_blk_get_features;
  2.1039 ++    s->bs = bs;
  2.1040 ++
  2.1041 ++    virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output);
  2.1042 ++
  2.1043 ++    return &s->vdev;
  2.1044 ++}
  2.1045 +Index: qemu-0.9.1/sysemu.h
  2.1046 +===================================================================
  2.1047 +--- qemu-0.9.1.orig/sysemu.h	2008-01-06 19:38:42.000000000 +0000
  2.1048 ++++ qemu-0.9.1/sysemu.h	2008-02-07 13:38:53.000000000 +0000
  2.1049 +@@ -117,7 +117,7 @@
  2.1050 + #endif
  2.1051 + 
  2.1052 + typedef enum {
  2.1053 +-    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD
  2.1054 ++    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO
  2.1055 + } BlockInterfaceType;
  2.1056 + 
  2.1057 + typedef struct DriveInfo {
  2.1058 +Index: qemu-0.9.1/vl.c
  2.1059 +===================================================================
  2.1060 +--- qemu-0.9.1.orig/vl.c	2008-01-06 19:38:42.000000000 +0000
  2.1061 ++++ qemu-0.9.1/vl.c	2008-02-07 13:40:52.000000000 +0000
  2.1062 +@@ -4953,6 +4953,9 @@
  2.1063 + 	} else if (!strcmp(buf, "sd")) {
  2.1064 + 	    type = IF_SD;
  2.1065 +             max_devs = 0;
  2.1066 ++	} else if (!strcmp(buf, "virtio")) {
  2.1067 ++	    type = IF_VIRTIO;
  2.1068 ++            max_devs = 0;
  2.1069 + 	} else {
  2.1070 +             fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf);
  2.1071 +             return -1;
  2.1072 +@@ -5141,6 +5144,7 @@
  2.1073 +         break;
  2.1074 +     case IF_PFLASH:
  2.1075 +     case IF_MTD:
  2.1076 ++    case IF_VIRTIO:
  2.1077 +         break;
  2.1078 +     }
  2.1079 +     if (!file[0])