diff options
47 files changed, 812 insertions, 308 deletions
diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 5b969cda1c..bef451b3b2 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -10,6 +10,7 @@ #include "config.h" #include "hw/hw.h" #include "hw/arm/arm.h" +#include "hw/arm/linux-boot-if.h" #include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/loader.h" @@ -555,6 +556,20 @@ static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key, fw_cfg_add_bytes(fw_cfg, data_key, data, size); } +static int do_arm_linux_init(Object *obj, void *opaque) +{ + if (object_dynamic_cast(obj, TYPE_ARM_LINUX_BOOT_IF)) { + ARMLinuxBootIf *albif = ARM_LINUX_BOOT_IF(obj); + ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_GET_CLASS(obj); + struct arm_boot_info *info = opaque; + + if (albifc->arm_linux_init) { + albifc->arm_linux_init(albif, info->secure_boot); + } + } + return 0; +} + static void arm_load_kernel_notify(Notifier *notifier, void *data) { CPUState *cs; @@ -778,6 +793,12 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) if (info->nb_cpus > 1) { info->write_secondary_boot(cpu, info); } + + /* Notify devices which need to fake up firmware initialization + * that we're doing a direct kernel boot. + */ + object_child_foreach_recursive(object_get_root(), + do_arm_linux_init, info); } info->is_linux = is_linux; @@ -803,3 +824,16 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) qemu_register_reset(do_cpu_reset, ARM_CPU(cs)); } } + +static const TypeInfo arm_linux_boot_if_info = { + .name = TYPE_ARM_LINUX_BOOT_IF, + .parent = TYPE_INTERFACE, + .class_size = sizeof(ARMLinuxBootIfClass), +}; + +static void arm_linux_boot_register_types(void) +{ + type_register_static(&arm_linux_boot_if_info); +} + +type_init(arm_linux_boot_register_types) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 91e45e04a1..e9324f56bd 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -396,7 +396,7 @@ static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic) fdt_add_v2m_gic_node(vbi); } -static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic) +static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, bool secure) { /* We create a standalone GIC v2 */ DeviceState *gicdev; @@ -413,6 +413,9 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic) * interrupts; there are always 32 of the former (mandated by GIC spec). */ qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32); + if (!kvm_irqchip_in_kernel()) { + qdev_prop_set_bit(gicdev, "has-security-extensions", secure); + } qdev_init_nofail(gicdev); gicbusdev = SYS_BUS_DEVICE(gicdev); sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base); @@ -967,7 +970,7 @@ static void machvirt_init(MachineState *machine) create_flash(vbi); - create_gic(vbi, pic); + create_gic(vbi, pic, vms->secure); create_uart(vbi, pic); @@ -1044,8 +1047,11 @@ static void virt_instance_init(Object *obj) { VirtMachineState *vms = VIRT_MACHINE(obj); - /* EL3 is enabled by default on virt */ - vms->secure = true; + /* EL3 is disabled by default on virt: this makes us consistent + * between KVM and TCG for this board, and it also allows us to + * boot UEFI blobs which assume no TrustZone support. + */ + vms->secure = false; object_property_add_bool(obj, "secure", virt_get_secure, virt_set_secure, NULL); object_property_set_description(obj, "secure", diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 388baef76e..2955f3b866 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -28,6 +28,10 @@ #define GIC_DIST_ADDR 0xf9010000 #define GIC_CPU_ADDR 0xf9020000 +#define SATA_INTR 133 +#define SATA_ADDR 0xFD0C0000 +#define SATA_NUM_PORTS 2 + static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = { 0xFF0B0000, 0xFF0C0000, 0xFF0D0000, 0xFF0E0000, }; @@ -90,6 +94,9 @@ static void xlnx_zynqmp_init(Object *obj) object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_CADENCE_UART); qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default()); } + + object_initialize(&s->sata, sizeof(s->sata), TYPE_SYSBUS_AHCI); + qdev_set_parent_bus(DEVICE(&s->sata), sysbus_get_default()); } static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) @@ -162,12 +169,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) g_free(name); object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR, - "reset-cbar", &err); - if (err) { - error_propagate((errp), (err)); - return; - } - + "reset-cbar", &error_abort); object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized", &err); if (err) { @@ -200,12 +202,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) g_free(name); object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs", - &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - + &error_abort); object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "realized", &err); if (err) { @@ -250,6 +247,17 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, gic_spi[uart_intr[i]]); } + + object_property_set_int(OBJECT(&s->sata), SATA_NUM_PORTS, "num-ports", + &error_abort); + object_property_set_bool(OBJECT(&s->sata), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->sata), 0, SATA_ADDR); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->sata), 0, gic_spi[SATA_INTR]); } static Property xlnx_zynqmp_props[] = { diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 1556c9cf5a..f9301ae541 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -731,7 +731,7 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features, virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY); virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY); virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE); - if (__virtio_has_feature(features, VIRTIO_F_VERSION_1)) { + if (virtio_has_feature(features, VIRTIO_F_VERSION_1)) { if (s->conf.scsi) { error_setg(errp, "Please set scsi=off for virtio-blk devices in order to use virtio 1.0"); return 0; @@ -782,10 +782,11 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) * * s->blk would erroneously be placed in writethrough mode. */ - if (!virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) { + if (!virtio_vdev_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) { aio_context_acquire(blk_get_aio_context(s->blk)); blk_set_enable_write_cache(s->blk, - virtio_has_feature(vdev, VIRTIO_BLK_F_WCE)); + virtio_vdev_has_feature(vdev, + VIRTIO_BLK_F_WCE)); aio_context_release(blk_get_aio_context(s->blk)); } } diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index bc56f5d520..be97058712 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -76,7 +76,7 @@ static VirtIOSerialPort *find_port_by_name(char *name) static bool use_multiport(VirtIOSerial *vser) { VirtIODevice *vdev = VIRTIO_DEVICE(vser); - return virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT); + return virtio_vdev_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT); } static size_t write_to_port(VirtIOSerialPort *port, diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c index 58ac02e610..4ef8db1a4c 100644 --- a/hw/cpu/a15mpcore.c +++ b/hw/cpu/a15mpcore.c @@ -52,10 +52,23 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp) SysBusDevice *busdev; int i; Error *err = NULL; + bool has_el3; + Object *cpuobj; gicdev = DEVICE(&s->gic); qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu); qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq); + + if (!kvm_irqchip_in_kernel()) { + /* Make the GIC's TZ support match the CPUs. We assume that + * either all the CPUs have TZ, or none do. + */ + cpuobj = OBJECT(qemu_get_cpu(0)); + has_el3 = object_property_find(cpuobj, "has_el3", &error_abort) && + object_property_get_bool(cpuobj, "has_el3", &error_abort); + qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3); + } + object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); if (err != NULL) { error_propagate(errp, err); diff --git a/hw/cpu/a9mpcore.c b/hw/cpu/a9mpcore.c index c09358c6e7..7046246896 100644 --- a/hw/cpu/a9mpcore.c +++ b/hw/cpu/a9mpcore.c @@ -49,6 +49,8 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) *wdtbusdev; Error *err = NULL; int i; + bool has_el3; + Object *cpuobj; scudev = DEVICE(&s->scu); qdev_prop_set_uint32(scudev, "num-cpu", s->num_cpu); @@ -62,6 +64,15 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) gicdev = DEVICE(&s->gic); qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu); qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq); + + /* Make the GIC's TZ support match the CPUs. We assume that + * either all the CPUs have TZ, or none do. + */ + cpuobj = OBJECT(qemu_get_cpu(0)); + has_el3 = object_property_find(cpuobj, "has_el3", &error_abort) && + object_property_get_bool(cpuobj, "has_el3", &error_abort); + qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3); + object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); if (err != NULL) { error_propagate(errp, err); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 9f2924e5df..b5107f7c58 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1412,7 +1412,13 @@ FWCfgState *pc_memory_init(PCMachineState *pcms, if (guest_info->has_reserved_memory && pcms->hotplug_memory.base) { uint64_t *val = g_malloc(sizeof(*val)); - *val = cpu_to_le64(ROUND_UP(pcms->hotplug_memory.base, 0x1ULL << 30)); + PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); + uint64_t res_mem_end = pcms->hotplug_memory.base; + + if (!pcmc->broken_reserved_end) { + res_mem_end += memory_region_size(&pcms->hotplug_memory.mr); + } + *val = cpu_to_le64(ROUND_UP(res_mem_end, 0x1ULL << 30)); fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val)); } diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index edef0cc038..3f925b26db 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -136,9 +136,7 @@ static void pc_init1(MachineState *machine, pcms->below_4g_mem_size = machine->ram_size; } - if (xen_enabled() && xen_hvm_init(&pcms->below_4g_mem_size, - &pcms->above_4g_mem_size, - &ram_memory) != 0) { + if (xen_enabled() && xen_hvm_init(pcms, &ram_memory) != 0) { fprintf(stderr, "xen hardware virtual machine initialisation failed\n"); exit(1); } @@ -466,7 +464,9 @@ static void pc_i440fx_machine_options(MachineClass *m) static void pc_i440fx_2_4_machine_options(MachineClass *m) { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_i440fx_machine_options(m); + pcmc->broken_reserved_end = true; m->default_machine_opts = "firmware=bios-256k.bin"; m->default_display = "std"; m->alias = "pc"; diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 7217cbf38b..11601ab005 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -125,9 +125,7 @@ static void pc_q35_init(MachineState *machine) pcms->below_4g_mem_size = machine->ram_size; } - if (xen_enabled() && xen_hvm_init(&pcms->below_4g_mem_size, - &pcms->above_4g_mem_size, - &ram_memory) != 0) { + if (xen_enabled() && xen_hvm_init(pcms, &ram_memory) != 0) { fprintf(stderr, "xen hardware virtual machine initialisation failed\n"); exit(1); } @@ -370,7 +368,9 @@ static void pc_q35_machine_options(MachineClass *m) static void pc_q35_2_4_machine_options(MachineClass *m) { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_q35_machine_options(m); + pcmc->broken_reserved_end = true; m->default_machine_opts = "firmware=bios-256k.bin"; m->default_display = "std"; m->no_floppy = 1; diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 48749c1dc1..d83efa47a4 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -25,7 +25,6 @@ #include <hw/pci/msi.h> #include <hw/i386/pc.h> #include <hw/pci/pci.h> -#include <hw/sysbus.h> #include "qemu/error-report.h" #include "sysemu/block-backend.h" @@ -122,9 +121,9 @@ static uint32_t ahci_port_read(AHCIState *s, int port, int offset) static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev) { - AHCIPCIState *d = container_of(s, AHCIPCIState, ahci); - PCIDevice *pci_dev = - (PCIDevice *)object_dynamic_cast(OBJECT(d), TYPE_PCI_DEVICE); + DeviceState *dev_state = s->container; + PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state), + TYPE_PCI_DEVICE); DPRINTF(0, "raise irq\n"); @@ -137,9 +136,9 @@ static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev) static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev) { - AHCIPCIState *d = container_of(s, AHCIPCIState, ahci); - PCIDevice *pci_dev = - (PCIDevice *)object_dynamic_cast(OBJECT(d), TYPE_PCI_DEVICE); + DeviceState *dev_state = s->container; + PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state), + TYPE_PCI_DEVICE); DPRINTF(0, "lower irq\n"); @@ -1437,6 +1436,7 @@ void ahci_init(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports) s->as = as; s->ports = ports; s->dev = g_new0(AHCIDevice, ports); + s->container = qdev; ahci_reg_init(s); /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */ memory_region_init_io(&s->mem, OBJECT(qdev), &ahci_mem_ops, s, @@ -1625,18 +1625,6 @@ const VMStateDescription vmstate_ahci = { }, }; -#define TYPE_SYSBUS_AHCI "sysbus-ahci" -#define SYSBUS_AHCI(obj) OBJECT_CHECK(SysbusAHCIState, (obj), TYPE_SYSBUS_AHCI) - -typedef struct SysbusAHCIState { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - AHCIState ahci; - uint32_t num_ports; -} SysbusAHCIState; - static const VMStateDescription vmstate_sysbus_ahci = { .name = "sysbus-ahci", .fields = (VMStateField[]) { diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h index 79a463d93c..c9b3805415 100644 --- a/hw/ide/ahci.h +++ b/hw/ide/ahci.h @@ -24,6 +24,8 @@ #ifndef HW_IDE_AHCI_H #define HW_IDE_AHCI_H +#include <hw/sysbus.h> + #define AHCI_MEM_BAR_SIZE 0x1000 #define AHCI_MAX_PORTS 32 #define AHCI_MAX_SG 168 /* hardware max is 64K */ @@ -285,6 +287,8 @@ struct AHCIDevice { }; typedef struct AHCIState { + DeviceState *container; + AHCIDevice *dev; AHCIControlRegs control_regs; MemoryRegion mem; @@ -369,4 +373,16 @@ void ahci_reset(AHCIState *s); void ahci_ide_create_devs(PCIDevice *dev, DriveInfo **hd); +#define TYPE_SYSBUS_AHCI "sysbus-ahci" +#define SYSBUS_AHCI(obj) OBJECT_CHECK(SysbusAHCIState, (obj), TYPE_SYSBUS_AHCI) + +typedef struct SysbusAHCIState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + AHCIState ahci; + uint32_t num_ports; +} SysbusAHCIState; + #endif /* HW_IDE_AHCI_H */ diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index a8c5d19448..2df550c01b 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -219,15 +219,99 @@ static uint16_t gic_get_current_pending_irq(GICState *s, int cpu, return pending_irq; } -static void gic_set_running_irq(GICState *s, int cpu, int irq) +static int gic_get_group_priority(GICState *s, int cpu, int irq) { - s->running_irq[cpu] = irq; - if (irq == 1023) { - s->running_priority[cpu] = 0x100; + /* Return the group priority of the specified interrupt + * (which is the top bits of its priority, with the number + * of bits masked determined by the applicable binary point register). + */ + int bpr; + uint32_t mask; + + if (gic_has_groups(s) && + !(s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) && + GIC_TEST_GROUP(irq, (1 << cpu))) { + bpr = s->abpr[cpu]; } else { - s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu); + bpr = s->bpr[cpu]; } - gic_update(s); + + /* a BPR of 0 means the group priority bits are [7:1]; + * a BPR of 1 means they are [7:2], and so on down to + * a BPR of 7 meaning no group priority bits at all. + */ + mask = ~0U << ((bpr & 7) + 1); + + return GIC_GET_PRIORITY(irq, cpu) & mask; +} + +static void gic_activate_irq(GICState *s, int cpu, int irq) +{ + /* Set the appropriate Active Priority Register bit for this IRQ, + * and update the running priority. + */ + int prio = gic_get_group_priority(s, cpu, irq); + int preemption_level = prio >> (GIC_MIN_BPR + 1); + int regno = preemption_level / 32; + int bitno = preemption_level % 32; + + if (gic_has_groups(s) && GIC_TEST_GROUP(irq, (1 << cpu))) { + s->nsapr[regno][cpu] &= (1 << bitno); + } else { + s->apr[regno][cpu] &= (1 << bitno); + } + + s->running_priority[cpu] = prio; + GIC_SET_ACTIVE(irq, 1 << cpu); +} + +static int gic_get_prio_from_apr_bits(GICState *s, int cpu) +{ + /* Recalculate the current running priority for this CPU based + * on the set bits in the Active Priority Registers. + */ + int i; + for (i = 0; i < GIC_NR_APRS; i++) { + uint32_t apr = s->apr[i][cpu] | s->nsapr[i][cpu]; + if (!apr) { + continue; + } + return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1); + } + return 0x100; +} + +static void gic_drop_prio(GICState *s, int cpu, int group) +{ + /* Drop the priority of the currently active interrupt in the + * specified group. + * + * Note that we can guarantee (because of the requirement to nest + * GICC_IAR reads [which activate an interrupt and raise priority] + * with GICC_EOIR writes [which drop the priority for the interrupt]) + * that the interrupt we're being called for is the highest priority + * active interrupt, meaning that it has the lowest set bit in the + * APR registers. + * + * If the guest does not honour the ordering constraints then the + * behaviour of the GIC is UNPREDICTABLE, which for us means that + * the values of the APR registers might become incorrect and the + * running priority will be wrong, so interrupts that should preempt + * might not do so, and interrupts that should not preempt might do so. + */ + int i; + + for (i = 0; i < GIC_NR_APRS; i++) { + uint32_t *papr = group ? &s->nsapr[i][cpu] : &s->apr[i][cpu]; + if (!*papr) { + continue; + } + /* Clear lowest set bit */ + *papr &= *papr - 1; + break; + } + + s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu); } uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) @@ -250,7 +334,6 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) DPRINTF("ACK, pending interrupt (%d) has insufficient priority\n", irq); return 1023; } - s->last_active[irq][cpu] = s->running_irq[cpu]; if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { /* Clear pending flags for both level and edge triggered interrupts. @@ -281,7 +364,8 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) } } - gic_set_running_irq(s, cpu, irq); + gic_activate_irq(s, cpu, irq); + gic_update(s); DPRINTF("ACK %d\n", irq); return ret; } @@ -411,8 +495,9 @@ static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs) void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) { - int update = 0; int cm = 1 << cpu; + int group; + DPRINTF("EOI %d\n", irq); if (irq >= s->num_irq) { /* This handles two cases: @@ -425,8 +510,9 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) */ return; } - if (s->running_irq[cpu] == 1023) + if (s->running_priority[cpu] == 0x100) { return; /* No active IRQ. */ + } if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { /* Mark level triggered interrupts as pending if they are still @@ -435,11 +521,12 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) { DPRINTF("Set %d pending mask %x\n", irq, cm); GIC_SET_PENDING(irq, cm); - update = 1; } } - if (s->security_extn && !attrs.secure && !GIC_TEST_GROUP(irq, cm)) { + group = gic_has_groups(s) && GIC_TEST_GROUP(irq, cm); + + if (s->security_extn && !attrs.secure && !group) { DPRINTF("Non-secure EOI for Group0 interrupt %d ignored\n", irq); return; } @@ -449,23 +536,9 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs) * i.e. go ahead and complete the irq anyway. */ - if (irq != s->running_irq[cpu]) { - /* Complete an IRQ that is not currently running. */ - int tmp = s->running_irq[cpu]; - while (s->last_active[tmp][cpu] != 1023) { - if (s->last_active[tmp][cpu] == irq) { - s->last_active[tmp][cpu] = s->last_active[irq][cpu]; - break; - } - tmp = s->last_active[tmp][cpu]; - } - if (update) { - gic_update(s); - } - } else { - /* Complete the current running IRQ. */ - gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]); - } + gic_drop_prio(s, cpu, group); + GIC_CLEAR_ACTIVE(irq, cm); + gic_update(s); } static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) @@ -922,6 +995,68 @@ static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data, } } +static inline uint32_t gic_apr_ns_view(GICState *s, int cpu, int regno) +{ + /* Return the Nonsecure view of GICC_APR<regno>. This is the + * second half of GICC_NSAPR. + */ + switch (GIC_MIN_BPR) { + case 0: + if (regno < 2) { + return s->nsapr[regno + 2][cpu]; + } + break; + case 1: + if (regno == 0) { + return s->nsapr[regno + 1][cpu]; + } + break; + case 2: + if (regno == 0) { + return extract32(s->nsapr[0][cpu], 16, 16); + } + break; + case 3: + if (regno == 0) { + return extract32(s->nsapr[0][cpu], 8, 8); + } + break; + default: + g_assert_not_reached(); + } + return 0; +} + +static inline void gic_apr_write_ns_view(GICState *s, int cpu, int regno, + uint32_t value) +{ + /* Write the Nonsecure view of GICC_APR<regno>. */ + switch (GIC_MIN_BPR) { + case 0: + if (regno < 2) { + s->nsapr[regno + 2][cpu] = value; + } + break; + case 1: + if (regno == 0) { + s->nsapr[regno + 1][cpu] = value; + } + break; + case 2: + if (regno == 0) { + s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 16, 16, value); + } + break; + case 3: + if (regno == 0) { + s->nsapr[0][cpu] = deposit32(s->nsapr[0][cpu], 8, 8, value); + } + break; + default: + g_assert_not_reached(); + } +} + static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, uint64_t *data, MemTxAttrs attrs) { @@ -962,8 +1097,31 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, } break; case 0xd0: case 0xd4: case 0xd8: case 0xdc: - *data = s->apr[(offset - 0xd0) / 4][cpu]; + { + int regno = (offset - 0xd0) / 4; + + if (regno >= GIC_NR_APRS || s->revision != 2) { + *data = 0; + } else if (s->security_extn && !attrs.secure) { + /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */ + *data = gic_apr_ns_view(s, regno, cpu); + } else { + *data = s->apr[regno][cpu]; + } break; + } + case 0xe0: case 0xe4: case 0xe8: case 0xec: + { + int regno = (offset - 0xe0) / 4; + + if (regno >= GIC_NR_APRS || s->revision != 2 || !gic_has_groups(s) || + (s->security_extn && !attrs.secure)) { + *data = 0; + } else { + *data = s->nsapr[regno][cpu]; + } + break; + } default: qemu_log_mask(LOG_GUEST_ERROR, "gic_cpu_read: Bad offset %x\n", (int)offset); @@ -1001,8 +1159,33 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, } break; case 0xd0: case 0xd4: case 0xd8: case 0xdc: - qemu_log_mask(LOG_UNIMP, "Writing APR not implemented\n"); + { + int regno = (offset - 0xd0) / 4; + + if (regno >= GIC_NR_APRS || s->revision != 2) { + return MEMTX_OK; + } + if (s->security_extn && !attrs.secure) { + /* NS view of GICC_APR<n> is the top half of GIC_NSAPR<n> */ + gic_apr_write_ns_view(s, regno, cpu, value); + } else { + s->apr[regno][cpu] = value; + } break; + } + case 0xe0: case 0xe4: case 0xe8: case 0xec: + { + int regno = (offset - 0xe0) / 4; + + if (regno >= GIC_NR_APRS || s->revision != 2) { + return MEMTX_OK; + } + if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { + return MEMTX_OK; + } + s->nsapr[regno][cpu] = value; + break; + } default: qemu_log_mask(LOG_GUEST_ERROR, "gic_cpu_write: Bad offset %x\n", (int)offset); diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index fe64b51cff..9c82b97293 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -19,6 +19,7 @@ */ #include "gic_internal.h" +#include "hw/arm/linux-boot-if.h" static void gic_pre_save(void *opaque) { @@ -59,8 +60,8 @@ static const VMStateDescription vmstate_gic_irq_state = { static const VMStateDescription vmstate_gic = { .name = "arm_gic", - .version_id = 10, - .minimum_version_id = 10, + .version_id = 12, + .minimum_version_id = 12, .pre_save = gic_pre_save, .post_load = gic_post_load, .fields = (VMStateField[]) { @@ -71,15 +72,14 @@ static const VMStateDescription vmstate_gic = { VMSTATE_UINT8_ARRAY(irq_target, GICState, GIC_MAXIRQ), VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, GIC_NCPU), VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL), - VMSTATE_UINT16_2DARRAY(last_active, GICState, GIC_MAXIRQ, GIC_NCPU), VMSTATE_UINT8_2DARRAY(sgi_pending, GICState, GIC_NR_SGIS, GIC_NCPU), VMSTATE_UINT16_ARRAY(priority_mask, GICState, GIC_NCPU), - VMSTATE_UINT16_ARRAY(running_irq, GICState, GIC_NCPU), VMSTATE_UINT16_ARRAY(running_priority, GICState, GIC_NCPU), VMSTATE_UINT16_ARRAY(current_pending, GICState, GIC_NCPU), VMSTATE_UINT8_ARRAY(bpr, GICState, GIC_NCPU), VMSTATE_UINT8_ARRAY(abpr, GICState, GIC_NCPU), VMSTATE_UINT32_2DARRAY(apr, GICState, GIC_NR_APRS, GIC_NCPU), + VMSTATE_UINT32_2DARRAY(nsapr, GICState, GIC_NR_APRS, GIC_NCPU), VMSTATE_END_OF_LIST() } }; @@ -165,21 +165,35 @@ static void arm_gic_common_reset(DeviceState *dev) { GICState *s = ARM_GIC_COMMON(dev); int i, j; + int resetprio; + + /* If we're resetting a TZ-aware GIC as if secure firmware + * had set it up ready to start a kernel in non-secure, + * we need to set interrupt priorities to a "zero for the + * NS view" value. This is particularly critical for the + * priority_mask[] values, because if they are zero then NS + * code cannot ever rewrite the priority to anything else. + */ + if (s->security_extn && s->irq_reset_nonsecure) { + resetprio = 0x80; + } else { + resetprio = 0; + } + memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state)); for (i = 0 ; i < s->num_cpu; i++) { if (s->revision == REV_11MPCORE) { s->priority_mask[i] = 0xf0; } else { - s->priority_mask[i] = 0; + s->priority_mask[i] = resetprio; } s->current_pending[i] = 1023; - s->running_irq[i] = 1023; s->running_priority[i] = 0x100; s->cpu_ctlr[i] = 0; s->bpr[i] = GIC_MIN_BPR; s->abpr[i] = GIC_MIN_ABPR; for (j = 0; j < GIC_INTERNAL; j++) { - s->priority1[j][i] = 0; + s->priority1[j][i] = resetprio; } for (j = 0; j < GIC_NR_SGIS; j++) { s->sgi_pending[j][i] = 0; @@ -191,7 +205,7 @@ static void arm_gic_common_reset(DeviceState *dev) } for (i = 0; i < ARRAY_SIZE(s->priority2); i++) { - s->priority2[i] = 0; + s->priority2[i] = resetprio; } for (i = 0; i < GIC_MAXIRQ; i++) { @@ -202,9 +216,32 @@ static void arm_gic_common_reset(DeviceState *dev) s->irq_target[i] = 0; } } + if (s->security_extn && s->irq_reset_nonsecure) { + for (i = 0; i < GIC_MAXIRQ; i++) { + GIC_SET_GROUP(i, ALL_CPU_MASK); + } + } + s->ctlr = 0; } +static void arm_gic_common_linux_init(ARMLinuxBootIf *obj, + bool secure_boot) +{ + GICState *s = ARM_GIC_COMMON(obj); + + if (s->security_extn && !secure_boot) { + /* We're directly booting a kernel into NonSecure. If this GIC + * implements the security extensions then we must configure it + * to have all the interrupts be NonSecure (this is a job that + * is done by the Secure boot firmware in real hardware, and in + * this mode QEMU is acting as a minimalist firmware-and-bootloader + * equivalent). + */ + s->irq_reset_nonsecure = true; + } +} + static Property arm_gic_common_properties[] = { DEFINE_PROP_UINT32("num-cpu", GICState, num_cpu, 1), DEFINE_PROP_UINT32("num-irq", GICState, num_irq, 32), @@ -221,11 +258,13 @@ static Property arm_gic_common_properties[] = { static void arm_gic_common_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass); dc->reset = arm_gic_common_reset; dc->realize = arm_gic_common_realize; dc->props = arm_gic_common_properties; dc->vmsd = &vmstate_gic; + albifc->arm_linux_init = arm_gic_common_linux_init; } static const TypeInfo arm_gic_common_type = { @@ -235,6 +274,10 @@ static const TypeInfo arm_gic_common_type = { .class_size = sizeof(ARMGICCommonClass), .class_init = arm_gic_common_class_init, .abstract = true, + .interfaces = (InterfaceInfo []) { + { TYPE_ARM_LINUX_BOOT_IF }, + { }, + }, }; static void register_types(void) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index e13b729e1d..3ec8408618 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -185,26 +185,25 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset) return cpu->midr; case 0xd04: /* Interrupt Control State. */ /* VECTACTIVE */ - val = s->gic.running_irq[0]; + cpu = ARM_CPU(current_cpu); + val = cpu->env.v7m.exception; if (val == 1023) { val = 0; } else if (val >= 32) { val -= 16; } - /* RETTOBASE */ - if (s->gic.running_irq[0] == 1023 - || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) { - val |= (1 << 11); - } /* VECTPENDING */ if (s->gic.current_pending[0] != 1023) val |= (s->gic.current_pending[0] << 12); - /* ISRPENDING */ + /* ISRPENDING and RETTOBASE */ for (irq = 32; irq < s->num_irq; irq++) { if (s->gic.irq_state[irq].pending) { val |= (1 << 22); break; } + if (irq != cpu->env.v7m.exception && s->gic.irq_state[irq].active) { + val |= (1 << 11); + } } /* PENDSTSET */ if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 494a346cf6..1127223cfd 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -951,7 +951,7 @@ static void gem_phy_reset(CadenceGEMState *s) s->phy_regs[PHY_REG_1000BTSTAT] = 0x7C00; s->phy_regs[PHY_REG_EXTSTAT] = 0x3000; s->phy_regs[PHY_REG_PHYSPCFC_CTL] = 0x0078; - s->phy_regs[PHY_REG_PHYSPCFC_ST] = 0xBC00; + s->phy_regs[PHY_REG_PHYSPCFC_ST] = 0x7C00; s->phy_regs[PHY_REG_EXT_PHYSPCFC_CTL] = 0x0C60; s->phy_regs[PHY_REG_LED] = 0x4100; s->phy_regs[PHY_REG_EXT_PHYSPCFC_CTL2] = 0x000A; diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 5c1d11f517..1d76b94c84 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -197,7 +197,7 @@ static int vhost_net_set_vnet_endian(VirtIODevice *dev, NetClientState *peer, { int r = 0; - if (virtio_has_feature(dev, VIRTIO_F_VERSION_1) || + if (virtio_vdev_has_feature(dev, VIRTIO_F_VERSION_1) || (virtio_legacy_is_cross_endian(dev) && !virtio_is_big_endian(dev))) { r = qemu_set_vnet_le(peer, set); if (r) { diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 8d28e45afc..f72eebff2b 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -86,8 +86,8 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) memcpy(&netcfg, config, n->config_size); - if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR) && - !virtio_has_feature(vdev, VIRTIO_F_VERSION_1) && + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR) && + !virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) && memcmp(netcfg.mac, n->mac, ETH_ALEN)) { memcpy(n->mac, netcfg.mac, ETH_ALEN); qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac); @@ -304,7 +304,7 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc) info->multicast_table = str_list; info->vlan_table = get_vlan_table(n); - if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VLAN)) { + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VLAN)) { info->vlan = RX_STATE_ALL; } else if (!info->vlan_table) { info->vlan = RX_STATE_NONE; @@ -529,13 +529,13 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) int i; virtio_net_set_multiqueue(n, - __virtio_has_feature(features, VIRTIO_NET_F_MQ)); + virtio_has_feature(features, VIRTIO_NET_F_MQ)); virtio_net_set_mrg_rx_bufs(n, - __virtio_has_feature(features, - VIRTIO_NET_F_MRG_RXBUF), - __virtio_has_feature(features, - VIRTIO_F_VERSION_1)); + virtio_has_feature(features, + VIRTIO_NET_F_MRG_RXBUF), + virtio_has_feature(features, + VIRTIO_F_VERSION_1)); if (n->has_vnet_hdr) { n->curr_guest_offloads = @@ -552,7 +552,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) vhost_net_ack_features(get_vhost_net(nc->peer), features); } - if (__virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) { + if (virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) { memset(n->vlans, 0, MAX_VLAN >> 3); } else { memset(n->vlans, 0xff, MAX_VLAN >> 3); @@ -599,7 +599,7 @@ static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd, uint64_t offloads; size_t s; - if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { + if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { return VIRTIO_NET_ERR; } @@ -1449,7 +1449,7 @@ static void virtio_net_save_device(VirtIODevice *vdev, QEMUFile *f) } } - if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { + if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { qemu_put_be64(f, n->curr_guest_offloads); } } @@ -1475,7 +1475,8 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f, n->vqs[0].tx_waiting = qemu_get_be32(f); virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f), - virtio_has_feature(vdev, VIRTIO_F_VERSION_1)); + virtio_vdev_has_feature(vdev, + VIRTIO_F_VERSION_1)); if (version_id >= 3) n->status = qemu_get_be16(f); @@ -1558,7 +1559,7 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f, } } - if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { + if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { n->curr_guest_offloads = qemu_get_be64(f); } else { n->curr_guest_offloads = virtio_net_supported_guest_offloads(n); @@ -1585,8 +1586,8 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f, qemu_get_subqueue(n->nic, i)->link_down = link_down; } - if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) && - virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { + if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) && + virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { n->announce_counter = SELF_ANNOUNCE_ROUNDS; timer_mod(n->announce_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)); } diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 4700e95206..ccea628209 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1154,16 +1154,16 @@ static void pci_update_mappings(PCIDevice *d) /* now do the real mapping */ if (r->addr != PCI_BAR_UNMAPPED) { trace_pci_update_mappings_del(d, pci_bus_num(d->bus), - PCI_FUNC(d->devfn), PCI_SLOT(d->devfn), + PCI_FUNC(d->devfn), i, r->addr, r->size); memory_region_del_subregion(r->address_space, r->memory); } r->addr = new_addr; if (r->addr != PCI_BAR_UNMAPPED) { trace_pci_update_mappings_add(d, pci_bus_num(d->bus), - PCI_FUNC(d->devfn), PCI_SLOT(d->devfn), + PCI_FUNC(d->devfn), i, r->addr, r->size); memory_region_add_subregion_overlap(r->address_space, r->addr, r->memory, 1); @@ -2383,17 +2383,14 @@ static void pci_device_class_init(ObjectClass *klass, void *data) AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) { PCIBus *bus = PCI_BUS(dev->bus); + PCIBus *iommu_bus = bus; - if (bus->iommu_fn) { - return bus->iommu_fn(bus, bus->iommu_opaque, dev->devfn); + while(iommu_bus && !iommu_bus->iommu_fn && iommu_bus->parent_dev) { + iommu_bus = PCI_BUS(iommu_bus->parent_dev->bus); } - - if (bus->parent_dev) { - /** We are ignoring the bus master DMA bit of the bridge - * as it would complicate things such as VFIO for no good reason */ - return pci_device_iommu_address_space(bus->parent_dev); + if (iommu_bus && iommu_bus->iommu_fn) { + return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, dev->devfn); } - return &address_space_memory; } diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index a8bb1c66f9..1c33f146a7 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -145,7 +145,7 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req, * * TODO: always disable this workaround for virtio 1.0 devices. */ - if (!virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT)) { + if (!virtio_vdev_has_feature(vdev, VIRTIO_F_ANY_LAYOUT)) { if (req->elem.out_num) { req_size = req->elem.out_sg[0].iov_len; } @@ -759,7 +759,7 @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense) VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); VirtIODevice *vdev = VIRTIO_DEVICE(s); - if (virtio_has_feature(vdev, VIRTIO_SCSI_F_CHANGE) && + if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_CHANGE) && dev->type != TYPE_ROM) { virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE, sense.asc | (sense.ascq << 8)); @@ -783,7 +783,7 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, aio_context_release(s->ctx); } - if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) { + if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) { virtio_scsi_push_event(s, sd, VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_RESCAN); @@ -797,7 +797,7 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev, VirtIOSCSI *s = VIRTIO_SCSI(vdev); SCSIDevice *sd = SCSI_DEVICE(dev); - if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) { + if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) { virtio_scsi_push_event(s, sd, VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_REMOVED); diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c index 07fd69c69e..fece83a829 100644 --- a/hw/virtio/dataplane/vring.c +++ b/hw/virtio/dataplane/vring.c @@ -105,7 +105,7 @@ void vring_teardown(Vring *vring, VirtIODevice *vdev, int n) /* Disable guest->host notifies */ void vring_disable_notification(VirtIODevice *vdev, Vring *vring) { - if (!virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { + if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { vring_set_used_flags(vdev, vring, VRING_USED_F_NO_NOTIFY); } } @@ -116,7 +116,7 @@ void vring_disable_notification(VirtIODevice *vdev, Vring *vring) */ bool vring_enable_notification(VirtIODevice *vdev, Vring *vring) { - if (virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { + if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { vring_avail_event(&vring->vr) = vring->vr.avail->idx; } else { vring_clear_used_flags(vdev, vring, VRING_USED_F_NO_NOTIFY); @@ -135,12 +135,12 @@ bool vring_should_notify(VirtIODevice *vdev, Vring *vring) * interrupts. */ smp_mb(); - if (virtio_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) && + if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) && unlikely(!vring_more_avail(vdev, vring))) { return true; } - if (!virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { + if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { return !(vring_get_avail_flags(vdev, vring) & VRING_AVAIL_F_NO_INTERRUPT); } @@ -402,7 +402,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring, /* On success, increment avail index. */ vring->last_avail_idx++; - if (virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { + if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { vring_avail_event(&vring->vr) = virtio_tswap16(vdev, vring->last_avail_idx); } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 2712c6fc0a..a08c36bb45 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -742,7 +742,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, return -errno; } - if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) && + if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) && virtio_legacy_is_cross_endian(vdev)) { r = vhost_virtqueue_set_vring_endian_legacy(dev, virtio_is_big_endian(vdev), @@ -839,7 +839,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev, /* In the cross-endian case, we need to reset the vring endianness to * native as legacy devices expect so by default. */ - if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) && + if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) && virtio_legacy_is_cross_endian(vdev)) { r = vhost_virtqueue_set_vring_endian_legacy(dev, !virtio_is_big_endian(vdev), diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 3577b7af91..c419b17143 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -70,7 +70,7 @@ static inline void reset_stats(VirtIOBalloon *dev) static bool balloon_stats_supported(const VirtIOBalloon *s) { VirtIODevice *vdev = VIRTIO_DEVICE(s); - return virtio_has_feature(vdev, VIRTIO_BALLOON_F_STATS_VQ); + return virtio_vdev_has_feature(vdev, VIRTIO_BALLOON_F_STATS_VQ); } static bool balloon_stats_enabled(const VirtIOBalloon *s) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 788b556a74..0832db9935 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -220,7 +220,7 @@ static inline void vring_set_avail_event(VirtQueue *vq, uint16_t val) void virtio_queue_set_notification(VirtQueue *vq, int enable) { vq->notification = enable; - if (virtio_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX)) { + if (virtio_vdev_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX)) { vring_set_avail_event(vq, vring_avail_idx(vq)); } else if (enable) { vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY); @@ -471,7 +471,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) max = vq->vring.num; i = head = virtqueue_get_head(vq, vq->last_avail_idx++); - if (virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { + if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { vring_set_avail_event(vq, vq->last_avail_idx); } @@ -560,7 +560,7 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val) VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); trace_virtio_set_status(vdev, val); - if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { + if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { if (!(vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) && val & VIRTIO_CONFIG_S_FEATURES_OK) { int ret = virtio_validate_features(vdev); @@ -898,7 +898,7 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align) VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); /* virtio-1 compliant devices cannot change the alignment */ - if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { + if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { error_report("tried to modify queue alignment for virtio-1 device"); return; } @@ -993,12 +993,12 @@ static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq) /* We need to expose used array entries before checking used event. */ smp_mb(); /* Always notify when queue is empty (when feature acknowledge) */ - if (virtio_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) && + if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) && !vq->inuse && vring_avail_idx(vq) == vq->last_avail_idx) { return true; } - if (!virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { + if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) { return !(vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT); } @@ -1035,7 +1035,7 @@ static bool virtio_device_endian_needed(void *opaque) VirtIODevice *vdev = opaque; assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); - if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { + if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { return vdev->device_endian != virtio_default_endian(); } /* Devices conforming to VIRTIO 1.0 or later are always LE. */ diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index e3afa13678..1b632dc542 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -9,7 +9,6 @@ /* Reserve RAM space for tables: add another order of magnitude. */ #define ACPI_BUILD_TABLE_MAX_SIZE 0x200000 -#define ACPI_BUILD_APPNAME "Bochs" #define ACPI_BUILD_APPNAME6 "BOCHS " #define ACPI_BUILD_APPNAME4 "BXPC" diff --git a/include/hw/arm/linux-boot-if.h b/include/hw/arm/linux-boot-if.h new file mode 100644 index 0000000000..aba4479a14 --- /dev/null +++ b/include/hw/arm/linux-boot-if.h @@ -0,0 +1,43 @@ +/* + * hw/arm/linux-boot-if.h : interface for devices which need to behave + * specially for direct boot of an ARM Linux kernel + */ + +#ifndef HW_ARM_LINUX_BOOT_IF_H +#define HW_ARM_LINUX_BOOT_IF_H + +#include "qom/object.h" + +#define TYPE_ARM_LINUX_BOOT_IF "arm-linux-boot-if" +#define ARM_LINUX_BOOT_IF_CLASS(klass) \ + OBJECT_CLASS_CHECK(ARMLinuxBootIfClass, (klass), TYPE_ARM_LINUX_BOOT_IF) +#define ARM_LINUX_BOOT_IF_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ARMLinuxBootIfClass, (obj), TYPE_ARM_LINUX_BOOT_IF) +#define ARM_LINUX_BOOT_IF(obj) \ + INTERFACE_CHECK(ARMLinuxBootIf, (obj), TYPE_ARM_LINUX_BOOT_IF) + +typedef struct ARMLinuxBootIf { + /*< private >*/ + Object parent_obj; +} ARMLinuxBootIf; + +typedef struct ARMLinuxBootIfClass { + /*< private >*/ + InterfaceClass parent_class; + + /*< public >*/ + /** arm_linux_init: configure the device for a direct boot + * of an ARM Linux kernel (so that device reset puts it into + * the state the kernel expects after firmware initialization, + * rather than the true hardware reset state). This callback is + * called once after machine construction is complete (before the + * first system reset). + * + * @obj: the object implementing this interface + * @secure_boot: true if we are booting Secure, false for NonSecure + * (or for a CPU which doesn't support TrustZone) + */ + void (*arm_linux_init)(ARMLinuxBootIf *obj, bool secure_boot); +} ARMLinuxBootIfClass; + +#endif diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h index 6ccb57b187..97622ecf8f 100644 --- a/include/hw/arm/xlnx-zynqmp.h +++ b/include/hw/arm/xlnx-zynqmp.h @@ -22,6 +22,8 @@ #include "hw/intc/arm_gic.h" #include "hw/net/cadence_gem.h" #include "hw/char/cadence_uart.h" +#include "hw/ide/pci.h" +#include "hw/ide/ahci.h" #define TYPE_XLNX_ZYNQMP "xlnx,zynqmp" #define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \ @@ -60,6 +62,7 @@ typedef struct XlnxZynqMPState { CadenceGEMState gem[XLNX_ZYNQMP_NUM_GEMS]; CadenceUARTState uart[XLNX_ZYNQMP_NUM_UARTS]; + SysbusAHCIState sata; char *boot_cpu; ARMCPU *boot_cpu_ptr; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 0639e46b2a..3e002c9da6 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -59,6 +59,7 @@ struct PCMachineClass { MachineClass parent_class; /*< public >*/ + bool broken_reserved_end; HotplugHandler *(*get_hotplug_handler)(MachineState *machine, DeviceState *dev); }; diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h index edca3e08e9..564a72b2cf 100644 --- a/include/hw/intc/arm_gic_common.h +++ b/include/hw/intc/arm_gic_common.h @@ -68,7 +68,6 @@ typedef struct GICState { uint8_t irq_target[GIC_MAXIRQ]; uint8_t priority1[GIC_INTERNAL][GIC_NCPU]; uint8_t priority2[GIC_MAXIRQ - GIC_INTERNAL]; - uint16_t last_active[GIC_MAXIRQ][GIC_NCPU]; /* For each SGI on the target CPU, we store 8 bits * indicating which source CPUs have made this SGI * pending on the target CPU. These correspond to @@ -78,7 +77,6 @@ typedef struct GICState { uint8_t sgi_pending[GIC_NR_SGIS][GIC_NCPU]; uint16_t priority_mask[GIC_NCPU]; - uint16_t running_irq[GIC_NCPU]; uint16_t running_priority[GIC_NCPU]; uint16_t current_pending[GIC_NCPU]; @@ -96,16 +94,9 @@ typedef struct GICState { * If an interrupt for preemption level X is active, then * APRn[X mod 32] == 0b1, where n = X / 32 * otherwise the bit is clear. - * - * TODO: rewrite the interrupt acknowlege/complete routines to use - * the APR registers to track the necessary information to update - * s->running_priority[] on interrupt completion (ie completely remove - * last_active[][] and running_irq[]). This will be necessary if we ever - * want to support TCG<->KVM migration, or TCG guests which can - * do power management involving powering down and restarting - * the GIC. */ uint32_t apr[GIC_NR_APRS][GIC_NCPU]; + uint32_t nsapr[GIC_NR_APRS][GIC_NCPU]; uint32_t num_cpu; @@ -118,6 +109,7 @@ typedef struct GICState { uint32_t num_irq; uint32_t revision; bool security_extn; + bool irq_reset_nonsecure; /* configure IRQs as group 1 (NS) on reset? */ int dev_fd; /* kvm device fd if backed by kvm vgic support */ } GICState; diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h index 1ec1dfdb6c..8aec843c8f 100644 --- a/include/hw/virtio/virtio-access.h +++ b/include/hw/virtio/virtio-access.h @@ -19,7 +19,7 @@ static inline bool virtio_access_is_big_endian(VirtIODevice *vdev) { - if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { + if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { /* Devices conforming to VIRTIO 1.0 or later are always LE. */ return false; } diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index cccae89d83..6201ee8ce0 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -261,26 +261,27 @@ static inline void virtio_clear_feature(uint64_t *features, unsigned int fbit) *features &= ~(1ULL << fbit); } -static inline bool __virtio_has_feature(uint64_t features, unsigned int fbit) +static inline bool virtio_has_feature(uint64_t features, unsigned int fbit) { assert(fbit < 64); return !!(features & (1ULL << fbit)); } -static inline bool virtio_has_feature(VirtIODevice *vdev, unsigned int fbit) +static inline bool virtio_vdev_has_feature(VirtIODevice *vdev, + unsigned int fbit) { - return __virtio_has_feature(vdev->guest_features, fbit); + return virtio_has_feature(vdev->guest_features, fbit); } static inline bool virtio_host_has_feature(VirtIODevice *vdev, unsigned int fbit) { - return __virtio_has_feature(vdev->host_features, fbit); + return virtio_has_feature(vdev->host_features, fbit); } static inline bool virtio_is_big_endian(VirtIODevice *vdev) { - if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { + if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN); return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG; } diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h index 4356af4560..e90931a508 100644 --- a/include/hw/xen/xen.h +++ b/include/hw/xen/xen.h @@ -10,6 +10,7 @@ #include "hw/irq.h" #include "qemu-common.h" +#include "qemu/typedefs.h" /* xen-machine.c */ enum xen_mode { @@ -38,8 +39,7 @@ qemu_irq *xen_interrupt_controller_init(void); void xenstore_store_pv_console_info(int i, struct CharDriverState *chr); #if defined(NEED_CPU_H) && !defined(CONFIG_USER_ONLY) -int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size, - MemoryRegion **ram_memory); +int xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory); void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, struct MemoryRegion *mr); void xen_modified_memory(ram_addr_t start, ram_addr_t length); diff --git a/include/qapi/error.h b/include/qapi/error.h index f44c451830..426d5eaceb 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -2,13 +2,75 @@ * QEMU Error Objects * * Copyright IBM, Corp. 2011 + * Copyright (C) 2011-2015 Red Hat, Inc. * * Authors: * Anthony Liguori <aliguori@us.ibm.com> + * Markus Armbruster <armbru@redhat.com> * * This work is licensed under the terms of the GNU LGPL, version 2. See * the COPYING.LIB file in the top-level directory. */ + +/* + * Error reporting system loosely patterned after Glib's GError. + * + * Create an error: + * error_setg(&err, "situation normal, all fouled up"); + * + * Report an error to stderr: + * error_report_err(err); + * This frees the error object. + * + * Report an error somewhere else: + * const char *msg = error_get_pretty(err); + * do with msg what needs to be done... + * error_free(err); + * + * Handle an error without reporting it (just for completeness): + * error_free(err); + * + * Pass an existing error to the caller: + * error_propagate(errp, err); + * where Error **errp is a parameter, by convention the last one. + * + * Create a new error and pass it to the caller: + * error_setg(errp, "situation normal, all fouled up"); + * + * Call a function and receive an error from it: + * Error *err = NULL; + * foo(arg, &err); + * if (err) { + * handle the error... + * } + * + * Call a function ignoring errors: + * foo(arg, NULL); + * + * Call a function aborting on errors: + * foo(arg, &error_abort); + * + * Receive an error and pass it on to the caller: + * Error *err = NULL; + * foo(arg, &err); + * if (err) { + * handle the error... + * error_propagate(errp, err); + * } + * where Error **errp is a parameter, by convention the last one. + * + * Do *not* "optimize" this to + * foo(arg, errp); + * if (*errp) { // WRONG! + * handle the error... + * } + * because errp may be NULL! + * + * But when all you do with the error is pass it on, please use + * foo(arg, errp); + * for readability. + */ + #ifndef ERROR_H #define ERROR_H @@ -16,93 +78,125 @@ #include "qapi-types.h" #include <stdbool.h> -/** - * A class representing internal errors within QEMU. An error has a ErrorClass - * code and a human message. +/* + * Opaque error object. */ typedef struct Error Error; -/** - * Set an indirect pointer to an error given a ErrorClass value and a - * printf-style human message. This function is not meant to be used outside - * of QEMU. +/* + * Get @err's human-readable error message. */ -void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...) - GCC_FMT_ATTR(3, 4); +const char *error_get_pretty(Error *err); -/** - * Set an indirect pointer to an error given a ErrorClass value and a - * printf-style human message, followed by a strerror() string if - * @os_error is not zero. +/* + * Get @err's error class. + * Note: use of error classes other than ERROR_CLASS_GENERIC_ERROR is + * strongly discouraged. */ -void error_set_errno(Error **errp, int os_error, ErrorClass err_class, - const char *fmt, ...) GCC_FMT_ATTR(4, 5); +ErrorClass error_get_class(const Error *err); -#ifdef _WIN32 -/** - * Set an indirect pointer to an error given a ErrorClass value and a - * printf-style human message, followed by a g_win32_error_message() string if - * @win32_err is not zero. +/* + * Create a new error object and assign it to *@errp. + * If @errp is NULL, the error is ignored. Don't bother creating one + * then. + * If @errp is &error_abort, print a suitable message and abort(). + * If @errp is anything else, *@errp must be NULL. + * The new error's class is ERROR_CLASS_GENERIC_ERROR, and its + * human-readable error message is made from printf-style @fmt, ... */ -void error_set_win32(Error **errp, int win32_err, ErrorClass err_class, - const char *fmt, ...) GCC_FMT_ATTR(4, 5); -#endif +#define error_setg(errp, fmt, ...) \ + error_setg_internal((errp), __FILE__, __LINE__, __func__, \ + (fmt), ## __VA_ARGS__) +void error_setg_internal(Error **errp, + const char *src, int line, const char *func, + const char *fmt, ...) + GCC_FMT_ATTR(5, 6); -/** - * Same as error_set(), but sets a generic error +/* + * Just like error_setg(), with @os_error info added to the message. + * If @os_error is non-zero, ": " + strerror(os_error) is appended to + * the human-readable error message. */ -#define error_setg(errp, fmt, ...) \ - error_set(errp, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__) -#define error_setg_errno(errp, os_error, fmt, ...) \ - error_set_errno(errp, os_error, ERROR_CLASS_GENERIC_ERROR, \ - fmt, ## __VA_ARGS__) +#define error_setg_errno(errp, os_error, fmt, ...) \ + error_setg_errno_internal((errp), __FILE__, __LINE__, __func__, \ + (os_error), (fmt), ## __VA_ARGS__) +void error_setg_errno_internal(Error **errp, + const char *fname, int line, const char *func, + int os_error, const char *fmt, ...) + GCC_FMT_ATTR(6, 7); + #ifdef _WIN32 -#define error_setg_win32(errp, win32_err, fmt, ...) \ - error_set_win32(errp, win32_err, ERROR_CLASS_GENERIC_ERROR, \ - fmt, ## __VA_ARGS__) +/* + * Just like error_setg(), with @win32_error info added to the message. + * If @win32_error is non-zero, ": " + g_win32_error_message(win32_err) + * is appended to the human-readable error message. + */ +#define error_setg_win32(errp, win32_err, fmt, ...) \ + error_setg_win32_internal((errp), __FILE__, __LINE__, __func__, \ + (win32_err), (fmt), ## __VA_ARGS__) +void error_setg_win32_internal(Error **errp, + const char *src, int line, const char *func, + int win32_err, const char *fmt, ...) + GCC_FMT_ATTR(6, 7); #endif -/** - * Helper for open() errors +/* + * Propagate error object (if any) from @local_err to @dst_errp. + * If @local_err is NULL, do nothing (because there's nothing to + * propagate). + * Else, if @dst_errp is NULL, errors are being ignored. Free the + * error object. + * Else, if @dst_errp is &error_abort, print a suitable message and + * abort(). + * Else, if @dst_errp already contains an error, ignore this one: free + * the error object. + * Else, move the error object from @local_err to *@dst_errp. + * On return, @local_err is invalid. */ -void error_setg_file_open(Error **errp, int os_errno, const char *filename); +void error_propagate(Error **dst_errp, Error *local_err); /* - * Get the error class of an error object. + * Convenience function to report open() failure. */ -ErrorClass error_get_class(const Error *err); +#define error_setg_file_open(errp, os_errno, filename) \ + error_setg_file_open_internal((errp), __FILE__, __LINE__, __func__, \ + (os_errno), (filename)) +void error_setg_file_open_internal(Error **errp, + const char *src, int line, const char *func, + int os_errno, const char *filename); -/** - * Returns an exact copy of the error passed as an argument. +/* + * Return an exact copy of @err. */ Error *error_copy(const Error *err); -/** - * Get a human readable representation of an error object. +/* + * Free @err. + * @err may be NULL. */ -const char *error_get_pretty(Error *err); +void error_free(Error *err); -/** - * Convenience function to error_report() and free an error object. +/* + * Convenience function to error_report() and free @err. */ void error_report_err(Error *); -/** - * Propagate an error to an indirect pointer to an error. This function will - * always transfer ownership of the error reference and handles the case where - * dst_err is NULL correctly. Errors after the first are discarded. - */ -void error_propagate(Error **dst_errp, Error *local_err); - -/** - * Free an error object. +/* + * Just like error_setg(), except you get to specify the error class. + * Note: use of error classes other than ERROR_CLASS_GENERIC_ERROR is + * strongly discouraged. */ -void error_free(Error *err); +#define error_set(errp, err_class, fmt, ...) \ + error_set_internal((errp), __FILE__, __LINE__, __func__, \ + (err_class), (fmt), ## __VA_ARGS__) +void error_set_internal(Error **errp, + const char *src, int line, const char *func, + ErrorClass err_class, const char *fmt, ...) + GCC_FMT_ATTR(6, 7); -/** - * If passed to error_set and friends, abort(). +/* + * Pass to error_setg() & friends to abort() on error. */ - extern Error *error_abort; #endif diff --git a/include/qom/object.h b/include/qom/object.h index 807978eec7..be7280c862 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1494,6 +1494,21 @@ int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), void *opaque); /** + * object_child_foreach_recursive: + * @obj: the object whose children will be navigated + * @fn: the iterator function to be called + * @opaque: an opaque value that will be passed to the iterator + * + * Call @fn passing each child of @obj and @opaque to it, until @fn returns + * non-zero. Calls recursively, all child nodes of @obj will also be passed + * all the way down to the leaf nodes of the tree. Depth first ordering. + * + * Returns: The last value returned by @fn, or 0 if there is no child. + */ +int object_child_foreach_recursive(Object *obj, + int (*fn)(Object *child, void *opaque), + void *opaque); +/** * container_get: * @root: root of the #path, e.g., object_get_root() * @path: path to the container diff --git a/qga/vss-win32.c b/qga/vss-win32.c index 0e4095736e..2142b4964d 100644 --- a/qga/vss-win32.c +++ b/qga/vss-win32.c @@ -150,11 +150,11 @@ void qga_vss_fsfreeze(int *nr_volume, Error **errp, bool freeze) const char *func_name = freeze ? "requester_freeze" : "requester_thaw"; QGAVSSRequesterFunc func; ErrorSet errset = { - .error_set = (ErrorSetFunc)error_set_win32, - .errp = (void **)errp, - .err_class = ERROR_CLASS_GENERIC_ERROR + .error_setg_win32 = error_setg_win32_internal, + .errp = errp, }; + g_assert(errp); /* requester.cpp requires it */ func = (QGAVSSRequesterFunc)GetProcAddress(provider_lib, func_name); if (!func) { error_setg_win32(errp, GetLastError(), "failed to load %s from %s", diff --git a/qga/vss-win32/requester.cpp b/qga/vss-win32/requester.cpp index 922e74ddfc..9b3e310971 100644 --- a/qga/vss-win32/requester.cpp +++ b/qga/vss-win32/requester.cpp @@ -23,10 +23,12 @@ /* Call QueryStatus every 10 ms while waiting for frozen event */ #define VSS_TIMEOUT_EVENT_MSEC 10 -#define err_set(e, err, fmt, ...) \ - ((e)->error_set((e)->errp, err, (e)->err_class, fmt, ## __VA_ARGS__)) +#define err_set(e, err, fmt, ...) \ + ((e)->error_setg_win32((e)->errp, __FILE__, __LINE__, __func__, \ + err, fmt, ## __VA_ARGS__)) +/* Bad idea, works only when (e)->errp != NULL: */ #define err_is_set(e) ((e)->errp && *(e)->errp) - +/* To lift this restriction, error_propagate(), like we do in QEMU code */ /* Handle to VSSAPI.DLL */ static HMODULE hLib; diff --git a/qga/vss-win32/requester.h b/qga/vss-win32/requester.h index 374f9b8d16..c3093cf4b6 100644 --- a/qga/vss-win32/requester.h +++ b/qga/vss-win32/requester.h @@ -20,13 +20,16 @@ extern "C" { #endif +struct Error; + /* Callback to set Error; used to avoid linking glib to the DLL */ -typedef void (*ErrorSetFunc)(void **errp, int win32_err, int err_class, - const char *fmt, ...) GCC_FMT_ATTR(4, 5); +typedef void (*ErrorSetFunc)(struct Error **errp, + const char *src, int line, const char *func, + int win32_err, const char *fmt, ...) + GCC_FMT_ATTR(6, 7); typedef struct ErrorSet { - ErrorSetFunc error_set; - void **errp; - int err_class; + ErrorSetFunc error_setg_win32; + struct Error **errp; /* restriction: must not be null */ } ErrorSet; STDAPI requester_init(void); diff --git a/qom/object.c b/qom/object.c index eea8edf3d3..b7b05d3ffb 100644 --- a/qom/object.c +++ b/qom/object.c @@ -775,23 +775,42 @@ void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque), enumerating_types = false; } -int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), - void *opaque) +static int do_object_child_foreach(Object *obj, + int (*fn)(Object *child, void *opaque), + void *opaque, bool recurse) { ObjectProperty *prop, *next; int ret = 0; QTAILQ_FOREACH_SAFE(prop, &obj->properties, node, next) { if (object_property_is_child(prop)) { - ret = fn(prop->opaque, opaque); + Object *child = prop->opaque; + + ret = fn(child, opaque); if (ret != 0) { break; } + if (recurse) { + do_object_child_foreach(child, fn, opaque, true); + } } } return ret; } +int object_child_foreach(Object *obj, int (*fn)(Object *child, void *opaque), + void *opaque) +{ + return do_object_child_foreach(obj, fn, opaque, false); +} + +int object_child_foreach_recursive(Object *obj, + int (*fn)(Object *child, void *opaque), + void *opaque) +{ + return do_object_child_foreach(obj, fn, opaque, true); +} + static void object_class_get_list_tramp(ObjectClass *klass, void *opaque) { GSList **list = opaque; diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c index 02fc9b4a29..2c7a645f66 100644 --- a/target-arm/helper-a64.c +++ b/target-arm/helper-a64.c @@ -478,7 +478,8 @@ void aarch64_cpu_do_interrupt(CPUState *cs) } arm_log_exception(cs->exception_index); - qemu_log_mask(CPU_LOG_INT, "...from EL%d\n", arm_current_el(env)); + qemu_log_mask(CPU_LOG_INT, "...from EL%d to EL%d\n", arm_current_el(env), + new_el); if (qemu_loglevel_mask(CPU_LOG_INT) && !excp_is_internal(cs->exception_index)) { qemu_log_mask(CPU_LOG_INT, "...with ESR 0x%" PRIx32 "\n", diff --git a/target-arm/helper.c b/target-arm/helper.c index 040bc709a5..fc4b65fd54 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2975,16 +2975,16 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 3, .access = PL1_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, { .name = "AT_S12E1R", .state = ARM_CP_STATE_AA64, - .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 4, + .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 4, .access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, { .name = "AT_S12E1W", .state = ARM_CP_STATE_AA64, - .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 5, + .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 5, .access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, { .name = "AT_S12E0R", .state = ARM_CP_STATE_AA64, - .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 6, + .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 6, .access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, { .name = "AT_S12E0W", .state = ARM_CP_STATE_AA64, - .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 7, + .opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 7, .access = PL2_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, /* AT S1E2* are elsewhere as they UNDEF from EL3 if EL2 is not present */ { .name = "AT_S1E3R", .state = ARM_CP_STATE_AA64, @@ -2993,6 +2993,12 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "AT_S1E3W", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 6, .crn = 7, .crm = 8, .opc2 = 1, .access = PL3_W, .type = ARM_CP_NO_RAW, .writefn = ats_write64 }, + { .name = "PAR_EL1", .state = ARM_CP_STATE_AA64, + .type = ARM_CP_ALIAS, + .opc0 = 3, .opc1 = 0, .crn = 7, .crm = 4, .opc2 = 0, + .access = PL1_RW, .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.par_el[1]), + .writefn = par_write }, #endif /* TLB invalidate last level of translation table walk */ { .name = "TLBIMVALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5, diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 529bb0c41d..faece2cd43 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -10966,7 +10966,11 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, dc->condjmp = 0; dc->aarch64 = 1; - dc->el3_is_aa64 = arm_el_is_aa64(env, 3); + /* If we are coming from secure EL0 in a system with a 32-bit EL3, then + * there is no secure EL1, so we route exceptions to EL3. + */ + dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) && + !arm_el_is_aa64(env, 3); dc->thumb = 0; dc->bswap_code = 0; dc->condexec_mask = 0; diff --git a/target-arm/translate.c b/target-arm/translate.c index e27634f3c8..0bd3d0517b 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -11172,7 +11172,11 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, dc->condjmp = 0; dc->aarch64 = 0; - dc->el3_is_aa64 = arm_el_is_aa64(env, 3); + /* If we are coming from secure EL0 in a system with a 32-bit EL3, then + * there is no secure EL1, so we route exceptions to EL3. + */ + dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) && + !arm_el_is_aa64(env, 3); dc->thumb = ARM_TBFLAG_THUMB(tb->flags); dc->bswap_code = ARM_TBFLAG_BSWAP_CODE(tb->flags); dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1; diff --git a/target-arm/translate.h b/target-arm/translate.h index 9ab978fb75..4b618a4c85 100644 --- a/target-arm/translate.h +++ b/target-arm/translate.h @@ -23,7 +23,8 @@ typedef struct DisasContext { ARMMMUIdx mmu_idx; /* MMU index to use for normal loads/stores */ bool ns; /* Use non-secure CPREG bank on access */ int fp_excp_el; /* FP exception EL or 0 if enabled */ - bool el3_is_aa64; /* Flag indicating whether EL3 is AArch64 or not */ + /* Flag indicating that exceptions from secure mode are routed to EL3. */ + bool secure_routed_to_el3; bool vfp_enabled; /* FP enabled via FPSCR.EN */ int vec_len; int vec_stride; @@ -84,7 +85,7 @@ static inline int default_exception_el(DisasContext *s) * exceptions can only be routed to ELs above 1, so we target the higher of * 1 or the current EL. */ - return (s->mmu_idx == ARMMMUIdx_S1SE0 && !s->el3_is_aa64) + return (s->mmu_idx == ARMMMUIdx_S1SE0 && s->secure_routed_to_el3) ? 3 : MAX(1, s->current_el); } diff --git a/trace-events b/trace-events index 985b041873..1927c764a9 100644 --- a/trace-events +++ b/trace-events @@ -1310,8 +1310,8 @@ spapr_pci_lsi_set(const char *busname, int pin, uint32_t irq) "%s PIN%d IRQ %u" spapr_pci_msi_retry(unsigned config_addr, unsigned req_num, unsigned max_irqs) "Guest device at %x asked %u, have only %u" # hw/pci/pci.c -pci_update_mappings_del(void *d, uint32_t bus, uint32_t func, uint32_t slot, int bar, uint64_t addr, uint64_t size) "d=%p %02x:%02x.%x %d,%#"PRIx64"+%#"PRIx64 -pci_update_mappings_add(void *d, uint32_t bus, uint32_t func, uint32_t slot, int bar, uint64_t addr, uint64_t size) "d=%p %02x:%02x.%x %d,%#"PRIx64"+%#"PRIx64 +pci_update_mappings_del(void *d, uint32_t bus, uint32_t slot, uint32_t func, int bar, uint64_t addr, uint64_t size) "d=%p %02x:%02x.%x %d,%#"PRIx64"+%#"PRIx64 +pci_update_mappings_add(void *d, uint32_t bus, uint32_t slot, uint32_t func, int bar, uint64_t addr, uint64_t size) "d=%p %02x:%02x.%x %d,%#"PRIx64"+%#"PRIx64 # hw/net/pcnet.c pcnet_s_reset(void *s) "s=%p" diff --git a/util/error.c b/util/error.c index 14f4351879..cdb726ce81 100644 --- a/util/error.c +++ b/util/error.c @@ -18,14 +18,25 @@ struct Error { char *msg; ErrorClass err_class; + const char *src, *func; + int line; }; Error *error_abort; -void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...) +static void error_do_abort(Error *err) +{ + fprintf(stderr, "Unexpected error in %s() at %s:%d:\n", + err->func, err->src, err->line); + error_report_err(err); + abort(); +} + +static void error_setv(Error **errp, + const char *src, int line, const char *func, + ErrorClass err_class, const char *fmt, va_list ap) { Error *err; - va_list ap; int saved_errno = errno; if (errp == NULL) { @@ -34,15 +45,14 @@ void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...) assert(*errp == NULL); err = g_malloc0(sizeof(*err)); - - va_start(ap, fmt); err->msg = g_strdup_vprintf(fmt, ap); - va_end(ap); err->err_class = err_class; + err->src = src; + err->line = line; + err->func = func; if (errp == &error_abort) { - error_report_err(err); - abort(); + error_do_abort(err); } *errp = err; @@ -50,83 +60,86 @@ void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...) errno = saved_errno; } -void error_set_errno(Error **errp, int os_errno, ErrorClass err_class, - const char *fmt, ...) +void error_set_internal(Error **errp, + const char *src, int line, const char *func, + ErrorClass err_class, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + error_setv(errp, src, line, func, err_class, fmt, ap); + va_end(ap); +} + +void error_setg_internal(Error **errp, + const char *src, int line, const char *func, + const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap); + va_end(ap); +} + +void error_setg_errno_internal(Error **errp, + const char *src, int line, const char *func, + int os_errno, const char *fmt, ...) { - Error *err; - char *msg1; va_list ap; + char *msg; int saved_errno = errno; if (errp == NULL) { return; } - assert(*errp == NULL); - - err = g_malloc0(sizeof(*err)); va_start(ap, fmt); - msg1 = g_strdup_vprintf(fmt, ap); - if (os_errno != 0) { - err->msg = g_strdup_printf("%s: %s", msg1, strerror(os_errno)); - g_free(msg1); - } else { - err->msg = msg1; - } + error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap); va_end(ap); - err->err_class = err_class; - if (errp == &error_abort) { - error_report_err(err); - abort(); + if (os_errno != 0) { + msg = (*errp)->msg; + (*errp)->msg = g_strdup_printf("%s: %s", msg, strerror(os_errno)); + g_free(msg); } - *errp = err; - errno = saved_errno; } -void error_setg_file_open(Error **errp, int os_errno, const char *filename) +void error_setg_file_open_internal(Error **errp, + const char *src, int line, const char *func, + int os_errno, const char *filename) { - error_setg_errno(errp, os_errno, "Could not open '%s'", filename); + error_setg_errno_internal(errp, src, line, func, os_errno, + "Could not open '%s'", filename); } #ifdef _WIN32 -void error_set_win32(Error **errp, int win32_err, ErrorClass err_class, - const char *fmt, ...) +void error_setg_win32_internal(Error **errp, + const char *src, int line, const char *func, + int win32_err, const char *fmt, ...) { - Error *err; - char *msg1; va_list ap; + char *msg1, *msg2; if (errp == NULL) { return; } - assert(*errp == NULL); - - err = g_malloc0(sizeof(*err)); va_start(ap, fmt); - msg1 = g_strdup_vprintf(fmt, ap); + error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap); + va_end(ap); + if (win32_err != 0) { - char *msg2 = g_win32_error_message(win32_err); - err->msg = g_strdup_printf("%s: %s (error: %x)", msg1, msg2, - (unsigned)win32_err); + msg1 = (*errp)->msg; + msg2 = g_win32_error_message(win32_err); + (*errp)->msg = g_strdup_printf("%s: %s (error: %x)", msg1, msg2, + (unsigned)win32_err); g_free(msg2); g_free(msg1); - } else { - err->msg = msg1; } - va_end(ap); - err->err_class = err_class; - - if (errp == &error_abort) { - error_report_err(err); - abort(); - } - - *errp = err; } #endif @@ -169,8 +182,7 @@ void error_free(Error *err) void error_propagate(Error **dst_errp, Error *local_err) { if (local_err && dst_errp == &error_abort) { - error_report_err(local_err); - abort(); + error_do_abort(local_err); } else if (dst_errp && !*dst_errp) { *dst_errp = local_err; } else if (local_err) { diff --git a/xen-hvm-stub.c b/xen-hvm-stub.c index 46867d87d7..6a39425da0 100644 --- a/xen-hvm-stub.c +++ b/xen-hvm-stub.c @@ -47,8 +47,7 @@ void xen_modified_memory(ram_addr_t start, ram_addr_t length) { } -int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size, - MemoryRegion **ram_memory) +int xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory) { return 0; } @@ -180,8 +180,7 @@ qemu_irq *xen_interrupt_controller_init(void) /* Memory Ops */ -static void xen_ram_init(ram_addr_t *below_4g_mem_size, - ram_addr_t *above_4g_mem_size, +static void xen_ram_init(PCMachineState *pcms, ram_addr_t ram_size, MemoryRegion **ram_memory_p) { MemoryRegion *sysmem = get_system_memory(); @@ -198,20 +197,20 @@ static void xen_ram_init(ram_addr_t *below_4g_mem_size, } if (ram_size >= user_lowmem) { - *above_4g_mem_size = ram_size - user_lowmem; - *below_4g_mem_size = user_lowmem; + pcms->above_4g_mem_size = ram_size - user_lowmem; + pcms->below_4g_mem_size = user_lowmem; } else { - *above_4g_mem_size = 0; - *below_4g_mem_size = ram_size; + pcms->above_4g_mem_size = 0; + pcms->below_4g_mem_size = ram_size; } - if (!*above_4g_mem_size) { + if (!pcms->above_4g_mem_size) { block_len = ram_size; } else { /* * Xen does not allocate the memory continuously, it keeps a * hole of the size computed above or passed in. */ - block_len = (1ULL << 32) + *above_4g_mem_size; + block_len = (1ULL << 32) + pcms->above_4g_mem_size; } memory_region_init_ram(&ram_memory, NULL, "xen.ram", block_len, &error_abort); @@ -229,12 +228,12 @@ static void xen_ram_init(ram_addr_t *below_4g_mem_size, */ memory_region_init_alias(&ram_lo, NULL, "xen.ram.lo", &ram_memory, 0xc0000, - *below_4g_mem_size - 0xc0000); + pcms->below_4g_mem_size - 0xc0000); memory_region_add_subregion(sysmem, 0xc0000, &ram_lo); - if (*above_4g_mem_size > 0) { + if (pcms->above_4g_mem_size > 0) { memory_region_init_alias(&ram_hi, NULL, "xen.ram.hi", &ram_memory, 0x100000000ULL, - *above_4g_mem_size); + pcms->above_4g_mem_size); memory_region_add_subregion(sysmem, 0x100000000ULL, &ram_hi); } } @@ -1190,7 +1189,7 @@ static void xen_wakeup_notifier(Notifier *notifier, void *data) } /* return 0 means OK, or -1 means critical issue -- will exit(1) */ -int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size, +int xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory) { int i, rc; @@ -1301,7 +1300,7 @@ int xen_hvm_init(ram_addr_t *below_4g_mem_size, ram_addr_t *above_4g_mem_size, /* Init RAM management */ xen_map_cache_init(xen_phys_offset_to_gaddr, state); - xen_ram_init(below_4g_mem_size, above_4g_mem_size, ram_size, ram_memory); + xen_ram_init(pcms, ram_size, ram_memory); qemu_add_vm_change_state_handler(xen_hvm_change_state_handler, state); |