aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/arm/boot.c34
-rw-r--r--hw/arm/virt.c14
-rw-r--r--hw/arm/xlnx-zynqmp.c32
-rw-r--r--hw/block/virtio-blk.c7
-rw-r--r--hw/char/virtio-serial-bus.c2
-rw-r--r--hw/cpu/a15mpcore.c13
-rw-r--r--hw/cpu/a9mpcore.c11
-rw-r--r--hw/i386/pc.c8
-rw-r--r--hw/i386/pc_piix.c6
-rw-r--r--hw/i386/pc_q35.c6
-rw-r--r--hw/ide/ahci.c26
-rw-r--r--hw/ide/ahci.h16
-rw-r--r--hw/intc/arm_gic.c245
-rw-r--r--hw/intc/arm_gic_common.c59
-rw-r--r--hw/intc/armv7m_nvic.c13
-rw-r--r--hw/net/cadence_gem.c2
-rw-r--r--hw/net/vhost_net.c2
-rw-r--r--hw/net/virtio-net.c31
-rw-r--r--hw/pci/pci.c17
-rw-r--r--hw/scsi/virtio-scsi.c8
-rw-r--r--hw/virtio/dataplane/vring.c10
-rw-r--r--hw/virtio/vhost.c4
-rw-r--r--hw/virtio/virtio-balloon.c2
-rw-r--r--hw/virtio/virtio.c14
-rw-r--r--include/hw/acpi/aml-build.h1
-rw-r--r--include/hw/arm/linux-boot-if.h43
-rw-r--r--include/hw/arm/xlnx-zynqmp.h3
-rw-r--r--include/hw/i386/pc.h1
-rw-r--r--include/hw/intc/arm_gic_common.h12
-rw-r--r--include/hw/virtio/virtio-access.h2
-rw-r--r--include/hw/virtio/virtio.h11
-rw-r--r--include/hw/xen/xen.h4
-rw-r--r--include/qapi/error.h210
-rw-r--r--include/qom/object.h15
-rw-r--r--qga/vss-win32.c6
-rw-r--r--qga/vss-win32/requester.cpp8
-rw-r--r--qga/vss-win32/requester.h13
-rw-r--r--qom/object.c25
-rw-r--r--target-arm/helper-a64.c3
-rw-r--r--target-arm/helper.c14
-rw-r--r--target-arm/translate-a64.c6
-rw-r--r--target-arm/translate.c6
-rw-r--r--target-arm/translate.h5
-rw-r--r--trace-events4
-rw-r--r--util/error.c118
-rw-r--r--xen-hvm-stub.c3
-rw-r--r--xen-hvm.c25
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;
}
diff --git a/xen-hvm.c b/xen-hvm.c
index 3371c4ea31..5ea621e7b7 100644
--- a/xen-hvm.c
+++ b/xen-hvm.c
@@ -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);