|
|
1.1 root 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: #include "hw.h"
17: #include "pc.h"
18: #include "pci.h"
19: #include "msix.h"
20: #include "kvm.h"
21:
22: #include <sys/mman.h>
23: #include <sys/types.h>
24:
25: #define IVSHMEM_IOEVENTFD 0
26: #define IVSHMEM_MSI 1
27:
28: #define IVSHMEM_PEER 0
29: #define IVSHMEM_MASTER 1
30:
31: #define IVSHMEM_REG_BAR_SIZE 0x100
32:
33: //#define DEBUG_IVSHMEM
34: #ifdef DEBUG_IVSHMEM
35: #define IVSHMEM_DPRINTF(fmt, ...) \
36: do {printf("IVSHMEM: " fmt, ## __VA_ARGS__); } while (0)
37: #else
38: #define IVSHMEM_DPRINTF(fmt, ...)
39: #endif
40:
41: typedef struct Peer {
42: int nb_eventfds;
43: int *eventfds;
44: } Peer;
45:
46: typedef struct EventfdEntry {
47: PCIDevice *pdev;
48: int vector;
49: } EventfdEntry;
50:
51: typedef struct IVShmemState {
52: PCIDevice dev;
53: uint32_t intrmask;
54: uint32_t intrstatus;
55: uint32_t doorbell;
56:
57: CharDriverState **eventfd_chr;
58: CharDriverState *server_chr;
59: int ivshmem_mmio_io_addr;
60:
61: pcibus_t mmio_addr;
62: pcibus_t shm_pci_addr;
63: uint64_t ivshmem_offset;
64: uint64_t ivshmem_size; /* size of shared memory region */
65: int shm_fd; /* shared memory file descriptor */
66:
67: Peer *peers;
68: int nb_peers; /* how many guests we have space for */
69: int max_peer; /* maximum numbered peer */
70:
71: int vm_id;
72: uint32_t vectors;
73: uint32_t features;
74: EventfdEntry *eventfd_table;
75:
76: char * shmobj;
77: char * sizearg;
78: char * role;
79: int role_val; /* scalar to avoid multiple string comparisons */
80: } IVShmemState;
81:
82: /* registers for the Inter-VM shared memory device */
83: enum ivshmem_registers {
84: INTRMASK = 0,
85: INTRSTATUS = 4,
86: IVPOSITION = 8,
87: DOORBELL = 12,
88: };
89:
90: static inline uint32_t ivshmem_has_feature(IVShmemState *ivs,
91: unsigned int feature) {
92: return (ivs->features & (1 << feature));
93: }
94:
95: static inline bool is_power_of_two(uint64_t x) {
96: return (x & (x - 1)) == 0;
97: }
98:
99: static void ivshmem_map(PCIDevice *pci_dev, int region_num,
100: pcibus_t addr, pcibus_t size, int type)
101: {
102: IVShmemState *s = DO_UPCAST(IVShmemState, dev, pci_dev);
103:
104: s->shm_pci_addr = addr;
105:
106: if (s->ivshmem_offset > 0) {
107: cpu_register_physical_memory(s->shm_pci_addr, s->ivshmem_size,
108: s->ivshmem_offset);
109: }
110:
111: IVSHMEM_DPRINTF("guest pci addr = %" FMT_PCIBUS ", guest h/w addr = %"
112: PRIu64 ", size = %" FMT_PCIBUS "\n", addr, s->ivshmem_offset, size);
113:
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: return;
157: }
158:
159: static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
160: {
161: uint32_t ret = s->intrstatus;
162:
163: /* reading ISR clears all interrupts */
164: s->intrstatus = 0;
165:
166: ivshmem_update_irq(s, 0);
167:
168: return ret;
169: }
170:
171: static void ivshmem_io_writew(void *opaque, target_phys_addr_t addr,
172: uint32_t val)
173: {
174:
175: IVSHMEM_DPRINTF("We shouldn't be writing words\n");
176: }
177:
178: static void ivshmem_io_writel(void *opaque, target_phys_addr_t addr,
179: uint32_t val)
180: {
181: IVShmemState *s = opaque;
182:
183: uint64_t write_one = 1;
184: uint16_t dest = val >> 16;
185: uint16_t vector = val & 0xff;
186:
187: addr &= 0xfc;
188:
189: IVSHMEM_DPRINTF("writing to addr " TARGET_FMT_plx "\n", addr);
190: switch (addr)
191: {
192: case INTRMASK:
193: ivshmem_IntrMask_write(s, val);
194: break;
195:
196: case INTRSTATUS:
197: ivshmem_IntrStatus_write(s, val);
198: break;
199:
200: case DOORBELL:
201: /* check that dest VM ID is reasonable */
202: if (dest > s->max_peer) {
203: IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
204: break;
205: }
206:
207: /* check doorbell range */
208: if (vector < s->peers[dest].nb_eventfds) {
209: IVSHMEM_DPRINTF("Writing %" PRId64 " to VM %d on vector %d\n",
210: write_one, dest, vector);
211: if (write(s->peers[dest].eventfds[vector],
212: &(write_one), 8) != 8) {
213: IVSHMEM_DPRINTF("error writing to eventfd\n");
214: }
215: }
216: break;
217: default:
218: IVSHMEM_DPRINTF("Invalid VM Doorbell VM %d\n", dest);
219: }
220: }
221:
222: static void ivshmem_io_writeb(void *opaque, target_phys_addr_t addr,
223: uint32_t val)
224: {
225: IVSHMEM_DPRINTF("We shouldn't be writing bytes\n");
226: }
227:
228: static uint32_t ivshmem_io_readw(void *opaque, target_phys_addr_t addr)
229: {
230:
231: IVSHMEM_DPRINTF("We shouldn't be reading words\n");
232: return 0;
233: }
234:
235: static uint32_t ivshmem_io_readl(void *opaque, target_phys_addr_t addr)
236: {
237:
238: IVShmemState *s = opaque;
239: uint32_t ret;
240:
241: switch (addr)
242: {
243: case INTRMASK:
244: ret = ivshmem_IntrMask_read(s);
245: break;
246:
247: case INTRSTATUS:
248: ret = ivshmem_IntrStatus_read(s);
249: break;
250:
251: case IVPOSITION:
252: /* return my VM ID if the memory is mapped */
253: if (s->shm_fd > 0) {
254: ret = s->vm_id;
255: } else {
256: ret = -1;
257: }
258: break;
259:
260: default:
261: IVSHMEM_DPRINTF("why are we reading " TARGET_FMT_plx "\n", addr);
262: ret = 0;
263: }
264:
265: return ret;
266: }
267:
268: static uint32_t ivshmem_io_readb(void *opaque, target_phys_addr_t addr)
269: {
270: IVSHMEM_DPRINTF("We shouldn't be reading bytes\n");
271:
272: return 0;
273: }
274:
275: static CPUReadMemoryFunc * const ivshmem_mmio_read[3] = {
276: ivshmem_io_readb,
277: ivshmem_io_readw,
278: ivshmem_io_readl,
279: };
280:
281: static CPUWriteMemoryFunc * const ivshmem_mmio_write[3] = {
282: ivshmem_io_writeb,
283: ivshmem_io_writew,
284: ivshmem_io_writel,
285: };
286:
287: static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
288: {
289: IVShmemState *s = opaque;
290:
291: ivshmem_IntrStatus_write(s, *buf);
292:
293: IVSHMEM_DPRINTF("ivshmem_receive 0x%02x\n", *buf);
294: }
295:
296: static int ivshmem_can_receive(void * opaque)
297: {
298: return 8;
299: }
300:
301: static void ivshmem_event(void *opaque, int event)
302: {
303: IVSHMEM_DPRINTF("ivshmem_event %d\n", event);
304: }
305:
306: static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
307:
308: EventfdEntry *entry = opaque;
309: PCIDevice *pdev = entry->pdev;
310:
311: IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, entry->vector);
312: msix_notify(pdev, entry->vector);
313: }
314:
315: static CharDriverState* create_eventfd_chr_device(void * opaque, int eventfd,
316: int vector)
317: {
318: /* create a event character device based on the passed eventfd */
319: IVShmemState *s = opaque;
320: CharDriverState * chr;
321:
322: chr = qemu_chr_open_eventfd(eventfd);
323:
324: if (chr == NULL) {
325: fprintf(stderr, "creating eventfd for eventfd %d failed\n", eventfd);
326: exit(-1);
327: }
328:
329: /* if MSI is supported we need multiple interrupts */
330: if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
331: s->eventfd_table[vector].pdev = &s->dev;
332: s->eventfd_table[vector].vector = vector;
333:
334: qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
335: ivshmem_event, &s->eventfd_table[vector]);
336: } else {
337: qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive,
338: ivshmem_event, s);
339: }
340:
341: return chr;
342:
343: }
344:
345: static int check_shm_size(IVShmemState *s, int fd) {
346: /* check that the guest isn't going to try and map more memory than the
347: * the object has allocated return -1 to indicate error */
348:
349: struct stat buf;
350:
351: fstat(fd, &buf);
352:
353: if (s->ivshmem_size > buf.st_size) {
354: fprintf(stderr,
355: "IVSHMEM ERROR: Requested memory size greater"
356: " than shared object size (%" PRIu64 " > %" PRIu64")\n",
357: s->ivshmem_size, (uint64_t)buf.st_size);
358: return -1;
359: } else {
360: return 0;
361: }
362: }
363:
364: /* create the shared memory BAR when we are not using the server, so we can
365: * create the BAR and map the memory immediately */
366: static void create_shared_memory_BAR(IVShmemState *s, int fd) {
367:
368: void * ptr;
369:
370: s->shm_fd = fd;
371:
372: ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
373:
374: s->ivshmem_offset = qemu_ram_alloc_from_ptr(&s->dev.qdev, "ivshmem.bar2",
375: s->ivshmem_size, ptr);
376:
377: /* region for shared memory */
378: pci_register_bar(&s->dev, 2, s->ivshmem_size,
379: PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map);
380: }
381:
382: static void close_guest_eventfds(IVShmemState *s, int posn)
383: {
384: int i, guest_curr_max;
385:
386: guest_curr_max = s->peers[posn].nb_eventfds;
387:
388: for (i = 0; i < guest_curr_max; i++) {
389: kvm_set_ioeventfd_mmio_long(s->peers[posn].eventfds[i],
390: s->mmio_addr + DOORBELL, (posn << 16) | i, 0);
391: close(s->peers[posn].eventfds[i]);
392: }
393:
394: qemu_free(s->peers[posn].eventfds);
395: s->peers[posn].nb_eventfds = 0;
396: }
397:
398: static void setup_ioeventfds(IVShmemState *s) {
399:
400: int i, j;
401:
402: for (i = 0; i <= s->max_peer; i++) {
403: for (j = 0; j < s->peers[i].nb_eventfds; j++) {
404: kvm_set_ioeventfd_mmio_long(s->peers[i].eventfds[j],
405: s->mmio_addr + DOORBELL, (i << 16) | j, 1);
406: }
407: }
408: }
409:
410: /* this function increase the dynamic storage need to store data about other
411: * guests */
412: static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
413:
414: int j, old_nb_alloc;
415:
416: old_nb_alloc = s->nb_peers;
417:
418: while (new_min_size >= s->nb_peers)
419: s->nb_peers = s->nb_peers * 2;
420:
421: IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
422: s->peers = qemu_realloc(s->peers, s->nb_peers * sizeof(Peer));
423:
424: /* zero out new pointers */
425: for (j = old_nb_alloc; j < s->nb_peers; j++) {
426: s->peers[j].eventfds = NULL;
427: s->peers[j].nb_eventfds = 0;
428: }
429: }
430:
431: static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
432: {
433: IVShmemState *s = opaque;
434: int incoming_fd, tmp_fd;
435: int guest_max_eventfd;
436: long incoming_posn;
437:
438: memcpy(&incoming_posn, buf, sizeof(long));
439: /* pick off s->server_chr->msgfd and store it, posn should accompany msg */
440: tmp_fd = qemu_chr_get_msgfd(s->server_chr);
441: IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
442:
443: /* make sure we have enough space for this guest */
444: if (incoming_posn >= s->nb_peers) {
445: increase_dynamic_storage(s, incoming_posn);
446: }
447:
448: if (tmp_fd == -1) {
449: /* if posn is positive and unseen before then this is our posn*/
450: if ((incoming_posn >= 0) &&
451: (s->peers[incoming_posn].eventfds == NULL)) {
452: /* receive our posn */
453: s->vm_id = incoming_posn;
454: return;
455: } else {
456: /* otherwise an fd == -1 means an existing guest has gone away */
457: IVSHMEM_DPRINTF("posn %ld has gone away\n", incoming_posn);
458: close_guest_eventfds(s, incoming_posn);
459: return;
460: }
461: }
462:
463: /* because of the implementation of get_msgfd, we need a dup */
464: incoming_fd = dup(tmp_fd);
465:
466: if (incoming_fd == -1) {
467: fprintf(stderr, "could not allocate file descriptor %s\n",
468: strerror(errno));
469: return;
470: }
471:
472: /* if the position is -1, then it's shared memory region fd */
473: if (incoming_posn == -1) {
474:
475: void * map_ptr;
476:
477: s->max_peer = 0;
478:
479: if (check_shm_size(s, incoming_fd) == -1) {
480: exit(-1);
481: }
482:
483: /* mmap the region and map into the BAR2 */
484: map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
485: incoming_fd, 0);
486: s->ivshmem_offset = qemu_ram_alloc_from_ptr(&s->dev.qdev,
487: "ivshmem.bar2", s->ivshmem_size, map_ptr);
488:
489: IVSHMEM_DPRINTF("guest pci addr = %" FMT_PCIBUS ", guest h/w addr = %"
490: PRIu64 ", size = %" PRIu64 "\n", s->shm_pci_addr,
491: s->ivshmem_offset, s->ivshmem_size);
492:
493: if (s->shm_pci_addr > 0) {
494: /* map memory into BAR2 */
495: cpu_register_physical_memory(s->shm_pci_addr, s->ivshmem_size,
496: s->ivshmem_offset);
497: }
498:
499: /* only store the fd if it is successfully mapped */
500: s->shm_fd = incoming_fd;
501:
502: return;
503: }
504:
505: /* each guest has an array of eventfds, and we keep track of how many
506: * guests for each VM */
507: guest_max_eventfd = s->peers[incoming_posn].nb_eventfds;
508:
509: if (guest_max_eventfd == 0) {
510: /* one eventfd per MSI vector */
511: s->peers[incoming_posn].eventfds = (int *) qemu_malloc(s->vectors *
512: sizeof(int));
513: }
514:
515: /* this is an eventfd for a particular guest VM */
516: IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
517: guest_max_eventfd, incoming_fd);
518: s->peers[incoming_posn].eventfds[guest_max_eventfd] = incoming_fd;
519:
520: /* increment count for particular guest */
521: s->peers[incoming_posn].nb_eventfds++;
522:
523: /* keep track of the maximum VM ID */
524: if (incoming_posn > s->max_peer) {
525: s->max_peer = incoming_posn;
526: }
527:
528: if (incoming_posn == s->vm_id) {
529: s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
530: s->peers[s->vm_id].eventfds[guest_max_eventfd],
531: guest_max_eventfd);
532: }
533:
534: if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
535: if (kvm_set_ioeventfd_mmio_long(incoming_fd, s->mmio_addr + DOORBELL,
536: (incoming_posn << 16) | guest_max_eventfd, 1) < 0) {
537: fprintf(stderr, "ivshmem: ioeventfd not available\n");
538: }
539: }
540:
541: return;
542: }
543:
544: static void ivshmem_reset(DeviceState *d)
545: {
546: IVShmemState *s = DO_UPCAST(IVShmemState, dev.qdev, d);
547:
548: s->intrstatus = 0;
549: return;
550: }
551:
552: static void ivshmem_mmio_map(PCIDevice *pci_dev, int region_num,
553: pcibus_t addr, pcibus_t size, int type)
554: {
555: IVShmemState *s = DO_UPCAST(IVShmemState, dev, pci_dev);
556:
557: s->mmio_addr = addr;
558: cpu_register_physical_memory(addr + 0, IVSHMEM_REG_BAR_SIZE,
559: s->ivshmem_mmio_io_addr);
560:
561: if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
562: setup_ioeventfds(s);
563: }
564: }
565:
566: static uint64_t ivshmem_get_size(IVShmemState * s) {
567:
568: uint64_t value;
569: char *ptr;
570:
571: value = strtoull(s->sizearg, &ptr, 10);
572: switch (*ptr) {
573: case 0: case 'M': case 'm':
574: value <<= 20;
575: break;
576: case 'G': case 'g':
577: value <<= 30;
578: break;
579: default:
580: fprintf(stderr, "qemu: invalid ram size: %s\n", s->sizearg);
581: exit(1);
582: }
583:
584: /* BARs must be a power of 2 */
585: if (!is_power_of_two(value)) {
586: fprintf(stderr, "ivshmem: size must be power of 2\n");
587: exit(1);
588: }
589:
590: return value;
591: }
592:
593: static void ivshmem_setup_msi(IVShmemState * s) {
594:
595: int i;
596:
597: /* allocate the MSI-X vectors */
598:
599: if (!msix_init(&s->dev, s->vectors, 1, 0)) {
600: pci_register_bar(&s->dev, 1,
601: msix_bar_size(&s->dev),
602: PCI_BASE_ADDRESS_SPACE_MEMORY,
603: msix_mmio_map);
604: IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
605: } else {
606: IVSHMEM_DPRINTF("msix initialization failed\n");
607: exit(1);
608: }
609:
610: /* 'activate' the vectors */
611: for (i = 0; i < s->vectors; i++) {
612: msix_vector_use(&s->dev, i);
613: }
614:
615: /* allocate Qemu char devices for receiving interrupts */
616: s->eventfd_table = qemu_mallocz(s->vectors * sizeof(EventfdEntry));
617: }
618:
619: static void ivshmem_save(QEMUFile* f, void *opaque)
620: {
621: IVShmemState *proxy = opaque;
622:
623: IVSHMEM_DPRINTF("ivshmem_save\n");
624: pci_device_save(&proxy->dev, f);
625:
626: if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
627: msix_save(&proxy->dev, f);
628: } else {
629: qemu_put_be32(f, proxy->intrstatus);
630: qemu_put_be32(f, proxy->intrmask);
631: }
632:
633: }
634:
635: static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
636: {
637: IVSHMEM_DPRINTF("ivshmem_load\n");
638:
639: IVShmemState *proxy = opaque;
640: int ret, i;
641:
642: if (version_id > 0) {
643: return -EINVAL;
644: }
645:
646: if (proxy->role_val == IVSHMEM_PEER) {
647: fprintf(stderr, "ivshmem: 'peer' devices are not migratable\n");
648: return -EINVAL;
649: }
650:
651: ret = pci_device_load(&proxy->dev, f);
652: if (ret) {
653: return ret;
654: }
655:
656: if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
657: msix_load(&proxy->dev, f);
658: for (i = 0; i < proxy->vectors; i++) {
659: msix_vector_use(&proxy->dev, i);
660: }
661: } else {
662: proxy->intrstatus = qemu_get_be32(f);
663: proxy->intrmask = qemu_get_be32(f);
664: }
665:
666: return 0;
667: }
668:
669: static int pci_ivshmem_init(PCIDevice *dev)
670: {
671: IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
672: uint8_t *pci_conf;
673:
674: if (s->sizearg == NULL)
675: s->ivshmem_size = 4 << 20; /* 4 MB default */
676: else {
677: s->ivshmem_size = ivshmem_get_size(s);
678: }
679:
680: register_savevm(&s->dev.qdev, "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
681: dev);
682:
683: /* IRQFD requires MSI */
684: if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
685: !ivshmem_has_feature(s, IVSHMEM_MSI)) {
686: fprintf(stderr, "ivshmem: ioeventfd/irqfd requires MSI\n");
687: exit(1);
688: }
689:
690: /* check that role is reasonable */
691: if (s->role) {
692: if (strncmp(s->role, "peer", 5) == 0) {
693: s->role_val = IVSHMEM_PEER;
694: } else if (strncmp(s->role, "master", 7) == 0) {
695: s->role_val = IVSHMEM_MASTER;
696: } else {
697: fprintf(stderr, "ivshmem: 'role' must be 'peer' or 'master'\n");
698: exit(1);
699: }
700: } else {
701: s->role_val = IVSHMEM_MASTER; /* default */
702: }
703:
704: if (s->role_val == IVSHMEM_PEER) {
705: register_device_unmigratable(&s->dev.qdev, "ivshmem", s);
706: }
707:
708: pci_conf = s->dev.config;
709: pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REDHAT_QUMRANET);
710: pci_conf[0x02] = 0x10;
711: pci_conf[0x03] = 0x11;
712: pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
713: pci_config_set_class(pci_conf, PCI_CLASS_MEMORY_RAM);
714: pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
715:
716: pci_config_set_interrupt_pin(pci_conf, 1);
717:
718: s->shm_pci_addr = 0;
719: s->ivshmem_offset = 0;
720: s->shm_fd = 0;
721:
722: s->ivshmem_mmio_io_addr = cpu_register_io_memory(ivshmem_mmio_read,
1.1.1.2 ! root 723: ivshmem_mmio_write, s, DEVICE_NATIVE_ENDIAN);
1.1 root 724: /* region for registers*/
725: pci_register_bar(&s->dev, 0, IVSHMEM_REG_BAR_SIZE,
726: PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_mmio_map);
727:
728: if ((s->server_chr != NULL) &&
729: (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
730: /* if we get a UNIX socket as the parameter we will talk
731: * to the ivshmem server to receive the memory region */
732:
733: if (s->shmobj != NULL) {
734: fprintf(stderr, "WARNING: do not specify both 'chardev' "
735: "and 'shm' with ivshmem\n");
736: }
737:
738: IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
739: s->server_chr->filename);
740:
741: if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
742: ivshmem_setup_msi(s);
743: }
744:
745: /* we allocate enough space for 16 guests and grow as needed */
746: s->nb_peers = 16;
747: s->vm_id = -1;
748:
749: /* allocate/initialize space for interrupt handling */
750: s->peers = qemu_mallocz(s->nb_peers * sizeof(Peer));
751:
752: pci_register_bar(&s->dev, 2, s->ivshmem_size,
753: PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map);
754:
755: s->eventfd_chr = qemu_mallocz(s->vectors * sizeof(CharDriverState *));
756:
757: qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
758: ivshmem_event, s);
759: } else {
760: /* just map the file immediately, we're not using a server */
761: int fd;
762:
763: if (s->shmobj == NULL) {
764: fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n");
765: }
766:
767: IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
768:
769: /* try opening with O_EXCL and if it succeeds zero the memory
770: * by truncating to 0 */
771: if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL,
772: S_IRWXU|S_IRWXG|S_IRWXO)) > 0) {
773: /* truncate file to length PCI device's memory */
774: if (ftruncate(fd, s->ivshmem_size) != 0) {
775: fprintf(stderr, "ivshmem: could not truncate shared file\n");
776: }
777:
778: } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR,
779: S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
780: fprintf(stderr, "ivshmem: could not open shared file\n");
781: exit(-1);
782:
783: }
784:
785: if (check_shm_size(s, fd) == -1) {
786: exit(-1);
787: }
788:
789: create_shared_memory_BAR(s, fd);
790:
791: }
792:
793: return 0;
794: }
795:
796: static int pci_ivshmem_uninit(PCIDevice *dev)
797: {
798: IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
799:
800: cpu_unregister_io_memory(s->ivshmem_mmio_io_addr);
801: unregister_savevm(&dev->qdev, "ivshmem", s);
802:
803: return 0;
804: }
805:
806: static PCIDeviceInfo ivshmem_info = {
807: .qdev.name = "ivshmem",
808: .qdev.size = sizeof(IVShmemState),
809: .qdev.reset = ivshmem_reset,
810: .init = pci_ivshmem_init,
811: .exit = pci_ivshmem_uninit,
812: .qdev.props = (Property[]) {
813: DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
814: DEFINE_PROP_STRING("size", IVShmemState, sizearg),
815: DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
816: DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false),
817: DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
818: DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
819: DEFINE_PROP_STRING("role", IVShmemState, role),
820: DEFINE_PROP_END_OF_LIST(),
821: }
822: };
823:
824: static void ivshmem_register_devices(void)
825: {
826: pci_qdev_register(&ivshmem_info);
827: }
828:
829: device_init(ivshmem_register_devices)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.