diff options
Diffstat (limited to 'hw')
| -rw-r--r-- | hw/arm/sbsa-ref.c | 8 | ||||
| -rw-r--r-- | hw/core/Makefile.objs | 1 | ||||
| -rw-r--r-- | hw/core/vm-change-state-handler.c | 61 | ||||
| -rw-r--r-- | hw/i386/intel_iommu.c | 71 | ||||
| -rw-r--r-- | hw/i386/pc_piix.c | 12 | ||||
| -rw-r--r-- | hw/intc/ioapic.c | 11 | ||||
| -rw-r--r-- | hw/scsi/scsi-bus.c | 4 | ||||
| -rw-r--r-- | hw/tpm/Makefile.objs | 4 | ||||
| -rw-r--r-- | hw/virtio/virtio.c | 4 |
9 files changed, 128 insertions, 48 deletions
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index e8c65e31c7..9c67d5c6f9 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -254,8 +254,6 @@ static void sbsa_flash_map(SBSAMachineState *sms, * sysmem is the system memory space. secure_sysmem is the secure view * of the system, and the first flash device should be made visible only * there. The second flash device is visible to both secure and nonsecure. - * If sysmem == secure_sysmem this means there is no separate Secure - * address space and both flash devices are generally visible. */ hwaddr flashsize = sbsa_ref_memmap[SBSA_FLASH].size / 2; hwaddr flashbase = sbsa_ref_memmap[SBSA_FLASH].base; @@ -591,7 +589,7 @@ static void sbsa_ref_init(MachineState *machine) SBSAMachineState *sms = SBSA_MACHINE(machine); MachineClass *mc = MACHINE_GET_CLASS(machine); MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *secure_sysmem = NULL; + MemoryRegion *secure_sysmem = g_new(MemoryRegion, 1); MemoryRegion *ram = g_new(MemoryRegion, 1); bool firmware_loaded; const CPUArchIdList *possible_cpus; @@ -615,13 +613,11 @@ static void sbsa_ref_init(MachineState *machine) * containing the system memory at low priority; any secure-only * devices go in at higher priority and take precedence. */ - secure_sysmem = g_new(MemoryRegion, 1); memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory", UINT64_MAX); memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1); - firmware_loaded = sbsa_firmware_init(sms, sysmem, - secure_sysmem ?: sysmem); + firmware_loaded = sbsa_firmware_init(sms, sysmem, secure_sysmem); if (machine->kernel_filename && firmware_loaded) { error_report("sbsa-ref: No fw_cfg device on this machine, " diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index 585b734358..f8481d959f 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -7,6 +7,7 @@ common-obj-$(CONFIG_SOFTMMU) += fw-path-provider.o 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-$(CONFIG_EMPTY_SLOT) += empty_slot.o common-obj-$(CONFIG_XILINX_AXI) += stream.o diff --git a/hw/core/vm-change-state-handler.c b/hw/core/vm-change-state-handler.c new file mode 100644 index 0000000000..f814813bdd --- /dev/null +++ b/hw/core/vm-change-state-handler.c @@ -0,0 +1,61 @@ +/* + * qdev vm change state handlers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "hw/qdev.h" + +static int qdev_get_dev_tree_depth(DeviceState *dev) +{ + int depth; + + for (depth = 0; dev; depth++) { + BusState *bus = dev->parent_bus; + + if (!bus) { + break; + } + + dev = bus->parent; + } + + return depth; +} + +/** + * qdev_add_vm_change_state_handler: + * @dev: the device that owns this handler + * @cb: the callback function to be invoked + * @opaque: user data passed to the callback function + * + * This function works like qemu_add_vm_change_state_handler() except callbacks + * are invoked in qdev tree depth order. Ordering is desirable when callbacks + * of children depend on their parent's callback having completed first. + * + * For example, when qdev_add_vm_change_state_handler() is used, a host + * controller's callback is invoked before the children on its bus when the VM + * starts running. The order is reversed when the VM stops running. + * + * Returns: an entry to be freed with qemu_del_vm_change_state_handler() + */ +VMChangeStateEntry *qdev_add_vm_change_state_handler(DeviceState *dev, + VMChangeStateHandler *cb, + void *opaque) +{ + int depth = qdev_get_dev_tree_depth(dev); + + return qemu_add_vm_change_state_handler_prio(cb, opaque, depth); +} diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 44b1231157..de86f53b4e 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3363,11 +3363,28 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) return vtd_dev_as; } +static uint64_t get_naturally_aligned_size(uint64_t start, + uint64_t size, int gaw) +{ + uint64_t max_mask = 1ULL << gaw; + uint64_t alignment = start ? start & -start : max_mask; + + alignment = MIN(alignment, max_mask); + size = MIN(size, max_mask); + + if (alignment <= size) { + /* Increase the alignment of start */ + return alignment; + } else { + /* Find the largest page mask from size */ + return 1ULL << (63 - clz64(size)); + } +} + /* Unmap the whole range in the notifier's scope. */ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) { - IOMMUTLBEntry entry; - hwaddr size; + hwaddr size, remain; hwaddr start = n->start; hwaddr end = n->end; IntelIOMMUState *s = as->iommu_state; @@ -3379,48 +3396,46 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) * VT-d spec), otherwise we need to consider overflow of 64 bits. */ - if (end > VTD_ADDRESS_SIZE(s->aw_bits)) { + if (end > VTD_ADDRESS_SIZE(s->aw_bits) - 1) { /* * Don't need to unmap regions that is bigger than the whole * VT-d supported address space size */ - end = VTD_ADDRESS_SIZE(s->aw_bits); + end = VTD_ADDRESS_SIZE(s->aw_bits) - 1; } assert(start <= end); - size = end - start; + size = remain = end - start + 1; - if (ctpop64(size) != 1) { - /* - * This size cannot format a correct mask. Let's enlarge it to - * suite the minimum available mask. - */ - int n = 64 - clz64(size); - if (n > s->aw_bits) { - /* should not happen, but in case it happens, limit it */ - n = s->aw_bits; - } - size = 1ULL << n; + while (remain >= VTD_PAGE_SIZE) { + IOMMUTLBEntry entry; + uint64_t mask = get_naturally_aligned_size(start, remain, s->aw_bits); + + assert(mask); + + entry.iova = start; + entry.addr_mask = mask - 1; + entry.target_as = &address_space_memory; + entry.perm = IOMMU_NONE; + /* This field is meaningless for unmap */ + entry.translated_addr = 0; + + memory_region_notify_one(n, &entry); + + start += mask; + remain -= mask; } - entry.target_as = &address_space_memory; - /* Adjust iova for the size */ - entry.iova = n->start & ~(size - 1); - /* This field is meaningless for unmap */ - entry.translated_addr = 0; - entry.perm = IOMMU_NONE; - entry.addr_mask = size - 1; + assert(!remain); trace_vtd_as_unmap_whole(pci_bus_num(as->bus), VTD_PCI_SLOT(as->devfn), VTD_PCI_FUNC(as->devfn), - entry.iova, size); + n->start, size); - map.iova = entry.iova; - map.size = entry.addr_mask; + map.iova = n->start; + map.size = size; iova_tree_remove(as->iova_tree, &map); - - memory_region_notify_one(n, &entry); } static void vtd_address_space_unmap_all(IntelIOMMUState *s) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 581b3c2baa..c2280c72ef 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "config-devices.h" #include "qemu/units.h" #include "hw/hw.h" @@ -61,9 +62,11 @@ #define MAX_IDE_BUS 2 +#ifdef CONFIG_IDE_ISA static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 }; static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 }; static const int ide_irq[MAX_IDE_BUS] = { 14, 15 }; +#endif /* PC hardware initialisation */ static void pc_init1(MachineState *machine, @@ -254,7 +257,10 @@ static void pc_init1(MachineState *machine, } idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0"); idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1"); - } else { + pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state); + } +#ifdef CONFIG_IDE_ISA +else { for(i = 0; i < MAX_IDE_BUS; i++) { ISADevice *dev; char busname[] = "ide.0"; @@ -268,9 +274,9 @@ static void pc_init1(MachineState *machine, busname[4] = '0' + i; idebus[i] = qdev_get_child_bus(DEVICE(dev), busname); } + pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state); } - - pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state); +#endif if (pcmc->pci_enabled && machine_usb(machine)) { pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci"); diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index 7074489fdf..c408749876 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -245,8 +245,8 @@ void ioapic_eoi_broadcast(int vector) s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR; if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) { - ++s->irq_eoi[vector]; - if (s->irq_eoi[vector] >= SUCCESSIVE_IRQ_MAX_COUNT) { + ++s->irq_eoi[n]; + if (s->irq_eoi[n] >= SUCCESSIVE_IRQ_MAX_COUNT) { /* * Real hardware does not deliver the interrupt immediately * during eoi broadcast, and this lets a buggy guest make @@ -254,16 +254,16 @@ void ioapic_eoi_broadcast(int vector) * level-triggered interrupt. Emulate this behavior if we * detect an interrupt storm. */ - s->irq_eoi[vector] = 0; + s->irq_eoi[n] = 0; timer_mod_anticipate(s->delayed_ioapic_service_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 100); - trace_ioapic_eoi_delayed_reassert(vector); + trace_ioapic_eoi_delayed_reassert(n); } else { ioapic_service(s); } } else { - s->irq_eoi[vector] = 0; + s->irq_eoi[n] = 0; } } } @@ -380,6 +380,7 @@ ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val, /* restore RO bits */ s->ioredtbl[index] &= IOAPIC_RW_BITS; s->ioredtbl[index] |= ro_bits; + s->irq_eoi[index] = 0; ioapic_fix_edge_remote_irr(&s->ioredtbl[index]); ioapic_service(s); } diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 196136a307..fdc3a0e4e0 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -207,8 +207,8 @@ static void scsi_qdev_realize(DeviceState *qdev, Error **errp) error_propagate(errp, local_err); return; } - dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb, - dev); + dev->vmsentry = qdev_add_vm_change_state_handler(DEVICE(dev), + scsi_dma_restart_cb, dev); } static void scsi_qdev_unrealize(DeviceState *qdev, Error **errp) diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index 700c878622..de0b85d02a 100644 --- a/hw/tpm/Makefile.objs +++ b/hw/tpm/Makefile.objs @@ -1,5 +1,5 @@ -common-obj-y += tpm_util.o -obj-y += tpm_ppi.o +common-obj-$(CONFIG_TPM) += tpm_util.o +obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 18f9f4c372..a94ea18a9c 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2362,8 +2362,8 @@ void virtio_init(VirtIODevice *vdev, const char *name, } else { vdev->config = NULL; } - vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change, - vdev); + vdev->vmstate = qdev_add_vm_change_state_handler(DEVICE(vdev), + virtio_vmstate_change, vdev); vdev->device_endian = virtio_default_endian(); vdev->use_guest_notifier_mask = true; } |