Statistics
| Branch: | Revision:

root / hw / ivshmem.c @ 0d09e41a

History | View | Annotate | Download (22.7 kB)

1
/*
2
 * Inter-VM Shared Memory PCI device.
3
 *
4
 * Author:
5
 *      Cam Macdonell <cam@cs.ualberta.ca>
6
 *
7
 * Based On: cirrus_vga.c
8
 *          Copyright (c) 2004 Fabrice Bellard
9
 *          Copyright (c) 2004 Makoto Suzuki (suzu)
10
 *
11
 *      and rtl8139.c
12
 *          Copyright (c) 2006 Igor Kovalenko
13
 *
14
 * This code is licensed under the GNU GPL v2.
15
 *
16
 * Contributions after 2012-01-13 are licensed under the terms of the
17
 * GNU GPL, version 2 or (at your option) any later version.
18
 */
19
#include "hw/hw.h"
20
#include "hw/i386/pc.h"
21
#include "hw/pci/pci.h"
22
#include "hw/pci/msix.h"
23
#include "sysemu/kvm.h"
24
#include "migration/migration.h"
25
#include "qapi/qmp/qerror.h"
26
#include "qemu/event_notifier.h"
27
#include "char/char.h"
28

    
29
#include <sys/mman.h>
30
#include <sys/types.h>
31

    
32
#define PCI_VENDOR_ID_IVSHMEM   PCI_VENDOR_ID_REDHAT_QUMRANET
33
#define PCI_DEVICE_ID_IVSHMEM   0x1110
34

    
35
#define IVSHMEM_IOEVENTFD   0
36
#define IVSHMEM_MSI     1
37

    
38
#define IVSHMEM_PEER    0
39
#define IVSHMEM_MASTER  1
40

    
41
#define IVSHMEM_REG_BAR_SIZE 0x100
42

    
43
//#define DEBUG_IVSHMEM
44
#ifdef DEBUG_IVSHMEM
45
#define IVSHMEM_DPRINTF(fmt, ...)        \
46
    do {printf("IVSHMEM: " fmt, ## __VA_ARGS__); } while (0)
47
#else
48
#define IVSHMEM_DPRINTF(fmt, ...)
49
#endif
50

    
51
typedef struct Peer {
52
    int nb_eventfds;
53
    EventNotifier *eventfds;
54
} Peer;
55

    
56
typedef struct EventfdEntry {
57
    PCIDevice *pdev;
58
    int vector;
59
} EventfdEntry;
60

    
61
typedef struct IVShmemState {
62
    PCIDevice dev;
63
    uint32_t intrmask;
64
    uint32_t intrstatus;
65
    uint32_t doorbell;
66

    
67
    CharDriverState **eventfd_chr;
68
    CharDriverState *server_chr;
69
    MemoryRegion ivshmem_mmio;
70

    
71
    /* We might need to register the BAR before we actually have the memory.
72
     * So prepare a container MemoryRegion for the BAR immediately and
73
     * add a subregion when we have the memory.
74
     */
75
    MemoryRegion bar;
76
    MemoryRegion ivshmem;
77
    uint64_t ivshmem_size; /* size of shared memory region */
78
    uint32_t ivshmem_attr;
79
    uint32_t ivshmem_64bit;
80
    int shm_fd; /* shared memory file descriptor */
81

    
82
    Peer *peers;
83
    int nb_peers; /* how many guests we have space for */
84
    int max_peer; /* maximum numbered peer */
85

    
86
    int vm_id;
87
    uint32_t vectors;
88
    uint32_t features;
89
    EventfdEntry *eventfd_table;
90

    
91
    Error *migration_blocker;
92

    
93
    char * shmobj;
94
    char * sizearg;
95
    char * role;
96
    int role_val;   /* scalar to avoid multiple string comparisons */
97
} IVShmemState;
98

    
99
/* registers for the Inter-VM shared memory device */
100
enum ivshmem_registers {
101
    INTRMASK = 0,
102
    INTRSTATUS = 4,
103
    IVPOSITION = 8,
104
    DOORBELL = 12,
105
};
106

    
107
static inline uint32_t ivshmem_has_feature(IVShmemState *ivs,
108
                                                    unsigned int feature) {
109
    return (ivs->features & (1 << feature));
110
}
111

    
112
static inline bool is_power_of_two(uint64_t x) {
113
    return (x & (x - 1)) == 0;
114
}
115

    
116
/* accessing registers - based on rtl8139 */
117
static void ivshmem_update_irq(IVShmemState *s, int val)
118
{
119
    int isr;
120
    isr = (s->intrstatus & s->intrmask) & 0xffffffff;
121

    
122
    /* don't print ISR resets */
123
    if (isr) {
124
        IVSHMEM_DPRINTF("Set IRQ to %d (%04x %04x)\n",
125
           isr ? 1 : 0, s->intrstatus, s->intrmask);
126
    }
127

    
128
    qemu_set_irq(s->dev.irq[0], (isr != 0));
129
}
130

    
131
static void ivshmem_IntrMask_write(IVShmemState *s, uint32_t val)
132
{
133
    IVSHMEM_DPRINTF("IntrMask write(w) val = 0x%04x\n", val);
134

    
135
    s->intrmask = val;
136

    
137
    ivshmem_update_irq(s, val);
138
}
139

    
140
static uint32_t ivshmem_IntrMask_read(IVShmemState *s)
141
{
142
    uint32_t ret = s->intrmask;
143

    
144
    IVSHMEM_DPRINTF("intrmask read(w) val = 0x%04x\n", ret);
145

    
146
    return ret;
147
}
148

    
149
static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val)
150
{
151
    IVSHMEM_DPRINTF("IntrStatus write(w) val = 0x%04x\n", val);
152

    
153
    s->intrstatus = val;
154

    
155
    ivshmem_update_irq(s, val);
156
}
157

    
158
static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
159
{
160
    uint32_t ret = s->intrstatus;
161

    
162
    /* reading ISR clears all interrupts */
163
    s->intrstatus = 0;
164

    
165
    ivshmem_update_irq(s, 0);
166

    
167
    return ret;
168
}
169

    
170
static void ivshmem_io_write(void *opaque, hwaddr addr,
171
                             uint64_t val, unsigned size)
172
{
173
    IVShmemState *s = opaque;
174

    
175
    uint16_t dest = val >> 16;
176
    uint16_t vector = val & 0xff;
177

    
178
    addr &= 0xfc;
179

    
180
    IVSHMEM_DPRINTF("writing to addr " TARGET_FMT_plx "\n", addr);
181
    switch (addr)
182
    {
183
        case INTRMASK:
184
            ivshmem_IntrMask_write(s, val);
185
            break;
186

    
187
        case INTRSTATUS:
188
            ivshmem_IntrStatus_write(s, val);
189
            break;
190

    
191
        case DOORBELL:
192
            /* check that dest VM ID is reasonable */
193
            if (dest > s->max_peer) {
194
                IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
195
                break;
196
            }
197

    
198
            /* check doorbell range */
199
            if (vector < s->peers[dest].nb_eventfds) {
200
                IVSHMEM_DPRINTF("Notifying VM %d on vector %d\n", dest, vector);
201
                event_notifier_set(&s->peers[dest].eventfds[vector]);
202
            }
203
            break;
204
        default:
205
            IVSHMEM_DPRINTF("Invalid VM Doorbell VM %d\n", dest);
206
    }
207
}
208

    
209
static uint64_t ivshmem_io_read(void *opaque, hwaddr addr,
210
                                unsigned size)
211
{
212

    
213
    IVShmemState *s = opaque;
214
    uint32_t ret;
215

    
216
    switch (addr)
217
    {
218
        case INTRMASK:
219
            ret = ivshmem_IntrMask_read(s);
220
            break;
221

    
222
        case INTRSTATUS:
223
            ret = ivshmem_IntrStatus_read(s);
224
            break;
225

    
226
        case IVPOSITION:
227
            /* return my VM ID if the memory is mapped */
228
            if (s->shm_fd > 0) {
229
                ret = s->vm_id;
230
            } else {
231
                ret = -1;
232
            }
233
            break;
234

    
235
        default:
236
            IVSHMEM_DPRINTF("why are we reading " TARGET_FMT_plx "\n", addr);
237
            ret = 0;
238
    }
239

    
240
    return ret;
241
}
242

    
243
static const MemoryRegionOps ivshmem_mmio_ops = {
244
    .read = ivshmem_io_read,
245
    .write = ivshmem_io_write,
246
    .endianness = DEVICE_NATIVE_ENDIAN,
247
    .impl = {
248
        .min_access_size = 4,
249
        .max_access_size = 4,
250
    },
251
};
252

    
253
static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
254
{
255
    IVShmemState *s = opaque;
256

    
257
    ivshmem_IntrStatus_write(s, *buf);
258

    
259
    IVSHMEM_DPRINTF("ivshmem_receive 0x%02x\n", *buf);
260
}
261

    
262
static int ivshmem_can_receive(void * opaque)
263
{
264
    return 8;
265
}
266

    
267
static void ivshmem_event(void *opaque, int event)
268
{
269
    IVSHMEM_DPRINTF("ivshmem_event %d\n", event);
270
}
271

    
272
static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
273

    
274
    EventfdEntry *entry = opaque;
275
    PCIDevice *pdev = entry->pdev;
276

    
277
    IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, entry->vector);
278
    msix_notify(pdev, entry->vector);
279
}
280

    
281
static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *n,
282
                                                  int vector)
283
{
284
    /* create a event character device based on the passed eventfd */
285
    IVShmemState *s = opaque;
286
    CharDriverState * chr;
287
    int eventfd = event_notifier_get_fd(n);
288

    
289
    chr = qemu_chr_open_eventfd(eventfd);
290

    
291
    if (chr == NULL) {
292
        fprintf(stderr, "creating eventfd for eventfd %d failed\n", eventfd);
293
        exit(-1);
294
    }
295
    qemu_chr_fe_claim_no_fail(chr);
296

    
297
    /* if MSI is supported we need multiple interrupts */
298
    if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
299
        s->eventfd_table[vector].pdev = &s->dev;
300
        s->eventfd_table[vector].vector = vector;
301

    
302
        qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
303
                      ivshmem_event, &s->eventfd_table[vector]);
304
    } else {
305
        qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive,
306
                      ivshmem_event, s);
307
    }
308

    
309
    return chr;
310

    
311
}
312

    
313
static int check_shm_size(IVShmemState *s, int fd) {
314
    /* check that the guest isn't going to try and map more memory than the
315
     * the object has allocated return -1 to indicate error */
316

    
317
    struct stat buf;
318

    
319
    fstat(fd, &buf);
320

    
321
    if (s->ivshmem_size > buf.st_size) {
322
        fprintf(stderr,
323
                "IVSHMEM ERROR: Requested memory size greater"
324
                " than shared object size (%" PRIu64 " > %" PRIu64")\n",
325
                s->ivshmem_size, (uint64_t)buf.st_size);
326
        return -1;
327
    } else {
328
        return 0;
329
    }
330
}
331

    
332
/* create the shared memory BAR when we are not using the server, so we can
333
 * create the BAR and map the memory immediately */
334
static void create_shared_memory_BAR(IVShmemState *s, int fd) {
335

    
336
    void * ptr;
337

    
338
    s->shm_fd = fd;
339

    
340
    ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
341

    
342
    memory_region_init_ram_ptr(&s->ivshmem, "ivshmem.bar2",
343
                               s->ivshmem_size, ptr);
344
    vmstate_register_ram(&s->ivshmem, &s->dev.qdev);
345
    memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
346

    
347
    /* region for shared memory */
348
    pci_register_bar(&s->dev, 2, s->ivshmem_attr, &s->bar);
349
}
350

    
351
static void ivshmem_add_eventfd(IVShmemState *s, int posn, int i)
352
{
353
    memory_region_add_eventfd(&s->ivshmem_mmio,
354
                              DOORBELL,
355
                              4,
356
                              true,
357
                              (posn << 16) | i,
358
                              &s->peers[posn].eventfds[i]);
359
}
360

    
361
static void ivshmem_del_eventfd(IVShmemState *s, int posn, int i)
362
{
363
    memory_region_del_eventfd(&s->ivshmem_mmio,
364
                              DOORBELL,
365
                              4,
366
                              true,
367
                              (posn << 16) | i,
368
                              &s->peers[posn].eventfds[i]);
369
}
370

    
371
static void close_guest_eventfds(IVShmemState *s, int posn)
372
{
373
    int i, guest_curr_max;
374

    
375
    if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
376
        return;
377
    }
378

    
379
    guest_curr_max = s->peers[posn].nb_eventfds;
380

    
381
    memory_region_transaction_begin();
382
    for (i = 0; i < guest_curr_max; i++) {
383
        ivshmem_del_eventfd(s, posn, i);
384
    }
385
    memory_region_transaction_commit();
386
    for (i = 0; i < guest_curr_max; i++) {
387
        event_notifier_cleanup(&s->peers[posn].eventfds[i]);
388
    }
389

    
390
    g_free(s->peers[posn].eventfds);
391
    s->peers[posn].nb_eventfds = 0;
392
}
393

    
394
/* this function increase the dynamic storage need to store data about other
395
 * guests */
396
static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
397

    
398
    int j, old_nb_alloc;
399

    
400
    old_nb_alloc = s->nb_peers;
401

    
402
    while (new_min_size >= s->nb_peers)
403
        s->nb_peers = s->nb_peers * 2;
404

    
405
    IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
406
    s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
407

    
408
    /* zero out new pointers */
409
    for (j = old_nb_alloc; j < s->nb_peers; j++) {
410
        s->peers[j].eventfds = NULL;
411
        s->peers[j].nb_eventfds = 0;
412
    }
413
}
414

    
415
static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
416
{
417
    IVShmemState *s = opaque;
418
    int incoming_fd, tmp_fd;
419
    int guest_max_eventfd;
420
    long incoming_posn;
421

    
422
    memcpy(&incoming_posn, buf, sizeof(long));
423
    /* pick off s->server_chr->msgfd and store it, posn should accompany msg */
424
    tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr);
425
    IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
426

    
427
    /* make sure we have enough space for this guest */
428
    if (incoming_posn >= s->nb_peers) {
429
        increase_dynamic_storage(s, incoming_posn);
430
    }
431

    
432
    if (tmp_fd == -1) {
433
        /* if posn is positive and unseen before then this is our posn*/
434
        if ((incoming_posn >= 0) &&
435
                            (s->peers[incoming_posn].eventfds == NULL)) {
436
            /* receive our posn */
437
            s->vm_id = incoming_posn;
438
            return;
439
        } else {
440
            /* otherwise an fd == -1 means an existing guest has gone away */
441
            IVSHMEM_DPRINTF("posn %ld has gone away\n", incoming_posn);
442
            close_guest_eventfds(s, incoming_posn);
443
            return;
444
        }
445
    }
446

    
447
    /* because of the implementation of get_msgfd, we need a dup */
448
    incoming_fd = dup(tmp_fd);
449

    
450
    if (incoming_fd == -1) {
451
        fprintf(stderr, "could not allocate file descriptor %s\n",
452
                                                            strerror(errno));
453
        return;
454
    }
455

    
456
    /* if the position is -1, then it's shared memory region fd */
457
    if (incoming_posn == -1) {
458

    
459
        void * map_ptr;
460

    
461
        s->max_peer = 0;
462

    
463
        if (check_shm_size(s, incoming_fd) == -1) {
464
            exit(-1);
465
        }
466

    
467
        /* mmap the region and map into the BAR2 */
468
        map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
469
                                                            incoming_fd, 0);
470
        memory_region_init_ram_ptr(&s->ivshmem,
471
                                   "ivshmem.bar2", s->ivshmem_size, map_ptr);
472
        vmstate_register_ram(&s->ivshmem, &s->dev.qdev);
473

    
474
        IVSHMEM_DPRINTF("guest h/w addr = %" PRIu64 ", size = %" PRIu64 "\n",
475
                         s->ivshmem_offset, s->ivshmem_size);
476

    
477
        memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
478

    
479
        /* only store the fd if it is successfully mapped */
480
        s->shm_fd = incoming_fd;
481

    
482
        return;
483
    }
484

    
485
    /* each guest has an array of eventfds, and we keep track of how many
486
     * guests for each VM */
487
    guest_max_eventfd = s->peers[incoming_posn].nb_eventfds;
488

    
489
    if (guest_max_eventfd == 0) {
490
        /* one eventfd per MSI vector */
491
        s->peers[incoming_posn].eventfds = g_new(EventNotifier, s->vectors);
492
    }
493

    
494
    /* this is an eventfd for a particular guest VM */
495
    IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
496
                                            guest_max_eventfd, incoming_fd);
497
    event_notifier_init_fd(&s->peers[incoming_posn].eventfds[guest_max_eventfd],
498
                           incoming_fd);
499

    
500
    /* increment count for particular guest */
501
    s->peers[incoming_posn].nb_eventfds++;
502

    
503
    /* keep track of the maximum VM ID */
504
    if (incoming_posn > s->max_peer) {
505
        s->max_peer = incoming_posn;
506
    }
507

    
508
    if (incoming_posn == s->vm_id) {
509
        s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
510
                   &s->peers[s->vm_id].eventfds[guest_max_eventfd],
511
                   guest_max_eventfd);
512
    }
513

    
514
    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
515
        ivshmem_add_eventfd(s, incoming_posn, guest_max_eventfd);
516
    }
517
}
518

    
519
/* Select the MSI-X vectors used by device.
520
 * ivshmem maps events to vectors statically, so
521
 * we just enable all vectors on init and after reset. */
522
static void ivshmem_use_msix(IVShmemState * s)
523
{
524
    int i;
525

    
526
    if (!msix_present(&s->dev)) {
527
        return;
528
    }
529

    
530
    for (i = 0; i < s->vectors; i++) {
531
        msix_vector_use(&s->dev, i);
532
    }
533
}
534

    
535
static void ivshmem_reset(DeviceState *d)
536
{
537
    IVShmemState *s = DO_UPCAST(IVShmemState, dev.qdev, d);
538

    
539
    s->intrstatus = 0;
540
    ivshmem_use_msix(s);
541
}
542

    
543
static uint64_t ivshmem_get_size(IVShmemState * s) {
544

    
545
    uint64_t value;
546
    char *ptr;
547

    
548
    value = strtoull(s->sizearg, &ptr, 10);
549
    switch (*ptr) {
550
        case 0: case 'M': case 'm':
551
            value <<= 20;
552
            break;
553
        case 'G': case 'g':
554
            value <<= 30;
555
            break;
556
        default:
557
            fprintf(stderr, "qemu: invalid ram size: %s\n", s->sizearg);
558
            exit(1);
559
    }
560

    
561
    /* BARs must be a power of 2 */
562
    if (!is_power_of_two(value)) {
563
        fprintf(stderr, "ivshmem: size must be power of 2\n");
564
        exit(1);
565
    }
566

    
567
    return value;
568
}
569

    
570
static void ivshmem_setup_msi(IVShmemState * s)
571
{
572
    if (msix_init_exclusive_bar(&s->dev, s->vectors, 1)) {
573
        IVSHMEM_DPRINTF("msix initialization failed\n");
574
        exit(1);
575
    }
576

    
577
    IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
578

    
579
    /* allocate QEMU char devices for receiving interrupts */
580
    s->eventfd_table = g_malloc0(s->vectors * sizeof(EventfdEntry));
581

    
582
    ivshmem_use_msix(s);
583
}
584

    
585
static void ivshmem_save(QEMUFile* f, void *opaque)
586
{
587
    IVShmemState *proxy = opaque;
588

    
589
    IVSHMEM_DPRINTF("ivshmem_save\n");
590
    pci_device_save(&proxy->dev, f);
591

    
592
    if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
593
        msix_save(&proxy->dev, f);
594
    } else {
595
        qemu_put_be32(f, proxy->intrstatus);
596
        qemu_put_be32(f, proxy->intrmask);
597
    }
598

    
599
}
600

    
601
static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
602
{
603
    IVSHMEM_DPRINTF("ivshmem_load\n");
604

    
605
    IVShmemState *proxy = opaque;
606
    int ret;
607

    
608
    if (version_id > 0) {
609
        return -EINVAL;
610
    }
611

    
612
    if (proxy->role_val == IVSHMEM_PEER) {
613
        fprintf(stderr, "ivshmem: 'peer' devices are not migratable\n");
614
        return -EINVAL;
615
    }
616

    
617
    ret = pci_device_load(&proxy->dev, f);
618
    if (ret) {
619
        return ret;
620
    }
621

    
622
    if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
623
        msix_load(&proxy->dev, f);
624
        ivshmem_use_msix(proxy);
625
    } else {
626
        proxy->intrstatus = qemu_get_be32(f);
627
        proxy->intrmask = qemu_get_be32(f);
628
    }
629

    
630
    return 0;
631
}
632

    
633
static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address,
634
                                 uint32_t val, int len)
635
{
636
    pci_default_write_config(pci_dev, address, val, len);
637
    msix_write_config(pci_dev, address, val, len);
638
}
639

    
640
static int pci_ivshmem_init(PCIDevice *dev)
641
{
642
    IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
643
    uint8_t *pci_conf;
644

    
645
    if (s->sizearg == NULL)
646
        s->ivshmem_size = 4 << 20; /* 4 MB default */
647
    else {
648
        s->ivshmem_size = ivshmem_get_size(s);
649
    }
650

    
651
    register_savevm(&s->dev.qdev, "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
652
                                                                        dev);
653

    
654
    /* IRQFD requires MSI */
655
    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
656
        !ivshmem_has_feature(s, IVSHMEM_MSI)) {
657
        fprintf(stderr, "ivshmem: ioeventfd/irqfd requires MSI\n");
658
        exit(1);
659
    }
660

    
661
    /* check that role is reasonable */
662
    if (s->role) {
663
        if (strncmp(s->role, "peer", 5) == 0) {
664
            s->role_val = IVSHMEM_PEER;
665
        } else if (strncmp(s->role, "master", 7) == 0) {
666
            s->role_val = IVSHMEM_MASTER;
667
        } else {
668
            fprintf(stderr, "ivshmem: 'role' must be 'peer' or 'master'\n");
669
            exit(1);
670
        }
671
    } else {
672
        s->role_val = IVSHMEM_MASTER; /* default */
673
    }
674

    
675
    if (s->role_val == IVSHMEM_PEER) {
676
        error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
677
                  "peer mode", "ivshmem");
678
        migrate_add_blocker(s->migration_blocker);
679
    }
680

    
681
    pci_conf = s->dev.config;
682
    pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
683

    
684
    pci_config_set_interrupt_pin(pci_conf, 1);
685

    
686
    s->shm_fd = 0;
687

    
688
    memory_region_init_io(&s->ivshmem_mmio, &ivshmem_mmio_ops, s,
689
                          "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
690

    
691
    /* region for registers*/
692
    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
693
                     &s->ivshmem_mmio);
694

    
695
    memory_region_init(&s->bar, "ivshmem-bar2-container", s->ivshmem_size);
696
    s->ivshmem_attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
697
        PCI_BASE_ADDRESS_MEM_PREFETCH;
698
    if (s->ivshmem_64bit) {
699
        s->ivshmem_attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
700
    }
701

    
702
    if ((s->server_chr != NULL) &&
703
                        (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
704
        /* if we get a UNIX socket as the parameter we will talk
705
         * to the ivshmem server to receive the memory region */
706

    
707
        if (s->shmobj != NULL) {
708
            fprintf(stderr, "WARNING: do not specify both 'chardev' "
709
                                                "and 'shm' with ivshmem\n");
710
        }
711

    
712
        IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
713
                                                    s->server_chr->filename);
714

    
715
        if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
716
            ivshmem_setup_msi(s);
717
        }
718

    
719
        /* we allocate enough space for 16 guests and grow as needed */
720
        s->nb_peers = 16;
721
        s->vm_id = -1;
722

    
723
        /* allocate/initialize space for interrupt handling */
724
        s->peers = g_malloc0(s->nb_peers * sizeof(Peer));
725

    
726
        pci_register_bar(&s->dev, 2, s->ivshmem_attr, &s->bar);
727

    
728
        s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *));
729

    
730
        qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
731
                     ivshmem_event, s);
732
    } else {
733
        /* just map the file immediately, we're not using a server */
734
        int fd;
735

    
736
        if (s->shmobj == NULL) {
737
            fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n");
738
        }
739

    
740
        IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
741

    
742
        /* try opening with O_EXCL and if it succeeds zero the memory
743
         * by truncating to 0 */
744
        if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL,
745
                        S_IRWXU|S_IRWXG|S_IRWXO)) > 0) {
746
           /* truncate file to length PCI device's memory */
747
            if (ftruncate(fd, s->ivshmem_size) != 0) {
748
                fprintf(stderr, "ivshmem: could not truncate shared file\n");
749
            }
750

    
751
        } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR,
752
                        S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
753
            fprintf(stderr, "ivshmem: could not open shared file\n");
754
            exit(-1);
755

    
756
        }
757

    
758
        if (check_shm_size(s, fd) == -1) {
759
            exit(-1);
760
        }
761

    
762
        create_shared_memory_BAR(s, fd);
763

    
764
    }
765

    
766
    s->dev.config_write = ivshmem_write_config;
767

    
768
    return 0;
769
}
770

    
771
static void pci_ivshmem_uninit(PCIDevice *dev)
772
{
773
    IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
774

    
775
    if (s->migration_blocker) {
776
        migrate_del_blocker(s->migration_blocker);
777
        error_free(s->migration_blocker);
778
    }
779

    
780
    memory_region_destroy(&s->ivshmem_mmio);
781
    memory_region_del_subregion(&s->bar, &s->ivshmem);
782
    vmstate_unregister_ram(&s->ivshmem, &s->dev.qdev);
783
    memory_region_destroy(&s->ivshmem);
784
    memory_region_destroy(&s->bar);
785
    unregister_savevm(&dev->qdev, "ivshmem", s);
786
}
787

    
788
static Property ivshmem_properties[] = {
789
    DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
790
    DEFINE_PROP_STRING("size", IVShmemState, sizearg),
791
    DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
792
    DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false),
793
    DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
794
    DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
795
    DEFINE_PROP_STRING("role", IVShmemState, role),
796
    DEFINE_PROP_UINT32("use64", IVShmemState, ivshmem_64bit, 1),
797
    DEFINE_PROP_END_OF_LIST(),
798
};
799

    
800
static void ivshmem_class_init(ObjectClass *klass, void *data)
801
{
802
    DeviceClass *dc = DEVICE_CLASS(klass);
803
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
804

    
805
    k->init = pci_ivshmem_init;
806
    k->exit = pci_ivshmem_uninit;
807
    k->vendor_id = PCI_VENDOR_ID_IVSHMEM;
808
    k->device_id = PCI_DEVICE_ID_IVSHMEM;
809
    k->class_id = PCI_CLASS_MEMORY_RAM;
810
    dc->reset = ivshmem_reset;
811
    dc->props = ivshmem_properties;
812
}
813

    
814
static const TypeInfo ivshmem_info = {
815
    .name          = "ivshmem",
816
    .parent        = TYPE_PCI_DEVICE,
817
    .instance_size = sizeof(IVShmemState),
818
    .class_init    = ivshmem_class_init,
819
};
820

    
821
static void ivshmem_register_types(void)
822
{
823
    type_register_static(&ivshmem_info);
824
}
825

    
826
type_init(ivshmem_register_types)