virtio.c 31.1 KB
Newer Older
A
aliguori 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * 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>

16
#include "trace.h"
17
#include "qemu/error-report.h"
P
Paolo Bonzini 已提交
18
#include "hw/virtio/virtio.h"
19
#include "qemu/atomic.h"
P
Paolo Bonzini 已提交
20
#include "hw/virtio/virtio-bus.h"
A
aliguori 已提交
21

22 23 24 25 26
/*
 * The alignment to use between consumer and producer parts of vring.
 * x86 pagesize again. This is the default, used by transports like PCI
 * which don't provide a means for the guest to tell the host the alignment.
 */
27 28
#define VIRTIO_PCI_VRING_ALIGN         4096

A
aliguori 已提交
29 30 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
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;
60
    unsigned int align;
A
Avi Kivity 已提交
61 62 63
    hwaddr desc;
    hwaddr avail;
    hwaddr used;
A
aliguori 已提交
64 65 66 67 68
} VRing;

struct VirtQueue
{
    VRing vring;
A
Avi Kivity 已提交
69
    hwaddr pa;
A
aliguori 已提交
70
    uint16_t last_avail_idx;
M
Michael S. Tsirkin 已提交
71 72 73 74 75 76 77 78 79
    /* Last used index value we have signalled on */
    uint16_t signalled_used;

    /* Last used index value we have signalled on */
    bool signalled_used_valid;

    /* Notification enabled? */
    bool notification;

80 81
    uint16_t queue_index;

A
aliguori 已提交
82
    int inuse;
M
Michael S. Tsirkin 已提交
83

84
    uint16_t vector;
A
aliguori 已提交
85
    void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
86 87 88
    VirtIODevice *vdev;
    EventNotifier guest_notifier;
    EventNotifier host_notifier;
A
aliguori 已提交
89 90 91
};

/* virt queue functions */
P
Paul Brook 已提交
92
static void virtqueue_init(VirtQueue *vq)
A
aliguori 已提交
93
{
A
Avi Kivity 已提交
94
    hwaddr pa = vq->pa;
P
Paul Brook 已提交
95

A
aliguori 已提交
96 97
    vq->vring.desc = pa;
    vq->vring.avail = pa + vq->vring.num * sizeof(VRingDesc);
98 99
    vq->vring.used = vring_align(vq->vring.avail +
                                 offsetof(VRingAvail, ring[vq->vring.num]),
100
                                 vq->vring.align);
A
aliguori 已提交
101 102
}

A
Avi Kivity 已提交
103
static inline uint64_t vring_desc_addr(hwaddr desc_pa, int i)
A
aliguori 已提交
104
{
A
Avi Kivity 已提交
105
    hwaddr pa;
106
    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr);
A
aliguori 已提交
107 108 109
    return ldq_phys(pa);
}

A
Avi Kivity 已提交
110
static inline uint32_t vring_desc_len(hwaddr desc_pa, int i)
A
aliguori 已提交
111
{
A
Avi Kivity 已提交
112
    hwaddr pa;
113
    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, len);
A
aliguori 已提交
114 115 116
    return ldl_phys(pa);
}

A
Avi Kivity 已提交
117
static inline uint16_t vring_desc_flags(hwaddr desc_pa, int i)
A
aliguori 已提交
118
{
A
Avi Kivity 已提交
119
    hwaddr pa;
120
    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags);
A
aliguori 已提交
121 122 123
    return lduw_phys(pa);
}

A
Avi Kivity 已提交
124
static inline uint16_t vring_desc_next(hwaddr desc_pa, int i)
A
aliguori 已提交
125
{
A
Avi Kivity 已提交
126
    hwaddr pa;
127
    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, next);
A
aliguori 已提交
128 129 130 131 132
    return lduw_phys(pa);
}

static inline uint16_t vring_avail_flags(VirtQueue *vq)
{
A
Avi Kivity 已提交
133
    hwaddr pa;
A
aliguori 已提交
134 135 136 137 138 139
    pa = vq->vring.avail + offsetof(VRingAvail, flags);
    return lduw_phys(pa);
}

static inline uint16_t vring_avail_idx(VirtQueue *vq)
{
A
Avi Kivity 已提交
140
    hwaddr pa;
A
aliguori 已提交
141 142 143 144 145 146
    pa = vq->vring.avail + offsetof(VRingAvail, idx);
    return lduw_phys(pa);
}

static inline uint16_t vring_avail_ring(VirtQueue *vq, int i)
{
A
Avi Kivity 已提交
147
    hwaddr pa;
A
aliguori 已提交
148 149 150 151
    pa = vq->vring.avail + offsetof(VRingAvail, ring[i]);
    return lduw_phys(pa);
}

M
Michael S. Tsirkin 已提交
152 153 154 155 156
static inline uint16_t vring_used_event(VirtQueue *vq)
{
    return vring_avail_ring(vq, vq->vring.num);
}

A
aliguori 已提交
157 158
static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val)
{
A
Avi Kivity 已提交
159
    hwaddr pa;
A
aliguori 已提交
160 161 162 163 164 165
    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
Avi Kivity 已提交
166
    hwaddr pa;
A
aliguori 已提交
167 168 169 170 171 172
    pa = vq->vring.used + offsetof(VRingUsed, ring[i].len);
    stl_phys(pa, val);
}

static uint16_t vring_used_idx(VirtQueue *vq)
{
A
Avi Kivity 已提交
173
    hwaddr pa;
A
aliguori 已提交
174 175 176 177
    pa = vq->vring.used + offsetof(VRingUsed, idx);
    return lduw_phys(pa);
}

M
Michael S. Tsirkin 已提交
178
static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val)
A
aliguori 已提交
179
{
A
Avi Kivity 已提交
180
    hwaddr pa;
A
aliguori 已提交
181
    pa = vq->vring.used + offsetof(VRingUsed, idx);
M
Michael S. Tsirkin 已提交
182
    stw_phys(pa, val);
A
aliguori 已提交
183 184 185 186
}

static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask)
{
A
Avi Kivity 已提交
187
    hwaddr pa;
A
aliguori 已提交
188 189 190 191 192 193
    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
Avi Kivity 已提交
194
    hwaddr pa;
A
aliguori 已提交
195 196 197 198
    pa = vq->vring.used + offsetof(VRingUsed, flags);
    stw_phys(pa, lduw_phys(pa) & ~mask);
}

M
Michael S. Tsirkin 已提交
199 200
static inline void vring_avail_event(VirtQueue *vq, uint16_t val)
{
A
Avi Kivity 已提交
201
    hwaddr pa;
M
Michael S. Tsirkin 已提交
202 203 204 205 206 207 208
    if (!vq->notification) {
        return;
    }
    pa = vq->vring.used + offsetof(VRingUsed, ring[vq->vring.num]);
    stw_phys(pa, val);
}

A
aliguori 已提交
209 210
void virtio_queue_set_notification(VirtQueue *vq, int enable)
{
M
Michael S. Tsirkin 已提交
211 212 213 214
    vq->notification = enable;
    if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
        vring_avail_event(vq, vring_avail_idx(vq));
    } else if (enable) {
A
aliguori 已提交
215
        vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY);
M
Michael S. Tsirkin 已提交
216
    } else {
A
aliguori 已提交
217
        vring_used_flags_set_bit(vq, VRING_USED_F_NO_NOTIFY);
M
Michael S. Tsirkin 已提交
218
    }
219 220 221 222
    if (enable) {
        /* Expose avail event/used flags before caller checks the avail idx. */
        smp_mb();
    }
A
aliguori 已提交
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
}

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;

241 242
    trace_virtqueue_fill(vq, elem, len, idx);

A
aliguori 已提交
243 244 245 246
    offset = 0;
    for (i = 0; i < elem->in_num; i++) {
        size_t size = MIN(len - offset, elem->in_sg[i].iov_len);

247 248 249
        cpu_physical_memory_unmap(elem->in_sg[i].iov_base,
                                  elem->in_sg[i].iov_len,
                                  1, size);
A
aliguori 已提交
250

251
        offset += size;
A
aliguori 已提交
252 253
    }

254 255 256 257 258
    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 已提交
259 260 261 262 263 264 265 266 267
    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)
{
M
Michael S. Tsirkin 已提交
268
    uint16_t old, new;
A
aliguori 已提交
269
    /* Make sure buffer is written before we update index. */
270
    smp_wmb();
271
    trace_virtqueue_flush(vq, count);
M
Michael S. Tsirkin 已提交
272 273 274
    old = vring_used_idx(vq);
    new = old + count;
    vring_used_idx_set(vq, new);
A
aliguori 已提交
275
    vq->inuse -= count;
M
Michael S. Tsirkin 已提交
276 277
    if (unlikely((int16_t)(new - vq->signalled_used) < (uint16_t)(new - old)))
        vq->signalled_used_valid = false;
A
aliguori 已提交
278 279 280 281 282 283 284 285 286 287 288 289 290 291
}

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 已提交
292
    if (num_heads > vq->vring.num) {
293 294
        error_report("Guest moved used index from %u to %u",
                     idx, vring_avail_idx(vq));
A
aliguori 已提交
295 296
        exit(1);
    }
297 298 299 300 301
    /* On success, callers read a descriptor at vq->last_avail_idx.
     * Make sure descriptor read does not bypass avail index read. */
    if (num_heads) {
        smp_rmb();
    }
A
aliguori 已提交
302 303 304 305 306 307 308 309 310 311 312 313 314

    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 已提交
315
    if (head >= vq->vring.num) {
316
        error_report("Guest says index %u is available", head);
A
aliguori 已提交
317 318
        exit(1);
    }
A
aliguori 已提交
319 320 321 322

    return head;
}

A
Avi Kivity 已提交
323
static unsigned virtqueue_next_desc(hwaddr desc_pa,
324
                                    unsigned int i, unsigned int max)
A
aliguori 已提交
325 326 327 328
{
    unsigned int next;

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

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

337
    if (next >= max) {
338
        error_report("Desc next is %u", next);
A
aliguori 已提交
339 340
        exit(1);
    }
A
aliguori 已提交
341 342 343 344

    return next;
}

345
void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
346 347
                               unsigned int *out_bytes,
                               unsigned max_in_bytes, unsigned max_out_bytes)
A
aliguori 已提交
348
{
349
    unsigned int idx;
350
    unsigned int total_bufs, in_total, out_total;
A
aliguori 已提交
351 352 353

    idx = vq->last_avail_idx;

354
    total_bufs = in_total = out_total = 0;
A
aliguori 已提交
355
    while (virtqueue_num_heads(vq, idx)) {
356
        unsigned int max, num_bufs, indirect = 0;
A
Avi Kivity 已提交
357
        hwaddr desc_pa;
A
aliguori 已提交
358 359
        int i;

360 361
        max = vq->vring.num;
        num_bufs = total_bufs;
A
aliguori 已提交
362
        i = virtqueue_get_head(vq, idx++);
363 364 365 366
        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)) {
367
                error_report("Invalid size for indirect buffer table");
368 369 370 371 372
                exit(1);
            }

            /* If we've got too many, that implies a descriptor loop. */
            if (num_bufs >= max) {
373
                error_report("Looped descriptor");
374 375 376 377 378 379 380 381 382 383
                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 已提交
384 385
        do {
            /* If we've got too many, that implies a descriptor loop. */
386
            if (++num_bufs > max) {
387
                error_report("Looped descriptor");
A
aliguori 已提交
388 389
                exit(1);
            }
A
aliguori 已提交
390

391
            if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
392
                in_total += vring_desc_len(desc_pa, i);
A
aliguori 已提交
393
            } else {
394
                out_total += vring_desc_len(desc_pa, i);
A
aliguori 已提交
395
            }
396 397 398
            if (in_total >= max_in_bytes && out_total >= max_out_bytes) {
                goto done;
            }
399
        } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
400 401 402 403 404

        if (!indirect)
            total_bufs = num_bufs;
        else
            total_bufs++;
A
aliguori 已提交
405
    }
406
done:
407 408 409 410 411 412 413
    if (in_bytes) {
        *in_bytes = in_total;
    }
    if (out_bytes) {
        *out_bytes = out_total;
    }
}
A
aliguori 已提交
414

415 416 417 418 419
int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
                          unsigned int out_bytes)
{
    unsigned int in_total, out_total;

420 421
    virtqueue_get_avail_bytes(vq, &in_total, &out_total, in_bytes, out_bytes);
    return in_bytes <= in_total && out_bytes <= out_total;
A
aliguori 已提交
422 423
}

A
Avi Kivity 已提交
424
void virtqueue_map_sg(struct iovec *sg, hwaddr *addr,
K
Kevin Wolf 已提交
425 426 427
    size_t num_sg, int is_write)
{
    unsigned int i;
A
Avi Kivity 已提交
428
    hwaddr len;
K
Kevin Wolf 已提交
429 430 431 432 433

    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) {
434
            error_report("virtio: trying to map MMIO memory");
K
Kevin Wolf 已提交
435 436 437 438 439
            exit(1);
        }
    }
}

A
aliguori 已提交
440 441
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
{
442
    unsigned int i, head, max;
A
Avi Kivity 已提交
443
    hwaddr desc_pa = vq->vring.desc;
A
aliguori 已提交
444 445 446 447 448 449 450

    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;

451 452
    max = vq->vring.num;

A
aliguori 已提交
453
    i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
M
Michael S. Tsirkin 已提交
454 455 456
    if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
        vring_avail_event(vq, vring_avail_idx(vq));
    }
457 458 459

    if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
        if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
460
            error_report("Invalid size for indirect buffer table");
461 462 463 464 465 466 467 468 469
            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 已提交
470
    /* Collect all the descriptors */
A
aliguori 已提交
471 472 473
    do {
        struct iovec *sg;

474
        if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
475 476 477 478
            if (elem->in_num >= ARRAY_SIZE(elem->in_sg)) {
                error_report("Too many write descriptors in indirect table");
                exit(1);
            }
479
            elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i);
A
aliguori 已提交
480
            sg = &elem->in_sg[elem->in_num++];
K
Kevin Wolf 已提交
481
        } else {
482 483 484 485
            if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) {
                error_report("Too many read descriptors in indirect table");
                exit(1);
            }
K
Kevin Wolf 已提交
486
            elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i);
A
aliguori 已提交
487
            sg = &elem->out_sg[elem->out_num++];
K
Kevin Wolf 已提交
488
        }
A
aliguori 已提交
489

490
        sg->iov_len = vring_desc_len(desc_pa, i);
A
aliguori 已提交
491 492

        /* If we've got too many, that implies a descriptor loop. */
493
        if ((elem->in_num + elem->out_num) > max) {
494
            error_report("Looped descriptor");
A
aliguori 已提交
495 496
            exit(1);
        }
497
    } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
A
aliguori 已提交
498

K
Kevin Wolf 已提交
499 500 501 502
    /* 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 已提交
503 504 505 506
    elem->index = head;

    vq->inuse++;

507
    trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num);
A
aliguori 已提交
508 509 510 511
    return elem->in_num + elem->out_num;
}

/* virtio device */
512 513
static void virtio_notify_vector(VirtIODevice *vdev, uint16_t vector)
{
K
KONRAD Frederic 已提交
514 515 516 517 518
    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);

    if (k->notify) {
        k->notify(qbus->parent, vector);
519 520
    }
}
A
aliguori 已提交
521

P
Paul Brook 已提交
522
void virtio_update_irq(VirtIODevice *vdev)
A
aliguori 已提交
523
{
524
    virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
A
aliguori 已提交
525 526
}

527 528
void virtio_set_status(VirtIODevice *vdev, uint8_t val)
{
529
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
530 531
    trace_virtio_set_status(vdev, val);

532 533
    if (k->set_status) {
        k->set_status(vdev, val);
534 535 536 537
    }
    vdev->status = val;
}

P
Paul Brook 已提交
538
void virtio_reset(void *opaque)
A
aliguori 已提交
539 540
{
    VirtIODevice *vdev = opaque;
541
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
A
aliguori 已提交
542 543
    int i;

544 545
    virtio_set_status(vdev, 0);

546 547 548
    if (k->reset) {
        k->reset(vdev);
    }
A
aliguori 已提交
549

550
    vdev->guest_features = 0;
A
aliguori 已提交
551 552 553
    vdev->queue_sel = 0;
    vdev->status = 0;
    vdev->isr = 0;
554 555
    vdev->config_vector = VIRTIO_NO_VECTOR;
    virtio_notify_vector(vdev, vdev->config_vector);
A
aliguori 已提交
556 557 558 559 560 561

    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 已提交
562
        vdev->vq[i].pa = 0;
563
        vdev->vq[i].vector = VIRTIO_NO_VECTOR;
M
Michael S. Tsirkin 已提交
564 565 566
        vdev->vq[i].signalled_used = 0;
        vdev->vq[i].signalled_used_valid = false;
        vdev->vq[i].notification = true;
A
aliguori 已提交
567 568 569
    }
}

P
Paul Brook 已提交
570
uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr)
A
aliguori 已提交
571
{
572
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
A
aliguori 已提交
573 574
    uint8_t val;

575
    if (addr + sizeof(val) > vdev->config_len) {
A
aliguori 已提交
576
        return (uint32_t)-1;
577 578 579
    }

    k->get_config(vdev, vdev->config);
A
aliguori 已提交
580

581
    val = ldub_p(vdev->config + addr);
A
aliguori 已提交
582 583 584
    return val;
}

P
Paul Brook 已提交
585
uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr)
A
aliguori 已提交
586
{
587
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
A
aliguori 已提交
588 589
    uint16_t val;

590
    if (addr + sizeof(val) > vdev->config_len) {
A
aliguori 已提交
591
        return (uint32_t)-1;
592 593 594
    }

    k->get_config(vdev, vdev->config);
A
aliguori 已提交
595

596
    val = lduw_p(vdev->config + addr);
A
aliguori 已提交
597 598 599
    return val;
}

P
Paul Brook 已提交
600
uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr)
A
aliguori 已提交
601
{
602
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
A
aliguori 已提交
603 604
    uint32_t val;

605
    if (addr + sizeof(val) > vdev->config_len) {
A
aliguori 已提交
606
        return (uint32_t)-1;
607 608 609
    }

    k->get_config(vdev, vdev->config);
A
aliguori 已提交
610

611
    val = ldl_p(vdev->config + addr);
A
aliguori 已提交
612 613 614
    return val;
}

P
Paul Brook 已提交
615
void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data)
A
aliguori 已提交
616
{
617
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
A
aliguori 已提交
618 619
    uint8_t val = data;

620
    if (addr + sizeof(val) > vdev->config_len) {
A
aliguori 已提交
621
        return;
622
    }
A
aliguori 已提交
623

624
    stb_p(vdev->config + addr, val);
A
aliguori 已提交
625

626 627 628
    if (k->set_config) {
        k->set_config(vdev, vdev->config);
    }
A
aliguori 已提交
629 630
}

P
Paul Brook 已提交
631
void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data)
A
aliguori 已提交
632
{
633
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
A
aliguori 已提交
634 635
    uint16_t val = data;

636
    if (addr + sizeof(val) > vdev->config_len) {
A
aliguori 已提交
637
        return;
638
    }
A
aliguori 已提交
639

640
    stw_p(vdev->config + addr, val);
A
aliguori 已提交
641

642 643 644
    if (k->set_config) {
        k->set_config(vdev, vdev->config);
    }
A
aliguori 已提交
645 646
}

P
Paul Brook 已提交
647
void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data)
A
aliguori 已提交
648
{
649
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
A
aliguori 已提交
650 651
    uint32_t val = data;

652
    if (addr + sizeof(val) > vdev->config_len) {
A
aliguori 已提交
653
        return;
654
    }
A
aliguori 已提交
655

656
    stl_p(vdev->config + addr, val);
A
aliguori 已提交
657

658 659 660
    if (k->set_config) {
        k->set_config(vdev, vdev->config);
    }
A
aliguori 已提交
661 662
}

A
Avi Kivity 已提交
663
void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr)
A
aliguori 已提交
664
{
665 666
    vdev->vq[n].pa = addr;
    virtqueue_init(&vdev->vq[n]);
P
Paul Brook 已提交
667 668
}

A
Avi Kivity 已提交
669
hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n)
P
Paul Brook 已提交
670 671 672 673
{
    return vdev->vq[n].pa;
}

674 675 676 677 678 679 680 681
void virtio_queue_set_num(VirtIODevice *vdev, int n, int num)
{
    if (num <= VIRTQUEUE_MAX_SIZE) {
        vdev->vq[n].vring.num = num;
        virtqueue_init(&vdev->vq[n]);
    }
}

P
Paul Brook 已提交
682 683 684 685
int virtio_queue_get_num(VirtIODevice *vdev, int n)
{
    return vdev->vq[n].vring.num;
}
A
aliguori 已提交
686

P
Paolo Bonzini 已提交
687 688 689 690 691 692 693
int virtio_queue_get_id(VirtQueue *vq)
{
    VirtIODevice *vdev = vq->vdev;
    assert(vq >= &vdev->vq[0] && vq < &vdev->vq[VIRTIO_PCI_QUEUE_MAX]);
    return vq - &vdev->vq[0];
}

694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
{
    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);

    /* Check that the transport told us it was going to do this
     * (so a buggy transport will immediately assert rather than
     * silently failing to migrate this state)
     */
    assert(k->has_variable_vring_alignment);

    vdev->vq[n].vring.align = align;
    virtqueue_init(&vdev->vq[n]);
}

709 710 711 712 713 714 715 716 717
void virtio_queue_notify_vq(VirtQueue *vq)
{
    if (vq->vring.desc) {
        VirtIODevice *vdev = vq->vdev;
        trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
        vq->handle_output(vdev, vq);
    }
}

P
Paul Brook 已提交
718 719
void virtio_queue_notify(VirtIODevice *vdev, int n)
{
720
    virtio_queue_notify_vq(&vdev->vq[n]);
A
aliguori 已提交
721 722
}

723 724 725 726 727 728 729 730 731 732 733 734
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 已提交
735 736 737 738 739 740 741 742 743 744 745 746 747 748
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;
749
    vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN;
A
aliguori 已提交
750 751 752 753 754
    vdev->vq[i].handle_output = handle_output;

    return &vdev->vq[i];
}

755 756 757 758 759 760 761 762 763
void virtio_del_queue(VirtIODevice *vdev, int n)
{
    if (n < 0 || n >= VIRTIO_PCI_QUEUE_MAX) {
        abort();
    }

    vdev->vq[n].vring.num = 0;
}

764 765
void virtio_irq(VirtQueue *vq)
{
766
    trace_virtio_irq(vq);
767 768 769 770
    vq->vdev->isr |= 0x01;
    virtio_notify_vector(vq->vdev, vq->vector);
}

M
Michael S. Tsirkin 已提交
771 772 773 774
/* Assuming a given event_idx value from the other size, if
 * we have just incremented index from old to new_idx,
 * should we trigger an event? */
static inline int vring_need_event(uint16_t event, uint16_t new, uint16_t old)
A
aliguori 已提交
775
{
M
Michael S. Tsirkin 已提交
776 777 778 779 780 781 782 783 784 785 786 787
	/* Note: Xen has similar logic for notification hold-off
	 * in include/xen/interface/io/ring.h with req_event and req_prod
	 * corresponding to event_idx + 1 and new respectively.
	 * Note also that req_event and req_prod in Xen start at 1,
	 * event indexes in virtio start at 0. */
	return (uint16_t)(new - event - 1) < (uint16_t)(new - old);
}

static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
{
    uint16_t old, new;
    bool v;
788 789
    /* We need to expose used array entries before checking used event. */
    smp_mb();
790
    /* Always notify when queue is empty (when feature acknowledge) */
M
Michael S. Tsirkin 已提交
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
    if (((vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) &&
         !vq->inuse && vring_avail_idx(vq) == vq->last_avail_idx)) {
        return true;
    }

    if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
        return !(vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT);
    }

    v = vq->signalled_used_valid;
    vq->signalled_used_valid = true;
    old = vq->signalled_used;
    new = vq->signalled_used = vring_used_idx(vq);
    return !v || vring_need_event(vring_used_event(vq), new, old);
}

void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
{
    if (!vring_notify(vdev, vq)) {
A
aliguori 已提交
810
        return;
M
Michael S. Tsirkin 已提交
811
    }
A
aliguori 已提交
812

813
    trace_virtio_notify(vdev, vq);
A
aliguori 已提交
814
    vdev->isr |= 0x01;
815
    virtio_notify_vector(vdev, vq->vector);
A
aliguori 已提交
816 817 818 819
}

void virtio_notify_config(VirtIODevice *vdev)
{
820 821 822
    if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))
        return;

A
aliguori 已提交
823
    vdev->isr |= 0x03;
824
    virtio_notify_vector(vdev, vdev->config_vector);
A
aliguori 已提交
825 826 827 828
}

void virtio_save(VirtIODevice *vdev, QEMUFile *f)
{
K
KONRAD Frederic 已提交
829 830
    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
A
aliguori 已提交
831 832
    int i;

K
KONRAD Frederic 已提交
833 834 835
    if (k->save_config) {
        k->save_config(qbus->parent, f);
    }
A
aliguori 已提交
836 837 838 839

    qemu_put_8s(f, &vdev->status);
    qemu_put_8s(f, &vdev->isr);
    qemu_put_be16s(f, &vdev->queue_sel);
840
    qemu_put_be32s(f, &vdev->guest_features);
A
aliguori 已提交
841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
    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);
856 857 858
        if (k->has_variable_vring_alignment) {
            qemu_put_be32(f, vdev->vq[i].vring.align);
        }
P
Paul Brook 已提交
859
        qemu_put_be64(f, vdev->vq[i].pa);
A
aliguori 已提交
860
        qemu_put_be16s(f, &vdev->vq[i].last_avail_idx);
K
KONRAD Frederic 已提交
861 862 863
        if (k->save_queue) {
            k->save_queue(qbus->parent, i, f);
        }
A
aliguori 已提交
864 865 866
    }
}

867 868
int virtio_set_features(VirtIODevice *vdev, uint32_t val)
{
K
KONRAD Frederic 已提交
869 870
    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
    VirtioBusClass *vbusk = VIRTIO_BUS_GET_CLASS(qbus);
871
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
K
KONRAD Frederic 已提交
872
    uint32_t supported_features = vbusk->get_features(qbus->parent);
873 874 875
    bool bad = (val & ~supported_features) != 0;

    val &= supported_features;
876 877
    if (k->set_features) {
        k->set_features(vdev, val);
878 879 880 881 882
    }
    vdev->guest_features = val;
    return bad ? -1 : 0;
}

883
int virtio_load(VirtIODevice *vdev, QEMUFile *f)
A
aliguori 已提交
884
{
885
    int num, i, ret;
886
    uint32_t features;
887
    uint32_t supported_features;
K
KONRAD Frederic 已提交
888 889
    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
A
aliguori 已提交
890

K
KONRAD Frederic 已提交
891 892
    if (k->load_config) {
        ret = k->load_config(qbus->parent, f);
893 894 895
        if (ret)
            return ret;
    }
A
aliguori 已提交
896 897 898 899

    qemu_get_8s(f, &vdev->status);
    qemu_get_8s(f, &vdev->isr);
    qemu_get_be16s(f, &vdev->queue_sel);
900
    qemu_get_be32s(f, &features);
901 902

    if (virtio_set_features(vdev, features) < 0) {
K
KONRAD Frederic 已提交
903
        supported_features = k->get_features(qbus->parent);
904 905
        error_report("Features 0x%x unsupported. Allowed features: 0x%x",
                     features, supported_features);
906 907
        return -1;
    }
A
aliguori 已提交
908 909 910 911 912 913 914
    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);
915 916 917
        if (k->has_variable_vring_alignment) {
            vdev->vq[i].vring.align = qemu_get_be32(f);
        }
P
Paul Brook 已提交
918
        vdev->vq[i].pa = qemu_get_be64(f);
A
aliguori 已提交
919
        qemu_get_be16s(f, &vdev->vq[i].last_avail_idx);
M
Michael S. Tsirkin 已提交
920 921
        vdev->vq[i].signalled_used_valid = false;
        vdev->vq[i].notification = true;
A
aliguori 已提交
922

P
Paul Brook 已提交
923
        if (vdev->vq[i].pa) {
M
Michael S. Tsirkin 已提交
924
            uint16_t nheads;
P
Paul Brook 已提交
925
            virtqueue_init(&vdev->vq[i]);
M
Michael S. Tsirkin 已提交
926 927 928 929
            nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
            /* Check it isn't doing very strange things with descriptor numbers. */
            if (nheads > vdev->vq[i].vring.num) {
                error_report("VQ %d size 0x%x Guest index 0x%x "
930
                             "inconsistent with Host index 0x%x: delta 0x%x",
M
Michael S. Tsirkin 已提交
931 932 933 934 935 936 937
                             i, vdev->vq[i].vring.num,
                             vring_avail_idx(&vdev->vq[i]),
                             vdev->vq[i].last_avail_idx, nheads);
                return -1;
            }
        } else if (vdev->vq[i].last_avail_idx) {
            error_report("VQ %d address 0x0 "
938
                         "inconsistent with Host index 0x%x",
M
Michael S. Tsirkin 已提交
939 940
                         i, vdev->vq[i].last_avail_idx);
                return -1;
941
	}
K
KONRAD Frederic 已提交
942 943
        if (k->load_queue) {
            ret = k->load_queue(qbus->parent, i, f);
944 945
            if (ret)
                return ret;
946
        }
A
aliguori 已提交
947 948
    }

949
    virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
950
    return 0;
A
aliguori 已提交
951 952
}

953
void virtio_cleanup(VirtIODevice *vdev)
954
{
955
    qemu_del_vm_change_state_handler(vdev->vmstate);
956
    g_free(vdev->config);
957
    g_free(vdev->vq);
958 959
}

960
static void virtio_vmstate_change(void *opaque, int running, RunState state)
961 962
{
    VirtIODevice *vdev = opaque;
K
KONRAD Frederic 已提交
963 964
    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
965 966 967 968 969 970 971
    bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK);
    vdev->vm_running = running;

    if (backend_run) {
        virtio_set_status(vdev, vdev->status);
    }

K
KONRAD Frederic 已提交
972 973
    if (k->vmstate_change) {
        k->vmstate_change(qbus->parent, backend_run);
974 975 976 977 978 979 980
    }

    if (!backend_run) {
        virtio_set_status(vdev, vdev->status);
    }
}

981 982
void virtio_init(VirtIODevice *vdev, const char *name,
                 uint16_t device_id, size_t config_size)
A
aliguori 已提交
983
{
984
    int i;
P
Paul Brook 已提交
985
    vdev->device_id = device_id;
A
aliguori 已提交
986 987 988
    vdev->status = 0;
    vdev->isr = 0;
    vdev->queue_sel = 0;
989
    vdev->config_vector = VIRTIO_NO_VECTOR;
990
    vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
991
    vdev->vm_running = runstate_is_running();
992
    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
993
        vdev->vq[i].vector = VIRTIO_NO_VECTOR;
994
        vdev->vq[i].vdev = vdev;
995
        vdev->vq[i].queue_index = i;
996
    }
A
aliguori 已提交
997 998 999

    vdev->name = name;
    vdev->config_len = config_size;
1000
    if (vdev->config_len) {
1001
        vdev->config = g_malloc0(config_size);
1002
    } else {
A
aliguori 已提交
1003
        vdev->config = NULL;
1004 1005 1006 1007
    }
    vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change,
                                                     vdev);
}
A
aliguori 已提交
1008

A
Avi Kivity 已提交
1009
hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
1010 1011 1012 1013
{
    return vdev->vq[n].vring.desc;
}

A
Avi Kivity 已提交
1014
hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n)
1015 1016 1017 1018
{
    return vdev->vq[n].vring.avail;
}

A
Avi Kivity 已提交
1019
hwaddr virtio_queue_get_used_addr(VirtIODevice *vdev, int n)
1020 1021 1022 1023
{
    return vdev->vq[n].vring.used;
}

A
Avi Kivity 已提交
1024
hwaddr virtio_queue_get_ring_addr(VirtIODevice *vdev, int n)
1025 1026 1027 1028
{
    return vdev->vq[n].vring.desc;
}

A
Avi Kivity 已提交
1029
hwaddr virtio_queue_get_desc_size(VirtIODevice *vdev, int n)
1030 1031 1032 1033
{
    return sizeof(VRingDesc) * vdev->vq[n].vring.num;
}

A
Avi Kivity 已提交
1034
hwaddr virtio_queue_get_avail_size(VirtIODevice *vdev, int n)
1035 1036
{
    return offsetof(VRingAvail, ring) +
1037
        sizeof(uint64_t) * vdev->vq[n].vring.num;
1038 1039
}

A
Avi Kivity 已提交
1040
hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n)
1041 1042 1043 1044 1045
{
    return offsetof(VRingUsed, ring) +
        sizeof(VRingUsedElem) * vdev->vq[n].vring.num;
}

A
Avi Kivity 已提交
1046
hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int n)
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
{
    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;
}

1067 1068 1069 1070 1071
uint16_t virtio_get_queue_index(VirtQueue *vq)
{
    return vq->queue_index;
}

1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
static void virtio_queue_guest_notifier_read(EventNotifier *n)
{
    VirtQueue *vq = container_of(n, VirtQueue, guest_notifier);
    if (event_notifier_test_and_clear(n)) {
        virtio_irq(vq);
    }
}

void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
                                                bool with_irqfd)
{
    if (assign && !with_irqfd) {
        event_notifier_set_handler(&vq->guest_notifier,
                                   virtio_queue_guest_notifier_read);
    } else {
        event_notifier_set_handler(&vq->guest_notifier, NULL);
    }
    if (!assign) {
        /* Test and clear notifier before closing it,
         * in case poll callback didn't have time to run. */
        virtio_queue_guest_notifier_read(&vq->guest_notifier);
    }
}

1096 1097 1098 1099
EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq)
{
    return &vq->guest_notifier;
}
1100 1101 1102 1103 1104 1105 1106 1107 1108

static void virtio_queue_host_notifier_read(EventNotifier *n)
{
    VirtQueue *vq = container_of(n, VirtQueue, host_notifier);
    if (event_notifier_test_and_clear(n)) {
        virtio_queue_notify_vq(vq);
    }
}

P
Paolo Bonzini 已提交
1109 1110
void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign,
                                               bool set_handler)
1111
{
P
Paolo Bonzini 已提交
1112
    if (assign && set_handler) {
1113 1114 1115 1116
        event_notifier_set_handler(&vq->host_notifier,
                                   virtio_queue_host_notifier_read);
    } else {
        event_notifier_set_handler(&vq->host_notifier, NULL);
P
Paolo Bonzini 已提交
1117 1118
    }
    if (!assign) {
1119 1120 1121 1122 1123 1124
        /* Test and clear notifier before after disabling event,
         * in case poll callback didn't have time to run. */
        virtio_queue_host_notifier_read(&vq->host_notifier);
    }
}

1125 1126 1127 1128
EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq)
{
    return &vq->host_notifier;
}
1129

1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
void virtio_device_set_child_bus_name(VirtIODevice *vdev, char *bus_name)
{
    if (vdev->bus_name) {
        g_free(vdev->bus_name);
        vdev->bus_name = NULL;
    }

    if (bus_name) {
        vdev->bus_name = g_strdup(bus_name);
    }
}

1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
static int virtio_device_init(DeviceState *qdev)
{
    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(qdev);
    assert(k->init != NULL);
    if (k->init(vdev) < 0) {
        return -1;
    }
    virtio_bus_plug_device(vdev);
    return 0;
}

1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
static int virtio_device_exit(DeviceState *qdev)
{
    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);

    if (vdev->bus_name) {
        g_free(vdev->bus_name);
        vdev->bus_name = NULL;
    }
    return 0;
}

1165 1166 1167 1168 1169
static void virtio_device_class_init(ObjectClass *klass, void *data)
{
    /* Set the default value here. */
    DeviceClass *dc = DEVICE_CLASS(klass);
    dc->init = virtio_device_init;
1170
    dc->exit = virtio_device_exit;
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
    dc->bus_type = TYPE_VIRTIO_BUS;
}

static const TypeInfo virtio_device_info = {
    .name = TYPE_VIRTIO_DEVICE,
    .parent = TYPE_DEVICE,
    .instance_size = sizeof(VirtIODevice),
    .class_init = virtio_device_class_init,
    .abstract = true,
    .class_size = sizeof(VirtioDeviceClass),
};

static void virtio_register_types(void)
{
    type_register_static(&virtio_device_info);
}

type_init(virtio_register_types)