wok-next diff qemu/stuff/virtio.u @ rev 12865
Up: awesome to 3.4.11.
author | Christopher Rogers <slaxemulator@gmail.com> |
---|---|
date | Thu May 24 21:17:01 2012 +0000 (2012-05-24) |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/qemu/stuff/virtio.u Thu May 24 21:17:01 2012 +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])