Exemple #1
0
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;
}
Exemple #2
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);
    }
}
Exemple #3
0
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 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;
}