]> Git Repo - qemu.git/blob - hw/misc/ivshmem.c
ivshmem: remove useless ivshmem_update_irq() val argument
[qemu.git] / hw / misc / ivshmem.c
1 /*
2  * Inter-VM Shared Memory PCI device.
3  *
4  * Author:
5  *      Cam Macdonell <[email protected]>
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 "qemu/error-report.h"
26 #include "qemu/event_notifier.h"
27 #include "qemu/fifo8.h"
28 #include "sysemu/char.h"
29
30 #include <sys/mman.h>
31 #include <sys/types.h>
32 #include <limits.h>
33
34 #define PCI_VENDOR_ID_IVSHMEM   PCI_VENDOR_ID_REDHAT_QUMRANET
35 #define PCI_DEVICE_ID_IVSHMEM   0x1110
36
37 #define IVSHMEM_MAX_PEERS G_MAXUINT16
38 #define IVSHMEM_IOEVENTFD   0
39 #define IVSHMEM_MSI     1
40
41 #define IVSHMEM_PEER    0
42 #define IVSHMEM_MASTER  1
43
44 #define IVSHMEM_REG_BAR_SIZE 0x100
45
46 //#define DEBUG_IVSHMEM
47 #ifdef DEBUG_IVSHMEM
48 #define IVSHMEM_DPRINTF(fmt, ...)        \
49     do {printf("IVSHMEM: " fmt, ## __VA_ARGS__); } while (0)
50 #else
51 #define IVSHMEM_DPRINTF(fmt, ...)
52 #endif
53
54 #define TYPE_IVSHMEM "ivshmem"
55 #define IVSHMEM(obj) \
56     OBJECT_CHECK(IVShmemState, (obj), TYPE_IVSHMEM)
57
58 typedef struct Peer {
59     int nb_eventfds;
60     EventNotifier *eventfds;
61 } Peer;
62
63 typedef struct EventfdEntry {
64     PCIDevice *pdev;
65     int vector;
66 } EventfdEntry;
67
68 typedef struct IVShmemState {
69     /*< private >*/
70     PCIDevice parent_obj;
71     /*< public >*/
72
73     uint32_t intrmask;
74     uint32_t intrstatus;
75
76     CharDriverState **eventfd_chr;
77     CharDriverState *server_chr;
78     Fifo8 incoming_fifo;
79     MemoryRegion ivshmem_mmio;
80
81     /* We might need to register the BAR before we actually have the memory.
82      * So prepare a container MemoryRegion for the BAR immediately and
83      * add a subregion when we have the memory.
84      */
85     MemoryRegion bar;
86     MemoryRegion ivshmem;
87     uint64_t ivshmem_size; /* size of shared memory region */
88     uint32_t ivshmem_64bit;
89     int shm_fd; /* shared memory file descriptor */
90
91     Peer *peers;
92     int nb_peers; /* how many guests we have space for */
93     int max_peer; /* maximum numbered peer */
94
95     int vm_id;
96     uint32_t vectors;
97     uint32_t features;
98     EventfdEntry *eventfd_table;
99
100     Error *migration_blocker;
101
102     char * shmobj;
103     char * sizearg;
104     char * role;
105     int role_val;   /* scalar to avoid multiple string comparisons */
106 } IVShmemState;
107
108 /* registers for the Inter-VM shared memory device */
109 enum ivshmem_registers {
110     INTRMASK = 0,
111     INTRSTATUS = 4,
112     IVPOSITION = 8,
113     DOORBELL = 12,
114 };
115
116 static inline uint32_t ivshmem_has_feature(IVShmemState *ivs,
117                                                     unsigned int feature) {
118     return (ivs->features & (1 << feature));
119 }
120
121 static inline bool is_power_of_two(uint64_t x) {
122     return (x & (x - 1)) == 0;
123 }
124
125 /* accessing registers - based on rtl8139 */
126 static void ivshmem_update_irq(IVShmemState *s)
127 {
128     PCIDevice *d = PCI_DEVICE(s);
129     int isr;
130     isr = (s->intrstatus & s->intrmask) & 0xffffffff;
131
132     /* don't print ISR resets */
133     if (isr) {
134         IVSHMEM_DPRINTF("Set IRQ to %d (%04x %04x)\n",
135                         isr ? 1 : 0, s->intrstatus, s->intrmask);
136     }
137
138     pci_set_irq(d, (isr != 0));
139 }
140
141 static void ivshmem_IntrMask_write(IVShmemState *s, uint32_t val)
142 {
143     IVSHMEM_DPRINTF("IntrMask write(w) val = 0x%04x\n", val);
144
145     s->intrmask = val;
146
147     ivshmem_update_irq(s);
148 }
149
150 static uint32_t ivshmem_IntrMask_read(IVShmemState *s)
151 {
152     uint32_t ret = s->intrmask;
153
154     IVSHMEM_DPRINTF("intrmask read(w) val = 0x%04x\n", ret);
155
156     return ret;
157 }
158
159 static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val)
160 {
161     IVSHMEM_DPRINTF("IntrStatus write(w) val = 0x%04x\n", val);
162
163     s->intrstatus = val;
164
165     ivshmem_update_irq(s);
166 }
167
168 static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
169 {
170     uint32_t ret = s->intrstatus;
171
172     /* reading ISR clears all interrupts */
173     s->intrstatus = 0;
174
175     ivshmem_update_irq(s);
176
177     return ret;
178 }
179
180 static void ivshmem_io_write(void *opaque, hwaddr addr,
181                              uint64_t val, unsigned size)
182 {
183     IVShmemState *s = opaque;
184
185     uint16_t dest = val >> 16;
186     uint16_t vector = val & 0xff;
187
188     addr &= 0xfc;
189
190     IVSHMEM_DPRINTF("writing to addr " TARGET_FMT_plx "\n", addr);
191     switch (addr)
192     {
193         case INTRMASK:
194             ivshmem_IntrMask_write(s, val);
195             break;
196
197         case INTRSTATUS:
198             ivshmem_IntrStatus_write(s, val);
199             break;
200
201         case DOORBELL:
202             /* check that dest VM ID is reasonable */
203             if (dest > s->max_peer) {
204                 IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
205                 break;
206             }
207
208             /* check doorbell range */
209             if (vector < s->peers[dest].nb_eventfds) {
210                 IVSHMEM_DPRINTF("Notifying VM %d on vector %d\n", dest, vector);
211                 event_notifier_set(&s->peers[dest].eventfds[vector]);
212             }
213             break;
214         default:
215             IVSHMEM_DPRINTF("Invalid VM Doorbell VM %d\n", dest);
216     }
217 }
218
219 static uint64_t ivshmem_io_read(void *opaque, hwaddr addr,
220                                 unsigned size)
221 {
222
223     IVShmemState *s = opaque;
224     uint32_t ret;
225
226     switch (addr)
227     {
228         case INTRMASK:
229             ret = ivshmem_IntrMask_read(s);
230             break;
231
232         case INTRSTATUS:
233             ret = ivshmem_IntrStatus_read(s);
234             break;
235
236         case IVPOSITION:
237             /* return my VM ID if the memory is mapped */
238             if (s->shm_fd > 0) {
239                 ret = s->vm_id;
240             } else {
241                 ret = -1;
242             }
243             break;
244
245         default:
246             IVSHMEM_DPRINTF("why are we reading " TARGET_FMT_plx "\n", addr);
247             ret = 0;
248     }
249
250     return ret;
251 }
252
253 static const MemoryRegionOps ivshmem_mmio_ops = {
254     .read = ivshmem_io_read,
255     .write = ivshmem_io_write,
256     .endianness = DEVICE_NATIVE_ENDIAN,
257     .impl = {
258         .min_access_size = 4,
259         .max_access_size = 4,
260     },
261 };
262
263 static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
264 {
265     IVShmemState *s = opaque;
266
267     ivshmem_IntrStatus_write(s, *buf);
268
269     IVSHMEM_DPRINTF("ivshmem_receive 0x%02x\n", *buf);
270 }
271
272 static int ivshmem_can_receive(void * opaque)
273 {
274     return sizeof(long);
275 }
276
277 static void ivshmem_event(void *opaque, int event)
278 {
279     IVSHMEM_DPRINTF("ivshmem_event %d\n", event);
280 }
281
282 static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
283
284     EventfdEntry *entry = opaque;
285     PCIDevice *pdev = entry->pdev;
286
287     IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, entry->vector);
288     msix_notify(pdev, entry->vector);
289 }
290
291 static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *n,
292                                                   int vector)
293 {
294     /* create a event character device based on the passed eventfd */
295     IVShmemState *s = opaque;
296     CharDriverState * chr;
297     int eventfd = event_notifier_get_fd(n);
298
299     chr = qemu_chr_open_eventfd(eventfd);
300
301     if (chr == NULL) {
302         error_report("creating eventfd for eventfd %d failed", eventfd);
303         return NULL;
304     }
305     qemu_chr_fe_claim_no_fail(chr);
306
307     /* if MSI is supported we need multiple interrupts */
308     if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
309         s->eventfd_table[vector].pdev = PCI_DEVICE(s);
310         s->eventfd_table[vector].vector = vector;
311
312         qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
313                       ivshmem_event, &s->eventfd_table[vector]);
314     } else {
315         qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive,
316                       ivshmem_event, s);
317     }
318
319     return chr;
320
321 }
322
323 static int check_shm_size(IVShmemState *s, int fd, Error **errp)
324 {
325     /* check that the guest isn't going to try and map more memory than the
326      * the object has allocated return -1 to indicate error */
327
328     struct stat buf;
329
330     if (fstat(fd, &buf) < 0) {
331         error_setg(errp, "exiting: fstat on fd %d failed: %s",
332                    fd, strerror(errno));
333         return -1;
334     }
335
336     if (s->ivshmem_size > buf.st_size) {
337         error_setg(errp, "Requested memory size greater"
338                    " than shared object size (%" PRIu64 " > %" PRIu64")",
339                    s->ivshmem_size, (uint64_t)buf.st_size);
340         return -1;
341     } else {
342         return 0;
343     }
344 }
345
346 /* create the shared memory BAR when we are not using the server, so we can
347  * create the BAR and map the memory immediately */
348 static int create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr,
349                                     Error **errp)
350 {
351     void * ptr;
352
353     ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
354     if (ptr == MAP_FAILED) {
355         error_setg_errno(errp, errno, "Failed to mmap shared memory");
356         return -1;
357     }
358
359     s->shm_fd = fd;
360
361     memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s), "ivshmem.bar2",
362                                s->ivshmem_size, ptr);
363     vmstate_register_ram(&s->ivshmem, DEVICE(s));
364     memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
365
366     /* region for shared memory */
367     pci_register_bar(PCI_DEVICE(s), 2, attr, &s->bar);
368
369     return 0;
370 }
371
372 static void ivshmem_add_eventfd(IVShmemState *s, int posn, int i)
373 {
374     memory_region_add_eventfd(&s->ivshmem_mmio,
375                               DOORBELL,
376                               4,
377                               true,
378                               (posn << 16) | i,
379                               &s->peers[posn].eventfds[i]);
380 }
381
382 static void ivshmem_del_eventfd(IVShmemState *s, int posn, int i)
383 {
384     memory_region_del_eventfd(&s->ivshmem_mmio,
385                               DOORBELL,
386                               4,
387                               true,
388                               (posn << 16) | i,
389                               &s->peers[posn].eventfds[i]);
390 }
391
392 static void close_guest_eventfds(IVShmemState *s, int posn)
393 {
394     int i, guest_curr_max;
395
396     if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
397         return;
398     }
399     if (posn < 0 || posn >= s->nb_peers) {
400         return;
401     }
402
403     guest_curr_max = s->peers[posn].nb_eventfds;
404
405     memory_region_transaction_begin();
406     for (i = 0; i < guest_curr_max; i++) {
407         ivshmem_del_eventfd(s, posn, i);
408     }
409     memory_region_transaction_commit();
410     for (i = 0; i < guest_curr_max; i++) {
411         event_notifier_cleanup(&s->peers[posn].eventfds[i]);
412     }
413
414     g_free(s->peers[posn].eventfds);
415     s->peers[posn].nb_eventfds = 0;
416 }
417
418 /* this function increase the dynamic storage need to store data about other
419  * guests */
420 static int resize_peers(IVShmemState *s, int new_min_size)
421 {
422
423     int j, old_size;
424
425     /* limit number of max peers */
426     if (new_min_size <= 0 || new_min_size > IVSHMEM_MAX_PEERS) {
427         return -1;
428     }
429     if (new_min_size <= s->nb_peers) {
430         return 0;
431     }
432
433     old_size = s->nb_peers;
434     s->nb_peers = new_min_size;
435
436     IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
437
438     s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
439
440     for (j = old_size; j < s->nb_peers; j++) {
441         s->peers[j].eventfds = g_new0(EventNotifier, s->vectors);
442         s->peers[j].nb_eventfds = 0;
443     }
444
445     return 0;
446 }
447
448 static bool fifo_update_and_get(IVShmemState *s, const uint8_t *buf, int size,
449                                 void *data, size_t len)
450 {
451     const uint8_t *p;
452     uint32_t num;
453
454     assert(len <= sizeof(long)); /* limitation of the fifo */
455     if (fifo8_is_empty(&s->incoming_fifo) && size == len) {
456         memcpy(data, buf, size);
457         return true;
458     }
459
460     IVSHMEM_DPRINTF("short read of %d bytes\n", size);
461
462     num = MIN(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo));
463     fifo8_push_all(&s->incoming_fifo, buf, num);
464
465     if (fifo8_num_used(&s->incoming_fifo) < len) {
466         assert(num == 0);
467         return false;
468     }
469
470     size -= num;
471     buf += num;
472     p = fifo8_pop_buf(&s->incoming_fifo, len, &num);
473     assert(num == len);
474
475     memcpy(data, p, len);
476
477     if (size > 0) {
478         fifo8_push_all(&s->incoming_fifo, buf, size);
479     }
480
481     return true;
482 }
483
484 static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
485 {
486     IVShmemState *s = opaque;
487     int incoming_fd;
488     int guest_max_eventfd;
489     long incoming_posn;
490     Error *err = NULL;
491
492     if (!fifo_update_and_get(s, buf, size,
493                              &incoming_posn, sizeof(incoming_posn))) {
494         return;
495     }
496
497     if (incoming_posn < -1) {
498         IVSHMEM_DPRINTF("invalid incoming_posn %ld\n", incoming_posn);
499         return;
500     }
501
502     /* pick off s->server_chr->msgfd and store it, posn should accompany msg */
503     incoming_fd = qemu_chr_fe_get_msgfd(s->server_chr);
504     IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, incoming_fd);
505
506     /* make sure we have enough space for this guest */
507     if (incoming_posn >= s->nb_peers) {
508         if (resize_peers(s, incoming_posn + 1) < 0) {
509             error_report("failed to resize peers array");
510             if (incoming_fd != -1) {
511                 close(incoming_fd);
512             }
513             return;
514         }
515     }
516
517     if (incoming_fd == -1) {
518         /* if posn is positive and unseen before then this is our posn*/
519         if (incoming_posn >= 0 && s->vm_id == -1) {
520             /* receive our posn */
521             s->vm_id = incoming_posn;
522             return;
523         } else {
524             /* otherwise an fd == -1 means an existing guest has gone away */
525             IVSHMEM_DPRINTF("posn %ld has gone away\n", incoming_posn);
526             close_guest_eventfds(s, incoming_posn);
527             return;
528         }
529     }
530
531     /* if the position is -1, then it's shared memory region fd */
532     if (incoming_posn == -1) {
533         void * map_ptr;
534
535         s->max_peer = 0;
536
537         if (check_shm_size(s, incoming_fd, &err) == -1) {
538             error_report_err(err);
539             close(incoming_fd);
540             return;
541         }
542
543         /* mmap the region and map into the BAR2 */
544         map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
545                                                             incoming_fd, 0);
546         if (map_ptr == MAP_FAILED) {
547             error_report("Failed to mmap shared memory %s", strerror(errno));
548             close(incoming_fd);
549             return;
550         }
551         memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s),
552                                    "ivshmem.bar2", s->ivshmem_size, map_ptr);
553         vmstate_register_ram(&s->ivshmem, DEVICE(s));
554
555         IVSHMEM_DPRINTF("guest h/w addr = %p, size = %" PRIu64 "\n",
556                         map_ptr, s->ivshmem_size);
557
558         memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
559
560         /* only store the fd if it is successfully mapped */
561         s->shm_fd = incoming_fd;
562
563         return;
564     }
565
566     /* each guest has an array of eventfds, and we keep track of how many
567      * guests for each VM */
568     guest_max_eventfd = s->peers[incoming_posn].nb_eventfds;
569
570     /* this is an eventfd for a particular guest VM */
571     IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
572                     guest_max_eventfd, incoming_fd);
573     event_notifier_init_fd(&s->peers[incoming_posn].eventfds[guest_max_eventfd],
574                            incoming_fd);
575
576     /* increment count for particular guest */
577     s->peers[incoming_posn].nb_eventfds++;
578
579     /* keep track of the maximum VM ID */
580     if (incoming_posn > s->max_peer) {
581         s->max_peer = incoming_posn;
582     }
583
584     if (incoming_posn == s->vm_id) {
585         s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
586                    &s->peers[s->vm_id].eventfds[guest_max_eventfd],
587                    guest_max_eventfd);
588     }
589
590     if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
591         ivshmem_add_eventfd(s, incoming_posn, guest_max_eventfd);
592     }
593 }
594
595 /* Select the MSI-X vectors used by device.
596  * ivshmem maps events to vectors statically, so
597  * we just enable all vectors on init and after reset. */
598 static void ivshmem_use_msix(IVShmemState * s)
599 {
600     PCIDevice *d = PCI_DEVICE(s);
601     int i;
602
603     if (!msix_present(d)) {
604         return;
605     }
606
607     for (i = 0; i < s->vectors; i++) {
608         msix_vector_use(d, i);
609     }
610 }
611
612 static void ivshmem_reset(DeviceState *d)
613 {
614     IVShmemState *s = IVSHMEM(d);
615
616     s->intrstatus = 0;
617     ivshmem_use_msix(s);
618 }
619
620 static uint64_t ivshmem_get_size(IVShmemState * s, Error **errp) {
621
622     uint64_t value;
623     char *ptr;
624
625     value = strtoull(s->sizearg, &ptr, 10);
626     switch (*ptr) {
627         case 0: case 'M': case 'm':
628             value <<= 20;
629             break;
630         case 'G': case 'g':
631             value <<= 30;
632             break;
633         default:
634             error_setg(errp, "invalid ram size: %s", s->sizearg);
635             return 0;
636     }
637
638     /* BARs must be a power of 2 */
639     if (!is_power_of_two(value)) {
640         error_setg(errp, "size must be power of 2");
641         return 0;
642     }
643
644     return value;
645 }
646
647 static int ivshmem_setup_msi(IVShmemState * s)
648 {
649     if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1)) {
650         return -1;
651     }
652
653     IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
654
655     /* allocate QEMU char devices for receiving interrupts */
656     s->eventfd_table = g_malloc0(s->vectors * sizeof(EventfdEntry));
657
658     ivshmem_use_msix(s);
659     return 0;
660 }
661
662 static void ivshmem_save(QEMUFile* f, void *opaque)
663 {
664     IVShmemState *proxy = opaque;
665     PCIDevice *pci_dev = PCI_DEVICE(proxy);
666
667     IVSHMEM_DPRINTF("ivshmem_save\n");
668     pci_device_save(pci_dev, f);
669
670     if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
671         msix_save(pci_dev, f);
672     } else {
673         qemu_put_be32(f, proxy->intrstatus);
674         qemu_put_be32(f, proxy->intrmask);
675     }
676
677 }
678
679 static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
680 {
681     IVSHMEM_DPRINTF("ivshmem_load\n");
682
683     IVShmemState *proxy = opaque;
684     PCIDevice *pci_dev = PCI_DEVICE(proxy);
685     int ret;
686
687     if (version_id > 0) {
688         return -EINVAL;
689     }
690
691     if (proxy->role_val == IVSHMEM_PEER) {
692         error_report("'peer' devices are not migratable");
693         return -EINVAL;
694     }
695
696     ret = pci_device_load(pci_dev, f);
697     if (ret) {
698         return ret;
699     }
700
701     if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
702         msix_load(pci_dev, f);
703         ivshmem_use_msix(proxy);
704     } else {
705         proxy->intrstatus = qemu_get_be32(f);
706         proxy->intrmask = qemu_get_be32(f);
707     }
708
709     return 0;
710 }
711
712 static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address,
713                                  uint32_t val, int len)
714 {
715     pci_default_write_config(pci_dev, address, val, len);
716 }
717
718 static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
719 {
720     IVShmemState *s = IVSHMEM(dev);
721     uint8_t *pci_conf;
722     uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
723         PCI_BASE_ADDRESS_MEM_PREFETCH;
724     Error *local_err = NULL;
725
726     if (s->sizearg == NULL) {
727         s->ivshmem_size = 4 << 20; /* 4 MB default */
728     } else {
729         s->ivshmem_size = ivshmem_get_size(s, &local_err);
730         if (local_err) {
731             error_propagate(errp, local_err);
732             return;
733         }
734     }
735
736     fifo8_create(&s->incoming_fifo, sizeof(long));
737     register_savevm(DEVICE(dev), "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
738                                                                         dev);
739     /* IRQFD requires MSI */
740     if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
741         !ivshmem_has_feature(s, IVSHMEM_MSI)) {
742         error_setg(errp, "ioeventfd/irqfd requires MSI");
743         return;
744     }
745
746     /* check that role is reasonable */
747     if (s->role) {
748         if (strncmp(s->role, "peer", 5) == 0) {
749             s->role_val = IVSHMEM_PEER;
750         } else if (strncmp(s->role, "master", 7) == 0) {
751             s->role_val = IVSHMEM_MASTER;
752         } else {
753             error_setg(errp, "'role' must be 'peer' or 'master'");
754             return;
755         }
756     } else {
757         s->role_val = IVSHMEM_MASTER; /* default */
758     }
759
760     if (s->role_val == IVSHMEM_PEER) {
761         error_setg(&s->migration_blocker,
762                    "Migration is disabled when using feature 'peer mode' in device 'ivshmem'");
763         migrate_add_blocker(s->migration_blocker);
764     }
765
766     pci_conf = dev->config;
767     pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
768
769     pci_config_set_interrupt_pin(pci_conf, 1);
770
771     s->shm_fd = 0;
772
773     memory_region_init_io(&s->ivshmem_mmio, OBJECT(s), &ivshmem_mmio_ops, s,
774                           "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
775
776     /* region for registers*/
777     pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
778                      &s->ivshmem_mmio);
779
780     memory_region_init(&s->bar, OBJECT(s), "ivshmem-bar2-container", s->ivshmem_size);
781     if (s->ivshmem_64bit) {
782         attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
783     }
784
785     if ((s->server_chr != NULL) &&
786                         (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
787         /* if we get a UNIX socket as the parameter we will talk
788          * to the ivshmem server to receive the memory region */
789
790         if (s->shmobj != NULL) {
791             error_setg(errp, "do not specify both 'chardev' "
792                        "and 'shm' with ivshmem");
793             return;
794         }
795
796         IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
797                         s->server_chr->filename);
798
799         if (ivshmem_has_feature(s, IVSHMEM_MSI) &&
800             ivshmem_setup_msi(s)) {
801             error_setg(errp, "msix initialization failed");
802             return;
803         }
804
805         /* we allocate enough space for 16 guests and grow as needed */
806         resize_peers(s, 16);
807         s->vm_id = -1;
808
809         pci_register_bar(dev, 2, attr, &s->bar);
810
811         s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *));
812
813         qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
814                      ivshmem_event, s);
815     } else {
816         /* just map the file immediately, we're not using a server */
817         int fd;
818
819         if (s->shmobj == NULL) {
820             error_setg(errp, "Must specify 'chardev' or 'shm' to ivshmem");
821             return;
822         }
823
824         IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
825
826         /* try opening with O_EXCL and if it succeeds zero the memory
827          * by truncating to 0 */
828         if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL,
829                         S_IRWXU|S_IRWXG|S_IRWXO)) > 0) {
830            /* truncate file to length PCI device's memory */
831             if (ftruncate(fd, s->ivshmem_size) != 0) {
832                 error_report("could not truncate shared file");
833             }
834
835         } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR,
836                         S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
837             error_setg(errp, "could not open shared file");
838             return;
839         }
840
841         if (check_shm_size(s, fd, errp) == -1) {
842             return;
843         }
844
845         create_shared_memory_BAR(s, fd, attr, errp);
846     }
847 }
848
849 static void pci_ivshmem_exit(PCIDevice *dev)
850 {
851     IVShmemState *s = IVSHMEM(dev);
852
853     if (s->migration_blocker) {
854         migrate_del_blocker(s->migration_blocker);
855         error_free(s->migration_blocker);
856     }
857
858     memory_region_del_subregion(&s->bar, &s->ivshmem);
859     vmstate_unregister_ram(&s->ivshmem, DEVICE(dev));
860     unregister_savevm(DEVICE(dev), "ivshmem", s);
861     fifo8_destroy(&s->incoming_fifo);
862 }
863
864 static Property ivshmem_properties[] = {
865     DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
866     DEFINE_PROP_STRING("size", IVShmemState, sizearg),
867     DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
868     DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false),
869     DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
870     DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
871     DEFINE_PROP_STRING("role", IVShmemState, role),
872     DEFINE_PROP_UINT32("use64", IVShmemState, ivshmem_64bit, 1),
873     DEFINE_PROP_END_OF_LIST(),
874 };
875
876 static void ivshmem_class_init(ObjectClass *klass, void *data)
877 {
878     DeviceClass *dc = DEVICE_CLASS(klass);
879     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
880
881     k->realize = pci_ivshmem_realize;
882     k->exit = pci_ivshmem_exit;
883     k->config_write = ivshmem_write_config;
884     k->vendor_id = PCI_VENDOR_ID_IVSHMEM;
885     k->device_id = PCI_DEVICE_ID_IVSHMEM;
886     k->class_id = PCI_CLASS_MEMORY_RAM;
887     dc->reset = ivshmem_reset;
888     dc->props = ivshmem_properties;
889     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
890 }
891
892 static const TypeInfo ivshmem_info = {
893     .name          = TYPE_IVSHMEM,
894     .parent        = TYPE_PCI_DEVICE,
895     .instance_size = sizeof(IVShmemState),
896     .class_init    = ivshmem_class_init,
897 };
898
899 static void ivshmem_register_types(void)
900 {
901     type_register_static(&ivshmem_info);
902 }
903
904 type_init(ivshmem_register_types)
This page took 0.07984 seconds and 4 git commands to generate.