diff --git a/MAINTAINERS b/MAINTAINERS index d6de2004537ca83014bd185c7e323c31fdeaae2e..e2d74d7ec397aa5c5ddd974a296e00f894ffc4f1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2135,6 +2135,8 @@ Migration M: Juan Quintela M: Dr. David Alan Gilbert S: Maintained +F: hw/core/vmstate-if.c +F: include/hw/vmstate-if.h F: include/migration/ F: migration/ F: scripts/vmstate-static-checker.py diff --git a/docs/devel/migration.rst b/docs/devel/migration.rst index 220059679ac91cb8487d61bd22314a3c82632a2e..cc6f839fce9445c64fa5f3c14afad704cdc471e4 100644 --- a/docs/devel/migration.rst +++ b/docs/devel/migration.rst @@ -183,8 +183,7 @@ another to load the state back. .. code:: c - int register_savevm_live(DeviceState *dev, - const char *idstr, + int register_savevm_live(const char *idstr, int instance_id, int version_id, SaveVMHandlers *ops, diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index f8481d959f6068cb0c4e38dfeaf0d70240ffa634..54c51583d824082bea6aa1bec56181eca848efa4 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -8,6 +8,7 @@ common-obj-y += irq.o common-obj-y += hotplug.o common-obj-$(CONFIG_SOFTMMU) += nmi.o common-obj-$(CONFIG_SOFTMMU) += vm-change-state-handler.o +common-obj-y += vmstate-if.o common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o common-obj-$(CONFIG_XILINX_AXI) += stream.o diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 4b32f2f46d8c858f2335f9472265d97104079b05..13931b1117f9f58d12248ddef7a94da373699021 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -1048,9 +1048,18 @@ static void device_unparent(Object *obj) } } +static char * +device_vmstate_if_get_id(VMStateIf *obj) +{ + DeviceState *dev = DEVICE(obj); + + return qdev_get_dev_path(dev); +} + static void device_class_init(ObjectClass *class, void *data) { DeviceClass *dc = DEVICE_CLASS(class); + VMStateIfClass *vc = VMSTATE_IF_CLASS(class); class->unparent = device_unparent; @@ -1062,6 +1071,7 @@ static void device_class_init(ObjectClass *class, void *data) */ dc->hotpluggable = true; dc->user_creatable = true; + vc->get_id = device_vmstate_if_get_id; } void device_class_set_parent_reset(DeviceClass *dc, @@ -1119,6 +1129,10 @@ static const TypeInfo device_type_info = { .class_init = device_class_init, .abstract = true, .class_size = sizeof(DeviceClass), + .interfaces = (InterfaceInfo[]) { + { TYPE_VMSTATE_IF }, + { } + } }; static void qdev_register_types(void) diff --git a/hw/core/vmstate-if.c b/hw/core/vmstate-if.c new file mode 100644 index 0000000000000000000000000000000000000000..bf453620fed43e7708d358dbc1e85d25300f5435 --- /dev/null +++ b/hw/core/vmstate-if.c @@ -0,0 +1,23 @@ +/* + * VMState interface + * + * Copyright (c) 2009-2019 Red Hat Inc + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/vmstate-if.h" + +static const TypeInfo vmstate_if_info = { + .name = TYPE_VMSTATE_IF, + .parent = TYPE_INTERFACE, + .class_size = sizeof(VMStateIfClass), +}; + +static void vmstate_register_types(void) +{ + type_register_static(&vmstate_if_info); +} + +type_init(vmstate_register_types); diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index ecc4f5bcf000528ecb0850ba6d270b4bb099fce9..bf8e6ca4c923b17ef95e24f78586d094f99bc11c 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2153,21 +2153,6 @@ vmxnet3_cleanup_msi(VMXNET3State *s) msi_uninit(d); } -static void -vmxnet3_msix_save(QEMUFile *f, void *opaque) -{ - PCIDevice *d = PCI_DEVICE(opaque); - msix_save(d, f); -} - -static int -vmxnet3_msix_load(QEMUFile *f, void *opaque, int version_id) -{ - PCIDevice *d = PCI_DEVICE(opaque); - msix_load(d, f); - return 0; -} - static const MemoryRegionOps b0_ops = { .read = vmxnet3_io_bar0_read, .write = vmxnet3_io_bar0_write, @@ -2188,11 +2173,6 @@ static const MemoryRegionOps b1_ops = { }, }; -static SaveVMHandlers savevm_vmxnet3_msix = { - .save_state = vmxnet3_msix_save, - .load_state = vmxnet3_msix_load, -}; - static uint64_t vmxnet3_device_serial_num(VMXNET3State *s) { uint64_t dsn_payload; @@ -2215,7 +2195,6 @@ static uint64_t vmxnet3_device_serial_num(VMXNET3State *s) static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp) { - DeviceState *dev = DEVICE(pci_dev); VMXNET3State *s = VMXNET3(pci_dev); int ret; @@ -2261,8 +2240,6 @@ static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp) pcie_dev_ser_num_init(pci_dev, VMXNET3_DSN_OFFSET, vmxnet3_device_serial_num(s)); } - - register_savevm_live(dev, "vmxnet3-msix", -1, 1, &savevm_vmxnet3_msix, s); } static void vmxnet3_instance_init(Object *obj) @@ -2452,29 +2429,6 @@ static const VMStateDescription vmstate_vmxnet3_int_state = { } }; -static bool vmxnet3_vmstate_need_pcie_device(void *opaque) -{ - VMXNET3State *s = VMXNET3(opaque); - - return !(s->compat_flags & VMXNET3_COMPAT_FLAG_DISABLE_PCIE); -} - -static bool vmxnet3_vmstate_test_pci_device(void *opaque, int version_id) -{ - return !vmxnet3_vmstate_need_pcie_device(opaque); -} - -static const VMStateDescription vmstate_vmxnet3_pcie_device = { - .name = "vmxnet3/pcie", - .version_id = 1, - .minimum_version_id = 1, - .needed = vmxnet3_vmstate_need_pcie_device, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(parent_obj, VMXNET3State), - VMSTATE_END_OF_LIST() - } -}; - static const VMStateDescription vmstate_vmxnet3 = { .name = "vmxnet3", .version_id = 1, @@ -2482,9 +2436,8 @@ static const VMStateDescription vmstate_vmxnet3 = { .pre_save = vmxnet3_pre_save, .post_load = vmxnet3_post_load, .fields = (VMStateField[]) { - VMSTATE_STRUCT_TEST(parent_obj, VMXNET3State, - vmxnet3_vmstate_test_pci_device, 0, - vmstate_pci_device, PCIDevice), + VMSTATE_PCI_DEVICE(parent_obj, VMXNET3State), + VMSTATE_MSIX(parent_obj, VMXNET3State), VMSTATE_BOOL(rx_packets_compound, VMXNET3State), VMSTATE_BOOL(rx_vlan_stripping, VMXNET3State), VMSTATE_BOOL(lro_supported, VMXNET3State), @@ -2520,7 +2473,6 @@ static const VMStateDescription vmstate_vmxnet3 = { }, .subsections = (const VMStateDescription*[]) { &vmxstate_vmxnet3_mcast_list, - &vmstate_vmxnet3_pcie_device, NULL } }; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index b0f37c34a4217d81db4ae1ef40aed8fa3f6af051..289967c3dec15744fe0745d64702f4f36abd97ba 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3069,7 +3069,7 @@ static void spapr_machine_init(MachineState *machine) * interface, this is a legacy from the sPAPREnvironment structure * which predated MachineState but had a similar function */ vmstate_register(NULL, 0, &vmstate_spapr, spapr); - register_savevm_live(NULL, "spapr/htab", VMSTATE_INSTANCE_ID_ANY, 1, + register_savevm_live("spapr/htab", VMSTATE_INSTANCE_ID_ANY, 1, &savevm_htab_handlers, spapr); qbus_set_hotplug_handler(sysbus_get_default(), OBJECT(machine), diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index e5bd92c0c73f167256ebe41725cd27f56537e044..fb7d57865d0bd9fb8e1b313853c4cdfa104ba5f8 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -388,7 +388,7 @@ static inline void s390_skeys_set_migration_enabled(Object *obj, bool value, ss->migration_enabled = value; if (ss->migration_enabled) { - register_savevm_live(NULL, TYPE_S390_SKEYS, 0, 1, + register_savevm_live(TYPE_S390_SKEYS, 0, 1, &savevm_s390_storage_keys, ss); } else { unregister_savevm(DEVICE(ss), TYPE_S390_SKEYS, ss); diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index 766f2015a48f0a9da72e141968d652ba3b30332a..5ee15d5e820ba8eda9f23164b6a506289f6e419f 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -382,7 +382,7 @@ static void s390_stattrib_instance_init(Object *obj) { S390StAttribState *sas = S390_STATTRIB(obj); - register_savevm_live(NULL, TYPE_S390_STATTRIB, 0, 0, + register_savevm_live(TYPE_S390_STATTRIB, 0, 0, &savevm_s390_stattrib_handlers, sas); object_property_add_bool(obj, "migration-enabled", diff --git a/hw/s390x/tod.c b/hw/s390x/tod.c index a9fca8eb0b4ff0565f1090d24f844cb34f919bad..d6b22bb966bff8f66c8f39606ff3ba3760e3bf28 100644 --- a/hw/s390x/tod.c +++ b/hw/s390x/tod.c @@ -100,7 +100,7 @@ static void s390_tod_realize(DeviceState *dev, Error **errp) S390TODState *td = S390_TOD(dev); /* Legacy migration interface */ - register_savevm_live(NULL, "todclock", 0, 1, &savevm_tod, td); + register_savevm_live("todclock", 0, 1, &savevm_tod, td); } static void s390_tod_class_init(ObjectClass *oc, void *data) diff --git a/hw/vfio/Makefile.objs b/hw/vfio/Makefile.objs index abad8b818c9ba5b2f55fd11cf90413a5aab288a4..36033d1437c53f69a642267a4cd8636fb616ecdd 100644 --- a/hw/vfio/Makefile.objs +++ b/hw/vfio/Makefile.objs @@ -1,4 +1,4 @@ -obj-y += common.o spapr.o +obj-y += common.o spapr.o migration.o obj-$(CONFIG_VFIO_PCI) += pci.o pci-quirks.o display.o obj-$(CONFIG_VFIO_CCW) += ccw.o obj-$(CONFIG_VFIO_PLATFORM) += platform.o diff --git a/hw/vfio/common.c b/hw/vfio/common.c index a859298fdad95a88dbf7dcfd699704232d39223b..a86a4c4506558a41a36d6f4a3be0dbec73ad588c 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -29,6 +29,7 @@ #include "hw/vfio/vfio.h" #include "exec/address-spaces.h" #include "exec/memory.h" +#include "exec/ram_addr.h" #include "hw/hw.h" #include "qemu/error-report.h" #include "qemu/range.h" @@ -36,6 +37,7 @@ #include "sysemu/kvm.h" #include "trace.h" #include "qapi/error.h" +#include "migration/migration.h" VFIOGroupList vfio_group_list = QLIST_HEAD_INITIALIZER(vfio_group_list); @@ -285,11 +287,147 @@ const MemoryRegionOps vfio_region_ops = { }, }; +/* + * Device state interfaces + */ + +bool vfio_mig_active(void) +{ + VFIOGroup *group; + VFIODevice *vbasedev; + + if (QLIST_EMPTY(&vfio_group_list)) { + return false; + } + + QLIST_FOREACH(group, &vfio_group_list, next) { + QLIST_FOREACH(vbasedev, &group->device_list, next) { + if (vbasedev->migration_blocker) { + return false; + } + } + } + return true; +} + +static bool vfio_devices_all_stopped_and_saving(VFIOContainer *container) +{ + VFIOGroup *group; + VFIODevice *vbasedev; + MigrationState *ms = migrate_get_current(); + + if (!migration_is_setup_or_active(ms->state)) { + return false; + } + + QLIST_FOREACH(group, &container->group_list, container_next) { + QLIST_FOREACH(vbasedev, &group->device_list, next) { + VFIOMigration *migration = vbasedev->migration; + + if (!migration) { + return false; + } + + if ((migration->device_state & VFIO_DEVICE_STATE_SAVING) && + !(migration->device_state & VFIO_DEVICE_STATE_RUNNING)) { + continue; + } else { + return false; + } + } + } + return true; +} + +static bool vfio_devices_all_running_and_saving(VFIOContainer *container) +{ + VFIOGroup *group; + VFIODevice *vbasedev; + MigrationState *ms = migrate_get_current(); + + if (!migration_is_setup_or_active(ms->state)) { + return false; + } + + QLIST_FOREACH(group, &container->group_list, container_next) { + QLIST_FOREACH(vbasedev, &group->device_list, next) { + VFIOMigration *migration = vbasedev->migration; + + if (!migration) { + return false; + } + + if ((migration->device_state & VFIO_DEVICE_STATE_SAVING) && + (migration->device_state & VFIO_DEVICE_STATE_RUNNING)) { + continue; + } else { + return false; + } + } + } + return true; +} + +static int vfio_dma_unmap_bitmap(VFIOContainer *container, + hwaddr iova, ram_addr_t size, + IOMMUTLBEntry *iotlb) +{ + struct vfio_iommu_type1_dma_unmap *unmap; + struct vfio_bitmap *bitmap; + uint64_t pages = TARGET_PAGE_ALIGN(size) >> TARGET_PAGE_BITS; + int ret; + + unmap = g_malloc0(sizeof(*unmap) + sizeof(*bitmap)); + + unmap->argsz = sizeof(*unmap) + sizeof(*bitmap); + unmap->iova = iova; + unmap->size = size; + unmap->flags |= VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP; + bitmap = (struct vfio_bitmap *)&unmap->data; + + /* + * cpu_physical_memory_set_dirty_lebitmap() expects pages in bitmap of + * TARGET_PAGE_SIZE to mark those dirty. Hence set bitmap_pgsize to + * TARGET_PAGE_SIZE. + */ + + bitmap->pgsize = TARGET_PAGE_SIZE; + bitmap->size = ROUND_UP(pages, sizeof(__u64) * BITS_PER_BYTE) / + BITS_PER_BYTE; + + if (bitmap->size > container->max_dirty_bitmap_size) { + error_report("UNMAP: Size of bitmap too big 0x%"PRIx64, + (uint64_t)bitmap->size); + ret = -E2BIG; + goto unmap_exit; + } + + bitmap->data = g_try_malloc0(bitmap->size); + if (!bitmap->data) { + ret = -ENOMEM; + goto unmap_exit; + } + + ret = ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, unmap); + if (!ret) { + cpu_physical_memory_set_dirty_lebitmap((unsigned long *)bitmap->data, + iotlb->translated_addr, pages); + } else { + error_report("VFIO_UNMAP_DMA with DIRTY_BITMAP : %m"); + } + + g_free(bitmap->data); +unmap_exit: + g_free(unmap); + return ret; +} + /* * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86 */ static int vfio_dma_unmap(VFIOContainer *container, - hwaddr iova, ram_addr_t size) + hwaddr iova, ram_addr_t size, + IOMMUTLBEntry *iotlb) { struct vfio_iommu_type1_dma_unmap unmap = { .argsz = sizeof(unmap), @@ -298,6 +436,11 @@ static int vfio_dma_unmap(VFIOContainer *container, .size = size, }; + if (iotlb && container->dirty_pages_supported && + vfio_devices_all_running_and_saving(container)) { + return vfio_dma_unmap_bitmap(container, iova, size, iotlb); + } + while (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) { /* * The type1 backend has an off-by-one bug in the kernel (71a7d3d78e3c @@ -345,7 +488,7 @@ static int vfio_dma_map(VFIOContainer *container, hwaddr iova, * the VGA ROM space. */ if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0 || - (errno == EBUSY && vfio_dma_unmap(container, iova, size) == 0 && + (errno == EBUSY && vfio_dma_unmap(container, iova, size, NULL) == 0 && ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0)) { return 0; } @@ -406,8 +549,8 @@ static bool vfio_listener_skipped_section(MemoryRegionSection *section) } /* Called with rcu_read_lock held. */ -static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void **vaddr, - bool *read_only) +static bool vfio_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr, + ram_addr_t *ram_addr, bool *read_only) { MemoryRegion *mr; hwaddr xlat; @@ -438,8 +581,17 @@ static bool vfio_get_vaddr(IOMMUTLBEntry *iotlb, void **vaddr, return false; } - *vaddr = memory_region_get_ram_ptr(mr) + xlat; - *read_only = !writable || mr->readonly; + if (vaddr) { + *vaddr = memory_region_get_ram_ptr(mr) + xlat; + } + + if (ram_addr) { + *ram_addr = memory_region_get_ram_addr(mr) + xlat; + } + + if (read_only) { + *read_only = !writable || mr->readonly; + } return true; } @@ -449,7 +601,6 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n); VFIOContainer *container = giommu->container; hwaddr iova = iotlb->iova + giommu->iommu_offset; - bool read_only; void *vaddr; int ret; @@ -465,7 +616,9 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) rcu_read_lock(); if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) { - if (!vfio_get_vaddr(iotlb, &vaddr, &read_only)) { + bool read_only; + + if (!vfio_get_xlat_addr(iotlb, &vaddr, NULL, &read_only)) { goto out; } /* @@ -485,7 +638,7 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) iotlb->addr_mask + 1, vaddr, ret); } } else { - ret = vfio_dma_unmap(container, iova, iotlb->addr_mask + 1); + ret = vfio_dma_unmap(container, iova, iotlb->addr_mask + 1, iotlb); if (ret) { error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " "0x%"HWADDR_PRIx") = %d (%m)", @@ -771,7 +924,7 @@ static void vfio_listener_region_del(MemoryListener *listener, } if (try_unmap) { - ret = vfio_dma_unmap(container, iova, int128_get64(llsize)); + ret = vfio_dma_unmap(container, iova, int128_get64(llsize), NULL); if (ret) { error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " "0x%"HWADDR_PRIx") = %d (%m)", @@ -794,9 +947,156 @@ static void vfio_listener_region_del(MemoryListener *listener, } } +static int vfio_get_dirty_bitmap(VFIOContainer *container, uint64_t iova, + uint64_t size, ram_addr_t ram_addr) +{ + struct vfio_iommu_type1_dirty_bitmap *dbitmap; + struct vfio_iommu_type1_dirty_bitmap_get *range; + uint64_t pages; + int ret; + + dbitmap = g_malloc0(sizeof(*dbitmap) + sizeof(*range)); + + dbitmap->argsz = sizeof(*dbitmap) + sizeof(*range); + dbitmap->flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_GET_BITMAP; + range = (struct vfio_iommu_type1_dirty_bitmap_get *)&dbitmap->data; + range->iova = iova; + range->size = size; + + /* + * cpu_physical_memory_set_dirty_lebitmap() expects pages in bitmap of + * TARGET_PAGE_SIZE to mark those dirty. Hence set bitmap's pgsize to + * TARGET_PAGE_SIZE. + */ + range->bitmap.pgsize = TARGET_PAGE_SIZE; + + pages = TARGET_PAGE_ALIGN(range->size) >> TARGET_PAGE_BITS; + range->bitmap.size = ROUND_UP(pages, sizeof(__u64) * BITS_PER_BYTE) / + BITS_PER_BYTE; + range->bitmap.data = g_try_malloc0(range->bitmap.size); + if (!range->bitmap.data) { + ret = -ENOMEM; + goto err_out; + } + + ret = ioctl(container->fd, VFIO_IOMMU_DIRTY_PAGES, dbitmap); + if (ret) { + error_report("Failed to get dirty bitmap for iova: 0x%"PRIx64 + " size: 0x%"PRIx64" err: %d", (uint64_t)range->iova, + (uint64_t)range->size, errno); + goto err_out; + } + + cpu_physical_memory_set_dirty_lebitmap((unsigned long *)range->bitmap.data, + ram_addr, pages); + + trace_vfio_get_dirty_bitmap(container->fd, range->iova, range->size, + range->bitmap.size, ram_addr); +err_out: + g_free(range->bitmap.data); + g_free(dbitmap); + + return ret; +} + +typedef struct { + IOMMUNotifier n; + VFIOGuestIOMMU *giommu; +} vfio_giommu_dirty_notifier; + +static void vfio_iommu_map_dirty_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) +{ + vfio_giommu_dirty_notifier *gdn = container_of(n, + vfio_giommu_dirty_notifier, n); + VFIOGuestIOMMU *giommu = gdn->giommu; + VFIOContainer *container = giommu->container; + hwaddr iova = iotlb->iova + giommu->iommu_offset; + ram_addr_t translated_addr; + + trace_vfio_iommu_map_dirty_notify(iova, iova + iotlb->addr_mask); + + if (iotlb->target_as != &address_space_memory) { + error_report("Wrong target AS \"%s\", only system memory is allowed", + iotlb->target_as->name ? iotlb->target_as->name : "none"); + return; + } + + rcu_read_lock(); + if (vfio_get_xlat_addr(iotlb, NULL, &translated_addr, NULL)) { + int ret; + + ret = vfio_get_dirty_bitmap(container, iova, iotlb->addr_mask + 1, + translated_addr); + if (ret) { + error_report("vfio_iommu_map_dirty_notify(%p, 0x%"HWADDR_PRIx", " + "0x%"HWADDR_PRIx") = %d (%m)", + container, iova, + iotlb->addr_mask + 1, ret); + } + } + rcu_read_unlock(); +} + +static int vfio_sync_dirty_bitmap(VFIOContainer *container, + MemoryRegionSection *section) +{ + ram_addr_t ram_addr; + + if (memory_region_is_iommu(section->mr)) { + VFIOGuestIOMMU *giommu; + + QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) { + if (MEMORY_REGION(giommu->iommu) == section->mr && + giommu->n.start == section->offset_within_region) { + Int128 llend; + vfio_giommu_dirty_notifier gdn = { .giommu = giommu }; + int idx = memory_region_iommu_attrs_to_index(giommu->iommu, + MEMTXATTRS_UNSPECIFIED); + + llend = int128_add(int128_make64(section->offset_within_region), + section->size); + llend = int128_sub(llend, int128_one()); + + iommu_notifier_init(&gdn.n, + vfio_iommu_map_dirty_notify, + IOMMU_NOTIFIER_MAP, + section->offset_within_region, + int128_get64(llend), + idx); + memory_region_iommu_replay(giommu->iommu, &gdn.n); + break; + } + } + return 0; + } + + ram_addr = memory_region_get_ram_addr(section->mr) + + section->offset_within_region; + + return vfio_get_dirty_bitmap(container, + TARGET_PAGE_ALIGN(section->offset_within_address_space), + int128_get64(section->size), ram_addr); +} + +static void vfio_listerner_log_sync(MemoryListener *listener, + MemoryRegionSection *section) +{ + VFIOContainer *container = container_of(listener, VFIOContainer, listener); + + if (vfio_listener_skipped_section(section) || + !container->dirty_pages_supported) { + return; + } + + if (vfio_devices_all_stopped_and_saving(container)) { + vfio_sync_dirty_bitmap(container, section); + } +} + static const MemoryListener vfio_memory_listener = { .region_add = vfio_listener_region_add, .region_del = vfio_listener_region_del, + .log_sync = vfio_listerner_log_sync, }; static void vfio_listener_release(VFIOContainer *container) @@ -906,6 +1206,18 @@ int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, return 0; } +static void vfio_subregion_unmap(VFIORegion *region, int index) +{ + trace_vfio_region_unmap(memory_region_name(®ion->mmaps[index].mem), + region->mmaps[index].offset, + region->mmaps[index].offset + + region->mmaps[index].size - 1); + memory_region_del_subregion(region->mem, ®ion->mmaps[index].mem); + munmap(region->mmaps[index].mmap, region->mmaps[index].size); + object_unparent(OBJECT(®ion->mmaps[index].mem)); + region->mmaps[index].mmap = NULL; +} + int vfio_region_mmap(VFIORegion *region) { int i, prot = 0; @@ -936,10 +1248,7 @@ int vfio_region_mmap(VFIORegion *region) region->mmaps[i].mmap = NULL; for (i--; i >= 0; i--) { - memory_region_del_subregion(region->mem, ®ion->mmaps[i].mem); - munmap(region->mmaps[i].mmap, region->mmaps[i].size); - object_unparent(OBJECT(®ion->mmaps[i].mem)); - region->mmaps[i].mmap = NULL; + vfio_subregion_unmap(region, i); } return ret; @@ -964,6 +1273,21 @@ int vfio_region_mmap(VFIORegion *region) return 0; } +void vfio_region_unmap(VFIORegion *region) +{ + int i; + + if (!region->mem) { + return; + } + + for (i = 0; i < region->nr_mmaps; i++) { + if (region->mmaps[i].mmap) { + vfio_subregion_unmap(region, i); + } + } +} + void vfio_region_exit(VFIORegion *region) { int i; @@ -1186,6 +1510,75 @@ static int vfio_init_container(VFIOContainer *container, int group_fd, return 0; } +static int vfio_get_iommu_info(VFIOContainer *container, + struct vfio_iommu_type1_info **info) +{ + + size_t argsz = sizeof(struct vfio_iommu_type1_info); + + *info = g_new0(struct vfio_iommu_type1_info, 1); +again: + (*info)->argsz = argsz; + + if (ioctl(container->fd, VFIO_IOMMU_GET_INFO, *info)) { + g_free(*info); + *info = NULL; + return -errno; + } + + if (((*info)->argsz > argsz)) { + argsz = (*info)->argsz; + *info = g_realloc(*info, argsz); + goto again; + } + + return 0; +} + +static struct vfio_info_cap_header * +vfio_get_iommu_info_cap(struct vfio_iommu_type1_info *info, uint16_t id) +{ + struct vfio_info_cap_header *hdr; + void *ptr = info; + + if (!(info->flags & VFIO_IOMMU_INFO_CAPS)) { + return NULL; + } + + for (hdr = ptr + info->cap_offset; hdr != ptr; hdr = ptr + hdr->next) { + if (hdr->id == id) { + return hdr; + } + } + + return NULL; +} + +static void vfio_get_iommu_info_migration(VFIOContainer *container, + struct vfio_iommu_type1_info *info) +{ + struct vfio_info_cap_header *hdr; + struct vfio_iommu_type1_info_cap_migration *cap_mig; + + hdr = vfio_get_iommu_info_cap(info, VFIO_IOMMU_TYPE1_INFO_CAP_MIGRATION); + if (!hdr) { + return; + } + + cap_mig = container_of(hdr, struct vfio_iommu_type1_info_cap_migration, + header); + + /* + * cpu_physical_memory_set_dirty_lebitmap() expects pages in bitmap of + * TARGET_PAGE_SIZE to mark those dirty. + */ + if (cap_mig->pgsize_bitmap & TARGET_PAGE_SIZE) { + container->dirty_pages_supported = true; + container->max_dirty_bitmap_size = cap_mig->max_dirty_bitmap_size; + container->dirty_pgsizes = cap_mig->pgsize_bitmap; + } +} + static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, Error **errp) { @@ -1249,6 +1642,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, container = g_malloc0(sizeof(*container)); container->space = space; container->fd = fd; + container->dirty_pages_supported = false; QLIST_INIT(&container->giommu_list); QLIST_INIT(&container->hostwin_list); @@ -1261,7 +1655,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, case VFIO_TYPE1v2_IOMMU: case VFIO_TYPE1_IOMMU: { - struct vfio_iommu_type1_info info; + struct vfio_iommu_type1_info *info; /* * FIXME: This assumes that a Type1 IOMMU can map any 64-bit @@ -1270,15 +1664,19 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, * existing Type1 IOMMUs generally support any IOVA we're * going to actually try in practice. */ - info.argsz = sizeof(info); - ret = ioctl(fd, VFIO_IOMMU_GET_INFO, &info); - /* Ignore errors */ - if (ret || !(info.flags & VFIO_IOMMU_INFO_PGSIZES)) { + ret = vfio_get_iommu_info(container, &info); + + if (ret || !(info->flags & VFIO_IOMMU_INFO_PGSIZES)) { /* Assume 4k IOVA page size */ - info.iova_pgsizes = 4096; + info->iova_pgsizes = 4096; } - vfio_host_win_add(container, 0, (hwaddr)-1, info.iova_pgsizes); - container->pgsizes = info.iova_pgsizes; + vfio_host_win_add(container, 0, (hwaddr)-1, info->iova_pgsizes); + container->pgsizes = info->iova_pgsizes; + + if (!ret) { + vfio_get_iommu_info_migration(container, info); + } + g_free(info); break; } case VFIO_SPAPR_TCE_v2_IOMMU: diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c new file mode 100644 index 0000000000000000000000000000000000000000..b77c66557eb26c94c477552a849d111f0c7efb86 --- /dev/null +++ b/hw/vfio/migration.c @@ -0,0 +1,933 @@ +/* + * Migration support for VFIO devices + * + * Copyright NVIDIA, Inc. 2020 + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qemu/cutils.h" +#include +#include + +#include "sysemu/sysemu.h" +#include "hw/vfio/vfio-common.h" +#include "cpu.h" +#include "migration/migration.h" +#include "migration/vmstate.h" +#include "migration/qemu-file.h" +#include "migration/register.h" +#include "migration/blocker.h" +#include "migration/misc.h" +#include "qapi/error.h" +#include "exec/ramlist.h" +#include "exec/ram_addr.h" +#include "pci.h" +#include "trace.h" +#include "hw/hw.h" + +/* + * Flags to be used as unique delimiters for VFIO devices in the migration + * stream. These flags are composed as: + * 0xffffffff => MSB 32-bit all 1s + * 0xef10 => Magic ID, represents emulated (virtual) function IO + * 0x0000 => 16-bits reserved for flags + * + * The beginning of state information is marked by _DEV_CONFIG_STATE, + * _DEV_SETUP_STATE, or _DEV_DATA_STATE, respectively. The end of a + * certain state information is marked by _END_OF_STATE. + */ +#define VFIO_MIG_FLAG_END_OF_STATE (0xffffffffef100001ULL) +#define VFIO_MIG_FLAG_DEV_CONFIG_STATE (0xffffffffef100002ULL) +#define VFIO_MIG_FLAG_DEV_SETUP_STATE (0xffffffffef100003ULL) +#define VFIO_MIG_FLAG_DEV_DATA_STATE (0xffffffffef100004ULL) + +static int64_t bytes_transferred; + +static inline int vfio_mig_access(VFIODevice *vbasedev, void *val, int count, + off_t off, bool iswrite) +{ + int ret; + + ret = iswrite ? pwrite(vbasedev->fd, val, count, off) : + pread(vbasedev->fd, val, count, off); + if (ret < count) { + error_report("vfio_mig_%s %d byte %s: failed at offset 0x%" + HWADDR_PRIx", err: %s", iswrite ? "write" : "read", count, + vbasedev->name, off, strerror(errno)); + return (ret < 0) ? ret : -EINVAL; + } + return 0; +} + +static int vfio_mig_rw(VFIODevice *vbasedev, __u8 *buf, size_t count, + off_t off, bool iswrite) +{ + int ret, done = 0; + __u8 *tbuf = buf; + + while (count) { + int bytes = 0; + + if (count >= 8 && !(off % 8)) { + bytes = 8; + } else if (count >= 4 && !(off % 4)) { + bytes = 4; + } else if (count >= 2 && !(off % 2)) { + bytes = 2; + } else { + bytes = 1; + } + + ret = vfio_mig_access(vbasedev, tbuf, bytes, off, iswrite); + if (ret) { + return ret; + } + + count -= bytes; + done += bytes; + off += bytes; + tbuf += bytes; + } + return done; +} + +#define vfio_mig_read(f, v, c, o) vfio_mig_rw(f, (__u8 *)v, c, o, false) +#define vfio_mig_write(f, v, c, o) vfio_mig_rw(f, (__u8 *)v, c, o, true) + +#define VFIO_MIG_STRUCT_OFFSET(f) \ + offsetof(struct vfio_device_migration_info, f) +/* + * Change the device_state register for device @vbasedev. Bits set in @mask + * are preserved, bits set in @value are set, and bits not set in either @mask + * or @value are cleared in device_state. If the register cannot be accessed, + * the resulting state would be invalid, or the device enters an error state, + * an error is returned. + */ + +static int vfio_migration_set_state(VFIODevice *vbasedev, uint32_t mask, + uint32_t value) +{ + VFIOMigration *migration = vbasedev->migration; + VFIORegion *region = &migration->region; + off_t dev_state_off = region->fd_offset + + VFIO_MIG_STRUCT_OFFSET(device_state); + uint32_t device_state; + int ret; + + ret = vfio_mig_read(vbasedev, &device_state, sizeof(device_state), + dev_state_off); + if (ret < 0) { + return ret; + } + + device_state = (device_state & mask) | value; + + if (!VFIO_DEVICE_STATE_VALID(device_state)) { + return -EINVAL; + } + + ret = vfio_mig_write(vbasedev, &device_state, sizeof(device_state), + dev_state_off); + if (ret < 0) { + int rret; + + rret = vfio_mig_read(vbasedev, &device_state, sizeof(device_state), + dev_state_off); + + if ((rret < 0) || (VFIO_DEVICE_STATE_IS_ERROR(device_state))) { + hw_error("%s: Device in error state 0x%x", vbasedev->name, + device_state); + return rret ? rret : -EIO; + } + return ret; + } + + migration->device_state = device_state; + trace_vfio_migration_set_state(vbasedev->name, device_state); + return 0; +} + +static void *get_data_section_size(VFIORegion *region, uint64_t data_offset, + uint64_t data_size, uint64_t *size) +{ + void *ptr = NULL; + uint64_t limit = 0; + int i; + + if (!region->mmaps) { + if (size) { + *size = MIN(data_size, region->size - data_offset); + } + return ptr; + } + + for (i = 0; i < region->nr_mmaps; i++) { + VFIOMmap *map = region->mmaps + i; + + if ((data_offset >= map->offset) && + (data_offset < map->offset + map->size)) { + + /* check if data_offset is within sparse mmap areas */ + ptr = map->mmap + data_offset - map->offset; + if (size) { + *size = MIN(data_size, map->offset + map->size - data_offset); + } + break; + } else if ((data_offset < map->offset) && + (!limit || limit > map->offset)) { + /* + * data_offset is not within sparse mmap areas, find size of + * non-mapped area. Check through all list since region->mmaps list + * is not sorted. + */ + limit = map->offset; + } + } + + if (!ptr && size) { + *size = limit ? MIN(data_size, limit - data_offset) : data_size; + } + return ptr; +} + +static int vfio_save_buffer(QEMUFile *f, VFIODevice *vbasedev, uint64_t *size) +{ + VFIOMigration *migration = vbasedev->migration; + VFIORegion *region = &migration->region; + uint64_t data_offset = 0, data_size = 0, sz; + int ret; + + ret = vfio_mig_read(vbasedev, &data_offset, sizeof(data_offset), + region->fd_offset + VFIO_MIG_STRUCT_OFFSET(data_offset)); + if (ret < 0) { + return ret; + } + + ret = vfio_mig_read(vbasedev, &data_size, sizeof(data_size), + region->fd_offset + VFIO_MIG_STRUCT_OFFSET(data_size)); + if (ret < 0) { + return ret; + } + + trace_vfio_save_buffer(vbasedev->name, data_offset, data_size, + migration->pending_bytes); + + qemu_put_be64(f, data_size); + sz = data_size; + + while (sz) { + void *buf; + uint64_t sec_size; + bool buf_allocated = false; + + buf = get_data_section_size(region, data_offset, sz, &sec_size); + + if (!buf) { + buf = g_try_malloc(sec_size); + if (!buf) { + error_report("%s: Error allocating buffer ", __func__); + return -ENOMEM; + } + buf_allocated = true; + + ret = vfio_mig_read(vbasedev, buf, sec_size, + region->fd_offset + data_offset); + if (ret < 0) { + g_free(buf); + return ret; + } + } + + qemu_put_buffer(f, buf, sec_size); + + if (buf_allocated) { + g_free(buf); + } + sz -= sec_size; + data_offset += sec_size; + } + + ret = qemu_file_get_error(f); + + if (!ret && size) { + *size = data_size; + } + + bytes_transferred += data_size; + return ret; +} + +static int vfio_load_buffer(QEMUFile *f, VFIODevice *vbasedev, + uint64_t data_size) +{ + VFIORegion *region = &vbasedev->migration->region; + uint64_t data_offset = 0, size, report_size; + int ret; + + do { + ret = vfio_mig_read(vbasedev, &data_offset, sizeof(data_offset), + region->fd_offset + VFIO_MIG_STRUCT_OFFSET(data_offset)); + if (ret < 0) { + return ret; + } + + if (data_offset + data_size > region->size) { + /* + * If data_size is greater than the data section of migration region + * then iterate the write buffer operation. This case can occur if + * size of migration region at destination is smaller than size of + * migration region at source. + */ + report_size = size = region->size - data_offset; + data_size -= size; + } else { + report_size = size = data_size; + data_size = 0; + } + + trace_vfio_load_state_device_data(vbasedev->name, data_offset, size); + + while (size) { + void *buf; + uint64_t sec_size; + bool buf_alloc = false; + + buf = get_data_section_size(region, data_offset, size, &sec_size); + + if (!buf) { + buf = g_try_malloc(sec_size); + if (!buf) { + error_report("%s: Error allocating buffer ", __func__); + return -ENOMEM; + } + buf_alloc = true; + } + + qemu_get_buffer(f, buf, sec_size); + + if (buf_alloc) { + ret = vfio_mig_write(vbasedev, buf, sec_size, + region->fd_offset + data_offset); + g_free(buf); + + if (ret < 0) { + return ret; + } + } + size -= sec_size; + data_offset += sec_size; + } + + ret = vfio_mig_write(vbasedev, &report_size, sizeof(report_size), + region->fd_offset + VFIO_MIG_STRUCT_OFFSET(data_size)); + if (ret < 0) { + return ret; + } + } while (data_size); + + return 0; +} + +static int vfio_update_pending(VFIODevice *vbasedev) +{ + VFIOMigration *migration = vbasedev->migration; + VFIORegion *region = &migration->region; + uint64_t pending_bytes = 0; + int ret; + + ret = vfio_mig_read(vbasedev, &pending_bytes, sizeof(pending_bytes), + region->fd_offset + VFIO_MIG_STRUCT_OFFSET(pending_bytes)); + if (ret < 0) { + migration->pending_bytes = 0; + return ret; + } + + migration->pending_bytes = pending_bytes; + trace_vfio_update_pending(vbasedev->name, pending_bytes); + return 0; +} + +static int vfio_save_device_config_state(QEMUFile *f, void *opaque) +{ + VFIODevice *vbasedev = opaque; + + qemu_put_be64(f, VFIO_MIG_FLAG_DEV_CONFIG_STATE); + + if (vbasedev->ops && vbasedev->ops->vfio_save_config) { + vbasedev->ops->vfio_save_config(vbasedev, f); + } + + qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); + + trace_vfio_save_device_config_state(vbasedev->name); + + return qemu_file_get_error(f); +} + +static int vfio_load_device_config_state(QEMUFile *f, void *opaque) +{ + VFIODevice *vbasedev = opaque; + uint64_t data; + + if (vbasedev->ops && vbasedev->ops->vfio_load_config) { + int ret; + + ret = vbasedev->ops->vfio_load_config(vbasedev, f); + if (ret) { + error_report("%s: Failed to load device config space", + vbasedev->name); + return ret; + } + } + + data = qemu_get_be64(f); + if (data != VFIO_MIG_FLAG_END_OF_STATE) { + error_report("%s: Failed loading device config space, " + "end flag incorrect 0x%"PRIx64, vbasedev->name, data); + return -EINVAL; + } + + trace_vfio_load_device_config_state(vbasedev->name); + return qemu_file_get_error(f); +} + +static int vfio_set_dirty_page_tracking(VFIODevice *vbasedev, bool start) +{ + int ret; + VFIOMigration *migration = vbasedev->migration; + VFIOContainer *container = vbasedev->group->container; + struct vfio_iommu_type1_dirty_bitmap dirty = { + .argsz = sizeof(dirty), + }; + + if (start) { + if (migration->device_state & VFIO_DEVICE_STATE_SAVING) { + dirty.flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_START; + } else { + return -EINVAL; + } + } else { + dirty.flags = VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP; + } + + ret = ioctl(container->fd, VFIO_IOMMU_DIRTY_PAGES, &dirty); + if (ret) { + error_report("Failed to set dirty tracking flag 0x%x errno: %d", + dirty.flags, errno); + return -errno; + } + return ret; +} + +static void vfio_migration_cleanup(VFIODevice *vbasedev) +{ + VFIOMigration *migration = vbasedev->migration; + + vfio_set_dirty_page_tracking(vbasedev, false); + + if (migration->region.mmaps) { + vfio_region_unmap(&migration->region); + } +} + +/* ---------------------------------------------------------------------- */ + +static int vfio_save_setup(QEMUFile *f, void *opaque) +{ + VFIODevice *vbasedev = opaque; + VFIOMigration *migration = vbasedev->migration; + int ret; + + trace_vfio_save_setup(vbasedev->name); + + qemu_put_be64(f, VFIO_MIG_FLAG_DEV_SETUP_STATE); + + if (migration->region.mmaps) { + /* + * Calling vfio_region_mmap() from migration thread. Memory API called + * from this function require locking the iothread when called from + * outside the main loop thread. + */ + qemu_mutex_lock_iothread(); + ret = vfio_region_mmap(&migration->region); + qemu_mutex_unlock_iothread(); + if (ret) { + error_report("%s: Failed to mmap VFIO migration region: %s", + vbasedev->name, strerror(-ret)); + error_report("%s: Falling back to slow path", vbasedev->name); + } + } + + ret = vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_MASK, + VFIO_DEVICE_STATE_SAVING); + if (ret) { + error_report("%s: Failed to set state SAVING", vbasedev->name); + return ret; + } + + ret = vfio_set_dirty_page_tracking(vbasedev, true); + if (ret) { + return ret; + } + + qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); + + ret = qemu_file_get_error(f); + if (ret) { + return ret; + } + + return 0; +} + +static void vfio_save_cleanup(void *opaque) +{ + VFIODevice *vbasedev = opaque; + + vfio_migration_cleanup(vbasedev); + trace_vfio_save_cleanup(vbasedev->name); +} + +static void vfio_save_pending(QEMUFile *f, void *opaque, + uint64_t threshold_size, + uint64_t *res_precopy_only, + uint64_t *res_compatible, + uint64_t *res_postcopy_only) +{ + VFIODevice *vbasedev = opaque; + VFIOMigration *migration = vbasedev->migration; + int ret; + + ret = vfio_update_pending(vbasedev); + if (ret) { + return; + } + + *res_precopy_only += migration->pending_bytes; + + trace_vfio_save_pending(vbasedev->name, *res_precopy_only, + *res_postcopy_only, *res_compatible); +} + +static int vfio_save_iterate(QEMUFile *f, void *opaque) +{ + VFIODevice *vbasedev = opaque; + VFIOMigration *migration = vbasedev->migration; + uint64_t data_size; + int ret; + + qemu_put_be64(f, VFIO_MIG_FLAG_DEV_DATA_STATE); + + if (migration->pending_bytes == 0) { + ret = vfio_update_pending(vbasedev); + if (ret) { + return ret; + } + + if (migration->pending_bytes == 0) { + qemu_put_be64(f, 0); + qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); + /* indicates data finished, goto complete phase */ + return 1; + } + } + + ret = vfio_save_buffer(f, vbasedev, &data_size); + if (ret) { + error_report("%s: vfio_save_buffer failed %s", vbasedev->name, + strerror(errno)); + return ret; + } + + qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); + + ret = qemu_file_get_error(f); + if (ret) { + return ret; + } + + /* + * Reset pending_bytes as .save_live_pending is not called during savevm or + * snapshot case, in such case vfio_update_pending() at the start of this + * function updates pending_bytes. + */ + migration->pending_bytes = 0; + trace_vfio_save_iterate(vbasedev->name, data_size); + return 0; +} + +static int vfio_save_complete_precopy(QEMUFile *f, void *opaque) +{ + VFIODevice *vbasedev = opaque; + VFIOMigration *migration = vbasedev->migration; + uint64_t data_size; + int ret; + + ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_RUNNING, + VFIO_DEVICE_STATE_SAVING); + if (ret) { + error_report("%s: Failed to set state STOP and SAVING", + vbasedev->name); + return ret; + } + + ret = vfio_save_device_config_state(f, opaque); + if (ret) { + return ret; + } + + ret = vfio_update_pending(vbasedev); + if (ret) { + return ret; + } + + while (migration->pending_bytes > 0) { + qemu_put_be64(f, VFIO_MIG_FLAG_DEV_DATA_STATE); + ret = vfio_save_buffer(f, vbasedev, &data_size); + if (ret < 0) { + error_report("%s: Failed to save buffer", vbasedev->name); + return ret; + } + + if (data_size == 0) { + break; + } + + ret = vfio_update_pending(vbasedev); + if (ret) { + return ret; + } + } + + qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE); + + ret = qemu_file_get_error(f); + if (ret) { + return ret; + } + + ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_SAVING, 0); + if (ret) { + error_report("%s: Failed to set state STOPPED", vbasedev->name); + return ret; + } + + trace_vfio_save_complete_precopy(vbasedev->name); + return ret; +} + +static int vfio_load_setup(QEMUFile *f, void *opaque) +{ + VFIODevice *vbasedev = opaque; + VFIOMigration *migration = vbasedev->migration; + int ret = 0; + + if (migration->region.mmaps) { + ret = vfio_region_mmap(&migration->region); + if (ret) { + error_report("%s: Failed to mmap VFIO migration region %d: %s", + vbasedev->name, migration->region.nr, + strerror(-ret)); + error_report("%s: Falling back to slow path", vbasedev->name); + } + } + + ret = vfio_migration_set_state(vbasedev, ~VFIO_DEVICE_STATE_MASK, + VFIO_DEVICE_STATE_RESUMING); + if (ret) { + error_report("%s: Failed to set state RESUMING", vbasedev->name); + if (migration->region.mmaps) { + vfio_region_unmap(&migration->region); + } + } + return ret; +} + +static int vfio_load_cleanup(void *opaque) +{ + VFIODevice *vbasedev = opaque; + + vfio_migration_cleanup(vbasedev); + trace_vfio_load_cleanup(vbasedev->name); + return 0; +} + +static int vfio_load_state(QEMUFile *f, void *opaque, int version_id) +{ + VFIODevice *vbasedev = opaque; + int ret = 0; + uint64_t data; + + data = qemu_get_be64(f); + while (data != VFIO_MIG_FLAG_END_OF_STATE) { + + trace_vfio_load_state(vbasedev->name, data); + + switch (data) { + case VFIO_MIG_FLAG_DEV_CONFIG_STATE: + { + ret = vfio_load_device_config_state(f, opaque); + if (ret) { + return ret; + } + break; + } + case VFIO_MIG_FLAG_DEV_SETUP_STATE: + { + data = qemu_get_be64(f); + if (data == VFIO_MIG_FLAG_END_OF_STATE) { + return ret; + } else { + error_report("%s: SETUP STATE: EOS not found 0x%"PRIx64, + vbasedev->name, data); + return -EINVAL; + } + break; + } + case VFIO_MIG_FLAG_DEV_DATA_STATE: + { + uint64_t data_size = qemu_get_be64(f); + + if (data_size) { + ret = vfio_load_buffer(f, vbasedev, data_size); + if (ret < 0) { + return ret; + } + } + break; + } + default: + error_report("%s: Unknown tag 0x%"PRIx64, vbasedev->name, data); + return -EINVAL; + } + + data = qemu_get_be64(f); + ret = qemu_file_get_error(f); + if (ret) { + return ret; + } + } + return ret; +} + +static SaveVMHandlers savevm_vfio_handlers = { + .save_setup = vfio_save_setup, + .save_cleanup = vfio_save_cleanup, + .save_live_pending = vfio_save_pending, + .save_live_iterate = vfio_save_iterate, + .save_live_complete_precopy = vfio_save_complete_precopy, + .load_setup = vfio_load_setup, + .load_cleanup = vfio_load_cleanup, + .load_state = vfio_load_state, +}; + +/* ---------------------------------------------------------------------- */ + +static void vfio_vmstate_change(void *opaque, int running, RunState state) +{ + VFIODevice *vbasedev = opaque; + VFIOMigration *migration = vbasedev->migration; + uint32_t value, mask; + int ret; + + if (vbasedev->migration->vm_running == running) { + return; + } + + if (running) { + /* + * Here device state can have one of _SAVING, _RESUMING or _STOP bit. + * Transition from _SAVING to _RUNNING can happen if there is migration + * failure, in that case clear _SAVING bit. + * Transition from _RESUMING to _RUNNING occurs during resuming + * phase, in that case clear _RESUMING bit. + * In both the above cases, set _RUNNING bit. + */ + mask = ~VFIO_DEVICE_STATE_MASK; + value = VFIO_DEVICE_STATE_RUNNING; + } else { + /* + * Here device state could be either _RUNNING or _SAVING|_RUNNING. Reset + * _RUNNING bit + */ + mask = ~VFIO_DEVICE_STATE_RUNNING; + value = 0; + } + + ret = vfio_migration_set_state(vbasedev, mask, value); + if (ret) { + /* + * Migration should be aborted in this case, but vm_state_notify() + * currently does not support reporting failures. + */ + error_report("%s: Failed to set device state 0x%x", vbasedev->name, + (migration->device_state & mask) | value); + qemu_file_set_error(migrate_get_current()->to_dst_file, ret); + } + vbasedev->migration->vm_running = running; + trace_vfio_vmstate_change(vbasedev->name, running, RunState_str(state), + (migration->device_state & mask) | value); +} + +static void vfio_migration_state_notifier(Notifier *notifier, void *data) +{ + MigrationState *s = data; + VFIOMigration *migration = container_of(notifier, VFIOMigration, + migration_state); + VFIODevice *vbasedev = migration->vbasedev; + int ret; + + trace_vfio_migration_state_notifier(vbasedev->name, + MigrationStatus_str(s->state)); + + switch (s->state) { + case MIGRATION_STATUS_CANCELLING: + case MIGRATION_STATUS_CANCELLED: + case MIGRATION_STATUS_FAILED: + bytes_transferred = 0; + ret = vfio_migration_set_state(vbasedev, + ~(VFIO_DEVICE_STATE_SAVING | VFIO_DEVICE_STATE_RESUMING), + VFIO_DEVICE_STATE_RUNNING); + if (ret) { + error_report("%s: Failed to set state RUNNING", vbasedev->name); + } + } +} + +static void vfio_migration_exit(VFIODevice *vbasedev) +{ + VFIOMigration *migration = vbasedev->migration; + + vfio_region_exit(&migration->region); + vfio_region_finalize(&migration->region); + g_free(vbasedev->migration); + vbasedev->migration = NULL; +} + +static int vfio_migration_init(VFIODevice *vbasedev, + struct vfio_region_info *info) +{ + int ret; + Object *obj; + VFIOMigration *migration; + char id[256] = ""; + g_autofree char *path = NULL, *oid = NULL; + + if (!vbasedev->ops->vfio_get_object) { + return -EINVAL; + } + + obj = vbasedev->ops->vfio_get_object(vbasedev); + if (!obj) { + return -EINVAL; + } + + vbasedev->migration = g_new0(VFIOMigration, 1); + + ret = vfio_region_setup(obj, vbasedev, &vbasedev->migration->region, + info->index, "migration"); + if (ret) { + error_report("%s: Failed to setup VFIO migration region %d: %s", + vbasedev->name, info->index, strerror(-ret)); + goto err; + } + + if (!vbasedev->migration->region.size) { + error_report("%s: Invalid zero-sized VFIO migration region %d", + vbasedev->name, info->index); + ret = -EINVAL; + goto err; + } + + migration = vbasedev->migration; + migration->vbasedev = vbasedev; + + oid = vmstate_if_get_id(VMSTATE_IF(DEVICE(obj))); + if (oid) { + path = g_strdup_printf("%s/vfio", oid); + } else { + path = g_strdup("vfio"); + } + strpadcpy(id, sizeof(id), path, '\0'); + + register_savevm_live(id, VMSTATE_INSTANCE_ID_ANY, 1, &savevm_vfio_handlers, + vbasedev); + + migration->vm_state = qemu_add_vm_change_state_handler(vfio_vmstate_change, + vbasedev); + migration->migration_state.notify = vfio_migration_state_notifier; + add_migration_state_change_notifier(&migration->migration_state); + return 0; + +err: + vfio_migration_exit(vbasedev); + return ret; +} + +/* ---------------------------------------------------------------------- */ + +int64_t vfio_mig_bytes_transferred(void) +{ + return bytes_transferred; +} + +int vfio_migration_probe(VFIODevice *vbasedev, Error **errp) +{ + VFIOContainer *container = vbasedev->group->container; + struct vfio_region_info *info = NULL; + Error *local_err = NULL; + int ret = -ENOTSUP; + + if (!container->dirty_pages_supported) { + goto add_blocker; + } + + ret = vfio_get_dev_region_info(vbasedev, VFIO_REGION_TYPE_MIGRATION, + VFIO_REGION_SUBTYPE_MIGRATION, &info); + if (ret) { + goto add_blocker; + } + + ret = vfio_migration_init(vbasedev, info); + if (ret) { + goto add_blocker; + } + + g_free(info); + trace_vfio_migration_probe(vbasedev->name, info->index); + return 0; + +add_blocker: + error_setg(&vbasedev->migration_blocker, + "VFIO device doesn't support migration"); + g_free(info); + + ret = migrate_add_blocker(vbasedev->migration_blocker, &local_err); + if (local_err) { + error_propagate(errp, local_err); + error_free(vbasedev->migration_blocker); + vbasedev->migration_blocker = NULL; + } + return ret; +} + +void vfio_migration_finalize(VFIODevice *vbasedev) +{ + if (vbasedev->migration) { + VFIOMigration *migration = vbasedev->migration; + + remove_migration_state_change_notifier(&migration->migration_state); + qemu_del_vm_change_state_handler(migration->vm_state); + vfio_migration_exit(vbasedev); + } + + if (vbasedev->migration_blocker) { + migrate_del_blocker(vbasedev->migration_blocker); + error_free(vbasedev->migration_blocker); + vbasedev->migration_blocker = NULL; + } +} diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index d7a4e1875c055eed8983b3553bde376406aea938..a637c35e7a3bd444a5db1505abb40240a65c8e1b 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -35,6 +35,7 @@ #include "pci.h" #include "trace.h" #include "qapi/error.h" +#include "migration/qemu-file.h" #define TYPE_VFIO_PCI "vfio-pci" #define PCI_VFIO(obj) OBJECT_CHECK(VFIOPCIDevice, obj, TYPE_VFIO_PCI) @@ -2388,10 +2389,68 @@ static void vfio_pci_compute_needs_reset(VFIODevice *vbasedev) } } +static Object *vfio_pci_get_object(VFIODevice *vbasedev) +{ + VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev); + + return OBJECT(vdev); +} + +static bool vfio_msix_present(void *opaque, int version_id) +{ + PCIDevice *pdev = opaque; + + return msix_present(pdev); +} + +const VMStateDescription vmstate_vfio_pci_config = { + .name = "VFIOPCIDevice", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(pdev, VFIOPCIDevice), + VMSTATE_MSIX_TEST(pdev, VFIOPCIDevice, vfio_msix_present), + VMSTATE_END_OF_LIST() + } +}; + +static void vfio_pci_save_config(VFIODevice *vbasedev, QEMUFile *f) +{ + VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev); + + vmstate_save_state(f, &vmstate_vfio_pci_config, vdev, NULL); +} + +static int vfio_pci_load_config(VFIODevice *vbasedev, QEMUFile *f) +{ + VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev); + PCIDevice *pdev = &vdev->pdev; + int ret; + + ret = vmstate_load_state(f, &vmstate_vfio_pci_config, vdev, 1); + if (ret) { + return ret; + } + + vfio_pci_write_config(pdev, PCI_COMMAND, + pci_get_word(pdev->config + PCI_COMMAND), 2); + + if (msi_enabled(pdev)) { + vfio_msi_enable(vdev); + } else if (msix_enabled(pdev)) { + vfio_msix_enable(vdev); + } + + return ret; +} + static VFIODeviceOps vfio_pci_ops = { .vfio_compute_needs_reset = vfio_pci_compute_needs_reset, .vfio_hot_reset_multi = vfio_pci_hot_reset_multi, .vfio_eoi = vfio_intx_eoi, + .vfio_get_object = vfio_pci_get_object, + .vfio_save_config = vfio_pci_save_config, + .vfio_load_config = vfio_pci_load_config, }; int vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp) @@ -2990,6 +3049,11 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) } } + ret = vfio_migration_probe(&vdev->vbasedev, errp); + if (ret) { + error_report("%s: Migration disabled", vdev->vbasedev.name); + } + vfio_register_err_notifier(vdev); vfio_register_req_notifier(vdev); vfio_setup_resetfn_quirk(vdev); @@ -3037,6 +3101,7 @@ static void vfio_exitfn(PCIDevice *pdev) } vfio_teardown_msi(vdev); vfio_bars_exit(vdev); + vfio_migration_finalize(&vdev->vbasedev); } static void vfio_pci_reset(DeviceState *dev) @@ -3145,11 +3210,6 @@ static Property vfio_pci_dev_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static const VMStateDescription vfio_pci_vmstate = { - .name = "vfio-pci", - .unmigratable = 1, -}; - static void vfio_pci_dev_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -3157,7 +3217,6 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, void *data) dc->reset = vfio_pci_reset; dc->props = vfio_pci_dev_properties; - dc->vmsd = &vfio_pci_vmstate; dc->desc = "VFIO-based PCI device assignment"; set_bit(DEVICE_CATEGORY_MISC, dc->categories); pdc->realize = vfio_realize; diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index b1ef55a33ffd1bb16e9e49126677f34e85f1cd74..575ebde6e0f2dbd16fbee90f17b80fc1d8af9c3c 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -111,6 +111,7 @@ vfio_region_mmap(const char *name, unsigned long offset, unsigned long end) "Reg vfio_region_exit(const char *name, int index) "Device %s, region %d" vfio_region_finalize(const char *name, int index) "Device %s, region %d" vfio_region_mmaps_set_enabled(const char *name, bool enabled) "Region %s mmaps enabled: %d" +vfio_region_unmap(const char *name, unsigned long offset, unsigned long end) "Region %s unmap [0x%lx - 0x%lx]" vfio_region_sparse_mmap_header(const char *name, int index, int nr_areas) "Device %s region %d: %d sparse mmap entries" vfio_region_sparse_mmap_entry(int i, unsigned long start, unsigned long end) "sparse entry %d [0x%lx - 0x%lx]" vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%0x8" @@ -142,3 +143,23 @@ vfio_display_edid_link_up(void) "" vfio_display_edid_link_down(void) "" vfio_display_edid_update(uint32_t prefx, uint32_t prefy) "%ux%u" vfio_display_edid_write_error(void) "" + +# migration.c +vfio_migration_probe(const char *name, uint32_t index) " (%s) Region %d" +vfio_migration_set_state(const char *name, uint32_t state) " (%s) state %d" +vfio_vmstate_change(const char *name, int running, const char *reason, uint32_t dev_state) " (%s) running %d reason %s device state %d" +vfio_migration_state_notifier(const char *name, const char *state) " (%s) state %s" +vfio_save_setup(const char *name) " (%s)" +vfio_save_cleanup(const char *name) " (%s)" +vfio_save_buffer(const char *name, uint64_t data_offset, uint64_t data_size, uint64_t pending) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64" pending 0x%"PRIx64 +vfio_update_pending(const char *name, uint64_t pending) " (%s) pending 0x%"PRIx64 +vfio_save_device_config_state(const char *name) " (%s)" +vfio_save_pending(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t compatible) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64" compatible 0x%"PRIx64 +vfio_save_iterate(const char *name, int data_size) " (%s) data_size %d" +vfio_save_complete_precopy(const char *name) " (%s)" +vfio_load_device_config_state(const char *name) " (%s)" +vfio_load_state(const char *name, uint64_t data) " (%s) data 0x%"PRIx64 +vfio_load_state_device_data(const char *name, uint64_t data_offset, uint64_t data_size) " (%s) Offset 0x%"PRIx64" size 0x%"PRIx64 +vfio_load_cleanup(const char *name) " (%s)" +vfio_get_dirty_bitmap(int fd, uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start) "container fd=%d, iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64 +vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64 diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h index 0cb7cc74a2979462ccaf046724ff438d7f30168f..4629f24d088199ab11379877e4e69519a5401e9e 100644 --- a/include/block/raw-aio.h +++ b/include/block/raw-aio.h @@ -12,9 +12,11 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ + #ifndef QEMU_RAW_AIO_H #define QEMU_RAW_AIO_H +#include "block/aio.h" #include "qemu/coroutine.h" #include "qemu/iov.h" diff --git a/include/block/write-threshold.h b/include/block/write-threshold.h index 80d8aab5d03c1a3f38228fcc992749a8d6f94a39..c646f267a45c7139854013e612e0a43aa82b52fc 100644 --- a/include/block/write-threshold.h +++ b/include/block/write-threshold.h @@ -9,9 +9,11 @@ * This work is licensed under the terms of the GNU LGPL, version 2 or later. * See the COPYING.LIB file in the top-level directory. */ + #ifndef BLOCK_WRITE_THRESHOLD_H #define BLOCK_WRITE_THRESHOLD_H +#include "block/block_int.h" /* * bdrv_write_threshold_set: diff --git a/include/disas/disas.h b/include/disas/disas.h index 15da511f49c766bb5d368cc848177bcc4c8638b1..ba47e9197cd944c79d017048bffde540cec14ab2 100644 --- a/include/disas/disas.h +++ b/include/disas/disas.h @@ -1,6 +1,7 @@ #ifndef QEMU_DISAS_H #define QEMU_DISAS_H +#include "exec/hwaddr.h" #ifdef NEED_CPU_H #include "cpu.h" diff --git a/include/exec/cputlb.h b/include/exec/cputlb.h index 5373188be34542deea80484f29ca97450111e133..a62cfb28d5db00027c3ee397c4ca4b097a2ade9e 100644 --- a/include/exec/cputlb.h +++ b/include/exec/cputlb.h @@ -16,9 +16,12 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ + #ifndef CPUTLB_H #define CPUTLB_H +#include "exec/cpu-common.h" + #if !defined(CONFIG_USER_ONLY) /* cputlb.c */ void tlb_protect_code(ram_addr_t ram_addr); diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 16034ee651e9ddcf2ebe07f9112dc8e9e8207c3c..135aeaab0d8b01e251662e08618fabb55e0b7edc 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -20,6 +20,7 @@ #ifndef EXEC_ALL_H #define EXEC_ALL_H +#include "cpu.h" #include "exec/tb-context.h" #include "sysemu/cpus.h" diff --git a/include/exec/ioport.h b/include/exec/ioport.h index a298b89ce15a3cfd2bd3a36d5caea7c6478337ab..97feb296d234f68f2d9f8ca5251c0ad24b84c9da 100644 --- a/include/exec/ioport.h +++ b/include/exec/ioport.h @@ -24,6 +24,8 @@ #ifndef IOPORT_H #define IOPORT_H +#include "exec/memory.h" + #define MAX_IOPORTS (64 * 1024) #define IOPORTS_MASK (MAX_IOPORTS - 1) diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h index d1a9dd1ec898dfef7346e09236d492c43a3603f1..ef4fb9237127e4aee2e4a0bff9531f3feabcb4df 100644 --- a/include/exec/memory-internal.h +++ b/include/exec/memory-internal.h @@ -20,6 +20,8 @@ #ifndef MEMORY_INTERNAL_H #define MEMORY_INTERNAL_H +#include "cpu.h" + #ifndef CONFIG_USER_ONLY static inline AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv) { diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 523440662b36fee4a283db7c1dfe4fc2699fb02d..27a164b669a2b0ab482ad4360ed62e9137950fd4 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -20,6 +20,7 @@ #define RAM_ADDR_H #ifndef CONFIG_USER_ONLY +#include "cpu.h" #include "hw/xen/xen.h" #include "sysemu/tcg.h" #include "exec/ramlist.h" diff --git a/include/exec/softmmu-semi.h b/include/exec/softmmu-semi.h index 970837992e75a3b787982c18cfae442c2bbf91c0..fbcae88f4bab73714a674f019f1f303a15a51564 100644 --- a/include/exec/softmmu-semi.h +++ b/include/exec/softmmu-semi.h @@ -10,6 +10,8 @@ #ifndef SOFTMMU_SEMI_H #define SOFTMMU_SEMI_H +#include "cpu.h" + static inline uint64_t softmmu_tget64(CPUArchState *env, target_ulong addr) { uint64_t val; diff --git a/include/exec/tb-hash.h b/include/exec/tb-hash.h index 4f3a37d927dc67df4bd1e5b8c8ed3c00506450ca..805235d321c27390f6e85fc3586c65aec5b16992 100644 --- a/include/exec/tb-hash.h +++ b/include/exec/tb-hash.h @@ -20,6 +20,8 @@ #ifndef EXEC_TB_HASH_H #define EXEC_TB_HASH_H +#include "exec/cpu-defs.h" +#include "exec/exec-all.h" #include "qemu/xxhash.h" #ifdef CONFIG_SOFTMMU diff --git a/include/exec/user/thunk.h b/include/exec/user/thunk.h index 8d3af5a3be9d8150fb0a88814233f2393b124d63..eae2c27f99daa4f7b02e22911aaad7570c83a0e7 100644 --- a/include/exec/user/thunk.h +++ b/include/exec/user/thunk.h @@ -16,10 +16,12 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ + #ifndef THUNK_H #define THUNK_H #include "cpu.h" +#include "exec/user/abitypes.h" /* types enums definitions */ diff --git a/include/fpu/softfloat-macros.h b/include/fpu/softfloat-macros.h index c55aa6d1742381dedc89f4fa429b88c87e4dfced..be83a833ec90eabfb21f0b141c1ac72483b4dd49 100644 --- a/include/fpu/softfloat-macros.h +++ b/include/fpu/softfloat-macros.h @@ -82,6 +82,8 @@ this code that are retained. #ifndef FPU_SOFTFLOAT_MACROS_H #define FPU_SOFTFLOAT_MACROS_H +#include "fpu/softfloat.h" + /*---------------------------------------------------------------------------- | Shifts `a' right by the number of bits given in `count'. If any nonzero | bits are shifted off, they are ``jammed'' into the least significant bit of diff --git a/include/hw/acpi/pci.h b/include/hw/acpi/pci.h index 8bbd32cf45d9dd8281bbc4f49ead50cd3b220521..bf2a3ed0bab96e37207b77a9dd5e110f948b62ba 100644 --- a/include/hw/acpi/pci.h +++ b/include/hw/acpi/pci.h @@ -22,9 +22,12 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ + #ifndef HW_ACPI_PCI_H #define HW_ACPI_PCI_H +#include "hw/acpi/bios-linker-loader.h" + typedef struct AcpiMcfgInfo { uint64_t base; uint32_t size; diff --git a/include/hw/acpi/tco.h b/include/hw/acpi/tco.h index d19dd59353313696a62a494d3ae354dfd4a7a5da..726f840cce0b826eac379e4ce4cc8bf7d0fdb865 100644 --- a/include/hw/acpi/tco.h +++ b/include/hw/acpi/tco.h @@ -6,9 +6,12 @@ * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ + #ifndef HW_ACPI_TCO_H #define HW_ACPI_TCO_H +#include "exec/memory.h" +#include "migration/vmstate.h" /* As per ICH9 spec, the internal timer has an error of ~0.6s on every tick */ #define TCO_TICK_NSEC 600000000LL diff --git a/include/hw/adc/stm32f2xx_adc.h b/include/hw/adc/stm32f2xx_adc.h index a72f734eb1eb21a4e38bd1ef905ffc3d747b1da1..663b79f4f3a8ef32919e2c674011c7d999eecfec 100644 --- a/include/hw/adc/stm32f2xx_adc.h +++ b/include/hw/adc/stm32f2xx_adc.h @@ -25,6 +25,8 @@ #ifndef HW_STM32F2XX_ADC_H #define HW_STM32F2XX_ADC_H +#include "hw/sysbus.h" + #define ADC_SR 0x00 #define ADC_CR1 0x04 #define ADC_CR2 0x08 diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h index e99fe2ea2efa8732547d1154df0b2db72b3e5086..7182ce5c4b2d55147a6388571f90d45345fd1a94 100644 --- a/include/hw/arm/allwinner-a10.h +++ b/include/hw/arm/allwinner-a10.h @@ -11,6 +11,7 @@ #include "hw/ide/ahci.h" #include "sysemu/sysemu.h" +#include "target/arm/cpu.h" #define AW_A10_PIC_REG_BASE 0x01c20400 diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index cef605ad6bde081decb8a6f5b57c58bcdf552f62..976fd6be93f61433f14167ec4167636a3406d998 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -22,6 +22,7 @@ #include "hw/ssi/aspeed_smc.h" #include "hw/watchdog/wdt_aspeed.h" #include "hw/net/ftgmac100.h" +#include "target/arm/cpu.h" #define ASPEED_SPIS_NUM 2 #define ASPEED_WDTS_NUM 3 diff --git a/include/hw/arm/bcm2836.h b/include/hw/arm/bcm2836.h index a2cb8454dea705dd2ee98fd19096cb28d5d0e536..97187f72be9aa81921e0011721ed6691c7d7401c 100644 --- a/include/hw/arm/bcm2836.h +++ b/include/hw/arm/bcm2836.h @@ -13,6 +13,7 @@ #include "hw/arm/bcm2835_peripherals.h" #include "hw/intc/bcm2836_control.h" +#include "target/arm/cpu.h" #define TYPE_BCM283X "bcm283x" #define BCM283X(obj) OBJECT_CHECK(BCM283XState, (obj), TYPE_BCM283X) diff --git a/include/hw/arm/exynos4210.h b/include/hw/arm/exynos4210.h index aa137271c059a47c3481ded37761f2075bb6ec87..f0f23b0e9b2ee22a0c9c6958b248fd3f48249b5f 100644 --- a/include/hw/arm/exynos4210.h +++ b/include/hw/arm/exynos4210.h @@ -19,13 +19,12 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, see . - * */ #ifndef EXYNOS4210_H #define EXYNOS4210_H -#include "exec/memory.h" +#include "hw/sysbus.h" #include "target/arm/cpu-qom.h" #define EXYNOS4210_NCPUS 2 diff --git a/include/hw/arm/fsl-imx25.h b/include/hw/arm/fsl-imx25.h index 3280ab1fb0585b19f86747fed482f0b64087f668..241efb52ae043b7aaf3a302f344b4185cdb959eb 100644 --- a/include/hw/arm/fsl-imx25.h +++ b/include/hw/arm/fsl-imx25.h @@ -27,6 +27,7 @@ #include "hw/i2c/imx_i2c.h" #include "hw/gpio/imx_gpio.h" #include "exec/memory.h" +#include "target/arm/cpu.h" #define TYPE_FSL_IMX25 "fsl,imx25" #define FSL_IMX25(obj) OBJECT_CHECK(FslIMX25State, (obj), TYPE_FSL_IMX25) diff --git a/include/hw/arm/fsl-imx31.h b/include/hw/arm/fsl-imx31.h index e68a81efd750e66a935b8431a00b827352421473..ac5ca9826a494ed0c3249ae953e4b8b84d2323af 100644 --- a/include/hw/arm/fsl-imx31.h +++ b/include/hw/arm/fsl-imx31.h @@ -26,6 +26,7 @@ #include "hw/i2c/imx_i2c.h" #include "hw/gpio/imx_gpio.h" #include "exec/memory.h" +#include "target/arm/cpu.h" #define TYPE_FSL_IMX31 "fsl,imx31" #define FSL_IMX31(obj) OBJECT_CHECK(FslIMX31State, (obj), TYPE_FSL_IMX31) diff --git a/include/hw/arm/sharpsl.h b/include/hw/arm/sharpsl.h index 5bf6db1fa250d9d3b713d0337a67431afc74c104..89e168fbff39478e7f294031e9b737e3bc6a2391 100644 --- a/include/hw/arm/sharpsl.h +++ b/include/hw/arm/sharpsl.h @@ -3,9 +3,12 @@ * * This file is licensed under the GNU GPL. */ + #ifndef QEMU_SHARPSL_H #define QEMU_SHARPSL_H +#include "exec/hwaddr.h" + #define zaurus_printf(format, ...) \ fprintf(stderr, "%s: " format, __func__, ##__VA_ARGS__) diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h index 35804ea80a22ffc147d41c8b42a5595b4f078a12..6cb65e7537577a37a9a98563b22819fd6d97fa83 100644 --- a/include/hw/arm/xlnx-zynqmp.h +++ b/include/hw/arm/xlnx-zynqmp.h @@ -32,6 +32,7 @@ #include "hw/intc/xlnx-zynqmp-ipi.h" #include "hw/timer/xlnx-zynqmp-rtc.h" #include "hw/cpu/cluster.h" +#include "target/arm/cpu.h" #define TYPE_XLNX_ZYNQMP "xlnx,zynqmp" #define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \ diff --git a/include/hw/block/fdc.h b/include/hw/block/fdc.h index 8cece84326547eb3ad10d53b7191807adc06a742..f4fe2f471b408019035a87bef94bb7426e390c93 100644 --- a/include/hw/block/fdc.h +++ b/include/hw/block/fdc.h @@ -1,6 +1,8 @@ #ifndef HW_FDC_H #define HW_FDC_H +#include "exec/hwaddr.h" +#include "hw/irq.h" #include "qapi/qapi-types-block.h" /* fdc.c */ diff --git a/include/hw/block/flash.h b/include/hw/block/flash.h index 1acaf7de80219cca8b9689fccbca5ea101d6a810..83a75f317003d225f71e570f24021b2e25a56286 100644 --- a/include/hw/block/flash.h +++ b/include/hw/block/flash.h @@ -4,6 +4,7 @@ /* NOR flash devices */ #include "exec/memory.h" +#include "migration/vmstate.h" /* pflash_cfi01.c */ diff --git a/include/hw/char/escc.h b/include/hw/char/escc.h index 42aca83611023467edf9a389c2a2a49a7f991793..d5196c53e6f3c36ffa58e74c6c3c8e44e2186533 100644 --- a/include/hw/char/escc.h +++ b/include/hw/char/escc.h @@ -3,6 +3,7 @@ #include "chardev/char-fe.h" #include "chardev/char-serial.h" +#include "hw/sysbus.h" #include "ui/input.h" /* escc.c */ diff --git a/include/hw/char/xilinx_uartlite.h b/include/hw/char/xilinx_uartlite.h index 634086b6573283894fbb90c01c13d8e7082d9559..99d8bbf40533f9a45f57f70ec971159018a1983b 100644 --- a/include/hw/char/xilinx_uartlite.h +++ b/include/hw/char/xilinx_uartlite.h @@ -15,6 +15,8 @@ #ifndef XILINX_UARTLITE_H #define XILINX_UARTLITE_H +#include "hw/sysbus.h" + static inline DeviceState *xilinx_uartlite_create(hwaddr addr, qemu_irq irq, Chardev *chr) diff --git a/include/hw/core/generic-loader.h b/include/hw/core/generic-loader.h index dd27c42ab03abe2ae12c066dc8c87419c1c4fe86..9ffce1c5a30c464083f01d4e185a87cee113693b 100644 --- a/include/hw/core/generic-loader.h +++ b/include/hw/core/generic-loader.h @@ -19,6 +19,7 @@ #define GENERIC_LOADER_H #include "elf.h" +#include "hw/qdev-core.h" typedef struct GenericLoaderState { /* */ diff --git a/include/hw/cris/etraxfs.h b/include/hw/cris/etraxfs.h index 8da965addb68573c79e86f64c60660d915a654e4..494222d315fe30d91bbe3eb1825b12638ab0e824 100644 --- a/include/hw/cris/etraxfs.h +++ b/include/hw/cris/etraxfs.h @@ -27,6 +27,7 @@ #include "net/net.h" #include "hw/cris/etraxfs_dma.h" +#include "hw/sysbus.h" /* Instantiate an ETRAXFS Ethernet MAC. */ static inline DeviceState * diff --git a/include/hw/cris/etraxfs_dma.h b/include/hw/cris/etraxfs_dma.h index f6f33e0980f423476bbb99d5bfeee41a388d2976..31ae360611f464a7aa076f45f34ac37aca8c7295 100644 --- a/include/hw/cris/etraxfs_dma.h +++ b/include/hw/cris/etraxfs_dma.h @@ -1,6 +1,9 @@ #ifndef HW_ETRAXFS_DMA_H #define HW_ETRAXFS_DMA_H +#include "exec/hwaddr.h" +#include "hw/irq.h" + struct dma_context_metadata { /* data descriptor md */ uint16_t metadata; diff --git a/include/hw/display/i2c-ddc.h b/include/hw/display/i2c-ddc.h index c29443c5afd4b189e201d4ae10e64db387cfcc6f..1cf53a0c8dbc8244380d6186897c4eede77c5106 100644 --- a/include/hw/display/i2c-ddc.h +++ b/include/hw/display/i2c-ddc.h @@ -20,6 +20,7 @@ #define I2C_DDC_H #include "hw/display/edid.h" +#include "hw/i2c/i2c.h" /* A simple I2C slave which just returns the contents of its EDID blob. */ struct I2CDDCState { diff --git a/include/hw/empty_slot.h b/include/hw/empty_slot.h index 123a9f89890b23892c5565b0010a3d2274b2bb4a..cb9a221aa622a62e9cb33222b3d9bcfb0ac832f0 100644 --- a/include/hw/empty_slot.h +++ b/include/hw/empty_slot.h @@ -1,6 +1,8 @@ #ifndef HW_EMPTY_SLOT_H #define HW_EMPTY_SLOT_H +#include "exec/hwaddr.h" + /* empty_slot.c */ void empty_slot_init(hwaddr addr, uint64_t slot_size); diff --git a/include/hw/gpio/bcm2835_gpio.h b/include/hw/gpio/bcm2835_gpio.h index 9f8e0c720c3855a4688a6949fc955bf2cfe22772..b0de0a3c749dbbfa688c396f77a69823369c9b39 100644 --- a/include/hw/gpio/bcm2835_gpio.h +++ b/include/hw/gpio/bcm2835_gpio.h @@ -15,6 +15,7 @@ #define BCM2835_GPIO_H #include "hw/sd/sd.h" +#include "hw/sysbus.h" typedef struct BCM2835GpioState { SysBusDevice parent_obj; diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h index f9020acdef30feea42edd96ffd4d751626e2a899..a2753f0bbbaa82076b262d7e8517bddb06d327a8 100644 --- a/include/hw/i2c/aspeed_i2c.h +++ b/include/hw/i2c/aspeed_i2c.h @@ -17,10 +17,12 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + #ifndef ASPEED_I2C_H #define ASPEED_I2C_H #include "hw/i2c/i2c.h" +#include "hw/sysbus.h" #define TYPE_ASPEED_I2C "aspeed.i2c" #define ASPEED_I2C(obj) \ diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h index 1209eb483ab6c10d1d2cd0f3ee65ba6cd364942a..b04bdd947f8b08dc9a432adb60cefffec690aad8 100644 --- a/include/hw/i386/apic_internal.h +++ b/include/hw/i386/apic_internal.h @@ -24,6 +24,7 @@ #include "cpu.h" #include "exec/memory.h" #include "qemu/timer.h" +#include "target/i386/cpu-qom.h" /* APIC Local Vector Table */ #define APIC_LVT_TIMER 0 diff --git a/include/hw/i386/ioapic_internal.h b/include/hw/i386/ioapic_internal.h index 07002f966215965518096ce0021a8d9ce423acc8..3d2eec2aa77ca39f779fb1d92202fd1671de5868 100644 --- a/include/hw/i386/ioapic_internal.h +++ b/include/hw/i386/ioapic_internal.h @@ -24,6 +24,7 @@ #include "hw/hw.h" #include "exec/memory.h" +#include "hw/i386/ioapic.h" #include "hw/sysbus.h" #include "qemu/notify.h" diff --git a/include/hw/intc/allwinner-a10-pic.h b/include/hw/intc/allwinner-a10-pic.h index 1d314a70d9ef1efb614ea82b9dc292d07d4ab59b..a5895401d15fd7ec0db4056bfac8138028fe235e 100644 --- a/include/hw/intc/allwinner-a10-pic.h +++ b/include/hw/intc/allwinner-a10-pic.h @@ -1,6 +1,8 @@ #ifndef ALLWINNER_A10_PIC_H #define ALLWINNER_A10_PIC_H +#include "hw/sysbus.h" + #define TYPE_AW_A10_PIC "allwinner-a10-pic" #define AW_A10_PIC(obj) OBJECT_CHECK(AwA10PICState, (obj), TYPE_AW_A10_PIC) diff --git a/include/hw/intc/heathrow_pic.h b/include/hw/intc/heathrow_pic.h index 6c91ec91bb51eeba119d16749bad603f8c03bfaa..b163e27ab940e9d5f77b93d94008653187ae3eb9 100644 --- a/include/hw/intc/heathrow_pic.h +++ b/include/hw/intc/heathrow_pic.h @@ -26,6 +26,8 @@ #ifndef HW_INTC_HEATHROW_PIC_H #define HW_INTC_HEATHROW_PIC_H +#include "hw/sysbus.h" + #define TYPE_HEATHROW "heathrow" #define HEATHROW(obj) OBJECT_CHECK(HeathrowState, (obj), TYPE_HEATHROW) diff --git a/include/hw/intc/mips_gic.h b/include/hw/intc/mips_gic.h index 902a12b1780f6497126168a4c2e7ec3a33b450aa..8428287bf981f5b85a3f0d8276bcfb5db5fd281d 100644 --- a/include/hw/intc/mips_gic.h +++ b/include/hw/intc/mips_gic.h @@ -13,6 +13,7 @@ #include "qemu/units.h" #include "hw/timer/mips_gictimer.h" +#include "hw/sysbus.h" #include "cpu.h" /* * GIC Specific definitions diff --git a/include/hw/isa/vt82c686.h b/include/hw/isa/vt82c686.h index c3c2b6e786769e298824485a77b5ff7e091098c1..a54c3fe60a0124b1302740444d66004b6755c936 100644 --- a/include/hw/isa/vt82c686.h +++ b/include/hw/isa/vt82c686.h @@ -1,6 +1,8 @@ #ifndef HW_VT82C686_H #define HW_VT82C686_H +#include "hw/irq.h" + #define TYPE_VT82C686B_SUPERIO "vt82c686b-superio" /* vt82c686.c */ diff --git a/include/hw/mips/cps.h b/include/hw/mips/cps.h index aab1af926dff8cb11449d965b615789c202de634..a941c55f27e7f6619a92f054eb21a57ff84c7d94 100644 --- a/include/hw/mips/cps.h +++ b/include/hw/mips/cps.h @@ -25,6 +25,7 @@ #include "hw/intc/mips_gic.h" #include "hw/misc/mips_cpc.h" #include "hw/misc/mips_itu.h" +#include "target/mips/cpu.h" #define TYPE_MIPS_CPS "mips-cps" #define MIPS_CPS(obj) OBJECT_CHECK(MIPSCPSState, (obj), TYPE_MIPS_CPS) diff --git a/include/hw/misc/macio/cuda.h b/include/hw/misc/macio/cuda.h index 7dad469142369056379cf4d6b032feb15cae29c2..5768075ac5d3b5ddc81c5fe1e4b35a010984821d 100644 --- a/include/hw/misc/macio/cuda.h +++ b/include/hw/misc/macio/cuda.h @@ -26,6 +26,8 @@ #ifndef CUDA_H #define CUDA_H +#include "hw/misc/mos6522.h" + /* CUDA commands (2nd byte) */ #define CUDA_WARM_START 0x0 #define CUDA_AUTOPOLL 0x1 diff --git a/include/hw/misc/macio/gpio.h b/include/hw/misc/macio/gpio.h index 2838ae5fde93b79ec427c0caed44a78a5bf05541..24a4364b39e70ac69b556195b39f5bd70a50c327 100644 --- a/include/hw/misc/macio/gpio.h +++ b/include/hw/misc/macio/gpio.h @@ -26,6 +26,9 @@ #ifndef MACIO_GPIO_H #define MACIO_GPIO_H +#include "hw/ppc/openpic.h" +#include "hw/sysbus.h" + #define TYPE_MACIO_GPIO "macio-gpio" #define MACIO_GPIO(obj) OBJECT_CHECK(MacIOGPIOState, (obj), TYPE_MACIO_GPIO) diff --git a/include/hw/misc/macio/macio.h b/include/hw/misc/macio/macio.h index 970058b6edfc219ce9f4423bffc994e950470a0b..070a694eb536a373079f59e2e78f758a4cf8e78b 100644 --- a/include/hw/misc/macio/macio.h +++ b/include/hw/misc/macio/macio.h @@ -27,10 +27,12 @@ #define MACIO_H #include "hw/char/escc.h" +#include "hw/ide/internal.h" #include "hw/intc/heathrow_pic.h" #include "hw/misc/macio/cuda.h" #include "hw/misc/macio/gpio.h" #include "hw/misc/macio/pmu.h" +#include "hw/ppc/mac.h" #include "hw/ppc/mac_dbdma.h" #include "hw/ppc/openpic.h" diff --git a/include/hw/misc/macio/pmu.h b/include/hw/misc/macio/pmu.h index d10895ba5f3950bfb102387b0a53921c6581233e..7ef83dee4c5772b6d7cbbd250ddf7601eafc3e7e 100644 --- a/include/hw/misc/macio/pmu.h +++ b/include/hw/misc/macio/pmu.h @@ -10,6 +10,9 @@ #ifndef PMU_H #define PMU_H +#include "hw/misc/mos6522.h" +#include "hw/misc/macio/gpio.h" + /* * PMU commands */ diff --git a/include/hw/misc/mips_cmgcr.h b/include/hw/misc/mips_cmgcr.h index c9dfcb4b84c2373668386434a3cb102927594d21..3e6e22327381d24669ef5ffd4c11e3479d4b2113 100644 --- a/include/hw/misc/mips_cmgcr.h +++ b/include/hw/misc/mips_cmgcr.h @@ -10,6 +10,8 @@ #ifndef MIPS_CMGCR_H #define MIPS_CMGCR_H +#include "hw/sysbus.h" + #define TYPE_MIPS_GCR "mips-gcr" #define MIPS_GCR(obj) OBJECT_CHECK(MIPSGCRState, (obj), TYPE_MIPS_GCR) diff --git a/include/hw/misc/mips_cpc.h b/include/hw/misc/mips_cpc.h index 72c834e039add7ce4f18a9219cf8ecaee6eb45a6..3f670578b05b366efe9a2da6ae33048d91e4522f 100644 --- a/include/hw/misc/mips_cpc.h +++ b/include/hw/misc/mips_cpc.h @@ -20,6 +20,8 @@ #ifndef MIPS_CPC_H #define MIPS_CPC_H +#include "hw/sysbus.h" + #define CPC_ADDRSPACE_SZ 0x6000 /* CPC blocks offsets relative to base address */ diff --git a/include/hw/misc/pvpanic.h b/include/hw/misc/pvpanic.h index 1ee071a70313e24a97a03e776bc90f08f4636ee7..ae0c8188cef7e6e920b5cbd5d1a91e3247befcf8 100644 --- a/include/hw/misc/pvpanic.h +++ b/include/hw/misc/pvpanic.h @@ -11,9 +11,12 @@ * See the COPYING file in the top-level directory. * */ + #ifndef HW_MISC_PVPANIC_H #define HW_MISC_PVPANIC_H +#include "qom/object.h" + #define TYPE_PVPANIC "pvpanic" #define PVPANIC_IOPORT_PROP "ioport" diff --git a/include/hw/net/allwinner_emac.h b/include/hw/net/allwinner_emac.h index 905a43deb43d9ccb74731aa4810ec7f1acb1a8d0..5013207d158aa9d426b0f1d0cf0466bd0a0daf7e 100644 --- a/include/hw/net/allwinner_emac.h +++ b/include/hw/net/allwinner_emac.h @@ -27,6 +27,7 @@ #include "net/net.h" #include "qemu/fifo8.h" #include "hw/net/mii.h" +#include "hw/sysbus.h" #define TYPE_AW_EMAC "allwinner-emac" #define AW_EMAC(obj) OBJECT_CHECK(AwEmacState, (obj), TYPE_AW_EMAC) diff --git a/include/hw/net/lance.h b/include/hw/net/lance.h index ffdd35c4d7134291bd45c4ac55187c2763fd059b..0357f5f65c1b3fc5a2a55fdf60ff585ed782ef96 100644 --- a/include/hw/net/lance.h +++ b/include/hw/net/lance.h @@ -31,6 +31,7 @@ #include "net/net.h" #include "hw/net/pcnet.h" +#include "hw/sysbus.h" #define TYPE_LANCE "lance" #define SYSBUS_PCNET(obj) \ diff --git a/include/hw/nvram/chrp_nvram.h b/include/hw/nvram/chrp_nvram.h index b4f5b2b104579464cac8d8b221d24844abc5659c..09941a9be454e1fc6af79e2eb27f01706ff4f825 100644 --- a/include/hw/nvram/chrp_nvram.h +++ b/include/hw/nvram/chrp_nvram.h @@ -18,6 +18,8 @@ #ifndef CHRP_NVRAM_H #define CHRP_NVRAM_H +#include "qemu/bswap.h" + /* OpenBIOS NVRAM partition */ typedef struct { uint8_t signature; diff --git a/include/hw/pci-host/sabre.h b/include/hw/pci-host/sabre.h index 9afa4938fd83cee9794c2e3875aee97db14169c9..99b5aefbecdda2dd170ac2bfdb0a62c220a05456 100644 --- a/include/hw/pci-host/sabre.h +++ b/include/hw/pci-host/sabre.h @@ -1,6 +1,8 @@ #ifndef HW_PCI_HOST_SABRE_H #define HW_PCI_HOST_SABRE_H +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" #include "hw/sparc/sun4u_iommu.h" #define MAX_IVEC 0x40 diff --git a/include/hw/pci-host/uninorth.h b/include/hw/pci-host/uninorth.h index 060324536aee4f3669896b65071f59dcb0d4852c..9a5cabd4c597630b561862901cd6bcec3f80c902 100644 --- a/include/hw/pci-host/uninorth.h +++ b/include/hw/pci-host/uninorth.h @@ -26,7 +26,7 @@ #define UNINORTH_H #include "hw/hw.h" - +#include "hw/pci/pci_host.h" #include "hw/ppc/openpic.h" /* UniNorth version */ diff --git a/include/hw/pci/pcie_aer.h b/include/hw/pci/pcie_aer.h index 729a9439c8a36421a3211c388a7213402f562221..502dcd7eba04b1b4c05b9254840b741a30d07d65 100644 --- a/include/hw/pci/pcie_aer.h +++ b/include/hw/pci/pcie_aer.h @@ -22,6 +22,7 @@ #define QEMU_PCIE_AER_H #include "hw/hw.h" +#include "hw/pci/pci_regs.h" /* definitions which PCIExpressDevice uses */ diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h index d0926454a9b36a1824578a0511e1f92faaa3a747..bfbd2ec42aa652fe4061f723cee39ecd7240344e 100644 --- a/include/hw/ppc/pnv_core.h +++ b/include/hw/ppc/pnv_core.h @@ -21,6 +21,7 @@ #define PPC_PNV_CORE_H #include "hw/cpu/core.h" +#include "target/ppc/cpu.h" #define TYPE_PNV_CORE "powernv-cpu-core" #define PNV_CORE(obj) \ diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h index 39a7ba1ce6a19de31002304d8fd2a2151b940028..90f8866138e867ec8e72afce55cb72371e8c043d 100644 --- a/include/hw/ppc/ppc4xx.h +++ b/include/hw/ppc/ppc4xx.h @@ -25,6 +25,10 @@ #ifndef PPC4XX_H #define PPC4XX_H +#include "hw/ppc/ppc.h" +#include "exec/cpu-common.h" +#include "exec/memory.h" + /* PowerPC 4xx core initialization */ PowerPCCPU *ppc4xx_init(const char *cpu_model, clk_setup_t *cpu_clk, clk_setup_t *tb_clk, diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index f965a58f89540a6a68e355ed82e0b98cadb3c38c..cd6e18b05e496b47082a3fc8ea8b72b024d49bb5 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -10,6 +10,9 @@ #ifndef HW_SPAPR_IRQ_H #define HW_SPAPR_IRQ_H +#include "hw/irq.h" +#include "target/ppc/cpu-qom.h" + /* * IRQ range offsets per device type */ diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h index 97951fc6b484e035dc74d2f25964b0387565f503..92bfa72caf2452dae07dddf4fcef3ab78ac8651c 100644 --- a/include/hw/ppc/spapr_vio.h +++ b/include/hw/ppc/spapr_vio.h @@ -22,6 +22,7 @@ * License along with this library; if not, see . */ +#include "hw/ppc/spapr.h" #include "sysemu/dma.h" #define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device" diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h index 71971442652497f9c12a418c84a4f6abb61b600e..a39e672f2766d5bef1687c45a0539fc2dff90ca6 100644 --- a/include/hw/ppc/spapr_xive.h +++ b/include/hw/ppc/spapr_xive.h @@ -10,7 +10,9 @@ #ifndef PPC_SPAPR_XIVE_H #define PPC_SPAPR_XIVE_H +#include "hw/ppc/spapr_irq.h" #include "hw/ppc/xive.h" +#include "sysemu/sysemu.h" #define TYPE_SPAPR_XIVE "spapr-xive" #define SPAPR_XIVE(obj) OBJECT_CHECK(SpaprXive, (obj), TYPE_SPAPR_XIVE) diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h index 1a8c5b5e64f05f3f0b46323a51c30f9d46815295..b0c68ab5f7a69a3dfe301bb149153d098a3f521c 100644 --- a/include/hw/ppc/xive_regs.h +++ b/include/hw/ppc/xive_regs.h @@ -16,6 +16,9 @@ #ifndef PPC_XIVE_REGS_H #define PPC_XIVE_REGS_H +#include "qemu/bswap.h" +#include "qemu/host-utils.h" + /* * Interrupt source number encoding on PowerBUS */ diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index d56f2ae3eb5d731d0c7c6995e8a72cbb5103f7b5..1f21c2bef1a6f153e3d6d0d1e37a290f26ee346f 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -20,6 +20,8 @@ #ifndef RISCV_BOOT_H #define RISCV_BOOT_H +#include "exec/cpu-defs.h" + void riscv_find_and_load_firmware(MachineState *machine, const char *default_machine_firmware, hwaddr firmware_load_addr); diff --git a/include/hw/riscv/riscv_hart.h b/include/hw/riscv/riscv_hart.h index 0671d88a443906762708d92273b9b93a9cac9d17..3b52b50571d26ef408eb34e0fd1aebe45917b69c 100644 --- a/include/hw/riscv/riscv_hart.h +++ b/include/hw/riscv/riscv_hart.h @@ -21,6 +21,9 @@ #ifndef HW_RISCV_HART_H #define HW_RISCV_HART_H +#include "hw/sysbus.h" +#include "target/riscv/cpu.h" + #define TYPE_RISCV_HART_ARRAY "riscv.hart_array" #define RISCV_HART_ARRAY(obj) \ diff --git a/include/hw/riscv/sifive_clint.h b/include/hw/riscv/sifive_clint.h index e2865be1d18b3a2f7bd5d2933f0c252e5010a22d..ae8286c884cc00c2d2f8205c395db8546ba22de7 100644 --- a/include/hw/riscv/sifive_clint.h +++ b/include/hw/riscv/sifive_clint.h @@ -20,6 +20,8 @@ #ifndef HW_SIFIVE_CLINT_H #define HW_SIFIVE_CLINT_H +#include "hw/sysbus.h" + #define TYPE_SIFIVE_CLINT "riscv.sifive.clint" #define SIFIVE_CLINT(obj) \ diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h index d175b24cb209403ef019d6eded0c21026f53dfb2..9c868dd7f96a3d7164996a51a0070db93465d865 100644 --- a/include/hw/riscv/sifive_e.h +++ b/include/hw/riscv/sifive_e.h @@ -19,6 +19,7 @@ #ifndef HW_SIFIVE_E_H #define HW_SIFIVE_E_H +#include "hw/riscv/riscv_hart.h" #include "hw/riscv/sifive_gpio.h" #define TYPE_RISCV_E_SOC "riscv.sifive.e.soc" diff --git a/include/hw/riscv/sifive_plic.h b/include/hw/riscv/sifive_plic.h index ce8907f6aa02d7373899df3e85783a90d929f65e..b0edba2884336fa78ecd376ea8c482a0df46ff4f 100644 --- a/include/hw/riscv/sifive_plic.h +++ b/include/hw/riscv/sifive_plic.h @@ -21,7 +21,7 @@ #ifndef HW_SIFIVE_PLIC_H #define HW_SIFIVE_PLIC_H -#include "hw/irq.h" +#include "hw/sysbus.h" #define TYPE_SIFIVE_PLIC "riscv.sifive.plic" diff --git a/include/hw/riscv/sifive_prci.h b/include/hw/riscv/sifive_prci.h index bd51c4af3c1c665b34040d06d406017bfcc63411..8b7de134f848514395cf17edadd26e2488102e40 100644 --- a/include/hw/riscv/sifive_prci.h +++ b/include/hw/riscv/sifive_prci.h @@ -19,6 +19,8 @@ #ifndef HW_SIFIVE_PRCI_H #define HW_SIFIVE_PRCI_H +#include "hw/sysbus.h" + enum { SIFIVE_PRCI_HFROSCCFG = 0x0, SIFIVE_PRCI_HFXOSCCFG = 0x4, diff --git a/include/hw/riscv/sifive_test.h b/include/hw/riscv/sifive_test.h index 71d4c9fad7292af199f5ff5539f686c18028ef03..3a603a6eadd57c061f3c517d23682f39c7e97799 100644 --- a/include/hw/riscv/sifive_test.h +++ b/include/hw/riscv/sifive_test.h @@ -19,6 +19,8 @@ #ifndef HW_SIFIVE_TEST_H #define HW_SIFIVE_TEST_H +#include "hw/sysbus.h" + #define TYPE_SIFIVE_TEST "riscv.sifive.test" #define SIFIVE_TEST(obj) \ diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index 892f0eee21bc926f8c48a9040e98936ed50e2d59..be021ce2566d2fa4e4329f0a9418893d72a1ea44 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -20,6 +20,7 @@ #define HW_SIFIVE_U_H #include "hw/net/cadence_gem.h" +#include "hw/riscv/riscv_hart.h" #define TYPE_RISCV_U_SOC "riscv.sifive.u.soc" #define RISCV_U_SOC(obj) \ diff --git a/include/hw/riscv/sifive_uart.h b/include/hw/riscv/sifive_uart.h index c8dc1c57fd0ba47b4b80bf5fba69077fbdef1be2..65668825a35daa8b0af60629b944bde28dfc325d 100644 --- a/include/hw/riscv/sifive_uart.h +++ b/include/hw/riscv/sifive_uart.h @@ -20,6 +20,9 @@ #ifndef HW_SIFIVE_UART_H #define HW_SIFIVE_UART_H +#include "chardev/char-fe.h" +#include "hw/sysbus.h" + enum { SIFIVE_UART_TXFIFO = 0, SIFIVE_UART_RXFIFO = 4, diff --git a/include/hw/riscv/spike.h b/include/hw/riscv/spike.h index 641b70da67b64d56e6598fe2278425064f758912..03d870363c7b66fd8a6369d221c0c73011e4ee1c 100644 --- a/include/hw/riscv/spike.h +++ b/include/hw/riscv/spike.h @@ -19,6 +19,9 @@ #ifndef HW_RISCV_SPIKE_H #define HW_RISCV_SPIKE_H +#include "hw/riscv/riscv_hart.h" +#include "hw/sysbus.h" + typedef struct { /*< private >*/ SysBusDevice parent_obj; diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h index d01a1a85c42671ecbcf7f6a528b1c8c68b5c4481..6e5fbe5d3b089040282bc77ef7c9b73256cc8edb 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -19,6 +19,9 @@ #ifndef HW_RISCV_VIRT_H #define HW_RISCV_VIRT_H +#include "hw/riscv/riscv_hart.h" +#include "hw/sysbus.h" + typedef struct { /*< private >*/ SysBusDevice parent_obj; diff --git a/include/hw/s390x/ap-device.h b/include/hw/s390x/ap-device.h index 765e9082a3dbe5775238824d5d68df865475906c..8df9cd29542f290a50f2a68622c96a73b3ed3008 100644 --- a/include/hw/s390x/ap-device.h +++ b/include/hw/s390x/ap-device.h @@ -7,9 +7,12 @@ * your option) any later version. See the COPYING file in the top-level * directory. */ + #ifndef HW_S390X_AP_DEVICE_H #define HW_S390X_AP_DEVICE_H +#include "hw/qdev-core.h" + #define AP_DEVICE_TYPE "ap-device" typedef struct APDevice { diff --git a/include/hw/s390x/css-bridge.h b/include/hw/s390x/css-bridge.h index 5a0203be5f95061bf65a815c01dd9d4a0a589df1..f7ed2d9a03e4d6021f29387f2317c6a32faaa7fc 100644 --- a/include/hw/s390x/css-bridge.h +++ b/include/hw/s390x/css-bridge.h @@ -12,8 +12,9 @@ #ifndef HW_S390X_CSS_BRIDGE_H #define HW_S390X_CSS_BRIDGE_H + #include "qom/object.h" -#include "hw/qdev-core.h" +#include "hw/sysbus.h" /* virtual css bridge */ typedef struct VirtualCssBridge { diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index d033387fba8a1cf5e9676c5e9708d9f85c0f241a..f46bcafb16c3f8c80ed967e8901f211d34e17496 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -17,6 +17,7 @@ #include "hw/s390x/s390_flic.h" #include "hw/s390x/ioinst.h" #include "sysemu/kvm.h" +#include "target/s390x/cpu-qom.h" /* Channel subsystem constants. */ #define MAX_DEVNO 65535 diff --git a/include/hw/s390x/tod.h b/include/hw/s390x/tod.h index 9c4a6000c33179274e676ede25e86ee2f161d610..d71f4ea8a7995390ff988faa1662483a416e5a6c 100644 --- a/include/hw/s390x/tod.h +++ b/include/hw/s390x/tod.h @@ -12,7 +12,7 @@ #define HW_S390_TOD_H #include "hw/qdev.h" -#include "s390-tod.h" +#include "target/s390x/s390-tod.h" typedef struct S390TOD { uint8_t high; diff --git a/include/hw/semihosting/console.h b/include/hw/semihosting/console.h index cfab572c0c384c213b81b5b377bb7872f71899f5..9be9754bcdf776249fc341fa6e5b150446815c98 100644 --- a/include/hw/semihosting/console.h +++ b/include/hw/semihosting/console.h @@ -9,6 +9,8 @@ #ifndef SEMIHOST_CONSOLE_H #define SEMIHOST_CONSOLE_H +#include "cpu.h" + /** * qemu_semihosting_console_outs: * @env: CPUArchState diff --git a/include/hw/sh4/sh_intc.h b/include/hw/sh4/sh_intc.h index b7c2404334bb3be2ee802458a28c5bf8fb4aaa59..3d3efde0598c30590d9a95255afbb27242087c98 100644 --- a/include/hw/sh4/sh_intc.h +++ b/include/hw/sh4/sh_intc.h @@ -1,6 +1,7 @@ #ifndef SH_INTC_H #define SH_INTC_H +#include "exec/memory.h" #include "hw/irq.h" typedef unsigned char intc_enum; diff --git a/include/hw/sparc/sparc64.h b/include/hw/sparc/sparc64.h index 21ab79e34348e3203b5763b1a30132c43bf4ecc8..4ced36fb5a59684031e7632653b5860cfcdb3830 100644 --- a/include/hw/sparc/sparc64.h +++ b/include/hw/sparc/sparc64.h @@ -1,6 +1,8 @@ #ifndef HW_SPARC_SPARC64_H #define HW_SPARC_SPARC64_H +#include "target/sparc/cpu-qom.h" + #define IVEC_MAX 0x40 SPARCCPU *sparc64_cpu_devinit(const char *cpu_type, uint64_t prom_addr); diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h index 591279ba1f43d5ba38a6deac637b6accfa4073d4..aa07dac4fe3724e693138d02e8095f1b5c36f539 100644 --- a/include/hw/ssi/aspeed_smc.h +++ b/include/hw/ssi/aspeed_smc.h @@ -26,6 +26,7 @@ #define ASPEED_SMC_H #include "hw/ssi/ssi.h" +#include "hw/sysbus.h" typedef struct AspeedSegments { hwaddr addr; diff --git a/include/hw/ssi/xilinx_spips.h b/include/hw/ssi/xilinx_spips.h index a0a0ae7584aa16c175c00fd7045a65eb654e5c6b..6a39b55a7bdcd14515ab44d0d80dc2c837fa562d 100644 --- a/include/hw/ssi/xilinx_spips.h +++ b/include/hw/ssi/xilinx_spips.h @@ -28,6 +28,7 @@ #include "hw/ssi/ssi.h" #include "qemu/fifo32.h" #include "hw/stream.h" +#include "hw/sysbus.h" typedef struct XilinxSPIPS XilinxSPIPS; diff --git a/include/hw/timer/allwinner-a10-pit.h b/include/hw/timer/allwinner-a10-pit.h index c0cc3e2169e1cae2cde44aa742f3c3e71951c0b2..871c95b5128018b60c37603b8ca2a08a46a5cbcc 100644 --- a/include/hw/timer/allwinner-a10-pit.h +++ b/include/hw/timer/allwinner-a10-pit.h @@ -2,6 +2,7 @@ #define ALLWINNER_A10_PIT_H #include "hw/ptimer.h" +#include "hw/sysbus.h" #define TYPE_AW_A10_PIT "allwinner-A10-timer" #define AW_A10_PIT(obj) OBJECT_CHECK(AwA10PITState, (obj), TYPE_AW_A10_PIT) diff --git a/include/hw/timer/i8254_internal.h b/include/hw/timer/i8254_internal.h index c37a438f82e293733db3d87853d392a7e6b5e50e..e611c6f227bf9ee430b1973954ee7ade17018903 100644 --- a/include/hw/timer/i8254_internal.h +++ b/include/hw/timer/i8254_internal.h @@ -27,6 +27,7 @@ #include "hw/hw.h" #include "hw/isa/isa.h" +#include "hw/timer/i8254.h" #include "qemu/timer.h" typedef struct PITChannelState { diff --git a/include/hw/timer/m48t59.h b/include/hw/timer/m48t59.h index 43efc91f567ceeb22c0ad17e6716d9a6ab56de69..d3fb50e08cae8fde3816409602f5303856be8747 100644 --- a/include/hw/timer/m48t59.h +++ b/include/hw/timer/m48t59.h @@ -1,6 +1,8 @@ #ifndef HW_M48T59_H #define HW_M48T59_H +#include "exec/hwaddr.h" +#include "hw/irq.h" #include "qom/object.h" #define TYPE_NVRAM "nvram" diff --git a/include/hw/timer/mc146818rtc_regs.h b/include/hw/timer/mc146818rtc_regs.h index c62f17bf2d3690b033b8501c880b4d2d00a10e0a..bfbb57e57012d6ed6b4f77f68f6238d929aad034 100644 --- a/include/hw/timer/mc146818rtc_regs.h +++ b/include/hw/timer/mc146818rtc_regs.h @@ -25,6 +25,8 @@ #ifndef MC146818RTC_REGS_H #define MC146818RTC_REGS_H +#include "qemu/timer.h" + #define RTC_ISA_IRQ 8 #define RTC_SECONDS 0 diff --git a/include/hw/timer/xlnx-zynqmp-rtc.h b/include/hw/timer/xlnx-zynqmp-rtc.h index 6e9134edf63f18f80a0fae8e842a49f4b583f187..97e32322ed705be520d602a1eea19b609eb312d6 100644 --- a/include/hw/timer/xlnx-zynqmp-rtc.h +++ b/include/hw/timer/xlnx-zynqmp-rtc.h @@ -28,6 +28,7 @@ #define HW_TIMER_XLNX_ZYNQMP_RTC_H #include "hw/register.h" +#include "hw/sysbus.h" #define TYPE_XLNX_ZYNQMP_RTC "xlnx-zynmp.rtc" diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 9107bd41c0304ceb8b1c659f413aa8a5348a7a43..048731e81f70bf6e836a81a68729eff9968e577c 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -29,6 +29,7 @@ #ifdef CONFIG_LINUX #include #endif +#include "sysemu/sysemu.h" #define VFIO_MSG_PREFIX "vfio %s: " @@ -57,6 +58,16 @@ typedef struct VFIORegion { uint8_t nr; /* cache the region number for debug */ } VFIORegion; +typedef struct VFIOMigration { + struct VFIODevice *vbasedev; + VMChangeStateEntry *vm_state; + VFIORegion region; + uint32_t device_state; + int vm_running; + Notifier migration_state; + uint64_t pending_bytes; +} VFIOMigration; + typedef struct VFIOAddressSpace { AddressSpace *as; QLIST_HEAD(, VFIOContainer) containers; @@ -73,6 +84,9 @@ typedef struct VFIOContainer { unsigned iommu_type; int error; bool initialized; + bool dirty_pages_supported; + uint64_t dirty_pgsizes; + uint64_t max_dirty_bitmap_size; unsigned long pgsizes; QLIST_HEAD(, VFIOGuestIOMMU) giommu_list; QLIST_HEAD(, VFIOHostDMAWindow) hostwin_list; @@ -113,12 +127,17 @@ typedef struct VFIODevice { unsigned int num_irqs; unsigned int num_regions; unsigned int flags; + VFIOMigration *migration; + Error *migration_blocker; } VFIODevice; struct VFIODeviceOps { void (*vfio_compute_needs_reset)(VFIODevice *vdev); int (*vfio_hot_reset_multi)(VFIODevice *vdev); void (*vfio_eoi)(VFIODevice *vdev); + Object *(*vfio_get_object)(VFIODevice *vdev); + void (*vfio_save_config)(VFIODevice *vdev, QEMUFile *f); + int (*vfio_load_config)(VFIODevice *vdev, QEMUFile *f); }; typedef struct VFIOGroup { @@ -171,6 +190,7 @@ int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, int index, const char *name); int vfio_region_mmap(VFIORegion *region); void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled); +void vfio_region_unmap(VFIORegion *region); void vfio_region_exit(VFIORegion *region); void vfio_region_finalize(VFIORegion *region); void vfio_reset_handler(void *opaque); @@ -183,6 +203,9 @@ extern const MemoryRegionOps vfio_region_ops; typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList; extern VFIOGroupList vfio_group_list; +bool vfio_mig_active(void); +int64_t vfio_mig_bytes_transferred(void); + #ifdef CONFIG_LINUX int vfio_get_region_info(VFIODevice *vbasedev, int index, struct vfio_region_info **info); @@ -200,4 +223,7 @@ int vfio_spapr_create_window(VFIOContainer *container, int vfio_spapr_remove_window(VFIOContainer *container, hwaddr offset_within_address_space); +int vfio_migration_probe(VFIODevice *vbasedev, Error **errp); +void vfio_migration_finalize(VFIODevice *vbasedev); + #endif /* HW_VFIO_VFIO_COMMON_H */ diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h index bdf58f3119f86d5e86e4ba5ba6fdecaa5f773a90..6818a23a2d351858dd60e4b3b72b2e1c86b416da 100644 --- a/include/hw/virtio/virtio-access.h +++ b/include/hw/virtio/virtio-access.h @@ -16,6 +16,7 @@ #ifndef QEMU_VIRTIO_ACCESS_H #define QEMU_VIRTIO_ACCESS_H +#include "exec/hwaddr.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-bus.h" diff --git a/include/hw/virtio/virtio-gpu-bswap.h b/include/hw/virtio/virtio-gpu-bswap.h index 38d12160f6a9176325cd6f3f2369a22153e55e69..203f9e17189ee7b4c8c3aba684766d6dff05b8fc 100644 --- a/include/hw/virtio/virtio-gpu-bswap.h +++ b/include/hw/virtio/virtio-gpu-bswap.h @@ -15,6 +15,7 @@ #define HW_VIRTIO_GPU_BSWAP_H #include "qemu/bswap.h" +#include "standard-headers/linux/virtio_gpu.h" static inline void virtio_gpu_ctrl_hdr_bswap(struct virtio_gpu_ctrl_hdr *hdr) diff --git a/include/hw/virtio/virtio-rng.h b/include/hw/virtio/virtio-rng.h index 922dce7caccf7f05bb9e6d100893d9cd30676bf0..ff699335e3b9a18762d6306d6e099855241c5195 100644 --- a/include/hw/virtio/virtio-rng.h +++ b/include/hw/virtio/virtio-rng.h @@ -12,6 +12,7 @@ #ifndef QEMU_VIRTIO_RNG_H #define QEMU_VIRTIO_RNG_H +#include "hw/virtio/virtio.h" #include "sysemu/rng.h" #include "sysemu/rng-random.h" #include "standard-headers/linux/virtio_rng.h" diff --git a/include/hw/vmstate-if.h b/include/hw/vmstate-if.h new file mode 100644 index 0000000000000000000000000000000000000000..8ff7f0f2929813f8b7cda82f6e4b877f82757b77 --- /dev/null +++ b/include/hw/vmstate-if.h @@ -0,0 +1,40 @@ +/* + * VMState interface + * + * Copyright (c) 2009-2019 Red Hat Inc + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef VMSTATE_IF_H +#define VMSTATE_IF_H + +#include "qom/object.h" + +#define TYPE_VMSTATE_IF "vmstate-if" + +#define VMSTATE_IF_CLASS(klass) \ + OBJECT_CLASS_CHECK(VMStateIfClass, (klass), TYPE_VMSTATE_IF) +#define VMSTATE_IF_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VMStateIfClass, (obj), TYPE_VMSTATE_IF) +#define VMSTATE_IF(obj) \ + INTERFACE_CHECK(VMStateIf, (obj), TYPE_VMSTATE_IF) + +typedef struct VMStateIf VMStateIf; + +typedef struct VMStateIfClass { + InterfaceClass parent_class; + + char * (*get_id)(VMStateIf *obj); +} VMStateIfClass; + +static inline char *vmstate_if_get_id(VMStateIf *vmif) +{ + if (!vmif) { + return NULL; + } + + return VMSTATE_IF_GET_CLASS(vmif)->get_id(vmif); +} + +#endif /* VMSTATE_IF_H */ diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h index daef0c0e230bfa2627a05300cdf52c91581e5985..8c5691ce20476723af5e8bd6cb27c272bc46b671 100644 --- a/include/hw/watchdog/wdt_aspeed.h +++ b/include/hw/watchdog/wdt_aspeed.h @@ -10,6 +10,7 @@ #ifndef WDT_ASPEED_H #define WDT_ASPEED_H +#include "hw/misc/aspeed_scu.h" #include "hw/sysbus.h" #define TYPE_ASPEED_WDT "aspeed.wdt" diff --git a/include/libdecnumber/decNumberLocal.h b/include/libdecnumber/decNumberLocal.h index 12cf1d8b6f34cc9980faaf185481282e71cc9eb2..4d53c077f2af7249faa107eb5f9c12abbf139b1e 100644 --- a/include/libdecnumber/decNumberLocal.h +++ b/include/libdecnumber/decNumberLocal.h @@ -44,6 +44,7 @@ #define DECNLAUTHOR "Mike Cowlishaw" /* Who to blame */ #include "libdecnumber/dconfig.h" + #include "libdecnumber/decContext.h" /* Conditional code flag -- set this to match hardware platform */ /* 1=little-endian, 0=big-endian */ diff --git a/include/migration/cpu.h b/include/migration/cpu.h index a40bd3549f4743f7bf0c7c70feb32df0958c084f..da1618d6206fa439cee59b2fd66c34632fc65970 100644 --- a/include/migration/cpu.h +++ b/include/migration/cpu.h @@ -1,7 +1,10 @@ /* Declarations for use for CPU state serialization. */ + #ifndef MIGRATION_CPU_H #define MIGRATION_CPU_H +#include "exec/cpu-defs.h" + #if TARGET_LONG_BITS == 64 #define qemu_put_betl qemu_put_be64 #define qemu_get_betl qemu_get_be64 diff --git a/include/migration/register.h b/include/migration/register.h index 8b2bc5b12991f37c81daeb99396bbaa733e7dcaa..158130c8c4ddb814f98bc8430eaebd8d08d8036e 100644 --- a/include/migration/register.h +++ b/include/migration/register.h @@ -14,6 +14,8 @@ #ifndef MIGRATION_REGISTER_H #define MIGRATION_REGISTER_H +#include "hw/vmstate-if.h" + typedef struct SaveVMHandlers { /* This runs inside the iothread lock. */ SaveStateHandler *save_state; @@ -68,8 +70,7 @@ typedef struct SaveVMHandlers { int (*resume_prepare)(MigrationState *s, void *opaque); } SaveVMHandlers; -int register_savevm_live(DeviceState *dev, - const char *idstr, +int register_savevm_live(const char *idstr, uint32_t instance_id, int version_id, const SaveVMHandlers *ops, diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 8abd2e3b80703c7bc1d2faa1d69b3523a4307bc4..8cc1e19fd906b81d9f48002bf7317048ae5fe6f4 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -27,6 +27,8 @@ #ifndef QEMU_VMSTATE_H #define QEMU_VMSTATE_H +#include "hw/vmstate-if.h" + typedef struct VMStateInfo VMStateInfo; typedef struct VMStateDescription VMStateDescription; typedef struct VMStateField VMStateField; diff --git a/include/monitor/hmp-target.h b/include/monitor/hmp-target.h index 454e8ed15545941bdd3ba21233af5eedb9d97e3c..8b7820a3ad53d53fdb737c3b5e31c67264793e92 100644 --- a/include/monitor/hmp-target.h +++ b/include/monitor/hmp-target.h @@ -25,6 +25,8 @@ #ifndef MONITOR_HMP_TARGET_H #define MONITOR_HMP_TARGET_H +#include "cpu.h" + #define MD_TLONG 0 #define MD_I32 1 diff --git a/include/qemu/atomic128.h b/include/qemu/atomic128.h index ddd0d55d31c8e3457f8585b26f930ea889862183..6b34484e15ca88fb5dd70012c1d675a8d840d3dc 100644 --- a/include/qemu/atomic128.h +++ b/include/qemu/atomic128.h @@ -13,6 +13,8 @@ #ifndef QEMU_ATOMIC128_H #define QEMU_ATOMIC128_H +#include "qemu/int128.h" + /* * GCC is a house divided about supporting large atomic operations. * diff --git a/include/qemu/ratelimit.h b/include/qemu/ratelimit.h index 1b38291823b7fef5ac596557b0269f0c38b8887a..01da8d63f149264144465e935c672d91c0849e13 100644 --- a/include/qemu/ratelimit.h +++ b/include/qemu/ratelimit.h @@ -14,6 +14,8 @@ #ifndef QEMU_RATELIMIT_H #define QEMU_RATELIMIT_H +#include "qemu/timer.h" + typedef struct { int64_t slice_start_time; int64_t slice_end_time; diff --git a/include/qemu/thread-win32.h b/include/qemu/thread-win32.h index 50af5dd7ab863c486e0d26356c72c035d2c5313c..d0a1a9597eb05a66df50de293f00fea7cb2f5173 100644 --- a/include/qemu/thread-win32.h +++ b/include/qemu/thread-win32.h @@ -47,6 +47,6 @@ struct QemuThread { }; /* Only valid for joinable threads. */ -HANDLE qemu_thread_get_handle(QemuThread *thread); +HANDLE qemu_thread_get_handle(struct QemuThread *thread); #endif diff --git a/include/sysemu/balloon.h b/include/sysemu/balloon.h index c8f61452574e7474a9a1e2691356e9cb6224be35..aea0c449850e941d6e88893fed3fac31bcc55124 100644 --- a/include/sysemu/balloon.h +++ b/include/sysemu/balloon.h @@ -14,6 +14,7 @@ #ifndef QEMU_BALLOON_H #define QEMU_BALLOON_H +#include "exec/cpu-common.h" #include "qapi/qapi-types-misc.h" typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target); diff --git a/include/sysemu/cryptodev-vhost-user.h b/include/sysemu/cryptodev-vhost-user.h index 6debf53fc53b58f5bfb2ce8e18b73f3581116297..0d3421e7e8ca2ec315d35d1bce62b8dd4e5014fd 100644 --- a/include/sysemu/cryptodev-vhost-user.h +++ b/include/sysemu/cryptodev-vhost-user.h @@ -20,9 +20,12 @@ * License along with this library; if not, see . * */ + #ifndef CRYPTODEV_VHOST_USER_H #define CRYPTODEV_VHOST_USER_H +#include "sysemu/cryptodev-vhost.h" + #define VHOST_USER_MAX_AUTH_KEY_LEN 512 #define VHOST_USER_MAX_CIPHER_KEY_LEN 64 diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index d275b5a843c7f93f55ea83df1e88b38edb1e9fb2..dd1722f2df42e3f2e6aefb9f3a711881d34cee86 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -13,6 +13,7 @@ #ifndef HVF_H #define HVF_H +#include "cpu.h" #include "qemu/bitops.h" #include "exec/memory.h" #include "sysemu/accel.h" diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h index 5f6240d5cb7fcb605071bfa00a430e6159e47f75..61814864017476071fde1eca94ebd338757cc97e 100644 --- a/include/sysemu/iothread.h +++ b/include/sysemu/iothread.h @@ -16,6 +16,7 @@ #include "block/aio.h" #include "qemu/thread.h" +#include "qom/object.h" #define TYPE_IOTHREAD "iothread" diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h index 31df465fdccd9203834c778836d196a15bf0e9df..787dbc7770e6726723648d5d535c4b2c296bc588 100644 --- a/include/sysemu/kvm_int.h +++ b/include/sysemu/kvm_int.h @@ -9,6 +9,8 @@ #ifndef QEMU_KVM_INT_H #define QEMU_KVM_INT_H +#include "exec/cpu-common.h" +#include "exec/memory.h" #include "sysemu/sysemu.h" #include "sysemu/accel.h" #include "sysemu/kvm.h" diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h index 58452457ce0583fa007b74f819f50fc3ffd2b3ac..1b440df486fef8c22228a0d2e1fa3f318e398dc2 100644 --- a/include/sysemu/memory_mapping.h +++ b/include/sysemu/memory_mapping.h @@ -15,6 +15,8 @@ #define MEMORY_MAPPING_H #include "qemu/queue.h" +#include "exec/cpu-common.h" +#include "exec/cpu-defs.h" #include "exec/memory.h" typedef struct GuestPhysBlock { diff --git a/include/sysemu/xen-mapcache.h b/include/sysemu/xen-mapcache.h index a03e2f1878fe85291e4c9d1449a53719daa7591b..c8e7c2f6cf51aa39cc2230de6196e43d99afff34 100644 --- a/include/sysemu/xen-mapcache.h +++ b/include/sysemu/xen-mapcache.h @@ -9,6 +9,8 @@ #ifndef XEN_MAPCACHE_H #define XEN_MAPCACHE_H +#include "exec/cpu-common.h" + typedef hwaddr (*phys_offset_to_gaddr_t)(hwaddr phys_offset, ram_addr_t size); #ifdef CONFIG_XEN diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h index d714127799135272f0d50f22bff477e2f18f2d0c..58bd3a1ec4bc6ff7da024f42cb84b208d270b9d7 100644 --- a/include/ui/egl-helpers.h +++ b/include/ui/egl-helpers.h @@ -4,6 +4,9 @@ #include #include #include +#include "qapi/qapi-types-ui.h" +#include "ui/console.h" +#include "ui/shader.h" extern EGLDisplay *qemu_egl_display; extern EGLConfig qemu_egl_config; diff --git a/include/ui/input.h b/include/ui/input.h index 8c8ccb999f0fc03559412a9fdb7c8477ae014d6e..c86219a1c11a0015c00659530297caec67475ca6 100644 --- a/include/ui/input.h +++ b/include/ui/input.h @@ -2,6 +2,7 @@ #define INPUT_H #include "qapi/qapi-types-ui.h" +#include "qemu/notify.h" #define INPUT_EVENT_MASK_KEY (1< #include #include #include diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index 24f505199f835b379506907ba71017611568d48b..a90672494dc584fff35d3141e248393d0697fdb7 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -295,15 +295,39 @@ struct vfio_region_info_cap_type { __u32 subtype; /* type specific */ }; +/* + * List of region types, global per bus driver. + * If you introduce a new type, please add it here. + */ + +/* PCI region type containing a PCI vendor part */ #define VFIO_REGION_TYPE_PCI_VENDOR_TYPE (1 << 31) #define VFIO_REGION_TYPE_PCI_VENDOR_MASK (0xffff) +#define VFIO_REGION_TYPE_GFX (1) +#define VFIO_REGION_TYPE_CCW (2) +#define VFIO_REGION_TYPE_MIGRATION (3) + +/* sub-types for VFIO_REGION_TYPE_PCI_* */ -/* 8086 Vendor sub-types */ +/* 8086 vendor PCI sub-types */ #define VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION (1) #define VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG (2) #define VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG (3) -#define VFIO_REGION_TYPE_GFX (1) +/* 10de vendor PCI sub-types */ +/* + * NVIDIA GPU NVlink2 RAM is coherent RAM mapped onto the host address space. + */ +#define VFIO_REGION_SUBTYPE_NVIDIA_NVLINK2_RAM (1) + +/* 1014 vendor PCI sub-types */ +/* + * IBM NPU NVlink2 ATSD (Address Translation Shootdown) register of NPU + * to do TLB invalidation on a GPU. + */ +#define VFIO_REGION_SUBTYPE_IBM_NVLINK2_ATSD (1) + +/* sub-types for VFIO_REGION_TYPE_GFX */ #define VFIO_REGION_SUBTYPE_GFX_EDID (1) /** @@ -353,24 +377,237 @@ struct vfio_region_gfx_edid { #define VFIO_DEVICE_GFX_LINK_STATE_DOWN 2 }; -#define VFIO_REGION_TYPE_CCW (2) -/* ccw sub-types */ +/* sub-types for VFIO_REGION_TYPE_CCW */ #define VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD (1) +#define VFIO_REGION_SUBTYPE_CCW_SCHIB (2) +#define VFIO_REGION_SUBTYPE_CCW_CRW (3) -/* - * 10de vendor sub-type - * - * NVIDIA GPU NVlink2 RAM is coherent RAM mapped onto the host address space. - */ -#define VFIO_REGION_SUBTYPE_NVIDIA_NVLINK2_RAM (1) +/* sub-types for VFIO_REGION_TYPE_MIGRATION */ +#define VFIO_REGION_SUBTYPE_MIGRATION (1) /* - * 1014 vendor sub-type + * The structure vfio_device_migration_info is placed at the 0th offset of + * the VFIO_REGION_SUBTYPE_MIGRATION region to get and set VFIO device related + * migration information. Field accesses from this structure are only supported + * at their native width and alignment. Otherwise, the result is undefined and + * vendor drivers should return an error. * - * IBM NPU NVlink2 ATSD (Address Translation Shootdown) register of NPU - * to do TLB invalidation on a GPU. + * device_state: (read/write) + * - The user application writes to this field to inform the vendor driver + * about the device state to be transitioned to. + * - The vendor driver should take the necessary actions to change the + * device state. After successful transition to a given state, the + * vendor driver should return success on write(device_state, state) + * system call. If the device state transition fails, the vendor driver + * should return an appropriate -errno for the fault condition. + * - On the user application side, if the device state transition fails, + * that is, if write(device_state, state) returns an error, read + * device_state again to determine the current state of the device from + * the vendor driver. + * - The vendor driver should return previous state of the device unless + * the vendor driver has encountered an internal error, in which case + * the vendor driver may report the device_state VFIO_DEVICE_STATE_ERROR. + * - The user application must use the device reset ioctl to recover the + * device from VFIO_DEVICE_STATE_ERROR state. If the device is + * indicated to be in a valid device state by reading device_state, the + * user application may attempt to transition the device to any valid + * state reachable from the current state or terminate itself. + * + * device_state consists of 3 bits: + * - If bit 0 is set, it indicates the _RUNNING state. If bit 0 is clear, + * it indicates the _STOP state. When the device state is changed to + * _STOP, driver should stop the device before write() returns. + * - If bit 1 is set, it indicates the _SAVING state, which means that the + * driver should start gathering device state information that will be + * provided to the VFIO user application to save the device's state. + * - If bit 2 is set, it indicates the _RESUMING state, which means that + * the driver should prepare to resume the device. Data provided through + * the migration region should be used to resume the device. + * Bits 3 - 31 are reserved for future use. To preserve them, the user + * application should perform a read-modify-write operation on this + * field when modifying the specified bits. + * + * +------- _RESUMING + * |+------ _SAVING + * ||+----- _RUNNING + * ||| + * 000b => Device Stopped, not saving or resuming + * 001b => Device running, which is the default state + * 010b => Stop the device & save the device state, stop-and-copy state + * 011b => Device running and save the device state, pre-copy state + * 100b => Device stopped and the device state is resuming + * 101b => Invalid state + * 110b => Error state + * 111b => Invalid state + * + * State transitions: + * + * _RESUMING _RUNNING Pre-copy Stop-and-copy _STOP + * (100b) (001b) (011b) (010b) (000b) + * 0. Running or default state + * | + * + * 1. Normal Shutdown (optional) + * |------------------------------------->| + * + * 2. Save the state or suspend + * |------------------------->|---------->| + * + * 3. Save the state during live migration + * |----------->|------------>|---------->| + * + * 4. Resuming + * |<---------| + * + * 5. Resumed + * |--------->| + * + * 0. Default state of VFIO device is _RUNNNG when the user application starts. + * 1. During normal shutdown of the user application, the user application may + * optionally change the VFIO device state from _RUNNING to _STOP. This + * transition is optional. The vendor driver must support this transition but + * must not require it. + * 2. When the user application saves state or suspends the application, the + * device state transitions from _RUNNING to stop-and-copy and then to _STOP. + * On state transition from _RUNNING to stop-and-copy, driver must stop the + * device, save the device state and send it to the application through the + * migration region. The sequence to be followed for such transition is given + * below. + * 3. In live migration of user application, the state transitions from _RUNNING + * to pre-copy, to stop-and-copy, and to _STOP. + * On state transition from _RUNNING to pre-copy, the driver should start + * gathering the device state while the application is still running and send + * the device state data to application through the migration region. + * On state transition from pre-copy to stop-and-copy, the driver must stop + * the device, save the device state and send it to the user application + * through the migration region. + * Vendor drivers must support the pre-copy state even for implementations + * where no data is provided to the user before the stop-and-copy state. The + * user must not be required to consume all migration data before the device + * transitions to a new state, including the stop-and-copy state. + * The sequence to be followed for above two transitions is given below. + * 4. To start the resuming phase, the device state should be transitioned from + * the _RUNNING to the _RESUMING state. + * In the _RESUMING state, the driver should use the device state data + * received through the migration region to resume the device. + * 5. After providing saved device data to the driver, the application should + * change the state from _RESUMING to _RUNNING. + * + * reserved: + * Reads on this field return zero and writes are ignored. + * + * pending_bytes: (read only) + * The number of pending bytes still to be migrated from the vendor driver. + * + * data_offset: (read only) + * The user application should read data_offset field from the migration + * region. The user application should read the device data from this + * offset within the migration region during the _SAVING state or write + * the device data during the _RESUMING state. See below for details of + * sequence to be followed. + * + * data_size: (read/write) + * The user application should read data_size to get the size in bytes of + * the data copied in the migration region during the _SAVING state and + * write the size in bytes of the data copied in the migration region + * during the _RESUMING state. + * + * The format of the migration region is as follows: + * ------------------------------------------------------------------ + * |vfio_device_migration_info| data section | + * | | /////////////////////////////// | + * ------------------------------------------------------------------ + * ^ ^ + * offset 0-trapped part data_offset + * + * The structure vfio_device_migration_info is always followed by the data + * section in the region, so data_offset will always be nonzero. The offset + * from where the data is copied is decided by the kernel driver. The data + * section can be trapped, mmapped, or partitioned, depending on how the kernel + * driver defines the data section. The data section partition can be defined + * as mapped by the sparse mmap capability. If mmapped, data_offset must be + * page aligned, whereas initial section which contains the + * vfio_device_migration_info structure, might not end at the offset, which is + * page aligned. The user is not required to access through mmap regardless + * of the capabilities of the region mmap. + * The vendor driver should determine whether and how to partition the data + * section. The vendor driver should return data_offset accordingly. + * + * The sequence to be followed while in pre-copy state and stop-and-copy state + * is as follows: + * a. Read pending_bytes, indicating the start of a new iteration to get device + * data. Repeated read on pending_bytes at this stage should have no side + * effects. + * If pending_bytes == 0, the user application should not iterate to get data + * for that device. + * If pending_bytes > 0, perform the following steps. + * b. Read data_offset, indicating that the vendor driver should make data + * available through the data section. The vendor driver should return this + * read operation only after data is available from (region + data_offset) + * to (region + data_offset + data_size). + * c. Read data_size, which is the amount of data in bytes available through + * the migration region. + * Read on data_offset and data_size should return the offset and size of + * the current buffer if the user application reads data_offset and + * data_size more than once here. + * d. Read data_size bytes of data from (region + data_offset) from the + * migration region. + * e. Process the data. + * f. Read pending_bytes, which indicates that the data from the previous + * iteration has been read. If pending_bytes > 0, go to step b. + * + * The user application can transition from the _SAVING|_RUNNING + * (pre-copy state) to the _SAVING (stop-and-copy) state regardless of the + * number of pending bytes. The user application should iterate in _SAVING + * (stop-and-copy) until pending_bytes is 0. + * + * The sequence to be followed while _RESUMING device state is as follows: + * While data for this device is available, repeat the following steps: + * a. Read data_offset from where the user application should write data. + * b. Write migration data starting at the migration region + data_offset for + * the length determined by data_size from the migration source. + * c. Write data_size, which indicates to the vendor driver that data is + * written in the migration region. Vendor driver must return this write + * operations on consuming data. Vendor driver should apply the + * user-provided migration region data to the device resume state. + * + * If an error occurs during the above sequences, the vendor driver can return + * an error code for next read() or write() operation, which will terminate the + * loop. The user application should then take the next necessary action, for + * example, failing migration or terminating the user application. + * + * For the user application, data is opaque. The user application should write + * data in the same order as the data is received and the data should be of + * same transaction size at the source. */ -#define VFIO_REGION_SUBTYPE_IBM_NVLINK2_ATSD (1) + +struct vfio_device_migration_info { + __u32 device_state; /* VFIO device state */ +#define VFIO_DEVICE_STATE_STOP (0) +#define VFIO_DEVICE_STATE_RUNNING (1 << 0) +#define VFIO_DEVICE_STATE_SAVING (1 << 1) +#define VFIO_DEVICE_STATE_RESUMING (1 << 2) +#define VFIO_DEVICE_STATE_MASK (VFIO_DEVICE_STATE_RUNNING | \ + VFIO_DEVICE_STATE_SAVING | \ + VFIO_DEVICE_STATE_RESUMING) + +#define VFIO_DEVICE_STATE_VALID(state) \ + (state & VFIO_DEVICE_STATE_RESUMING ? \ + (state & VFIO_DEVICE_STATE_MASK) == VFIO_DEVICE_STATE_RESUMING : 1) + +#define VFIO_DEVICE_STATE_IS_ERROR(state) \ + ((state & VFIO_DEVICE_STATE_MASK) == (VFIO_DEVICE_STATE_SAVING | \ + VFIO_DEVICE_STATE_RESUMING)) + +#define VFIO_DEVICE_STATE_SET_ERROR(state) \ + ((state & ~VFIO_DEVICE_STATE_MASK) | VFIO_DEVICE_SATE_SAVING | \ + VFIO_DEVICE_STATE_RESUMING) + + __u32 reserved; + __u64 pending_bytes; + __u64 data_offset; + __u64 data_size; +}; /* * The MSIX mappable capability informs that MSIX data of a BAR can be mmapped @@ -570,6 +807,7 @@ enum { enum { VFIO_CCW_IO_IRQ_INDEX, + VFIO_CCW_CRW_IRQ_INDEX, VFIO_CCW_NUM_IRQS }; @@ -700,6 +938,43 @@ struct vfio_device_ioeventfd { #define VFIO_DEVICE_IOEVENTFD _IO(VFIO_TYPE, VFIO_BASE + 16) +/** + * VFIO_DEVICE_FEATURE - _IORW(VFIO_TYPE, VFIO_BASE + 17, + * struct vfio_device_feature) + * + * Get, set, or probe feature data of the device. The feature is selected + * using the FEATURE_MASK portion of the flags field. Support for a feature + * can be probed by setting both the FEATURE_MASK and PROBE bits. A probe + * may optionally include the GET and/or SET bits to determine read vs write + * access of the feature respectively. Probing a feature will return success + * if the feature is supported and all of the optionally indicated GET/SET + * methods are supported. The format of the data portion of the structure is + * specific to the given feature. The data portion is not required for + * probing. GET and SET are mutually exclusive, except for use with PROBE. + * + * Return 0 on success, -errno on failure. + */ +struct vfio_device_feature { + __u32 argsz; + __u32 flags; +#define VFIO_DEVICE_FEATURE_MASK (0xffff) /* 16-bit feature index */ +#define VFIO_DEVICE_FEATURE_GET (1 << 16) /* Get feature into data[] */ +#define VFIO_DEVICE_FEATURE_SET (1 << 17) /* Set feature from data[] */ +#define VFIO_DEVICE_FEATURE_PROBE (1 << 18) /* Probe feature support */ + __u8 data[]; +}; + +#define VFIO_DEVICE_FEATURE _IO(VFIO_TYPE, VFIO_BASE + 17) + +/* + * Provide support for setting a PCI VF Token, which is used as a shared + * secret between PF and VF drivers. This feature may only be set on a + * PCI SR-IOV PF when SR-IOV is enabled on the PF and there are no existing + * open VFs. Data provided when setting this feature is a 16-byte array + * (__u8 b[16]), representing a UUID. + */ +#define VFIO_DEVICE_FEATURE_PCI_VF_TOKEN (0) + /* -------- API for Type1 VFIO IOMMU -------- */ /** @@ -714,7 +989,54 @@ struct vfio_iommu_type1_info { __u32 argsz; __u32 flags; #define VFIO_IOMMU_INFO_PGSIZES (1 << 0) /* supported page sizes info */ - __u64 iova_pgsizes; /* Bitmap of supported page sizes */ +#define VFIO_IOMMU_INFO_CAPS (1 << 1) /* Info supports caps */ + __u64 iova_pgsizes; /* Bitmap of supported page sizes */ + __u32 cap_offset; /* Offset within info struct of first cap */ +}; + +/* + * The IOVA capability allows to report the valid IOVA range(s) + * excluding any non-relaxable reserved regions exposed by + * devices attached to the container. Any DMA map attempt + * outside the valid iova range will return error. + * + * The structures below define version 1 of this capability. + */ +#define VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE 1 + +struct vfio_iova_range { + __u64 start; + __u64 end; +}; + +struct vfio_iommu_type1_info_cap_iova_range { + struct vfio_info_cap_header header; + __u32 nr_iovas; + __u32 reserved; + struct vfio_iova_range iova_ranges[]; +}; + +/* + * The migration capability allows to report supported features for migration. + * + * The structures below define version 1 of this capability. + * + * The existence of this capability indicates that IOMMU kernel driver supports + * dirty page logging. + * + * pgsize_bitmap: Kernel driver returns bitmap of supported page sizes for dirty + * page logging. + * max_dirty_bitmap_size: Kernel driver returns maximum supported dirty bitmap + * size in bytes that can be used by user applications when getting the dirty + * bitmap. + */ +#define VFIO_IOMMU_TYPE1_INFO_CAP_MIGRATION 2 + +struct vfio_iommu_type1_info_cap_migration { + struct vfio_info_cap_header header; + __u32 flags; + __u64 pgsize_bitmap; + __u64 max_dirty_bitmap_size; /* in bytes */ }; #define VFIO_IOMMU_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12) @@ -737,6 +1059,12 @@ struct vfio_iommu_type1_dma_map { #define VFIO_IOMMU_MAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 13) +struct vfio_bitmap { + __u64 pgsize; /* page size for bitmap in bytes */ + __u64 size; /* in bytes */ + __u64 *data; /* one bit per page */ +}; + /** * VFIO_IOMMU_UNMAP_DMA - _IOWR(VFIO_TYPE, VFIO_BASE + 14, * struct vfio_dma_unmap) @@ -746,12 +1074,23 @@ struct vfio_iommu_type1_dma_map { * field. No guarantee is made to the user that arbitrary unmaps of iova * or size different from those used in the original mapping call will * succeed. + * VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP should be set to get the dirty bitmap + * before unmapping IO virtual addresses. When this flag is set, the user must + * provide a struct vfio_bitmap in data[]. User must provide zero-allocated + * memory via vfio_bitmap.data and its size in the vfio_bitmap.size field. + * A bit in the bitmap represents one page, of user provided page size in + * vfio_bitmap.pgsize field, consecutively starting from iova offset. Bit set + * indicates that the page at that offset from iova is dirty. A Bitmap of the + * pages in the range of unmapped size is returned in the user-provided + * vfio_bitmap.data. */ struct vfio_iommu_type1_dma_unmap { __u32 argsz; __u32 flags; +#define VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP (1 << 0) __u64 iova; /* IO virtual address */ __u64 size; /* Size of mapping (bytes) */ + __u8 data[]; }; #define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14) @@ -763,6 +1102,57 @@ struct vfio_iommu_type1_dma_unmap { #define VFIO_IOMMU_ENABLE _IO(VFIO_TYPE, VFIO_BASE + 15) #define VFIO_IOMMU_DISABLE _IO(VFIO_TYPE, VFIO_BASE + 16) +/** + * VFIO_IOMMU_DIRTY_PAGES - _IOWR(VFIO_TYPE, VFIO_BASE + 17, + * struct vfio_iommu_type1_dirty_bitmap) + * IOCTL is used for dirty pages logging. + * Caller should set flag depending on which operation to perform, details as + * below: + * + * Calling the IOCTL with VFIO_IOMMU_DIRTY_PAGES_FLAG_START flag set, instructs + * the IOMMU driver to log pages that are dirtied or potentially dirtied by + * the device; designed to be used when a migration is in progress. Dirty pages + * are logged until logging is disabled by user application by calling the IOCTL + * with VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP flag. + * + * Calling the IOCTL with VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP flag set, instructs + * the IOMMU driver to stop logging dirtied pages. + * + * Calling the IOCTL with VFIO_IOMMU_DIRTY_PAGES_FLAG_GET_BITMAP flag set + * returns the dirty pages bitmap for IOMMU container for a given IOVA range. + * The user must specify the IOVA range and the pgsize through the structure + * vfio_iommu_type1_dirty_bitmap_get in the data[] portion. This interface + * supports getting a bitmap of the smallest supported pgsize only and can be + * modified in future to get a bitmap of any specified supported pgsize. The + * user must provide a zeroed memory area for the bitmap memory and specify its + * size in bitmap.size. One bit is used to represent one page consecutively + * starting from iova offset. The user should provide page size in bitmap.pgsize + * field. A bit set in the bitmap indicates that the page at that offset from + * iova is dirty. The caller must set argsz to a value including the size of + * structure vfio_iommu_type1_dirty_bitmap_get, but excluding the size of the + * actual bitmap. If dirty pages logging is not enabled, an error will be + * returned. + * + * Only one of the flags _START, _STOP and _GET may be specified at a time. + * + */ +struct vfio_iommu_type1_dirty_bitmap { + __u32 argsz; + __u32 flags; +#define VFIO_IOMMU_DIRTY_PAGES_FLAG_START (1 << 0) +#define VFIO_IOMMU_DIRTY_PAGES_FLAG_STOP (1 << 1) +#define VFIO_IOMMU_DIRTY_PAGES_FLAG_GET_BITMAP (1 << 2) + __u8 data[]; +}; + +struct vfio_iommu_type1_dirty_bitmap_get { + __u64 iova; /* IO virtual address */ + __u64 size; /* Size of iova range */ + struct vfio_bitmap bitmap; +}; + +#define VFIO_IOMMU_DIRTY_PAGES _IO(VFIO_TYPE, VFIO_BASE + 17) + /* -------- Additional API for SPAPR TCE (Server POWERPC) IOMMU -------- */ /* diff --git a/memory.c b/memory.c index 5d8c9a9234fbe67424ccb902a6748f06d527e669..44713efc66b2b8ed5ec198841f6daa8ae9777cf2 100644 --- a/memory.c +++ b/memory.c @@ -1825,7 +1825,7 @@ bool memory_region_is_ram_device(MemoryRegion *mr) uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr) { uint8_t mask = mr->dirty_log_mask; - if (global_dirty_log && mr->ram_block) { + if (global_dirty_log && (mr->ram_block || memory_region_is_iommu(mr))) { mask |= (1 << DIRTY_MEMORY_MIGRATION); } return mask; diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c index 4a896a09eb4728ccea2eb8b02b6f74f55ad8271c..11e8feb5958c77a8c0a430eb88b23866ba467f2f 100644 --- a/migration/block-dirty-bitmap.c +++ b/migration/block-dirty-bitmap.c @@ -733,7 +733,7 @@ void dirty_bitmap_mig_init(void) { QSIMPLEQ_INIT(&dirty_bitmap_mig_state.dbms_list); - register_savevm_live(NULL, "dirty-bitmap", 0, 1, + register_savevm_live("dirty-bitmap", 0, 1, &savevm_dirty_bitmap_handlers, &dirty_bitmap_mig_state); } diff --git a/migration/block.c b/migration/block.c index 91f98ef44a1ae09ac77737640aa4aa0134094866..ec15d1d6b3f3fff1c0ee20a75040ff6f1dd56efa 100644 --- a/migration/block.c +++ b/migration/block.c @@ -1030,6 +1030,6 @@ void blk_mig_init(void) QSIMPLEQ_INIT(&block_mig_state.blk_list); qemu_mutex_init(&block_mig_state.lock); - register_savevm_live(NULL, "block", 0, 1, &savevm_block_handlers, + register_savevm_live("block", 0, 1, &savevm_block_handlers, &block_mig_state); } diff --git a/migration/migration.c b/migration/migration.c index b0b9430822c729a6de8c43dfa02a60bb90c0e033..9faf5f63a627a7155f0d2fa1a13c53fa866af4e4 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -49,6 +49,10 @@ #include "monitor/monitor.h" #include "net/announce.h" +#ifdef CONFIG_VFIO +#include "hw/vfio/vfio-common.h" +#endif + #define MAX_THROTTLE (32 << 20) /* Migration transfer speed throttling */ /* Amount of time to allocate to each "chunk" of bandwidth-throttled @@ -908,6 +912,17 @@ static void populate_disk_info(MigrationInfo *info) } } +static void populate_vfio_info(MigrationInfo *info) +{ +#ifdef CONFIG_VFIO + if (vfio_mig_active()) { + info->has_vfio = true; + info->vfio = g_malloc0(sizeof(*info->vfio)); + info->vfio->transferred = vfio_mig_bytes_transferred(); + } +#endif +} + static void fill_source_migration_info(MigrationInfo *info) { MigrationState *s = migrate_get_current(); @@ -941,6 +956,7 @@ static void fill_source_migration_info(MigrationInfo *info) populate_ram_info(info, s); populate_disk_info(info); + populate_vfio_info(info); break; case MIGRATION_STATUS_COLO: info->has_status = true; @@ -956,6 +972,7 @@ static void fill_source_migration_info(MigrationInfo *info) info->setup_time = s->setup_time; populate_ram_info(info, s); + populate_vfio_info(info); break; case MIGRATION_STATUS_FAILED: info->has_status = true; diff --git a/migration/ram.c b/migration/ram.c index d6657a80933a945b6ff79a11665f3fad7d657602..2077ba5be4b917aa2c7f139e69a9502bc2e3c50d 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -5125,5 +5125,5 @@ static SaveVMHandlers savevm_ram_handlers = { void ram_mig_init(void) { qemu_mutex_init(&XBZRLE.lock); - register_savevm_live(NULL, "ram", 0, 4, &savevm_ram_handlers, &ram_state); + register_savevm_live("ram", 0, 4, &savevm_ram_handlers, &ram_state); } diff --git a/migration/savevm.c b/migration/savevm.c index f0974380e5f9b600a66df0497e7b902d8d6e33f4..cdb79222a4491cfb096cd617138aeb63e69fcd2f 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -683,8 +683,7 @@ static void savevm_state_handler_insert(SaveStateEntry *nse) of the system, so instance_id should be removed/replaced. Meanwhile pass -1 as instance_id if you do not already have a clearly distinguishing id for all instances of your device class. */ -int register_savevm_live(DeviceState *dev, - const char *idstr, +int register_savevm_live(const char *idstr, uint32_t instance_id, int version_id, const SaveVMHandlers *ops, @@ -703,26 +702,6 @@ int register_savevm_live(DeviceState *dev, se->is_ram = 1; } - if (dev) { - char *id = qdev_get_dev_path(dev); - if (id) { - if (snprintf(se->idstr, sizeof(se->idstr), "%s/", id) >= - sizeof(se->idstr)) { - error_report("Path too long for VMState (%s)", id); - g_free(id); - g_free(se); - - return -1; - } - g_free(id); - - se->compat = g_new0(CompatEntry, 1); - pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), idstr); - se->compat->instance_id = instance_id == -1 ? - calculate_compat_instance_id(idstr) : instance_id; - instance_id = -1; - } - } pstrcat(se->idstr, sizeof(se->idstr), idstr); if (instance_id == VMSTATE_INSTANCE_ID_ANY) { diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index e5a7a88ba2b303b97ab3c52a8a88ad8ce3a05489..cecaae0a473184c4900040ce0cb3edd989c7ac1e 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -370,6 +370,12 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) } monitor_printf(mon, "]\n"); } + + if (info->has_vfio) { + monitor_printf(mon, "vfio device transferred: %" PRIu64 " kbytes\n", + info->vfio->transferred >> 10); + } + qapi_free_MigrationInfo(info); qapi_free_MigrationCapabilityStatusList(caps); } diff --git a/net/slirp.c b/net/slirp.c index b34cb29276849829a8910028f9a54c866601c168..f42f496641ef2e9f561a87cc9b2f18086575b49f 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -576,7 +576,7 @@ static int net_slirp_init(NetClientState *peer, const char *model, * specific version? */ g_assert(slirp_state_version() == 4); - register_savevm_live(NULL, "slirp", 0, slirp_state_version(), + register_savevm_live("slirp", 0, slirp_state_version(), &savevm_slirp_state, s->slirp); s->poll_notifier.notify = net_slirp_poll_notify; diff --git a/qapi/migration.json b/qapi/migration.json index 587ef65872e1cdeecb5350623b8bb5d64fec3839..1f0eb19ac69600216480a12c11fe8f2e737247cc 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -141,6 +141,18 @@ 'active', 'postcopy-active', 'postcopy-paused', 'postcopy-recover', 'completed', 'failed', 'colo', 'pre-switchover', 'device' ] } +## +# @VfioStats: +# +# Detailed VFIO devices migration statistics +# +# @transferred: amount of bytes transferred to the target VM by VFIO devices +# +# Since: 5.2 +# +## +{ 'struct': 'VfioStats', + 'data': {'transferred': 'int' } } ## # @MigrationInfo: @@ -202,11 +214,16 @@ # # @socket-address: Only used for tcp, to know what the real port is (Since 4.0) # +# @vfio: @VfioStats containing detailed VFIO devices migration statistics, +# only returned if VFIO device is present, migration is supported by all +# VFIO devices and status is 'active' or 'completed' (since 5.2) +# # Since: 0.14.0 ## { 'struct': 'MigrationInfo', 'data': {'*status': 'MigrationStatus', '*ram': 'MigrationStats', '*disk': 'MigrationStats', + '*vfio': 'VfioStats', '*xbzrle-cache': 'XBZRLECacheStats', '*total-time': 'int', '*expected-downtime': 'int', diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index aab251bc4bb90c81e89521934549100eb9c3c82e..e9fba96be9dfe89fcd13fa9dd788ac396f837009 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -22,7 +22,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" - +#include "exec/memory.h" /* PA-RISC 1.x processors have a strong memory model. */ /* ??? While we do not yet implement PA-RISC 2.0, those processors have diff --git a/tests/Makefile.include b/tests/Makefile.include index 3be60ab9991bdcef51dabd587b4d35fb3b02187e..1c7772a230f9ed6601059b3f2a0165461ddc1291 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -566,6 +566,7 @@ tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \ hw/core/irq.o \ hw/core/fw-path-provider.o \ hw/core/reset.o \ + hw/core/vmstate-if.o \ $(test-qapi-obj-y) tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ migration/vmstate.o migration/vmstate-types.o migration/qemu-file.o \