Annotation of qemu/hw/virtio.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Virtio Support
        !             3:  *
        !             4:  * Copyright IBM, Corp. 2007
        !             5:  *
        !             6:  * Authors:
        !             7:  *  Anthony Liguori   <[email protected]>
        !             8:  *
        !             9:  * This work is licensed under the terms of the GNU GPL, version 2.  See
        !            10:  * the COPYING file in the top-level directory.
        !            11:  *
        !            12:  */
        !            13: 
        !            14: #include <inttypes.h>
        !            15: 
        !            16: #include "virtio.h"
        !            17: #include "sysemu.h"
        !            18: 
        !            19: //#define VIRTIO_ZERO_COPY
        !            20: 
        !            21: /* from Linux's linux/virtio_pci.h */
        !            22: 
        !            23: /* A 32-bit r/o bitmask of the features supported by the host */
        !            24: #define VIRTIO_PCI_HOST_FEATURES        0
        !            25: 
        !            26: /* A 32-bit r/w bitmask of features activated by the guest */
        !            27: #define VIRTIO_PCI_GUEST_FEATURES       4
        !            28: 
        !            29: /* A 32-bit r/w PFN for the currently selected queue */
        !            30: #define VIRTIO_PCI_QUEUE_PFN            8
        !            31: 
        !            32: /* A 16-bit r/o queue size for the currently selected queue */
        !            33: #define VIRTIO_PCI_QUEUE_NUM            12
        !            34: 
        !            35: /* A 16-bit r/w queue selector */
        !            36: #define VIRTIO_PCI_QUEUE_SEL            14
        !            37: 
        !            38: /* A 16-bit r/w queue notifier */
        !            39: #define VIRTIO_PCI_QUEUE_NOTIFY         16
        !            40: 
        !            41: /* An 8-bit device status register.  */
        !            42: #define VIRTIO_PCI_STATUS               18
        !            43: 
        !            44: /* An 8-bit r/o interrupt status register.  Reading the value will return the
        !            45:  * current contents of the ISR and will also clear it.  This is effectively
        !            46:  * a read-and-acknowledge. */
        !            47: #define VIRTIO_PCI_ISR                  19
        !            48: 
        !            49: #define VIRTIO_PCI_CONFIG               20
        !            50: 
        !            51: /* Virtio ABI version, if we increment this, we break the guest driver. */
        !            52: #define VIRTIO_PCI_ABI_VERSION          0
        !            53: 
        !            54: /* How many bits to shift physical queue address written to QUEUE_PFN.
        !            55:  * 12 is historical, and due to x86 page size. */
        !            56: #define VIRTIO_PCI_QUEUE_ADDR_SHIFT    12
        !            57: 
        !            58: /* The alignment to use between consumer and producer parts of vring.
        !            59:  * x86 pagesize again. */
        !            60: #define VIRTIO_PCI_VRING_ALIGN         4096
        !            61: 
        !            62: /* QEMU doesn't strictly need write barriers since everything runs in
        !            63:  * lock-step.  We'll leave the calls to wmb() in though to make it obvious for
        !            64:  * KVM or if kqemu gets SMP support.
        !            65:  */
        !            66: #define wmb() do { } while (0)
        !            67: 
        !            68: typedef struct VRingDesc
        !            69: {
        !            70:     uint64_t addr;
        !            71:     uint32_t len;
        !            72:     uint16_t flags;
        !            73:     uint16_t next;
        !            74: } VRingDesc;
        !            75: 
        !            76: typedef struct VRingAvail
        !            77: {
        !            78:     uint16_t flags;
        !            79:     uint16_t idx;
        !            80:     uint16_t ring[0];
        !            81: } VRingAvail;
        !            82: 
        !            83: typedef struct VRingUsedElem
        !            84: {
        !            85:     uint32_t id;
        !            86:     uint32_t len;
        !            87: } VRingUsedElem;
        !            88: 
        !            89: typedef struct VRingUsed
        !            90: {
        !            91:     uint16_t flags;
        !            92:     uint16_t idx;
        !            93:     VRingUsedElem ring[0];
        !            94: } VRingUsed;
        !            95: 
        !            96: typedef struct VRing
        !            97: {
        !            98:     unsigned int num;
        !            99:     target_phys_addr_t desc;
        !           100:     target_phys_addr_t avail;
        !           101:     target_phys_addr_t used;
        !           102: } VRing;
        !           103: 
        !           104: struct VirtQueue
        !           105: {
        !           106:     VRing vring;
        !           107:     uint32_t pfn;
        !           108:     uint16_t last_avail_idx;
        !           109:     int inuse;
        !           110:     void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
        !           111: };
        !           112: 
        !           113: #define VIRTIO_PCI_QUEUE_MAX        16
        !           114: 
        !           115: /* virt queue functions */
        !           116: #ifdef VIRTIO_ZERO_COPY
        !           117: static void *virtio_map_gpa(target_phys_addr_t addr, size_t size)
        !           118: {
        !           119:     ram_addr_t off;
        !           120:     target_phys_addr_t addr1;
        !           121: 
        !           122:     off = cpu_get_physical_page_desc(addr);
        !           123:     if ((off & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
        !           124:         fprintf(stderr, "virtio DMA to IO ram\n");
        !           125:         exit(1);
        !           126:     }
        !           127: 
        !           128:     off = (off & TARGET_PAGE_MASK) | (addr & ~TARGET_PAGE_MASK);
        !           129: 
        !           130:     for (addr1 = addr + TARGET_PAGE_SIZE;
        !           131:          addr1 < TARGET_PAGE_ALIGN(addr + size);
        !           132:          addr1 += TARGET_PAGE_SIZE) {
        !           133:         ram_addr_t off1;
        !           134: 
        !           135:         off1 = cpu_get_physical_page_desc(addr1);
        !           136:         if ((off1 & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
        !           137:             fprintf(stderr, "virtio DMA to IO ram\n");
        !           138:             exit(1);
        !           139:         }
        !           140: 
        !           141:         off1 = (off1 & TARGET_PAGE_MASK) | (addr1 & ~TARGET_PAGE_MASK);
        !           142: 
        !           143:         if (off1 != (off + (addr1 - addr))) {
        !           144:             fprintf(stderr, "discontigous virtio memory\n");
        !           145:             exit(1);
        !           146:         }
        !           147:     }
        !           148: 
        !           149:     return phys_ram_base + off;
        !           150: }
        !           151: #endif
        !           152: 
        !           153: static void virtqueue_init(VirtQueue *vq, target_phys_addr_t pa)
        !           154: {
        !           155:     vq->vring.desc = pa;
        !           156:     vq->vring.avail = pa + vq->vring.num * sizeof(VRingDesc);
        !           157:     vq->vring.used = vring_align(vq->vring.avail +
        !           158:                                  offsetof(VRingAvail, ring[vq->vring.num]),
        !           159:                                  VIRTIO_PCI_VRING_ALIGN);
        !           160: }
        !           161: 
        !           162: static inline uint64_t vring_desc_addr(VirtQueue *vq, int i)
        !           163: {
        !           164:     target_phys_addr_t pa;
        !           165:     pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr);
        !           166:     return ldq_phys(pa);
        !           167: }
        !           168: 
        !           169: static inline uint32_t vring_desc_len(VirtQueue *vq, int i)
        !           170: {
        !           171:     target_phys_addr_t pa;
        !           172:     pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, len);
        !           173:     return ldl_phys(pa);
        !           174: }
        !           175: 
        !           176: static inline uint16_t vring_desc_flags(VirtQueue *vq, int i)
        !           177: {
        !           178:     target_phys_addr_t pa;
        !           179:     pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags);
        !           180:     return lduw_phys(pa);
        !           181: }
        !           182: 
        !           183: static inline uint16_t vring_desc_next(VirtQueue *vq, int i)
        !           184: {
        !           185:     target_phys_addr_t pa;
        !           186:     pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, next);
        !           187:     return lduw_phys(pa);
        !           188: }
        !           189: 
        !           190: static inline uint16_t vring_avail_flags(VirtQueue *vq)
        !           191: {
        !           192:     target_phys_addr_t pa;
        !           193:     pa = vq->vring.avail + offsetof(VRingAvail, flags);
        !           194:     return lduw_phys(pa);
        !           195: }
        !           196: 
        !           197: static inline uint16_t vring_avail_idx(VirtQueue *vq)
        !           198: {
        !           199:     target_phys_addr_t pa;
        !           200:     pa = vq->vring.avail + offsetof(VRingAvail, idx);
        !           201:     return lduw_phys(pa);
        !           202: }
        !           203: 
        !           204: static inline uint16_t vring_avail_ring(VirtQueue *vq, int i)
        !           205: {
        !           206:     target_phys_addr_t pa;
        !           207:     pa = vq->vring.avail + offsetof(VRingAvail, ring[i]);
        !           208:     return lduw_phys(pa);
        !           209: }
        !           210: 
        !           211: static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val)
        !           212: {
        !           213:     target_phys_addr_t pa;
        !           214:     pa = vq->vring.used + offsetof(VRingUsed, ring[i].id);
        !           215:     stl_phys(pa, val);
        !           216: }
        !           217: 
        !           218: static inline void vring_used_ring_len(VirtQueue *vq, int i, uint32_t val)
        !           219: {
        !           220:     target_phys_addr_t pa;
        !           221:     pa = vq->vring.used + offsetof(VRingUsed, ring[i].len);
        !           222:     stl_phys(pa, val);
        !           223: }
        !           224: 
        !           225: static uint16_t vring_used_idx(VirtQueue *vq)
        !           226: {
        !           227:     target_phys_addr_t pa;
        !           228:     pa = vq->vring.used + offsetof(VRingUsed, idx);
        !           229:     return lduw_phys(pa);
        !           230: }
        !           231: 
        !           232: static inline void vring_used_idx_increment(VirtQueue *vq, uint16_t val)
        !           233: {
        !           234:     target_phys_addr_t pa;
        !           235:     pa = vq->vring.used + offsetof(VRingUsed, idx);
        !           236:     stw_phys(pa, vring_used_idx(vq) + val);
        !           237: }
        !           238: 
        !           239: static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask)
        !           240: {
        !           241:     target_phys_addr_t pa;
        !           242:     pa = vq->vring.used + offsetof(VRingUsed, flags);
        !           243:     stw_phys(pa, lduw_phys(pa) | mask);
        !           244: }
        !           245: 
        !           246: static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask)
        !           247: {
        !           248:     target_phys_addr_t pa;
        !           249:     pa = vq->vring.used + offsetof(VRingUsed, flags);
        !           250:     stw_phys(pa, lduw_phys(pa) & ~mask);
        !           251: }
        !           252: 
        !           253: void virtio_queue_set_notification(VirtQueue *vq, int enable)
        !           254: {
        !           255:     if (enable)
        !           256:         vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY);
        !           257:     else
        !           258:         vring_used_flags_set_bit(vq, VRING_USED_F_NO_NOTIFY);
        !           259: }
        !           260: 
        !           261: int virtio_queue_ready(VirtQueue *vq)
        !           262: {
        !           263:     return vq->vring.avail != 0;
        !           264: }
        !           265: 
        !           266: int virtio_queue_empty(VirtQueue *vq)
        !           267: {
        !           268:     return vring_avail_idx(vq) == vq->last_avail_idx;
        !           269: }
        !           270: 
        !           271: void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
        !           272:                     unsigned int len, unsigned int idx)
        !           273: {
        !           274:     unsigned int offset;
        !           275:     int i;
        !           276: 
        !           277: #ifndef VIRTIO_ZERO_COPY
        !           278:     for (i = 0; i < elem->out_num; i++)
        !           279:         qemu_free(elem->out_sg[i].iov_base);
        !           280: #endif
        !           281: 
        !           282:     offset = 0;
        !           283:     for (i = 0; i < elem->in_num; i++) {
        !           284:         size_t size = MIN(len - offset, elem->in_sg[i].iov_len);
        !           285: 
        !           286: #ifdef VIRTIO_ZERO_COPY
        !           287:         if (size) {
        !           288:             ram_addr_t addr = (uint8_t *)elem->in_sg[i].iov_base - phys_ram_base;
        !           289:             ram_addr_t off;
        !           290: 
        !           291:             for (off = 0; off < size; off += TARGET_PAGE_SIZE)
        !           292:                 cpu_physical_memory_set_dirty(addr + off);
        !           293:         }
        !           294: #else
        !           295:         if (size)
        !           296:             cpu_physical_memory_write(elem->in_addr[i],
        !           297:                                       elem->in_sg[i].iov_base,
        !           298:                                       size);
        !           299: 
        !           300:         qemu_free(elem->in_sg[i].iov_base);
        !           301: #endif
        !           302:         
        !           303:         offset += size;
        !           304:     }
        !           305: 
        !           306:     idx = (idx + vring_used_idx(vq)) % vq->vring.num;
        !           307: 
        !           308:     /* Get a pointer to the next entry in the used ring. */
        !           309:     vring_used_ring_id(vq, idx, elem->index);
        !           310:     vring_used_ring_len(vq, idx, len);
        !           311: }
        !           312: 
        !           313: void virtqueue_flush(VirtQueue *vq, unsigned int count)
        !           314: {
        !           315:     /* Make sure buffer is written before we update index. */
        !           316:     wmb();
        !           317:     vring_used_idx_increment(vq, count);
        !           318:     vq->inuse -= count;
        !           319: }
        !           320: 
        !           321: void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
        !           322:                     unsigned int len)
        !           323: {
        !           324:     virtqueue_fill(vq, elem, len, 0);
        !           325:     virtqueue_flush(vq, 1);
        !           326: }
        !           327: 
        !           328: static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx)
        !           329: {
        !           330:     uint16_t num_heads = vring_avail_idx(vq) - idx;
        !           331: 
        !           332:     /* Check it isn't doing very strange things with descriptor numbers. */
        !           333:     if (num_heads > vq->vring.num) {
        !           334:         fprintf(stderr, "Guest moved used index from %u to %u",
        !           335:                 idx, vring_avail_idx(vq));
        !           336:         exit(1);
        !           337:     }
        !           338: 
        !           339:     return num_heads;
        !           340: }
        !           341: 
        !           342: static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx)
        !           343: {
        !           344:     unsigned int head;
        !           345: 
        !           346:     /* Grab the next descriptor number they're advertising, and increment
        !           347:      * the index we've seen. */
        !           348:     head = vring_avail_ring(vq, idx % vq->vring.num);
        !           349: 
        !           350:     /* If their number is silly, that's a fatal mistake. */
        !           351:     if (head >= vq->vring.num) {
        !           352:         fprintf(stderr, "Guest says index %u is available", head);
        !           353:         exit(1);
        !           354:     }
        !           355: 
        !           356:     return head;
        !           357: }
        !           358: 
        !           359: static unsigned virtqueue_next_desc(VirtQueue *vq, unsigned int i)
        !           360: {
        !           361:     unsigned int next;
        !           362: 
        !           363:     /* If this descriptor says it doesn't chain, we're done. */
        !           364:     if (!(vring_desc_flags(vq, i) & VRING_DESC_F_NEXT))
        !           365:         return vq->vring.num;
        !           366: 
        !           367:     /* Check they're not leading us off end of descriptors. */
        !           368:     next = vring_desc_next(vq, i);
        !           369:     /* Make sure compiler knows to grab that: we don't want it changing! */
        !           370:     wmb();
        !           371: 
        !           372:     if (next >= vq->vring.num) {
        !           373:         fprintf(stderr, "Desc next is %u", next);
        !           374:         exit(1);
        !           375:     }
        !           376: 
        !           377:     return next;
        !           378: }
        !           379: 
        !           380: int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes)
        !           381: {
        !           382:     unsigned int idx;
        !           383:     int num_bufs, in_total, out_total;
        !           384: 
        !           385:     idx = vq->last_avail_idx;
        !           386: 
        !           387:     num_bufs = in_total = out_total = 0;
        !           388:     while (virtqueue_num_heads(vq, idx)) {
        !           389:         int i;
        !           390: 
        !           391:         i = virtqueue_get_head(vq, idx++);
        !           392:         do {
        !           393:             /* If we've got too many, that implies a descriptor loop. */
        !           394:             if (++num_bufs > vq->vring.num) {
        !           395:                 fprintf(stderr, "Looped descriptor");
        !           396:                 exit(1);
        !           397:             }
        !           398: 
        !           399:             if (vring_desc_flags(vq, i) & VRING_DESC_F_WRITE) {
        !           400:                 if (in_bytes > 0 &&
        !           401:                     (in_total += vring_desc_len(vq, i)) >= in_bytes)
        !           402:                     return 1;
        !           403:             } else {
        !           404:                 if (out_bytes > 0 &&
        !           405:                     (out_total += vring_desc_len(vq, i)) >= out_bytes)
        !           406:                     return 1;
        !           407:             }
        !           408:         } while ((i = virtqueue_next_desc(vq, i)) != vq->vring.num);
        !           409:     }
        !           410: 
        !           411:     return 0;
        !           412: }
        !           413: 
        !           414: int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
        !           415: {
        !           416:     unsigned int i, head;
        !           417: 
        !           418:     if (!virtqueue_num_heads(vq, vq->last_avail_idx))
        !           419:         return 0;
        !           420: 
        !           421:     /* When we start there are none of either input nor output. */
        !           422:     elem->out_num = elem->in_num = 0;
        !           423: 
        !           424:     i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
        !           425:     do {
        !           426:         struct iovec *sg;
        !           427: 
        !           428:         if (vring_desc_flags(vq, i) & VRING_DESC_F_WRITE) {
        !           429:             elem->in_addr[elem->in_num] = vring_desc_addr(vq, i);
        !           430:             sg = &elem->in_sg[elem->in_num++];
        !           431:         } else
        !           432:             sg = &elem->out_sg[elem->out_num++];
        !           433: 
        !           434:         /* Grab the first descriptor, and check it's OK. */
        !           435:         sg->iov_len = vring_desc_len(vq, i);
        !           436: 
        !           437: #ifdef VIRTIO_ZERO_COPY
        !           438:         sg->iov_base = virtio_map_gpa(vring_desc_addr(vq, i), sg->iov_len);
        !           439: #else
        !           440:         /* cap individual scatter element size to prevent unbounded allocations
        !           441:            of memory from the guest.  Practically speaking, no virtio driver
        !           442:            will ever pass more than a page in each element.  We set the cap to
        !           443:            be 2MB in case for some reason a large page makes it way into the
        !           444:            sg list.  When we implement a zero copy API, this limitation will
        !           445:            disappear */
        !           446:         if (sg->iov_len > (2 << 20))
        !           447:             sg->iov_len = 2 << 20;
        !           448: 
        !           449:         sg->iov_base = qemu_malloc(sg->iov_len);
        !           450:         if (!(vring_desc_flags(vq, i) & VRING_DESC_F_WRITE)) {
        !           451:             cpu_physical_memory_read(vring_desc_addr(vq, i),
        !           452:                                      sg->iov_base,
        !           453:                                      sg->iov_len);
        !           454:         }
        !           455: #endif
        !           456:         if (sg->iov_base == NULL) {
        !           457:             fprintf(stderr, "Invalid mapping\n");
        !           458:             exit(1);
        !           459:         }
        !           460: 
        !           461:         /* If we've got too many, that implies a descriptor loop. */
        !           462:         if ((elem->in_num + elem->out_num) > vq->vring.num) {
        !           463:             fprintf(stderr, "Looped descriptor");
        !           464:             exit(1);
        !           465:         }
        !           466:     } while ((i = virtqueue_next_desc(vq, i)) != vq->vring.num);
        !           467: 
        !           468:     elem->index = head;
        !           469: 
        !           470:     vq->inuse++;
        !           471: 
        !           472:     return elem->in_num + elem->out_num;
        !           473: }
        !           474: 
        !           475: /* virtio device */
        !           476: 
        !           477: static VirtIODevice *to_virtio_device(PCIDevice *pci_dev)
        !           478: {
        !           479:     return (VirtIODevice *)pci_dev;
        !           480: }
        !           481: 
        !           482: static void virtio_update_irq(VirtIODevice *vdev)
        !           483: {
        !           484:     qemu_set_irq(vdev->pci_dev.irq[0], vdev->isr & 1);
        !           485: }
        !           486: 
        !           487: static void virtio_reset(void *opaque)
        !           488: {
        !           489:     VirtIODevice *vdev = opaque;
        !           490:     int i;
        !           491: 
        !           492:     if (vdev->reset)
        !           493:         vdev->reset(vdev);
        !           494: 
        !           495:     vdev->features = 0;
        !           496:     vdev->queue_sel = 0;
        !           497:     vdev->status = 0;
        !           498:     vdev->isr = 0;
        !           499:     virtio_update_irq(vdev);
        !           500: 
        !           501:     for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
        !           502:         vdev->vq[i].vring.desc = 0;
        !           503:         vdev->vq[i].vring.avail = 0;
        !           504:         vdev->vq[i].vring.used = 0;
        !           505:         vdev->vq[i].last_avail_idx = 0;
        !           506:         vdev->vq[i].pfn = 0;
        !           507:     }
        !           508: }
        !           509: 
        !           510: static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
        !           511: {
        !           512:     VirtIODevice *vdev = to_virtio_device(opaque);
        !           513:     ram_addr_t pa;
        !           514: 
        !           515:     addr -= vdev->addr;
        !           516: 
        !           517:     switch (addr) {
        !           518:     case VIRTIO_PCI_GUEST_FEATURES:
        !           519:         if (vdev->set_features)
        !           520:             vdev->set_features(vdev, val);
        !           521:         vdev->features = val;
        !           522:         break;
        !           523:     case VIRTIO_PCI_QUEUE_PFN:
        !           524:         pa = (ram_addr_t)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
        !           525:         vdev->vq[vdev->queue_sel].pfn = val;
        !           526:         if (pa == 0) {
        !           527:             virtio_reset(vdev);
        !           528:         } else {
        !           529:             virtqueue_init(&vdev->vq[vdev->queue_sel], pa);
        !           530:         }
        !           531:         break;
        !           532:     case VIRTIO_PCI_QUEUE_SEL:
        !           533:         if (val < VIRTIO_PCI_QUEUE_MAX)
        !           534:             vdev->queue_sel = val;
        !           535:         break;
        !           536:     case VIRTIO_PCI_QUEUE_NOTIFY:
        !           537:         if (val < VIRTIO_PCI_QUEUE_MAX && vdev->vq[val].vring.desc)
        !           538:             vdev->vq[val].handle_output(vdev, &vdev->vq[val]);
        !           539:         break;
        !           540:     case VIRTIO_PCI_STATUS:
        !           541:         vdev->status = val & 0xFF;
        !           542:         if (vdev->status == 0)
        !           543:             virtio_reset(vdev);
        !           544:         break;
        !           545:     }
        !           546: }
        !           547: 
        !           548: static uint32_t virtio_ioport_read(void *opaque, uint32_t addr)
        !           549: {
        !           550:     VirtIODevice *vdev = to_virtio_device(opaque);
        !           551:     uint32_t ret = 0xFFFFFFFF;
        !           552: 
        !           553:     addr -= vdev->addr;
        !           554: 
        !           555:     switch (addr) {
        !           556:     case VIRTIO_PCI_HOST_FEATURES:
        !           557:         ret = vdev->get_features(vdev);
        !           558:         ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
        !           559:         break;
        !           560:     case VIRTIO_PCI_GUEST_FEATURES:
        !           561:         ret = vdev->features;
        !           562:         break;
        !           563:     case VIRTIO_PCI_QUEUE_PFN:
        !           564:         ret = vdev->vq[vdev->queue_sel].pfn;
        !           565:         break;
        !           566:     case VIRTIO_PCI_QUEUE_NUM:
        !           567:         ret = vdev->vq[vdev->queue_sel].vring.num;
        !           568:         break;
        !           569:     case VIRTIO_PCI_QUEUE_SEL:
        !           570:         ret = vdev->queue_sel;
        !           571:         break;
        !           572:     case VIRTIO_PCI_STATUS:
        !           573:         ret = vdev->status;
        !           574:         break;
        !           575:     case VIRTIO_PCI_ISR:
        !           576:         /* reading from the ISR also clears it. */
        !           577:         ret = vdev->isr;
        !           578:         vdev->isr = 0;
        !           579:         virtio_update_irq(vdev);
        !           580:         break;
        !           581:     default:
        !           582:         break;
        !           583:     }
        !           584: 
        !           585:     return ret;
        !           586: }
        !           587: 
        !           588: static uint32_t virtio_config_readb(void *opaque, uint32_t addr)
        !           589: {
        !           590:     VirtIODevice *vdev = opaque;
        !           591:     uint8_t val;
        !           592: 
        !           593:     vdev->get_config(vdev, vdev->config);
        !           594: 
        !           595:     addr -= vdev->addr + VIRTIO_PCI_CONFIG;
        !           596:     if (addr > (vdev->config_len - sizeof(val)))
        !           597:         return (uint32_t)-1;
        !           598: 
        !           599:     memcpy(&val, vdev->config + addr, sizeof(val));
        !           600:     return val;
        !           601: }
        !           602: 
        !           603: static uint32_t virtio_config_readw(void *opaque, uint32_t addr)
        !           604: {
        !           605:     VirtIODevice *vdev = opaque;
        !           606:     uint16_t val;
        !           607: 
        !           608:     vdev->get_config(vdev, vdev->config);
        !           609: 
        !           610:     addr -= vdev->addr + VIRTIO_PCI_CONFIG;
        !           611:     if (addr > (vdev->config_len - sizeof(val)))
        !           612:         return (uint32_t)-1;
        !           613: 
        !           614:     memcpy(&val, vdev->config + addr, sizeof(val));
        !           615:     return val;
        !           616: }
        !           617: 
        !           618: static uint32_t virtio_config_readl(void *opaque, uint32_t addr)
        !           619: {
        !           620:     VirtIODevice *vdev = opaque;
        !           621:     uint32_t val;
        !           622: 
        !           623:     vdev->get_config(vdev, vdev->config);
        !           624: 
        !           625:     addr -= vdev->addr + VIRTIO_PCI_CONFIG;
        !           626:     if (addr > (vdev->config_len - sizeof(val)))
        !           627:         return (uint32_t)-1;
        !           628: 
        !           629:     memcpy(&val, vdev->config + addr, sizeof(val));
        !           630:     return val;
        !           631: }
        !           632: 
        !           633: static void virtio_config_writeb(void *opaque, uint32_t addr, uint32_t data)
        !           634: {
        !           635:     VirtIODevice *vdev = opaque;
        !           636:     uint8_t val = data;
        !           637: 
        !           638:     addr -= vdev->addr + VIRTIO_PCI_CONFIG;
        !           639:     if (addr > (vdev->config_len - sizeof(val)))
        !           640:         return;
        !           641: 
        !           642:     memcpy(vdev->config + addr, &val, sizeof(val));
        !           643: 
        !           644:     if (vdev->set_config)
        !           645:         vdev->set_config(vdev, vdev->config);
        !           646: }
        !           647: 
        !           648: static void virtio_config_writew(void *opaque, uint32_t addr, uint32_t data)
        !           649: {
        !           650:     VirtIODevice *vdev = opaque;
        !           651:     uint16_t val = data;
        !           652: 
        !           653:     addr -= vdev->addr + VIRTIO_PCI_CONFIG;
        !           654:     if (addr > (vdev->config_len - sizeof(val)))
        !           655:         return;
        !           656: 
        !           657:     memcpy(vdev->config + addr, &val, sizeof(val));
        !           658: 
        !           659:     if (vdev->set_config)
        !           660:         vdev->set_config(vdev, vdev->config);
        !           661: }
        !           662: 
        !           663: static void virtio_config_writel(void *opaque, uint32_t addr, uint32_t data)
        !           664: {
        !           665:     VirtIODevice *vdev = opaque;
        !           666:     uint32_t val = data;
        !           667: 
        !           668:     addr -= vdev->addr + VIRTIO_PCI_CONFIG;
        !           669:     if (addr > (vdev->config_len - sizeof(val)))
        !           670:         return;
        !           671: 
        !           672:     memcpy(vdev->config + addr, &val, sizeof(val));
        !           673: 
        !           674:     if (vdev->set_config)
        !           675:         vdev->set_config(vdev, vdev->config);
        !           676: }
        !           677: 
        !           678: static void virtio_map(PCIDevice *pci_dev, int region_num,
        !           679:                        uint32_t addr, uint32_t size, int type)
        !           680: {
        !           681:     VirtIODevice *vdev = to_virtio_device(pci_dev);
        !           682:     int i;
        !           683: 
        !           684:     vdev->addr = addr;
        !           685:     for (i = 0; i < 3; i++) {
        !           686:         register_ioport_write(addr, 20, 1 << i, virtio_ioport_write, vdev);
        !           687:         register_ioport_read(addr, 20, 1 << i, virtio_ioport_read, vdev);
        !           688:     }
        !           689: 
        !           690:     if (vdev->config_len) {
        !           691:         register_ioport_write(addr + 20, vdev->config_len, 1,
        !           692:                               virtio_config_writeb, vdev);
        !           693:         register_ioport_write(addr + 20, vdev->config_len, 2,
        !           694:                               virtio_config_writew, vdev);
        !           695:         register_ioport_write(addr + 20, vdev->config_len, 4,
        !           696:                               virtio_config_writel, vdev);
        !           697:         register_ioport_read(addr + 20, vdev->config_len, 1,
        !           698:                              virtio_config_readb, vdev);
        !           699:         register_ioport_read(addr + 20, vdev->config_len, 2,
        !           700:                              virtio_config_readw, vdev);
        !           701:         register_ioport_read(addr + 20, vdev->config_len, 4,
        !           702:                              virtio_config_readl, vdev);
        !           703: 
        !           704:         vdev->get_config(vdev, vdev->config);
        !           705:     }
        !           706: }
        !           707: 
        !           708: VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
        !           709:                             void (*handle_output)(VirtIODevice *, VirtQueue *))
        !           710: {
        !           711:     int i;
        !           712: 
        !           713:     for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
        !           714:         if (vdev->vq[i].vring.num == 0)
        !           715:             break;
        !           716:     }
        !           717: 
        !           718:     if (i == VIRTIO_PCI_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
        !           719:         abort();
        !           720: 
        !           721:     vdev->vq[i].vring.num = queue_size;
        !           722:     vdev->vq[i].handle_output = handle_output;
        !           723: 
        !           724:     return &vdev->vq[i];
        !           725: }
        !           726: 
        !           727: void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
        !           728: {
        !           729:     /* Always notify when queue is empty */
        !           730:     if ((vq->inuse || vring_avail_idx(vq) != vq->last_avail_idx) &&
        !           731:         (vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT))
        !           732:         return;
        !           733: 
        !           734:     vdev->isr |= 0x01;
        !           735:     virtio_update_irq(vdev);
        !           736: }
        !           737: 
        !           738: void virtio_notify_config(VirtIODevice *vdev)
        !           739: {
        !           740:     if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))
        !           741:         return;
        !           742: 
        !           743:     vdev->isr |= 0x03;
        !           744:     virtio_update_irq(vdev);
        !           745: }
        !           746: 
        !           747: void virtio_save(VirtIODevice *vdev, QEMUFile *f)
        !           748: {
        !           749:     int i;
        !           750: 
        !           751:     pci_device_save(&vdev->pci_dev, f);
        !           752: 
        !           753:     qemu_put_be32s(f, &vdev->addr);
        !           754:     qemu_put_8s(f, &vdev->status);
        !           755:     qemu_put_8s(f, &vdev->isr);
        !           756:     qemu_put_be16s(f, &vdev->queue_sel);
        !           757:     qemu_put_be32s(f, &vdev->features);
        !           758:     qemu_put_be32(f, vdev->config_len);
        !           759:     qemu_put_buffer(f, vdev->config, vdev->config_len);
        !           760: 
        !           761:     for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
        !           762:         if (vdev->vq[i].vring.num == 0)
        !           763:             break;
        !           764:     }
        !           765: 
        !           766:     qemu_put_be32(f, i);
        !           767: 
        !           768:     for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
        !           769:         if (vdev->vq[i].vring.num == 0)
        !           770:             break;
        !           771: 
        !           772:         qemu_put_be32(f, vdev->vq[i].vring.num);
        !           773:         qemu_put_be32s(f, &vdev->vq[i].pfn);
        !           774:         qemu_put_be16s(f, &vdev->vq[i].last_avail_idx);
        !           775:     }
        !           776: }
        !           777: 
        !           778: void virtio_load(VirtIODevice *vdev, QEMUFile *f)
        !           779: {
        !           780:     int num, i;
        !           781: 
        !           782:     pci_device_load(&vdev->pci_dev, f);
        !           783: 
        !           784:     qemu_get_be32s(f, &vdev->addr);
        !           785:     qemu_get_8s(f, &vdev->status);
        !           786:     qemu_get_8s(f, &vdev->isr);
        !           787:     qemu_get_be16s(f, &vdev->queue_sel);
        !           788:     qemu_get_be32s(f, &vdev->features);
        !           789:     vdev->config_len = qemu_get_be32(f);
        !           790:     qemu_get_buffer(f, vdev->config, vdev->config_len);
        !           791: 
        !           792:     num = qemu_get_be32(f);
        !           793: 
        !           794:     for (i = 0; i < num; i++) {
        !           795:         vdev->vq[i].vring.num = qemu_get_be32(f);
        !           796:         qemu_get_be32s(f, &vdev->vq[i].pfn);
        !           797:         qemu_get_be16s(f, &vdev->vq[i].last_avail_idx);
        !           798: 
        !           799:         if (vdev->vq[i].pfn) {
        !           800:             target_phys_addr_t pa;
        !           801: 
        !           802:             pa = (ram_addr_t)vdev->vq[i].pfn << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
        !           803:             virtqueue_init(&vdev->vq[i], pa);
        !           804:         }
        !           805:     }
        !           806: 
        !           807:     virtio_update_irq(vdev);
        !           808: }
        !           809: 
        !           810: VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name,
        !           811:                               uint16_t vendor, uint16_t device,
        !           812:                               uint16_t subvendor, uint16_t subdevice,
        !           813:                               uint16_t class_code, uint8_t pif,
        !           814:                               size_t config_size, size_t struct_size)
        !           815: {
        !           816:     VirtIODevice *vdev;
        !           817:     PCIDevice *pci_dev;
        !           818:     uint8_t *config;
        !           819:     uint32_t size;
        !           820: 
        !           821:     pci_dev = pci_register_device(bus, name, struct_size,
        !           822:                                   -1, NULL, NULL);
        !           823:     if (!pci_dev)
        !           824:         return NULL;
        !           825: 
        !           826:     vdev = to_virtio_device(pci_dev);
        !           827: 
        !           828:     vdev->status = 0;
        !           829:     vdev->isr = 0;
        !           830:     vdev->queue_sel = 0;
        !           831:     vdev->vq = qemu_mallocz(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
        !           832: 
        !           833:     config = pci_dev->config;
        !           834:     pci_config_set_vendor_id(config, vendor);
        !           835:     pci_config_set_device_id(config, device);
        !           836: 
        !           837:     config[0x08] = VIRTIO_PCI_ABI_VERSION;
        !           838: 
        !           839:     config[0x09] = pif;
        !           840:     pci_config_set_class(config, class_code);
        !           841:     config[0x0e] = 0x00;
        !           842: 
        !           843:     config[0x2c] = subvendor & 0xFF;
        !           844:     config[0x2d] = (subvendor >> 8) & 0xFF;
        !           845:     config[0x2e] = subdevice & 0xFF;
        !           846:     config[0x2f] = (subdevice >> 8) & 0xFF;
        !           847: 
        !           848:     config[0x3d] = 1;
        !           849: 
        !           850:     vdev->name = name;
        !           851:     vdev->config_len = config_size;
        !           852:     if (vdev->config_len)
        !           853:         vdev->config = qemu_mallocz(config_size);
        !           854:     else
        !           855:         vdev->config = NULL;
        !           856: 
        !           857:     size = 20 + config_size;
        !           858:     if (size & (size-1))
        !           859:         size = 1 << qemu_fls(size);
        !           860: 
        !           861:     pci_register_io_region(pci_dev, 0, size, PCI_ADDRESS_SPACE_IO,
        !           862:                            virtio_map);
        !           863:     qemu_register_reset(virtio_reset, vdev);
        !           864: 
        !           865:     return vdev;
        !           866: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.