wok-6.x diff qemu/stuff/virtio.u @ rev 2059

Add socat
author Pascal Bellard <pascal.bellard@slitaz.org>
date Wed Jan 21 10:56:35 2009 +0000 (2009-01-21)
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/qemu/stuff/virtio.u	Wed Jan 21 10:56:35 2009 +0000
     1.3 @@ -0,0 +1,1076 @@
     1.4 +Index: qemu-0.9.1/Makefile.target
     1.5 +===================================================================
     1.6 +--- qemu-0.9.1.orig/Makefile.target	2008-01-06 19:38:41.000000000 +0000
     1.7 ++++ qemu-0.9.1/Makefile.target	2008-02-07 13:36:23.000000000 +0000
     1.8 +@@ -436,6 +436,9 @@
     1.9 + VL_OBJS += pcnet.o
    1.10 + VL_OBJS += rtl8139.o
    1.11 + 
    1.12 ++# virtio devices
    1.13 ++VL_OBJS += virtio.o
    1.14 ++
    1.15 + ifeq ($(TARGET_BASE_ARCH), i386)
    1.16 + # Hardware support
    1.17 + VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o
    1.18 +Index: qemu-0.9.1/hw/virtio.c
    1.19 +===================================================================
    1.20 +--- /dev/null	1970-01-01 00:00:00.000000000 +0000
    1.21 ++++ qemu-0.9.1/hw/virtio.c	2008-02-07 13:36:23.000000000 +0000
    1.22 +@@ -0,0 +1,422 @@
    1.23 ++/*
    1.24 ++ * Virtio Support
    1.25 ++ *
    1.26 ++ * Copyright IBM, Corp. 2007
    1.27 ++ *
    1.28 ++ * Authors:
    1.29 ++ *  Anthony Liguori   <address@hidden>
    1.30 ++ *
    1.31 ++ * This work is licensed under the terms of the GNU GPL, version 2.  See
    1.32 ++ * the COPYING file in the top-level directory.
    1.33 ++ *
    1.34 ++ */
    1.35 ++
    1.36 ++#include <inttypes.h>
    1.37 ++#include <err.h>
    1.38 ++
    1.39 ++#include "virtio.h"
    1.40 ++#include "sysemu.h"
    1.41 ++
    1.42 ++/* from Linux's linux/virtio_pci.h */
    1.43 ++
    1.44 ++/* A 32-bit r/o bitmask of the features supported by the host */
    1.45 ++#define VIRTIO_PCI_HOST_FEATURES       0
    1.46 ++
    1.47 ++/* A 32-bit r/w bitmask of features activated by the guest */
    1.48 ++#define VIRTIO_PCI_GUEST_FEATURES      4
    1.49 ++
    1.50 ++/* A 32-bit r/w PFN for the currently selected queue */
    1.51 ++#define VIRTIO_PCI_QUEUE_PFN           8
    1.52 ++
    1.53 ++/* A 16-bit r/o queue size for the currently selected queue */
    1.54 ++#define VIRTIO_PCI_QUEUE_NUM           12
    1.55 ++
    1.56 ++/* A 16-bit r/w queue selector */
    1.57 ++#define VIRTIO_PCI_QUEUE_SEL           14
    1.58 ++
    1.59 ++/* A 16-bit r/w queue notifier */
    1.60 ++#define VIRTIO_PCI_QUEUE_NOTIFY                16
    1.61 ++
    1.62 ++/* An 8-bit device status register.  */
    1.63 ++#define VIRTIO_PCI_STATUS              18
    1.64 ++
    1.65 ++/* An 8-bit r/o interrupt status register.  Reading the value will return the
    1.66 ++ * current contents of the ISR and will also clear it.  This is effectively
    1.67 ++ * a read-and-acknowledge. */
    1.68 ++#define VIRTIO_PCI_ISR                 19
    1.69 ++
    1.70 ++#define VIRTIO_PCI_CONFIG              20
    1.71 ++
    1.72 ++/* QEMU doesn't strictly need write barriers since everything runs in
    1.73 ++ * lock-step.  We'll leave the calls to wmb() in though to make it obvious for
    1.74 ++ * KVM or if kqemu gets SMP support.
    1.75 ++ */
    1.76 ++#define wmb() do { } while (0)
    1.77 ++
    1.78 ++/* virt queue functions */
    1.79 ++
    1.80 ++static void virtqueue_init(VirtQueue *vq, void *p)
    1.81 ++{
    1.82 ++    vq->vring.desc = p;
    1.83 ++    vq->vring.avail = p + vq->vring.num * sizeof(VRingDesc);
    1.84 ++    vq->vring.used = (void *)TARGET_PAGE_ALIGN((unsigned long)&vq->vring.avail->ring[vq->vring.num]);
    1.85 ++}
    1.86 ++
    1.87 ++static unsigned virtqueue_next_desc(VirtQueue *vq, unsigned int i)
    1.88 ++{
    1.89 ++    unsigned int next;
    1.90 ++
    1.91 ++    /* If this descriptor says it doesn't chain, we're done. */
    1.92 ++    if (!(vq->vring.desc[i].flags & VRING_DESC_F_NEXT))
    1.93 ++       return vq->vring.num;
    1.94 ++
    1.95 ++    /* Check they're not leading us off end of descriptors. */
    1.96 ++    next = vq->vring.desc[i].next;
    1.97 ++    /* Make sure compiler knows to grab that: we don't want it changing! */
    1.98 ++    wmb();
    1.99 ++
   1.100 ++    if (next >= vq->vring.num)
   1.101 ++       errx(1, "Desc next is %u", next);
   1.102 ++
   1.103 ++    return next;
   1.104 ++}
   1.105 ++
   1.106 ++void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
   1.107 ++                   unsigned int len)
   1.108 ++{
   1.109 ++    VRingUsedElem *used;
   1.110 ++
   1.111 ++    /* Get a pointer to the next entry in the used ring. */
   1.112 ++    used = &vq->vring.used->ring[vq->vring.used->idx % vq->vring.num];
   1.113 ++    used->id = elem->index;
   1.114 ++    used->len = len;
   1.115 ++    /* Make sure buffer is written before we update index. */
   1.116 ++    wmb();
   1.117 ++    vq->vring.used->idx++;
   1.118 ++}
   1.119 ++
   1.120 ++int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
   1.121 ++{
   1.122 ++    unsigned int i, head;
   1.123 ++    unsigned int position;
   1.124 ++
   1.125 ++    /* Check it isn't doing very strange things with descriptor numbers. */
   1.126 ++    if ((uint16_t)(vq->vring.avail->idx - vq->last_avail_idx) > vq->vring.num)
   1.127 ++       errx(1, "Guest moved used index from %u to %u",
   1.128 ++            vq->last_avail_idx, vq->vring.avail->idx);
   1.129 ++
   1.130 ++    /* If there's nothing new since last we looked, return invalid. */
   1.131 ++    if (vq->vring.avail->idx == vq->last_avail_idx)
   1.132 ++       return 0;
   1.133 ++
   1.134 ++    /* Grab the next descriptor number they're advertising, and increment
   1.135 ++     * the index we've seen. */
   1.136 ++    head = vq->vring.avail->ring[vq->last_avail_idx++ % vq->vring.num];
   1.137 ++
   1.138 ++    /* If their number is silly, that's a fatal mistake. */
   1.139 ++    if (head >= vq->vring.num)
   1.140 ++       errx(1, "Guest says index %u is available", head);
   1.141 ++
   1.142 ++    /* When we start there are none of either input nor output. */
   1.143 ++    position = elem->out_num = elem->in_num = 0;
   1.144 ++
   1.145 ++    i = head;
   1.146 ++    do {
   1.147 ++       struct iovec *sg;
   1.148 ++
   1.149 ++       if ((vq->vring.desc[i].addr + vq->vring.desc[i].len) > ram_size)
   1.150 ++           errx(1, "Guest sent invalid pointer");
   1.151 ++
   1.152 ++       if (vq->vring.desc[i].flags & VRING_DESC_F_WRITE)
   1.153 ++           sg = &elem->in_sg[elem->in_num++];
   1.154 ++       else
   1.155 ++           sg = &elem->out_sg[elem->out_num++];
   1.156 ++
   1.157 ++       /* Grab the first descriptor, and check it's OK. */
   1.158 ++       sg->iov_len = vq->vring.desc[i].len;
   1.159 ++       sg->iov_base = phys_ram_base + vq->vring.desc[i].addr;
   1.160 ++
   1.161 ++       /* If we've got too many, that implies a descriptor loop. */
   1.162 ++       if ((elem->in_num + elem->out_num) > vq->vring.num)
   1.163 ++           errx(1, "Looped descriptor");
   1.164 ++    } while ((i = virtqueue_next_desc(vq, i)) != vq->vring.num);
   1.165 ++
   1.166 ++    elem->index = head;
   1.167 ++
   1.168 ++    return elem->in_num + elem->out_num;
   1.169 ++}
   1.170 ++
   1.171 ++/* virtio device */
   1.172 ++
   1.173 ++static VirtIODevice *to_virtio_device(PCIDevice *pci_dev)
   1.174 ++{
   1.175 ++    return (VirtIODevice *)pci_dev;
   1.176 ++}
   1.177 ++
   1.178 ++static void virtio_update_irq(VirtIODevice *vdev)
   1.179 ++{
   1.180 ++    qemu_set_irq(vdev->pci_dev.irq[0], vdev->isr & 1);
   1.181 ++}
   1.182 ++
   1.183 ++static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
   1.184 ++{
   1.185 ++    VirtIODevice *vdev = to_virtio_device(opaque);
   1.186 ++    ram_addr_t pa;
   1.187 ++
   1.188 ++    addr -= vdev->addr;
   1.189 ++
   1.190 ++    switch (addr) {
   1.191 ++    case VIRTIO_PCI_GUEST_FEATURES:
   1.192 ++       if (vdev->set_features)
   1.193 ++           vdev->set_features(vdev, val);
   1.194 ++       vdev->features = val;
   1.195 ++       break;
   1.196 ++    case VIRTIO_PCI_QUEUE_PFN:
   1.197 ++       pa = (ram_addr_t)val << TARGET_PAGE_BITS;
   1.198 ++       vdev->vq[vdev->queue_sel].pfn = val;
   1.199 ++       if (pa == 0) {
   1.200 ++           vdev->vq[vdev->queue_sel].vring.desc = NULL;
   1.201 ++           vdev->vq[vdev->queue_sel].vring.avail = NULL;
   1.202 ++           vdev->vq[vdev->queue_sel].vring.used = NULL;
   1.203 ++       } else if (pa < (ram_size - TARGET_PAGE_SIZE)) {
   1.204 ++           virtqueue_init(&vdev->vq[vdev->queue_sel], phys_ram_base + pa);
   1.205 ++           /* FIXME if pa == 0, deal with device tear down */
   1.206 ++       }
   1.207 ++       break;
   1.208 ++    case VIRTIO_PCI_QUEUE_SEL:
   1.209 ++       if (val < VIRTIO_PCI_QUEUE_MAX)
   1.210 ++           vdev->queue_sel = val;
   1.211 ++       break;
   1.212 ++    case VIRTIO_PCI_QUEUE_NOTIFY:
   1.213 ++       if (val < VIRTIO_PCI_QUEUE_MAX && vdev->vq[val].vring.desc)
   1.214 ++           vdev->vq[val].handle_output(vdev, &vdev->vq[val]);
   1.215 ++       break;
   1.216 ++    case VIRTIO_PCI_STATUS:
   1.217 ++       vdev->status = val & 0xFF;
   1.218 ++       break;
   1.219 ++    }
   1.220 ++}
   1.221 ++
   1.222 ++static uint32_t virtio_ioport_read(void *opaque, uint32_t addr)
   1.223 ++{
   1.224 ++    VirtIODevice *vdev = to_virtio_device(opaque);
   1.225 ++    uint32_t ret = 0xFFFFFFFF;
   1.226 ++
   1.227 ++    addr -= vdev->addr;
   1.228 ++
   1.229 ++    switch (addr) {
   1.230 ++    case VIRTIO_PCI_HOST_FEATURES:
   1.231 ++       ret = vdev->get_features(vdev);
   1.232 ++       break;
   1.233 ++    case VIRTIO_PCI_GUEST_FEATURES:
   1.234 ++       ret = vdev->features;
   1.235 ++       break;
   1.236 ++    case VIRTIO_PCI_QUEUE_PFN:
   1.237 ++       ret = vdev->vq[vdev->queue_sel].pfn;
   1.238 ++       break;
   1.239 ++    case VIRTIO_PCI_QUEUE_NUM:
   1.240 ++       ret = vdev->vq[vdev->queue_sel].vring.num;
   1.241 ++       break;
   1.242 ++    case VIRTIO_PCI_QUEUE_SEL:
   1.243 ++       ret = vdev->queue_sel;
   1.244 ++       break;
   1.245 ++    case VIRTIO_PCI_STATUS:
   1.246 ++       ret = vdev->status;
   1.247 ++       break;
   1.248 ++    case VIRTIO_PCI_ISR:
   1.249 ++       /* reading from the ISR also clears it. */
   1.250 ++       ret = vdev->isr;
   1.251 ++       vdev->isr = 0;
   1.252 ++       virtio_update_irq(vdev);
   1.253 ++       break;
   1.254 ++    default:
   1.255 ++       break;
   1.256 ++    }
   1.257 ++
   1.258 ++    return ret;
   1.259 ++}
   1.260 ++
   1.261 ++static uint32_t virtio_config_readb(void *opaque, uint32_t addr)
   1.262 ++{
   1.263 ++    VirtIODevice *vdev = opaque;
   1.264 ++    uint8_t val;
   1.265 ++
   1.266 ++    addr -= vdev->addr + VIRTIO_PCI_CONFIG;
   1.267 ++    if (addr > (vdev->config_len - sizeof(val)))
   1.268 ++       return (uint32_t)-1;
   1.269 ++
   1.270 ++    memcpy(&val, vdev->config + addr, sizeof(val));
   1.271 ++    return val;
   1.272 ++}
   1.273 ++
   1.274 ++static uint32_t virtio_config_readw(void *opaque, uint32_t addr)
   1.275 ++{
   1.276 ++    VirtIODevice *vdev = opaque;
   1.277 ++    uint16_t val;
   1.278 ++
   1.279 ++    addr -= vdev->addr + VIRTIO_PCI_CONFIG;
   1.280 ++    if (addr > (vdev->config_len - sizeof(val)))
   1.281 ++       return (uint32_t)-1;
   1.282 ++
   1.283 ++    memcpy(&val, vdev->config + addr, sizeof(val));
   1.284 ++    return val;
   1.285 ++}
   1.286 ++
   1.287 ++static uint32_t virtio_config_readl(void *opaque, uint32_t addr)
   1.288 ++{
   1.289 ++    VirtIODevice *vdev = opaque;
   1.290 ++    uint32_t val;
   1.291 ++
   1.292 ++    addr -= vdev->addr + VIRTIO_PCI_CONFIG;
   1.293 ++    if (addr > (vdev->config_len - sizeof(val)))
   1.294 ++       return (uint32_t)-1;
   1.295 ++
   1.296 ++    memcpy(&val, vdev->config + addr, sizeof(val));
   1.297 ++    return val;
   1.298 ++}
   1.299 ++
   1.300 ++static void virtio_config_writeb(void *opaque, uint32_t addr, uint32_t data)
   1.301 ++{
   1.302 ++    VirtIODevice *vdev = opaque;
   1.303 ++    uint8_t val = data;
   1.304 ++
   1.305 ++    addr -= vdev->addr + VIRTIO_PCI_CONFIG;
   1.306 ++    if (addr > (vdev->config_len - sizeof(val)))
   1.307 ++       return;
   1.308 ++
   1.309 ++    memcpy(vdev->config + addr, &val, sizeof(val));
   1.310 ++}
   1.311 ++
   1.312 ++static void virtio_config_writew(void *opaque, uint32_t addr, uint32_t data)
   1.313 ++{
   1.314 ++    VirtIODevice *vdev = opaque;
   1.315 ++    uint16_t val = data;
   1.316 ++
   1.317 ++    addr -= vdev->addr + VIRTIO_PCI_CONFIG;
   1.318 ++    if (addr > (vdev->config_len - sizeof(val)))
   1.319 ++       return;
   1.320 ++
   1.321 ++    memcpy(vdev->config + addr, &val, sizeof(val));
   1.322 ++}
   1.323 ++
   1.324 ++static void virtio_config_writel(void *opaque, uint32_t addr, uint32_t data)
   1.325 ++{
   1.326 ++    VirtIODevice *vdev = opaque;
   1.327 ++    uint32_t val = data;
   1.328 ++
   1.329 ++    addr -= vdev->addr + VIRTIO_PCI_CONFIG;
   1.330 ++    if (addr > (vdev->config_len - sizeof(val)))
   1.331 ++       return;
   1.332 ++
   1.333 ++    memcpy(vdev->config + addr, &val, sizeof(val));
   1.334 ++}
   1.335 ++
   1.336 ++static void virtio_map(PCIDevice *pci_dev, int region_num,
   1.337 ++                      uint32_t addr, uint32_t size, int type)
   1.338 ++{
   1.339 ++    VirtIODevice *vdev = to_virtio_device(pci_dev);
   1.340 ++    int i;
   1.341 ++
   1.342 ++    vdev->addr = addr;
   1.343 ++    for (i = 0; i < 3; i++) {
   1.344 ++       register_ioport_write(addr, 20, 1 << i, virtio_ioport_write, vdev);
   1.345 ++       register_ioport_read(addr, 20, 1 << i, virtio_ioport_read, vdev);
   1.346 ++    }
   1.347 ++
   1.348 ++    if (vdev->config_len) {
   1.349 ++       register_ioport_write(addr + 20, vdev->config_len, 1,
   1.350 ++                             virtio_config_writeb, vdev);
   1.351 ++       register_ioport_write(addr + 20, vdev->config_len, 2,
   1.352 ++                             virtio_config_writew, vdev);
   1.353 ++       register_ioport_write(addr + 20, vdev->config_len, 4,
   1.354 ++                             virtio_config_writel, vdev);
   1.355 ++       register_ioport_read(addr + 20, vdev->config_len, 1,
   1.356 ++                            virtio_config_readb, vdev);
   1.357 ++       register_ioport_read(addr + 20, vdev->config_len, 2,
   1.358 ++                            virtio_config_readw, vdev);
   1.359 ++       register_ioport_read(addr + 20, vdev->config_len, 4,
   1.360 ++                            virtio_config_readl, vdev);
   1.361 ++
   1.362 ++       vdev->update_config(vdev, vdev->config);
   1.363 ++    }
   1.364 ++}
   1.365 ++
   1.366 ++VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
   1.367 ++                           void (*handle_output)(VirtIODevice *, VirtQueue *))
   1.368 ++{
   1.369 ++    int i;
   1.370 ++
   1.371 ++    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
   1.372 ++       if (vdev->vq[i].vring.num == 0)
   1.373 ++           break;
   1.374 ++    }
   1.375 ++
   1.376 ++    if (i == VIRTIO_PCI_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
   1.377 ++       abort();
   1.378 ++
   1.379 ++    vdev->vq[i].vring.num = queue_size;
   1.380 ++    vdev->vq[i].handle_output = handle_output;
   1.381 ++    vdev->vq[i].index = i;
   1.382 ++
   1.383 ++    return &vdev->vq[i];
   1.384 ++}
   1.385 ++
   1.386 ++void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
   1.387 ++{
   1.388 ++    if (vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
   1.389 ++       return;
   1.390 ++
   1.391 ++    vdev->isr = 1;
   1.392 ++    virtio_update_irq(vdev);
   1.393 ++}
   1.394 ++
   1.395 ++VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name,
   1.396 ++                             uint16_t vendor, uint16_t device,
   1.397 ++                             uint16_t subvendor, uint16_t subdevice,
   1.398 ++                             uint8_t class_code, uint8_t subclass_code,
   1.399 ++                             uint8_t pif, size_t config_size,
   1.400 ++                             size_t struct_size)
   1.401 ++{
   1.402 ++    VirtIODevice *vdev;
   1.403 ++    PCIDevice *pci_dev;
   1.404 ++    uint8_t *config;
   1.405 ++
   1.406 ++    pci_dev = pci_register_device(bus, name, struct_size,
   1.407 ++                                 -1, NULL, NULL);
   1.408 ++    vdev = to_virtio_device(pci_dev);
   1.409 ++
   1.410 ++    vdev->status = 0;
   1.411 ++    vdev->isr = 0;
   1.412 ++    vdev->queue_sel = 0;
   1.413 ++    memset(vdev->vq, 0, sizeof(vdev->vq));
   1.414 ++
   1.415 ++    config = pci_dev->config;
   1.416 ++    config[0x00] = vendor & 0xFF;
   1.417 ++    config[0x01] = (vendor >> 8) & 0xFF;
   1.418 ++    config[0x02] = device & 0xFF;
   1.419 ++    config[0x03] = (device >> 8) & 0xFF;
   1.420 ++
   1.421 ++    config[0x09] = pif;
   1.422 ++    config[0x0a] = subclass_code;
   1.423 ++    config[0x0b] = class_code;
   1.424 ++    config[0x0e] = 0x00;
   1.425 ++
   1.426 ++    config[0x2c] = subvendor & 0xFF;
   1.427 ++    config[0x2d] = (subvendor >> 8) & 0xFF;
   1.428 ++    config[0x2e] = subdevice & 0xFF;
   1.429 ++    config[0x2f] = (subdevice >> 8) & 0xFF;
   1.430 ++
   1.431 ++    config[0x3d] = 1;
   1.432 ++
   1.433 ++    vdev->name = name;
   1.434 ++    vdev->config_len = config_size;
   1.435 ++    if (vdev->config_len)
   1.436 ++       vdev->config = qemu_mallocz(config_size);
   1.437 ++    else
   1.438 ++       vdev->config = NULL;
   1.439 ++
   1.440 ++    pci_register_io_region(pci_dev, 0, 20 + config_size, PCI_ADDRESS_SPACE_IO,
   1.441 ++                          virtio_map);
   1.442 ++
   1.443 ++    return vdev;
   1.444 ++}
   1.445 +Index: qemu-0.9.1/hw/virtio.h
   1.446 +===================================================================
   1.447 +--- /dev/null	1970-01-01 00:00:00.000000000 +0000
   1.448 ++++ qemu-0.9.1/hw/virtio.h	2008-02-07 13:36:23.000000000 +0000
   1.449 +@@ -0,0 +1,143 @@
   1.450 ++/*
   1.451 ++ * Virtio Support
   1.452 ++ *
   1.453 ++ * Copyright IBM, Corp. 2007
   1.454 ++ *
   1.455 ++ * Authors:
   1.456 ++ *  Anthony Liguori   <address@hidden>
   1.457 ++ *
   1.458 ++ * This work is licensed under the terms of the GNU GPL, version 2.  See
   1.459 ++ * the COPYING file in the top-level directory.
   1.460 ++ *
   1.461 ++ */
   1.462 ++
   1.463 ++#ifndef _QEMU_VIRTIO_H
   1.464 ++#define _QEMU_VIRTIO_H
   1.465 ++
   1.466 ++#include <sys/uio.h>
   1.467 ++#include "hw.h"
   1.468 ++#include "pci.h"
   1.469 ++
   1.470 ++/* from Linux's linux/virtio_config.h */
   1.471 ++
   1.472 ++/* Status byte for guest to report progress, and synchronize features. */
   1.473 ++/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
   1.474 ++#define VIRTIO_CONFIG_S_ACKNOWLEDGE    1
   1.475 ++/* We have found a driver for the device. */
   1.476 ++#define VIRTIO_CONFIG_S_DRIVER         2
   1.477 ++/* Driver has used its parts of the config, and is happy */
   1.478 ++#define VIRTIO_CONFIG_S_DRIVER_OK      4
   1.479 ++/* We've given up on this device. */
   1.480 ++#define VIRTIO_CONFIG_S_FAILED         0x80
   1.481 ++
   1.482 ++/* from Linux's linux/virtio_ring.h */
   1.483 ++
   1.484 ++/* This marks a buffer as continuing via the next field. */
   1.485 ++#define VRING_DESC_F_NEXT      1
   1.486 ++/* This marks a buffer as write-only (otherwise read-only). */
   1.487 ++#define VRING_DESC_F_WRITE     2
   1.488 ++
   1.489 ++/* This means don't notify other side when buffer added. */
   1.490 ++#define VRING_USED_F_NO_NOTIFY 1
   1.491 ++/* This means don't interrupt guest when buffer consumed. */
   1.492 ++#define VRING_AVAIL_F_NO_INTERRUPT     1
   1.493 ++
   1.494 ++typedef struct VirtQueue VirtQueue;
   1.495 ++typedef struct VirtIODevice VirtIODevice;
   1.496 ++
   1.497 ++typedef struct VRingDesc
   1.498 ++{
   1.499 ++    uint64_t addr;
   1.500 ++    uint32_t len;
   1.501 ++    uint16_t flags;
   1.502 ++    uint16_t next;
   1.503 ++} VRingDesc;
   1.504 ++
   1.505 ++typedef struct VRingAvail
   1.506 ++{
   1.507 ++    uint16_t flags;
   1.508 ++    uint16_t idx;
   1.509 ++    uint16_t ring[0];
   1.510 ++} VRingAvail;
   1.511 ++
   1.512 ++typedef struct VRingUsedElem
   1.513 ++{
   1.514 ++    uint32_t id;
   1.515 ++    uint32_t len;
   1.516 ++} VRingUsedElem;
   1.517 ++
   1.518 ++typedef struct VRingUsed
   1.519 ++{
   1.520 ++    uint16_t flags;
   1.521 ++    uint16_t idx;
   1.522 ++    VRingUsedElem ring[0];
   1.523 ++} VRingUsed;
   1.524 ++
   1.525 ++typedef struct VRing
   1.526 ++{
   1.527 ++    unsigned int num;
   1.528 ++    VRingDesc *desc;
   1.529 ++    VRingAvail *avail;
   1.530 ++    VRingUsed *used;
   1.531 ++} VRing;
   1.532 ++
   1.533 ++struct VirtQueue
   1.534 ++{
   1.535 ++    VRing vring;
   1.536 ++    uint32_t pfn;
   1.537 ++    uint16_t last_avail_idx;
   1.538 ++    void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
   1.539 ++    int index;
   1.540 ++};
   1.541 ++
   1.542 ++#define VIRTQUEUE_MAX_SIZE 1024
   1.543 ++
   1.544 ++typedef struct VirtQueueElement
   1.545 ++{
   1.546 ++    unsigned int index;
   1.547 ++    unsigned int out_num;
   1.548 ++    unsigned int in_num;
   1.549 ++    struct iovec in_sg[VIRTQUEUE_MAX_SIZE];
   1.550 ++    struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
   1.551 ++} VirtQueueElement;
   1.552 ++
   1.553 ++#define VIRTIO_PCI_QUEUE_MAX   16
   1.554 ++
   1.555 ++struct VirtIODevice
   1.556 ++{
   1.557 ++    PCIDevice pci_dev;
   1.558 ++    const char *name;
   1.559 ++    uint32_t addr;
   1.560 ++    uint16_t vendor;
   1.561 ++    uint16_t device;
   1.562 ++    uint8_t status;
   1.563 ++    uint8_t isr;
   1.564 ++    uint16_t queue_sel;
   1.565 ++    uint32_t features;
   1.566 ++    size_t config_len;
   1.567 ++    void *config;
   1.568 ++    uint32_t (*get_features)(VirtIODevice *vdev);
   1.569 ++    void (*set_features)(VirtIODevice *vdev, uint32_t val);
   1.570 ++    void (*update_config)(VirtIODevice *vdev, uint8_t *config);
   1.571 ++    VirtQueue vq[VIRTIO_PCI_QUEUE_MAX];
   1.572 ++};
   1.573 ++
   1.574 ++VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name,
   1.575 ++                             uint16_t vendor, uint16_t device,
   1.576 ++                             uint16_t subvendor, uint16_t subdevice,
   1.577 ++                             uint8_t class_code, uint8_t subclass_code,
   1.578 ++                             uint8_t pif, size_t config_size,
   1.579 ++                             size_t struct_size);
   1.580 ++
   1.581 ++VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
   1.582 ++                           void (*handle_output)(VirtIODevice *,
   1.583 ++                                                 VirtQueue *));
   1.584 ++
   1.585 ++void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
   1.586 ++                   unsigned int len);
   1.587 ++
   1.588 ++int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem);
   1.589 ++
   1.590 ++void virtio_notify(VirtIODevice *vdev, VirtQueue *vq);
   1.591 ++
   1.592 ++#endif
   1.593 +Index: qemu-0.9.1/Makefile.target
   1.594 +===================================================================
   1.595 +--- qemu-0.9.1.orig/Makefile.target	2008-02-07 13:36:23.000000000 +0000
   1.596 ++++ qemu-0.9.1/Makefile.target	2008-02-07 13:36:37.000000000 +0000
   1.597 +@@ -437,7 +437,7 @@
   1.598 + VL_OBJS += rtl8139.o
   1.599 + 
   1.600 + # virtio devices
   1.601 +-VL_OBJS += virtio.o
   1.602 ++VL_OBJS += virtio.o virtio-net.o
   1.603 + 
   1.604 + ifeq ($(TARGET_BASE_ARCH), i386)
   1.605 + # Hardware support
   1.606 +Index: qemu-0.9.1/hw/pc.h
   1.607 +===================================================================
   1.608 +--- qemu-0.9.1.orig/hw/pc.h	2008-01-06 19:38:42.000000000 +0000
   1.609 ++++ qemu-0.9.1/hw/pc.h	2008-02-07 13:36:37.000000000 +0000
   1.610 +@@ -142,4 +142,9 @@
   1.611 + 
   1.612 + void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd);
   1.613 + 
   1.614 ++/* virtio-net.c */
   1.615 ++
   1.616 ++void *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn);
   1.617 ++
   1.618 ++
   1.619 + #endif
   1.620 +Index: qemu-0.9.1/hw/pci.c
   1.621 +===================================================================
   1.622 +--- qemu-0.9.1.orig/hw/pci.c	2008-01-06 19:38:42.000000000 +0000
   1.623 ++++ qemu-0.9.1/hw/pci.c	2008-02-07 13:36:37.000000000 +0000
   1.624 +@@ -25,6 +25,7 @@
   1.625 + #include "pci.h"
   1.626 + #include "console.h"
   1.627 + #include "net.h"
   1.628 ++#include "pc.h"
   1.629 + 
   1.630 + //#define DEBUG_PCI
   1.631 + 
   1.632 +@@ -638,9 +639,11 @@
   1.633 +         pci_rtl8139_init(bus, nd, devfn);
   1.634 +     } else if (strcmp(nd->model, "pcnet") == 0) {
   1.635 +         pci_pcnet_init(bus, nd, devfn);
   1.636 ++    } else if (strcmp(nd->model, "virtio") == 0) {
   1.637 ++       virtio_net_init(bus, nd, devfn);
   1.638 +     } else if (strcmp(nd->model, "?") == 0) {
   1.639 +         fprintf(stderr, "qemu: Supported PCI NICs: i82551 i82557b i82559er"
   1.640 +-                        " ne2k_pci pcnet rtl8139\n");
   1.641 ++                        " ne2k_pci pcnet rtl8139 virtio\n");
   1.642 +         exit (1);
   1.643 +     } else {
   1.644 +         fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
   1.645 +Index: qemu-0.9.1/hw/virtio-net.c
   1.646 +===================================================================
   1.647 +--- /dev/null	1970-01-01 00:00:00.000000000 +0000
   1.648 ++++ qemu-0.9.1/hw/virtio-net.c	2008-02-07 13:36:37.000000000 +0000
   1.649 +@@ -0,0 +1,178 @@
   1.650 ++/*
   1.651 ++ * Virtio Network Device
   1.652 ++ *
   1.653 ++ * Copyright IBM, Corp. 2007
   1.654 ++ *
   1.655 ++ * Authors:
   1.656 ++ *  Anthony Liguori   <address@hidden>
   1.657 ++ *
   1.658 ++ * This work is licensed under the terms of the GNU GPL, version 2.  See
   1.659 ++ * the COPYING file in the top-level directory.
   1.660 ++ *
   1.661 ++ */
   1.662 ++
   1.663 ++#include "virtio.h"
   1.664 ++#include "net.h"
   1.665 ++#include "pc.h"
   1.666 ++
   1.667 ++/* from Linux's virtio_net.h */
   1.668 ++
   1.669 ++/* The ID for virtio_net */
   1.670 ++#define VIRTIO_ID_NET  1
   1.671 ++
   1.672 ++/* The feature bitmap for virtio net */
   1.673 ++#define VIRTIO_NET_F_NO_CSUM   0
   1.674 ++#define VIRTIO_NET_F_TSO4      1
   1.675 ++#define VIRTIO_NET_F_UFO       2
   1.676 ++#define VIRTIO_NET_F_TSO4_ECN  3
   1.677 ++#define VIRTIO_NET_F_TSO6      4
   1.678 ++#define VIRTIO_NET_F_MAC       5
   1.679 ++
   1.680 ++/* The config defining mac address (6 bytes) */
   1.681 ++struct virtio_net_config
   1.682 ++{
   1.683 ++    uint8_t mac[6];
   1.684 ++} __attribute__((packed));
   1.685 ++
   1.686 ++/* This is the first element of the scatter-gather list.  If you don't
   1.687 ++ * specify GSO or CSUM features, you can simply ignore the header. */
   1.688 ++struct virtio_net_hdr
   1.689 ++{
   1.690 ++#define VIRTIO_NET_HDR_F_NEEDS_CSUM    1       // Use csum_start, csum_offset
   1.691 ++    uint8_t flags;
   1.692 ++#define VIRTIO_NET_HDR_GSO_NONE                0       // Not a GSO frame
   1.693 ++#define VIRTIO_NET_HDR_GSO_TCPV4       1       // GSO frame, IPv4 TCP (TSO)
   1.694 ++/* FIXME: Do we need this?  If they said they can handle ECN, do they care? */
   1.695 ++#define VIRTIO_NET_HDR_GSO_TCPV4_ECN   2       // GSO frame, IPv4 TCP w/ ECN
   1.696 ++#define VIRTIO_NET_HDR_GSO_UDP         3       // GSO frame, IPv4 UDP (UFO)
   1.697 ++#define VIRTIO_NET_HDR_GSO_TCPV6       4       // GSO frame, IPv6 TCP
   1.698 ++    uint8_t gso_type;
   1.699 ++    uint16_t gso_size;
   1.700 ++    uint16_t csum_start;
   1.701 ++    uint16_t csum_offset;
   1.702 ++};
   1.703 ++
   1.704 ++typedef struct VirtIONet
   1.705 ++{
   1.706 ++    VirtIODevice vdev;
   1.707 ++    uint8_t mac[6];
   1.708 ++    VirtQueue *rx_vq;
   1.709 ++    VirtQueue *tx_vq;
   1.710 ++    VLANClientState *vc;
   1.711 ++    int can_receive;
   1.712 ++} VirtIONet;
   1.713 ++
   1.714 ++static VirtIONet *to_virtio_net(VirtIODevice *vdev)
   1.715 ++{
   1.716 ++    return (VirtIONet *)vdev;
   1.717 ++}
   1.718 ++
   1.719 ++static void virtio_net_update_config(VirtIODevice *vdev, uint8_t *config)
   1.720 ++{
   1.721 ++    VirtIONet *n = to_virtio_net(vdev);
   1.722 ++    struct virtio_net_config netcfg;
   1.723 ++
   1.724 ++    memcpy(netcfg.mac, n->mac, 6);
   1.725 ++    memcpy(config, &netcfg, sizeof(netcfg));
   1.726 ++}
   1.727 ++
   1.728 ++static uint32_t virtio_net_get_features(VirtIODevice *vdev)
   1.729 ++{
   1.730 ++    return (1 << VIRTIO_NET_F_MAC);
   1.731 ++}
   1.732 ++
   1.733 ++/* RX */
   1.734 ++
   1.735 ++static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
   1.736 ++{
   1.737 ++    VirtIONet *n = to_virtio_net(vdev);
   1.738 ++    n->can_receive = 1;
   1.739 ++}
   1.740 ++
   1.741 ++static int virtio_net_can_receive(void *opaque)
   1.742 ++{
   1.743 ++    VirtIONet *n = opaque;
   1.744 ++
   1.745 ++    return (n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) && n->can_receive;
   1.746 ++}
   1.747 ++
   1.748 ++static void virtio_net_receive(void *opaque, const uint8_t *buf, int size)
   1.749 ++{
   1.750 ++    VirtIONet *n = opaque;
   1.751 ++    VirtQueueElement elem;
   1.752 ++    struct virtio_net_hdr *hdr;
   1.753 ++    int offset, i;
   1.754 ++
   1.755 ++    /* FIXME: the drivers really need to set their status better */
   1.756 ++    if (n->rx_vq->vring.avail == NULL) {
   1.757 ++       n->can_receive = 0;
   1.758 ++       return;
   1.759 ++    }
   1.760 ++
   1.761 ++    if (virtqueue_pop(n->rx_vq, &elem) == 0) {
   1.762 ++       /* wait until the guest adds some rx bufs */
   1.763 ++       n->can_receive = 0;
   1.764 ++       return;
   1.765 ++    }
   1.766 ++
   1.767 ++    hdr = (void *)elem.in_sg[0].iov_base;
   1.768 ++    hdr->flags = 0;
   1.769 ++    hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
   1.770 ++
   1.771 ++    /* copy in packet.  ugh */
   1.772 ++    offset = 0;
   1.773 ++    i = 1;
   1.774 ++    while (offset < size && i < elem.in_num) {
   1.775 ++       int len = MIN(elem.in_sg[i].iov_len, size - offset);
   1.776 ++       memcpy(elem.in_sg[i].iov_base, buf + offset, len);
   1.777 ++       offset += len;
   1.778 ++       i++;
   1.779 ++    }
   1.780 ++
   1.781 ++    /* signal other side */
   1.782 ++    virtqueue_push(n->rx_vq, &elem, sizeof(*hdr) + offset);
   1.783 ++    virtio_notify(&n->vdev, n->rx_vq);
   1.784 ++}
   1.785 ++
   1.786 ++/* TX */
   1.787 ++static void virtio_net_handle_tx(VirtIODevice *vdev, VirtQueue *vq)
   1.788 ++{
   1.789 ++    VirtIONet *n = to_virtio_net(vdev);
   1.790 ++    VirtQueueElement elem;
   1.791 ++
   1.792 ++    while (virtqueue_pop(vq, &elem)) {
   1.793 ++       int i;
   1.794 ++       size_t len = 0;
   1.795 ++
   1.796 ++       /* ignore the header for now */
   1.797 ++       for (i = 1; i < elem.out_num; i++) {
   1.798 ++           qemu_send_packet(n->vc, elem.out_sg[i].iov_base,
   1.799 ++                            elem.out_sg[i].iov_len);
   1.800 ++           len += elem.out_sg[i].iov_len;
   1.801 ++       }
   1.802 ++
   1.803 ++       virtqueue_push(vq, &elem, sizeof(struct virtio_net_hdr) + len);
   1.804 ++       virtio_notify(&n->vdev, vq);
   1.805 ++    }
   1.806 ++}
   1.807 ++
   1.808 ++void *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn)
   1.809 ++{
   1.810 ++    VirtIONet *n;
   1.811 ++
   1.812 ++    n = (VirtIONet *)virtio_init_pci(bus, "virtio-net", 6900, 0x1000,
   1.813 ++                                    0, VIRTIO_ID_NET,
   1.814 ++                                    0x02, 0x00, 0x00,
   1.815 ++                                    6, sizeof(VirtIONet));
   1.816 ++
   1.817 ++    n->vdev.update_config = virtio_net_update_config;
   1.818 ++    n->vdev.get_features = virtio_net_get_features;
   1.819 ++    n->rx_vq = virtio_add_queue(&n->vdev, 512, virtio_net_handle_rx);
   1.820 ++    n->tx_vq = virtio_add_queue(&n->vdev, 128, virtio_net_handle_tx);
   1.821 ++    n->can_receive = 0;
   1.822 ++    memcpy(n->mac, nd->macaddr, 6);
   1.823 ++    n->vc = qemu_new_vlan_client(nd->vlan, virtio_net_receive,
   1.824 ++                                virtio_net_can_receive, n);
   1.825 ++
   1.826 ++    return &n->vdev;
   1.827 ++}
   1.828 +Index: qemu-0.9.1/Makefile.target
   1.829 +===================================================================
   1.830 +--- qemu-0.9.1.orig/Makefile.target	2008-02-07 13:36:37.000000000 +0000
   1.831 ++++ qemu-0.9.1/Makefile.target	2008-02-07 13:38:53.000000000 +0000
   1.832 +@@ -437,7 +437,7 @@
   1.833 + VL_OBJS += rtl8139.o
   1.834 + 
   1.835 + # virtio devices
   1.836 +-VL_OBJS += virtio.o virtio-net.o
   1.837 ++VL_OBJS += virtio.o virtio-net.o virtio-blk.o
   1.838 + 
   1.839 + ifeq ($(TARGET_BASE_ARCH), i386)
   1.840 + # Hardware support
   1.841 +Index: qemu-0.9.1/hw/pc.c
   1.842 +===================================================================
   1.843 +--- qemu-0.9.1.orig/hw/pc.c	2008-01-06 19:38:42.000000000 +0000
   1.844 ++++ qemu-0.9.1/hw/pc.c	2008-02-07 13:38:53.000000000 +0000
   1.845 +@@ -1008,6 +1008,18 @@
   1.846 + 	    }
   1.847 +         }
   1.848 +     }
   1.849 ++
   1.850 ++    /* Add virtio block devices */
   1.851 ++    if (pci_enabled) {
   1.852 ++       int index;
   1.853 ++       int unit_id = 0;
   1.854 ++
   1.855 ++       while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) {
   1.856 ++           virtio_blk_init(pci_bus, 0x5002, 0x2258,
   1.857 ++                           drives_table[index].bdrv);
   1.858 ++           unit_id++;
   1.859 ++       }
   1.860 ++    }
   1.861 + }
   1.862 + 
   1.863 + static void pc_init_pci(int ram_size, int vga_ram_size,
   1.864 +Index: qemu-0.9.1/hw/pc.h
   1.865 +===================================================================
   1.866 +--- qemu-0.9.1.orig/hw/pc.h	2008-02-07 13:36:37.000000000 +0000
   1.867 ++++ qemu-0.9.1/hw/pc.h	2008-02-07 13:38:53.000000000 +0000
   1.868 +@@ -147,4 +147,8 @@
   1.869 + void *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn);
   1.870 + 
   1.871 + 
   1.872 ++/* virtio-blk.h */
   1.873 ++void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device,
   1.874 ++                     BlockDriverState *bs);
   1.875 ++
   1.876 + #endif
   1.877 +Index: qemu-0.9.1/hw/virtio-blk.c
   1.878 +===================================================================
   1.879 +--- /dev/null	1970-01-01 00:00:00.000000000 +0000
   1.880 ++++ qemu-0.9.1/hw/virtio-blk.c	2008-02-07 13:38:53.000000000 +0000
   1.881 +@@ -0,0 +1,163 @@
   1.882 ++/*
   1.883 ++ * Virtio Block Device
   1.884 ++ *
   1.885 ++ * Copyright IBM, Corp. 2007
   1.886 ++ *
   1.887 ++ * Authors:
   1.888 ++ *  Anthony Liguori   <address@hidden>
   1.889 ++ *
   1.890 ++ * This work is licensed under the terms of the GNU GPL, version 2.  See
   1.891 ++ * the COPYING file in the top-level directory.
   1.892 ++ *
   1.893 ++ */
   1.894 ++
   1.895 ++#include "virtio.h"
   1.896 ++#include "block.h"
   1.897 ++#include "pc.h"
   1.898 ++
   1.899 ++/* from Linux's linux/virtio_blk.h */
   1.900 ++
   1.901 ++/* The ID for virtio_block */
   1.902 ++#define VIRTIO_ID_BLOCK        2
   1.903 ++
   1.904 ++/* Feature bits */
   1.905 ++#define VIRTIO_BLK_F_BARRIER   0       /* Does host support barriers? */
   1.906 ++#define VIRTIO_BLK_F_SIZE_MAX  1       /* Indicates maximum segment size */
   1.907 ++#define VIRTIO_BLK_F_SEG_MAX   2       /* Indicates maximum # of segments */
   1.908 ++
   1.909 ++struct virtio_blk_config
   1.910 ++{
   1.911 ++    uint64_t capacity;
   1.912 ++    uint32_t size_max;
   1.913 ++    uint32_t seg_max;
   1.914 ++};
   1.915 ++
   1.916 ++/* These two define direction. */
   1.917 ++#define VIRTIO_BLK_T_IN                0
   1.918 ++#define VIRTIO_BLK_T_OUT       1
   1.919 ++
   1.920 ++/* This bit says it's a scsi command, not an actual read or write. */
   1.921 ++#define VIRTIO_BLK_T_SCSI_CMD  2
   1.922 ++
   1.923 ++/* Barrier before this op. */
   1.924 ++#define VIRTIO_BLK_T_BARRIER   0x80000000
   1.925 ++
   1.926 ++/* This is the first element of the read scatter-gather list. */
   1.927 ++struct virtio_blk_outhdr
   1.928 ++{
   1.929 ++    /* VIRTIO_BLK_T* */
   1.930 ++    uint32_t type;
   1.931 ++    /* io priority. */
   1.932 ++    uint32_t ioprio;
   1.933 ++    /* Sector (ie. 512 byte offset) */
   1.934 ++    uint64_t sector;
   1.935 ++    /* Where to put reply. */
   1.936 ++    uint64_t id;
   1.937 ++};
   1.938 ++
   1.939 ++#define VIRTIO_BLK_S_OK                0
   1.940 ++#define VIRTIO_BLK_S_IOERR     1
   1.941 ++#define VIRTIO_BLK_S_UNSUPP    2
   1.942 ++
   1.943 ++/* This is the first element of the write scatter-gather list */
   1.944 ++struct virtio_blk_inhdr
   1.945 ++{
   1.946 ++    unsigned char status;
   1.947 ++};
   1.948 ++
   1.949 ++typedef struct VirtIOBlock
   1.950 ++{
   1.951 ++    VirtIODevice vdev;
   1.952 ++    BlockDriverState *bs;
   1.953 ++} VirtIOBlock;
   1.954 ++
   1.955 ++static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
   1.956 ++{
   1.957 ++    return (VirtIOBlock *)vdev;
   1.958 ++}
   1.959 ++
   1.960 ++static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
   1.961 ++{
   1.962 ++    VirtIOBlock *s = to_virtio_blk(vdev);
   1.963 ++    VirtQueueElement elem;
   1.964 ++    unsigned int count;
   1.965 ++
   1.966 ++    while ((count = virtqueue_pop(vq, &elem)) != 0) {
   1.967 ++       struct virtio_blk_inhdr *in;
   1.968 ++       struct virtio_blk_outhdr *out;
   1.969 ++       unsigned int wlen;
   1.970 ++       off_t off;
   1.971 ++       int i;
   1.972 ++
   1.973 ++       out = (void *)elem.out_sg[0].iov_base;
   1.974 ++       in = (void *)elem.in_sg[elem.in_num - 1].iov_base;
   1.975 ++       off = out->sector;
   1.976 ++
   1.977 ++       if (out->type & VIRTIO_BLK_T_SCSI_CMD) {
   1.978 ++           wlen = sizeof(*in);
   1.979 ++           in->status = VIRTIO_BLK_S_UNSUPP;
   1.980 ++       } else if (out->type & VIRTIO_BLK_T_OUT) {
   1.981 ++           wlen = sizeof(*in);
   1.982 ++
   1.983 ++           for (i = 1; i < elem.out_num; i++) {
   1.984 ++               bdrv_write(s->bs, off,
   1.985 ++                          elem.out_sg[i].iov_base,
   1.986 ++                          elem.out_sg[i].iov_len / 512);
   1.987 ++               off += elem.out_sg[i].iov_len / 512;
   1.988 ++           }
   1.989 ++
   1.990 ++           in->status = VIRTIO_BLK_S_OK;
   1.991 ++       } else {
   1.992 ++           wlen = sizeof(*in);
   1.993 ++
   1.994 ++           for (i = 0; i < elem.in_num - 1; i++) {
   1.995 ++               bdrv_read(s->bs, off,
   1.996 ++                         elem.in_sg[i].iov_base,
   1.997 ++                         elem.in_sg[i].iov_len / 512);
   1.998 ++               off += elem.in_sg[i].iov_len / 512;
   1.999 ++               wlen += elem.in_sg[i].iov_len;
  1.1000 ++           }
  1.1001 ++
  1.1002 ++           in->status = VIRTIO_BLK_S_OK;
  1.1003 ++       }
  1.1004 ++
  1.1005 ++       virtqueue_push(vq, &elem, wlen);
  1.1006 ++       virtio_notify(vdev, vq);
  1.1007 ++    }
  1.1008 ++}
  1.1009 ++
  1.1010 ++static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
  1.1011 ++{
  1.1012 ++    VirtIOBlock *s = to_virtio_blk(vdev);
  1.1013 ++    struct virtio_blk_config blkcfg;
  1.1014 ++    int64_t capacity;
  1.1015 ++
  1.1016 ++    bdrv_get_geometry(s->bs, &capacity);
  1.1017 ++    blkcfg.capacity = capacity;
  1.1018 ++    blkcfg.seg_max = 128 - 2;
  1.1019 ++    memcpy(config, &blkcfg, sizeof(blkcfg));
  1.1020 ++}
  1.1021 ++
  1.1022 ++static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
  1.1023 ++{
  1.1024 ++    return (1 << VIRTIO_BLK_F_SEG_MAX);
  1.1025 ++}
  1.1026 ++
  1.1027 ++void *virtio_blk_init(PCIBus *bus, uint16_t vendor, uint16_t device,
  1.1028 ++                     BlockDriverState *bs)
  1.1029 ++{
  1.1030 ++    VirtIOBlock *s;
  1.1031 ++
  1.1032 ++    s = (VirtIOBlock *)virtio_init_pci(bus, "virtio-blk", 6900, 0x1001,
  1.1033 ++                                      0, VIRTIO_ID_BLOCK,
  1.1034 ++                                      0x01, 0x80, 0x00,
  1.1035 ++                                      16, sizeof(VirtIOBlock));
  1.1036 ++
  1.1037 ++    s->vdev.update_config = virtio_blk_update_config;
  1.1038 ++    s->vdev.get_features = virtio_blk_get_features;
  1.1039 ++    s->bs = bs;
  1.1040 ++
  1.1041 ++    virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output);
  1.1042 ++
  1.1043 ++    return &s->vdev;
  1.1044 ++}
  1.1045 +Index: qemu-0.9.1/sysemu.h
  1.1046 +===================================================================
  1.1047 +--- qemu-0.9.1.orig/sysemu.h	2008-01-06 19:38:42.000000000 +0000
  1.1048 ++++ qemu-0.9.1/sysemu.h	2008-02-07 13:38:53.000000000 +0000
  1.1049 +@@ -117,7 +117,7 @@
  1.1050 + #endif
  1.1051 + 
  1.1052 + typedef enum {
  1.1053 +-    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD
  1.1054 ++    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO
  1.1055 + } BlockInterfaceType;
  1.1056 + 
  1.1057 + typedef struct DriveInfo {
  1.1058 +Index: qemu-0.9.1/vl.c
  1.1059 +===================================================================
  1.1060 +--- qemu-0.9.1.orig/vl.c	2008-01-06 19:38:42.000000000 +0000
  1.1061 ++++ qemu-0.9.1/vl.c	2008-02-07 13:40:52.000000000 +0000
  1.1062 +@@ -4953,6 +4953,9 @@
  1.1063 + 	} else if (!strcmp(buf, "sd")) {
  1.1064 + 	    type = IF_SD;
  1.1065 +             max_devs = 0;
  1.1066 ++	} else if (!strcmp(buf, "virtio")) {
  1.1067 ++	    type = IF_VIRTIO;
  1.1068 ++            max_devs = 0;
  1.1069 + 	} else {
  1.1070 +             fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf);
  1.1071 +             return -1;
  1.1072 +@@ -5141,6 +5144,7 @@
  1.1073 +         break;
  1.1074 +     case IF_PFLASH:
  1.1075 +     case IF_MTD:
  1.1076 ++    case IF_VIRTIO:
  1.1077 +         break;
  1.1078 +     }
  1.1079 +     if (!file[0])