Merge remote-tracking branch 'remotes/agraf/tags/signed-ppc-for-upstream' into staging
Patch queue for ppc - 2015-06-03
Highlights this time around:
- sPAPR: endian fixes, speedups, bug fixes, hotplug basics
- add default ram size capability for machines (sPAPR defaults to 512MB now)
# gpg: Signature made Wed Jun 3 22:59:09 2015 BST using RSA key ID 03FEDC60
# gpg: Good signature from "Alexander Graf <agraf@suse.de>"
# gpg: aka "Alexander Graf <alex@csgraf.de>"
* remotes/agraf/tags/signed-ppc-for-upstream: (40 commits)
softmmu: support up to 12 MMU modes
tcg: add TCG_TARGET_TLB_DISPLACEMENT_BITS
tci: do not use CPUArchState in tcg-target.h
Add David Gibson for sPAPR in MAINTAINERS file
pseries: Enable in-kernel H_LOGICAL_CI_{LOAD, STORE} implementations
spapr: override default ram size to 512MB
machine: add default_ram_size to machine class
spapr_pci: emit hotplug add/remove events during hotplug
spapr_pci: enable basic hotplug operations
pci: make pci_bar useable outside pci.c
spapr_pci: create DRConnectors for each PCI slot during PHB realize
spapr_pci: add dynamic-reconfiguration option for spapr-pci-host-bridge
spapr_drc: add spapr_drc_populate_dt()
spapr_events: event-scan RTAS interface
spapr_events: re-use EPOW event infrastructure for hotplug events
spapr_rtas: add ibm, configure-connector RTAS interface
spapr: add rtas_st_buffer_direct() helper
spapr_rtas: add get-sensor-state RTAS interface
spapr_rtas: add set-indicator RTAS interface
spapr_rtas: add get/set-power-level RTAS interfaces
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/Makefile b/Makefile
index d945804..2d52536 100644
--- a/Makefile
+++ b/Makefile
@@ -389,13 +389,8 @@
endif
endif
-install-confdir:
- $(INSTALL_DIR) "$(DESTDIR)$(qemu_confdir)"
-install-sysconfig: install-datadir install-confdir
- $(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)"
-
-install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig \
+install: all $(if $(BUILD_DOCS),install-doc) \
install-datadir install-localstatedir
ifneq ($(TOOLS),)
$(call install-prog,$(TOOLS),$(DESTDIR)$(bindir))
diff --git a/Makefile.objs b/Makefile.objs
index 28999d3..4881d2c 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -76,6 +76,8 @@
common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y)
+common-obj-$(CONFIG_FDT) += device_tree.o
+
######################################################################
# qapi
diff --git a/Makefile.target b/Makefile.target
index be01dd3..3e861c8 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -129,7 +129,6 @@
obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o numa.o
obj-y += qtest.o bootdevice.o
obj-y += hw/
-obj-$(CONFIG_FDT) += device_tree.o
obj-$(CONFIG_KVM) += kvm-all.o
obj-y += memory.o savevm.o cputlb.o
obj-y += memory_mapping.o
diff --git a/arch_init.c b/arch_init.c
index 23d3feb..b5d90a4 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -136,7 +136,6 @@
bool userconfig;
} default_config_files[] = {
{ CONFIG_QEMU_CONFDIR "/qemu.conf", true },
- { CONFIG_QEMU_CONFDIR "/target-" TARGET_NAME ".conf", true },
{ NULL }, /* end of list */
};
diff --git a/block/iscsi.c b/block/iscsi.c
index 8fca1d3..14e97a6 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -1323,13 +1323,6 @@
const char *filename;
int i, ret = 0;
- if ((BDRV_SECTOR_SIZE % 512) != 0) {
- error_setg(errp, "iSCSI: Invalid BDRV_SECTOR_SIZE. "
- "BDRV_SECTOR_SIZE(%lld) is not a multiple "
- "of 512", BDRV_SECTOR_SIZE);
- return -EINVAL;
- }
-
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
diff --git a/blockdev.c b/blockdev.c
index 5eaf77e..de94a8b 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2113,7 +2113,7 @@
aio_context_release(aio_context);
}
-int hmp_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
+void hmp_drive_del(Monitor *mon, const QDict *qdict)
{
const char *id = qdict_get_str(qdict, "id");
BlockBackend *blk;
@@ -2124,14 +2124,14 @@
blk = blk_by_name(id);
if (!blk) {
error_report("Device '%s' not found", id);
- return -1;
+ return;
}
bs = blk_bs(blk);
if (!blk_legacy_dinfo(blk)) {
error_report("Deleting device added with blockdev-add"
" is not supported");
- return -1;
+ return;
}
aio_context = bdrv_get_aio_context(bs);
@@ -2140,7 +2140,7 @@
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
error_report_err(local_err);
aio_context_release(aio_context);
- return -1;
+ return;
}
/* quiesce block driver; prevent further io */
@@ -2163,7 +2163,6 @@
}
aio_context_release(aio_context);
- return 0;
}
void qmp_block_resize(bool has_device, const char *device,
diff --git a/configure b/configure
index 35111b2..409edf9 100755
--- a/configure
+++ b/configure
@@ -353,7 +353,7 @@
;;
--cpu=*) cpu="$optarg"
;;
- --extra-cflags=*) QEMU_CFLAGS="$optarg $QEMU_CFLAGS"
+ --extra-cflags=*) QEMU_CFLAGS="$QEMU_CFLAGS $optarg"
EXTRA_CFLAGS="$optarg"
;;
--extra-ldflags=*) LDFLAGS="$optarg $LDFLAGS"
diff --git a/device_tree.c b/device_tree.c
index 3d119ef..d2de580 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -18,7 +18,6 @@
#include <unistd.h>
#include <stdlib.h>
-#include "config.h"
#include "qemu-common.h"
#include "qemu/error-report.h"
#include "sysemu/device_tree.h"
diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt
index f3df206..ab1fdd3 100644
--- a/docs/writing-qmp-commands.txt
+++ b/docs/writing-qmp-commands.txt
@@ -598,7 +598,7 @@
to an TimerAlarmMethod instance.
Notice that the "current" variable is used as "true" only in the first
-interation of the loop. That's because the alarm timer method in use is the
+iteration of the loop. That's because the alarm timer method in use is the
first element of the alarm_timers array. Also notice that QAPI lists are handled
by hand and we return the head of the list.
diff --git a/hmp-commands.hx b/hmp-commands.hx
index e864a6c..3d7dfcc 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -178,8 +178,7 @@
.args_type = "id:B",
.params = "device",
.help = "remove host block device",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = hmp_drive_del,
+ .mhandler.cmd = hmp_drive_del,
},
STEXI
@@ -654,8 +653,7 @@
.args_type = "device:O",
.params = "driver[,prop=value][,...]",
.help = "add device, like -device on the command line",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_device_add,
+ .mhandler.cmd = hmp_device_add,
.command_completion = device_add_completion,
},
@@ -1011,17 +1009,16 @@
.name = "client_migrate_info",
.args_type = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
.params = "protocol hostname port tls-port cert-subject",
- .help = "send migration info to spice/vnc client",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = client_migrate_info,
+ .help = "set migration information for remote display",
+ .mhandler.cmd = hmp_client_migrate_info,
},
STEXI
@item client_migrate_info @var{protocol} @var{hostname} @var{port} @var{tls-port} @var{cert-subject}
@findex client_migrate_info
-Set the spice/vnc connection info for the migration target. The spice/vnc
-server will ask the spice/vnc client to automatically reconnect using the
-new parameters (if specified) once the vm migration finished successfully.
+Set migration information for remote display. This makes the server
+ask the client to automatically reconnect using the new parameters
+once migration finished successfully. Only implemented for SPICE.
ETEXI
{
@@ -1186,8 +1183,7 @@
"<error_status> = error string or 32bit\n\t\t\t"
"<tlb header> = 32bit x 4\n\t\t\t"
"<tlb header prefix> = 32bit x 4",
- .user_print = pcie_aer_inject_error_print,
- .mhandler.cmd_new = hmp_pcie_aer_inject_error,
+ .mhandler.cmd = hmp_pcie_aer_inject_error,
},
STEXI
diff --git a/hmp.c b/hmp.c
index e17852d..514f22f 100644
--- a/hmp.c
+++ b/hmp.c
@@ -22,6 +22,7 @@
#include "qmp-commands.h"
#include "qemu/sockets.h"
#include "monitor/monitor.h"
+#include "monitor/qdev.h"
#include "qapi/opts-visitor.h"
#include "qapi/string-output-visitor.h"
#include "qapi-visit.h"
@@ -1250,6 +1251,23 @@
}
}
+void hmp_client_migrate_info(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+ const char *protocol = qdict_get_str(qdict, "protocol");
+ const char *hostname = qdict_get_str(qdict, "hostname");
+ bool has_port = qdict_haskey(qdict, "port");
+ int port = qdict_get_try_int(qdict, "port", -1);
+ bool has_tls_port = qdict_haskey(qdict, "tls-port");
+ int tls_port = qdict_get_try_int(qdict, "tls-port", -1);
+ const char *cert_subject = qdict_get_try_str(qdict, "cert-subject");
+
+ qmp_client_migrate_info(protocol, hostname,
+ has_port, port, has_tls_port, tls_port,
+ !!cert_subject, cert_subject, &err);
+ hmp_handle_error(mon, &err);
+}
+
void hmp_set_password(Monitor *mon, const QDict *qdict)
{
const char *protocol = qdict_get_str(qdict, "protocol");
@@ -1482,6 +1500,11 @@
}
}
+void hmp_device_add(Monitor *mon, const QDict *qdict)
+{
+ do_device_add(mon, qdict, NULL);
+}
+
void hmp_device_del(Monitor *mon, const QDict *qdict)
{
const char *id = qdict_get_str(qdict, "id");
diff --git a/hmp.h b/hmp.h
index a158e3f..a70ac4f 100644
--- a/hmp.h
+++ b/hmp.h
@@ -67,6 +67,7 @@
void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict);
+void hmp_client_migrate_info(Monitor *mon, const QDict *qdict);
void hmp_set_password(Monitor *mon, const QDict *qdict);
void hmp_expire_password(Monitor *mon, const QDict *qdict);
void hmp_eject(Monitor *mon, const QDict *qdict);
@@ -79,6 +80,7 @@
void hmp_block_job_resume(Monitor *mon, const QDict *qdict);
void hmp_block_job_complete(Monitor *mon, const QDict *qdict);
void hmp_migrate(Monitor *mon, const QDict *qdict);
+void hmp_device_add(Monitor *mon, const QDict *qdict);
void hmp_device_del(Monitor *mon, const QDict *qdict);
void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict);
void hmp_netdev_add(Monitor *mon, const QDict *qdict);
diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c
index 9fe7e8b..f86e7bb 100644
--- a/hw/alpha/dp264.c
+++ b/hw/alpha/dp264.c
@@ -55,7 +55,7 @@
ISABus *isa_bus;
qemu_irq rtc_irq;
long size, i;
- const char *palcode_filename;
+ char *palcode_filename;
uint64_t palcode_entry, palcode_low, palcode_high;
uint64_t kernel_entry, kernel_low, kernel_high;
@@ -101,8 +101,8 @@
/* Load PALcode. Given that this is not "real" cpu palcode,
but one explicitly written for the emulation, we might as
well load it directly from and ELF image. */
- palcode_filename = (bios_name ? bios_name : "palcode-clipper");
- palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, palcode_filename);
+ palcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
+ bios_name ? bios_name : "palcode-clipper");
if (palcode_filename == NULL) {
hw_error("no palcode provided\n");
exit(1);
@@ -114,6 +114,7 @@
hw_error("could not load palcode '%s'\n", palcode_filename);
exit(1);
}
+ g_free(palcode_filename);
/* Start all cpus at the PALcode RESET entry point. */
for (i = 0; i < smp_cpus; ++i) {
diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c
index 7df842d..421162e 100644
--- a/hw/alpha/typhoon.c
+++ b/hw/alpha/typhoon.c
@@ -841,7 +841,7 @@
}
}
- *p_rtc_irq = *qemu_allocate_irqs(typhoon_set_timer_irq, s, 1);
+ *p_rtc_irq = qemu_allocate_irq(typhoon_set_timer_irq, s, 0);
/* Main memory region, 0x00.0000.0000. Real hardware supports 32GB,
but the address space hole reserved at this point is 8TB. */
@@ -918,11 +918,11 @@
/* Init the ISA bus. */
/* ??? Technically there should be a cy82c693ub pci-isa bridge. */
{
- qemu_irq isa_pci_irq, *isa_irqs;
+ qemu_irq *isa_irqs;
*isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io);
- isa_pci_irq = *qemu_allocate_irqs(typhoon_set_isa_irq, s, 1);
- isa_irqs = i8259_init(*isa_bus, isa_pci_irq);
+ isa_irqs = i8259_init(*isa_bus,
+ qemu_allocate_irq(typhoon_set_isa_irq, s, 0));
isa_bus_irqs(*isa_bus, isa_irqs);
}
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 4b09caf..cf346c1 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -5,6 +5,7 @@
obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
obj-$(CONFIG_ACPI) += virt-acpi-build.o
obj-y += netduino2.o
+obj-y += sysbus-fdt.o
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
obj-$(CONFIG_DIGIC) += digic.o
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index fa69503..d036624 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -557,7 +557,7 @@
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
}
-void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
+static void arm_load_kernel_notify(Notifier *notifier, void *data)
{
CPUState *cs;
int kernel_size;
@@ -568,6 +568,11 @@
hwaddr entry, kernel_load_offset;
int big_endian;
static const ARMInsnFixup *primary_loader;
+ ArmLoadKernelNotifier *n = DO_UPCAST(ArmLoadKernelNotifier,
+ notifier, notifier);
+ ARMCPU *cpu = n->cpu;
+ struct arm_boot_info *info =
+ container_of(n, struct arm_boot_info, load_kernel_notifier);
/* CPU objects (unlike devices) are not automatically reset on system
* reset, so we must always register a handler to do so. If we're
@@ -775,3 +780,10 @@
ARM_CPU(cs)->env.boot_info = info;
}
}
+
+void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
+{
+ info->load_kernel_notifier.cpu = cpu;
+ info->load_kernel_notifier.notifier.notify = arm_load_kernel_notify;
+ qemu_add_machine_init_done_notifier(&info->load_kernel_notifier.notifier);
+}
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
index d243159..a659e85 100644
--- a/hw/arm/nseries.c
+++ b/hw/arm/nseries.c
@@ -133,9 +133,8 @@
static void n8x0_gpio_setup(struct n800_s *s)
{
- qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->mpu->mmc, 1);
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO, mmc_cs[0]);
-
+ qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO,
+ qemu_allocate_irq(n800_mmc_cs_cb, s->mpu->mmc, 0));
qemu_irq_lower(qdev_get_gpio_in(s->mpu->gpio, N800_BAT_COVER_GPIO));
}
diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c
index 671e02c..4b0f7f9 100644
--- a/hw/arm/omap_sx1.c
+++ b/hw/arm/omap_sx1.c
@@ -103,7 +103,6 @@
struct omap_mpu_state_s *mpu;
MemoryRegion *address_space = get_system_memory();
MemoryRegion *flash = g_new(MemoryRegion, 1);
- MemoryRegion *flash_1 = g_new(MemoryRegion, 1);
MemoryRegion *cs = g_new(MemoryRegion, 4);
static uint32_t cs0val = 0x00213090;
static uint32_t cs1val = 0x00215070;
@@ -165,6 +164,7 @@
if ((version == 1) &&
(dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
+ MemoryRegion *flash_1 = g_new(MemoryRegion, 1);
memory_region_init_ram(flash_1, NULL, "omap_sx1.flash1-0", flash1_size,
&error_abort);
vmstate_register_ram_global(flash_1);
diff --git a/hw/arm/sysbus-fdt.c b/hw/arm/sysbus-fdt.c
new file mode 100644
index 0000000..3038b94
--- /dev/null
+++ b/hw/arm/sysbus-fdt.c
@@ -0,0 +1,174 @@
+/*
+ * ARM Platform Bus device tree generation helpers
+ *
+ * Copyright (c) 2014 Linaro Limited
+ *
+ * Authors:
+ * Alex Graf <agraf@suse.de>
+ * Eric Auger <eric.auger@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "hw/arm/sysbus-fdt.h"
+#include "qemu/error-report.h"
+#include "sysemu/device_tree.h"
+#include "hw/platform-bus.h"
+#include "sysemu/sysemu.h"
+
+/*
+ * internal struct that contains the information to create dynamic
+ * sysbus device node
+ */
+typedef struct PlatformBusFDTData {
+ void *fdt; /* device tree handle */
+ int irq_start; /* index of the first IRQ usable by platform bus devices */
+ const char *pbus_node_name; /* name of the platform bus node */
+ PlatformBusDevice *pbus;
+} PlatformBusFDTData;
+
+/*
+ * struct used when calling the machine init done notifier
+ * that constructs the fdt nodes of platform bus devices
+ */
+typedef struct PlatformBusFDTNotifierParams {
+ Notifier notifier;
+ ARMPlatformBusFDTParams *fdt_params;
+} PlatformBusFDTNotifierParams;
+
+/* struct that associates a device type name and a node creation function */
+typedef struct NodeCreationPair {
+ const char *typename;
+ int (*add_fdt_node_fn)(SysBusDevice *sbdev, void *opaque);
+} NodeCreationPair;
+
+/* list of supported dynamic sysbus devices */
+static const NodeCreationPair add_fdt_node_functions[] = {
+ {"", NULL}, /* last element */
+};
+
+/**
+ * add_fdt_node - add the device tree node of a dynamic sysbus device
+ *
+ * @sbdev: handle to the sysbus device
+ * @opaque: handle to the PlatformBusFDTData
+ *
+ * Checks the sysbus type belongs to the list of device types that
+ * are dynamically instantiable and if so call the node creation
+ * function.
+ */
+static int add_fdt_node(SysBusDevice *sbdev, void *opaque)
+{
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(add_fdt_node_functions); i++) {
+ if (!strcmp(object_get_typename(OBJECT(sbdev)),
+ add_fdt_node_functions[i].typename)) {
+ ret = add_fdt_node_functions[i].add_fdt_node_fn(sbdev, opaque);
+ assert(!ret);
+ return 0;
+ }
+ }
+ error_report("Device %s can not be dynamically instantiated",
+ qdev_fw_name(DEVICE(sbdev)));
+ exit(1);
+}
+
+/**
+ * add_all_platform_bus_fdt_nodes - create all the platform bus nodes
+ *
+ * builds the parent platform bus node and all the nodes of dynamic
+ * sysbus devices attached to it.
+ */
+static void add_all_platform_bus_fdt_nodes(ARMPlatformBusFDTParams *fdt_params)
+{
+ const char platcomp[] = "qemu,platform\0simple-bus";
+ PlatformBusDevice *pbus;
+ DeviceState *dev;
+ gchar *node;
+ uint64_t addr, size;
+ int irq_start, dtb_size;
+ struct arm_boot_info *info = fdt_params->binfo;
+ const ARMPlatformBusSystemParams *params = fdt_params->system_params;
+ const char *intc = fdt_params->intc;
+ void *fdt = info->get_dtb(info, &dtb_size);
+
+ /*
+ * If the user provided a dtb, we assume the dynamic sysbus nodes
+ * already are integrated there. This corresponds to a use case where
+ * the dynamic sysbus nodes are complex and their generation is not yet
+ * supported. In that case the user can take charge of the guest dt
+ * while qemu takes charge of the qom stuff.
+ */
+ if (info->dtb_filename) {
+ return;
+ }
+
+ assert(fdt);
+
+ node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base);
+ addr = params->platform_bus_base;
+ size = params->platform_bus_size;
+ irq_start = params->platform_bus_first_irq;
+
+ /* Create a /platform node that we can put all devices into */
+ qemu_fdt_add_subnode(fdt, node);
+ qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
+
+ /* Our platform bus region is less than 32bits, so 1 cell is enough for
+ * address and size
+ */
+ qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
+ qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
+ qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
+
+ qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", intc);
+
+ dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE);
+ pbus = PLATFORM_BUS_DEVICE(dev);
+
+ /* We can only create dt nodes for dynamic devices when they're ready */
+ assert(pbus->done_gathering);
+
+ PlatformBusFDTData data = {
+ .fdt = fdt,
+ .irq_start = irq_start,
+ .pbus_node_name = node,
+ .pbus = pbus,
+ };
+
+ /* Loop through all dynamic sysbus devices and create their node */
+ foreach_dynamic_sysbus_device(add_fdt_node, &data);
+
+ g_free(node);
+}
+
+static void platform_bus_fdt_notify(Notifier *notifier, void *data)
+{
+ PlatformBusFDTNotifierParams *p = DO_UPCAST(PlatformBusFDTNotifierParams,
+ notifier, notifier);
+
+ add_all_platform_bus_fdt_nodes(p->fdt_params);
+ g_free(p->fdt_params);
+ g_free(p);
+}
+
+void arm_register_platform_bus_fdt_creator(ARMPlatformBusFDTParams *fdt_params)
+{
+ PlatformBusFDTNotifierParams *p = g_new(PlatformBusFDTNotifierParams, 1);
+
+ p->fdt_params = fdt_params;
+ p->notifier.notify = platform_bus_fdt_notify;
+ qemu_add_machine_init_done_notifier(&p->notifier);
+}
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 05db8cb..0a75cc8 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -45,9 +45,11 @@
#include "qemu/error-report.h"
#include "hw/pci-host/gpex.h"
#include "hw/arm/virt-acpi-build.h"
+#include "hw/arm/sysbus-fdt.h"
+#include "hw/platform-bus.h"
/* Number of external interrupt lines to configure the GIC with */
-#define NUM_IRQS 128
+#define NUM_IRQS 256
#define GIC_FDT_IRQ_TYPE_SPI 0
#define GIC_FDT_IRQ_TYPE_PPI 1
@@ -60,6 +62,10 @@
#define GIC_FDT_IRQ_PPI_CPU_START 8
#define GIC_FDT_IRQ_PPI_CPU_WIDTH 8
+#define PLATFORM_BUS_NUM_IRQS 64
+
+static ARMPlatformBusSystemParams platform_bus_params;
+
typedef struct VirtBoardInfo {
struct arm_boot_info bootinfo;
const char *cpu_model;
@@ -69,6 +75,8 @@
void *fdt;
int fdt_size;
uint32_t clock_phandle;
+ uint32_t gic_phandle;
+ uint32_t v2m_phandle;
} VirtBoardInfo;
typedef struct {
@@ -103,20 +111,22 @@
*/
static const MemMapEntry a15memmap[] = {
/* Space up to 0x8000000 is reserved for a boot ROM */
- [VIRT_FLASH] = { 0, 0x08000000 },
- [VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 },
+ [VIRT_FLASH] = { 0, 0x08000000 },
+ [VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 },
/* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
- [VIRT_GIC_DIST] = { 0x08000000, 0x00010000 },
- [VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
- [VIRT_UART] = { 0x09000000, 0x00001000 },
- [VIRT_RTC] = { 0x09010000, 0x00001000 },
- [VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
- [VIRT_MMIO] = { 0x0a000000, 0x00000200 },
+ [VIRT_GIC_DIST] = { 0x08000000, 0x00010000 },
+ [VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
+ [VIRT_GIC_V2M] = { 0x08020000, 0x00001000 },
+ [VIRT_UART] = { 0x09000000, 0x00001000 },
+ [VIRT_RTC] = { 0x09010000, 0x00001000 },
+ [VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
+ [VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
- [VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 },
- [VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
- [VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 },
- [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
+ [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
+ [VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 },
+ [VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
+ [VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 },
+ [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
};
static const int a15irqmap[] = {
@@ -124,6 +134,8 @@
[VIRT_RTC] = 2,
[VIRT_PCIE] = 3, /* ... to 6 */
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
+ [VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */
+ [VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
};
static VirtBoardInfo machines[] = {
@@ -299,12 +311,23 @@
}
}
-static uint32_t fdt_add_gic_node(const VirtBoardInfo *vbi)
+static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi)
{
- uint32_t gic_phandle;
+ vbi->v2m_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
+ qemu_fdt_add_subnode(vbi->fdt, "/intc/v2m");
+ qemu_fdt_setprop_string(vbi->fdt, "/intc/v2m", "compatible",
+ "arm,gic-v2m-frame");
+ qemu_fdt_setprop(vbi->fdt, "/intc/v2m", "msi-controller", NULL, 0);
+ qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/v2m", "reg",
+ 2, vbi->memmap[VIRT_GIC_V2M].base,
+ 2, vbi->memmap[VIRT_GIC_V2M].size);
+ qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->v2m_phandle);
+}
- gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
- qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", gic_phandle);
+static void fdt_add_gic_node(VirtBoardInfo *vbi)
+{
+ vbi->gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
+ qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", vbi->gic_phandle);
qemu_fdt_add_subnode(vbi->fdt, "/intc");
/* 'cortex-a15-gic' means 'GIC v2' */
@@ -317,12 +340,32 @@
2, vbi->memmap[VIRT_GIC_DIST].size,
2, vbi->memmap[VIRT_GIC_CPU].base,
2, vbi->memmap[VIRT_GIC_CPU].size);
- qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle);
-
- return gic_phandle;
+ qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#address-cells", 0x2);
+ qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#size-cells", 0x2);
+ qemu_fdt_setprop(vbi->fdt, "/intc", "ranges", NULL, 0);
+ qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", vbi->gic_phandle);
}
-static uint32_t create_gic(const VirtBoardInfo *vbi, qemu_irq *pic)
+static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic)
+{
+ int i;
+ int irq = vbi->irqmap[VIRT_GIC_V2M];
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "arm-gicv2m");
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vbi->memmap[VIRT_GIC_V2M].base);
+ qdev_prop_set_uint32(dev, "base-spi", irq);
+ qdev_prop_set_uint32(dev, "num-spi", NUM_GICV2M_SPIS);
+ qdev_init_nofail(dev);
+
+ for (i = 0; i < NUM_GICV2M_SPIS; i++) {
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
+ }
+
+ fdt_add_v2m_gic_node(vbi);
+}
+
+static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
{
/* We create a standalone GIC v2 */
DeviceState *gicdev;
@@ -371,7 +414,9 @@
pic[i] = qdev_get_gpio_in(gicdev, i);
}
- return fdt_add_gic_node(vbi);
+ fdt_add_gic_node(vbi);
+
+ create_v2m(vbi, pic);
}
static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
@@ -587,7 +632,7 @@
int first_irq, const char *nodename)
{
int devfn, pin;
- uint32_t full_irq_map[4 * 4 * 8] = { 0 };
+ uint32_t full_irq_map[4 * 4 * 10] = { 0 };
uint32_t *irq_map = full_irq_map;
for (devfn = 0; devfn <= 0x18; devfn += 0x8) {
@@ -600,13 +645,13 @@
uint32_t map[] = {
devfn << 8, 0, 0, /* devfn */
pin + 1, /* PCI pin */
- gic_phandle, irq_type, irq_nr, irq_level }; /* GIC irq */
+ gic_phandle, 0, 0, irq_type, irq_nr, irq_level }; /* GIC irq */
/* Convert map to big endian */
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < 10; i++) {
irq_map[i] = cpu_to_be32(map[i]);
}
- irq_map += 8;
+ irq_map += 10;
}
}
@@ -618,8 +663,7 @@
0x7 /* PCI irq */);
}
-static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
- uint32_t gic_phandle)
+static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic)
{
hwaddr base_mmio = vbi->memmap[VIRT_PCIE_MMIO].base;
hwaddr size_mmio = vbi->memmap[VIRT_PCIE_MMIO].size;
@@ -676,6 +720,8 @@
qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0,
nr_pcie_buses - 1);
+ qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", vbi->v2m_phandle);
+
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
2, base_ecam, 2, size_ecam);
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
@@ -685,11 +731,52 @@
2, base_mmio, 2, size_mmio);
qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1);
- create_pcie_irq_map(vbi, gic_phandle, irq, nodename);
+ create_pcie_irq_map(vbi, vbi->gic_phandle, irq, nodename);
g_free(nodename);
}
+static void create_platform_bus(VirtBoardInfo *vbi, qemu_irq *pic)
+{
+ DeviceState *dev;
+ SysBusDevice *s;
+ int i;
+ ARMPlatformBusFDTParams *fdt_params = g_new(ARMPlatformBusFDTParams, 1);
+ MemoryRegion *sysmem = get_system_memory();
+
+ platform_bus_params.platform_bus_base = vbi->memmap[VIRT_PLATFORM_BUS].base;
+ platform_bus_params.platform_bus_size = vbi->memmap[VIRT_PLATFORM_BUS].size;
+ platform_bus_params.platform_bus_first_irq = vbi->irqmap[VIRT_PLATFORM_BUS];
+ platform_bus_params.platform_bus_num_irqs = PLATFORM_BUS_NUM_IRQS;
+
+ fdt_params->system_params = &platform_bus_params;
+ fdt_params->binfo = &vbi->bootinfo;
+ fdt_params->intc = "/intc";
+ /*
+ * register a machine init done notifier that creates the device tree
+ * nodes of the platform bus and its children dynamic sysbus devices
+ */
+ arm_register_platform_bus_fdt_creator(fdt_params);
+
+ dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE);
+ dev->id = TYPE_PLATFORM_BUS_DEVICE;
+ qdev_prop_set_uint32(dev, "num_irqs",
+ platform_bus_params.platform_bus_num_irqs);
+ qdev_prop_set_uint32(dev, "mmio_size",
+ platform_bus_params.platform_bus_size);
+ qdev_init_nofail(dev);
+ s = SYS_BUS_DEVICE(dev);
+
+ for (i = 0; i < platform_bus_params.platform_bus_num_irqs; i++) {
+ int irqn = platform_bus_params.platform_bus_first_irq + i;
+ sysbus_connect_irq(s, i, pic[irqn]);
+ }
+
+ memory_region_add_subregion(sysmem,
+ platform_bus_params.platform_bus_base,
+ sysbus_mmio_get_region(s, 0));
+}
+
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
{
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
@@ -717,7 +804,6 @@
VirtBoardInfo *vbi;
VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
VirtGuestInfo *guest_info = &guest_info_state->info;
- uint32_t gic_phandle;
char **cpustr;
if (!cpu_model) {
@@ -794,13 +880,13 @@
create_flash(vbi);
- gic_phandle = create_gic(vbi, pic);
+ create_gic(vbi, pic);
create_uart(vbi, pic);
create_rtc(vbi, pic);
- create_pcie(vbi, pic, gic_phandle);
+ create_pcie(vbi, pic);
/* Create mmio transports, so the user can create virtio backends
* (which will be automatically plugged in to the transports). If
@@ -828,6 +914,14 @@
vbi->bootinfo.get_dtb = machvirt_dtb;
vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
+
+ /*
+ * arm_load_kernel machine init done notifier registration must
+ * happen before the platform_bus_create call. In this latter,
+ * another notifier is registered which adds platform bus nodes.
+ * Notifiers are executed in registration reverse order.
+ */
+ create_platform_bus(vbi, pic);
}
static bool virt_get_secure(Object *obj, Error **errp)
@@ -866,6 +960,7 @@
mc->desc = "ARM Virtual Machine",
mc->init = machvirt_init;
mc->max_cpus = 8;
+ mc->has_dynamic_sysbus = true;
}
static const TypeInfo machvirt_info = {
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
index 66b7ade..f5f3f3e 100644
--- a/hw/display/tc6393xb.c
+++ b/hw/display/tc6393xb.c
@@ -571,7 +571,7 @@
s->irq = irq;
s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS);
- s->l3v = *qemu_allocate_irqs(tc6393xb_l3v, s, 1);
+ s->l3v = qemu_allocate_irq(tc6393xb_l3v, s, 0);
s->blanked = 1;
s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
index bd03e99..4ba730b 100644
--- a/hw/gpio/pl061.c
+++ b/hw/gpio/pl061.c
@@ -173,7 +173,7 @@
case 0x414: /* Raw interrupt status */
return s->istate;
case 0x418: /* Masked interrupt status */
- return s->istate | s->im;
+ return s->istate & s->im;
case 0x420: /* Alternate function select */
return s->afsel;
case 0x500: /* 2mA drive */
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 2c7399b..15fd4c5 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -596,6 +596,7 @@
}
}
aml_append(parent_scope, method);
+ qobject_decref(bsel);
}
static void
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 1eb1db0..973ee6b 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1006,7 +1006,6 @@
}
qdev_set_parent_bus(DEVICE(cpu), qdev_get_child_bus(icc_bridge, "icc"));
- object_unref(OBJECT(cpu));
object_property_set_int(OBJECT(cpu), apic_id, "apic-id", &local_err);
object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
@@ -1025,7 +1024,9 @@
void pc_hot_add_cpu(const int64_t id, Error **errp)
{
DeviceState *icc_bridge;
+ X86CPU *cpu;
int64_t apic_id = x86_cpu_apic_id_from_index(id);
+ Error *local_err = NULL;
if (id < 0) {
error_setg(errp, "Invalid CPU id: %" PRIi64, id);
@@ -1053,7 +1054,12 @@
icc_bridge = DEVICE(object_resolve_path_type("icc-bridge",
TYPE_ICC_BRIDGE, NULL));
- pc_new_cpu(current_cpu_model, apic_id, icc_bridge, errp);
+ cpu = pc_new_cpu(current_cpu_model, apic_id, icc_bridge, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ object_unref(OBJECT(cpu));
}
void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
@@ -1087,6 +1093,7 @@
error_report_err(error);
exit(1);
}
+ object_unref(OBJECT(cpu));
}
/* map APIC MMIO area if CPU has APIC */
@@ -1345,9 +1352,9 @@
return fw_cfg;
}
-qemu_irq *pc_allocate_cpu_irq(void)
+qemu_irq pc_allocate_cpu_irq(void)
{
- return qemu_allocate_irqs(pic_irq_request, NULL, 1);
+ return qemu_allocate_irq(pic_irq_request, NULL, 0);
}
DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus)
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 6e7fa42..768b09b 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -86,10 +86,9 @@
ISABus *isa_bus;
PCII440FXState *i440fx_state;
int piix3_devfn = -1;
- qemu_irq *cpu_irq;
qemu_irq *gsi;
qemu_irq *i8259;
- qemu_irq *smi_irq;
+ qemu_irq smi_irq;
GSIState *gsi_state;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
BusState *idebus[MAX_IDE_BUS];
@@ -220,13 +219,13 @@
} else if (xen_enabled()) {
i8259 = xen_interrupt_controller_init();
} else {
- cpu_irq = pc_allocate_cpu_irq();
- i8259 = i8259_init(isa_bus, cpu_irq[0]);
+ i8259 = i8259_init(isa_bus, pc_allocate_cpu_irq());
}
for (i = 0; i < ISA_NUM_IRQS; i++) {
gsi_state->i8259_irq[i] = i8259[i];
}
+ g_free(i8259);
if (pci_enabled) {
ioapic_init_gsi(gsi_state, "i440fx");
}
@@ -284,10 +283,10 @@
DeviceState *piix4_pm;
I2CBus *smbus;
- smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
+ smi_irq = qemu_allocate_irq(pc_acpi_smi_interrupt, first_cpu, 0);
/* TODO: Populate SPD eeprom data. */
smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
- gsi[9], *smi_irq,
+ gsi[9], smi_irq,
kvm_enabled(), fw_cfg, &piix4_pm);
smbus_eeprom_init(smbus, 8, NULL, 0);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 66220b3..110dfb7 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -79,7 +79,6 @@
GSIState *gsi_state;
ISABus *isa_bus;
int pci_enabled = 1;
- qemu_irq *cpu_irq;
qemu_irq *gsi;
qemu_irq *i8259;
int i;
@@ -230,8 +229,7 @@
} else if (xen_enabled()) {
i8259 = xen_interrupt_controller_init();
} else {
- cpu_irq = pc_allocate_cpu_irq();
- i8259 = i8259_init(isa_bus, cpu_irq[0]);
+ i8259 = i8259_init(isa_bus, pc_allocate_cpu_irq());
}
for (i = 0; i < ISA_NUM_IRQS; i++) {
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 1b3d1c1..4b5e32d 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -452,8 +452,6 @@
void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d)
{
- qemu_irq *irq;
-
if (bus->dma == &bm->dma) {
return;
}
@@ -461,8 +459,7 @@
bm->dma.ops = &bmdma_ops;
bus->dma = &bm->dma;
bm->irq = bus->irq;
- irq = qemu_allocate_irqs(bmdma_irq, bm, 1);
- bus->irq = *irq;
+ bus->irq = qemu_allocate_irq(bmdma_irq, bm, 0);
bm->pci_dev = d;
}
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 843864a..092d8a8 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -11,6 +11,7 @@
common-obj-$(CONFIG_IOAPIC) += ioapic_common.o
common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o
common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
+common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
common-obj-$(CONFIG_OPENPIC) += openpic.o
obj-$(CONFIG_APIC) += apic.o apic_common.o
diff --git a/hw/intc/apic.c b/hw/intc/apic.c
index 0f97b47..77b639c 100644
--- a/hw/intc/apic.c
+++ b/hw/intc/apic.c
@@ -370,13 +370,14 @@
static void apic_update_irq(APICCommonState *s)
{
CPUState *cpu;
+ DeviceState *dev = (DeviceState *)s;
cpu = CPU(s->cpu);
if (!qemu_cpu_is_self(cpu)) {
cpu_interrupt(cpu, CPU_INTERRUPT_POLL);
} else if (apic_irq_pending(s) > 0) {
cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
- } else if (!apic_accept_pic_intr(&s->busdev.qdev) || !pic_get_output(isa_pic)) {
+ } else if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) {
cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
}
}
@@ -549,10 +550,12 @@
static bool apic_check_pic(APICCommonState *s)
{
- if (!apic_accept_pic_intr(&s->busdev.qdev) || !pic_get_output(isa_pic)) {
+ DeviceState *dev = (DeviceState *)s;
+
+ if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) {
return false;
}
- apic_deliver_pic_intr(&s->busdev.qdev, 1);
+ apic_deliver_pic_intr(dev, 1);
return true;
}
diff --git a/hw/intc/arm_gicv2m.c b/hw/intc/arm_gicv2m.c
new file mode 100644
index 0000000..43d1976
--- /dev/null
+++ b/hw/intc/arm_gicv2m.c
@@ -0,0 +1,192 @@
+/*
+ * GICv2m extension for MSI/MSI-x support with a GICv2-based system
+ *
+ * Copyright (C) 2015 Linaro, All rights reserved.
+ *
+ * Author: Christoffer Dall <christoffer.dall@linaro.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This file implements an emulated GICv2m widget as described in the ARM
+ * Server Base System Architecture (SBSA) specification Version 2.2
+ * (ARM-DEN-0029 v2.2) pages 35-39 without any optional implementation defined
+ * identification registers and with a single non-secure MSI register frame.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/pci/msi.h"
+
+#define TYPE_ARM_GICV2M "arm-gicv2m"
+#define ARM_GICV2M(obj) OBJECT_CHECK(ARMGICv2mState, (obj), TYPE_ARM_GICV2M)
+
+#define GICV2M_NUM_SPI_MAX 128
+
+#define V2M_MSI_TYPER 0x008
+#define V2M_MSI_SETSPI_NS 0x040
+#define V2M_MSI_IIDR 0xFCC
+#define V2M_IIDR0 0xFD0
+#define V2M_IIDR11 0xFFC
+
+#define PRODUCT_ID_QEMU 0x51 /* ASCII code Q */
+
+typedef struct ARMGICv2mState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem;
+ qemu_irq spi[GICV2M_NUM_SPI_MAX];
+
+ uint32_t base_spi;
+ uint32_t num_spi;
+} ARMGICv2mState;
+
+static void gicv2m_set_irq(void *opaque, int irq)
+{
+ ARMGICv2mState *s = (ARMGICv2mState *)opaque;
+
+ qemu_irq_pulse(s->spi[irq]);
+}
+
+static uint64_t gicv2m_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ ARMGICv2mState *s = (ARMGICv2mState *)opaque;
+ uint32_t val;
+
+ if (size != 4) {
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv2m_read: bad size %u\n", size);
+ return 0;
+ }
+
+ switch (offset) {
+ case V2M_MSI_TYPER:
+ val = (s->base_spi + 32) << 16;
+ val |= s->num_spi;
+ return val;
+ case V2M_MSI_IIDR:
+ /* We don't have any valid implementor so we leave that field as zero
+ * and we return 0 in the arch revision as per the spec.
+ */
+ return (PRODUCT_ID_QEMU << 20);
+ case V2M_IIDR0 ... V2M_IIDR11:
+ /* We do not implement any optional identification registers and the
+ * mandatory MSI_PIDR2 register reads as 0x0, so we capture all
+ * implementation defined registers here.
+ */
+ return 0;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "gicv2m_read: Bad offset %x\n", (int)offset);
+ return 0;
+ }
+}
+
+static void gicv2m_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ ARMGICv2mState *s = (ARMGICv2mState *)opaque;
+
+ if (size != 2 && size != 4) {
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv2m_write: bad size %u\n", size);
+ return;
+ }
+
+ switch (offset) {
+ case V2M_MSI_SETSPI_NS: {
+ int spi;
+
+ spi = (value & 0x3ff) - (s->base_spi + 32);
+ if (spi >= 0 && spi < s->num_spi) {
+ gicv2m_set_irq(s, spi);
+ }
+ return;
+ }
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "gicv2m_write: Bad offset %x\n", (int)offset);
+ }
+}
+
+static const MemoryRegionOps gicv2m_ops = {
+ .read = gicv2m_read,
+ .write = gicv2m_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void gicv2m_realize(DeviceState *dev, Error **errp)
+{
+ ARMGICv2mState *s = ARM_GICV2M(dev);
+ int i;
+
+ if (s->num_spi > GICV2M_NUM_SPI_MAX) {
+ error_setg(errp,
+ "requested %u SPIs exceeds GICv2m frame maximum %d",
+ s->num_spi, GICV2M_NUM_SPI_MAX);
+ return;
+ }
+
+ if (s->base_spi + 32 > 1020 - s->num_spi) {
+ error_setg(errp,
+ "requested base SPI %u+%u exceeds max. number 1020",
+ s->base_spi + 32, s->num_spi);
+ return;
+ }
+
+ for (i = 0; i < s->num_spi; i++) {
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->spi[i]);
+ }
+
+ msi_supported = true;
+ kvm_gsi_direct_mapping = true;
+ kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
+}
+
+static void gicv2m_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ ARMGICv2mState *s = ARM_GICV2M(obj);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &gicv2m_ops, s,
+ "gicv2m", 0x1000);
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static Property gicv2m_properties[] = {
+ DEFINE_PROP_UINT32("base-spi", ARMGICv2mState, base_spi, 0),
+ DEFINE_PROP_UINT32("num-spi", ARMGICv2mState, num_spi, 64),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void gicv2m_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->props = gicv2m_properties;
+ dc->realize = gicv2m_realize;
+}
+
+static const TypeInfo gicv2m_info = {
+ .name = TYPE_ARM_GICV2M,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(ARMGICv2mState),
+ .instance_init = gicv2m_init,
+ .class_init = gicv2m_class_init,
+};
+
+static void gicv2m_register_types(void)
+{
+ type_register_static(&gicv2m_info);
+}
+
+type_init(gicv2m_register_types)
diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c
index 0590d5d..b2a4950 100644
--- a/hw/intc/exynos4210_gic.c
+++ b/hw/intc/exynos4210_gic.c
@@ -213,9 +213,6 @@
uint32_t grp, bit, irq_id, n;
for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) {
- s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
- s->ext_combiner_irq[n]);
-
irq_id = 0;
if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4) ||
n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4)) {
@@ -230,8 +227,10 @@
if (irq_id) {
s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
s->ext_gic_irq[irq_id-32]);
+ } else {
+ s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
+ s->ext_combiner_irq[n]);
}
-
}
for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) {
/* these IDs are passed to Internal Combiner and External GIC */
diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c
index 9da9dfc..fcf97d8 100644
--- a/hw/isa/i82378.c
+++ b/hw/isa/i82378.c
@@ -65,7 +65,6 @@
uint8_t *pci_conf;
ISABus *isabus;
ISADevice *isa;
- qemu_irq *out0_irq;
pci_conf = pci->config;
pci_set_word(pci_conf + PCI_COMMAND,
@@ -88,11 +87,9 @@
All devices accept byte access only, except timer
*/
- /* Workaround the fact that i8259 is not qdev'ified... */
- out0_irq = qemu_allocate_irqs(i82378_request_out0_irq, s, 1);
-
/* 2 82C59 (irq) */
- s->i8259 = i8259_init(isabus, *out0_irq);
+ s->i8259 = i8259_init(isabus,
+ qemu_allocate_irq(i82378_request_out0_irq, s, 0));
isa_bus_irqs(isabus, s->i8259);
/* 1 82C54 (pit) */
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index dba7585..144b210 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -360,11 +360,8 @@
void ich9_lpc_pm_init(PCIDevice *lpc_pci)
{
ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
- qemu_irq *sci_irq;
- sci_irq = qemu_allocate_irqs(ich9_set_sci, lpc, 1);
- ich9_pm_init(lpc_pci, &lpc->pm, sci_irq[0]);
-
+ ich9_pm_init(lpc_pci, &lpc->pm, qemu_allocate_irq(ich9_set_sci, lpc, 0));
ich9_lpc_reset(&lpc->d.qdev);
}
diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c
index 14d0efc..70f48d3 100644
--- a/hw/lm32/lm32_boards.c
+++ b/hw/lm32/lm32_boards.c
@@ -78,7 +78,7 @@
DriveInfo *dinfo;
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
- qemu_irq *cpu_irq, irq[32];
+ qemu_irq irq[32];
ResetInfo *reset_info;
int i;
@@ -123,8 +123,7 @@
1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
/* create irq lines */
- cpu_irq = qemu_allocate_irqs(cpu_irq_handler, cpu, 1);
- env->pic_state = lm32_pic_init(*cpu_irq);
+ env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0));
for (i = 0; i < 32; i++) {
irq[i] = qdev_get_gpio_in(env->pic_state, i);
}
@@ -173,7 +172,7 @@
DriveInfo *dinfo;
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
- qemu_irq *cpu_irq, irq[32];
+ qemu_irq irq[32];
HWSetup *hw;
ResetInfo *reset_info;
int i;
@@ -225,8 +224,7 @@
1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
/* create irq lines */
- cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1);
- env->pic_state = lm32_pic_init(*cpu_irq);
+ env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, env, 0));
for (i = 0; i < 32; i++) {
irq[i] = qdev_get_gpio_in(env->pic_state, i);
}
diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c
index e0cec7d..e755f5b 100644
--- a/hw/lm32/milkymist.c
+++ b/hw/lm32/milkymist.c
@@ -86,7 +86,7 @@
DriveInfo *dinfo;
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *phys_sdram = g_new(MemoryRegion, 1);
- qemu_irq irq[32], *cpu_irq;
+ qemu_irq irq[32];
int i;
char *bios_filename;
ResetInfo *reset_info;
@@ -130,8 +130,7 @@
2, 0x00, 0x89, 0x00, 0x1d, 1);
/* create irq lines */
- cpu_irq = qemu_allocate_irqs(cpu_irq_handler, cpu, 1);
- env->pic_state = lm32_pic_init(*cpu_irq);
+ env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0));
for (i = 0; i < 32; i++) {
irq[i] = qdev_get_gpio_in(env->pic_state, i);
}
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index dafe914..494a346 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -155,7 +155,7 @@
#define GEM_NWCFG_BCAST_REJ 0x00000020 /* Reject broadcast packets */
#define GEM_NWCFG_PROMISC 0x00000010 /* Accept all packets */
-#define GEM_DMACFG_RBUFSZ_M 0x007F0000 /* DMA RX Buffer Size mask */
+#define GEM_DMACFG_RBUFSZ_M 0x00FF0000 /* DMA RX Buffer Size mask */
#define GEM_DMACFG_RBUFSZ_S 16 /* DMA RX Buffer Size shift */
#define GEM_DMACFG_RBUFSZ_MUL 64 /* DMA RX Buffer Size multiplier */
#define GEM_DMACFG_TXCSUM_OFFL 0x00000800 /* Transmit checksum offload */
diff --git a/hw/pci/msi.c b/hw/pci/msi.c
index c111dba..f9c0484 100644
--- a/hw/pci/msi.c
+++ b/hw/pci/msi.c
@@ -21,10 +21,6 @@
#include "hw/pci/msi.h"
#include "qemu/range.h"
-/* Eventually those constants should go to Linux pci_regs.h */
-#define PCI_MSI_PENDING_32 0x10
-#define PCI_MSI_PENDING_64 0x14
-
/* PCI_MSI_ADDRESS_LO */
#define PCI_MSI_ADDRESS_LO_MASK (~0x3)
diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c
index 5e564c3..f8f237e 100644
--- a/hw/pci/pci-stub.c
+++ b/hw/pci/pci-stub.c
@@ -29,19 +29,7 @@
return NULL;
}
-static void pci_error_message(Monitor *mon)
+void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict)
{
monitor_printf(mon, "PCI devices not supported\n");
}
-
-int hmp_pcie_aer_inject_error(Monitor *mon,
- const QDict *qdict, QObject **ret_data)
-{
- pci_error_message(mon);
- return -ENOSYS;
-}
-
-void pcie_aer_inject_error_print(Monitor *mon, const QObject *data)
-{
- pci_error_message(mon);
-}
diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c
index b48c09c..c8dea8e 100644
--- a/hw/pci/pcie_aer.c
+++ b/hw/pci/pcie_aer.c
@@ -815,21 +815,6 @@
}
};
-void pcie_aer_inject_error_print(Monitor *mon, const QObject *data)
-{
- QDict *qdict;
- int devfn;
- assert(qobject_type(data) == QTYPE_QDICT);
- qdict = qobject_to_qdict(data);
-
- devfn = (int)qdict_get_int(qdict, "devfn");
- monitor_printf(mon, "OK id: %s root bus: %s, bus: %x devfn: %x.%x\n",
- qdict_get_str(qdict, "id"),
- qdict_get_str(qdict, "root_bus"),
- (int) qdict_get_int(qdict, "bus"),
- PCI_SLOT(devfn), PCI_FUNC(devfn));
-}
-
typedef struct PCIEAERErrorName {
const char *name;
uint32_t val;
@@ -962,8 +947,8 @@
return -EINVAL;
}
-int hmp_pcie_aer_inject_error(Monitor *mon,
- const QDict *qdict, QObject **ret_data)
+static int do_pcie_aer_inject_error(Monitor *mon,
+ const QDict *qdict, QObject **ret_data)
{
const char *id = qdict_get_str(qdict, "id");
const char *error_name;
@@ -1035,3 +1020,23 @@
return 0;
}
+
+void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict)
+{
+ QObject *data;
+ int devfn;
+
+ if (do_pcie_aer_inject_error(mon, qdict, &data) < 0) {
+ return;
+ }
+
+ assert(qobject_type(data) == QTYPE_QDICT);
+ qdict = qobject_to_qdict(data);
+
+ devfn = (int)qdict_get_int(qdict, "devfn");
+ monitor_printf(mon, "OK id: %s root bus: %s, bus: %x devfn: %x.%x\n",
+ qdict_get_str(qdict, "id"),
+ qdict_get_str(qdict, "root_bus"),
+ (int) qdict_get_int(qdict, "bus"),
+ PCI_SLOT(devfn), PCI_FUNC(devfn));
+}
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index c10e1b5..d300846 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -1030,6 +1030,7 @@
exit(1);
}
}
+ g_free(filename);
/* Reserve space for dtb */
dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 7f52662..998ee2d 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -528,7 +528,6 @@
PCIDevice *pci;
ISABus *isa_bus;
ISADevice *isa;
- qemu_irq *cpu_exit_irq;
int ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
@@ -625,11 +624,11 @@
/* PCI -> ISA bridge */
pci = pci_create_simple(pci_bus, PCI_DEVFN(1, 0), "i82378");
- cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
cpu = POWERPC_CPU(first_cpu);
qdev_connect_gpio_out(&pci->qdev, 0,
cpu->env.irq_inputs[PPC6xx_INPUT_INT]);
- qdev_connect_gpio_out(&pci->qdev, 1, *cpu_exit_irq);
+ qdev_connect_gpio_out(&pci->qdev, 1,
+ qemu_allocate_irq(cpu_request_exit, NULL, 0));
sysbus_connect_irq(&pcihost->busdev, 0, qdev_get_gpio_in(&pci->qdev, 9));
sysbus_connect_irq(&pcihost->busdev, 1, qdev_get_gpio_in(&pci->qdev, 11));
sysbus_connect_irq(&pcihost->busdev, 2, qdev_get_gpio_in(&pci->qdev, 9));
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index a69bf2d..8a3599c 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -897,7 +897,6 @@
espdma_irq, ledma_irq;
qemu_irq esp_reset, dma_enable;
qemu_irq fdc_tc;
- qemu_irq *cpu_halt;
unsigned long kernel_size;
DriveInfo *fd[MAX_FD];
FWCfgState *fw_cfg;
@@ -1024,9 +1023,8 @@
escc_init(hwdef->serial_base, slavio_irq[15], slavio_irq[15],
serial_hds[0], serial_hds[1], ESCC_CLOCK, 1);
- cpu_halt = qemu_allocate_irqs(cpu_halt_signal, NULL, 1);
if (hwdef->apc_base) {
- apc_init(hwdef->apc_base, cpu_halt[0]);
+ apc_init(hwdef->apc_base, qemu_allocate_irq(cpu_halt_signal, NULL, 0));
}
if (hwdef->fd_base) {
@@ -1036,7 +1034,7 @@
sun4m_fdctrl_init(slavio_irq[22], hwdef->fd_base, fd,
&fdc_tc);
} else {
- fdc_tc = *qemu_allocate_irqs(dummy_fdc_tc, NULL, 1);
+ fdc_tc = qemu_allocate_irq(dummy_fdc_tc, NULL, 0);
}
slavio_misc_init(hwdef->slavio_base, hwdef->aux1_base, hwdef->aux2_base,
diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c
index 1452910..d53f39a 100644
--- a/hw/timer/arm_timer.c
+++ b/hw/timer/arm_timer.c
@@ -280,14 +280,12 @@
{
DeviceState *dev = DEVICE(sbd);
SP804State *s = SP804(dev);
- qemu_irq *qi;
- qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
sysbus_init_irq(sbd, &s->irq);
s->timer[0] = arm_timer_init(s->freq0);
s->timer[1] = arm_timer_init(s->freq1);
- s->timer[0]->irq = qi[0];
- s->timer[1]->irq = qi[1];
+ s->timer[0]->irq = qemu_allocate_irq(sp804_set_irq, s, 0);
+ s->timer[1]->irq = qemu_allocate_irq(sp804_set_irq, s, 1);
memory_region_init_io(&s->iomem, OBJECT(s), &sp804_ops, s,
"sp804", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c
index cc9a21a..703e29d 100644
--- a/hw/unicore32/puv3.c
+++ b/hw/unicore32/puv3.c
@@ -40,15 +40,15 @@
static void puv3_soc_init(CPUUniCore32State *env)
{
- qemu_irq *cpu_intc, irqs[PUV3_IRQS_NR];
+ qemu_irq cpu_intc, irqs[PUV3_IRQS_NR];
DeviceState *dev;
MemoryRegion *i8042 = g_new(MemoryRegion, 1);
int i;
/* Initialize interrupt controller */
- cpu_intc = qemu_allocate_irqs(puv3_intc_cpu_handler,
- uc32_env_get_cpu(env), 1);
- dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, *cpu_intc);
+ cpu_intc = qemu_allocate_irq(puv3_intc_cpu_handler,
+ uc32_env_get_cpu(env), 0);
+ dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, cpu_intc);
for (i = 0; i < PUV3_IRQS_NR; i++) {
irqs[i] = qdev_get_gpio_in(dev, i);
}
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index d095c08..9afcda8 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -234,11 +234,12 @@
int index = 0;
XenPTRegGroup *reg_grp_entry = NULL;
int rc = 0;
- uint32_t read_val = 0;
+ uint32_t read_val = 0, wb_mask;
int emul_len = 0;
XenPTReg *reg_entry = NULL;
uint32_t find_addr = addr;
XenPTRegInfo *reg = NULL;
+ bool wp_flag = false;
if (xen_pt_pci_config_access_check(d, addr, len)) {
return;
@@ -271,10 +272,17 @@
if (rc < 0) {
XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
memset(&read_val, 0xff, len);
+ wb_mask = 0;
+ } else {
+ wb_mask = 0xFFFFFFFF >> ((4 - len) << 3);
}
/* pass directly to the real device for passthrough type register group */
if (reg_grp_entry == NULL) {
+ if (!s->permissive) {
+ wb_mask = 0;
+ wp_flag = true;
+ }
goto out;
}
@@ -295,9 +303,17 @@
uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
uint8_t *ptr_val = NULL;
+ uint32_t wp_mask = reg->emu_mask | reg->ro_mask;
valid_mask <<= (find_addr - real_offset) << 3;
ptr_val = (uint8_t *)&val + (real_offset & 3);
+ if (!s->permissive) {
+ wp_mask |= reg->res_mask;
+ }
+ if (wp_mask == (0xFFFFFFFF >> ((4 - reg->size) << 3))) {
+ wb_mask &= ~((wp_mask >> ((find_addr - real_offset) << 3))
+ << ((len - emul_len) << 3));
+ }
/* do emulation based on register size */
switch (reg->size) {
@@ -339,6 +355,16 @@
} else {
/* nothing to do with passthrough type register,
* continue to find next byte */
+ if (!s->permissive) {
+ wb_mask &= ~(0xff << ((len - emul_len) << 3));
+ /* Unused BARs will make it here, but we don't want to issue
+ * warnings for writes to them (bogus writes get dealt with
+ * above).
+ */
+ if (index < 0) {
+ wp_flag = true;
+ }
+ }
emul_len--;
find_addr++;
}
@@ -350,10 +376,26 @@
memory_region_transaction_commit();
out:
- if (!(reg && reg->no_wb)) {
+ if (wp_flag && !s->permissive_warned) {
+ s->permissive_warned = true;
+ xen_pt_log(d, "Write-back to unknown field 0x%02x (partially) inhibited (0x%0*x)\n",
+ addr, len * 2, wb_mask);
+ xen_pt_log(d, "If the device doesn't work, try enabling permissive mode\n");
+ xen_pt_log(d, "(unsafe) and if it helps report the problem to xen-devel\n");
+ }
+ for (index = 0; wb_mask; index += len) {
/* unknown regs are passed through */
- rc = xen_host_pci_set_block(&s->real_device, addr,
- (uint8_t *)&val, len);
+ while (!(wb_mask & 0xff)) {
+ index++;
+ wb_mask >>= 8;
+ }
+ len = 0;
+ do {
+ len++;
+ wb_mask >>= 8;
+ } while (wb_mask & 0xff);
+ rc = xen_host_pci_set_block(&s->real_device, addr + index,
+ (uint8_t *)&val + index, len);
if (rc < 0) {
XEN_PT_ERR(d, "pci_write_block failed. return value: %d.\n", rc);
@@ -807,6 +849,7 @@
static Property xen_pci_passthrough_properties[] = {
DEFINE_PROP_PCI_HOST_DEVADDR("hostaddr", XenPCIPassthroughState, hostaddr),
+ DEFINE_PROP_BOOL("permissive", XenPCIPassthroughState, permissive, false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
index 942dc60..4bba559 100644
--- a/hw/xen/xen_pt.h
+++ b/hw/xen/xen_pt.h
@@ -101,12 +101,12 @@
uint32_t offset;
uint32_t size;
uint32_t init_val;
+ /* reg reserved field mask (ON:reserved, OFF:defined) */
+ uint32_t res_mask;
/* reg read only field mask (ON:RO/ROS, OFF:other) */
uint32_t ro_mask;
/* reg emulate field mask (ON:emu, OFF:passthrough) */
uint32_t emu_mask;
- /* no write back allowed */
- uint32_t no_wb;
xen_pt_conf_reg_init init;
/* read/write function pointer
* for double_word/word/byte size */
@@ -177,6 +177,7 @@
uint32_t data;
uint32_t vector_ctrl;
bool updated; /* indicate whether MSI ADDR or DATA is updated */
+ bool warned; /* avoid issuing (bogus) warning more than once */
} XenPTMSIXEntry;
typedef struct XenPTMSIX {
uint32_t ctrl_offset;
@@ -196,6 +197,8 @@
PCIHostDeviceAddress hostaddr;
bool is_virtfn;
+ bool permissive;
+ bool permissive_warned;
XenHostPCIDevice real_device;
XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */
QLIST_HEAD(, XenPTRegGroup) reg_grps;
diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c
index 95a51db..f3cf069 100644
--- a/hw/xen/xen_pt_config_init.c
+++ b/hw/xen/xen_pt_config_init.c
@@ -95,6 +95,18 @@
return NULL;
}
+static uint32_t get_throughable_mask(const XenPCIPassthroughState *s,
+ const XenPTRegInfo *reg,
+ uint32_t valid_mask)
+{
+ uint32_t throughable_mask = ~(reg->emu_mask | reg->ro_mask);
+
+ if (!s->permissive) {
+ throughable_mask &= ~reg->res_mask;
+ }
+
+ return throughable_mask & valid_mask;
+}
/****************
* general register functions
@@ -157,14 +169,13 @@
{
XenPTRegInfo *reg = cfg_entry->reg;
uint8_t writable_mask = 0;
- uint8_t throughable_mask = 0;
+ uint8_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
return 0;
@@ -175,14 +186,13 @@
{
XenPTRegInfo *reg = cfg_entry->reg;
uint16_t writable_mask = 0;
- uint16_t throughable_mask = 0;
+ uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
return 0;
@@ -193,14 +203,13 @@
{
XenPTRegInfo *reg = cfg_entry->reg;
uint32_t writable_mask = 0;
- uint32_t throughable_mask = 0;
+ uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
return 0;
@@ -292,15 +301,13 @@
{
XenPTRegInfo *reg = cfg_entry->reg;
uint16_t writable_mask = 0;
- uint16_t throughable_mask = 0;
+ uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
/* modify emulate register */
writable_mask = ~reg->ro_mask & valid_mask;
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
-
if (*val & PCI_COMMAND_INTX_DISABLE) {
throughable_mask |= PCI_COMMAND_INTX_DISABLE;
} else {
@@ -454,7 +461,6 @@
PCIDevice *d = &s->dev;
const PCIIORegion *r;
uint32_t writable_mask = 0;
- uint32_t throughable_mask = 0;
uint32_t bar_emu_mask = 0;
uint32_t bar_ro_mask = 0;
uint32_t r_size = 0;
@@ -511,8 +517,7 @@
}
/* create value for writing to I/O device register */
- throughable_mask = ~bar_emu_mask & valid_mask;
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+ *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
return 0;
}
@@ -526,9 +531,8 @@
XenPTRegion *base = NULL;
PCIDevice *d = (PCIDevice *)&s->dev;
uint32_t writable_mask = 0;
- uint32_t throughable_mask = 0;
+ uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
pcibus_t r_size = 0;
- uint32_t bar_emu_mask = 0;
uint32_t bar_ro_mask = 0;
r_size = d->io_regions[PCI_ROM_SLOT].size;
@@ -537,7 +541,6 @@
r_size = xen_pt_get_emul_size(base->bar_flag, r_size);
/* set emulate mask and read-only mask */
- bar_emu_mask = reg->emu_mask;
bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE;
/* modify emulate register */
@@ -545,7 +548,6 @@
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
/* create value for writing to I/O device register */
- throughable_mask = ~bar_emu_mask & valid_mask;
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
return 0;
@@ -580,7 +582,7 @@
.offset = PCI_COMMAND,
.size = 2,
.init_val = 0x0000,
- .ro_mask = 0xF880,
+ .res_mask = 0xF880,
.emu_mask = 0x0743,
.init = xen_pt_common_reg_init,
.u.w.read = xen_pt_word_reg_read,
@@ -605,7 +607,8 @@
.offset = PCI_STATUS,
.size = 2,
.init_val = 0x0000,
- .ro_mask = 0x06FF,
+ .res_mask = 0x0007,
+ .ro_mask = 0x06F8,
.emu_mask = 0x0010,
.init = xen_pt_status_reg_init,
.u.w.read = xen_pt_word_reg_read,
@@ -755,6 +758,15 @@
.u.b.write = xen_pt_byte_reg_write,
},
{
+ .offset = PCI_VPD_ADDR,
+ .size = 2,
+ .ro_mask = 0x0003,
+ .emu_mask = 0x0003,
+ .init = xen_pt_common_reg_init,
+ .u.w.read = xen_pt_word_reg_read,
+ .u.w.write = xen_pt_word_reg_write,
+ },
+ {
.size = 0,
},
};
@@ -873,7 +885,7 @@
.offset = PCI_EXP_DEVCAP,
.size = 4,
.init_val = 0x00000000,
- .ro_mask = 0x1FFCFFFF,
+ .ro_mask = 0xFFFFFFFF,
.emu_mask = 0x10000000,
.init = xen_pt_common_reg_init,
.u.dw.read = xen_pt_long_reg_read,
@@ -890,6 +902,16 @@
.u.w.read = xen_pt_word_reg_read,
.u.w.write = xen_pt_word_reg_write,
},
+ /* Device Status reg */
+ {
+ .offset = PCI_EXP_DEVSTA,
+ .size = 2,
+ .res_mask = 0xFFC0,
+ .ro_mask = 0x0030,
+ .init = xen_pt_common_reg_init,
+ .u.w.read = xen_pt_word_reg_read,
+ .u.w.write = xen_pt_word_reg_write,
+ },
/* Link Control reg */
{
.offset = PCI_EXP_LNKCTL,
@@ -901,6 +923,15 @@
.u.w.read = xen_pt_word_reg_read,
.u.w.write = xen_pt_word_reg_write,
},
+ /* Link Status reg */
+ {
+ .offset = PCI_EXP_LNKSTA,
+ .size = 2,
+ .ro_mask = 0x3FFF,
+ .init = xen_pt_common_reg_init,
+ .u.w.read = xen_pt_word_reg_read,
+ .u.w.write = xen_pt_word_reg_write,
+ },
/* Device Control 2 reg */
{
.offset = 0x28,
@@ -933,39 +964,22 @@
* Power Management Capability
*/
-/* read Power Management Control/Status register */
-static int xen_pt_pmcsr_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint16_t *value, uint16_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint16_t valid_emu_mask = reg->emu_mask;
-
- valid_emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
-
- valid_emu_mask = valid_emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
-
- return 0;
-}
/* write Power Management Control/Status register */
static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s,
XenPTReg *cfg_entry, uint16_t *val,
uint16_t dev_value, uint16_t valid_mask)
{
XenPTRegInfo *reg = cfg_entry->reg;
- uint16_t emu_mask = reg->emu_mask;
uint16_t writable_mask = 0;
- uint16_t throughable_mask = 0;
-
- emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
+ uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
/* modify emulate register */
- writable_mask = emu_mask & ~reg->ro_mask & valid_mask;
+ writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
/* create value for writing to I/O device register */
- throughable_mask = ~emu_mask & valid_mask;
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+ *val = XEN_PT_MERGE_VALUE(*val, dev_value & ~PCI_PM_CTRL_PME_STATUS,
+ throughable_mask);
return 0;
}
@@ -999,10 +1013,11 @@
.offset = PCI_PM_CTRL,
.size = 2,
.init_val = 0x0008,
- .ro_mask = 0xE1FC,
- .emu_mask = 0x8100,
+ .res_mask = 0x00F0,
+ .ro_mask = 0xE10C,
+ .emu_mask = 0x810B,
.init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_pmcsr_reg_read,
+ .u.w.read = xen_pt_word_reg_read,
.u.w.write = xen_pt_pmcsr_reg_write,
},
{
@@ -1016,13 +1031,9 @@
*/
/* Helper */
-static bool xen_pt_msgdata_check_type(uint32_t offset, uint16_t flags)
-{
- /* check the offset whether matches the type or not */
- bool is_32 = (offset == PCI_MSI_DATA_32) && !(flags & PCI_MSI_FLAGS_64BIT);
- bool is_64 = (offset == PCI_MSI_DATA_64) && (flags & PCI_MSI_FLAGS_64BIT);
- return is_32 || is_64;
-}
+#define xen_pt_msi_check_type(offset, flags, what) \
+ ((offset) == ((flags) & PCI_MSI_FLAGS_64BIT ? \
+ PCI_MSI_##what##_64 : PCI_MSI_##what##_32))
/* Message Control register */
static int xen_pt_msgctrl_reg_init(XenPCIPassthroughState *s,
@@ -1056,8 +1067,7 @@
XenPTRegInfo *reg = cfg_entry->reg;
XenPTMSI *msi = s->msi;
uint16_t writable_mask = 0;
- uint16_t throughable_mask = 0;
- uint16_t raw_val;
+ uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
/* Currently no support for multi-vector */
if (*val & PCI_MSI_FLAGS_QSIZE) {
@@ -1070,12 +1080,10 @@
msi->flags |= cfg_entry->data & ~PCI_MSI_FLAGS_ENABLE;
/* create value for writing to I/O device register */
- raw_val = *val;
- throughable_mask = ~reg->emu_mask & valid_mask;
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
/* update MSI */
- if (raw_val & PCI_MSI_FLAGS_ENABLE) {
+ if (*val & PCI_MSI_FLAGS_ENABLE) {
/* setup MSI pirq for the first time */
if (!msi->initialized) {
/* Init physical one */
@@ -1103,10 +1111,6 @@
xen_pt_msi_disable(s);
}
- /* pass through MSI_ENABLE bit */
- *val &= ~PCI_MSI_FLAGS_ENABLE;
- *val |= raw_val & PCI_MSI_FLAGS_ENABLE;
-
return 0;
}
@@ -1134,7 +1138,45 @@
uint32_t offset = reg->offset;
/* check the offset whether matches the type or not */
- if (xen_pt_msgdata_check_type(offset, flags)) {
+ if (xen_pt_msi_check_type(offset, flags, DATA)) {
+ *data = reg->init_val;
+ } else {
+ *data = XEN_PT_INVALID_REG;
+ }
+ return 0;
+}
+
+/* this function will be called twice (for 32 bit and 64 bit type) */
+/* initialize Mask register */
+static int xen_pt_mask_reg_init(XenPCIPassthroughState *s,
+ XenPTRegInfo *reg, uint32_t real_offset,
+ uint32_t *data)
+{
+ uint32_t flags = s->msi->flags;
+
+ /* check the offset whether matches the type or not */
+ if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
+ *data = XEN_PT_INVALID_REG;
+ } else if (xen_pt_msi_check_type(reg->offset, flags, MASK)) {
+ *data = reg->init_val;
+ } else {
+ *data = XEN_PT_INVALID_REG;
+ }
+ return 0;
+}
+
+/* this function will be called twice (for 32 bit and 64 bit type) */
+/* initialize Pending register */
+static int xen_pt_pending_reg_init(XenPCIPassthroughState *s,
+ XenPTRegInfo *reg, uint32_t real_offset,
+ uint32_t *data)
+{
+ uint32_t flags = s->msi->flags;
+
+ /* check the offset whether matches the type or not */
+ if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
+ *data = XEN_PT_INVALID_REG;
+ } else if (xen_pt_msi_check_type(reg->offset, flags, PENDING)) {
*data = reg->init_val;
} else {
*data = XEN_PT_INVALID_REG;
@@ -1149,7 +1191,6 @@
{
XenPTRegInfo *reg = cfg_entry->reg;
uint32_t writable_mask = 0;
- uint32_t throughable_mask = 0;
uint32_t old_addr = cfg_entry->data;
/* modify emulate register */
@@ -1158,8 +1199,7 @@
s->msi->addr_lo = cfg_entry->data;
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+ *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
/* update MSI */
if (cfg_entry->data != old_addr) {
@@ -1177,7 +1217,6 @@
{
XenPTRegInfo *reg = cfg_entry->reg;
uint32_t writable_mask = 0;
- uint32_t throughable_mask = 0;
uint32_t old_addr = cfg_entry->data;
/* check whether the type is 64 bit or not */
@@ -1194,8 +1233,7 @@
s->msi->addr_hi = cfg_entry->data;
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+ *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
/* update MSI */
if (cfg_entry->data != old_addr) {
@@ -1217,12 +1255,11 @@
XenPTRegInfo *reg = cfg_entry->reg;
XenPTMSI *msi = s->msi;
uint16_t writable_mask = 0;
- uint16_t throughable_mask = 0;
uint16_t old_data = cfg_entry->data;
uint32_t offset = reg->offset;
/* check the offset whether matches the type or not */
- if (!xen_pt_msgdata_check_type(offset, msi->flags)) {
+ if (!xen_pt_msi_check_type(offset, msi->flags, DATA)) {
/* exit I/O emulator */
XEN_PT_ERR(&s->dev, "the offset does not match the 32/64 bit type!\n");
return -1;
@@ -1235,8 +1272,7 @@
msi->data = cfg_entry->data;
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+ *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
/* update MSI */
if (cfg_entry->data != old_data) {
@@ -1266,8 +1302,9 @@
.offset = PCI_MSI_FLAGS,
.size = 2,
.init_val = 0x0000,
- .ro_mask = 0xFF8E,
- .emu_mask = 0x007F,
+ .res_mask = 0xFE00,
+ .ro_mask = 0x018E,
+ .emu_mask = 0x017E,
.init = xen_pt_msgctrl_reg_init,
.u.w.read = xen_pt_word_reg_read,
.u.w.write = xen_pt_msgctrl_reg_write,
@@ -1279,7 +1316,6 @@
.init_val = 0x00000000,
.ro_mask = 0x00000003,
.emu_mask = 0xFFFFFFFF,
- .no_wb = 1,
.init = xen_pt_common_reg_init,
.u.dw.read = xen_pt_long_reg_read,
.u.dw.write = xen_pt_msgaddr32_reg_write,
@@ -1291,7 +1327,6 @@
.init_val = 0x00000000,
.ro_mask = 0x00000000,
.emu_mask = 0xFFFFFFFF,
- .no_wb = 1,
.init = xen_pt_msgaddr64_reg_init,
.u.dw.read = xen_pt_long_reg_read,
.u.dw.write = xen_pt_msgaddr64_reg_write,
@@ -1303,7 +1338,6 @@
.init_val = 0x0000,
.ro_mask = 0x0000,
.emu_mask = 0xFFFF,
- .no_wb = 1,
.init = xen_pt_msgdata_reg_init,
.u.w.read = xen_pt_word_reg_read,
.u.w.write = xen_pt_msgdata_reg_write,
@@ -1315,11 +1349,54 @@
.init_val = 0x0000,
.ro_mask = 0x0000,
.emu_mask = 0xFFFF,
- .no_wb = 1,
.init = xen_pt_msgdata_reg_init,
.u.w.read = xen_pt_word_reg_read,
.u.w.write = xen_pt_msgdata_reg_write,
},
+ /* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
+ {
+ .offset = PCI_MSI_MASK_32,
+ .size = 4,
+ .init_val = 0x00000000,
+ .ro_mask = 0xFFFFFFFF,
+ .emu_mask = 0xFFFFFFFF,
+ .init = xen_pt_mask_reg_init,
+ .u.dw.read = xen_pt_long_reg_read,
+ .u.dw.write = xen_pt_long_reg_write,
+ },
+ /* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
+ {
+ .offset = PCI_MSI_MASK_64,
+ .size = 4,
+ .init_val = 0x00000000,
+ .ro_mask = 0xFFFFFFFF,
+ .emu_mask = 0xFFFFFFFF,
+ .init = xen_pt_mask_reg_init,
+ .u.dw.read = xen_pt_long_reg_read,
+ .u.dw.write = xen_pt_long_reg_write,
+ },
+ /* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
+ {
+ .offset = PCI_MSI_MASK_32 + 4,
+ .size = 4,
+ .init_val = 0x00000000,
+ .ro_mask = 0xFFFFFFFF,
+ .emu_mask = 0x00000000,
+ .init = xen_pt_pending_reg_init,
+ .u.dw.read = xen_pt_long_reg_read,
+ .u.dw.write = xen_pt_long_reg_write,
+ },
+ /* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
+ {
+ .offset = PCI_MSI_MASK_64 + 4,
+ .size = 4,
+ .init_val = 0x00000000,
+ .ro_mask = 0xFFFFFFFF,
+ .emu_mask = 0x00000000,
+ .init = xen_pt_pending_reg_init,
+ .u.dw.read = xen_pt_long_reg_read,
+ .u.dw.write = xen_pt_long_reg_write,
+ },
{
.size = 0,
},
@@ -1358,7 +1435,7 @@
{
XenPTRegInfo *reg = cfg_entry->reg;
uint16_t writable_mask = 0;
- uint16_t throughable_mask = 0;
+ uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
int debug_msix_enabled_old;
/* modify emulate register */
@@ -1366,7 +1443,6 @@
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
/* update MSI-X */
@@ -1405,7 +1481,8 @@
.offset = PCI_MSI_FLAGS,
.size = 2,
.init_val = 0x0000,
- .ro_mask = 0x3FFF,
+ .res_mask = 0x3800,
+ .ro_mask = 0x07FF,
.emu_mask = 0x0000,
.init = xen_pt_msixctrl_reg_init,
.u.w.read = xen_pt_word_reg_read,
diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c
index 9ed9321..68db623 100644
--- a/hw/xen/xen_pt_msi.c
+++ b/hw/xen/xen_pt_msi.c
@@ -434,11 +434,10 @@
XenPCIPassthroughState *s = opaque;
XenPTMSIX *msix = s->msix;
XenPTMSIXEntry *entry;
- int entry_nr, offset;
+ unsigned int entry_nr, offset;
entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
- if (entry_nr < 0 || entry_nr >= msix->total_entries) {
- XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr);
+ if (entry_nr >= msix->total_entries) {
return;
}
entry = &msix->msix_entry[entry_nr];
@@ -460,8 +459,11 @@
+ PCI_MSIX_ENTRY_VECTOR_CTRL;
if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
- XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
- " already enabled.\n", entry_nr);
+ if (!entry->warned) {
+ entry->warned = true;
+ XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
+ " already enabled.\n", entry_nr);
+ }
return;
}
diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
index 5c940eb..760804c 100644
--- a/include/hw/arm/arm.h
+++ b/include/hw/arm/arm.h
@@ -13,11 +13,21 @@
#include "exec/memory.h"
#include "hw/irq.h"
+#include "qemu/notify.h"
/* armv7m.c */
qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
const char *kernel_filename, const char *cpu_model);
+/*
+ * struct used as a parameter of the arm_load_kernel machine init
+ * done notifier
+ */
+typedef struct {
+ Notifier notifier; /* actual notifier */
+ ARMCPU *cpu; /* handle to the first cpu object */
+} ArmLoadKernelNotifier;
+
/* arm_boot.c */
struct arm_boot_info {
uint64_t ram_size;
@@ -64,6 +74,8 @@
* the user it should implement this hook.
*/
void (*modify_dtb)(const struct arm_boot_info *info, void *fdt);
+ /* machine init done notifier executing arm_load_dtb */
+ ArmLoadKernelNotifier load_kernel_notifier;
/* Used internally by arm_boot.c */
int is_linux;
hwaddr initrd_start;
@@ -75,6 +87,22 @@
*/
bool firmware_loaded;
};
+
+/**
+ * arm_load_kernel - Loads memory with everything needed to boot
+ *
+ * @cpu: handle to the first CPU object
+ * @info: handle to the boot info struct
+ * Registers a machine init done notifier that copies to memory
+ * everything needed to boot, depending on machine and user options:
+ * kernel image, boot loaders, initrd, dtb. Also registers the CPU
+ * reset handler.
+ *
+ * In case the machine file supports the platform bus device and its
+ * dynamically instantiable sysbus devices, this function must be called
+ * before sysbus-fdt arm_register_platform_bus_fdt_creator. Indeed the
+ * machine init done notifiers are called in registration reverse order.
+ */
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
/* Multiplication factor to convert from system clock ticks to qemu timer
diff --git a/include/hw/arm/sysbus-fdt.h b/include/hw/arm/sysbus-fdt.h
new file mode 100644
index 0000000..e15bb81
--- /dev/null
+++ b/include/hw/arm/sysbus-fdt.h
@@ -0,0 +1,60 @@
+/*
+ * Dynamic sysbus device tree node generation API
+ *
+ * Copyright Linaro Limited, 2014
+ *
+ * Authors:
+ * Alex Graf <agraf@suse.de>
+ * Eric Auger <eric.auger@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef HW_ARM_SYSBUS_FDT_H
+#define HW_ARM_SYSBUS_FDT_H
+
+#include "hw/arm/arm.h"
+#include "qemu-common.h"
+#include "hw/sysbus.h"
+
+/*
+ * struct that contains dimensioning parameters of the platform bus
+ */
+typedef struct {
+ hwaddr platform_bus_base; /* start address of the bus */
+ hwaddr platform_bus_size; /* size of the bus */
+ int platform_bus_first_irq; /* first hwirq assigned to the bus */
+ int platform_bus_num_irqs; /* number of hwirq assigned to the bus */
+} ARMPlatformBusSystemParams;
+
+/*
+ * struct that contains all relevant info to build the fdt nodes of
+ * platform bus and attached dynamic sysbus devices
+ * in the future might be augmented with additional info
+ * such as PHY, CLK handles ...
+ */
+typedef struct {
+ const ARMPlatformBusSystemParams *system_params;
+ struct arm_boot_info *binfo;
+ const char *intc; /* parent interrupt controller name */
+} ARMPlatformBusFDTParams;
+
+/**
+ * arm_register_platform_bus_fdt_creator - register a machine init done
+ * notifier that creates the device tree nodes of the platform bus and
+ * associated dynamic sysbus devices
+ */
+void arm_register_platform_bus_fdt_creator(ARMPlatformBusFDTParams *fdt_params);
+
+#endif
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index ceec8b3..d22fd8e 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -32,6 +32,7 @@
#include "qemu-common.h"
+#define NUM_GICV2M_SPIS 64
#define NUM_VIRTIO_TRANSPORTS 32
#define ARCH_TIMER_VIRT_IRQ 11
@@ -53,6 +54,8 @@
VIRT_PCIE_MMIO,
VIRT_PCIE_PIO,
VIRT_PCIE_ECAM,
+ VIRT_GIC_V2M,
+ VIRT_PLATFORM_BUS,
};
typedef struct MemMapEntry {
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 27bd748..261155f 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -193,7 +193,7 @@
MemoryRegion *rom_memory,
MemoryRegion **ram_memory,
PcGuestInfo *guest_info);
-qemu_irq *pc_allocate_cpu_irq(void);
+qemu_irq pc_allocate_cpu_irq(void);
DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus);
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
ISADevice **rtc_state,
diff --git a/include/hw/pci/pci_regs.h b/include/hw/pci/pci_regs.h
index 56a404b..57e8c80 100644
--- a/include/hw/pci/pci_regs.h
+++ b/include/hw/pci/pci_regs.h
@@ -298,8 +298,10 @@
#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */
#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */
+#define PCI_MSI_PENDING_32 16 /* Pending bits register for 32-bit devices */
#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */
+#define PCI_MSI_PENDING_64 20 /* Pending bits register for 32-bit devices */
/* MSI-X registers */
#define PCI_MSIX_FLAGS 2
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index df67d56..57f8394 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -16,10 +16,7 @@
#define MONITOR_USE_CONTROL 0x04
#define MONITOR_USE_PRETTY 0x08
-/* flags for monitor commands */
-#define MONITOR_CMD_ASYNC 0x0001
-
-int monitor_cur_is_qmp(void);
+bool monitor_cur_is_qmp(void);
void monitor_init(CharDriverState *chr, int flags);
@@ -43,8 +40,6 @@
int monitor_set_cpu(int cpu_index);
int monitor_get_cpu_index(void);
-typedef void (MonitorCompletion)(void *opaque, QObject *ret_data);
-
void monitor_set_error(Monitor *mon, QError *qerror);
void monitor_read_command(Monitor *mon, int show_prompt);
int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
index 7ca59b5..3104150 100644
--- a/include/sysemu/blockdev.h
+++ b/include/sysemu/blockdev.h
@@ -66,5 +66,5 @@
void qmp_change_blockdev(const char *device, const char *filename,
const char *format, Error **errp);
void hmp_commit(Monitor *mon, const QDict *qdict);
-int hmp_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
+void hmp_drive_del(Monitor *mon, const QDict *qdict);
#endif
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 4878959..f459fbd 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -287,6 +287,8 @@
int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
uint64_t address, uint32_t data);
+int kvm_arch_msi_data_to_gsi(uint32_t data);
+
int kvm_set_irq(KVMState *s, int irq, int level);
int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg);
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 8a52934..e10c2c5 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -161,9 +161,7 @@
void hmp_drive_add(Monitor *mon, const QDict *qdict);
/* pcie aer error injection */
-void pcie_aer_inject_error_print(Monitor *mon, const QObject *data);
-int hmp_pcie_aer_inject_error(Monitor *mon,
- const QDict *qdict, QObject **ret_data);
+void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict);
/* serial ports */
diff --git a/kvm-all.c b/kvm-all.c
index 17a3771..b2b1bc3 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1228,7 +1228,7 @@
int virq;
if (kvm_gsi_direct_mapping()) {
- return msg.data & 0xffff;
+ return kvm_arch_msi_data_to_gsi(msg.data);
}
if (!kvm_gsi_routing_enabled()) {
diff --git a/monitor.c b/monitor.c
index b2561e1..c7baa91 100644
--- a/monitor.c
+++ b/monitor.c
@@ -118,25 +118,15 @@
*
*/
-typedef struct MonitorCompletionData MonitorCompletionData;
-struct MonitorCompletionData {
- Monitor *mon;
- void (*user_print)(Monitor *mon, const QObject *data);
-};
-
typedef struct mon_cmd_t {
const char *name;
const char *args_type;
const char *params;
const char *help;
- void (*user_print)(Monitor *mon, const QObject *data);
union {
void (*cmd)(Monitor *mon, const QDict *qdict);
int (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
- int (*cmd_async)(Monitor *mon, const QDict *params,
- MonitorCompletion *cb, void *opaque);
} mhandler;
- int flags;
/* @sub_table is a list of 2nd level of commands. If it do not exist,
* mhandler should be used. If it exist, sub_table[?].mhandler should be
* used, and mhandler of 1st level plays the role of help function.
@@ -171,11 +161,16 @@
QLIST_ENTRY(MonFdset) next;
};
-typedef struct MonitorControl {
+typedef struct {
QObject *id;
JSONMessageParser parser;
- int command_mode;
-} MonitorControl;
+ /*
+ * When a client connects, we're in capabilities negotiation mode.
+ * When command qmp_capabilities succeeds, we go into command
+ * mode.
+ */
+ bool in_command_mode; /* are we in command mode? */
+} MonitorQMP;
/*
* To prevent flooding clients, events can be throttled. The
@@ -205,7 +200,7 @@
int mux_out;
ReadLineState *rs;
- MonitorControl *mc;
+ MonitorQMP qmp;
CPUState *mon_cpu;
BlockCompletionFunc *password_completion_cb;
void *password_opaque;
@@ -236,21 +231,20 @@
static void monitor_command_cb(void *opaque, const char *cmdline,
void *readline_opaque);
-static inline int qmp_cmd_mode(const Monitor *mon)
-{
- return (mon->mc ? mon->mc->command_mode : 0);
-}
-
-/* Return true if in control mode, false otherwise */
-static inline int monitor_ctrl_mode(const Monitor *mon)
+/**
+ * Is @mon a QMP monitor?
+ */
+static inline bool monitor_is_qmp(const Monitor *mon)
{
return (mon->flags & MONITOR_USE_CONTROL);
}
-/* Return non-zero iff we have a current monitor, and it is in QMP mode. */
-int monitor_cur_is_qmp(void)
+/**
+ * Is the current monitor, if any, a QMP monitor?
+ */
+bool monitor_cur_is_qmp(void)
{
- return cur_mon && monitor_ctrl_mode(cur_mon);
+ return cur_mon && monitor_is_qmp(cur_mon);
}
void monitor_read_command(Monitor *mon, int show_prompt)
@@ -360,7 +354,7 @@
if (!mon)
return;
- if (monitor_ctrl_mode(mon)) {
+ if (monitor_is_qmp(mon)) {
return;
}
@@ -387,23 +381,6 @@
return 0;
}
-static void monitor_user_noop(Monitor *mon, const QObject *data) { }
-
-static inline int handler_is_qobject(const mon_cmd_t *cmd)
-{
- return cmd->user_print != NULL;
-}
-
-static inline bool handler_is_async(const mon_cmd_t *cmd)
-{
- return cmd->flags & MONITOR_CMD_ASYNC;
-}
-
-static inline int monitor_has_error(const Monitor *mon)
-{
- return mon->error != NULL;
-}
-
static void monitor_json_emitter(Monitor *mon, const QObject *data)
{
QString *json;
@@ -418,24 +395,25 @@
QDECREF(json);
}
-static QDict *build_qmp_error_dict(const QError *err)
+static QDict *build_qmp_error_dict(Error *err)
{
QObject *obj;
- obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %p } }",
- ErrorClass_lookup[err->err_class],
- qerror_human(err));
+ obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %s } }",
+ ErrorClass_lookup[error_get_class(err)],
+ error_get_pretty(err));
return qobject_to_qdict(obj);
}
-static void monitor_protocol_emitter(Monitor *mon, QObject *data)
+static void monitor_protocol_emitter(Monitor *mon, QObject *data,
+ Error *err)
{
QDict *qmp;
trace_monitor_protocol_emitter(mon);
- if (!monitor_has_error(mon)) {
+ if (!err) {
/* success response */
qmp = qdict_new();
if (data) {
@@ -447,14 +425,12 @@
}
} else {
/* error response */
- qmp = build_qmp_error_dict(mon->error);
- QDECREF(mon->error);
- mon->error = NULL;
+ qmp = build_qmp_error_dict(err);
}
- if (mon->mc->id) {
- qdict_put_obj(qmp, "id", mon->mc->id);
- mon->mc->id = NULL;
+ if (mon->qmp.id) {
+ qdict_put_obj(qmp, "id", mon->qmp.id);
+ mon->qmp.id = NULL;
}
monitor_json_emitter(mon, QOBJECT(qmp));
@@ -474,7 +450,7 @@
trace_monitor_protocol_event_emit(event, data);
QLIST_FOREACH(mon, &mon_list, entry) {
- if (monitor_ctrl_mode(mon) && qmp_cmd_mode(mon)) {
+ if (monitor_is_qmp(mon) && mon->qmp.in_command_mode) {
monitor_json_emitter(mon, data);
}
}
@@ -594,15 +570,11 @@
static int do_qmp_capabilities(Monitor *mon, const QDict *params,
QObject **ret_data)
{
- /* Will setup QMP capabilities in the future */
- if (monitor_ctrl_mode(mon)) {
- mon->mc->command_mode = 1;
- }
-
+ mon->qmp.in_command_mode = true;
return 0;
}
-static void handle_user_command(Monitor *mon, const char *cmdline);
+static void handle_hmp_command(Monitor *mon, const char *cmdline);
static void monitor_data_init(Monitor *mon)
{
@@ -641,7 +613,7 @@
}
}
- handle_user_command(&hmp, command_line);
+ handle_hmp_command(&hmp, command_line);
cur_mon = old_mon;
qemu_mutex_lock(&hmp.out_lock);
@@ -917,45 +889,6 @@
}
#endif
-static void user_monitor_complete(void *opaque, QObject *ret_data)
-{
- MonitorCompletionData *data = (MonitorCompletionData *)opaque;
-
- if (ret_data) {
- data->user_print(data->mon, ret_data);
- }
- monitor_resume(data->mon);
- g_free(data);
-}
-
-static void qmp_monitor_complete(void *opaque, QObject *ret_data)
-{
- monitor_protocol_emitter(opaque, ret_data);
-}
-
-static int qmp_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
- const QDict *params)
-{
- return cmd->mhandler.cmd_async(mon, params, qmp_monitor_complete, mon);
-}
-
-static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
- const QDict *params)
-{
- int ret;
-
- MonitorCompletionData *cb_data = g_malloc(sizeof(*cb_data));
- cb_data->mon = mon;
- cb_data->user_print = cmd->user_print;
- monitor_suspend(mon);
- ret = cmd->mhandler.cmd_async(mon, params,
- user_monitor_complete, cb_data);
- if (ret < 0) {
- monitor_resume(mon);
- g_free(cb_data);
- }
-}
-
static void hmp_info_help(Monitor *mon, const QDict *qdict)
{
help_cmd(mon, "info");
@@ -1085,39 +1018,33 @@
qapi_free_TraceEventInfoList(events);
}
-static int client_migrate_info(Monitor *mon, const QDict *qdict,
- QObject **ret_data)
+void qmp_client_migrate_info(const char *protocol, const char *hostname,
+ bool has_port, int64_t port,
+ bool has_tls_port, int64_t tls_port,
+ bool has_cert_subject, const char *cert_subject,
+ Error **errp)
{
- const char *protocol = qdict_get_str(qdict, "protocol");
- const char *hostname = qdict_get_str(qdict, "hostname");
- const char *subject = qdict_get_try_str(qdict, "cert-subject");
- int port = qdict_get_try_int(qdict, "port", -1);
- int tls_port = qdict_get_try_int(qdict, "tls-port", -1);
- Error *err = NULL;
- int ret;
-
if (strcmp(protocol, "spice") == 0) {
- if (!qemu_using_spice(&err)) {
- qerror_report_err(err);
- error_free(err);
- return -1;
+ if (!qemu_using_spice(errp)) {
+ return;
}
- if (port == -1 && tls_port == -1) {
- qerror_report(QERR_MISSING_PARAMETER, "port/tls-port");
- return -1;
+ if (!has_port && !has_tls_port) {
+ error_set(errp, QERR_MISSING_PARAMETER, "port/tls-port");
+ return;
}
- ret = qemu_spice_migrate_info(hostname, port, tls_port, subject);
- if (ret != 0) {
- qerror_report(QERR_UNDEFINED_ERROR);
- return -1;
+ if (qemu_spice_migrate_info(hostname,
+ has_port ? port : -1,
+ has_tls_port ? tls_port : -1,
+ cert_subject)) {
+ error_set(errp, QERR_UNDEFINED_ERROR);
+ return;
}
- return 0;
+ return;
}
- qerror_report(QERR_INVALID_PARAMETER, "protocol");
- return -1;
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "protocol", "spice");
}
static void hmp_logfile(Monitor *mon, const QDict *qdict)
@@ -4098,19 +4025,7 @@
}
}
-static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret)
-{
- if (ret && !monitor_has_error(mon)) {
- /*
- * If it returns failure, it must have passed on error.
- *
- * Action: Report an internal error to the client if in QMP.
- */
- qerror_report(QERR_UNDEFINED_ERROR);
- }
-}
-
-static void handle_user_command(Monitor *mon, const char *cmdline)
+static void handle_hmp_command(Monitor *mon, const char *cmdline)
{
QDict *qdict;
const mon_cmd_t *cmd;
@@ -4118,26 +4033,10 @@
qdict = qdict_new();
cmd = monitor_parse_command(mon, cmdline, 0, mon->cmd_table, qdict);
- if (!cmd)
- goto out;
-
- if (handler_is_async(cmd)) {
- user_async_cmd_handler(mon, cmd, qdict);
- } else if (handler_is_qobject(cmd)) {
- QObject *data = NULL;
-
- /* XXX: ignores the error code */
- cmd->mhandler.cmd_new(mon, qdict, &data);
- assert(!monitor_has_error(mon));
- if (data) {
- cmd->user_print(mon, data);
- qobject_decref(data);
- }
- } else {
+ if (cmd) {
cmd->mhandler.cmd(mon, qdict);
}
-out:
QDECREF(qdict);
}
@@ -4803,19 +4702,21 @@
return (mon->suspend_cnt == 0) ? 1 : 0;
}
-static bool invalid_qmp_mode(const Monitor *mon, const mon_cmd_t *cmd)
+static bool invalid_qmp_mode(const Monitor *mon, const mon_cmd_t *cmd,
+ Error **errp)
{
bool is_cap = cmd->mhandler.cmd_new == do_qmp_capabilities;
- if (is_cap && qmp_cmd_mode(mon)) {
- qerror_report(ERROR_CLASS_COMMAND_NOT_FOUND,
- "Capabilities negotiation is already complete, command "
- "'%s' ignored", cmd->name);
+
+ if (is_cap && mon->qmp.in_command_mode) {
+ error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
+ "Capabilities negotiation is already complete, command "
+ "'%s' ignored", cmd->name);
return true;
}
- if (!is_cap && !qmp_cmd_mode(mon)) {
- qerror_report(ERROR_CLASS_COMMAND_NOT_FOUND,
- "Expecting capabilities negotiation with "
- "'qmp_capabilities' before command '%s'", cmd->name);
+ if (!is_cap && !mon->qmp.in_command_mode) {
+ error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
+ "Expecting capabilities negotiation with "
+ "'qmp_capabilities' before command '%s'", cmd->name);
return true;
}
return false;
@@ -4831,8 +4732,9 @@
* the QMP_ACCEPT_UNKNOWNS flag is set, then the
* checking is skipped for it.
*/
-static int check_client_args_type(const QDict *client_args,
- const QDict *cmd_args, int flags)
+static void check_client_args_type(const QDict *client_args,
+ const QDict *cmd_args, int flags,
+ Error **errp)
{
const QDictEntry *ent;
@@ -4849,8 +4751,8 @@
continue;
}
/* client arg doesn't exist */
- qerror_report(QERR_INVALID_PARAMETER, client_arg_name);
- return -1;
+ error_set(errp, QERR_INVALID_PARAMETER, client_arg_name);
+ return;
}
arg_type = qobject_to_qstring(obj);
@@ -4862,9 +4764,9 @@
case 'B':
case 's':
if (qobject_type(client_arg) != QTYPE_QSTRING) {
- qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
- "string");
- return -1;
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE,
+ client_arg_name, "string");
+ return;
}
break;
case 'i':
@@ -4872,25 +4774,25 @@
case 'M':
case 'o':
if (qobject_type(client_arg) != QTYPE_QINT) {
- qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
- "int");
- return -1;
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE,
+ client_arg_name, "int");
+ return;
}
break;
case 'T':
if (qobject_type(client_arg) != QTYPE_QINT &&
qobject_type(client_arg) != QTYPE_QFLOAT) {
- qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
- "number");
- return -1;
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE,
+ client_arg_name, "number");
+ return;
}
break;
case 'b':
case '-':
if (qobject_type(client_arg) != QTYPE_QBOOL) {
- qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
- "bool");
- return -1;
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE,
+ client_arg_name, "bool");
+ return;
}
break;
case 'O':
@@ -4909,16 +4811,15 @@
abort();
}
}
-
- return 0;
}
/*
* - Check if the client has passed all mandatory args
* - Set special flags for argument validation
*/
-static int check_mandatory_args(const QDict *cmd_args,
- const QDict *client_args, int *flags)
+static void check_mandatory_args(const QDict *cmd_args,
+ const QDict *client_args, int *flags,
+ Error **errp)
{
const QDictEntry *ent;
@@ -4933,12 +4834,10 @@
} else if (qstring_get_str(type)[0] != '-' &&
qstring_get_str(type)[1] != '?' &&
!qdict_haskey(client_args, cmd_arg_name)) {
- qerror_report(QERR_MISSING_PARAMETER, cmd_arg_name);
- return -1;
+ error_set(errp, QERR_MISSING_PARAMETER, cmd_arg_name);
+ return;
}
}
-
- return 0;
}
static QDict *qdict_from_args_type(const char *args_type)
@@ -4994,24 +4893,26 @@
* 3. Each argument provided by the client must have the type expected
* by the command
*/
-static int qmp_check_client_args(const mon_cmd_t *cmd, QDict *client_args)
+static void qmp_check_client_args(const mon_cmd_t *cmd, QDict *client_args,
+ Error **errp)
{
- int flags, err;
+ Error *err = NULL;
+ int flags;
QDict *cmd_args;
cmd_args = qdict_from_args_type(cmd->args_type);
flags = 0;
- err = check_mandatory_args(cmd_args, client_args, &flags);
+ check_mandatory_args(cmd_args, client_args, &flags, &err);
if (err) {
goto out;
}
- err = check_client_args_type(client_args, cmd_args, flags);
+ check_client_args_type(client_args, cmd_args, flags, &err);
out:
+ error_propagate(errp, err);
QDECREF(cmd_args);
- return err;
}
/*
@@ -5024,14 +4925,14 @@
* 5. If the "id" key exists, it can be anything (ie. json-value)
* 6. Any argument not listed above is considered invalid
*/
-static QDict *qmp_check_input_obj(QObject *input_obj)
+static QDict *qmp_check_input_obj(QObject *input_obj, Error **errp)
{
const QDictEntry *ent;
int has_exec_key = 0;
QDict *input_dict;
if (qobject_type(input_obj) != QTYPE_QDICT) {
- qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "object");
+ error_set(errp, QERR_QMP_BAD_INPUT_OBJECT, "object");
return NULL;
}
@@ -5043,81 +4944,68 @@
if (!strcmp(arg_name, "execute")) {
if (qobject_type(arg_obj) != QTYPE_QSTRING) {
- qerror_report(QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "execute",
- "string");
+ error_set(errp, QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
+ "execute", "string");
return NULL;
}
has_exec_key = 1;
} else if (!strcmp(arg_name, "arguments")) {
if (qobject_type(arg_obj) != QTYPE_QDICT) {
- qerror_report(QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "arguments",
- "object");
+ error_set(errp, QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
+ "arguments", "object");
return NULL;
}
- } else if (!strcmp(arg_name, "id")) {
- /* FIXME: check duplicated IDs for async commands */
} else {
- qerror_report(QERR_QMP_EXTRA_MEMBER, arg_name);
+ error_set(errp, QERR_QMP_EXTRA_MEMBER, arg_name);
return NULL;
}
}
if (!has_exec_key) {
- qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "execute");
+ error_set(errp, QERR_QMP_BAD_INPUT_OBJECT, "execute");
return NULL;
}
return input_dict;
}
-static void qmp_call_cmd(Monitor *mon, const mon_cmd_t *cmd,
- const QDict *params)
-{
- int ret;
- QObject *data = NULL;
-
- ret = cmd->mhandler.cmd_new(mon, params, &data);
- handler_audit(mon, cmd, ret);
- monitor_protocol_emitter(mon, data);
- qobject_decref(data);
-}
-
static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
{
- int err;
- QObject *obj;
+ Error *local_err = NULL;
+ QObject *obj, *data;
QDict *input, *args;
const mon_cmd_t *cmd;
const char *cmd_name;
Monitor *mon = cur_mon;
args = input = NULL;
+ data = NULL;
obj = json_parser_parse(tokens, NULL);
if (!obj) {
// FIXME: should be triggered in json_parser_parse()
- qerror_report(QERR_JSON_PARSING);
+ error_set(&local_err, QERR_JSON_PARSING);
goto err_out;
}
- input = qmp_check_input_obj(obj);
+ input = qmp_check_input_obj(obj, &local_err);
if (!input) {
qobject_decref(obj);
goto err_out;
}
- mon->mc->id = qdict_get(input, "id");
- qobject_incref(mon->mc->id);
+ mon->qmp.id = qdict_get(input, "id");
+ qobject_incref(mon->qmp.id);
cmd_name = qdict_get_str(input, "execute");
trace_handle_qmp_command(mon, cmd_name);
cmd = qmp_find_cmd(cmd_name);
if (!cmd) {
- qerror_report(ERROR_CLASS_COMMAND_NOT_FOUND,
- "The command %s has not been found", cmd_name);
+ error_set(&local_err, ERROR_CLASS_COMMAND_NOT_FOUND,
+ "The command %s has not been found", cmd_name);
goto err_out;
}
- if (invalid_qmp_mode(mon, cmd)) {
+ if (invalid_qmp_mode(mon, cmd, &local_err)) {
goto err_out;
}
@@ -5129,40 +5017,39 @@
QINCREF(args);
}
- err = qmp_check_client_args(cmd, args);
- if (err < 0) {
+ qmp_check_client_args(cmd, args, &local_err);
+ if (local_err) {
goto err_out;
}
- if (handler_is_async(cmd)) {
- err = qmp_async_cmd_handler(mon, cmd, args);
- if (err) {
- /* emit the error response */
- goto err_out;
+ if (cmd->mhandler.cmd_new(mon, args, &data)) {
+ /* Command failed... */
+ if (!mon->error) {
+ /* ... without setting an error, so make one up */
+ error_set(&local_err, QERR_UNDEFINED_ERROR);
}
- } else {
- qmp_call_cmd(mon, cmd, args);
+ }
+ if (mon->error) {
+ error_set(&local_err, mon->error->err_class, "%s",
+ mon->error->err_msg);
}
- goto out;
-
err_out:
- monitor_protocol_emitter(mon, NULL);
-out:
+ monitor_protocol_emitter(mon, data, local_err);
+ qobject_decref(data);
+ QDECREF(mon->error);
+ mon->error = NULL;
QDECREF(input);
QDECREF(args);
}
-/**
- * monitor_control_read(): Read and handle QMP input
- */
-static void monitor_control_read(void *opaque, const uint8_t *buf, int size)
+static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
{
Monitor *old_mon = cur_mon;
cur_mon = opaque;
- json_message_parser_feed(&cur_mon->mc->parser, (const char *) buf, size);
+ json_message_parser_feed(&cur_mon->qmp.parser, (const char *) buf, size);
cur_mon = old_mon;
}
@@ -5181,7 +5068,7 @@
if (size == 0 || buf[size - 1] != 0)
monitor_printf(cur_mon, "corrupted command\n");
else
- handle_user_command(cur_mon, (char *)buf);
+ handle_hmp_command(cur_mon, (char *)buf);
}
cur_mon = old_mon;
@@ -5193,7 +5080,7 @@
Monitor *mon = opaque;
monitor_suspend(mon);
- handle_user_command(mon, cmdline);
+ handle_hmp_command(mon, cmdline);
monitor_resume(mon);
}
@@ -5221,25 +5108,22 @@
return qobject_from_jsonf("{'QMP':{'version': %p,'capabilities': []}}",ver);
}
-/**
- * monitor_control_event(): Print QMP gretting
- */
-static void monitor_control_event(void *opaque, int event)
+static void monitor_qmp_event(void *opaque, int event)
{
QObject *data;
Monitor *mon = opaque;
switch (event) {
case CHR_EVENT_OPENED:
- mon->mc->command_mode = 0;
+ mon->qmp.in_command_mode = false;
data = get_qmp_greeting();
monitor_json_emitter(mon, data);
qobject_decref(data);
mon_refcount++;
break;
case CHR_EVENT_CLOSED:
- json_message_parser_destroy(&mon->mc->parser);
- json_message_parser_init(&mon->mc->parser, handle_qmp_command);
+ json_message_parser_destroy(&mon->qmp.parser);
+ json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
mon_refcount--;
monitor_fdsets_cleanup();
break;
@@ -5371,14 +5255,11 @@
monitor_read_command(mon, 0);
}
- if (monitor_ctrl_mode(mon)) {
- mon->mc = g_malloc0(sizeof(MonitorControl));
- /* Control mode requires special handlers */
- qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read,
- monitor_control_event, mon);
+ if (monitor_is_qmp(mon)) {
+ qemu_chr_add_handlers(chr, monitor_can_read, monitor_qmp_read,
+ monitor_qmp_event, mon);
qemu_chr_fe_set_echo(chr, true);
-
- json_message_parser_init(&mon->mc->parser, handle_qmp_command);
+ json_message_parser_init(&mon->qmp.parser, handle_qmp_command);
} else {
qemu_chr_add_handlers(chr, monitor_can_read, monitor_read,
monitor_event, mon);
diff --git a/net/slirp.c b/net/slirp.c
index 0e15cf6..3533837 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -481,7 +481,6 @@
static int slirp_smb(SlirpState* s, const char *exported_dir,
struct in_addr vserver_addr)
{
- static int instance;
char smb_conf[128];
char smb_cmdline[128];
struct passwd *passwd;
@@ -505,10 +504,10 @@
return -1;
}
- snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d",
- (long)getpid(), instance++);
- if (mkdir(s->smb_dir, 0700) < 0) {
+ snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.XXXXXX");
+ if (!mkdtemp(s->smb_dir)) {
error_report("could not create samba server dir '%s'", s->smb_dir);
+ s->smb_dir[0] = 0;
return -1;
}
snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf");
diff --git a/qapi-schema.json b/qapi-schema.json
index 0662a9b..6e17a5c 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -638,6 +638,25 @@
'returns': 'MigrationParameters' }
##
+# @client_migrate_info
+#
+# Set migration information for remote display. This makes the server
+# ask the client to automatically reconnect using the new parameters
+# once migration finished successfully. Only implemented for SPICE.
+#
+# @protocol: must be "spice"
+# @hostname: migration target hostname
+# @port: #optional spice tcp port for plaintext channels
+# @tls-port: #optional spice tcp port for tls-secured channels
+# @cert-subject: #optional server certificate subject
+#
+# Since: 0.14.0
+##
+{ 'command': 'client_migrate_info',
+ 'data': { 'protocol': 'str', 'hostname': 'str', '*port': 'int',
+ '*tls-port': 'int', '*cert-subject': 'str' } }
+
+##
# @MouseInfo:
#
# Information about a mouse device.
diff --git a/qemu-options.hx b/qemu-options.hx
index 7edd1f1..b3db6cb 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3239,7 +3239,9 @@
"-incoming fd:fd\n" \
"-incoming exec:cmdline\n" \
" accept incoming migration on given file descriptor\n" \
- " or from given external command\n",
+ " or from given external command\n" \
+ "-incoming defer\n" \
+ " wait for the URI to be specified via migrate_incoming\n",
QEMU_ARCH_ALL)
STEXI
@item -incoming tcp:[@var{host}]:@var{port}[,to=@var{maxport}][,ipv4][,ipv6]
@@ -3255,6 +3257,11 @@
@item -incoming exec:@var{cmdline}
Accept incoming migration as an output from specified external command.
+
+@item -incoming defer
+Wait for the URI to be specified via migrate_incoming. The monitor can
+be used to change settings (such as migration parameters) prior to issuing
+the migrate_incoming to allow the migration to begin.
ETEXI
DEF("nodefaults", 0, QEMU_OPTION_nodefaults, \
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 14e109e..867a21f 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -784,23 +784,23 @@
.name = "client_migrate_info",
.args_type = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
.params = "protocol hostname port tls-port cert-subject",
- .help = "send migration info to spice/vnc client",
- .mhandler.cmd_new = client_migrate_info,
+ .help = "set migration information for remote display",
+ .mhandler.cmd_new = qmp_marshal_input_client_migrate_info,
},
SQMP
client_migrate_info
-------------------
+-------------------
-Set the spice/vnc connection info for the migration target. The spice/vnc
-server will ask the spice/vnc client to automatically reconnect using the
-new parameters (if specified) once the vm migration finished successfully.
+Set migration information for remote display. This makes the server
+ask the client to automatically reconnect using the new parameters
+once migration finished successfully. Only implemented for SPICE.
Arguments:
-- "protocol": protocol: "spice" or "vnc" (json-string)
+- "protocol": must be "spice" (json-string)
- "hostname": migration target hostname (json-string)
-- "port": spice/vnc tcp port for plaintext channels (json-int, optional)
+- "port": spice tcp port for plaintext channels (json-int, optional)
- "tls-port": spice tcp port for tls-secured channels (json-int, optional)
- "cert-subject": server certificate subject (json-string, optional)
diff --git a/stubs/mon-is-qmp.c b/stubs/mon-is-qmp.c
index 1f0a8fd..1ef136a 100644
--- a/stubs/mon-is-qmp.c
+++ b/stubs/mon-is-qmp.c
@@ -1,7 +1,7 @@
#include "qemu-common.h"
#include "monitor/monitor.h"
-int monitor_cur_is_qmp(void)
+bool monitor_cur_is_qmp(void)
{
- return 0;
+ return false;
}
diff --git a/sysconfigs/target/target-x86_64.conf b/sysconfigs/target/target-x86_64.conf
deleted file mode 100644
index e69de29..0000000
--- a/sysconfigs/target/target-x86_64.conf
+++ /dev/null
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 1cc4993..3da0c05 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -294,23 +294,15 @@
return 0;
}
-static void cpreg_make_keylist(gpointer key, gpointer value, gpointer udata)
-{
- GList **plist = udata;
-
- *plist = g_list_prepend(*plist, key);
-}
-
void init_cpreg_list(ARMCPU *cpu)
{
/* Initialise the cpreg_tuples[] array based on the cp_regs hash.
* Note that we require cpreg_tuples[] to be sorted by key ID.
*/
- GList *keys = NULL;
+ GList *keys;
int arraylen;
- g_hash_table_foreach(cpu->cp_regs, cpreg_make_keylist, &keys);
-
+ keys = g_hash_table_get_keys(cpu->cp_regs);
keys = g_list_sort(keys, cpreg_key_compare);
cpu->cpreg_array_len = 0;
@@ -492,10 +484,16 @@
.writefn = dacr_write, .raw_writefn = raw_write,
.bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dacr_s),
offsetoflow32(CPUARMState, cp15.dacr_ns) } },
- /* ??? This covers not just the impdef TLB lockdown registers but also
- * some v7VMSA registers relating to TEX remap, so it is overly broad.
+ /* ARMv7 allocates a range of implementation defined TLB LOCKDOWN regs.
+ * For v6 and v5, these mappings are overly broad.
*/
- { .name = "TLB_LOCKDOWN", .cp = 15, .crn = 10, .crm = CP_ANY,
+ { .name = "TLB_LOCKDOWN", .cp = 15, .crn = 10, .crm = 0,
+ .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_NOP },
+ { .name = "TLB_LOCKDOWN", .cp = 15, .crn = 10, .crm = 1,
+ .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_NOP },
+ { .name = "TLB_LOCKDOWN", .cp = 15, .crn = 10, .crm = 4,
+ .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_NOP },
+ { .name = "TLB_LOCKDOWN", .cp = 15, .crn = 10, .crm = 8,
.opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_NOP },
/* Cache maintenance ops; some of this space may be overridden later. */
{ .name = "CACHEMAINT", .cp = 15, .crn = 7, .crm = CP_ANY,
@@ -555,6 +553,10 @@
{ .name = "TLBIMVAA", .cp = 15, .crn = 8, .crm = CP_ANY,
.opc1 = CP_ANY, .opc2 = 3, .access = PL1_W, .writefn = tlbimvaa_write,
.type = ARM_CP_NO_RAW },
+ { .name = "PRRR", .cp = 15, .crn = 10, .crm = 2,
+ .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_NOP },
+ { .name = "NMRR", .cp = 15, .crn = 10, .crm = 2,
+ .opc1 = 0, .opc2 = 1, .access = PL1_RW, .type = ARM_CP_NOP },
REGINFO_SENTINEL
};
@@ -1021,19 +1023,17 @@
.resetvalue = 0 },
/* For non-long-descriptor page tables these are PRRR and NMRR;
* regardless they still act as reads-as-written for QEMU.
- * The override is necessary because of the overly-broad TLB_LOCKDOWN
- * definition.
*/
/* MAIR0/1 are defined separately from their 64-bit counterpart which
* allows them to assign the correct fieldoffset based on the endianness
* handled in the field definitions.
*/
- { .name = "MAIR0", .state = ARM_CP_STATE_AA32, .type = ARM_CP_OVERRIDE,
+ { .name = "MAIR0", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0, .access = PL1_RW,
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.mair0_s),
offsetof(CPUARMState, cp15.mair0_ns) },
.resetfn = arm_cp_reset_ignore },
- { .name = "MAIR1", .state = ARM_CP_STATE_AA32, .type = ARM_CP_OVERRIDE,
+ { .name = "MAIR1", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 1, .access = PL1_RW,
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.mair1_s),
offsetof(CPUARMState, cp15.mair1_ns) },
@@ -2088,16 +2088,14 @@
};
static const ARMCPRegInfo lpae_cp_reginfo[] = {
- /* NOP AMAIR0/1: the override is because these clash with the rather
- * broadly specified TLB_LOCKDOWN entry in the generic cp_reginfo.
- */
+ /* NOP AMAIR0/1 */
{ .name = "AMAIR0", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_OVERRIDE,
+ .access = PL1_RW, .type = ARM_CP_CONST,
.resetvalue = 0 },
/* AMAIR1 is mapped to AMAIR_EL1[63:32] */
{ .name = "AMAIR1", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 1,
- .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_OVERRIDE,
+ .access = PL1_RW, .type = ARM_CP_CONST,
.resetvalue = 0 },
{ .name = "PAR", .cp = 15, .crm = 7, .opc1 = 0,
.access = PL1_RW, .type = ARM_CP_64BIT, .resetvalue = 0,
@@ -2362,6 +2360,14 @@
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2,
.access = PL1_W, .type = ARM_CP_NOP },
/* TLBI operations */
+ { .name = "TLBI_ALLE1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 4,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbiall_write },
+ { .name = "TLBI_ALLE1IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 4,
+ .access = PL2_W, .type = ARM_CP_NO_RAW,
+ .writefn = tlbiall_write },
{ .name = "TLBI_VMALLE1IS", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0,
.access = PL1_W, .type = ARM_CP_NO_RAW,
@@ -2498,7 +2504,7 @@
};
/* Used to describe the behaviour of EL2 regs when EL2 does not exist. */
-static const ARMCPRegInfo v8_el3_no_el2_cp_reginfo[] = {
+static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
{ .name = "VBAR_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 0, .opc2 = 0,
.access = PL2_RW,
@@ -2511,6 +2517,28 @@
{ .name = "CPTR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 2,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
+ { .name = "MAIR_EL2", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 4, .crn = 10, .crm = 2, .opc2 = 0,
+ .access = PL2_RW, .type = ARM_CP_CONST,
+ .resetvalue = 0 },
+ { .name = "HMAIR1", .state = ARM_CP_STATE_AA32,
+ .opc1 = 4, .crn = 10, .crm = 2, .opc2 = 1,
+ .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
+ { .name = "TCR_EL2", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 2,
+ .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
+ { .name = "SCTLR_EL2", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 0,
+ .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
+ { .name = "TPIDR_EL2", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 2,
+ .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
+ { .name = "TTBR0_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0,
+ .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
+ { .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2,
+ .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST,
+ .resetvalue = 0 },
REGINFO_SENTINEL
};
@@ -2539,7 +2567,7 @@
raw_write(env, ri, value);
}
-static const ARMCPRegInfo v8_el2_cp_reginfo[] = {
+static const ARMCPRegInfo el2_cp_reginfo[] = {
{ .name = "HCR_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0,
.access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hcr_el2),
@@ -2582,6 +2610,47 @@
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 2,
.access = PL2_RW, .accessfn = cptr_access, .resetvalue = 0,
.fieldoffset = offsetof(CPUARMState, cp15.cptr_el[2]) },
+ { .name = "MAIR_EL2", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 4, .crn = 10, .crm = 2, .opc2 = 0,
+ .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.mair_el[2]),
+ .resetvalue = 0 },
+ { .name = "HMAIR1", .state = ARM_CP_STATE_AA32,
+ .opc1 = 4, .crn = 10, .crm = 2, .opc2 = 1,
+ .access = PL2_RW, .type = ARM_CP_ALIAS,
+ .fieldoffset = offsetofhigh32(CPUARMState, cp15.mair_el[2]) },
+ { .name = "TCR_EL2", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 2,
+ .access = PL2_RW, .writefn = vmsa_tcr_el1_write,
+ .resetfn = vmsa_ttbcr_reset, .raw_writefn = raw_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.tcr_el[2]) },
+ { .name = "SCTLR_EL2", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 0,
+ .access = PL2_RW, .raw_writefn = raw_write, .writefn = sctlr_write,
+ .fieldoffset = offsetof(CPUARMState, cp15.sctlr_el[2]) },
+ { .name = "TPIDR_EL2", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 2,
+ .access = PL2_RW, .resetvalue = 0,
+ .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el[2]) },
+ { .name = "TTBR0_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0,
+ .access = PL2_RW, .resetvalue = 0,
+ .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2]) },
+ { .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2,
+ .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS,
+ .resetvalue = 0,
+ .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2]) },
+ { .name = "TLBI_ALLE2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 0,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbiall_write },
+ { .name = "TLBI_VAE2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 1,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbi_aa64_vaa_write },
+ { .name = "TLBI_VAE2IS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 1,
+ .type = ARM_CP_NO_RAW, .access = PL2_W,
+ .writefn = tlbi_aa64_vaa_write },
REGINFO_SENTINEL
};
@@ -3243,7 +3312,7 @@
define_arm_cp_regs(cpu, v8_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_EL2)) {
- define_arm_cp_regs(cpu, v8_el2_cp_reginfo);
+ define_arm_cp_regs(cpu, el2_cp_reginfo);
/* RVBAR_EL2 is only implemented if EL2 is the highest EL */
if (!arm_feature(env, ARM_FEATURE_EL3)) {
ARMCPRegInfo rvbar = {
@@ -3258,7 +3327,7 @@
* register the no_el2 reginfos.
*/
if (arm_feature(env, ARM_FEATURE_EL3)) {
- define_arm_cp_regs(cpu, v8_el3_no_el2_cp_reginfo);
+ define_arm_cp_regs(cpu, el3_no_el2_cp_reginfo);
}
}
if (arm_feature(env, ARM_FEATURE_EL3)) {
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index 16abbf1..548bfd7 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -600,3 +600,8 @@
{
return 0;
}
+
+int kvm_arch_msi_data_to_gsi(uint32_t data)
+{
+ return (data - 32) & 0xffff;
+}
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 3305e09..99ad551 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -2841,12 +2841,126 @@
}
}
+typedef struct BitProperty {
+ uint32_t *ptr;
+ uint32_t mask;
+} BitProperty;
+
+static void x86_cpu_get_bit_prop(Object *obj,
+ struct Visitor *v,
+ void *opaque,
+ const char *name,
+ Error **errp)
+{
+ BitProperty *fp = opaque;
+ bool value = (*fp->ptr & fp->mask) == fp->mask;
+ visit_type_bool(v, &value, name, errp);
+}
+
+static void x86_cpu_set_bit_prop(Object *obj,
+ struct Visitor *v,
+ void *opaque,
+ const char *name,
+ Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ BitProperty *fp = opaque;
+ Error *local_err = NULL;
+ bool value;
+
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
+ return;
+ }
+
+ visit_type_bool(v, &value, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ if (value) {
+ *fp->ptr |= fp->mask;
+ } else {
+ *fp->ptr &= ~fp->mask;
+ }
+}
+
+static void x86_cpu_release_bit_prop(Object *obj, const char *name,
+ void *opaque)
+{
+ BitProperty *prop = opaque;
+ g_free(prop);
+}
+
+/* Register a boolean property to get/set a single bit in a uint32_t field.
+ *
+ * The same property name can be registered multiple times to make it affect
+ * multiple bits in the same FeatureWord. In that case, the getter will return
+ * true only if all bits are set.
+ */
+static void x86_cpu_register_bit_prop(X86CPU *cpu,
+ const char *prop_name,
+ uint32_t *field,
+ int bitnr)
+{
+ BitProperty *fp;
+ ObjectProperty *op;
+ uint32_t mask = (1UL << bitnr);
+
+ op = object_property_find(OBJECT(cpu), prop_name, NULL);
+ if (op) {
+ fp = op->opaque;
+ assert(fp->ptr == field);
+ fp->mask |= mask;
+ } else {
+ fp = g_new0(BitProperty, 1);
+ fp->ptr = field;
+ fp->mask = mask;
+ object_property_add(OBJECT(cpu), prop_name, "bool",
+ x86_cpu_get_bit_prop,
+ x86_cpu_set_bit_prop,
+ x86_cpu_release_bit_prop, fp, &error_abort);
+ }
+}
+
+static void x86_cpu_register_feature_bit_props(X86CPU *cpu,
+ FeatureWord w,
+ int bitnr)
+{
+ Object *obj = OBJECT(cpu);
+ int i;
+ char **names;
+ FeatureWordInfo *fi = &feature_word_info[w];
+
+ if (!fi->feat_names) {
+ return;
+ }
+ if (!fi->feat_names[bitnr]) {
+ return;
+ }
+
+ names = g_strsplit(fi->feat_names[bitnr], "|", 0);
+
+ feat2prop(names[0]);
+ x86_cpu_register_bit_prop(cpu, names[0], &cpu->env.features[w], bitnr);
+
+ for (i = 1; names[i]; i++) {
+ feat2prop(names[i]);
+ object_property_add_alias(obj, names[i], obj, g_strdup(names[0]),
+ &error_abort);
+ }
+
+ g_strfreev(names);
+}
+
static void x86_cpu_initfn(Object *obj)
{
CPUState *cs = CPU(obj);
X86CPU *cpu = X86_CPU(obj);
X86CPUClass *xcc = X86_CPU_GET_CLASS(obj);
CPUX86State *env = &cpu->env;
+ FeatureWord w;
static int inited;
cs->env_ptr = env;
@@ -2887,6 +3001,14 @@
cpu->apic_id = -1;
#endif
+ for (w = 0; w < FEATURE_WORDS; w++) {
+ int bitnr;
+
+ for (bitnr = 0; bitnr < 32; bitnr++) {
+ x86_cpu_register_feature_bit_props(cpu, w, bitnr);
+ }
+ }
+
x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort);
/* init various static tables used in TCG mode */
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 4ee12ca..26182bd 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -305,7 +305,7 @@
#define MSR_IA32_APICBASE 0x1b
#define MSR_IA32_APICBASE_BSP (1<<8)
#define MSR_IA32_APICBASE_ENABLE (1<<11)
-#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
+#define MSR_IA32_APICBASE_BASE (0xfffffU<<12)
#define MSR_IA32_FEATURE_CONTROL 0x0000003a
#define MSR_TSC_ADJUST 0x0000003b
#define MSR_IA32_TSCDEADLINE 0x6e0
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index a26d25a..ca2da84 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -2766,3 +2766,8 @@
{
return 0;
}
+
+int kvm_arch_msi_data_to_gsi(uint32_t data)
+{
+ abort();
+}
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h
index 4ea04ac..d73e1c7 100644
--- a/target-microblaze/cpu.h
+++ b/target-microblaze/cpu.h
@@ -285,7 +285,6 @@
/* FIXME: MB uses variable pages down to 1K but linux only uses 4k. */
#define TARGET_PAGE_BITS 12
-#define MMAP_SHIFT TARGET_PAGE_BITS
#define TARGET_PHYS_ADDR_SPACE_BITS 32
#define TARGET_VIRT_ADDR_SPACE_BITS 32
diff --git a/target-mips/kvm.c b/target-mips/kvm.c
index 59eb111..948619f 100644
--- a/target-mips/kvm.c
+++ b/target-mips/kvm.c
@@ -696,3 +696,8 @@
{
return 0;
}
+
+int kvm_arch_msi_data_to_gsi(uint32_t data)
+{
+ abort();
+}
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 97a50b1..afb4696 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -2427,3 +2427,8 @@
{
return 0;
}
+
+int kvm_arch_msi_data_to_gsi(uint32_t data)
+{
+ return data & 0xffff;
+}
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 6de7759..2740ec4 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -2216,3 +2216,8 @@
route->u.adapter.adapter_id = pbdev->routes.adapter.adapter_id;
return 0;
}
+
+int kvm_arch_msi_data_to_gsi(uint32_t data)
+{
+ abort();
+}
diff --git a/translate-all.h b/translate-all.h
index 02832b2..b6a07bd 100644
--- a/translate-all.h
+++ b/translate-all.h
@@ -21,7 +21,6 @@
/* translate-all.c */
void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len);
-void cpu_unlink_tb(CPUState *cpu);
void tb_check_watchpoint(CPUState *cpu);
#endif /* TRANSLATE_ALL_H */
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 22c8c4c..f9ad34e 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -45,6 +45,12 @@
.name = "port",
.type = QEMU_OPT_STRING,
},{
+ .name = "localaddr",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "localport",
+ .type = QEMU_OPT_STRING,
+ },{
.name = "to",
.type = QEMU_OPT_NUMBER,
},{
diff --git a/vl.c b/vl.c
index 6c7e4e4..cdd81b4 100644
--- a/vl.c
+++ b/vl.c
@@ -4314,8 +4314,9 @@
/* init remote displays */
qemu_opts_foreach(qemu_find_opts("vnc"), vnc_init_func, NULL, 0);
if (show_vnc_port) {
- printf("VNC server running on `%s'\n",
- vnc_display_local_addr("default"));
+ char *ret = vnc_display_local_addr("default");
+ printf("VNC server running on `%s'\n", ret);
+ g_free(ret);
}
#endif
#ifdef CONFIG_SPICE