Annotation of qemu/hw/ivshmem.c, revision 1.1.1.3

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_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
                    710: 
                    711:     pci_config_set_interrupt_pin(pci_conf, 1);
                    712: 
                    713:     s->shm_pci_addr = 0;
                    714:     s->ivshmem_offset = 0;
                    715:     s->shm_fd = 0;
                    716: 
                    717:     s->ivshmem_mmio_io_addr = cpu_register_io_memory(ivshmem_mmio_read,
1.1.1.2   root      718:                                     ivshmem_mmio_write, s, DEVICE_NATIVE_ENDIAN);
1.1       root      719:     /* region for registers*/
                    720:     pci_register_bar(&s->dev, 0, IVSHMEM_REG_BAR_SIZE,
                    721:                            PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_mmio_map);
                    722: 
                    723:     if ((s->server_chr != NULL) &&
                    724:                         (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
                    725:         /* if we get a UNIX socket as the parameter we will talk
                    726:          * to the ivshmem server to receive the memory region */
                    727: 
                    728:         if (s->shmobj != NULL) {
                    729:             fprintf(stderr, "WARNING: do not specify both 'chardev' "
                    730:                                                 "and 'shm' with ivshmem\n");
                    731:         }
                    732: 
                    733:         IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
                    734:                                                     s->server_chr->filename);
                    735: 
                    736:         if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
                    737:             ivshmem_setup_msi(s);
                    738:         }
                    739: 
                    740:         /* we allocate enough space for 16 guests and grow as needed */
                    741:         s->nb_peers = 16;
                    742:         s->vm_id = -1;
                    743: 
                    744:         /* allocate/initialize space for interrupt handling */
                    745:         s->peers = qemu_mallocz(s->nb_peers * sizeof(Peer));
                    746: 
                    747:         pci_register_bar(&s->dev, 2, s->ivshmem_size,
                    748:                                 PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map);
                    749: 
                    750:         s->eventfd_chr = qemu_mallocz(s->vectors * sizeof(CharDriverState *));
                    751: 
                    752:         qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
                    753:                      ivshmem_event, s);
                    754:     } else {
                    755:         /* just map the file immediately, we're not using a server */
                    756:         int fd;
                    757: 
                    758:         if (s->shmobj == NULL) {
                    759:             fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n");
                    760:         }
                    761: 
                    762:         IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
                    763: 
                    764:         /* try opening with O_EXCL and if it succeeds zero the memory
                    765:          * by truncating to 0 */
                    766:         if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL,
                    767:                         S_IRWXU|S_IRWXG|S_IRWXO)) > 0) {
                    768:            /* truncate file to length PCI device's memory */
                    769:             if (ftruncate(fd, s->ivshmem_size) != 0) {
                    770:                 fprintf(stderr, "ivshmem: could not truncate shared file\n");
                    771:             }
                    772: 
                    773:         } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR,
                    774:                         S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
                    775:             fprintf(stderr, "ivshmem: could not open shared file\n");
                    776:             exit(-1);
                    777: 
                    778:         }
                    779: 
                    780:         if (check_shm_size(s, fd) == -1) {
                    781:             exit(-1);
                    782:         }
                    783: 
                    784:         create_shared_memory_BAR(s, fd);
                    785: 
                    786:     }
                    787: 
                    788:     return 0;
                    789: }
                    790: 
                    791: static int pci_ivshmem_uninit(PCIDevice *dev)
                    792: {
                    793:     IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
                    794: 
                    795:     cpu_unregister_io_memory(s->ivshmem_mmio_io_addr);
                    796:     unregister_savevm(&dev->qdev, "ivshmem", s);
                    797: 
                    798:     return 0;
                    799: }
                    800: 
                    801: static PCIDeviceInfo ivshmem_info = {
                    802:     .qdev.name  = "ivshmem",
                    803:     .qdev.size  = sizeof(IVShmemState),
                    804:     .qdev.reset = ivshmem_reset,
                    805:     .init       = pci_ivshmem_init,
                    806:     .exit       = pci_ivshmem_uninit,
1.1.1.3 ! root      807:     .vendor_id  = PCI_VENDOR_ID_REDHAT_QUMRANET,
        !           808:     .device_id  = 0x1110,
        !           809:     .class_id   = PCI_CLASS_MEMORY_RAM,
1.1       root      810:     .qdev.props = (Property[]) {
                    811:         DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
                    812:         DEFINE_PROP_STRING("size", IVShmemState, sizearg),
                    813:         DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
                    814:         DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false),
                    815:         DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
                    816:         DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
                    817:         DEFINE_PROP_STRING("role", IVShmemState, role),
                    818:         DEFINE_PROP_END_OF_LIST(),
                    819:     }
                    820: };
                    821: 
                    822: static void ivshmem_register_devices(void)
                    823: {
                    824:     pci_qdev_register(&ivshmem_info);
                    825: }
                    826: 
                    827: device_init(ivshmem_register_devices)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.