static int pci_ivshmem_init(PCIDevice *dev) { IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev); uint8_t *pci_conf; if (s->sizearg == NULL) s->ivshmem_size = 4 << 20; /* 4 MB default */ else { s->ivshmem_size = ivshmem_get_size(s); } register_savevm(&s->dev.qdev, "ivshmem", 0, 0, ivshmem_save, ivshmem_load, dev); /* IRQFD requires MSI */ if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) && !ivshmem_has_feature(s, IVSHMEM_MSI)) { fprintf(stderr, "ivshmem: ioeventfd/irqfd requires MSI\n"); exit(1); } /* check that role is reasonable */ if (s->role) { if (strncmp(s->role, "peer", 5) == 0) { s->role_val = IVSHMEM_PEER; } else if (strncmp(s->role, "master", 7) == 0) { s->role_val = IVSHMEM_MASTER; } else { fprintf(stderr, "ivshmem: 'role' must be 'peer' or 'master'\n"); exit(1); } } else { s->role_val = IVSHMEM_MASTER; /* default */ } if (s->role_val == IVSHMEM_PEER) { error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, "peer mode", "ivshmem"); migrate_add_blocker(s->migration_blocker); } pci_conf = s->dev.config; pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY; pci_config_set_interrupt_pin(pci_conf, 1); s->shm_fd = 0; memory_region_init_io(&s->ivshmem_mmio, &ivshmem_mmio_ops, s, "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE); /* region for registers*/ pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ivshmem_mmio); memory_region_init(&s->bar, "ivshmem-bar2-container", s->ivshmem_size); s->ivshmem_attr = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH; if (s->ivshmem_64bit) { s->ivshmem_attr |= PCI_BASE_ADDRESS_MEM_TYPE_64; } if ((s->server_chr != NULL) && (strncmp(s->server_chr->filename, "unix:", 5) == 0)) { /* if we get a UNIX socket as the parameter we will talk * to the ivshmem server to receive the memory region */ if (s->shmobj != NULL) { fprintf(stderr, "WARNING: do not specify both 'chardev' " "and 'shm' with ivshmem\n"); } IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n", s->server_chr->filename); if (ivshmem_has_feature(s, IVSHMEM_MSI)) { ivshmem_setup_msi(s); } /* we allocate enough space for 16 guests and grow as needed */ s->nb_peers = 16; s->vm_id = -1; /* allocate/initialize space for interrupt handling */ s->peers = g_malloc0(s->nb_peers * sizeof(Peer)); pci_register_bar(&s->dev, 2, s->ivshmem_attr, &s->bar); s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *)); qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read, ivshmem_event, s); } else { /* just map the file immediately, we're not using a server */ int fd; if (s->shmobj == NULL) { fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n"); } IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj); /* try opening with O_EXCL and if it succeeds zero the memory * by truncating to 0 */ if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL, S_IRWXU|S_IRWXG|S_IRWXO)) > 0) { /* truncate file to length PCI device's memory */ if (ftruncate(fd, s->ivshmem_size) != 0) { fprintf(stderr, "ivshmem: could not truncate shared file\n"); } } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO)) < 0) { fprintf(stderr, "ivshmem: could not open shared file\n"); exit(-1); } if (check_shm_size(s, fd) == -1) { exit(-1); } create_shared_memory_BAR(s, fd); } s->dev.config_write = ivshmem_write_config; return 0; }
static void ivshmem_read(void *opaque, const uint8_t * buf, int flags) { IVShmemState *s = opaque; int incoming_fd, tmp_fd; int guest_max_eventfd; long incoming_posn; memcpy(&incoming_posn, buf, sizeof(long)); /* pick off s->server_chr->msgfd and store it, posn should accompany msg */ tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr); IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd); /* make sure we have enough space for this guest */ if (incoming_posn >= s->nb_peers) { increase_dynamic_storage(s, incoming_posn); } if (tmp_fd == -1) { /* if posn is positive and unseen before then this is our posn*/ if ((incoming_posn >= 0) && (s->peers[incoming_posn].eventfds == NULL)) { /* receive our posn */ s->vm_id = incoming_posn; return; } else { /* otherwise an fd == -1 means an existing guest has gone away */ IVSHMEM_DPRINTF("posn %ld has gone away\n", incoming_posn); close_guest_eventfds(s, incoming_posn); return; } } /* because of the implementation of get_msgfd, we need a dup */ incoming_fd = dup(tmp_fd); if (incoming_fd == -1) { fprintf(stderr, "could not allocate file descriptor %s\n", strerror(errno)); return; } /* if the position is -1, then it's shared memory region fd */ if (incoming_posn == -1) { void * map_ptr; s->max_peer = 0; if (check_shm_size(s, incoming_fd) == -1) { exit(-1); } /* mmap the region and map into the BAR2 */ map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, incoming_fd, 0); memory_region_init_ram_ptr(&s->ivshmem, "ivshmem.bar2", s->ivshmem_size, map_ptr); vmstate_register_ram(&s->ivshmem, &s->dev.qdev); IVSHMEM_DPRINTF("guest h/w addr = %" PRIu64 ", size = %" PRIu64 "\n", s->ivshmem_offset, s->ivshmem_size); memory_region_add_subregion(&s->bar, 0, &s->ivshmem); /* only store the fd if it is successfully mapped */ s->shm_fd = incoming_fd; return; } /* each guest has an array of eventfds, and we keep track of how many * guests for each VM */ guest_max_eventfd = s->peers[incoming_posn].nb_eventfds; if (guest_max_eventfd == 0) { /* one eventfd per MSI vector */ s->peers[incoming_posn].eventfds = g_new(EventNotifier, s->vectors); } /* this is an eventfd for a particular guest VM */ IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn, guest_max_eventfd, incoming_fd); event_notifier_init_fd(&s->peers[incoming_posn].eventfds[guest_max_eventfd], incoming_fd); /* increment count for particular guest */ s->peers[incoming_posn].nb_eventfds++; /* keep track of the maximum VM ID */ if (incoming_posn > s->max_peer) { s->max_peer = incoming_posn; } if (incoming_posn == s->vm_id) { s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s, &s->peers[s->vm_id].eventfds[guest_max_eventfd], guest_max_eventfd); } if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) { ivshmem_add_eventfd(s, incoming_posn, guest_max_eventfd); } }
static int pci_ivshmem_init(PCIDevice *dev) { IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev); uint8_t *pci_conf; if (s->sizearg == NULL) s->ivshmem_size = 4 << 20; /* 4 MB default */ else { s->ivshmem_size = ivshmem_get_size(s); } register_savevm(&s->dev.qdev, "ivshmem", 0, 0, ivshmem_save, ivshmem_load, dev); /* IRQFD requires MSI */ if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) && !ivshmem_has_feature(s, IVSHMEM_MSI)) { fprintf(stderr, "ivshmem: ioeventfd/irqfd requires MSI\n"); exit(1); } /* check that role is reasonable */ if (s->role) { if (strncmp(s->role, "peer", 5) == 0) { s->role_val = IVSHMEM_PEER; } else if (strncmp(s->role, "master", 7) == 0) { s->role_val = IVSHMEM_MASTER; } else { fprintf(stderr, "ivshmem: 'role' must be 'peer' or 'master'\n"); exit(1); } } else { s->role_val = IVSHMEM_MASTER; /* default */ } if (s->role_val == IVSHMEM_PEER) { error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION, "peer mode", "ivshmem"); migrate_add_blocker(s->migration_blocker); } pci_conf = s->dev.config; pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY; pci_config_set_interrupt_pin(pci_conf, 1); memset(s->shm_fds, 0, sizeof(s->shm_fds)); memory_region_init_io(&s->ivshmem_mmio, &ivshmem_mmio_ops, s, "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE); /* region for registers*/ pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ivshmem_mmio); memory_region_init(&s->bar, "ivshmem-bar2-container", s->ivshmem_size); s->ivshmem_attr = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH; if (s->ivshmem_64bit) { s->ivshmem_attr |= PCI_BASE_ADDRESS_MEM_TYPE_64; } if ((s->server_chr != NULL) && (strncmp(s->server_chr->filename, "unix:", 5) == 0)) { /* if we get a UNIX socket as the parameter we will talk * to the ivshmem server to receive the memory region */ if (s->shmobj != NULL) { fprintf(stderr, "WARNING: do not specify both 'chardev' " "and 'shm' with ivshmem\n"); } IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n", s->server_chr->filename); if (ivshmem_has_feature(s, IVSHMEM_MSI)) { ivshmem_setup_msi(s); } /* we allocate enough space for 16 guests and grow as needed */ s->nb_peers = 16; s->vm_id = -1; /* allocate/initialize space for interrupt handling */ s->peers = g_malloc0(s->nb_peers * sizeof(Peer)); pci_register_bar(&s->dev, 2, s->ivshmem_attr, &s->bar); s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *)); qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read, ivshmem_event, s); } else { /* just map the file immediately, we're not using a server */ IVShmemFile f[IVSHMEM_MAX_FILES]; int f_index = 0; if (s->shmobj == NULL) { fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n"); exit(1); } IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj); memset(f, 0, sizeof(f)); /* check if we are trying to share a regular file */ if (strncmp(s->shmobj, FD_PREFIX, sizeof(FD_PREFIX) - 1) == 0) { int token_n, n_cols, i; char * tok; n_cols = 0; token_n = -1; /* find out how many colons do we have */ for (i = 0; i <= strlen(s->shmobj); i++) { if (s->shmobj[i] == ':') n_cols++; } tok = strtok(s->shmobj, ":"); while (tok != NULL) { if (f_index == IVSHMEM_MAX_FILES) { fprintf(stderr, "ivshmem: too many files (maximum is %i)\n", IVSHMEM_MAX_FILES); exit(-1); } /* skip the first token */ if (token_n == -1) { tok = strtok(0, ":"); token_n++; continue; } switch (token_n % TOK_NUM) { case TOK_FILENAME: if ((f[f_index].fd = open(tok, O_RDWR | O_SYNC)) < 0) { fprintf(stderr, "ivshmem: error opening file %s: %s\n", tok, strerror(errno)); exit(-1); } /* get true file size, may be changed later */ f[f_index].size = get_file_size(f[f_index].fd); break; case TOK_OFFSET: f[f_index].offset = strtoull(tok, NULL, 16); break; case TOK_SIZE: f[f_index].size = strtoull(tok, NULL, 16); f_index++; break; default: fprintf(stderr, "ivshmem: invalid parameters\n"); exit(-1); } tok = strtok(0, ":"); token_n++; } /* check every file descriptor */ for (i = 0; i < IVSHMEM_MAX_FILES; i++) { if (f[i].fd > 0) { if (check_shm_size(f[i].fd, f[i].size, f[i].offset) == -1) exit(-1); } } /* check if we haven't skipped any tokens */ if ((token_n != n_cols) || (n_cols > (IVSHMEM_MAX_FILES * 3))) { fprintf(stderr, "ivshmem: invalid parameters\n"); exit(-1); } } else { /* try opening with O_EXCL and if it succeeds zero the memory * by truncating to 0 */ if ((f[0].fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL, S_IRWXU|S_IRWXG|S_IRWXO)) > 0) { /* truncate file to length PCI device's memory */ if (ftruncate(f[0].fd, s->ivshmem_size) != 0) { fprintf(stderr, "ivshmem: could not truncate shared file\n"); } } else if ((f[0].fd = shm_open(s->shmobj, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO)) < 0) { fprintf(stderr, "ivshmem: could not open shared file\n"); exit(-1); } if (s->ivshmem_size > get_file_size(f[0].fd)) { fprintf(stderr, "ivshmem: Requested memory size greater" " than shared object size\n"); exit(-1); } f_index = 1; } if (check_total_shm_size(s, f, f_index)) exit(-1); if (create_shared_memory_BAR(s, f, f_index) < 0) exit(-1); } s->dev.config_write = ivshmem_write_config; return 0; }
static void pci_ivshmem_realize(PCIDevice *dev, Error **errp) { IVShmemState *s = IVSHMEM(dev); uint8_t *pci_conf; uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH; if (!!s->server_chr + !!s->shmobj + !!s->hostmem != 1) { error_setg(errp, "You must specify either 'shm', 'chardev' or 'x-memdev'"); return; } if (s->hostmem) { MemoryRegion *mr; if (s->sizearg) { g_warning("size argument ignored with hostmem"); } mr = host_memory_backend_get_memory(s->hostmem, errp); s->ivshmem_size = memory_region_size(mr); } else if (s->sizearg == NULL) { s->ivshmem_size = 4 << 20; /* 4 MB default */ } else { char *end; int64_t size = qemu_strtosz(s->sizearg, &end); if (size < 0 || *end != '\0' || !is_power_of_2(size)) { error_setg(errp, "Invalid size %s", s->sizearg); return; } s->ivshmem_size = size; } fifo8_create(&s->incoming_fifo, sizeof(int64_t)); /* IRQFD requires MSI */ if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) && !ivshmem_has_feature(s, IVSHMEM_MSI)) { error_setg(errp, "ioeventfd/irqfd requires MSI"); return; } /* check that role is reasonable */ if (s->role) { if (strncmp(s->role, "peer", 5) == 0) { s->role_val = IVSHMEM_PEER; } else if (strncmp(s->role, "master", 7) == 0) { s->role_val = IVSHMEM_MASTER; } else { error_setg(errp, "'role' must be 'peer' or 'master'"); return; } } else { s->role_val = IVSHMEM_MASTER; /* default */ } if (s->role_val == IVSHMEM_PEER) { error_setg(&s->migration_blocker, "Migration is disabled when using feature 'peer mode' in device 'ivshmem'"); migrate_add_blocker(s->migration_blocker); } pci_conf = dev->config; pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY; pci_config_set_interrupt_pin(pci_conf, 1); memory_region_init_io(&s->ivshmem_mmio, OBJECT(s), &ivshmem_mmio_ops, s, "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE); /* region for registers*/ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ivshmem_mmio); memory_region_init(&s->bar, OBJECT(s), "ivshmem-bar2-container", s->ivshmem_size); if (s->ivshmem_64bit) { attr |= PCI_BASE_ADDRESS_MEM_TYPE_64; } if (s->hostmem != NULL) { MemoryRegion *mr; IVSHMEM_DPRINTF("using hostmem\n"); mr = host_memory_backend_get_memory(MEMORY_BACKEND(s->hostmem), errp); vmstate_register_ram(mr, DEVICE(s)); memory_region_add_subregion(&s->bar, 0, mr); pci_register_bar(PCI_DEVICE(s), 2, attr, &s->bar); } else if (s->server_chr != NULL) { /* FIXME do not rely on what chr drivers put into filename */ if (strncmp(s->server_chr->filename, "unix:", 5)) { error_setg(errp, "chardev is not a unix client socket"); return; } /* if we get a UNIX socket as the parameter we will talk * to the ivshmem server to receive the memory region */ IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n", s->server_chr->filename); if (ivshmem_has_feature(s, IVSHMEM_MSI) && ivshmem_setup_msi(s)) { error_setg(errp, "msix initialization failed"); return; } /* we allocate enough space for 16 peers and grow as needed */ resize_peers(s, 16); s->vm_id = -1; pci_register_bar(dev, 2, attr, &s->bar); s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *)); qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_check_version, ivshmem_event, s); } else { /* just map the file immediately, we're not using a server */ int fd; IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj); /* try opening with O_EXCL and if it succeeds zero the memory * by truncating to 0 */ if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL, S_IRWXU|S_IRWXG|S_IRWXO)) > 0) { /* truncate file to length PCI device's memory */ if (ftruncate(fd, s->ivshmem_size) != 0) { error_report("could not truncate shared file"); } } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO)) < 0) { error_setg(errp, "could not open shared file"); return; } if (check_shm_size(s, fd, errp) == -1) { return; } create_shared_memory_BAR(s, fd, attr, errp); } }
static void ivshmem_read(void *opaque, const uint8_t *buf, int size) { IVShmemState *s = opaque; int incoming_fd; int new_eventfd; int64_t incoming_posn; Error *err = NULL; Peer *peer; if (!fifo_update_and_get_i64(s, buf, size, &incoming_posn)) { return; } if (incoming_posn < -1) { IVSHMEM_DPRINTF("invalid incoming_posn %" PRId64 "\n", incoming_posn); return; } /* pick off s->server_chr->msgfd and store it, posn should accompany msg */ incoming_fd = qemu_chr_fe_get_msgfd(s->server_chr); IVSHMEM_DPRINTF("posn is %" PRId64 ", fd is %d\n", incoming_posn, incoming_fd); /* make sure we have enough space for this peer */ if (incoming_posn >= s->nb_peers) { if (resize_peers(s, incoming_posn + 1) < 0) { error_report("failed to resize peers array"); if (incoming_fd != -1) { close(incoming_fd); } return; } } peer = &s->peers[incoming_posn]; if (incoming_fd == -1) { /* if posn is positive and unseen before then this is our posn*/ if (incoming_posn >= 0 && s->vm_id == -1) { /* receive our posn */ s->vm_id = incoming_posn; } else { /* otherwise an fd == -1 means an existing peer has gone away */ IVSHMEM_DPRINTF("posn %" PRId64 " has gone away\n", incoming_posn); close_peer_eventfds(s, incoming_posn); } return; } /* if the position is -1, then it's shared memory region fd */ if (incoming_posn == -1) { void * map_ptr; if (memory_region_is_mapped(&s->ivshmem)) { error_report("shm already initialized"); close(incoming_fd); return; } if (check_shm_size(s, incoming_fd, &err) == -1) { error_report_err(err); close(incoming_fd); return; } /* mmap the region and map into the BAR2 */ map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, incoming_fd, 0); if (map_ptr == MAP_FAILED) { error_report("Failed to mmap shared memory %s", strerror(errno)); close(incoming_fd); return; } memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s), "ivshmem.bar2", s->ivshmem_size, map_ptr); qemu_set_ram_fd(s->ivshmem.ram_addr, incoming_fd); vmstate_register_ram(&s->ivshmem, DEVICE(s)); IVSHMEM_DPRINTF("guest h/w addr = %p, size = %" PRIu64 "\n", map_ptr, s->ivshmem_size); memory_region_add_subregion(&s->bar, 0, &s->ivshmem); return; } /* each peer has an associated array of eventfds, and we keep * track of how many eventfds received so far */ /* get a new eventfd: */ if (peer->nb_eventfds >= s->vectors) { error_report("Too many eventfd received, device has %d vectors", s->vectors); close(incoming_fd); return; } new_eventfd = peer->nb_eventfds++; /* this is an eventfd for a particular peer VM */ IVSHMEM_DPRINTF("eventfds[%" PRId64 "][%d] = %d\n", incoming_posn, new_eventfd, incoming_fd); event_notifier_init_fd(&peer->eventfds[new_eventfd], incoming_fd); fcntl_setfl(incoming_fd, O_NONBLOCK); /* msix/irqfd poll non block */ if (incoming_posn == s->vm_id) { setup_interrupt(s, new_eventfd); } if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) { ivshmem_add_eventfd(s, incoming_posn, new_eventfd); } }
static int pci_ivshmem_init(PCIDevice *dev) { IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev); uint8_t *pci_conf; if (s->sizearg == NULL) s->ivshmem_size = 4 << 20; /* 4 MB default */ else { s->ivshmem_size = ivshmem_get_size(s); } register_savevm(&s->dev.qdev, "ivshmem", 0, 0, ivshmem_save, ivshmem_load, dev); /* IRQFD requires MSI */ if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) && !ivshmem_has_feature(s, IVSHMEM_MSI)) { fprintf(stderr, "ivshmem: ioeventfd/irqfd requires MSI\n"); exit(1); } /* check that role is reasonable */ if (s->role) { if (strncmp(s->role, "peer", 5) == 0) { s->role_val = IVSHMEM_PEER; } else if (strncmp(s->role, "master", 7) == 0) { s->role_val = IVSHMEM_MASTER; } else { fprintf(stderr, "ivshmem: 'role' must be 'peer' or 'master'\n"); exit(1); } } else { s->role_val = IVSHMEM_MASTER; /* default */ } if (s->role_val == IVSHMEM_PEER) { register_device_unmigratable(&s->dev.qdev, "ivshmem", s); } pci_conf = s->dev.config; pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REDHAT_QUMRANET); pci_conf[0x02] = 0x10; pci_conf[0x03] = 0x11; pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY; pci_config_set_class(pci_conf, PCI_CLASS_MEMORY_RAM); pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; pci_config_set_interrupt_pin(pci_conf, 1); s->shm_pci_addr = 0; s->ivshmem_offset = 0; s->shm_fd = 0; s->ivshmem_mmio_io_addr = cpu_register_io_memory(ivshmem_mmio_read, ivshmem_mmio_write, s); /* region for registers*/ pci_register_bar(&s->dev, 0, IVSHMEM_REG_BAR_SIZE, PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_mmio_map); if ((s->server_chr != NULL) && (strncmp(s->server_chr->filename, "unix:", 5) == 0)) { /* if we get a UNIX socket as the parameter we will talk * to the ivshmem server to receive the memory region */ if (s->shmobj != NULL) { fprintf(stderr, "WARNING: do not specify both 'chardev' " "and 'shm' with ivshmem\n"); } IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n", s->server_chr->filename); if (ivshmem_has_feature(s, IVSHMEM_MSI)) { ivshmem_setup_msi(s); } /* we allocate enough space for 16 guests and grow as needed */ s->nb_peers = 16; s->vm_id = -1; /* allocate/initialize space for interrupt handling */ s->peers = qemu_mallocz(s->nb_peers * sizeof(Peer)); pci_register_bar(&s->dev, 2, s->ivshmem_size, PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map); s->eventfd_chr = qemu_mallocz(s->vectors * sizeof(CharDriverState *)); qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read, ivshmem_event, s); } else { /* just map the file immediately, we're not using a server */ int fd; if (s->shmobj == NULL) { fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n"); } IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj); /* try opening with O_EXCL and if it succeeds zero the memory * by truncating to 0 */ if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL, S_IRWXU|S_IRWXG|S_IRWXO)) > 0) { /* truncate file to length PCI device's memory */ if (ftruncate(fd, s->ivshmem_size) != 0) { fprintf(stderr, "ivshmem: could not truncate shared file\n"); } } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO)) < 0) { fprintf(stderr, "ivshmem: could not open shared file\n"); exit(-1); } if (check_shm_size(s, fd) == -1) { exit(-1); } create_shared_memory_BAR(s, fd); } return 0; }