virtio.c 21.1 KB
Newer Older
A
aliguori 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Virtio Support
 *
 * Copyright IBM, Corp. 2007
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 * the COPYING file in the top-level directory.
 *
 */

#include <inttypes.h>

#include "virtio.h"
#include "sysemu.h"

19 20 21 22
/* The alignment to use between consumer and producer parts of vring.
 * x86 pagesize again. */
#define VIRTIO_PCI_VRING_ALIGN         4096

A
aliguori 已提交
23 24 25
/* QEMU doesn't strictly need write barriers since everything runs in
 * lock-step.  We'll leave the calls to wmb() in though to make it obvious for
 * KVM or if kqemu gets SMP support.
26 27
 * In any case, we must prevent the compiler from reordering the code.
 * TODO: we likely need some rmb()/mb() as well.
A
aliguori 已提交
28
 */
29 30

#define wmb() __asm__ __volatile__("": : :"memory")
A
aliguori 已提交
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

typedef struct VRingDesc
{
    uint64_t addr;
    uint32_t len;
    uint16_t flags;
    uint16_t next;
} VRingDesc;

typedef struct VRingAvail
{
    uint16_t flags;
    uint16_t idx;
    uint16_t ring[0];
} VRingAvail;

typedef struct VRingUsedElem
{
    uint32_t id;
    uint32_t len;
} VRingUsedElem;

typedef struct VRingUsed
{
    uint16_t flags;
    uint16_t idx;
    VRingUsedElem ring[0];
} VRingUsed;

typedef struct VRing
{
    unsigned int num;
A
Anthony Liguori 已提交
63 64 65
    target_phys_addr_t desc;
    target_phys_addr_t avail;
    target_phys_addr_t used;
A
aliguori 已提交
66 67 68 69 70
} VRing;

struct VirtQueue
{
    VRing vring;
A
Anthony Liguori 已提交
71
    target_phys_addr_t pa;
A
aliguori 已提交
72 73
    uint16_t last_avail_idx;
    int inuse;
74
    uint16_t vector;
A
aliguori 已提交
75
    void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
76 77 78
    VirtIODevice *vdev;
    EventNotifier guest_notifier;
    EventNotifier host_notifier;
A
aliguori 已提交
79 80 81
};

/* virt queue functions */
P
Paul Brook 已提交
82
static void virtqueue_init(VirtQueue *vq)
A
aliguori 已提交
83
{
A
Anthony Liguori 已提交
84
    target_phys_addr_t pa = vq->pa;
P
Paul Brook 已提交
85

A
aliguori 已提交
86 87
    vq->vring.desc = pa;
    vq->vring.avail = pa + vq->vring.num * sizeof(VRingDesc);
88 89 90
    vq->vring.used = vring_align(vq->vring.avail +
                                 offsetof(VRingAvail, ring[vq->vring.num]),
                                 VIRTIO_PCI_VRING_ALIGN);
A
aliguori 已提交
91 92
}

A
Anthony Liguori 已提交
93
static inline uint64_t vring_desc_addr(target_phys_addr_t desc_pa, int i)
A
aliguori 已提交
94
{
A
Anthony Liguori 已提交
95
    target_phys_addr_t pa;
96
    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr);
A
aliguori 已提交
97 98 99
    return ldq_phys(pa);
}

A
Anthony Liguori 已提交
100
static inline uint32_t vring_desc_len(target_phys_addr_t desc_pa, int i)
A
aliguori 已提交
101
{
A
Anthony Liguori 已提交
102
    target_phys_addr_t pa;
103
    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, len);
A
aliguori 已提交
104 105 106
    return ldl_phys(pa);
}

A
Anthony Liguori 已提交
107
static inline uint16_t vring_desc_flags(target_phys_addr_t desc_pa, int i)
A
aliguori 已提交
108
{
A
Anthony Liguori 已提交
109
    target_phys_addr_t pa;
110
    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags);
A
aliguori 已提交
111 112 113
    return lduw_phys(pa);
}

A
Anthony Liguori 已提交
114
static inline uint16_t vring_desc_next(target_phys_addr_t desc_pa, int i)
A
aliguori 已提交
115
{
A
Anthony Liguori 已提交
116
    target_phys_addr_t pa;
117
    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, next);
A
aliguori 已提交
118 119 120 121 122
    return lduw_phys(pa);
}

static inline uint16_t vring_avail_flags(VirtQueue *vq)
{
A
Anthony Liguori 已提交
123
    target_phys_addr_t pa;
A
aliguori 已提交
124 125 126 127 128 129
    pa = vq->vring.avail + offsetof(VRingAvail, flags);
    return lduw_phys(pa);
}

static inline uint16_t vring_avail_idx(VirtQueue *vq)
{
A
Anthony Liguori 已提交
130
    target_phys_addr_t pa;
A
aliguori 已提交
131 132 133 134 135 136
    pa = vq->vring.avail + offsetof(VRingAvail, idx);
    return lduw_phys(pa);
}

static inline uint16_t vring_avail_ring(VirtQueue *vq, int i)
{
A
Anthony Liguori 已提交
137
    target_phys_addr_t pa;
A
aliguori 已提交
138 139 140 141 142 143
    pa = vq->vring.avail + offsetof(VRingAvail, ring[i]);
    return lduw_phys(pa);
}

static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val)
{
A
Anthony Liguori 已提交
144
    target_phys_addr_t pa;
A
aliguori 已提交
145 146 147 148 149 150
    pa = vq->vring.used + offsetof(VRingUsed, ring[i].id);
    stl_phys(pa, val);
}

static inline void vring_used_ring_len(VirtQueue *vq, int i, uint32_t val)
{
A
Anthony Liguori 已提交
151
    target_phys_addr_t pa;
A
aliguori 已提交
152 153 154 155 156 157
    pa = vq->vring.used + offsetof(VRingUsed, ring[i].len);
    stl_phys(pa, val);
}

static uint16_t vring_used_idx(VirtQueue *vq)
{
A
Anthony Liguori 已提交
158
    target_phys_addr_t pa;
A
aliguori 已提交
159 160 161 162 163 164
    pa = vq->vring.used + offsetof(VRingUsed, idx);
    return lduw_phys(pa);
}

static inline void vring_used_idx_increment(VirtQueue *vq, uint16_t val)
{
A
Anthony Liguori 已提交
165
    target_phys_addr_t pa;
A
aliguori 已提交
166 167 168 169 170 171
    pa = vq->vring.used + offsetof(VRingUsed, idx);
    stw_phys(pa, vring_used_idx(vq) + val);
}

static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask)
{
A
Anthony Liguori 已提交
172
    target_phys_addr_t pa;
A
aliguori 已提交
173 174 175 176 177 178
    pa = vq->vring.used + offsetof(VRingUsed, flags);
    stw_phys(pa, lduw_phys(pa) | mask);
}

static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask)
{
A
Anthony Liguori 已提交
179
    target_phys_addr_t pa;
A
aliguori 已提交
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
    pa = vq->vring.used + offsetof(VRingUsed, flags);
    stw_phys(pa, lduw_phys(pa) & ~mask);
}

void virtio_queue_set_notification(VirtQueue *vq, int enable)
{
    if (enable)
        vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY);
    else
        vring_used_flags_set_bit(vq, VRING_USED_F_NO_NOTIFY);
}

int virtio_queue_ready(VirtQueue *vq)
{
    return vq->vring.avail != 0;
}

int virtio_queue_empty(VirtQueue *vq)
{
    return vring_avail_idx(vq) == vq->last_avail_idx;
}

void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
                    unsigned int len, unsigned int idx)
{
    unsigned int offset;
    int i;

    offset = 0;
    for (i = 0; i < elem->in_num; i++) {
        size_t size = MIN(len - offset, elem->in_sg[i].iov_len);

212 213 214
        cpu_physical_memory_unmap(elem->in_sg[i].iov_base,
                                  elem->in_sg[i].iov_len,
                                  1, size);
A
aliguori 已提交
215

216
        offset += elem->in_sg[i].iov_len;
A
aliguori 已提交
217 218
    }

219 220 221 222 223
    for (i = 0; i < elem->out_num; i++)
        cpu_physical_memory_unmap(elem->out_sg[i].iov_base,
                                  elem->out_sg[i].iov_len,
                                  0, elem->out_sg[i].iov_len);

A
aliguori 已提交
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
    idx = (idx + vring_used_idx(vq)) % vq->vring.num;

    /* Get a pointer to the next entry in the used ring. */
    vring_used_ring_id(vq, idx, elem->index);
    vring_used_ring_len(vq, idx, len);
}

void virtqueue_flush(VirtQueue *vq, unsigned int count)
{
    /* Make sure buffer is written before we update index. */
    wmb();
    vring_used_idx_increment(vq, count);
    vq->inuse -= count;
}

void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
                    unsigned int len)
{
    virtqueue_fill(vq, elem, len, 0);
    virtqueue_flush(vq, 1);
}

static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx)
{
    uint16_t num_heads = vring_avail_idx(vq) - idx;

    /* Check it isn't doing very strange things with descriptor numbers. */
A
aliguori 已提交
251 252 253 254 255
    if (num_heads > vq->vring.num) {
        fprintf(stderr, "Guest moved used index from %u to %u",
                idx, vring_avail_idx(vq));
        exit(1);
    }
A
aliguori 已提交
256 257 258 259 260 261 262 263 264 265 266 267 268

    return num_heads;
}

static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx)
{
    unsigned int head;

    /* Grab the next descriptor number they're advertising, and increment
     * the index we've seen. */
    head = vring_avail_ring(vq, idx % vq->vring.num);

    /* If their number is silly, that's a fatal mistake. */
A
aliguori 已提交
269 270 271 272
    if (head >= vq->vring.num) {
        fprintf(stderr, "Guest says index %u is available", head);
        exit(1);
    }
A
aliguori 已提交
273 274 275 276

    return head;
}

A
Anthony Liguori 已提交
277
static unsigned virtqueue_next_desc(target_phys_addr_t desc_pa,
278
                                    unsigned int i, unsigned int max)
A
aliguori 已提交
279 280 281 282
{
    unsigned int next;

    /* If this descriptor says it doesn't chain, we're done. */
283 284
    if (!(vring_desc_flags(desc_pa, i) & VRING_DESC_F_NEXT))
        return max;
A
aliguori 已提交
285 286

    /* Check they're not leading us off end of descriptors. */
287
    next = vring_desc_next(desc_pa, i);
A
aliguori 已提交
288 289 290
    /* Make sure compiler knows to grab that: we don't want it changing! */
    wmb();

291
    if (next >= max) {
A
aliguori 已提交
292 293 294
        fprintf(stderr, "Desc next is %u", next);
        exit(1);
    }
A
aliguori 已提交
295 296 297 298 299 300

    return next;
}

int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes)
{
301 302
    unsigned int idx;
    int total_bufs, in_total, out_total;
A
aliguori 已提交
303 304 305

    idx = vq->last_avail_idx;

306
    total_bufs = in_total = out_total = 0;
A
aliguori 已提交
307
    while (virtqueue_num_heads(vq, idx)) {
308
        unsigned int max, num_bufs, indirect = 0;
A
Anthony Liguori 已提交
309
        target_phys_addr_t desc_pa;
A
aliguori 已提交
310 311
        int i;

312 313
        max = vq->vring.num;
        num_bufs = total_bufs;
A
aliguori 已提交
314
        i = virtqueue_get_head(vq, idx++);
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
        desc_pa = vq->vring.desc;

        if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
            if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
                fprintf(stderr, "Invalid size for indirect buffer table\n");
                exit(1);
            }

            /* If we've got too many, that implies a descriptor loop. */
            if (num_bufs >= max) {
                fprintf(stderr, "Looped descriptor");
                exit(1);
            }

            /* loop over the indirect descriptor table */
            indirect = 1;
            max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc);
            num_bufs = i = 0;
            desc_pa = vring_desc_addr(desc_pa, i);
        }

A
aliguori 已提交
336 337
        do {
            /* If we've got too many, that implies a descriptor loop. */
338
            if (++num_bufs > max) {
A
aliguori 已提交
339 340 341
                fprintf(stderr, "Looped descriptor");
                exit(1);
            }
A
aliguori 已提交
342

343
            if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
A
aliguori 已提交
344
                if (in_bytes > 0 &&
345
                    (in_total += vring_desc_len(desc_pa, i)) >= in_bytes)
A
aliguori 已提交
346 347 348
                    return 1;
            } else {
                if (out_bytes > 0 &&
349
                    (out_total += vring_desc_len(desc_pa, i)) >= out_bytes)
A
aliguori 已提交
350 351
                    return 1;
            }
352
        } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
353 354 355 356 357

        if (!indirect)
            total_bufs = num_bufs;
        else
            total_bufs++;
A
aliguori 已提交
358 359 360 361 362
    }

    return 0;
}

K
Kevin Wolf 已提交
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr,
    size_t num_sg, int is_write)
{
    unsigned int i;
    target_phys_addr_t len;

    for (i = 0; i < num_sg; i++) {
        len = sg[i].iov_len;
        sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
        if (sg[i].iov_base == NULL || len != sg[i].iov_len) {
            fprintf(stderr, "virtio: trying to map MMIO memory\n");
            exit(1);
        }
    }
}

A
aliguori 已提交
379 380
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
{
381
    unsigned int i, head, max;
A
Anthony Liguori 已提交
382
    target_phys_addr_t desc_pa = vq->vring.desc;
A
aliguori 已提交
383 384 385 386 387 388 389

    if (!virtqueue_num_heads(vq, vq->last_avail_idx))
        return 0;

    /* When we start there are none of either input nor output. */
    elem->out_num = elem->in_num = 0;

390 391
    max = vq->vring.num;

A
aliguori 已提交
392
    i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
393 394 395 396 397 398 399 400 401 402 403 404 405

    if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
        if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
            fprintf(stderr, "Invalid size for indirect buffer table\n");
            exit(1);
        }

        /* loop over the indirect descriptor table */
        max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc);
        desc_pa = vring_desc_addr(desc_pa, i);
        i = 0;
    }

K
Kevin Wolf 已提交
406
    /* Collect all the descriptors */
A
aliguori 已提交
407 408 409
    do {
        struct iovec *sg;

410 411
        if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
            elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i);
A
aliguori 已提交
412
            sg = &elem->in_sg[elem->in_num++];
K
Kevin Wolf 已提交
413 414
        } else {
            elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i);
A
aliguori 已提交
415
            sg = &elem->out_sg[elem->out_num++];
K
Kevin Wolf 已提交
416
        }
A
aliguori 已提交
417

418
        sg->iov_len = vring_desc_len(desc_pa, i);
A
aliguori 已提交
419 420

        /* If we've got too many, that implies a descriptor loop. */
421
        if ((elem->in_num + elem->out_num) > max) {
A
aliguori 已提交
422 423 424
            fprintf(stderr, "Looped descriptor");
            exit(1);
        }
425
    } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
A
aliguori 已提交
426

K
Kevin Wolf 已提交
427 428 429 430
    /* Now map what we have collected */
    virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1);
    virtqueue_map_sg(elem->out_sg, elem->out_addr, elem->out_num, 0);

A
aliguori 已提交
431 432 433 434 435 436 437 438
    elem->index = head;

    vq->inuse++;

    return elem->in_num + elem->out_num;
}

/* virtio device */
439 440 441 442 443 444
static void virtio_notify_vector(VirtIODevice *vdev, uint16_t vector)
{
    if (vdev->binding->notify) {
        vdev->binding->notify(vdev->binding_opaque, vector);
    }
}
A
aliguori 已提交
445

P
Paul Brook 已提交
446
void virtio_update_irq(VirtIODevice *vdev)
A
aliguori 已提交
447
{
448
    virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
A
aliguori 已提交
449 450
}

P
Paul Brook 已提交
451
void virtio_reset(void *opaque)
A
aliguori 已提交
452 453 454 455
{
    VirtIODevice *vdev = opaque;
    int i;

456 457
    virtio_set_status(vdev, 0);

A
aliguori 已提交
458 459 460
    if (vdev->reset)
        vdev->reset(vdev);

461
    vdev->guest_features = 0;
A
aliguori 已提交
462 463 464
    vdev->queue_sel = 0;
    vdev->status = 0;
    vdev->isr = 0;
465 466
    vdev->config_vector = VIRTIO_NO_VECTOR;
    virtio_notify_vector(vdev, vdev->config_vector);
A
aliguori 已提交
467 468 469 470 471 472

    for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
        vdev->vq[i].vring.desc = 0;
        vdev->vq[i].vring.avail = 0;
        vdev->vq[i].vring.used = 0;
        vdev->vq[i].last_avail_idx = 0;
P
Paul Brook 已提交
473
        vdev->vq[i].pa = 0;
474
        vdev->vq[i].vector = VIRTIO_NO_VECTOR;
A
aliguori 已提交
475 476 477
    }
}

P
Paul Brook 已提交
478
uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr)
A
aliguori 已提交
479 480 481 482 483 484 485 486 487 488 489 490
{
    uint8_t val;

    vdev->get_config(vdev, vdev->config);

    if (addr > (vdev->config_len - sizeof(val)))
        return (uint32_t)-1;

    memcpy(&val, vdev->config + addr, sizeof(val));
    return val;
}

P
Paul Brook 已提交
491
uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr)
A
aliguori 已提交
492 493 494 495 496 497 498 499 500 501 502 503
{
    uint16_t val;

    vdev->get_config(vdev, vdev->config);

    if (addr > (vdev->config_len - sizeof(val)))
        return (uint32_t)-1;

    memcpy(&val, vdev->config + addr, sizeof(val));
    return val;
}

P
Paul Brook 已提交
504
uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr)
A
aliguori 已提交
505 506 507 508 509 510 511 512 513 514 515 516
{
    uint32_t val;

    vdev->get_config(vdev, vdev->config);

    if (addr > (vdev->config_len - sizeof(val)))
        return (uint32_t)-1;

    memcpy(&val, vdev->config + addr, sizeof(val));
    return val;
}

P
Paul Brook 已提交
517
void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data)
A
aliguori 已提交
518 519 520 521 522 523 524 525 526 527 528 529
{
    uint8_t val = data;

    if (addr > (vdev->config_len - sizeof(val)))
        return;

    memcpy(vdev->config + addr, &val, sizeof(val));

    if (vdev->set_config)
        vdev->set_config(vdev, vdev->config);
}

P
Paul Brook 已提交
530
void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data)
A
aliguori 已提交
531 532 533 534 535 536 537 538 539 540 541 542
{
    uint16_t val = data;

    if (addr > (vdev->config_len - sizeof(val)))
        return;

    memcpy(vdev->config + addr, &val, sizeof(val));

    if (vdev->set_config)
        vdev->set_config(vdev, vdev->config);
}

P
Paul Brook 已提交
543
void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data)
A
aliguori 已提交
544 545 546 547 548 549 550 551 552 553 554 555
{
    uint32_t val = data;

    if (addr > (vdev->config_len - sizeof(val)))
        return;

    memcpy(vdev->config + addr, &val, sizeof(val));

    if (vdev->set_config)
        vdev->set_config(vdev, vdev->config);
}

A
Anthony Liguori 已提交
556
void virtio_queue_set_addr(VirtIODevice *vdev, int n, target_phys_addr_t addr)
A
aliguori 已提交
557
{
558 559
    vdev->vq[n].pa = addr;
    virtqueue_init(&vdev->vq[n]);
P
Paul Brook 已提交
560 561
}

A
Anthony Liguori 已提交
562
target_phys_addr_t virtio_queue_get_addr(VirtIODevice *vdev, int n)
P
Paul Brook 已提交
563 564 565 566 567 568 569 570
{
    return vdev->vq[n].pa;
}

int virtio_queue_get_num(VirtIODevice *vdev, int n)
{
    return vdev->vq[n].vring.num;
}
A
aliguori 已提交
571

P
Paul Brook 已提交
572 573 574 575
void virtio_queue_notify(VirtIODevice *vdev, int n)
{
    if (n < VIRTIO_PCI_QUEUE_MAX && vdev->vq[n].vring.desc) {
        vdev->vq[n].handle_output(vdev, &vdev->vq[n]);
A
aliguori 已提交
576 577 578
    }
}

579 580 581 582 583 584 585 586 587 588 589 590
uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
{
    return n < VIRTIO_PCI_QUEUE_MAX ? vdev->vq[n].vector :
        VIRTIO_NO_VECTOR;
}

void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector)
{
    if (n < VIRTIO_PCI_QUEUE_MAX)
        vdev->vq[n].vector = vector;
}

A
aliguori 已提交
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
                            void (*handle_output)(VirtIODevice *, VirtQueue *))
{
    int i;

    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
        if (vdev->vq[i].vring.num == 0)
            break;
    }

    if (i == VIRTIO_PCI_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
        abort();

    vdev->vq[i].vring.num = queue_size;
    vdev->vq[i].handle_output = handle_output;

    return &vdev->vq[i];
}

610 611 612 613 614 615
void virtio_irq(VirtQueue *vq)
{
    vq->vdev->isr |= 0x01;
    virtio_notify_vector(vq->vdev, vq->vector);
}

A
aliguori 已提交
616 617
void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
{
618 619
    /* Always notify when queue is empty (when feature acknowledge) */
    if ((vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT) &&
620
        (!(vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) ||
621
         (vq->inuse || vring_avail_idx(vq) != vq->last_avail_idx)))
A
aliguori 已提交
622 623 624
        return;

    vdev->isr |= 0x01;
625
    virtio_notify_vector(vdev, vq->vector);
A
aliguori 已提交
626 627 628 629
}

void virtio_notify_config(VirtIODevice *vdev)
{
630 631 632
    if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))
        return;

A
aliguori 已提交
633
    vdev->isr |= 0x03;
634
    virtio_notify_vector(vdev, vdev->config_vector);
A
aliguori 已提交
635 636 637 638 639 640
}

void virtio_save(VirtIODevice *vdev, QEMUFile *f)
{
    int i;

641 642
    if (vdev->binding->save_config)
        vdev->binding->save_config(vdev->binding_opaque, f);
A
aliguori 已提交
643 644 645 646

    qemu_put_8s(f, &vdev->status);
    qemu_put_8s(f, &vdev->isr);
    qemu_put_be16s(f, &vdev->queue_sel);
647
    qemu_put_be32s(f, &vdev->guest_features);
A
aliguori 已提交
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
    qemu_put_be32(f, vdev->config_len);
    qemu_put_buffer(f, vdev->config, vdev->config_len);

    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
        if (vdev->vq[i].vring.num == 0)
            break;
    }

    qemu_put_be32(f, i);

    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
        if (vdev->vq[i].vring.num == 0)
            break;

        qemu_put_be32(f, vdev->vq[i].vring.num);
P
Paul Brook 已提交
663
        qemu_put_be64(f, vdev->vq[i].pa);
A
aliguori 已提交
664
        qemu_put_be16s(f, &vdev->vq[i].last_avail_idx);
665 666
        if (vdev->binding->save_queue)
            vdev->binding->save_queue(vdev->binding_opaque, i, f);
A
aliguori 已提交
667 668 669
    }
}

670
int virtio_load(VirtIODevice *vdev, QEMUFile *f)
A
aliguori 已提交
671
{
672
    int num, i, ret;
673
    uint32_t features;
674
    uint32_t supported_features =
675
        vdev->binding->get_features(vdev->binding_opaque);
A
aliguori 已提交
676

677 678 679 680 681
    if (vdev->binding->load_config) {
        ret = vdev->binding->load_config(vdev->binding_opaque, f);
        if (ret)
            return ret;
    }
A
aliguori 已提交
682 683 684 685

    qemu_get_8s(f, &vdev->status);
    qemu_get_8s(f, &vdev->isr);
    qemu_get_be16s(f, &vdev->queue_sel);
686 687 688 689 690 691
    qemu_get_be32s(f, &features);
    if (features & ~supported_features) {
        fprintf(stderr, "Features 0x%x unsupported. Allowed features: 0x%x\n",
                features, supported_features);
        return -1;
    }
692 693
    if (vdev->set_features)
        vdev->set_features(vdev, features);
694
    vdev->guest_features = features;
A
aliguori 已提交
695 696 697 698 699 700 701
    vdev->config_len = qemu_get_be32(f);
    qemu_get_buffer(f, vdev->config, vdev->config_len);

    num = qemu_get_be32(f);

    for (i = 0; i < num; i++) {
        vdev->vq[i].vring.num = qemu_get_be32(f);
P
Paul Brook 已提交
702
        vdev->vq[i].pa = qemu_get_be64(f);
A
aliguori 已提交
703 704
        qemu_get_be16s(f, &vdev->vq[i].last_avail_idx);

P
Paul Brook 已提交
705 706
        if (vdev->vq[i].pa) {
            virtqueue_init(&vdev->vq[i]);
A
aliguori 已提交
707
        }
708 709 710 711
        if (vdev->binding->load_queue) {
            ret = vdev->binding->load_queue(vdev->binding_opaque, i, f);
            if (ret)
                return ret;
712
        }
A
aliguori 已提交
713 714
    }

715
    virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
716
    return 0;
A
aliguori 已提交
717 718
}

719 720 721 722 723 724 725
void virtio_cleanup(VirtIODevice *vdev)
{
    if (vdev->config)
        qemu_free(vdev->config);
    qemu_free(vdev->vq);
}

P
Paul Brook 已提交
726 727
VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
                                 size_t config_size, size_t struct_size)
A
aliguori 已提交
728 729
{
    VirtIODevice *vdev;
730
    int i;
A
aliguori 已提交
731

P
Paul Brook 已提交
732
    vdev = qemu_mallocz(struct_size);
A
aliguori 已提交
733

P
Paul Brook 已提交
734
    vdev->device_id = device_id;
A
aliguori 已提交
735 736 737
    vdev->status = 0;
    vdev->isr = 0;
    vdev->queue_sel = 0;
738
    vdev->config_vector = VIRTIO_NO_VECTOR;
A
aliguori 已提交
739
    vdev->vq = qemu_mallocz(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
740
    for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
741
        vdev->vq[i].vector = VIRTIO_NO_VECTOR;
742 743
        vdev->vq[i].vdev = vdev;
    }
A
aliguori 已提交
744 745 746 747 748 749 750 751 752 753

    vdev->name = name;
    vdev->config_len = config_size;
    if (vdev->config_len)
        vdev->config = qemu_mallocz(config_size);
    else
        vdev->config = NULL;

    return vdev;
}
P
Paul Brook 已提交
754 755 756 757 758 759 760

void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
                        void *opaque)
{
    vdev->binding = binding;
    vdev->binding_opaque = opaque;
}
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789

target_phys_addr_t virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
{
    return vdev->vq[n].vring.desc;
}

target_phys_addr_t virtio_queue_get_avail_addr(VirtIODevice *vdev, int n)
{
    return vdev->vq[n].vring.avail;
}

target_phys_addr_t virtio_queue_get_used_addr(VirtIODevice *vdev, int n)
{
    return vdev->vq[n].vring.used;
}

target_phys_addr_t virtio_queue_get_ring_addr(VirtIODevice *vdev, int n)
{
    return vdev->vq[n].vring.desc;
}

target_phys_addr_t virtio_queue_get_desc_size(VirtIODevice *vdev, int n)
{
    return sizeof(VRingDesc) * vdev->vq[n].vring.num;
}

target_phys_addr_t virtio_queue_get_avail_size(VirtIODevice *vdev, int n)
{
    return offsetof(VRingAvail, ring) +
790
        sizeof(uint64_t) * vdev->vq[n].vring.num;
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
}

target_phys_addr_t virtio_queue_get_used_size(VirtIODevice *vdev, int n)
{
    return offsetof(VRingUsed, ring) +
        sizeof(VRingUsedElem) * vdev->vq[n].vring.num;
}

target_phys_addr_t virtio_queue_get_ring_size(VirtIODevice *vdev, int n)
{
    return vdev->vq[n].vring.used - vdev->vq[n].vring.desc +
	    virtio_queue_get_used_size(vdev, n);
}

uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n)
{
    return vdev->vq[n].last_avail_idx;
}

void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx)
{
    vdev->vq[n].last_avail_idx = idx;
}

VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n)
{
    return vdev->vq + n;
}

EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq)
{
    return &vq->guest_notifier;
}
EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq)
{
    return &vq->host_notifier;
}