diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index e666dd4ff0..3cb97c9a29 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -29,7 +29,6 @@ struct VirtIOBlockDataPlane { bool starting; bool stopping; - bool disabled; VirtIOBlkConf *conf; @@ -185,6 +184,17 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) g_free(s); } +static void virtio_blk_data_plane_handle_output(VirtIODevice *vdev, + VirtQueue *vq) +{ + VirtIOBlock *s = (VirtIOBlock *)vdev; + + assert(s->dataplane); + assert(s->dataplane_started); + + virtio_blk_handle_vq(s, vq); +} + /* Context: QEMU global mutex held */ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) { @@ -227,14 +237,15 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) /* Get this show started by hooking up our callbacks */ aio_context_acquire(s->ctx); - virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, true, true); + virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, + virtio_blk_data_plane_handle_output); aio_context_release(s->ctx); return; fail_host_notifier: k->set_guest_notifiers(qbus->parent, 1, false); fail_guest_notifiers: - s->disabled = true; + vblk->dataplane_disabled = true; s->starting = false; vblk->dataplane_started = true; } @@ -251,8 +262,8 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) } /* Better luck next time. */ - if (s->disabled) { - s->disabled = false; + if (vblk->dataplane_disabled) { + vblk->dataplane_disabled = false; vblk->dataplane_started = false; return; } @@ -262,7 +273,7 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) aio_context_acquire(s->ctx); /* Stop notifications for new requests from guest */ - virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, false, false); + virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, NULL); /* Drain and switch bs back to the QEMU main loop */ blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context()); diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 870d345244..3f88f8cf59 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -54,7 +54,7 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) stb_p(&req->in->status, status); virtqueue_push(s->vq, &req->elem, req->in_len); - if (s->dataplane) { + if (s->dataplane_started && !s->dataplane_disabled) { virtio_blk_data_plane_notify(s->dataplane); } else { virtio_notify(vdev, s->vq); @@ -578,20 +578,11 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb) } } -static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) +void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) { - VirtIOBlock *s = VIRTIO_BLK(vdev); VirtIOBlockReq *req; MultiReqBuffer mrb = {}; - /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start - * dataplane here instead of waiting for .set_status(). - */ - if (s->dataplane && !s->dataplane_started) { - virtio_blk_data_plane_start(s->dataplane); - return; - } - blk_io_plug(s->blk); while ((req = virtio_blk_get_request(s))) { @@ -605,6 +596,22 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) blk_io_unplug(s->blk); } +static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOBlock *s = (VirtIOBlock *)vdev; + + if (s->dataplane) { + /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start + * dataplane here instead of waiting for .set_status(). + */ + virtio_blk_data_plane_start(s->dataplane); + if (!s->dataplane_disabled) { + return; + } + } + virtio_blk_handle_vq(s, vq); +} + static void virtio_blk_dma_restart_bh(void *opaque) { VirtIOBlock *s = opaque; diff --git a/hw/core/loader.c b/hw/core/loader.c index 6b949fe44f..c0499571c3 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -1053,6 +1053,20 @@ void rom_set_fw(FWCfgState *f) fw_cfg = f; } +void rom_set_order_override(int order) +{ + if (!fw_cfg) + return; + fw_cfg_set_order_override(fw_cfg, order); +} + +void rom_reset_order_override(void) +{ + if (!fw_cfg) + return; + fw_cfg_reset_order_override(fw_cfg); +} + static Rom *find_rom(hwaddr addr) { Rom *rom; diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 2ac97c4f29..99437e0b78 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1406,6 +1406,7 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) { DeviceState *dev = NULL; + rom_set_order_override(FW_CFG_ORDER_OVERRIDE_VGA); if (pci_bus) { PCIDevice *pcidev = pci_vga_init(pci_bus); dev = pcidev ? &pcidev->qdev : NULL; @@ -1413,6 +1414,7 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) ISADevice *isadev = isa_vga_init(isa_bus); dev = isadev ? DEVICE(isadev) : NULL; } + rom_reset_order_override(); return dev; } @@ -1541,6 +1543,7 @@ void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus) { int i; + rom_set_order_override(FW_CFG_ORDER_OVERRIDE_NIC); for (i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; @@ -1550,6 +1553,7 @@ void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus) pci_nic_init_nofail(nd, pci_bus, "e1000", NULL); } } + rom_reset_order_override(); } void pc_pci_device_init(PCIBus *pci_bus) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 6a69b23abc..7f50116bc7 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -434,6 +434,7 @@ static void pc_i440fx_2_5_machine_options(MachineClass *m) m->alias = NULL; m->is_default = 0; pcmc->save_tsc_khz = false; + m->legacy_fw_cfg_order = 1; SET_MACHINE_COMPAT(m, PC_COMPAT_2_5); } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 9ee939b4c2..04aae8958c 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -298,6 +298,7 @@ static void pc_q35_2_5_machine_options(MachineClass *m) pc_q35_2_6_machine_options(m); m->alias = NULL; pcmc->save_tsc_khz = false; + m->legacy_fw_cfg_order = 1; SET_MACHINE_COMPAT(m, PC_COMPAT_2_5); } diff --git a/hw/ide/piix.c b/hw/ide/piix.c index df46147c65..0a4cbcbcbb 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -258,22 +258,10 @@ static const TypeInfo piix3_ide_info = { .class_init = piix3_ide_class_init, }; -static void piix3_ide_xen_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->realize = pci_piix_ide_realize; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1; - k->class_id = PCI_CLASS_STORAGE_IDE; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); -} - static const TypeInfo piix3_ide_xen_info = { .name = "piix3-ide-xen", .parent = TYPE_PCI_IDE, - .class_init = piix3_ide_xen_class_init, + .class_init = piix3_ide_class_init, }; static void piix4_ide_class_init(ObjectClass *klass, void *data) diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c index 5df9089218..2f2e989778 100644 --- a/hw/misc/pci-testdev.c +++ b/hw/misc/pci-testdev.c @@ -239,6 +239,7 @@ static void pci_testdev_realize(PCIDevice *pci_dev, Error **errp) uint8_t *pci_conf; char *name; int r, i; + bool fastmmio = kvm_ioeventfd_any_length_enabled(); pci_conf = pci_dev->config; @@ -261,8 +262,12 @@ static void pci_testdev_realize(PCIDevice *pci_dev, Error **errp) memcpy(test->hdr->name, name, strlen(name) + 1); g_free(name); test->hdr->offset = cpu_to_le32(IOTEST_SIZE(i) + i * IOTEST_ACCESS_WIDTH); - test->size = IOTEST_ACCESS_WIDTH; test->match_data = strcmp(IOTEST_TEST(i), "wildcard-eventfd"); + if (fastmmio && IOTEST_IS_MEM(i) && !test->match_data) { + test->size = 0; + } else { + test->size = IOTEST_ACCESS_WIDTH; + } test->hdr->test = i; test->hdr->data = test->match_data ? IOTEST_DATAMATCH : IOTEST_NOMATCH; test->hdr->width = IOTEST_ACCESS_WIDTH; diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index d96932f6ca..999f480280 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -28,6 +28,7 @@ #include "hw/isa/isa.h" #include "hw/nvram/fw_cfg.h" #include "hw/sysbus.h" +#include "hw/boards.h" #include "trace.h" #include "qemu/error-report.h" #include "qemu/config-file.h" @@ -69,11 +70,14 @@ struct FWCfgState { /*< public >*/ FWCfgEntry entries[2][FW_CFG_MAX_ENTRY]; + int entry_order[FW_CFG_MAX_ENTRY]; FWCfgFiles *files; uint16_t cur_entry; uint32_t cur_offset; Notifier machine_ready; + int fw_cfg_order_override; + bool dma_enabled; dma_addr_t dma_addr; AddressSpace *dma_as; @@ -665,12 +669,87 @@ void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value) fw_cfg_add_bytes(s, key, copy, sizeof(value)); } +void fw_cfg_set_order_override(FWCfgState *s, int order) +{ + assert(s->fw_cfg_order_override == 0); + s->fw_cfg_order_override = order; +} + +void fw_cfg_reset_order_override(FWCfgState *s) +{ + assert(s->fw_cfg_order_override != 0); + s->fw_cfg_order_override = 0; +} + +/* + * This is the legacy order list. For legacy systems, files are in + * the fw_cfg in the order defined below, by the "order" value. Note + * that some entries (VGA ROMs, NIC option ROMS, etc.) go into a + * specific area, but there may be more than one and they occur in the + * order that the user specifies them on the command line. Those are + * handled in a special manner, using the order override above. + * + * For non-legacy, the files are sorted by filename to avoid this kind + * of complexity in the future. + * + * This is only for x86, other arches don't implement versioning so + * they won't set legacy mode. + */ +static struct { + const char *name; + int order; +} fw_cfg_order[] = { + { "etc/boot-menu-wait", 10 }, + { "bootsplash.jpg", 11 }, + { "bootsplash.bmp", 12 }, + { "etc/boot-fail-wait", 15 }, + { "etc/smbios/smbios-tables", 20 }, + { "etc/smbios/smbios-anchor", 30 }, + { "etc/e820", 40 }, + { "etc/reserved-memory-end", 50 }, + { "genroms/kvmvapic.bin", 55 }, + { "genroms/linuxboot.bin", 60 }, + { }, /* VGA ROMs from pc_vga_init come here, 70. */ + { }, /* NIC option ROMs from pc_nic_init come here, 80. */ + { "etc/system-states", 90 }, + { }, /* User ROMs come here, 100. */ + { }, /* Device FW comes here, 110. */ + { "etc/extra-pci-roots", 120 }, + { "etc/acpi/tables", 130 }, + { "etc/table-loader", 140 }, + { "etc/tpm/log", 150 }, + { "etc/acpi/rsdp", 160 }, + { "bootorder", 170 }, + +#define FW_CFG_ORDER_OVERRIDE_LAST 200 +}; + +static int get_fw_cfg_order(FWCfgState *s, const char *name) +{ + int i; + + if (s->fw_cfg_order_override > 0) + return s->fw_cfg_order_override; + + for (i = 0; i < ARRAY_SIZE(fw_cfg_order); i++) { + if (fw_cfg_order[i].name == NULL) + continue; + if (strcmp(name, fw_cfg_order[i].name) == 0) + return fw_cfg_order[i].order; + } + /* Stick unknown stuff at the end. */ + error_report("warning: Unknown firmware file in legacy mode: %s\n", name); + return FW_CFG_ORDER_OVERRIDE_LAST; +} + void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, FWCfgReadCallback callback, void *callback_opaque, void *data, size_t len) { - int i, index; + int i, index, count; size_t dsize; + MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); + int order = 0; if (!s->files) { dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS; @@ -678,13 +757,48 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, s->files, dsize); } - index = be32_to_cpu(s->files->count); - assert(index < FW_CFG_FILE_SLOTS); + count = be32_to_cpu(s->files->count); + assert(count < FW_CFG_FILE_SLOTS); - pstrcpy(s->files->f[index].name, sizeof(s->files->f[index].name), - filename); - for (i = 0; i < index; i++) { - if (strcmp(s->files->f[index].name, s->files->f[i].name) == 0) { + /* Find the insertion point. */ + if (mc->legacy_fw_cfg_order) { + /* + * Sort by order. For files with the same order, we keep them + * in the sequence in which they were added. + */ + order = get_fw_cfg_order(s, filename); + for (index = count; + index > 0 && order < s->entry_order[index - 1]; + index--); + } else { + /* Sort by file name. */ + for (index = count; + index > 0 && strcmp(filename, s->files->f[index - 1].name) < 0; + index--); + } + + /* + * Move all the entries from the index point and after down one + * to create a slot for the new entry. Because calculations are + * being done with the index, make it so that "i" is the current + * index and "i - 1" is the one being copied from, thus the + * unusual start and end in the for statement. + */ + for (i = count + 1; i > index; i--) { + s->files->f[i] = s->files->f[i - 1]; + s->files->f[i].select = cpu_to_be16(FW_CFG_FILE_FIRST + i); + s->entries[0][FW_CFG_FILE_FIRST + i] = + s->entries[0][FW_CFG_FILE_FIRST + i - 1]; + s->entry_order[i] = s->entry_order[i - 1]; + } + + memset(&s->files->f[index], 0, sizeof(FWCfgFile)); + memset(&s->entries[0][FW_CFG_FILE_FIRST + index], 0, sizeof(FWCfgEntry)); + + pstrcpy(s->files->f[index].name, sizeof(s->files->f[index].name), filename); + for (i = 0; i <= count; i++) { + if (i != index && + strcmp(s->files->f[index].name, s->files->f[i].name) == 0) { error_report("duplicate fw_cfg file name: %s", s->files->f[index].name); exit(1); @@ -696,9 +810,10 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, s->files->f[index].size = cpu_to_be32(len); s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index); + s->entry_order[index] = order; trace_fw_cfg_add_file(s, index, s->files->f[index].name, len); - s->files->count = cpu_to_be32(index+1); + s->files->count = cpu_to_be32(count+1); } void fw_cfg_add_file(FWCfgState *s, const char *filename, diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c index 5c40708ba8..2404e7ebae 100644 --- a/hw/pci-bridge/i82801b11.c +++ b/hw/pci-bridge/i82801b11.c @@ -78,6 +78,14 @@ err_bridge: return rc; } +static const VMStateDescription i82801b11_bridge_dev_vmstate = { + .name = "i82801b11_bridge", + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(parent_obj, PCIBridge), + VMSTATE_END_OF_LIST() + } +}; + static void i82801b11_bridge_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -89,6 +97,7 @@ static void i82801b11_bridge_class_init(ObjectClass *klass, void *data) k->revision = ICH9_D2P_A2_REVISION; k->init = i82801b11_bridge_initfn; k->config_write = pci_bridge_write_config; + dc->vmsd = &i82801b11_bridge_dev_vmstate; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index 5e7e546b99..ba320bd857 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -249,7 +249,7 @@ static int pxb_dev_init_common(PCIDevice *dev, bool pcie) PCI_HOST_BRIDGE(ds)->bus = bus; if (pxb_register_bus(dev, bus)) { - return -EINVAL; + goto err_register_bus; } qdev_init_nofail(ds); @@ -263,6 +263,12 @@ static int pxb_dev_init_common(PCIDevice *dev, bool pcie) pxb_dev_list = g_list_insert_sorted(pxb_dev_list, pxb, pxb_compare); return 0; + +err_register_bus: + object_unref(OBJECT(bds)); + object_unparent(OBJECT(bus)); + object_unref(OBJECT(ds)); + return -EINVAL; } static int pxb_dev_initfn(PCIDevice *dev) diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index b44ac5dfa0..1a49f1e4b7 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -38,7 +38,35 @@ void virtio_scsi_set_iothread(VirtIOSCSI *s, IOThread *iothread) } } -static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n) +static void virtio_scsi_data_plane_handle_cmd(VirtIODevice *vdev, + VirtQueue *vq) +{ + VirtIOSCSI *s = (VirtIOSCSI *)vdev; + + assert(s->ctx && s->dataplane_started); + virtio_scsi_handle_cmd_vq(s, vq); +} + +static void virtio_scsi_data_plane_handle_ctrl(VirtIODevice *vdev, + VirtQueue *vq) +{ + VirtIOSCSI *s = VIRTIO_SCSI(vdev); + + assert(s->ctx && s->dataplane_started); + virtio_scsi_handle_ctrl_vq(s, vq); +} + +static void virtio_scsi_data_plane_handle_event(VirtIODevice *vdev, + VirtQueue *vq) +{ + VirtIOSCSI *s = VIRTIO_SCSI(vdev); + + assert(s->ctx && s->dataplane_started); + virtio_scsi_handle_event_vq(s, vq); +} + +static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n, + void (*fn)(VirtIODevice *vdev, VirtQueue *vq)) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); @@ -53,7 +81,7 @@ static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n) return rc; } - virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, true, true); + virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, fn); return 0; } @@ -70,10 +98,10 @@ static void virtio_scsi_clear_aio(VirtIOSCSI *s) VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); int i; - virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx, false, false); - virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx, false, false); + virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx, NULL); + virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx, NULL); for (i = 0; i < vs->conf.num_queues; i++) { - virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx, false, false); + virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx, NULL); } } @@ -104,16 +132,19 @@ void virtio_scsi_dataplane_start(VirtIOSCSI *s) } aio_context_acquire(s->ctx); - rc = virtio_scsi_vring_init(s, vs->ctrl_vq, 0); + rc = virtio_scsi_vring_init(s, vs->ctrl_vq, 0, + virtio_scsi_data_plane_handle_ctrl); if (rc) { goto fail_vrings; } - rc = virtio_scsi_vring_init(s, vs->event_vq, 1); + rc = virtio_scsi_vring_init(s, vs->event_vq, 1, + virtio_scsi_data_plane_handle_event); if (rc) { goto fail_vrings; } for (i = 0; i < vs->conf.num_queues; i++) { - rc = virtio_scsi_vring_init(s, vs->cmd_vqs[i], i + 2); + rc = virtio_scsi_vring_init(s, vs->cmd_vqs[i], i + 2, + virtio_scsi_data_plane_handle_cmd); if (rc) { goto fail_vrings; } diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index ade49727d6..30415c6a92 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -68,7 +68,7 @@ static void virtio_scsi_complete_req(VirtIOSCSIReq *req) qemu_iovec_from_buf(&req->resp_iov, 0, &req->resp, req->resp_size); virtqueue_push(vq, &req->elem, req->qsgl.size + req->resp_iov.size); - if (s->dataplane_started) { + if (s->dataplane_started && !s->dataplane_fenced) { virtio_scsi_dataplane_notify(vdev, req); } else { virtio_notify(vdev, vq); @@ -374,7 +374,7 @@ fail: return ret; } -void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) +static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) { VirtIODevice *vdev = (VirtIODevice *)s; uint32_t type; @@ -412,20 +412,28 @@ void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) } } -static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) +void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq) { - VirtIOSCSI *s = (VirtIOSCSI *)vdev; VirtIOSCSIReq *req; - if (s->ctx && !s->dataplane_started) { - virtio_scsi_dataplane_start(s); - return; - } while ((req = virtio_scsi_pop_req(s, vq))) { virtio_scsi_handle_ctrl_req(s, req); } } +static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOSCSI *s = (VirtIOSCSI *)vdev; + + if (s->ctx) { + virtio_scsi_dataplane_start(s); + if (!s->dataplane_fenced) { + return; + } + } + virtio_scsi_handle_ctrl_vq(s, vq); +} + static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req) { /* Sense data is not in req->resp and is copied separately @@ -508,7 +516,7 @@ static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req) virtio_scsi_complete_cmd_req(req); } -bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) +static bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) { VirtIOSCSICommon *vs = &s->parent_obj; SCSIDevice *d; @@ -550,7 +558,7 @@ bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) return true; } -void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req) +static void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req) { SCSIRequest *sreq = req->sreq; if (scsi_req_enqueue(sreq)) { @@ -560,17 +568,11 @@ void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req) scsi_req_unref(sreq); } -static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) +void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) { - /* use non-QOM casts in the data path */ - VirtIOSCSI *s = (VirtIOSCSI *)vdev; VirtIOSCSIReq *req, *next; QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); - if (s->ctx && !s->dataplane_started) { - virtio_scsi_dataplane_start(s); - return; - } while ((req = virtio_scsi_pop_req(s, vq))) { if (virtio_scsi_handle_cmd_req_prepare(s, req)) { QTAILQ_INSERT_TAIL(&reqs, req, next); @@ -582,6 +584,20 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) } } +static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) +{ + /* use non-QOM casts in the data path */ + VirtIOSCSI *s = (VirtIOSCSI *)vdev; + + if (s->ctx) { + virtio_scsi_dataplane_start(s); + if (!s->dataplane_fenced) { + return; + } + } + virtio_scsi_handle_cmd_vq(s, vq); +} + static void virtio_scsi_get_config(VirtIODevice *vdev, uint8_t *config) { @@ -725,17 +741,24 @@ out: } } +void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq) +{ + if (s->events_dropped) { + virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0); + } +} + static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq) { VirtIOSCSI *s = VIRTIO_SCSI(vdev); - if (s->ctx && !s->dataplane_started) { + if (s->ctx) { virtio_scsi_dataplane_start(s); - return; - } - if (s->events_dropped) { - virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0); + if (!s->dataplane_fenced) { + return; + } } + virtio_scsi_handle_event_vq(s, vq); } static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense) @@ -773,7 +796,7 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, VirtIOSCSI *s = VIRTIO_SCSI(vdev); SCSIDevice *sd = SCSI_DEVICE(dev); - if (s->ctx && !s->dataplane_disabled) { + if (s->ctx && !s->dataplane_fenced) { VirtIOSCSIBlkChangeNotifier *insert_notifier, *remove_notifier; if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) { diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 22ad25cc97..c74101e479 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -426,6 +426,10 @@ static int virtio_balloon_load_device(VirtIODevice *vdev, QEMUFile *f, s->num_pages = qemu_get_be32(f); s->actual = qemu_get_be32(f); + + if (balloon_stats_enabled(s)) { + balloon_stats_change_timer(s, s->stats_poll_interval); + } return 0; } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 14d5d91397..f745c4abd0 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -96,6 +96,7 @@ struct VirtQueue uint16_t vector; void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq); + void (*handle_aio_output)(VirtIODevice *vdev, VirtQueue *vq); VirtIODevice *vdev; EventNotifier guest_notifier; EventNotifier host_notifier; @@ -1088,7 +1089,17 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align) virtio_queue_update_rings(vdev, n); } -void virtio_queue_notify_vq(VirtQueue *vq) +static void virtio_queue_notify_aio_vq(VirtQueue *vq) +{ + if (vq->vring.desc && vq->handle_aio_output) { + VirtIODevice *vdev = vq->vdev; + + trace_virtio_queue_notify(vdev, vq - vdev->vq, vq); + vq->handle_aio_output(vdev, vq); + } +} + +static void virtio_queue_notify_vq(VirtQueue *vq) { if (vq->vring.desc && vq->handle_output) { VirtIODevice *vdev = vq->vdev; @@ -1143,6 +1154,7 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, vdev->vq[i].vring.num_default = queue_size; vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN; vdev->vq[i].handle_output = handle_output; + vdev->vq[i].handle_aio_output = NULL; return &vdev->vq[i]; } @@ -1780,6 +1792,31 @@ EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq) return &vq->guest_notifier; } +static void virtio_queue_host_notifier_aio_read(EventNotifier *n) +{ + VirtQueue *vq = container_of(n, VirtQueue, host_notifier); + if (event_notifier_test_and_clear(n)) { + virtio_queue_notify_aio_vq(vq); + } +} + +void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, + void (*handle_output)(VirtIODevice *, + VirtQueue *)) +{ + if (handle_output) { + vq->handle_aio_output = handle_output; + aio_set_event_notifier(ctx, &vq->host_notifier, true, + virtio_queue_host_notifier_aio_read); + } else { + aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL); + /* Test and clear notifier before after disabling event, + * in case poll callback didn't have time to run. */ + virtio_queue_host_notifier_aio_read(&vq->host_notifier); + vq->handle_aio_output = NULL; + } +} + static void virtio_queue_host_notifier_read(EventNotifier *n) { VirtQueue *vq = container_of(n, VirtQueue, host_notifier); @@ -1788,22 +1825,6 @@ static void virtio_queue_host_notifier_read(EventNotifier *n) } } -void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, - bool assign, bool set_handler) -{ - if (assign && set_handler) { - aio_set_event_notifier(ctx, &vq->host_notifier, true, - virtio_queue_host_notifier_read); - } else { - aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL); - } - if (!assign) { - /* Test and clear notifier before after disabling event, - * in case poll callback didn't have time to run. */ - virtio_queue_host_notifier_read(&vq->host_notifier); - } -} - void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign, bool set_handler) { diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index 66f48ec04f..2c994b351a 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -369,6 +369,7 @@ build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets, const char *oem_id, const char *oem_table_id); int -build_append_named_dword(GArray *array, const char *name_format, ...); +build_append_named_dword(GArray *array, const char *name_format, ...) +GCC_FMT_ATTR(2, 3); #endif diff --git a/include/hw/boards.h b/include/hw/boards.h index aad5f2a99f..8d4fe56b5f 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -108,7 +108,8 @@ struct MachineClass { no_cdrom:1, no_sdcard:1, has_dynamic_sysbus:1, - pci_allow_0_address:1; + pci_allow_0_address:1, + legacy_fw_cfg_order:1; int is_default; const char *default_machine_opts; const char *default_boot_order; diff --git a/include/hw/loader.h b/include/hw/loader.h index b3d1358d9c..4879b63a2f 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -128,6 +128,8 @@ int rom_add_elf_program(const char *name, void *data, size_t datasize, size_t romsize, hwaddr addr); int rom_check_and_register_reset(void); void rom_set_fw(FWCfgState *f); +void rom_set_order_override(int order); +void rom_reset_order_override(void); int rom_copy(uint8_t *dest, hwaddr addr, size_t size); void *rom_ptr(hwaddr addr); void hmp_info_roms(Monitor *mon, const QDict *qdict); diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index d5169895dc..d00811258d 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -11,6 +11,14 @@ typedef struct FWCfgFile { char name[FW_CFG_MAX_FILE_PATH]; } FWCfgFile; +#define FW_CFG_ORDER_OVERRIDE_VGA 70 +#define FW_CFG_ORDER_OVERRIDE_NIC 80 +#define FW_CFG_ORDER_OVERRIDE_USER 100 +#define FW_CFG_ORDER_OVERRIDE_DEVICE 110 + +void fw_cfg_set_order_override(FWCfgState *fw_cfg, int order); +void fw_cfg_reset_order_override(FWCfgState *fw_cfg); + typedef struct FWCfgFiles { uint32_t count; FWCfgFile f[]; diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index ae84d92107..8f2b056515 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -53,6 +53,7 @@ typedef struct VirtIOBlock { unsigned short sector_mask; bool original_wce; VMChangeStateEntry *change; + bool dataplane_disabled; bool dataplane_started; struct VirtIOBlockDataPlane *dataplane; } VirtIOBlock; @@ -85,4 +86,6 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb); void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb); +void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq); + #endif diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 209eaa4466..ba2f5ce07c 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -91,7 +91,6 @@ typedef struct VirtIOSCSI { bool dataplane_started; bool dataplane_starting; bool dataplane_stopping; - bool dataplane_disabled; bool dataplane_fenced; Error *blocker; uint32_t host_features; @@ -140,9 +139,9 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, HandleOutput cmd); void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); -void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req); -bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req); -void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req); +void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq); +void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq); +void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq); void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req); void virtio_scsi_free_req(VirtIOSCSIReq *req); void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 2b5b248b0c..6a37065c23 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -251,8 +251,8 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq); void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign, bool set_handler); void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, - bool assign, bool set_handler); -void virtio_queue_notify_vq(VirtQueue *vq); + void (*fn)(VirtIODevice *, + VirtQueue *)); void virtio_irq(VirtQueue *vq); VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector); VirtQueue *virtio_vector_next_queue(VirtQueue *vq); diff --git a/tests/Makefile b/tests/Makefile index 651d8b2dac..9de959847b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -83,7 +83,7 @@ check-unit-y += tests/test-crypto-cipher$(EXESUF) check-unit-y += tests/test-crypto-secret$(EXESUF) check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlscredsx509$(EXESUF) check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlssession$(EXESUF) -check-unit-$(CONFIG_LINUX) += tests/test-qga$(EXESUF) +#check-unit-$(CONFIG_LINUX) += tests/test-qga$(EXESUF) check-unit-y += tests/test-timed-average$(EXESUF) check-unit-y += tests/test-io-task$(EXESUF) check-unit-y += tests/test-io-channel-socket$(EXESUF) diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 0a80ddf04b..03528140c1 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -432,7 +432,7 @@ static bool load_asl(GArray *sdts, AcpiSdtTable *sdt) #define COMMENT_END "*/" #define DEF_BLOCK "DefinitionBlock (" -#define BLOCK_NAME_END ".aml" +#define BLOCK_NAME_END "," static GString *normalize_asl(gchar *asl_code) { diff --git a/vl.c b/vl.c index 36293360e0..9df534ff14 100644 --- a/vl.c +++ b/vl.c @@ -2297,8 +2297,9 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp) gchar *buf; size_t size; const char *name, *file, *str; + FWCfgState *fw_cfg = (FWCfgState *) opaque; - if (opaque == NULL) { + if (fw_cfg == NULL) { error_report("fw_cfg device not available"); return -1; } @@ -2332,7 +2333,10 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp) return -1; } } - fw_cfg_add_file((FWCfgState *)opaque, name, buf, size); + /* For legacy, keep user files in a specific global order. */ + fw_cfg_set_order_override(fw_cfg, FW_CFG_ORDER_OVERRIDE_USER); + fw_cfg_add_file(fw_cfg, name, buf, size); + fw_cfg_reset_order_override(fw_cfg); return 0; } @@ -4535,10 +4539,12 @@ int main(int argc, char **argv, char **envp) igd_gfx_passthru(); /* init generic devices */ + rom_set_order_override(FW_CFG_ORDER_OVERRIDE_DEVICE); if (qemu_opts_foreach(qemu_find_opts("device"), device_init_func, NULL, NULL)) { exit(1); } + rom_reset_order_override(); /* Did we create any drives that we failed to create a device for? */ drive_check_orphaned();