static void usb_ohci_realize_pci(PCIDevice *dev, Error **errp) { Error *err = NULL; OHCIPCIState *ohci = PCI_OHCI(dev); dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */ dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0, ohci->masterbus, ohci->firstport, pci_get_address_space(dev), ohci_pci_die, &err); if (err) { error_propagate(errp, err); return; } ohci->state.irq = pci_allocate_irq(dev); pci_register_bar(dev, 0, 0, &ohci->state.mem); }
static int pci_bridge_dev_initfn(PCIDevice *dev) { PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br); int err, ret; pci_bridge_map_irq(br, NULL, pci_bridge_dev_map_irq_fn); err = pci_bridge_initfn(dev); if (err) { goto bridge_error; } memory_region_init(&bridge_dev->bar, "shpc-bar", shpc_bar_size(dev)); err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0); if (err) { goto shpc_error; } err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0); if (err) { goto slotid_error; } if ((bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_MSI_REQ)) && msi_supported) { err = msi_init(dev, 0, 1, true, true); if (err < 0) { goto msi_error; } } /* TODO: spec recommends using 64 bit prefetcheable BAR. * Check whether that works well. */ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar); dev->config[PCI_INTERRUPT_PIN] = 0x1; return 0; msi_error: slotid_cap_cleanup(dev); slotid_error: shpc_cleanup(dev, &bridge_dev->bar); shpc_error: memory_region_destroy(&bridge_dev->bar); ret = pci_bridge_exitfn(dev); assert(!ret); bridge_error: return err; }
int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, uint8_t bar_nr) { int ret; char *name; uint32_t bar_size = 4096; uint32_t bar_pba_offset = bar_size / 2; uint32_t bar_pba_size = (nentries / 8 + 1) * 8; /* * Migration compatibility dictates that this remains a 4k * BAR with the vector table in the lower half and PBA in * the upper half for nentries which is lower or equal to 128. * No need to care about using more than 65 entries for legacy * machine types who has at most 64 queues. */ if (nentries * PCI_MSIX_ENTRY_SIZE > bar_pba_offset) { bar_pba_offset = nentries * PCI_MSIX_ENTRY_SIZE; } if (bar_pba_offset + bar_pba_size > 4096) { bar_size = bar_pba_offset + bar_pba_size; } bar_size = pow2ceil(bar_size); name = g_strdup_printf("%s-msix", dev->name); memory_region_init(&dev->msix_exclusive_bar, OBJECT(dev), name, bar_size); g_free(name); ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr, 0, &dev->msix_exclusive_bar, bar_nr, bar_pba_offset, 0); if (ret) { return ret; } pci_register_bar(dev, bar_nr, PCI_BASE_ADDRESS_SPACE_MEMORY, &dev->msix_exclusive_bar); return 0; }
static void macio_common_realize(PCIDevice *d, Error **errp) { MacIOState *s = MACIO(d); SysBusDevice *sysbus_dev; Error *err = NULL; object_property_set_bool(OBJECT(&s->dbdma), true, "realized", &err); if (err) { error_propagate(errp, err); return; } sysbus_dev = SYS_BUS_DEVICE(&s->dbdma); memory_region_add_subregion(&s->bar, 0x08000, sysbus_mmio_get_region(sysbus_dev, 0)); qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency", s->frequency); object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err); if (err) { error_propagate(errp, err); return; } sysbus_dev = SYS_BUS_DEVICE(&s->cuda); memory_region_add_subregion(&s->bar, 0x16000, sysbus_mmio_get_region(sysbus_dev, 0)); qdev_prop_set_uint32(DEVICE(&s->escc), "disabled", 0); qdev_prop_set_uint32(DEVICE(&s->escc), "frequency", ESCC_CLOCK); qdev_prop_set_uint32(DEVICE(&s->escc), "it_shift", 4); qdev_prop_set_chr(DEVICE(&s->escc), "chrA", serial_hd(0)); qdev_prop_set_chr(DEVICE(&s->escc), "chrB", serial_hd(1)); qdev_prop_set_uint32(DEVICE(&s->escc), "chnBtype", escc_serial); qdev_prop_set_uint32(DEVICE(&s->escc), "chnAtype", escc_serial); object_property_set_bool(OBJECT(&s->escc), true, "realized", &err); if (err) { error_propagate(errp, err); return; } macio_bar_setup(s); pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar); }
static int multi_serial_pci_init(PCIDevice *dev) { PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev); SerialState *s; Error *err = NULL; int i; switch (pc->device_id) { case 0x0003: pci->ports = 2; break; case 0x0004: pci->ports = 4; break; } assert(pci->ports > 0); assert(pci->ports <= PCI_SERIAL_MAX_PORTS); pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * pci->ports); pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar); pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, pci->ports); for (i = 0; i < pci->ports; i++) { s = pci->state + i; s->baudbase = 115200; serial_realize_core(s, &err); if (err != NULL) { qerror_report_err(err); error_free(err); return -1; } s->irq = pci->irqs[i]; pci->name[i] = g_strdup_printf("uart #%d", i+1); memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s, pci->name[i], 8); memory_region_add_subregion(&pci->iobar, 8 * i, &s->io); } return 0; }
static void serial_pci_realize(PCIDevice *dev, Error **errp) { PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); SerialState *s = &pci->state; Error *err = NULL; s->baudbase = 115200; serial_realize_core(s, &err); if (err != NULL) { error_propagate(errp, err); return; } pci->dev.config[PCI_CLASS_PROG] = pci->prog_if; pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; s->irq = pci_allocate_irq(&pci->dev); memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s, "serial", 8); pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io); }
static int pci_edu_init(PCIDevice *pdev) { EduState *edu = DO_UPCAST(EduState, pdev, pdev); uint8_t *pci_conf = pdev->config; timer_init_ms(&edu->dma_timer, QEMU_CLOCK_VIRTUAL, edu_dma_timer, edu); qemu_mutex_init(&edu->thr_mutex); qemu_cond_init(&edu->thr_cond); qemu_thread_create(&edu->thread, "edu", edu_fact_thread, edu, QEMU_THREAD_JOINABLE); pci_config_set_interrupt_pin(pci_conf, 1); memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu, "edu-mmio", 1 << 20); pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio); return 0; }
static int serial_pci_init(PCIDevice *dev) { PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev); SerialState *s = &pci->state; Error *err = NULL; s->baudbase = 115200; serial_realize_core(s, &err); if (err != NULL) { qerror_report_err(err); error_free(err); return -1; } pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; s->irq = pci_allocate_irq(&pci->dev); memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s, "serial", 8); pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io); return 0; }
static int macio_common_initfn(PCIDevice *d) { MacIOState *s = MACIO(d); SysBusDevice *sysbus_dev; int ret; d->config[0x3d] = 0x01; // interrupt on pin 1 ret = qdev_init(DEVICE(&s->cuda)); if (ret < 0) { return ret; } sysbus_dev = SYS_BUS_DEVICE(&s->cuda); memory_region_add_subregion(&s->bar, 0x16000, sysbus_mmio_get_region(sysbus_dev, 0)); macio_bar_setup(s); pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar); return 0; }
/* via ide func */ static int vt82c686b_ide_initfn(PCIDevice *dev) { PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);; uint8_t *pci_conf = d->dev.config; pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA); pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_IDE); pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE); pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy ATA mode */ pci_config_set_revision(pci_conf,0x06); /* Revision 0.6 */ pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0); qemu_register_reset(via_reset, d); pci_register_bar(&d->dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map); vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d); vt82c686b_init_ports(d); return 0; }
static void macio_common_realize(PCIDevice *d, Error **errp) { MacIOState *s = MACIO(d); SysBusDevice *sysbus_dev; Error *err = NULL; MemoryRegion *dbdma_mem; s->dbdma = DBDMA_init(&dbdma_mem); memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem); object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err); if (err) { error_propagate(errp, err); return; } sysbus_dev = SYS_BUS_DEVICE(&s->cuda); memory_region_add_subregion(&s->bar, 0x16000, sysbus_mmio_get_region(sysbus_dev, 0)); macio_bar_setup(s); pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar); }
/* create the shared memory BAR when we are not using the server, so we can * create the BAR and map the memory immediately */ static int create_shared_memory_BAR(IVShmemState *s, int fd, uint8_t attr, Error **errp) { void * ptr; ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (ptr == MAP_FAILED) { error_setg_errno(errp, errno, "Failed to mmap shared memory"); return -1; } memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s), "ivshmem.bar2", s->ivshmem_size, ptr); qemu_set_ram_fd(s->ivshmem.ram_addr, fd); vmstate_register_ram(&s->ivshmem, DEVICE(s)); memory_region_add_subregion(&s->bar, 0, &s->ivshmem); /* region for shared memory */ pci_register_bar(PCI_DEVICE(s), 2, attr, &s->bar); return 0; }
void macio_init (PCIBus *bus, int device_id, int is_oldworld, MemoryRegion *pic_mem, MemoryRegion *dbdma_mem, MemoryRegion *cuda_mem, void *nvram, int nb_ide, MemoryRegion **ide_mem, MemoryRegion *escc_mem) { PCIDevice *d; macio_state_t *macio_state; int i; d = pci_register_device(bus, "macio", sizeof(PCIDevice) + sizeof(macio_state_t), -1, NULL, NULL); macio_state = (macio_state_t *)(d + 1); macio_state->is_oldworld = is_oldworld; macio_state->pic_mem = pic_mem; macio_state->dbdma_mem = dbdma_mem; macio_state->cuda_mem = cuda_mem; macio_state->escc_mem = escc_mem; macio_state->nvram = nvram; if (nb_ide > 4) nb_ide = 4; macio_state->nb_ide = nb_ide; for (i = 0; i < nb_ide; i++) macio_state->ide_mem[i] = ide_mem[i]; for (; i < 4; i++) macio_state->ide_mem[i] = NULL; /* Note: this code is strongly inspirated from the corresponding code in PearPC */ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE); pci_config_set_device_id(d->config, device_id); pci_config_set_class(d->config, PCI_CLASS_OTHERS << 8); d->config[0x3d] = 0x01; // interrupt on pin 1 macio_bar_setup(macio_state); pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &macio_state->bar); }
int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries, uint8_t bar_nr) { int ret; char *name; /* * Migration compatibility dictates that this remains a 4k * BAR with the vector table in the lower half and PBA in * the upper half. Do not use these elsewhere! */ #define MSIX_EXCLUSIVE_BAR_SIZE 4096 #define MSIX_EXCLUSIVE_BAR_TABLE_OFFSET 0 #define MSIX_EXCLUSIVE_BAR_PBA_OFFSET (MSIX_EXCLUSIVE_BAR_SIZE / 2) #define MSIX_EXCLUSIVE_CAP_OFFSET 0 if (nentries * PCI_MSIX_ENTRY_SIZE > MSIX_EXCLUSIVE_BAR_PBA_OFFSET) { return -EINVAL; } name = g_strdup_printf("%s-msix", dev->name); memory_region_init(&dev->msix_exclusive_bar, OBJECT(dev), name, MSIX_EXCLUSIVE_BAR_SIZE); g_free(name); ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr, MSIX_EXCLUSIVE_BAR_TABLE_OFFSET, &dev->msix_exclusive_bar, bar_nr, MSIX_EXCLUSIVE_BAR_PBA_OFFSET, MSIX_EXCLUSIVE_CAP_OFFSET); if (ret) { memory_region_destroy(&dev->msix_exclusive_bar); return ret; } pci_register_bar(dev, bar_nr, PCI_BASE_ADDRESS_SPACE_MEMORY, &dev->msix_exclusive_bar); return 0; }
static int pci_fake_init(PCIDevice *pci_dev) { PCIFakeState *d = DO_UPCAST(PCIFakeState, dev, pci_dev); uint8_t *pci_conf; int i; d->fake_pci = *s_fake_pci; pci_conf = d->dev.config; pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type pci_conf[0x3d] = 1; // interrupt pin 0 char *name_io = malloc(strlen(d->fake_pci.name) + 20); char *name_mmio = malloc(strlen(d->fake_pci.name) + 20); sprintf(name_io, "%s-io", d->fake_pci.name); sprintf(name_mmio, "%s-mmio", d->fake_pci.name); for(i=0; i<d->fake_pci.num_resources; ++i) { int type = d->fake_pci.resources[i].type; int size = d->fake_pci.resources[i].size; char *name; if (type == PCI_BASE_ADDRESS_SPACE_IO) { name = name_io; } else if (type == PCI_BASE_ADDRESS_SPACE_MEMORY) { name = name_mmio; } memory_region_init_io(&d->io[i], &fake_ops, d, name, size); pci_register_bar(&d->dev, i, type, &d->io[i]); //, pci_fake_map } free(name_io); free(name_mmio); return 0; }
static void ivshmem_setup_msi(IVShmemState * s) { int i; /* allocate the MSI-X vectors */ memory_region_init(&s->msix_bar, "ivshmem-msix", 4096); if (!msix_init(&s->dev, s->vectors, &s->msix_bar, 1, 0)) { pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->msix_bar); IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors); } else { IVSHMEM_DPRINTF("msix initialization failed\n"); exit(1); } /* 'activate' the vectors */ for (i = 0; i < s->vectors; i++) { msix_vector_use(&s->dev, i); } /* allocate QEMU char devices for receiving interrupts */ s->eventfd_table = g_malloc0(s->vectors * sizeof(EventfdEntry)); }
static void pci_bridge_dev_realize(PCIDevice *dev, Error **errp) { PCIBridge *br = PCI_BRIDGE(dev); PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev); int err; Error *local_err = NULL; pci_bridge_initfn(dev, TYPE_PCI_BUS); if (bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_SHPC_REQ)) { dev->config[PCI_INTERRUPT_PIN] = 0x1; memory_region_init(&bridge_dev->bar, OBJECT(dev), "shpc-bar", shpc_bar_size(dev)); err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0, errp); if (err) { goto shpc_error; } } else { /* MSI is not applicable without SHPC */ bridge_dev->msi = ON_OFF_AUTO_OFF; } err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0, errp); if (err) { goto slotid_error; } if (bridge_dev->msi != ON_OFF_AUTO_OFF) { /* it means SHPC exists, because MSI is needed by SHPC */ err = msi_init(dev, 0, 1, true, true, &local_err); /* Any error other than -ENOTSUP(board's MSI support is broken) * is a programming error */ assert(!err || err == -ENOTSUP); if (err && bridge_dev->msi == ON_OFF_AUTO_ON) { /* Can't satisfy user's explicit msi=on request, fail */ error_append_hint(&local_err, "You have to use msi=auto (default) " "or msi=off with this machine type.\n"); error_propagate(errp, local_err); goto msi_error; } assert(!local_err || bridge_dev->msi == ON_OFF_AUTO_AUTO); /* With msi=auto, we fall back to MSI off silently */ error_free(local_err); } if (shpc_present(dev)) { /* TODO: spec recommends using 64 bit prefetcheable BAR. * Check whether that works well. */ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar); } return; msi_error: slotid_cap_cleanup(dev); slotid_error: if (shpc_present(dev)) { shpc_cleanup(dev, &bridge_dev->bar); } shpc_error: pci_bridge_exitfn(dev); }
static void ivshmem_common_realize(PCIDevice *dev, Error **errp) { IVShmemState *s = IVSHMEM_COMMON(dev); Error *err = NULL; uint8_t *pci_conf; uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH; /* IRQFD requires MSI */ if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) && !ivshmem_has_feature(s, IVSHMEM_MSI)) { error_setg(errp, "ioeventfd/irqfd requires MSI"); return; } pci_conf = dev->config; pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY; 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); if (!s->not_legacy_32bit) { attr |= PCI_BASE_ADDRESS_MEM_TYPE_64; } if (s->hostmem != NULL) { IVSHMEM_DPRINTF("using hostmem\n"); s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem, &error_abort); } else { assert(s->server_chr); IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n", s->server_chr->filename); /* we allocate enough space for 16 peers and grow as needed */ resize_peers(s, 16); /* * Receive setup messages from server synchronously. * Older versions did it asynchronously, but that creates a * number of entertaining race conditions. */ ivshmem_recv_setup(s, &err); if (err) { error_propagate(errp, err); return; } if (s->master == ON_OFF_AUTO_ON && s->vm_id != 0) { error_setg(errp, "master must connect to the server before any peers"); return; } qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read, NULL, s); if (ivshmem_setup_interrupts(s) < 0) { error_setg(errp, "failed to initialize interrupts"); return; } } vmstate_register_ram(s->ivshmem_bar2, DEVICE(s)); pci_register_bar(PCI_DEVICE(s), 2, attr, s->ivshmem_bar2); if (s->master == ON_OFF_AUTO_AUTO) { s->master = s->vm_id == 0 ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; } if (!ivshmem_is_master(s)) { error_setg(&s->migration_blocker, "Migration is disabled when using feature 'peer mode' in device 'ivshmem'"); migrate_add_blocker(s->migration_blocker); } }
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 e1000e_pci_realize(PCIDevice *pci_dev, Error **errp) { static const uint16_t e1000e_pmrb_offset = 0x0C8; static const uint16_t e1000e_pcie_offset = 0x0E0; static const uint16_t e1000e_aer_offset = 0x100; static const uint16_t e1000e_dsn_offset = 0x140; E1000EState *s = E1000E(pci_dev); uint8_t *macaddr; int ret; trace_e1000e_cb_pci_realize(); pci_dev->config_write = e1000e_write_config; pci_dev->config[PCI_CACHE_LINE_SIZE] = 0x10; pci_dev->config[PCI_INTERRUPT_PIN] = 1; pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, s->subsys_ven); pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, s->subsys); s->subsys_ven_used = s->subsys_ven; s->subsys_used = s->subsys; /* Define IO/MMIO regions */ memory_region_init_io(&s->mmio, OBJECT(s), &mmio_ops, s, "e1000e-mmio", E1000E_MMIO_SIZE); pci_register_bar(pci_dev, E1000E_MMIO_IDX, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio); /* * We provide a dummy implementation for the flash BAR * for drivers that may theoretically probe for its presence. */ memory_region_init(&s->flash, OBJECT(s), "e1000e-flash", E1000E_FLASH_SIZE); pci_register_bar(pci_dev, E1000E_FLASH_IDX, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->flash); memory_region_init_io(&s->io, OBJECT(s), &io_ops, s, "e1000e-io", E1000E_IO_SIZE); pci_register_bar(pci_dev, E1000E_IO_IDX, PCI_BASE_ADDRESS_SPACE_IO, &s->io); memory_region_init(&s->msix, OBJECT(s), "e1000e-msix", E1000E_MSIX_SIZE); pci_register_bar(pci_dev, E1000E_MSIX_IDX, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->msix); /* Create networking backend */ qemu_macaddr_default_if_unset(&s->conf.macaddr); macaddr = s->conf.macaddr.a; e1000e_init_msix(s); if (pcie_endpoint_cap_v1_init(pci_dev, e1000e_pcie_offset) < 0) { hw_error("Failed to initialize PCIe capability"); } ret = msi_init(PCI_DEVICE(s), 0xD0, 1, true, false, NULL); if (ret) { trace_e1000e_msi_init_fail(ret); } if (e1000e_add_pm_capability(pci_dev, e1000e_pmrb_offset, PCI_PM_CAP_DSI) < 0) { hw_error("Failed to initialize PM capability"); } if (pcie_aer_init(pci_dev, PCI_ERR_VER, e1000e_aer_offset, PCI_ERR_SIZEOF, NULL) < 0) { hw_error("Failed to initialize AER capability"); } pcie_dev_ser_num_init(pci_dev, e1000e_dsn_offset, e1000e_gen_dsn(macaddr)); e1000e_init_net_peer(s, pci_dev, macaddr); /* Initialize core */ e1000e_core_realize(s); e1000e_core_pci_realize(&s->core, e1000e_eeprom_template, sizeof(e1000e_eeprom_template), macaddr); }
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); } }
/* * Scan the assigned devices for the devices that have an option ROM, and then * load the corresponding ROM data to RAM. If an error occurs while loading an * option ROM, we just ignore that option ROM and continue with the next one. */ void *pci_assign_dev_load_option_rom(PCIDevice *dev, struct Object *owner, int *size, unsigned int domain, unsigned int bus, unsigned int slot, unsigned int function) { char name[32], rom_file[64]; FILE *fp; uint8_t val; struct stat st; void *ptr = NULL; /* If loading ROM from file, pci handles it */ if (dev->romfile || !dev->rom_bar) { return NULL; } snprintf(rom_file, sizeof(rom_file), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/rom", domain, bus, slot, function); /* Write "1" to the ROM file to enable it */ fp = fopen(rom_file, "r+"); if (fp == NULL) { if (errno != ENOENT) { error_report("pci-assign: Cannot open %s: %s", rom_file, strerror(errno)); } return NULL; } if (fstat(fileno(fp), &st) == -1) { error_report("pci-assign: Cannot stat %s: %s", rom_file, strerror(errno)); goto close_rom; } val = 1; if (fwrite(&val, 1, 1, fp) != 1) { goto close_rom; } fseek(fp, 0, SEEK_SET); snprintf(name, sizeof(name), "%s.rom", object_get_typename(owner)); memory_region_init_ram(&dev->rom, owner, name, st.st_size, &error_abort); vmstate_register_ram(&dev->rom, &dev->qdev); ptr = memory_region_get_ram_ptr(&dev->rom); memset(ptr, 0xff, st.st_size); if (!fread(ptr, 1, st.st_size, fp)) { error_report("pci-assign: Cannot read from host %s", rom_file); error_printf("Device option ROM contents are probably invalid " "(check dmesg).\nSkip option ROM probe with rombar=0, " "or load from file with romfile=\n"); goto close_rom; } pci_register_bar(dev, PCI_ROM_SLOT, 0, &dev->rom); dev->has_rom = true; *size = st.st_size; close_rom: /* Write "0" to disable ROM */ fseek(fp, 0, SEEK_SET); val = 0; if (!fwrite(&val, 1, 1, fp)) { DEBUG("%s\n", "Failed to disable pci-sysfs rom file"); } fclose(fp); return ptr; }
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; }
static int vigs_device_init(PCIDevice *dev) { VIGSState *s = DO_UPCAST(VIGSState, dev.pci_dev, dev); struct vigs_backend *backend = NULL; XSetErrorHandler(x_error_handler); XInitThreads(); vigs_display = XOpenDisplay(0); if (!vigs_display) { fprintf(stderr, "Cannot open X display\n"); exit(1); } vigs_render_queue = work_queue_create("render_queue"); vigs_log_init(); if (s->vram_size < 16 * 1024 * 1024) { VIGS_LOG_WARN("\"vram_size\" is too small, defaulting to 16mb"); s->vram_size = 16 * 1024 * 1024; } if (s->ram_size < 1 * 1024 * 1024) { VIGS_LOG_WARN("\"ram_size\" is too small, defaulting to 1mb"); s->ram_size = 1 * 1024 * 1024; } pci_config_set_interrupt_pin(dev->config, 1); memory_region_init_ram(&s->vram_bar, OBJECT(s), TYPE_VIGS_DEVICE ".vram", s->vram_size); memory_region_init_ram(&s->ram_bar, OBJECT(s), TYPE_VIGS_DEVICE ".ram", s->ram_size); memory_region_init_io(&s->io_bar, OBJECT(s), &vigs_io_ops, s, TYPE_VIGS_DEVICE ".io", VIGS_IO_SIZE); pci_register_bar(&s->dev.pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->vram_bar); pci_register_bar(&s->dev.pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_bar); pci_register_bar(&s->dev.pci_dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io_bar); backend = vigs_gl_backend_create(vigs_display); if (!backend) { goto fail; } s->fenceman = vigs_fenceman_create(); s->fence_ack_bh = qemu_bh_new(vigs_fence_ack_bh, s); s->con = graphic_console_init(DEVICE(dev), 0, &vigs_hw_ops, s); if (!s->con) { goto fail; } s->server = vigs_server_create(memory_region_get_ram_ptr(&s->vram_bar), memory_region_get_ram_ptr(&s->ram_bar), &vigs_dpy_ops, s, backend, vigs_render_queue); if (!s->server) { goto fail; } vigs_wsi = s->dev.wsi = &s->server->wsi; VIGS_LOG_INFO("VIGS initialized"); VIGS_LOG_DEBUG("vram_size = %u", s->vram_size); VIGS_LOG_DEBUG("ram_size = %u", s->ram_size); return 0; fail: if (backend) { backend->destroy(backend); } if (s->fence_ack_bh) { qemu_bh_delete(s->fence_ack_bh); } if (s->fenceman) { vigs_fenceman_destroy(s->fenceman); } memory_region_destroy(&s->io_bar); memory_region_destroy(&s->ram_bar); memory_region_destroy(&s->vram_bar); vigs_log_cleanup(); return -1; }
/* create the shared memory BAR when we are not using the server, so we can * create the BAR and map the memory immediately */ static int create_shared_memory_BAR(IVShmemState *s, IVShmemFile f[IVSHMEM_MAX_FILES], int num_files) { void * ptr_data, * virt_area; uint64_t total_size = 0, one_gb_align; int i, fd_zero; /* open /dev/zero for mmap */ fd_zero = open("/dev/zero", O_RDWR); if (fd_zero < 0) { fprintf(stderr, "ivshmem: opening /dev/zero failed (%s)\n", strerror(errno)); return -1; } /* Get virtual area of ivshmem_size plus 1GB for alignment. * virt_area later will be used to remap files backed up by hugepages (1GB * or 2MB). Therefore and due to mmap restrictions virt_area will have to * be aligned to both 1GB and 2MB (1GB will cover both scenarios). In order * to be sure we can freely align virt_area up to 1GB we reserve vshmem_size * plus 1GB */ virt_area = mmap(NULL, s->ivshmem_size + ONE_GB, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd_zero, 0); if (virt_area == MAP_FAILED) { fprintf(stderr, "ivshmem: mmap /dev/zero failed (%s)\n", strerror(errno)); return -1; } /* Calculate 1GB boundary alignment covering 1GB and 2MB hugepage cases */ one_gb_align = ONE_GB - ((uint64_t) virt_area % ONE_GB); munmap(virt_area, s->ivshmem_size + ONE_GB); close(fd_zero); /* Finally align virt_area to 1GB boundary. */ virt_area += one_gb_align; /* at this point virt_area contains a virtual address that where we can * safely use to mmap all ivshmem files. * Proceed to mmap all ivshmem files so. */ for (i = 0; i < num_files; i++) { /* remap file into the start of virtual area */ ptr_data = mmap(virt_area + total_size, f[i].size, PROT_READ|PROT_WRITE, MAP_SHARED | MAP_FIXED, f[i].fd, f[i].offset); /* we need to make sure we get _exactly_ what we want */ if (ptr_data == MAP_FAILED || ptr_data != virt_area + total_size) { fprintf(stderr, "ivshmem: mmap failed (%s)\n", strerror(errno)); return -1; } total_size += f[i].size; } memcpy(s->shm_fds, f, sizeof(s->shm_fds)); memory_region_init_ram_ptr(&s->ivshmem, "ivshmem.bar2", s->ivshmem_size, virt_area); vmstate_register_ram(&s->ivshmem, &s->dev.qdev); memory_region_add_subregion(&s->bar, 0, &s->ivshmem); /* region for shared memory */ pci_register_bar(&s->dev, 2, s->ivshmem_attr, &s->bar); return 0; }
/* EBUS (Eight bit bus) bridge */ static void ebus_realize(PCIDevice *pci_dev, Error **errp) { EbusState *s = EBUS(pci_dev); SysBusDevice *sbd; DeviceState *dev; qemu_irq *isa_irq; DriveInfo *fd[MAX_FD]; int i; s->isa_bus = isa_bus_new(DEVICE(pci_dev), get_system_memory(), pci_address_space_io(pci_dev), errp); if (!s->isa_bus) { error_setg(errp, "unable to instantiate EBUS ISA bus"); return; } /* ISA bus */ isa_irq = qemu_allocate_irqs(ebus_isa_irq_handler, s, ISA_NUM_IRQS); isa_bus_irqs(s->isa_bus, isa_irq); qdev_init_gpio_out_named(DEVICE(s), s->isa_bus_irqs, "isa-irq", ISA_NUM_IRQS); /* Serial ports */ i = 0; if (s->console_serial_base) { serial_mm_init(pci_address_space(pci_dev), s->console_serial_base, 0, NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN); i++; } serial_hds_isa_init(s->isa_bus, i, MAX_SERIAL_PORTS); /* Parallel ports */ parallel_hds_isa_init(s->isa_bus, MAX_PARALLEL_PORTS); /* Keyboard */ isa_create_simple(s->isa_bus, "i8042"); /* Floppy */ for (i = 0; i < MAX_FD; i++) { fd[i] = drive_get(IF_FLOPPY, 0, i); } dev = DEVICE(isa_create(s->isa_bus, TYPE_ISA_FDC)); if (fd[0]) { qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fd[0]), &error_abort); } if (fd[1]) { qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fd[1]), &error_abort); } qdev_prop_set_uint32(dev, "dma", -1); qdev_init_nofail(dev); /* Power */ dev = qdev_create(NULL, TYPE_SUN4U_POWER); qdev_init_nofail(dev); sbd = SYS_BUS_DEVICE(dev); memory_region_add_subregion(pci_address_space_io(pci_dev), 0x7240, sysbus_mmio_get_region(sbd, 0)); /* PCI */ pci_dev->config[0x04] = 0x06; // command = bus master, pci mem pci_dev->config[0x05] = 0x00; pci_dev->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error pci_dev->config[0x07] = 0x03; // status = medium devsel pci_dev->config[0x09] = 0x00; // programming i/f pci_dev->config[0x0D] = 0x0a; // latency_timer memory_region_init_alias(&s->bar0, OBJECT(s), "bar0", get_system_io(), 0, 0x1000000); pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0); memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", get_system_io(), 0, 0x8000); pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1); }