aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.objs1
-rw-r--r--accel/kvm/kvm-all.c5
-rw-r--r--accel/stubs/kvm-stub.c5
-rw-r--r--backends/trace-events0
-rw-r--r--hw/arm/aspeed_soc.c25
-rw-r--r--hw/arm/exynos4210.c4
-rw-r--r--hw/intc/arm_gic.c7
-rw-r--r--hw/misc/Makefile.objs2
-rw-r--r--hw/misc/exynos4210_rng.c277
-rw-r--r--hw/ppc/spapr.c95
-rw-r--r--hw/ppc/spapr_drc.c37
-rw-r--r--hw/ppc/spapr_pci.c47
-rw-r--r--hw/vfio/common.c6
-rw-r--r--hw/vfio/pci.c19
-rw-r--r--hw/vfio/platform.c1
-rw-r--r--include/hw/arm/aspeed_soc.h4
-rw-r--r--include/hw/ppc/spapr.h7
-rw-r--r--include/hw/ppc/spapr_drc.h3
-rw-r--r--include/hw/ppc/spapr_ovec.h1
-rw-r--r--include/hw/vfio/vfio-common.h1
-rw-r--r--include/sysemu/kvm.h11
-rw-r--r--target/arm/cpu.h3
-rw-r--r--target/arm/helper.c13
-rw-r--r--target/arm/kvm.c51
-rw-r--r--target/ppc/excp_helper.c1
-rw-r--r--target/ppc/kvm.c5
-rw-r--r--target/ppc/mmu-radix64.c67
-rw-r--r--target/ppc/mmu-radix64.h1
-rw-r--r--target/ppc/mmu_helper.c3
-rw-r--r--trace/control-target.c10
30 files changed, 569 insertions, 143 deletions
diff --git a/Makefile.objs b/Makefile.objs
index 3e24c320c3..bfd5a6ceb1 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -122,7 +122,6 @@ trace-events-subdirs += crypto
trace-events-subdirs += io
trace-events-subdirs += migration
trace-events-subdirs += block
-trace-events-subdirs += backends
trace-events-subdirs += chardev
trace-events-subdirs += hw/block
trace-events-subdirs += hw/block/dataplane
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 2eef7daa01..46ce479dc3 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2274,6 +2274,11 @@ int kvm_has_intx_set_mask(void)
return kvm_state->intx_set_mask;
}
+bool kvm_arm_supports_user_irq(void)
+{
+ return kvm_check_extension(kvm_state, KVM_CAP_ARM_USER_IRQ);
+}
+
#ifdef KVM_CAP_SET_GUEST_DEBUG
struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu,
target_ulong pc)
diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c
index ef0c7346af..3965c528d3 100644
--- a/accel/stubs/kvm-stub.c
+++ b/accel/stubs/kvm-stub.c
@@ -155,4 +155,9 @@ void kvm_init_cpu_signals(CPUState *cpu)
{
abort();
}
+
+bool kvm_arm_supports_user_irq(void)
+{
+ return false;
+}
#endif
diff --git a/backends/trace-events b/backends/trace-events
deleted file mode 100644
index e69de29bb2..0000000000
--- a/backends/trace-events
+++ /dev/null
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
index 4937e2bc83..3034849c80 100644
--- a/hw/arm/aspeed_soc.c
+++ b/hw/arm/aspeed_soc.c
@@ -62,6 +62,7 @@ static const AspeedSoCInfo aspeed_socs[] = {
.spi_bases = aspeed_soc_ast2400_spi_bases,
.fmc_typename = "aspeed.smc.fmc",
.spi_typename = aspeed_soc_ast2400_typenames,
+ .wdts_num = 2,
}, {
.name = "ast2400-a1",
.cpu_model = "arm926",
@@ -72,6 +73,7 @@ static const AspeedSoCInfo aspeed_socs[] = {
.spi_bases = aspeed_soc_ast2400_spi_bases,
.fmc_typename = "aspeed.smc.fmc",
.spi_typename = aspeed_soc_ast2400_typenames,
+ .wdts_num = 2,
}, {
.name = "ast2400",
.cpu_model = "arm926",
@@ -82,6 +84,7 @@ static const AspeedSoCInfo aspeed_socs[] = {
.spi_bases = aspeed_soc_ast2400_spi_bases,
.fmc_typename = "aspeed.smc.fmc",
.spi_typename = aspeed_soc_ast2400_typenames,
+ .wdts_num = 2,
}, {
.name = "ast2500-a1",
.cpu_model = "arm1176",
@@ -92,6 +95,7 @@ static const AspeedSoCInfo aspeed_socs[] = {
.spi_bases = aspeed_soc_ast2500_spi_bases,
.fmc_typename = "aspeed.smc.ast2500-fmc",
.spi_typename = aspeed_soc_ast2500_typenames,
+ .wdts_num = 3,
},
};
@@ -175,9 +179,11 @@ static void aspeed_soc_init(Object *obj)
object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
"ram-size", &error_abort);
- object_initialize(&s->wdt, sizeof(s->wdt), TYPE_ASPEED_WDT);
- object_property_add_child(obj, "wdt", OBJECT(&s->wdt), NULL);
- qdev_set_parent_bus(DEVICE(&s->wdt), sysbus_get_default());
+ for (i = 0; i < sc->info->wdts_num; i++) {
+ object_initialize(&s->wdt[i], sizeof(s->wdt[i]), TYPE_ASPEED_WDT);
+ object_property_add_child(obj, "wdt[*]", OBJECT(&s->wdt[i]), NULL);
+ qdev_set_parent_bus(DEVICE(&s->wdt[i]), sysbus_get_default());
+ }
object_initialize(&s->ftgmac100, sizeof(s->ftgmac100), TYPE_FTGMAC100);
object_property_add_child(obj, "ftgmac100", OBJECT(&s->ftgmac100), NULL);
@@ -300,12 +306,15 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE);
/* Watch dog */
- object_property_set_bool(OBJECT(&s->wdt), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
+ for (i = 0; i < sc->info->wdts_num; i++) {
+ object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0,
+ ASPEED_SOC_WDT_BASE + i * 0x20);
}
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, ASPEED_SOC_WDT_BASE);
/* Net */
qdev_set_nic_properties(DEVICE(&s->ftgmac100), &nd_table[0]);
diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c
index 0050626a69..ee851e3ae5 100644
--- a/hw/arm/exynos4210.c
+++ b/hw/arm/exynos4210.c
@@ -87,6 +87,9 @@
/* Clock controller SFR base address */
#define EXYNOS4210_CLK_BASE_ADDR 0x10030000
+/* PRNG/HASH SFR base address */
+#define EXYNOS4210_RNG_BASE_ADDR 0x10830400
+
/* Display controllers (FIMD) */
#define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000
@@ -305,6 +308,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem)
sysbus_create_simple("exynos4210.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL);
sysbus_create_simple("exynos4210.clk", EXYNOS4210_CLK_BASE_ADDR, NULL);
+ sysbus_create_simple("exynos4210.rng", EXYNOS4210_RNG_BASE_ADDR, NULL);
/* PWM */
sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR,
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index b305d9032a..5a0e2a3c1a 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -25,6 +25,7 @@
#include "qom/cpu.h"
#include "qemu/log.h"
#include "trace.h"
+#include "sysemu/kvm.h"
/* #define DEBUG_GIC */
@@ -1412,6 +1413,12 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
return;
}
+ if (kvm_enabled() && !kvm_arm_supports_user_irq()) {
+ error_setg(errp, "KVM with user space irqchip only works when the "
+ "host kernel supports KVM_CAP_ARM_USER_IRQ");
+ return;
+ }
+
/* This creates distributor and main CPU interface (s->cpuiomem[0]) */
gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops);
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 44e0e79ba7..7e373dbbff 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -28,7 +28,7 @@ obj-$(CONFIG_IVSHMEM) += ivshmem.o
obj-$(CONFIG_REALVIEW) += arm_sysctl.o
obj-$(CONFIG_NSERIES) += cbus.o
obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
-obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o exynos4210_clk.o
+obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o exynos4210_clk.o exynos4210_rng.o
obj-$(CONFIG_IMX) += imx_ccm.o
obj-$(CONFIG_IMX) += imx31_ccm.o
obj-$(CONFIG_IMX) += imx25_ccm.o
diff --git a/hw/misc/exynos4210_rng.c b/hw/misc/exynos4210_rng.c
new file mode 100644
index 0000000000..31ebe38e26
--- /dev/null
+++ b/hw/misc/exynos4210_rng.c
@@ -0,0 +1,277 @@
+/*
+ * Exynos4210 Pseudo Random Nubmer Generator Emulation
+ *
+ * Copyright (c) 2017 Krzysztof Kozlowski <krzk@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "crypto/random.h"
+#include "hw/sysbus.h"
+#include "qemu/log.h"
+
+#define DEBUG_EXYNOS_RNG 0
+
+#define DPRINTF(fmt, ...) \
+ do { \
+ if (DEBUG_EXYNOS_RNG) { \
+ printf("exynos4210_rng: " fmt, ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+#define TYPE_EXYNOS4210_RNG "exynos4210.rng"
+#define EXYNOS4210_RNG(obj) \
+ OBJECT_CHECK(Exynos4210RngState, (obj), TYPE_EXYNOS4210_RNG)
+
+/*
+ * Exynos4220, PRNG, only polling mode is supported.
+ */
+
+/* RNG_CONTROL_1 register bitfields, reset value: 0x0 */
+#define EXYNOS4210_RNG_CONTROL_1_PRNG 0x8
+#define EXYNOS4210_RNG_CONTROL_1_START_INIT BIT(4)
+/* RNG_STATUS register bitfields, reset value: 0x1 */
+#define EXYNOS4210_RNG_STATUS_PRNG_ERROR BIT(7)
+#define EXYNOS4210_RNG_STATUS_PRNG_DONE BIT(5)
+#define EXYNOS4210_RNG_STATUS_MSG_DONE BIT(4)
+#define EXYNOS4210_RNG_STATUS_PARTIAL_DONE BIT(3)
+#define EXYNOS4210_RNG_STATUS_PRNG_BUSY BIT(2)
+#define EXYNOS4210_RNG_STATUS_SEED_SETTING_DONE BIT(1)
+#define EXYNOS4210_RNG_STATUS_BUFFER_READY BIT(0)
+#define EXYNOS4210_RNG_STATUS_WRITE_MASK (EXYNOS4210_RNG_STATUS_PRNG_DONE \
+ | EXYNOS4210_RNG_STATUS_MSG_DONE \
+ | EXYNOS4210_RNG_STATUS_PARTIAL_DONE)
+
+#define EXYNOS4210_RNG_CONTROL_1 0x0
+#define EXYNOS4210_RNG_STATUS 0x10
+#define EXYNOS4210_RNG_SEED_IN 0x140
+#define EXYNOS4210_RNG_SEED_IN_OFFSET(n) (EXYNOS4210_RNG_SEED_IN + (n * 0x4))
+#define EXYNOS4210_RNG_PRNG 0x160
+#define EXYNOS4210_RNG_PRNG_OFFSET(n) (EXYNOS4210_RNG_PRNG + (n * 0x4))
+
+#define EXYNOS4210_RNG_PRNG_NUM 5
+
+#define EXYNOS4210_RNG_REGS_MEM_SIZE 0x200
+
+typedef struct Exynos4210RngState {
+ SysBusDevice parent_obj;
+ MemoryRegion iomem;
+
+ int32_t randr_value[EXYNOS4210_RNG_PRNG_NUM];
+ /* bits from 0 to EXYNOS4210_RNG_PRNG_NUM if given seed register was set */
+ uint32_t seed_set;
+
+ /* Register values */
+ uint32_t reg_control;
+ uint32_t reg_status;
+} Exynos4210RngState;
+
+static bool exynos4210_rng_seed_ready(const Exynos4210RngState *s)
+{
+ uint32_t mask = MAKE_64BIT_MASK(0, EXYNOS4210_RNG_PRNG_NUM);
+
+ /* Return true if all the seed-set bits are set. */
+ return (s->seed_set & mask) == mask;
+}
+
+static void exynos4210_rng_set_seed(Exynos4210RngState *s, unsigned int i,
+ uint64_t val)
+{
+ /*
+ * We actually ignore the seed and always generate true random numbers.
+ * Theoretically this should not match the device as Exynos has
+ * a Pseudo Random Number Generator but testing shown that it always
+ * generates random numbers regardless of the seed value.
+ */
+ s->seed_set |= BIT(i);
+
+ /* If all seeds were written, update the status to reflect it */
+ if (exynos4210_rng_seed_ready(s)) {
+ s->reg_status |= EXYNOS4210_RNG_STATUS_SEED_SETTING_DONE;
+ } else {
+ s->reg_status &= ~EXYNOS4210_RNG_STATUS_SEED_SETTING_DONE;
+ }
+}
+
+static void exynos4210_rng_run_engine(Exynos4210RngState *s)
+{
+ Error *err = NULL;
+ int ret;
+
+ /* Seed set? */
+ if ((s->reg_status & EXYNOS4210_RNG_STATUS_SEED_SETTING_DONE) == 0) {
+ goto out;
+ }
+
+ /* PRNG engine chosen? */
+ if ((s->reg_control & EXYNOS4210_RNG_CONTROL_1_PRNG) == 0) {
+ goto out;
+ }
+
+ /* PRNG engine started? */
+ if ((s->reg_control & EXYNOS4210_RNG_CONTROL_1_START_INIT) == 0) {
+ goto out;
+ }
+
+ /* Get randoms */
+ ret = qcrypto_random_bytes((uint8_t *)s->randr_value,
+ sizeof(s->randr_value), &err);
+ if (!ret) {
+ /* Notify that PRNG is ready */
+ s->reg_status |= EXYNOS4210_RNG_STATUS_PRNG_DONE;
+ } else {
+ error_report_err(err);
+ }
+
+out:
+ /* Always clear start engine bit */
+ s->reg_control &= ~EXYNOS4210_RNG_CONTROL_1_START_INIT;
+}
+
+static uint64_t exynos4210_rng_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ Exynos4210RngState *s = (Exynos4210RngState *)opaque;
+ uint32_t val = 0;
+
+ assert(size == 4);
+
+ switch (offset) {
+ case EXYNOS4210_RNG_CONTROL_1:
+ val = s->reg_control;
+ break;
+
+ case EXYNOS4210_RNG_STATUS:
+ val = s->reg_status;
+ break;
+
+ case EXYNOS4210_RNG_PRNG_OFFSET(0):
+ case EXYNOS4210_RNG_PRNG_OFFSET(1):
+ case EXYNOS4210_RNG_PRNG_OFFSET(2):
+ case EXYNOS4210_RNG_PRNG_OFFSET(3):
+ case EXYNOS4210_RNG_PRNG_OFFSET(4):
+ val = s->randr_value[(offset - EXYNOS4210_RNG_PRNG_OFFSET(0)) / 4];
+ DPRINTF("returning random @0x%" HWADDR_PRIx ": 0x%" PRIx32 "\n",
+ offset, val);
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad read offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ return val;
+}
+
+static void exynos4210_rng_write(void *opaque, hwaddr offset,
+ uint64_t val, unsigned size)
+{
+ Exynos4210RngState *s = (Exynos4210RngState *)opaque;
+
+ assert(size == 4);
+
+ switch (offset) {
+ case EXYNOS4210_RNG_CONTROL_1:
+ DPRINTF("RNG_CONTROL_1 = 0x%" PRIx64 "\n", val);
+ s->reg_control = val;
+ exynos4210_rng_run_engine(s);
+ break;
+
+ case EXYNOS4210_RNG_STATUS:
+ /* For clearing status fields */
+ s->reg_status &= ~EXYNOS4210_RNG_STATUS_WRITE_MASK;
+ s->reg_status |= val & EXYNOS4210_RNG_STATUS_WRITE_MASK;
+ break;
+
+ case EXYNOS4210_RNG_SEED_IN_OFFSET(0):
+ case EXYNOS4210_RNG_SEED_IN_OFFSET(1):
+ case EXYNOS4210_RNG_SEED_IN_OFFSET(2):
+ case EXYNOS4210_RNG_SEED_IN_OFFSET(3):
+ case EXYNOS4210_RNG_SEED_IN_OFFSET(4):
+ exynos4210_rng_set_seed(s,
+ (offset - EXYNOS4210_RNG_SEED_IN_OFFSET(0)) / 4,
+ val);
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad write offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+}
+
+static const MemoryRegionOps exynos4210_rng_ops = {
+ .read = exynos4210_rng_read,
+ .write = exynos4210_rng_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void exynos4210_rng_reset(DeviceState *dev)
+{
+ Exynos4210RngState *s = EXYNOS4210_RNG(dev);
+
+ s->reg_control = 0;
+ s->reg_status = EXYNOS4210_RNG_STATUS_BUFFER_READY;
+ memset(s->randr_value, 0, sizeof(s->randr_value));
+ s->seed_set = 0;
+}
+
+static void exynos4210_rng_init(Object *obj)
+{
+ Exynos4210RngState *s = EXYNOS4210_RNG(obj);
+ SysBusDevice *dev = SYS_BUS_DEVICE(obj);
+
+ memory_region_init_io(&s->iomem, obj, &exynos4210_rng_ops, s,
+ TYPE_EXYNOS4210_RNG, EXYNOS4210_RNG_REGS_MEM_SIZE);
+ sysbus_init_mmio(dev, &s->iomem);
+}
+
+static const VMStateDescription exynos4210_rng_vmstate = {
+ .name = TYPE_EXYNOS4210_RNG,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT32_ARRAY(randr_value, Exynos4210RngState,
+ EXYNOS4210_RNG_PRNG_NUM),
+ VMSTATE_UINT32(seed_set, Exynos4210RngState),
+ VMSTATE_UINT32(reg_status, Exynos4210RngState),
+ VMSTATE_UINT32(reg_control, Exynos4210RngState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void exynos4210_rng_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = exynos4210_rng_reset;
+ dc->vmsd = &exynos4210_rng_vmstate;
+}
+
+static const TypeInfo exynos4210_rng_info = {
+ .name = TYPE_EXYNOS4210_RNG,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Exynos4210RngState),
+ .instance_init = exynos4210_rng_init,
+ .class_init = exynos4210_rng_class_init,
+};
+
+static void exynos4210_rng_register(void)
+{
+ type_register_static(&exynos4210_rng_info);
+}
+
+type_init(exynos4210_rng_register)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 990772b633..d38563d9a4 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -778,6 +778,11 @@ static int spapr_dt_cas_updates(sPAPRMachineState *spapr, void *fdt,
}
}
+ /* /interrupt controller */
+ if (!spapr_ovec_test(ov5_updates, OV5_XIVE_EXPLOIT)) {
+ spapr_dt_xics(xics_max_server_number(), fdt, PHANDLE_XICP);
+ }
+
offset = fdt_path_offset(fdt, "/chosen");
if (offset < 0) {
offset = fdt_add_subnode(fdt, 0, "chosen");
@@ -801,7 +806,7 @@ int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
size -= sizeof(hdr);
- /* Create sceleton */
+ /* Create skeleton */
fdt_skel = g_malloc0(size);
_FDT((fdt_create(fdt_skel, size)));
_FDT((fdt_begin_node(fdt_skel, "")));
@@ -910,7 +915,8 @@ static void spapr_dt_ov5_platform_support(void *fdt, int chosen)
{
PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
- char val[2 * 3] = {
+ char val[2 * 4] = {
+ 23, 0x00, /* Xive mode: 0 = legacy (as in ISA 2.7), 1 = Exploitation */
24, 0x00, /* Hash/Radix, filled in below. */
25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
26, 0x40, /* Radix options: GTSE == yes. */
@@ -918,19 +924,19 @@ static void spapr_dt_ov5_platform_support(void *fdt, int chosen)
if (kvm_enabled()) {
if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
- val[1] = 0x80; /* OV5_MMU_BOTH */
+ val[3] = 0x80; /* OV5_MMU_BOTH */
} else if (kvmppc_has_cap_mmu_radix()) {
- val[1] = 0x40; /* OV5_MMU_RADIX_300 */
+ val[3] = 0x40; /* OV5_MMU_RADIX_300 */
} else {
- val[1] = 0x00; /* Hash */
+ val[3] = 0x00; /* Hash */
}
} else {
if (first_ppc_cpu->env.mmu_model & POWERPC_MMU_V3) {
/* V3 MMU supports both hash and radix (with dynamic switching) */
- val[1] = 0xC0;
+ val[3] = 0xC0;
} else {
/* Otherwise we can only do hash */
- val[1] = 0x00;
+ val[3] = 0x00;
}
}
_FDT(fdt_setprop(fdt, chosen, "ibm,arch-vec-5-platform-support",
@@ -1068,9 +1074,6 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr,
_FDT(fdt_setprop_cell(fdt, 0, "#address-cells", 2));
_FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));
- /* /interrupt controller */
- spapr_dt_xics(xics_max_server_number(), fdt, PHANDLE_XICP);
-
ret = spapr_populate_memory(spapr, fdt);
if (ret < 0) {
error_report("couldn't setup memory nodes in fdt");
@@ -1967,24 +1970,6 @@ static void spapr_boot_set(void *opaque, const char *boot_device,
machine->boot_order = g_strdup(boot_device);
}
-/*
- * Reset routine for LMB DR devices.
- *
- * Unlike PCI DR devices, LMB DR devices explicitly register this reset
- * routine. Reset for PCI DR devices will be handled by PHB reset routine
- * when it walks all its children devices. LMB devices reset occurs
- * as part of spapr_ppc_reset().
- */
-static void spapr_drc_reset(void *opaque)
-{
- sPAPRDRConnector *drc = opaque;
- DeviceState *d = DEVICE(drc);
-
- if (d) {
- device_reset(d);
- }
-}
-
static void spapr_create_lmb_dr_connectors(sPAPRMachineState *spapr)
{
MachineState *machine = MACHINE(spapr);
@@ -1993,13 +1978,11 @@ static void spapr_create_lmb_dr_connectors(sPAPRMachineState *spapr)
int i;
for (i = 0; i < nr_lmbs; i++) {
- sPAPRDRConnector *drc;
uint64_t addr;
addr = i * lmb_size + spapr->hotplug_memory.base;
- drc = spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_LMB,
- addr/lmb_size);
- qemu_register_reset(spapr_drc_reset, drc);
+ spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_LMB,
+ addr / lmb_size);
}
}
@@ -2093,11 +2076,8 @@ static void spapr_init_cpus(sPAPRMachineState *spapr)
int core_id = i * smp_threads;
if (mc->has_hotpluggable_cpus) {
- sPAPRDRConnector *drc =
- spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
- (core_id / smp_threads) * smt);
-
- qemu_register_reset(spapr_drc_reset, drc);
+ spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
+ (core_id / smp_threads) * smt);
}
if (i < boot_cores_nr) {
@@ -2624,6 +2604,7 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
int i, fdt_offset, fdt_size;
void *fdt;
uint64_t addr = addr_start;
+ Error *local_err = NULL;
for (i = 0; i < nr_lmbs; i++) {
drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
@@ -2634,7 +2615,18 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr_start, uint64_t size,
fdt_offset = spapr_populate_memory_node(fdt, node, addr,
SPAPR_MEMORY_BLOCK_SIZE);
- spapr_drc_attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, errp);
+ spapr_drc_attach(drc, dev, fdt, fdt_offset, &local_err);
+ if (local_err) {
+ while (addr > addr_start) {
+ addr -= SPAPR_MEMORY_BLOCK_SIZE;
+ drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
+ addr / SPAPR_MEMORY_BLOCK_SIZE);
+ spapr_drc_detach(drc, dev, NULL);
+ }
+ g_free(fdt);
+ error_propagate(errp, local_err);
+ return;
+ }
addr += SPAPR_MEMORY_BLOCK_SIZE;
}
/* send hotplug notification to the
@@ -2674,14 +2666,20 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
addr = object_property_get_uint(OBJECT(dimm),
PC_DIMM_ADDR_PROP, &local_err);
if (local_err) {
- pc_dimm_memory_unplug(dev, &ms->hotplug_memory, mr);
- goto out;
+ goto out_unplug;
}
spapr_add_lmbs(dev, addr, size, node,
spapr_ovec_test(ms->ov5_cas, OV5_HP_EVT),
- &error_abort);
+ &local_err);
+ if (local_err) {
+ goto out_unplug;
+ }
+
+ return;
+out_unplug:
+ pc_dimm_memory_unplug(dev, &ms->hotplug_memory, mr);
out:
error_propagate(errp, local_err);
}
@@ -2863,8 +2861,8 @@ out:
error_propagate(errp, local_err);
}
-void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
- sPAPRMachineState *spapr)
+static void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
+ sPAPRMachineState *spapr)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
DeviceClass *dc = DEVICE_GET_CLASS(cs);
@@ -2979,17 +2977,10 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
g_assert(drc || !mc->has_hotpluggable_cpus);
- /*
- * Setup CPU DT entries only for hotplugged CPUs. For boot time or
- * coldplugged CPUs DT entries are setup in spapr_build_fdt().
- */
- if (dev->hotplugged) {
- fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr);
- }
+ fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr);
if (drc) {
- spapr_drc_attach(drc, dev, fdt, fdt_offset, !dev->hotplugged,
- &local_err);
+ spapr_drc_attach(drc, dev, fdt, fdt_offset, &local_err);
if (local_err) {
g_free(fdt);
error_propagate(errp, local_err);
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index bd40b84cfc..f34355dad1 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -340,7 +340,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
}
void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
- int fdt_start_offset, bool coldplug, Error **errp)
+ int fdt_start_offset, Error **errp)
{
trace_spapr_drc_attach(spapr_drc_index(drc));
@@ -351,14 +351,11 @@ void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_PCI) {
g_assert(drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE);
}
- g_assert(fdt || coldplug);
-
- drc->dr_indicator = SPAPR_DR_INDICATOR_ACTIVE;
+ g_assert(fdt);
drc->dev = d;
drc->fdt = fdt;
drc->fdt_start_offset = fdt_start_offset;
- drc->configured = coldplug;
if (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI) {
drc->awaiting_allocation = true;
@@ -372,24 +369,9 @@ void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
static void spapr_drc_release(sPAPRDRConnector *drc)
{
- drc->dr_indicator = SPAPR_DR_INDICATOR_INACTIVE;
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- /* Calling release callbacks based on spapr_drc_type(drc). */
- switch (spapr_drc_type(drc)) {
- case SPAPR_DR_CONNECTOR_TYPE_CPU:
- spapr_core_release(drc->dev);
- break;
- case SPAPR_DR_CONNECTOR_TYPE_PCI:
- spapr_phb_remove_pci_device_cb(drc->dev);
- break;
- case SPAPR_DR_CONNECTOR_TYPE_LMB:
- spapr_lmb_release(drc->dev);
- break;
- case SPAPR_DR_CONNECTOR_TYPE_PHB:
- case SPAPR_DR_CONNECTOR_TYPE_VIO:
- default:
- g_assert(false);
- }
+ drck->release(drc->dev);
drc->awaiting_release = false;
g_free(drc->fdt);
@@ -430,9 +412,9 @@ static bool release_pending(sPAPRDRConnector *drc)
return drc->awaiting_release;
}
-static void reset(DeviceState *d)
+static void drc_reset(void *opaque)
{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
+ sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(opaque);
trace_spapr_drc_reset(spapr_drc_index(drc));
@@ -454,12 +436,14 @@ static void reset(DeviceState *d)
if (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI) {
drc->allocation_state = SPAPR_DR_ALLOCATION_STATE_USABLE;
}
+ drc->dr_indicator = SPAPR_DR_INDICATOR_ACTIVE;
} else {
/* Otherwise device is absent, but might be hotplugged */
drc->isolation_state = SPAPR_DR_ISOLATION_STATE_ISOLATED;
if (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI) {
drc->allocation_state = SPAPR_DR_ALLOCATION_STATE_UNUSABLE;
}
+ drc->dr_indicator = SPAPR_DR_INDICATOR_INACTIVE;
}
}
@@ -540,6 +524,7 @@ static void realize(DeviceState *d, Error **errp)
g_free(child_name);
vmstate_register(DEVICE(drc), spapr_drc_index(drc), &vmstate_spapr_drc,
drc);
+ qemu_register_reset(drc_reset, drc);
trace_spapr_drc_realize_complete(spapr_drc_index(drc));
}
@@ -598,7 +583,6 @@ static void spapr_dr_connector_class_init(ObjectClass *k, void *data)
DeviceClass *dk = DEVICE_CLASS(k);
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
- dk->reset = reset;
dk->realize = realize;
dk->unrealize = unrealize;
drck->release_pending = release_pending;
@@ -633,6 +617,7 @@ static void spapr_drc_cpu_class_init(ObjectClass *k, void *data)
drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_CPU;
drck->typename = "CPU";
drck->drc_name_prefix = "CPU ";
+ drck->release = spapr_core_release;
}
static void spapr_drc_pci_class_init(ObjectClass *k, void *data)
@@ -642,6 +627,7 @@ static void spapr_drc_pci_class_init(ObjectClass *k, void *data)
drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_PCI;
drck->typename = "28";
drck->drc_name_prefix = "C";
+ drck->release = spapr_phb_remove_pci_device_cb;
}
static void spapr_drc_lmb_class_init(ObjectClass *k, void *data)
@@ -651,6 +637,7 @@ static void spapr_drc_lmb_class_init(ObjectClass *k, void *data)
drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_LMB;
drck->typename = "MEM";
drck->drc_name_prefix = "LMB ";
+ drck->release = spapr_lmb_release;
}
static const TypeInfo spapr_dr_connector_info = {
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 3b37dcdc09..a52dcf8ec0 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1388,8 +1388,8 @@ static uint32_t spapr_phb_get_pci_drc_index(sPAPRPHBState *phb,
return spapr_drc_index(drc);
}
-static void spapr_phb_hot_plug_child(HotplugHandler *plug_handler,
- DeviceState *plugged_dev, Error **errp)
+static void spapr_pci_plug(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev, Error **errp)
{
sPAPRPHBState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
PCIDevice *pdev = PCI_DEVICE(plugged_dev);
@@ -1435,8 +1435,7 @@ static void spapr_phb_hot_plug_child(HotplugHandler *plug_handler,
goto out;
}
- spapr_drc_attach(drc, DEVICE(pdev), fdt, fdt_start_offset,
- !plugged_dev->hotplugged, &local_err);
+ spapr_drc_attach(drc, DEVICE(pdev), fdt, fdt_start_offset, &local_err);
if (local_err) {
goto out;
}
@@ -1470,8 +1469,8 @@ out:
}
}
-static void spapr_phb_hot_unplug_child(HotplugHandler *plug_handler,
- DeviceState *plugged_dev, Error **errp)
+static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev, Error **errp)
{
sPAPRPHBState *phb = SPAPR_PCI_HOST_BRIDGE(DEVICE(plug_handler));
PCIDevice *pdev = PCI_DEVICE(plugged_dev);
@@ -1486,6 +1485,7 @@ static void spapr_phb_hot_unplug_child(HotplugHandler *plug_handler,
}
g_assert(drc);
+ g_assert(drc->dev == plugged_dev);
drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
if (!drck->release_pending(drc)) {
@@ -1745,7 +1745,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
}
/* DMA setup */
- if ((sphb->page_size_mask & qemu_getrampagesize()) == 0) {
+ if (((sphb->page_size_mask & qemu_getrampagesize()) == 0)
+ && kvm_enabled()) {
error_report("System page size 0x%lx is not enabled in page_size_mask "
"(0x%"PRIx64"). Performance may be slow",
qemu_getrampagesize(), sphb->page_size_mask);
@@ -1873,20 +1874,6 @@ static void spapr_pci_pre_save(void *opaque)
gpointer key, value;
int i;
- g_free(sphb->msi_devs);
- sphb->msi_devs = NULL;
- sphb->msi_devs_num = g_hash_table_size(sphb->msi);
- if (!sphb->msi_devs_num) {
- return;
- }
- sphb->msi_devs = g_malloc(sphb->msi_devs_num * sizeof(spapr_pci_msi_mig));
-
- g_hash_table_iter_init(&iter, sphb->msi);
- for (i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) {
- sphb->msi_devs[i].key = *(uint32_t *) key;
- sphb->msi_devs[i].value = *(spapr_pci_msi *) value;
- }
-
if (sphb->pre_2_8_migration) {
sphb->mig_liobn = sphb->dma_liobn[0];
sphb->mig_mem_win_addr = sphb->mem_win_addr;
@@ -1900,6 +1887,20 @@ static void spapr_pci_pre_save(void *opaque)
sphb->mig_mem_win_size += sphb->mem64_win_size;
}
}
+
+ g_free(sphb->msi_devs);
+ sphb->msi_devs = NULL;
+ sphb->msi_devs_num = g_hash_table_size(sphb->msi);
+ if (!sphb->msi_devs_num) {
+ return;
+ }
+ sphb->msi_devs = g_malloc(sphb->msi_devs_num * sizeof(spapr_pci_msi_mig));
+
+ g_hash_table_iter_init(&iter, sphb->msi);
+ for (i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) {
+ sphb->msi_devs[i].key = *(uint32_t *) key;
+ sphb->msi_devs[i].value = *(spapr_pci_msi *) value;
+ }
}
static int spapr_pci_post_load(void *opaque, int version_id)
@@ -1973,8 +1974,8 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
/* Supported by TYPE_SPAPR_MACHINE */
dc->user_creatable = true;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- hp->plug = spapr_phb_hot_plug_child;
- hp->unplug = spapr_phb_hot_unplug_child;
+ hp->plug = spapr_pci_plug;
+ hp->unplug_request = spapr_pci_unplug_request;
}
static const TypeInfo spapr_phb_info = {
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index b9abe77f5a..29923e4990 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -858,13 +858,15 @@ void vfio_reset_handler(void *opaque)
QLIST_FOREACH(group, &vfio_group_list, next) {
QLIST_FOREACH(vbasedev, &group->device_list, next) {
- vbasedev->ops->vfio_compute_needs_reset(vbasedev);
+ if (vbasedev->dev->realized) {
+ vbasedev->ops->vfio_compute_needs_reset(vbasedev);
+ }
}
}
QLIST_FOREACH(group, &vfio_group_list, next) {
QLIST_FOREACH(vbasedev, &group->device_list, next) {
- if (vbasedev->needs_reset) {
+ if (vbasedev->dev->realized && vbasedev->needs_reset) {
vbasedev->ops->vfio_hot_reset_multi(vbasedev);
}
}
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 8de8272e96..d4051cb951 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -1743,6 +1743,18 @@ static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size,
PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
}
+ /*
+ * Intel 82599 SR-IOV VFs report an invalid PCIe capability version 0
+ * (Niantic errate #35) causing Windows to error with a Code 10 for the
+ * device on Q35. Fixup any such devices to report version 1. If we
+ * were to remove the capability entirely the guest would lose extended
+ * config space.
+ */
+ if ((flags & PCI_EXP_FLAGS_VERS) == 0) {
+ vfio_add_emulated_word(vdev, pos + PCI_CAP_FLAGS,
+ 1, PCI_EXP_FLAGS_VERS);
+ }
+
pos = pci_add_capability(&vdev->pdev, PCI_CAP_ID_EXP, pos, size,
errp);
if (pos < 0) {
@@ -2116,7 +2128,8 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single)
/* Prep dependent devices for reset and clear our marker. */
QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
- if (vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) {
+ if (!vbasedev_iter->dev->realized ||
+ vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) {
continue;
}
tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev);
@@ -2197,7 +2210,8 @@ out:
}
QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
- if (vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) {
+ if (!vbasedev_iter->dev->realized ||
+ vbasedev_iter->type != VFIO_DEVICE_TYPE_PCI) {
continue;
}
tmp = container_of(vbasedev_iter, VFIOPCIDevice, vbasedev);
@@ -2647,6 +2661,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
vdev->vbasedev.name = g_strdup(basename(vdev->vbasedev.sysfsdev));
vdev->vbasedev.ops = &vfio_pci_ops;
vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI;
+ vdev->vbasedev.dev = &vdev->pdev.qdev;
tmp = g_strdup_printf("%s/iommu_group", vdev->vbasedev.sysfsdev);
len = readlink(tmp, group_path, sizeof(group_path));
diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c
index a4663c918e..7c09deda61 100644
--- a/hw/vfio/platform.c
+++ b/hw/vfio/platform.c
@@ -640,6 +640,7 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp)
int i, ret;
vbasedev->type = VFIO_DEVICE_TYPE_PLATFORM;
+ vbasedev->dev = dev;
vbasedev->ops = &vfio_platform_ops;
trace_vfio_platform_realize(vbasedev->sysfsdev ?
diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
index 4c5fc66a1e..0b88baaad0 100644
--- a/include/hw/arm/aspeed_soc.h
+++ b/include/hw/arm/aspeed_soc.h
@@ -23,6 +23,7 @@
#include "hw/net/ftgmac100.h"
#define ASPEED_SPIS_NUM 2
+#define ASPEED_WDTS_NUM 3
typedef struct AspeedSoCState {
/*< private >*/
@@ -39,7 +40,7 @@ typedef struct AspeedSoCState {
AspeedSMCState fmc;
AspeedSMCState spi[ASPEED_SPIS_NUM];
AspeedSDMCState sdmc;
- AspeedWDTState wdt;
+ AspeedWDTState wdt[ASPEED_WDTS_NUM];
FTGMAC100State ftgmac100;
} AspeedSoCState;
@@ -56,6 +57,7 @@ typedef struct AspeedSoCInfo {
const hwaddr *spi_bases;
const char *fmc_typename;
const char **spi_typename;
+ int wdts_num;
} AspeedSoCInfo;
typedef struct AspeedSoCClass {
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index a66bbac352..a184ffab0e 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -377,9 +377,8 @@ struct sPAPRMachineState {
* as well.
*
* We also need some hcalls which are specific to qemu / KVM-on-POWER.
- * So far we just need one for H_RTAS, but in future we'll need more
- * for extensions like virtio. We put those into the 0xf000-0xfffc
- * range which is reserved by PAPR for "platform-specific" hcalls.
+ * We put those into the 0xf000-0xfffc range which is reserved by PAPR
+ * for "platform-specific" hcalls.
*/
#define KVMPPC_HCALL_BASE 0xf000
#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0)
@@ -640,8 +639,6 @@ void spapr_hotplug_req_add_by_count_indexed(sPAPRDRConnectorType drc_type,
void spapr_hotplug_req_remove_by_count_indexed(sPAPRDRConnectorType drc_type,
uint32_t count, uint32_t index);
void spapr_cpu_parse_features(sPAPRMachineState *spapr);
-void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
- sPAPRMachineState *spapr);
/* CPU and LMB DRC release callbacks. */
void spapr_core_release(DeviceState *dev);
diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h
index d9cacb368f..d15e9eb3b4 100644
--- a/include/hw/ppc/spapr_drc.h
+++ b/include/hw/ppc/spapr_drc.h
@@ -217,6 +217,7 @@ typedef struct sPAPRDRConnectorClass {
sPAPRDREntitySense (*dr_entity_sense)(sPAPRDRConnector *drc);
uint32_t (*isolate)(sPAPRDRConnector *drc);
uint32_t (*unisolate)(sPAPRDRConnector *drc);
+ void (*release)(DeviceState *dev);
/* QEMU interfaces for managing hotplug operations */
bool (*release_pending)(sPAPRDRConnector *drc);
@@ -233,7 +234,7 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
uint32_t drc_type_mask);
void spapr_drc_attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
- int fdt_start_offset, bool coldplug, Error **errp);
+ int fdt_start_offset, Error **errp);
void spapr_drc_detach(sPAPRDRConnector *drc, DeviceState *d, Error **errp);
#endif /* HW_SPAPR_DRC_H */
diff --git a/include/hw/ppc/spapr_ovec.h b/include/hw/ppc/spapr_ovec.h
index f088833204..0b464e22e7 100644
--- a/include/hw/ppc/spapr_ovec.h
+++ b/include/hw/ppc/spapr_ovec.h
@@ -50,6 +50,7 @@ typedef struct sPAPROptionVector sPAPROptionVector;
#define OV5_DRCONF_MEMORY OV_BIT(2, 2)
#define OV5_FORM1_AFFINITY OV_BIT(5, 0)
#define OV5_HP_EVT OV_BIT(6, 5)
+#define OV5_XIVE_EXPLOIT OV_BIT(23, 7)
/* ISA 3.00 MMU features: */
#define OV5_MMU_BOTH OV_BIT(24, 0) /* Radix and hash */
diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index 9521013d52..0b475a3596 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -115,6 +115,7 @@ typedef struct VFIODevice {
struct VFIOGroup *group;
char *sysfsdev;
char *name;
+ DeviceState *dev;
int fd;
int type;
bool reset_works;
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 052e11f621..91fc07ee9a 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -220,6 +220,17 @@ int kvm_init_vcpu(CPUState *cpu);
int kvm_cpu_exec(CPUState *cpu);
int kvm_destroy_vcpu(CPUState *cpu);
+/**
+ * kvm_arm_supports_user_irq
+ *
+ * Not all KVM implementations support notifications for kernel generated
+ * interrupt events to user space. This function indicates whether the current
+ * KVM implementation does support them.
+ *
+ * Returns: true if KVM supports using kernel generated IRQs from user space
+ */
+bool kvm_arm_supports_user_irq(void);
+
#ifdef NEED_CPU_H
#include "cpu.h"
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 16a1e59615..102c58afac 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -706,6 +706,9 @@ struct ARMCPU {
void *el_change_hook_opaque;
int32_t node_id; /* NUMA node this CPU belongs to */
+
+ /* Used to synchronize KVM and QEMU in-kernel device levels */
+ uint8_t device_irq_level;
};
static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 2594faa9b8..4ed32c56b8 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -8768,9 +8768,16 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
}
break;
case 20: /* CONTROL */
- switch_v7m_sp(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
- env->v7m.control = val & (R_V7M_CONTROL_SPSEL_MASK |
- R_V7M_CONTROL_NPRIV_MASK);
+ /* Writing to the SPSEL bit only has an effect if we are in
+ * thread mode; other bits can be updated by any privileged code.
+ * switch_v7m_sp() deals with updating the SPSEL bit in
+ * env->v7m.control, so we only need update the others.
+ */
+ if (env->v7m.exception == 0) {
+ switch_v7m_sp(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
+ }
+ env->v7m.control &= ~R_V7M_CONTROL_NPRIV_MASK;
+ env->v7m.control |= val & R_V7M_CONTROL_NPRIV_MASK;
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special"
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 45554682f2..7c17f0d629 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -174,6 +174,12 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
*/
kvm_async_interrupts_allowed = true;
+ /*
+ * PSCI wakes up secondary cores, so we always need to
+ * have vCPUs waiting in kernel space
+ */
+ kvm_halt_in_kernel_allowed = true;
+
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
type_register_static(&host_arm_cpu_type_info);
@@ -528,6 +534,51 @@ void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
{
+ ARMCPU *cpu;
+ uint32_t switched_level;
+
+ if (kvm_irqchip_in_kernel()) {
+ /*
+ * We only need to sync timer states with user-space interrupt
+ * controllers, so return early and save cycles if we don't.
+ */
+ return MEMTXATTRS_UNSPECIFIED;
+ }
+
+ cpu = ARM_CPU(cs);
+
+ /* Synchronize our shadowed in-kernel device irq lines with the kvm ones */
+ if (run->s.regs.device_irq_level != cpu->device_irq_level) {
+ switched_level = cpu->device_irq_level ^ run->s.regs.device_irq_level;
+
+ qemu_mutex_lock_iothread();
+
+ if (switched_level & KVM_ARM_DEV_EL1_VTIMER) {
+ qemu_set_irq(cpu->gt_timer_outputs[GTIMER_VIRT],
+ !!(run->s.regs.device_irq_level &
+ KVM_ARM_DEV_EL1_VTIMER));
+ switched_level &= ~KVM_ARM_DEV_EL1_VTIMER;
+ }
+
+ if (switched_level & KVM_ARM_DEV_EL1_PTIMER) {
+ qemu_set_irq(cpu->gt_timer_outputs[GTIMER_PHYS],
+ !!(run->s.regs.device_irq_level &
+ KVM_ARM_DEV_EL1_PTIMER));
+ switched_level &= ~KVM_ARM_DEV_EL1_PTIMER;
+ }
+
+ /* XXX PMU IRQ is missing */
+
+ if (switched_level) {
+ qemu_log_mask(LOG_UNIMP, "%s: unhandled in-kernel device IRQ %x\n",
+ __func__, switched_level);
+ }
+
+ /* We also mark unknown levels as processed to not waste cycles */
+ cpu->device_irq_level = run->s.regs.device_irq_level;
+ qemu_mutex_unlock_iothread();
+ }
+
return MEMTXATTRS_UNSPECIFIED;
}
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 3a9f0861e7..e6009e70e5 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -283,6 +283,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
* precise in the MSR.
*/
msr |= 0x00100000;
+ env->spr[SPR_BOOKE_ESR] = ESR_FP;
break;
case POWERPC_EXCP_INVAL:
LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index f2f7c531bc..f7a7ea5858 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -2445,6 +2445,7 @@ static int kvm_ppc_register_host_cpu_type(void)
.class_init = kvmppc_host_cpu_class_init,
};
PowerPCCPUClass *pvr_pcc;
+ ObjectClass *oc;
DeviceClass *dc;
int i;
@@ -2455,6 +2456,9 @@ static int kvm_ppc_register_host_cpu_type(void)
type_info.parent = object_class_get_name(OBJECT_CLASS(pvr_pcc));
type_register(&type_info);
+ oc = object_class_by_name(type_info.name);
+ g_assert(oc);
+
#if defined(TARGET_PPC64)
type_info.name = g_strdup_printf("%s-"TYPE_SPAPR_CPU_CORE, "host");
type_info.parent = TYPE_SPAPR_CPU_CORE,
@@ -2474,7 +2478,6 @@ static int kvm_ppc_register_host_cpu_type(void)
dc = DEVICE_CLASS(ppc_cpu_get_family_class(pvr_pcc));
for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) {
if (strcmp(ppc_cpu_aliases[i].alias, dc->desc) == 0) {
- ObjectClass *oc = OBJECT_CLASS(pvr_pcc);
char *suffix;
ppc_cpu_aliases[i].model = g_strdup(object_class_get_name(oc));
diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
index 69fde65276..bbd37e3c7d 100644
--- a/target/ppc/mmu-radix64.c
+++ b/target/ppc/mmu-radix64.c
@@ -147,11 +147,10 @@ static void ppc_radix64_set_rc(PowerPCCPU *cpu, int rwx, uint64_t pte,
}
}
-static uint64_t ppc_radix64_walk_tree(PowerPCCPU *cpu, int rwx, vaddr eaddr,
+static uint64_t ppc_radix64_walk_tree(PowerPCCPU *cpu, vaddr eaddr,
uint64_t base_addr, uint64_t nls,
hwaddr *raddr, int *psize,
- int *fault_cause, int *prot,
- hwaddr *pte_addr)
+ int *fault_cause, hwaddr *pte_addr)
{
CPUState *cs = CPU(cpu);
uint64_t index, pde;
@@ -177,10 +176,6 @@ static uint64_t ppc_radix64_walk_tree(PowerPCCPU *cpu, int rwx, vaddr eaddr,
uint64_t rpn = pde & R_PTE_RPN;
uint64_t mask = (1UL << *psize) - 1;
- if (ppc_radix64_check_prot(cpu, rwx, pde, fault_cause, prot)) {
- return 0; /* Protection Denied Access */
- }
-
/* Or high bits of rpn and low bits to ea to form whole real addr */
*raddr = (rpn & ~mask) | (eaddr & mask);
*pte_addr = base_addr + (index * sizeof(pde));
@@ -188,9 +183,8 @@ static uint64_t ppc_radix64_walk_tree(PowerPCCPU *cpu, int rwx, vaddr eaddr,
}
/* Next Level of Radix Tree */
- return ppc_radix64_walk_tree(cpu, rwx, eaddr, pde & R_PDE_NLB,
- pde & R_PDE_NLS, raddr, psize,
- fault_cause, prot, pte_addr);
+ return ppc_radix64_walk_tree(cpu, eaddr, pde & R_PDE_NLB, pde & R_PDE_NLS,
+ raddr, psize, fault_cause, pte_addr);
}
int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
@@ -241,11 +235,11 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
/* Walk Radix Tree from Process Table Entry to Convert EA to RA */
page_size = PRTBE_R_GET_RTS(prtbe0);
- pte = ppc_radix64_walk_tree(cpu, rwx, eaddr & R_EADDR_MASK,
+ pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK,
prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
- &raddr, &page_size, &fault_cause, &prot,
- &pte_addr);
- if (!pte) {
+ &raddr, &page_size, &fault_cause, &pte_addr);
+ if (!pte || ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, &prot)) {
+ /* Couldn't get pte or access denied due to protection */
ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
return 1;
}
@@ -257,3 +251,48 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
prot, mmu_idx, 1UL << page_size);
return 0;
}
+
+hwaddr ppc_radix64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong eaddr)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ hwaddr raddr, pte_addr;
+ uint64_t lpid = 0, pid = 0, offset, size, patbe, prtbe0, pte;
+ int page_size, fault_cause = 0;
+
+ /* Handle Real Mode */
+ if (msr_dr == 0) {
+ /* In real mode top 4 effective addr bits (mostly) ignored */
+ return eaddr & 0x0FFFFFFFFFFFFFFFULL;
+ }
+
+ /* Virtual Mode Access - get the fully qualified address */
+ if (!ppc_radix64_get_fully_qualified_addr(env, eaddr, &lpid, &pid)) {
+ return -1;
+ }
+
+ /* Get Process Table */
+ patbe = vhc->get_patbe(cpu->vhyp);
+
+ /* Index Process Table by PID to Find Corresponding Process Table Entry */
+ offset = pid * sizeof(struct prtb_entry);
+ size = 1ULL << ((patbe & PATBE1_R_PRTS) + 12);
+ if (offset >= size) {
+ /* offset exceeds size of the process table */
+ return -1;
+ }
+ prtbe0 = ldq_phys(cs->as, (patbe & PATBE1_R_PRTB) + offset);
+
+ /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
+ page_size = PRTBE_R_GET_RTS(prtbe0);
+ pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK,
+ prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
+ &raddr, &page_size, &fault_cause, &pte_addr);
+ if (!pte) {
+ return -1;
+ }
+
+ return raddr & TARGET_PAGE_MASK;
+}
diff --git a/target/ppc/mmu-radix64.h b/target/ppc/mmu-radix64.h
index 1d5c7cfea5..0ecf063a17 100644
--- a/target/ppc/mmu-radix64.h
+++ b/target/ppc/mmu-radix64.h
@@ -46,6 +46,7 @@
int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
int mmu_idx);
+hwaddr ppc_radix64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr);
static inline int ppc_radix64_get_prot_eaa(uint64_t pte)
{
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index 65d1c8692d..b7b9088842 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -30,6 +30,7 @@
#include "helper_regs.h"
#include "qemu/error-report.h"
#include "mmu-book3s-v3.h"
+#include "mmu-radix64.h"
//#define DEBUG_MMU
//#define DEBUG_BATS
@@ -1432,7 +1433,7 @@ hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
return ppc_hash64_get_phys_page_debug(cpu, addr);
case POWERPC_MMU_VER_3_00:
if (ppc64_radix_guest(ppc_env_get_cpu(env))) {
- /* TODO - Unsupported */
+ return ppc_radix64_get_phys_page_debug(cpu, addr);
} else {
return ppc_hash64_get_phys_page_debug(cpu, addr);
}
diff --git a/trace/control-target.c b/trace/control-target.c
index 6266e6380d..99a8ed5157 100644
--- a/trace/control-target.c
+++ b/trace/control-target.c
@@ -1,7 +1,7 @@
/*
* Interface for configuring and controlling the state of tracing events.
*
- * Copyright (C) 2014-2016 Lluís Vilanova <vilanova@ac.upc.edu>
+ * Copyright (C) 2014-2017 Lluís Vilanova <vilanova@ac.upc.edu>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@@ -38,12 +38,16 @@ void trace_event_set_state_dynamic(TraceEvent *ev, bool state)
{
CPUState *vcpu;
assert(trace_event_get_state_static(ev));
- if (trace_event_is_vcpu(ev)) {
+ if (trace_event_is_vcpu(ev) && likely(first_cpu != NULL)) {
CPU_FOREACH(vcpu) {
trace_event_set_vcpu_state_dynamic(vcpu, ev, state);
}
} else {
- /* Without the "vcpu" property, dstate can only be 1 or 0 */
+ /*
+ * Without the "vcpu" property, dstate can only be 1 or 0. With it, we
+ * haven't instantiated any vCPU yet, so we will set a global state
+ * instead, and trace_init_vcpu will reconcile it afterwards.
+ */
bool state_pre = *ev->dstate;
if (state_pre != state) {
if (state) {