aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/acpi/core.c4
-rw-r--r--hw/acpi/cpu.c2
-rw-r--r--hw/acpi/memory_hotplug.c2
-rw-r--r--hw/acpi/vmgenid.c2
-rw-r--r--hw/arm/Makefile.objs2
-rw-r--r--hw/arm/armv7m.c35
-rw-r--r--hw/arm/boot.c119
-rw-r--r--hw/arm/iotkit.c598
-rw-r--r--hw/arm/mps2-tz.c503
-rw-r--r--hw/arm/vexpress.c6
-rw-r--r--hw/arm/xlnx-zynqmp.c14
-rw-r--r--hw/block/block.c1
-rw-r--r--hw/block/hd-geometry.c1
-rw-r--r--hw/char/virtio-console.c2
-rw-r--r--hw/core/Makefile.objs1
-rw-r--r--hw/core/loader.c8
-rw-r--r--hw/core/machine.c2
-rw-r--r--hw/core/qdev.c10
-rw-r--r--hw/core/register.c8
-rw-r--r--hw/core/split-irq.c89
-rw-r--r--hw/display/Makefile.objs1
-rw-r--r--hw/display/g364fb.c1
-rw-r--r--hw/display/sii9022.c191
-rw-r--r--hw/display/trace-events5
-rw-r--r--hw/i2c/core.c18
-rw-r--r--hw/i2c/i2c-ddc.c4
-rw-r--r--hw/i386/intel_iommu.c11
-rw-r--r--hw/i386/multiboot.c77
-rw-r--r--hw/i386/pc.c19
-rw-r--r--hw/i386/pc_piix.c4
-rw-r--r--hw/i386/pc_q35.c3
-rw-r--r--hw/i386/xen/xen-hvm.c2
-rw-r--r--hw/ide/core.c10
-rw-r--r--hw/input/adb-kbd.c4
-rw-r--r--hw/input/adb-mouse.c5
-rw-r--r--hw/input/trace-events5
-rw-r--r--hw/intc/heathrow_pic.c166
-rw-r--r--hw/intc/openpic.c157
-rw-r--r--hw/intc/openpic_kvm.c5
-rw-r--r--hw/intc/s390_flic.c4
-rw-r--r--hw/intc/trace-events5
-rw-r--r--hw/ipmi/ipmi.c2
-rw-r--r--hw/mem/nvdimm.c1
-rw-r--r--hw/misc/Makefile.objs4
-rw-r--r--hw/misc/iotkit-secctl.c704
-rw-r--r--hw/misc/macio/macio.c150
-rw-r--r--hw/misc/mps2-fpgaio.c176
-rw-r--r--hw/misc/trace-events24
-rw-r--r--hw/misc/tz-ppc.c302
-rw-r--r--hw/misc/unimp.c10
-rw-r--r--hw/net/e1000.c1
-rw-r--r--hw/net/lance.c3
-rw-r--r--hw/net/ne2000.c2
-rw-r--r--hw/net/net_tx_pkt.c2
-rw-r--r--hw/net/pcnet-pci.c1
-rw-r--r--hw/net/pcnet.c1
-rw-r--r--hw/net/rocker/qmp-norocker.c2
-rw-r--r--hw/net/rocker/rocker.c2
-rw-r--r--hw/net/rocker/rocker_fp.c2
-rw-r--r--hw/net/rocker/rocker_of_dpa.c2
-rw-r--r--hw/net/rtl8139.c2
-rw-r--r--hw/net/virtio-net.c2
-rw-r--r--hw/net/xgmac.c1
-rw-r--r--hw/pci/pci-stub.c2
-rw-r--r--hw/pci/pci.c2
-rw-r--r--hw/ppc/Makefile.objs3
-rw-r--r--hw/ppc/e500.c124
-rw-r--r--hw/ppc/mac.h10
-rw-r--r--hw/ppc/mac_newworld.c56
-rw-r--r--hw/ppc/mac_oldworld.c50
-rw-r--r--hw/ppc/ppc440_pcix.c528
-rw-r--r--hw/ppc/ppc440_uc.c3
-rw-r--r--hw/ppc/sam460ex.c603
-rw-r--r--hw/ppc/spapr.c176
-rw-r--r--hw/ppc/spapr_caps.c153
-rw-r--r--hw/ppc/spapr_hcall.c5
-rw-r--r--hw/ppc/spapr_rtas.c1
-rw-r--r--hw/ppc/spapr_rtc.c2
-rw-r--r--hw/ppc/trace-events8
-rw-r--r--hw/s390x/ipl.c77
-rw-r--r--hw/s390x/ipl.h31
-rw-r--r--hw/s390x/s390-ccw.c2
-rw-r--r--hw/s390x/s390-skeys.c2
-rw-r--r--hw/s390x/s390-stattrib.c26
-rw-r--r--hw/s390x/s390-virtio-ccw.c2
-rw-r--r--hw/s390x/sclp.c310
-rw-r--r--hw/scsi/lsi53c895a.c2
-rw-r--r--hw/scsi/scsi-bus.c49
-rw-r--r--hw/scsi/spapr_vscsi.c3
-rw-r--r--hw/ssi/xilinx_spips.c43
-rw-r--r--hw/timer/Makefile.objs1
-rw-r--r--hw/timer/mc146818rtc.c4
-rw-r--r--hw/timer/trace-events3
-rw-r--r--hw/timer/xlnx-zynqmp-rtc.c272
-rw-r--r--hw/tpm/tpm_emulator.c1
-rw-r--r--hw/tpm/tpm_passthrough.c1
-rw-r--r--hw/vfio/pci.c2
-rw-r--r--hw/vfio/platform.c2
-rw-r--r--hw/virtio/vhost-user.c104
-rw-r--r--hw/virtio/vhost.c41
-rw-r--r--hw/virtio/virtio-balloon.c2
-rw-r--r--hw/virtio/virtio-crypto.c70
-rw-r--r--hw/virtio/virtio-pci.c2
-rw-r--r--hw/watchdog/watchdog.c4
104 files changed, 5128 insertions, 1156 deletions
diff --git a/hw/acpi/core.c b/hw/acpi/core.c
index b50b3ca772..b8d39012cd 100644
--- a/hw/acpi/core.c
+++ b/hw/acpi/core.c
@@ -27,8 +27,8 @@
#include "qemu/config-file.h"
#include "qapi/error.h"
#include "qapi/opts-visitor.h"
-#include "qapi-visit.h"
-#include "qapi-event.h"
+#include "qapi/qapi-events-run-state.h"
+#include "qapi/qapi-visit-misc.h"
#include "qemu/error-report.h"
#include "qemu/option.h"
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index a233fe17cf..5ae595ecbe 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -2,7 +2,7 @@
#include "hw/boards.h"
#include "hw/acpi/cpu.h"
#include "qapi/error.h"
-#include "qapi-event.h"
+#include "qapi/qapi-events-misc.h"
#include "trace.h"
#include "sysemu/numa.h"
diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c
index ea958a0e99..0ff1712c4c 100644
--- a/hw/acpi/memory_hotplug.c
+++ b/hw/acpi/memory_hotplug.c
@@ -5,8 +5,8 @@
#include "hw/boards.h"
#include "hw/qdev-core.h"
#include "trace.h"
-#include "qapi-event.h"
#include "qapi/error.h"
+#include "qapi/qapi-events-misc.h"
#define MEMORY_SLOTS_NUMBER "MDNR"
#define MEMORY_HOTPLUG_IO_REGION "HPMR"
diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c
index f25eafc0ec..d78b579a20 100644
--- a/hw/acpi/vmgenid.c
+++ b/hw/acpi/vmgenid.c
@@ -12,7 +12,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qmp-commands.h"
+#include "qapi/qapi-commands-misc.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/vmgenid.h"
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 1c896bafb4..232258160a 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -19,4 +19,6 @@ obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o
obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o
obj-$(CONFIG_MPS2) += mps2.o
+obj-$(CONFIG_MPS2) += mps2-tz.o
obj-$(CONFIG_MSF2) += msf2-soc.o msf2-som.o
+obj-$(CONFIG_IOTKIT) += iotkit.o
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
index 56770a7048..f123cc7d3d 100644
--- a/hw/arm/armv7m.c
+++ b/hw/arm/armv7m.c
@@ -19,6 +19,7 @@
#include "sysemu/qtest.h"
#include "qemu/error-report.h"
#include "exec/address-spaces.h"
+#include "target/arm/idau.h"
/* Bitbanded IO. Each word corresponds to a single bit. */
@@ -162,6 +163,21 @@ static void armv7m_realize(DeviceState *dev, Error **errp)
object_property_set_link(OBJECT(s->cpu), OBJECT(&s->container), "memory",
&error_abort);
+ if (object_property_find(OBJECT(s->cpu), "idau", NULL)) {
+ object_property_set_link(OBJECT(s->cpu), s->idau, "idau", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ }
+ if (object_property_find(OBJECT(s->cpu), "init-svtor", NULL)) {
+ object_property_set_uint(OBJECT(s->cpu), s->init_svtor,
+ "init-svtor", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ }
object_property_set_bool(OBJECT(s->cpu), true, "realized", &err);
if (err != NULL) {
error_propagate(errp, err);
@@ -217,6 +233,8 @@ static Property armv7m_properties[] = {
DEFINE_PROP_STRING("cpu-type", ARMv7MState, cpu_type),
DEFINE_PROP_LINK("memory", ARMv7MState, board_memory, TYPE_MEMORY_REGION,
MemoryRegion *),
+ DEFINE_PROP_LINK("idau", ARMv7MState, idau, TYPE_IDAU_INTERFACE, Object *),
+ DEFINE_PROP_UINT32("init-svtor", ARMv7MState, init_svtor, 0),
DEFINE_PROP_END_OF_LIST(),
};
@@ -270,6 +288,9 @@ void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size)
uint64_t entry;
uint64_t lowaddr;
int big_endian;
+ AddressSpace *as;
+ int asidx;
+ CPUState *cs = CPU(cpu);
#ifdef TARGET_WORDS_BIGENDIAN
big_endian = 1;
@@ -282,11 +303,19 @@ void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size)
exit(1);
}
+ if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) {
+ asidx = ARMASIdx_S;
+ } else {
+ asidx = ARMASIdx_NS;
+ }
+ as = cpu_get_address_space(cs, asidx);
+
if (kernel_filename) {
- image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
- NULL, big_endian, EM_ARM, 1, 0);
+ image_size = load_elf_as(kernel_filename, NULL, NULL, &entry, &lowaddr,
+ NULL, big_endian, EM_ARM, 1, 0, as);
if (image_size < 0) {
- image_size = load_image_targphys(kernel_filename, 0, mem_size);
+ image_size = load_image_targphys_as(kernel_filename, 0,
+ mem_size, as);
lowaddr = 0;
}
if (image_size < 0) {
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 05108bc42f..6d0c92ab88 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -36,6 +36,25 @@
#define ARM64_TEXT_OFFSET_OFFSET 8
#define ARM64_MAGIC_OFFSET 56
+static AddressSpace *arm_boot_address_space(ARMCPU *cpu,
+ const struct arm_boot_info *info)
+{
+ /* Return the address space to use for bootloader reads and writes.
+ * We prefer the secure address space if the CPU has it and we're
+ * going to boot the guest into it.
+ */
+ int asidx;
+ CPUState *cs = CPU(cpu);
+
+ if (arm_feature(&cpu->env, ARM_FEATURE_EL3) && info->secure_boot) {
+ asidx = ARMASIdx_S;
+ } else {
+ asidx = ARMASIdx_NS;
+ }
+
+ return cpu_get_address_space(cs, asidx);
+}
+
typedef enum {
FIXUP_NONE = 0, /* do nothing */
FIXUP_TERMINATOR, /* end of insns */
@@ -125,7 +144,8 @@ static const ARMInsnFixup smpboot[] = {
};
static void write_bootloader(const char *name, hwaddr addr,
- const ARMInsnFixup *insns, uint32_t *fixupcontext)
+ const ARMInsnFixup *insns, uint32_t *fixupcontext,
+ AddressSpace *as)
{
/* Fix up the specified bootloader fragment and write it into
* guest memory using rom_add_blob_fixed(). fixupcontext is
@@ -164,7 +184,7 @@ static void write_bootloader(const char *name, hwaddr addr,
code[i] = tswap32(insn);
}
- rom_add_blob_fixed(name, code, len * sizeof(uint32_t), addr);
+ rom_add_blob_fixed_as(name, code, len * sizeof(uint32_t), addr, as);
g_free(code);
}
@@ -173,6 +193,7 @@ static void default_write_secondary(ARMCPU *cpu,
const struct arm_boot_info *info)
{
uint32_t fixupcontext[FIXUP_MAX];
+ AddressSpace *as = arm_boot_address_space(cpu, info);
fixupcontext[FIXUP_GIC_CPU_IF] = info->gic_cpu_if_addr;
fixupcontext[FIXUP_BOOTREG] = info->smp_bootreg_addr;
@@ -183,13 +204,14 @@ static void default_write_secondary(ARMCPU *cpu,
}
write_bootloader("smpboot", info->smp_loader_start,
- smpboot, fixupcontext);
+ smpboot, fixupcontext, as);
}
void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu,
const struct arm_boot_info *info,
hwaddr mvbar_addr)
{
+ AddressSpace *as = arm_boot_address_space(cpu, info);
int n;
uint32_t mvbar_blob[] = {
/* mvbar_addr: secure monitor vectors
@@ -227,22 +249,23 @@ void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu,
for (n = 0; n < ARRAY_SIZE(mvbar_blob); n++) {
mvbar_blob[n] = tswap32(mvbar_blob[n]);
}
- rom_add_blob_fixed("board-setup-mvbar", mvbar_blob, sizeof(mvbar_blob),
- mvbar_addr);
+ rom_add_blob_fixed_as("board-setup-mvbar", mvbar_blob, sizeof(mvbar_blob),
+ mvbar_addr, as);
for (n = 0; n < ARRAY_SIZE(board_setup_blob); n++) {
board_setup_blob[n] = tswap32(board_setup_blob[n]);
}
- rom_add_blob_fixed("board-setup", board_setup_blob,
- sizeof(board_setup_blob), info->board_setup_addr);
+ rom_add_blob_fixed_as("board-setup", board_setup_blob,
+ sizeof(board_setup_blob), info->board_setup_addr, as);
}
static void default_reset_secondary(ARMCPU *cpu,
const struct arm_boot_info *info)
{
+ AddressSpace *as = arm_boot_address_space(cpu, info);
CPUState *cs = CPU(cpu);
- address_space_stl_notdirty(&address_space_memory, info->smp_bootreg_addr,
+ address_space_stl_notdirty(as, info->smp_bootreg_addr,
0, MEMTXATTRS_UNSPECIFIED, NULL);
cpu_set_pc(cs, info->smp_loader_start);
}
@@ -253,12 +276,12 @@ static inline bool have_dtb(const struct arm_boot_info *info)
}
#define WRITE_WORD(p, value) do { \
- address_space_stl_notdirty(&address_space_memory, p, value, \
+ address_space_stl_notdirty(as, p, value, \
MEMTXATTRS_UNSPECIFIED, NULL); \
p += 4; \
} while (0)
-static void set_kernel_args(const struct arm_boot_info *info)
+static void set_kernel_args(const struct arm_boot_info *info, AddressSpace *as)
{
int initrd_size = info->initrd_size;
hwaddr base = info->loader_start;
@@ -289,8 +312,9 @@ static void set_kernel_args(const struct arm_boot_info *info)
int cmdline_size;
cmdline_size = strlen(info->kernel_cmdline);
- cpu_physical_memory_write(p + 8, info->kernel_cmdline,
- cmdline_size + 1);
+ address_space_write(as, p + 8, MEMTXATTRS_UNSPECIFIED,
+ (const uint8_t *)info->kernel_cmdline,
+ cmdline_size + 1);
cmdline_size = (cmdline_size >> 2) + 1;
WRITE_WORD(p, cmdline_size + 2);
WRITE_WORD(p, 0x54410009);
@@ -304,7 +328,8 @@ static void set_kernel_args(const struct arm_boot_info *info)
atag_board_len = (info->atag_board(info, atag_board_buf) + 3) & ~3;
WRITE_WORD(p, (atag_board_len + 8) >> 2);
WRITE_WORD(p, 0x414f4d50);
- cpu_physical_memory_write(p, atag_board_buf, atag_board_len);
+ address_space_write(as, p, MEMTXATTRS_UNSPECIFIED,
+ atag_board_buf, atag_board_len);
p += atag_board_len;
}
/* ATAG_END */
@@ -312,7 +337,8 @@ static void set_kernel_args(const struct arm_boot_info *info)
WRITE_WORD(p, 0);
}
-static void set_kernel_args_old(const struct arm_boot_info *info)
+static void set_kernel_args_old(const struct arm_boot_info *info,
+ AddressSpace *as)
{
hwaddr p;
const char *s;
@@ -380,7 +406,8 @@ static void set_kernel_args_old(const struct arm_boot_info *info)
}
s = info->kernel_cmdline;
if (s) {
- cpu_physical_memory_write(p, s, strlen(s) + 1);
+ address_space_write(as, p, MEMTXATTRS_UNSPECIFIED,
+ (const uint8_t *)s, strlen(s) + 1);
} else {
WRITE_WORD(p, 0);
}
@@ -454,6 +481,7 @@ static void fdt_add_psci_node(void *fdt)
* @addr: the address to load the image at
* @binfo: struct describing the boot environment
* @addr_limit: upper limit of the available memory area at @addr
+ * @as: address space to load image to
*
* Load a device tree supplied by the machine or by the user with the
* '-dtb' command line option, and put it at offset @addr in target
@@ -470,7 +498,7 @@ static void fdt_add_psci_node(void *fdt)
* Note: Must not be called unless have_dtb(binfo) is true.
*/
static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
- hwaddr addr_limit)
+ hwaddr addr_limit, AddressSpace *as)
{
void *fdt = NULL;
int size, rc;
@@ -616,7 +644,7 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
/* Put the DTB into the memory map as a ROM image: this will ensure
* the DTB is copied again upon reset, even if addr points into RAM.
*/
- rom_add_blob_fixed("dtb", fdt, size, addr);
+ rom_add_blob_fixed_as("dtb", fdt, size, addr, as);
g_free(fdt);
@@ -703,13 +731,15 @@ static void do_cpu_reset(void *opaque)
}
if (cs == first_cpu) {
+ AddressSpace *as = arm_boot_address_space(cpu, info);
+
cpu_set_pc(cs, info->loader_start);
if (!have_dtb(info)) {
if (old_param) {
- set_kernel_args_old(info);
+ set_kernel_args_old(info, as);
} else {
- set_kernel_args(info);
+ set_kernel_args(info, as);
}
}
} else {
@@ -784,7 +814,7 @@ static int do_arm_linux_init(Object *obj, void *opaque)
static uint64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry,
uint64_t *lowaddr, uint64_t *highaddr,
- int elf_machine)
+ int elf_machine, AddressSpace *as)
{
bool elf_is64;
union {
@@ -827,9 +857,9 @@ static uint64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry,
}
}
- ret = load_elf(info->kernel_filename, NULL, NULL,
- pentry, lowaddr, highaddr, big_endian, elf_machine,
- 1, data_swab);
+ ret = load_elf_as(info->kernel_filename, NULL, NULL,
+ pentry, lowaddr, highaddr, big_endian, elf_machine,
+ 1, data_swab, as);
if (ret <= 0) {
/* The header loaded but the image didn't */
exit(1);
@@ -839,7 +869,7 @@ static uint64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry,
}
static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base,
- hwaddr *entry)
+ hwaddr *entry, AddressSpace *as)
{
hwaddr kernel_load_offset = KERNEL64_LOAD_ADDR;
uint8_t *buffer;
@@ -874,7 +904,7 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base,
}
*entry = mem_base + kernel_load_offset;
- rom_add_blob_fixed(filename, buffer, size, *entry);
+ rom_add_blob_fixed_as(filename, buffer, size, *entry, as);
g_free(buffer);
@@ -896,6 +926,7 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
ARMCPU *cpu = n->cpu;
struct arm_boot_info *info =
container_of(n, struct arm_boot_info, load_kernel_notifier);
+ AddressSpace *as = arm_boot_address_space(cpu, info);
/* The board code is not supposed to set secure_board_setup unless
* running its code in secure mode is actually possible, and KVM
@@ -913,7 +944,7 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
* the kernel is supposed to be loaded by the bootloader), copy the
* DTB to the base of RAM for the bootloader to pick up.
*/
- if (load_dtb(info->loader_start, info, 0) < 0) {
+ if (load_dtb(info->loader_start, info, 0, as) < 0) {
exit(1);
}
}
@@ -988,7 +1019,7 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
/* Assume that raw images are linux kernels, and ELF images are not. */
kernel_size = arm_load_elf(info, &elf_entry, &elf_low_addr,
- &elf_high_addr, elf_machine);
+ &elf_high_addr, elf_machine, as);
if (kernel_size > 0 && have_dtb(info)) {
/* If there is still some room left at the base of RAM, try and put
* the DTB there like we do for images loaded with -bios or -pflash.
@@ -1001,25 +1032,26 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
if (elf_low_addr < info->loader_start) {
elf_low_addr = 0;
}
- if (load_dtb(info->loader_start, info, elf_low_addr) < 0) {
+ if (load_dtb(info->loader_start, info, elf_low_addr, as) < 0) {
exit(1);
}
}
}
entry = elf_entry;
if (kernel_size < 0) {
- kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
- &is_linux, NULL, NULL);
+ kernel_size = load_uimage_as(info->kernel_filename, &entry, NULL,
+ &is_linux, NULL, NULL, as);
}
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && kernel_size < 0) {
kernel_size = load_aarch64_image(info->kernel_filename,
- info->loader_start, &entry);
+ info->loader_start, &entry, as);
is_linux = 1;
} else if (kernel_size < 0) {
/* 32-bit ARM */
entry = info->loader_start + KERNEL_LOAD_ADDR;
- kernel_size = load_image_targphys(info->kernel_filename, entry,
- info->ram_size - KERNEL_LOAD_ADDR);
+ kernel_size = load_image_targphys_as(info->kernel_filename, entry,
+ info->ram_size - KERNEL_LOAD_ADDR,
+ as);
is_linux = 1;
}
if (kernel_size < 0) {
@@ -1031,15 +1063,16 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
uint32_t fixupcontext[FIXUP_MAX];
if (info->initrd_filename) {
- initrd_size = load_ramdisk(info->initrd_filename,
- info->initrd_start,
- info->ram_size -
- info->initrd_start);
+ initrd_size = load_ramdisk_as(info->initrd_filename,
+ info->initrd_start,
+ info->ram_size - info->initrd_start,
+ as);
if (initrd_size < 0) {
- initrd_size = load_image_targphys(info->initrd_filename,
- info->initrd_start,
- info->ram_size -
- info->initrd_start);
+ initrd_size = load_image_targphys_as(info->initrd_filename,
+ info->initrd_start,
+ info->ram_size -
+ info->initrd_start,
+ as);
}
if (initrd_size < 0) {
error_report("could not load initrd '%s'",
@@ -1080,7 +1113,7 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
/* Place the DTB after the initrd in memory with alignment. */
dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size, align);
- if (load_dtb(dtb_start, info, 0) < 0) {
+ if (load_dtb(dtb_start, info, 0, as) < 0) {
exit(1);
}
fixupcontext[FIXUP_ARGPTR] = dtb_start;
@@ -1096,7 +1129,7 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
fixupcontext[FIXUP_ENTRYPOINT] = entry;
write_bootloader("bootloader", info->loader_start,
- primary_loader, fixupcontext);
+ primary_loader, fixupcontext, as);
if (info->nb_cpus > 1) {
info->write_secondary_boot(cpu, info);
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
new file mode 100644
index 0000000000..c5f0a5b98a
--- /dev/null
+++ b/hw/arm/iotkit.c
@@ -0,0 +1,598 @@
+/*
+ * Arm IoT Kit
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "trace.h"
+#include "hw/sysbus.h"
+#include "hw/registerfields.h"
+#include "hw/arm/iotkit.h"
+#include "hw/misc/unimp.h"
+#include "hw/arm/arm.h"
+
+/* Create an alias region of @size bytes starting at @base
+ * which mirrors the memory starting at @orig.
+ */
+static void make_alias(IoTKit *s, MemoryRegion *mr, const char *name,
+ hwaddr base, hwaddr size, hwaddr orig)
+{
+ memory_region_init_alias(mr, NULL, name, &s->container, orig, size);
+ /* The alias is even lower priority than unimplemented_device regions */
+ memory_region_add_subregion_overlap(&s->container, base, mr, -1500);
+}
+
+static void init_sysbus_child(Object *parent, const char *childname,
+ void *child, size_t childsize,
+ const char *childtype)
+{
+ object_initialize(child, childsize, childtype);
+ object_property_add_child(parent, childname, OBJECT(child), &error_abort);
+ qdev_set_parent_bus(DEVICE(child), sysbus_get_default());
+}
+
+static void irq_status_forwarder(void *opaque, int n, int level)
+{
+ qemu_irq destirq = opaque;
+
+ qemu_set_irq(destirq, level);
+}
+
+static void nsccfg_handler(void *opaque, int n, int level)
+{
+ IoTKit *s = IOTKIT(opaque);
+
+ s->nsccfg = level;
+}
+
+static void iotkit_forward_ppc(IoTKit *s, const char *ppcname, int ppcnum)
+{
+ /* Each of the 4 AHB and 4 APB PPCs that might be present in a
+ * system using the IoTKit has a collection of control lines which
+ * are provided by the security controller and which we want to
+ * expose as control lines on the IoTKit device itself, so the
+ * code using the IoTKit can wire them up to the PPCs.
+ */
+ SplitIRQ *splitter = &s->ppc_irq_splitter[ppcnum];
+ DeviceState *iotkitdev = DEVICE(s);
+ DeviceState *dev_secctl = DEVICE(&s->secctl);
+ DeviceState *dev_splitter = DEVICE(splitter);
+ char *name;
+
+ name = g_strdup_printf("%s_nonsec", ppcname);
+ qdev_pass_gpios(dev_secctl, iotkitdev, name);
+ g_free(name);
+ name = g_strdup_printf("%s_ap", ppcname);
+ qdev_pass_gpios(dev_secctl, iotkitdev, name);
+ g_free(name);
+ name = g_strdup_printf("%s_irq_enable", ppcname);
+ qdev_pass_gpios(dev_secctl, iotkitdev, name);
+ g_free(name);
+ name = g_strdup_printf("%s_irq_clear", ppcname);
+ qdev_pass_gpios(dev_secctl, iotkitdev, name);
+ g_free(name);
+
+ /* irq_status is a little more tricky, because we need to
+ * split it so we can send it both to the security controller
+ * and to our OR gate for the NVIC interrupt line.
+ * Connect up the splitter's outputs, and create a GPIO input
+ * which will pass the line state to the input splitter.
+ */
+ name = g_strdup_printf("%s_irq_status", ppcname);
+ qdev_connect_gpio_out(dev_splitter, 0,
+ qdev_get_gpio_in_named(dev_secctl,
+ name, 0));
+ qdev_connect_gpio_out(dev_splitter, 1,
+ qdev_get_gpio_in(DEVICE(&s->ppc_irq_orgate), ppcnum));
+ s->irq_status_in[ppcnum] = qdev_get_gpio_in(dev_splitter, 0);
+ qdev_init_gpio_in_named_with_opaque(iotkitdev, irq_status_forwarder,
+ s->irq_status_in[ppcnum], name, 1);
+ g_free(name);
+}
+
+static void iotkit_forward_sec_resp_cfg(IoTKit *s)
+{
+ /* Forward the 3rd output from the splitter device as a
+ * named GPIO output of the iotkit object.
+ */
+ DeviceState *dev = DEVICE(s);
+ DeviceState *dev_splitter = DEVICE(&s->sec_resp_splitter);
+
+ qdev_init_gpio_out_named(dev, &s->sec_resp_cfg, "sec_resp_cfg", 1);
+ s->sec_resp_cfg_in = qemu_allocate_irq(irq_status_forwarder,
+ s->sec_resp_cfg, 1);
+ qdev_connect_gpio_out(dev_splitter, 2, s->sec_resp_cfg_in);
+}
+
+static void iotkit_init(Object *obj)
+{
+ IoTKit *s = IOTKIT(obj);
+ int i;
+
+ memory_region_init(&s->container, obj, "iotkit-container", UINT64_MAX);
+
+ init_sysbus_child(obj, "armv7m", &s->armv7m, sizeof(s->armv7m),
+ TYPE_ARMV7M);
+ qdev_prop_set_string(DEVICE(&s->armv7m), "cpu-type",
+ ARM_CPU_TYPE_NAME("cortex-m33"));
+
+ init_sysbus_child(obj, "secctl", &s->secctl, sizeof(s->secctl),
+ TYPE_IOTKIT_SECCTL);
+ init_sysbus_child(obj, "apb-ppc0", &s->apb_ppc0, sizeof(s->apb_ppc0),
+ TYPE_TZ_PPC);
+ init_sysbus_child(obj, "apb-ppc1", &s->apb_ppc1, sizeof(s->apb_ppc1),
+ TYPE_TZ_PPC);
+ init_sysbus_child(obj, "timer0", &s->timer0, sizeof(s->timer0),
+ TYPE_CMSDK_APB_TIMER);
+ init_sysbus_child(obj, "timer1", &s->timer1, sizeof(s->timer1),
+ TYPE_CMSDK_APB_TIMER);
+ init_sysbus_child(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer),
+ TYPE_UNIMPLEMENTED_DEVICE);
+ object_initialize(&s->ppc_irq_orgate, sizeof(s->ppc_irq_orgate),
+ TYPE_OR_IRQ);
+ object_property_add_child(obj, "ppc-irq-orgate",
+ OBJECT(&s->ppc_irq_orgate), &error_abort);
+ object_initialize(&s->sec_resp_splitter, sizeof(s->sec_resp_splitter),
+ TYPE_SPLIT_IRQ);
+ object_property_add_child(obj, "sec-resp-splitter",
+ OBJECT(&s->sec_resp_splitter), &error_abort);
+ for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) {
+ char *name = g_strdup_printf("ppc-irq-splitter-%d", i);
+ SplitIRQ *splitter = &s->ppc_irq_splitter[i];
+
+ object_initialize(splitter, sizeof(*splitter), TYPE_SPLIT_IRQ);
+ object_property_add_child(obj, name, OBJECT(splitter), &error_abort);
+ }
+ init_sysbus_child(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer),
+ TYPE_UNIMPLEMENTED_DEVICE);
+}
+
+static void iotkit_exp_irq(void *opaque, int n, int level)
+{
+ IoTKit *s = IOTKIT(opaque);
+
+ qemu_set_irq(s->exp_irqs[n], level);
+}
+
+static void iotkit_realize(DeviceState *dev, Error **errp)
+{
+ IoTKit *s = IOTKIT(dev);
+ int i;
+ MemoryRegion *mr;
+ Error *err = NULL;
+ SysBusDevice *sbd_apb_ppc0;
+ SysBusDevice *sbd_secctl;
+ DeviceState *dev_apb_ppc0;
+ DeviceState *dev_apb_ppc1;
+ DeviceState *dev_secctl;
+ DeviceState *dev_splitter;
+
+ if (!s->board_memory) {
+ error_setg(errp, "memory property was not set");
+ return;
+ }
+
+ if (!s->mainclk_frq) {
+ error_setg(errp, "MAINCLK property was not set");
+ return;
+ }
+
+ /* Handling of which devices should be available only to secure
+ * code is usually done differently for M profile than for A profile.
+ * Instead of putting some devices only into the secure address space,
+ * devices exist in both address spaces but with hard-wired security
+ * permissions that will cause the CPU to fault for non-secure accesses.
+ *
+ * The IoTKit has an IDAU (Implementation Defined Access Unit),
+ * which specifies hard-wired security permissions for different
+ * areas of the physical address space. For the IoTKit IDAU, the
+ * top 4 bits of the physical address are the IDAU region ID, and
+ * if bit 28 (ie the lowest bit of the ID) is 0 then this is an NS
+ * region, otherwise it is an S region.
+ *
+ * The various devices and RAMs are generally all mapped twice,
+ * once into a region that the IDAU defines as secure and once
+ * into a non-secure region. They sit behind either a Memory
+ * Protection Controller (for RAM) or a Peripheral Protection
+ * Controller (for devices), which allow a more fine grained
+ * configuration of whether non-secure accesses are permitted.
+ *
+ * (The other place that guest software can configure security
+ * permissions is in the architected SAU (Security Attribution
+ * Unit), which is entirely inside the CPU. The IDAU can upgrade
+ * the security attributes for a region to more restrictive than
+ * the SAU specifies, but cannot downgrade them.)
+ *
+ * 0x10000000..0x1fffffff alias of 0x00000000..0x0fffffff
+ * 0x20000000..0x2007ffff 32KB FPGA block RAM
+ * 0x30000000..0x3fffffff alias of 0x20000000..0x2fffffff
+ * 0x40000000..0x4000ffff base peripheral region 1
+ * 0x40010000..0x4001ffff CPU peripherals (none for IoTKit)
+ * 0x40020000..0x4002ffff system control element peripherals
+ * 0x40080000..0x400fffff base peripheral region 2
+ * 0x50000000..0x5fffffff alias of 0x40000000..0x4fffffff
+ */
+
+ memory_region_add_subregion_overlap(&s->container, 0, s->board_memory, -1);
+
+ qdev_prop_set_uint32(DEVICE(&s->armv7m), "num-irq", s->exp_numirq + 32);
+ /* In real hardware the initial Secure VTOR is set from the INITSVTOR0
+ * register in the IoT Kit System Control Register block, and the
+ * initial value of that is in turn specifiable by the FPGA that
+ * instantiates the IoT Kit. In QEMU we don't implement this wrinkle,
+ * and simply set the CPU's init-svtor to the IoT Kit default value.
+ */
+ qdev_prop_set_uint32(DEVICE(&s->armv7m), "init-svtor", 0x10000000);
+ object_property_set_link(OBJECT(&s->armv7m), OBJECT(&s->container),
+ "memory", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ object_property_set_link(OBJECT(&s->armv7m), OBJECT(s), "idau", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ object_property_set_bool(OBJECT(&s->armv7m), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ /* Connect our EXP_IRQ GPIOs to the NVIC's lines 32 and up. */
+ s->exp_irqs = g_new(qemu_irq, s->exp_numirq);
+ for (i = 0; i < s->exp_numirq; i++) {
+ s->exp_irqs[i] = qdev_get_gpio_in(DEVICE(&s->armv7m), i + 32);
+ }
+ qdev_init_gpio_in_named(dev, iotkit_exp_irq, "EXP_IRQ", s->exp_numirq);
+
+ /* Set up the big aliases first */
+ make_alias(s, &s->alias1, "alias 1", 0x10000000, 0x10000000, 0x00000000);
+ make_alias(s, &s->alias2, "alias 2", 0x30000000, 0x10000000, 0x20000000);
+ /* The 0x50000000..0x5fffffff region is not a pure alias: it has
+ * a few extra devices that only appear there (generally the
+ * control interfaces for the protection controllers).
+ * We implement this by mapping those devices over the top of this
+ * alias MR at a higher priority.
+ */
+ make_alias(s, &s->alias3, "alias 3", 0x50000000, 0x10000000, 0x40000000);
+
+ /* This RAM should be behind a Memory Protection Controller, but we
+ * don't implement that yet.
+ */
+ memory_region_init_ram(&s->sram0, NULL, "iotkit.sram0", 0x00008000, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ memory_region_add_subregion(&s->container, 0x20000000, &s->sram0);
+
+ /* Security controller */
+ object_property_set_bool(OBJECT(&s->secctl), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sbd_secctl = SYS_BUS_DEVICE(&s->secctl);
+ dev_secctl = DEVICE(&s->secctl);
+ sysbus_mmio_map(sbd_secctl, 0, 0x50080000);
+ sysbus_mmio_map(sbd_secctl, 1, 0x40080000);
+
+ s->nsc_cfg_in = qemu_allocate_irq(nsccfg_handler, s, 1);
+ qdev_connect_gpio_out_named(dev_secctl, "nsc_cfg", 0, s->nsc_cfg_in);
+
+ /* The sec_resp_cfg output from the security controller must be split into
+ * multiple lines, one for each of the PPCs within the IoTKit and one
+ * that will be an output from the IoTKit to the system.
+ */
+ object_property_set_int(OBJECT(&s->sec_resp_splitter), 3,
+ "num-lines", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ object_property_set_bool(OBJECT(&s->sec_resp_splitter), true,
+ "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ dev_splitter = DEVICE(&s->sec_resp_splitter);
+ qdev_connect_gpio_out_named(dev_secctl, "sec_resp_cfg", 0,
+ qdev_get_gpio_in(dev_splitter, 0));
+
+ /* Devices behind APB PPC0:
+ * 0x40000000: timer0
+ * 0x40001000: timer1
+ * 0x40002000: dual timer
+ * We must configure and realize each downstream device and connect
+ * it to the appropriate PPC port; then we can realize the PPC and
+ * map its upstream ends to the right place in the container.
+ */
+ qdev_prop_set_uint32(DEVICE(&s->timer0), "pclk-frq", s->mainclk_frq);
+ object_property_set_bool(OBJECT(&s->timer0), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer0), 0,
+ qdev_get_gpio_in(DEVICE(&s->armv7m), 3));
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer0), 0);
+ object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[0]", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ qdev_prop_set_uint32(DEVICE(&s->timer1), "pclk-frq", s->mainclk_frq);
+ object_property_set_bool(OBJECT(&s->timer1), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer1), 0,
+ qdev_get_gpio_in(DEVICE(&s->armv7m), 3));
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->timer1), 0);
+ object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[1]", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ qdev_prop_set_string(DEVICE(&s->dualtimer), "name", "Dual timer");
+ qdev_prop_set_uint64(DEVICE(&s->dualtimer), "size", 0x1000);
+ object_property_set_bool(OBJECT(&s->dualtimer), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dualtimer), 0);
+ object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ object_property_set_bool(OBJECT(&s->apb_ppc0), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ sbd_apb_ppc0 = SYS_BUS_DEVICE(&s->apb_ppc0);
+ dev_apb_ppc0 = DEVICE(&s->apb_ppc0);
+
+ mr = sysbus_mmio_get_region(sbd_apb_ppc0, 0);
+ memory_region_add_subregion(&s->container, 0x40000000, mr);
+ mr = sysbus_mmio_get_region(sbd_apb_ppc0, 1);
+ memory_region_add_subregion(&s->container, 0x40001000, mr);
+ mr = sysbus_mmio_get_region(sbd_apb_ppc0, 2);
+ memory_region_add_subregion(&s->container, 0x40002000, mr);
+ for (i = 0; i < IOTS_APB_PPC0_NUM_PORTS; i++) {
+ qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_nonsec", i,
+ qdev_get_gpio_in_named(dev_apb_ppc0,
+ "cfg_nonsec", i));
+ qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_ap", i,
+ qdev_get_gpio_in_named(dev_apb_ppc0,
+ "cfg_ap", i));
+ }
+ qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_irq_enable", 0,
+ qdev_get_gpio_in_named(dev_apb_ppc0,
+ "irq_enable", 0));
+ qdev_connect_gpio_out_named(dev_secctl, "apb_ppc0_irq_clear", 0,
+ qdev_get_gpio_in_named(dev_apb_ppc0,
+ "irq_clear", 0));
+ qdev_connect_gpio_out(dev_splitter, 0,
+ qdev_get_gpio_in_named(dev_apb_ppc0,
+ "cfg_sec_resp", 0));
+
+ /* All the PPC irq lines (from the 2 internal PPCs and the 8 external
+ * ones) are sent individually to the security controller, and also
+ * ORed together to give a single combined PPC interrupt to the NVIC.
+ */
+ object_property_set_int(OBJECT(&s->ppc_irq_orgate),
+ NUM_PPCS, "num-lines", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ object_property_set_bool(OBJECT(&s->ppc_irq_orgate), true,
+ "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ qdev_connect_gpio_out(DEVICE(&s->ppc_irq_orgate), 0,
+ qdev_get_gpio_in(DEVICE(&s->armv7m), 10));
+
+ /* 0x40010000 .. 0x4001ffff: private CPU region: unused in IoTKit */
+
+ /* 0x40020000 .. 0x4002ffff : IoTKit system control peripheral region */
+ /* Devices behind APB PPC1:
+ * 0x4002f000: S32K timer
+ */
+ qdev_prop_set_string(DEVICE(&s->s32ktimer), "name", "S32KTIMER");
+ qdev_prop_set_uint64(DEVICE(&s->s32ktimer), "size", 0x1000);
+ object_property_set_bool(OBJECT(&s->s32ktimer), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->s32ktimer), 0);
+ object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ object_property_set_bool(OBJECT(&s->apb_ppc1), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->apb_ppc1), 0);
+ memory_region_add_subregion(&s->container, 0x4002f000, mr);
+
+ dev_apb_ppc1 = DEVICE(&s->apb_ppc1);
+ qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_nonsec", 0,
+ qdev_get_gpio_in_named(dev_apb_ppc1,
+ "cfg_nonsec", 0));
+ qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_ap", 0,
+ qdev_get_gpio_in_named(dev_apb_ppc1,
+ "cfg_ap", 0));
+ qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_irq_enable", 0,
+ qdev_get_gpio_in_named(dev_apb_ppc1,
+ "irq_enable", 0));
+ qdev_connect_gpio_out_named(dev_secctl, "apb_ppc1_irq_clear", 0,
+ qdev_get_gpio_in_named(dev_apb_ppc1,
+ "irq_clear", 0));
+ qdev_connect_gpio_out(dev_splitter, 1,
+ qdev_get_gpio_in_named(dev_apb_ppc1,
+ "cfg_sec_resp", 0));
+
+ /* Using create_unimplemented_device() maps the stub into the
+ * system address space rather than into our container, but the
+ * overall effect to the guest is the same.
+ */
+ create_unimplemented_device("SYSINFO", 0x40020000, 0x1000);
+
+ create_unimplemented_device("SYSCONTROL", 0x50021000, 0x1000);
+ create_unimplemented_device("S32KWATCHDOG", 0x5002e000, 0x1000);
+
+ /* 0x40080000 .. 0x4008ffff : IoTKit second Base peripheral region */
+
+ create_unimplemented_device("NS watchdog", 0x40081000, 0x1000);
+ create_unimplemented_device("S watchdog", 0x50081000, 0x1000);
+
+ create_unimplemented_device("SRAM0 MPC", 0x50083000, 0x1000);
+
+ for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) {
+ Object *splitter = OBJECT(&s->ppc_irq_splitter[i]);
+
+ object_property_set_int(splitter, 2, "num-lines", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ object_property_set_bool(splitter, true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ }
+
+ for (i = 0; i < IOTS_NUM_AHB_EXP_PPC; i++) {
+ char *ppcname = g_strdup_printf("ahb_ppcexp%d", i);
+
+ iotkit_forward_ppc(s, ppcname, i);
+ g_free(ppcname);
+ }
+
+ for (i = 0; i < IOTS_NUM_APB_EXP_PPC; i++) {
+ char *ppcname = g_strdup_printf("apb_ppcexp%d", i);
+
+ iotkit_forward_ppc(s, ppcname, i + IOTS_NUM_AHB_EXP_PPC);
+ g_free(ppcname);
+ }
+
+ for (i = NUM_EXTERNAL_PPCS; i < NUM_PPCS; i++) {
+ /* Wire up IRQ splitter for internal PPCs */
+ DeviceState *devs = DEVICE(&s->ppc_irq_splitter[i]);
+ char *gpioname = g_strdup_printf("apb_ppc%d_irq_status",
+ i - NUM_EXTERNAL_PPCS);
+ TZPPC *ppc = (i == NUM_EXTERNAL_PPCS) ? &s->apb_ppc0 : &s->apb_ppc1;
+
+ qdev_connect_gpio_out(devs, 0,
+ qdev_get_gpio_in_named(dev_secctl, gpioname, 0));
+ qdev_connect_gpio_out(devs, 1,
+ qdev_get_gpio_in(DEVICE(&s->ppc_irq_orgate), i));
+ qdev_connect_gpio_out_named(DEVICE(ppc), "irq", 0,
+ qdev_get_gpio_in(devs, 0));
+ }
+
+ iotkit_forward_sec_resp_cfg(s);
+
+ system_clock_scale = NANOSECONDS_PER_SECOND / s->mainclk_frq;
+}
+
+static void iotkit_idau_check(IDAUInterface *ii, uint32_t address,
+ int *iregion, bool *exempt, bool *ns, bool *nsc)
+{
+ /* For IoTKit systems the IDAU responses are simple logical functions
+ * of the address bits. The NSC attribute is guest-adjustable via the
+ * NSCCFG register in the security controller.
+ */
+ IoTKit *s = IOTKIT(ii);
+ int region = extract32(address, 28, 4);
+
+ *ns = !(region & 1);
+ *nsc = (region == 1 && (s->nsccfg & 1)) || (region == 3 && (s->nsccfg & 2));
+ /* 0xe0000000..0xe00fffff and 0xf0000000..0xf00fffff are exempt */
+ *exempt = (address & 0xeff00000) == 0xe0000000;
+ *iregion = region;
+}
+
+static const VMStateDescription iotkit_vmstate = {
+ .name = "iotkit",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(nsccfg, IoTKit),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property iotkit_properties[] = {
+ DEFINE_PROP_LINK("memory", IoTKit, board_memory, TYPE_MEMORY_REGION,
+ MemoryRegion *),
+ DEFINE_PROP_UINT32("EXP_NUMIRQ", IoTKit, exp_numirq, 64),
+ DEFINE_PROP_UINT32("MAINCLK", IoTKit, mainclk_frq, 0),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void iotkit_reset(DeviceState *dev)
+{
+ IoTKit *s = IOTKIT(dev);
+
+ s->nsccfg = 0;
+}
+
+static void iotkit_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(klass);
+
+ dc->realize = iotkit_realize;
+ dc->vmsd = &iotkit_vmstate;
+ dc->props = iotkit_properties;
+ dc->reset = iotkit_reset;
+ iic->check = iotkit_idau_check;
+}
+
+static const TypeInfo iotkit_info = {
+ .name = TYPE_IOTKIT,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IoTKit),
+ .instance_init = iotkit_init,
+ .class_init = iotkit_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_IDAU_INTERFACE },
+ { }
+ }
+};
+
+static void iotkit_register_types(void)
+{
+ type_register_static(&iotkit_info);
+}
+
+type_init(iotkit_register_types);
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
new file mode 100644
index 0000000000..8c86cffa9e
--- /dev/null
+++ b/hw/arm/mps2-tz.c
@@ -0,0 +1,503 @@
+/*
+ * ARM V2M MPS2 board emulation, trustzone aware FPGA images
+ *
+ * Copyright (c) 2017 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+/* The MPS2 and MPS2+ dev boards are FPGA based (the 2+ has a bigger
+ * FPGA but is otherwise the same as the 2). Since the CPU itself
+ * and most of the devices are in the FPGA, the details of the board
+ * as seen by the guest depend significantly on the FPGA image.
+ * This source file covers the following FPGA images, for TrustZone cores:
+ * "mps2-an505" -- Cortex-M33 as documented in ARM Application Note AN505
+ *
+ * Links to the TRM for the board itself and to the various Application
+ * Notes which document the FPGA images can be found here:
+ * https://developer.arm.com/products/system-design/development-boards/fpga-prototyping-boards/mps2
+ *
+ * Board TRM:
+ * http://infocenter.arm.com/help/topic/com.arm.doc.100112_0200_06_en/versatile_express_cortex_m_prototyping_systems_v2m_mps2_and_v2m_mps2plus_technical_reference_100112_0200_06_en.pdf
+ * Application Note AN505:
+ * http://infocenter.arm.com/help/topic/com.arm.doc.dai0505b/index.html
+ *
+ * The AN505 defers to the Cortex-M33 processor ARMv8M IoT Kit FVP User Guide
+ * (ARM ECM0601256) for the details of some of the device layout:
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "hw/arm/arm.h"
+#include "hw/arm/armv7m.h"
+#include "hw/or-irq.h"
+#include "hw/boards.h"
+#include "exec/address-spaces.h"
+#include "sysemu/sysemu.h"
+#include "hw/misc/unimp.h"
+#include "hw/char/cmsdk-apb-uart.h"
+#include "hw/timer/cmsdk-apb-timer.h"
+#include "hw/misc/mps2-scc.h"
+#include "hw/misc/mps2-fpgaio.h"
+#include "hw/arm/iotkit.h"
+#include "hw/devices.h"
+#include "net/net.h"
+#include "hw/core/split-irq.h"
+
+typedef enum MPS2TZFPGAType {
+ FPGA_AN505,
+} MPS2TZFPGAType;
+
+typedef struct {
+ MachineClass parent;
+ MPS2TZFPGAType fpga_type;
+ uint32_t scc_id;
+} MPS2TZMachineClass;
+
+typedef struct {
+ MachineState parent;
+
+ IoTKit iotkit;
+ MemoryRegion psram;
+ MemoryRegion ssram1;
+ MemoryRegion ssram1_m;
+ MemoryRegion ssram23;
+ MPS2SCC scc;
+ MPS2FPGAIO fpgaio;
+ TZPPC ppc[5];
+ UnimplementedDeviceState ssram_mpc[3];
+ UnimplementedDeviceState spi[5];
+ UnimplementedDeviceState i2c[4];
+ UnimplementedDeviceState i2s_audio;
+ UnimplementedDeviceState gpio[5];
+ UnimplementedDeviceState dma[4];
+ UnimplementedDeviceState gfx;
+ CMSDKAPBUART uart[5];
+ SplitIRQ sec_resp_splitter;
+ qemu_or_irq uart_irq_orgate;
+} MPS2TZMachineState;
+
+#define TYPE_MPS2TZ_MACHINE "mps2tz"
+#define TYPE_MPS2TZ_AN505_MACHINE MACHINE_TYPE_NAME("mps2-an505")
+
+#define MPS2TZ_MACHINE(obj) \
+ OBJECT_CHECK(MPS2TZMachineState, obj, TYPE_MPS2TZ_MACHINE)
+#define MPS2TZ_MACHINE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(MPS2TZMachineClass, obj, TYPE_MPS2TZ_MACHINE)
+#define MPS2TZ_MACHINE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(MPS2TZMachineClass, klass, TYPE_MPS2TZ_MACHINE)
+
+/* Main SYSCLK frequency in Hz */
+#define SYSCLK_FRQ 20000000
+
+/* Initialize the auxiliary RAM region @mr and map it into
+ * the memory map at @base.
+ */
+static void make_ram(MemoryRegion *mr, const char *name,
+ hwaddr base, hwaddr size)
+{
+ memory_region_init_ram(mr, NULL, name, size, &error_fatal);
+ memory_region_add_subregion(get_system_memory(), base, mr);
+}
+
+/* Create an alias of an entire original MemoryRegion @orig
+ * located at @base in the memory map.
+ */
+static void make_ram_alias(MemoryRegion *mr, const char *name,
+ MemoryRegion *orig, hwaddr base)
+{
+ memory_region_init_alias(mr, NULL, name, orig, 0,
+ memory_region_size(orig));
+ memory_region_add_subregion(get_system_memory(), base, mr);
+}
+
+static void init_sysbus_child(Object *parent, const char *childname,
+ void *child, size_t childsize,
+ const char *childtype)
+{
+ object_initialize(child, childsize, childtype);
+ object_property_add_child(parent, childname, OBJECT(child), &error_abort);
+ qdev_set_parent_bus(DEVICE(child), sysbus_get_default());
+
+}
+
+/* Most of the devices in the AN505 FPGA image sit behind
+ * Peripheral Protection Controllers. These data structures
+ * define the layout of which devices sit behind which PPCs.
+ * The devfn for each port is a function which creates, configures
+ * and initializes the device, returning the MemoryRegion which
+ * needs to be plugged into the downstream end of the PPC port.
+ */
+typedef MemoryRegion *MakeDevFn(MPS2TZMachineState *mms, void *opaque,
+ const char *name, hwaddr size);
+
+typedef struct PPCPortInfo {
+ const char *name;
+ MakeDevFn *devfn;
+ void *opaque;
+ hwaddr addr;
+ hwaddr size;
+} PPCPortInfo;
+
+typedef struct PPCInfo {
+ const char *name;
+ PPCPortInfo ports[TZ_NUM_PORTS];
+} PPCInfo;
+
+static MemoryRegion *make_unimp_dev(MPS2TZMachineState *mms,
+ void *opaque,
+ const char *name, hwaddr size)
+{
+ /* Initialize, configure and realize a TYPE_UNIMPLEMENTED_DEVICE,
+ * and return a pointer to its MemoryRegion.
+ */
+ UnimplementedDeviceState *uds = opaque;
+
+ init_sysbus_child(OBJECT(mms), name, uds,
+ sizeof(UnimplementedDeviceState),
+ TYPE_UNIMPLEMENTED_DEVICE);
+ qdev_prop_set_string(DEVICE(uds), "name", name);
+ qdev_prop_set_uint64(DEVICE(uds), "size", size);
+ object_property_set_bool(OBJECT(uds), true, "realized", &error_fatal);
+ return sysbus_mmio_get_region(SYS_BUS_DEVICE(uds), 0);
+}
+
+static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque,
+ const char *name, hwaddr size)
+{
+ CMSDKAPBUART *uart = opaque;
+ int i = uart - &mms->uart[0];
+ Chardev *uartchr = i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL;
+ int rxirqno = i * 2;
+ int txirqno = i * 2 + 1;
+ int combirqno = i + 10;
+ SysBusDevice *s;
+ DeviceState *iotkitdev = DEVICE(&mms->iotkit);
+ DeviceState *orgate_dev = DEVICE(&mms->uart_irq_orgate);
+
+ init_sysbus_child(OBJECT(mms), name, uart,
+ sizeof(mms->uart[0]), TYPE_CMSDK_APB_UART);
+ qdev_prop_set_chr(DEVICE(uart), "chardev", uartchr);
+ qdev_prop_set_uint32(DEVICE(uart), "pclk-frq", SYSCLK_FRQ);
+ object_property_set_bool(OBJECT(uart), true, "realized", &error_fatal);
+ s = SYS_BUS_DEVICE(uart);
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in_named(iotkitdev,
+ "EXP_IRQ", txirqno));
+ sysbus_connect_irq(s, 1, qdev_get_gpio_in_named(iotkitdev,
+ "EXP_IRQ", rxirqno));
+ sysbus_connect_irq(s, 2, qdev_get_gpio_in(orgate_dev, i * 2));
+ sysbus_connect_irq(s, 3, qdev_get_gpio_in(orgate_dev, i * 2 + 1));
+ sysbus_connect_irq(s, 4, qdev_get_gpio_in_named(iotkitdev,
+ "EXP_IRQ", combirqno));
+ return sysbus_mmio_get_region(SYS_BUS_DEVICE(uart), 0);
+}
+
+static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque,
+ const char *name, hwaddr size)
+{
+ MPS2SCC *scc = opaque;
+ DeviceState *sccdev;
+ MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
+
+ object_initialize(scc, sizeof(mms->scc), TYPE_MPS2_SCC);
+ sccdev = DEVICE(scc);
+ qdev_set_parent_bus(sccdev, sysbus_get_default());
+ qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2);
+ qdev_prop_set_uint32(sccdev, "scc-aid", 0x02000008);
+ qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id);
+ object_property_set_bool(OBJECT(scc), true, "realized", &error_fatal);
+ return sysbus_mmio_get_region(SYS_BUS_DEVICE(sccdev), 0);
+}
+
+static MemoryRegion *make_fpgaio(MPS2TZMachineState *mms, void *opaque,
+ const char *name, hwaddr size)
+{
+ MPS2FPGAIO *fpgaio = opaque;
+
+ object_initialize(fpgaio, sizeof(mms->fpgaio), TYPE_MPS2_FPGAIO);
+ qdev_set_parent_bus(DEVICE(fpgaio), sysbus_get_default());
+ object_property_set_bool(OBJECT(fpgaio), true, "realized", &error_fatal);
+ return sysbus_mmio_get_region(SYS_BUS_DEVICE(fpgaio), 0);
+}
+
+static void mps2tz_common_init(MachineState *machine)
+{
+ MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ MemoryRegion *system_memory = get_system_memory();
+ DeviceState *iotkitdev;
+ DeviceState *dev_splitter;
+ int i;
+
+ if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
+ error_report("This board can only be used with CPU %s",
+ mc->default_cpu_type);
+ exit(1);
+ }
+
+ init_sysbus_child(OBJECT(machine), "iotkit", &mms->iotkit,
+ sizeof(mms->iotkit), TYPE_IOTKIT);
+ iotkitdev = DEVICE(&mms->iotkit);
+ object_property_set_link(OBJECT(&mms->iotkit), OBJECT(system_memory),
+ "memory", &error_abort);
+ qdev_prop_set_uint32(iotkitdev, "EXP_NUMIRQ", 92);
+ qdev_prop_set_uint32(iotkitdev, "MAINCLK", SYSCLK_FRQ);
+ object_property_set_bool(OBJECT(&mms->iotkit), true, "realized",
+ &error_fatal);
+
+ /* The sec_resp_cfg output from the IoTKit must be split into multiple
+ * lines, one for each of the PPCs we create here.
+ */
+ object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter),
+ TYPE_SPLIT_IRQ);
+ object_property_add_child(OBJECT(machine), "sec-resp-splitter",
+ OBJECT(&mms->sec_resp_splitter), &error_abort);
+ object_property_set_int(OBJECT(&mms->sec_resp_splitter), 5,
+ "num-lines", &error_fatal);
+ object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true,
+ "realized", &error_fatal);
+ dev_splitter = DEVICE(&mms->sec_resp_splitter);
+ qdev_connect_gpio_out_named(iotkitdev, "sec_resp_cfg", 0,
+ qdev_get_gpio_in(dev_splitter, 0));
+
+ /* The IoTKit sets up much of the memory layout, including
+ * the aliases between secure and non-secure regions in the
+ * address space. The FPGA itself contains:
+ *
+ * 0x00000000..0x003fffff SSRAM1
+ * 0x00400000..0x007fffff alias of SSRAM1
+ * 0x28000000..0x283fffff 4MB SSRAM2 + SSRAM3
+ * 0x40100000..0x4fffffff AHB Master Expansion 1 interface devices
+ * 0x80000000..0x80ffffff 16MB PSRAM
+ */
+
+ /* The FPGA images have an odd combination of different RAMs,
+ * because in hardware they are different implementations and
+ * connected to different buses, giving varying performance/size
+ * tradeoffs. For QEMU they're all just RAM, though. We arbitrarily
+ * call the 16MB our "system memory", as it's the largest lump.
+ */
+ memory_region_allocate_system_memory(&mms->psram,
+ NULL, "mps.ram", 0x01000000);
+ memory_region_add_subregion(system_memory, 0x80000000, &mms->psram);
+
+ /* The SSRAM memories should all be behind Memory Protection Controllers,
+ * but we don't implement that yet.
+ */
+ make_ram(&mms->ssram1, "mps.ssram1", 0x00000000, 0x00400000);
+ make_ram_alias(&mms->ssram1_m, "mps.ssram1_m", &mms->ssram1, 0x00400000);
+
+ make_ram(&mms->ssram23, "mps.ssram23", 0x28000000, 0x00400000);
+
+ /* The overflow IRQs for all UARTs are ORed together.
+ * Tx, Rx and "combined" IRQs are sent to the NVIC separately.
+ * Create the OR gate for this.
+ */
+ object_initialize(&mms->uart_irq_orgate, sizeof(mms->uart_irq_orgate),
+ TYPE_OR_IRQ);
+ object_property_add_child(OBJECT(mms), "uart-irq-orgate",
+ OBJECT(&mms->uart_irq_orgate), &error_abort);
+ object_property_set_int(OBJECT(&mms->uart_irq_orgate), 10, "num-lines",
+ &error_fatal);
+ object_property_set_bool(OBJECT(&mms->uart_irq_orgate), true,
+ "realized", &error_fatal);
+ qdev_connect_gpio_out(DEVICE(&mms->uart_irq_orgate), 0,
+ qdev_get_gpio_in_named(iotkitdev, "EXP_IRQ", 15));
+
+ /* Most of the devices in the FPGA are behind Peripheral Protection
+ * Controllers. The required order for initializing things is:
+ * + initialize the PPC
+ * + initialize, configure and realize downstream devices
+ * + connect downstream device MemoryRegions to the PPC
+ * + realize the PPC
+ * + map the PPC's MemoryRegions to the places in the address map
+ * where the downstream devices should appear
+ * + wire up the PPC's control lines to the IoTKit object
+ */
+
+ const PPCInfo ppcs[] = { {
+ .name = "apb_ppcexp0",
+ .ports = {
+ { "ssram-mpc0", make_unimp_dev, &mms->ssram_mpc[0],
+ 0x58007000, 0x1000 },
+ { "ssram-mpc1", make_unimp_dev, &mms->ssram_mpc[1],
+ 0x58008000, 0x1000 },
+ { "ssram-mpc2", make_unimp_dev, &mms->ssram_mpc[2],
+ 0x58009000, 0x1000 },
+ },
+ }, {
+ .name = "apb_ppcexp1",
+ .ports = {
+ { "spi0", make_unimp_dev, &mms->spi[0], 0x40205000, 0x1000 },
+ { "spi1", make_unimp_dev, &mms->spi[1], 0x40206000, 0x1000 },
+ { "spi2", make_unimp_dev, &mms->spi[2], 0x40209000, 0x1000 },
+ { "spi3", make_unimp_dev, &mms->spi[3], 0x4020a000, 0x1000 },
+ { "spi4", make_unimp_dev, &mms->spi[4], 0x4020b000, 0x1000 },
+ { "uart0", make_uart, &mms->uart[0], 0x40200000, 0x1000 },
+ { "uart1", make_uart, &mms->uart[1], 0x40201000, 0x1000 },
+ { "uart2", make_uart, &mms->uart[2], 0x40202000, 0x1000 },
+ { "uart3", make_uart, &mms->uart[3], 0x40203000, 0x1000 },
+ { "uart4", make_uart, &mms->uart[4], 0x40204000, 0x1000 },
+ { "i2c0", make_unimp_dev, &mms->i2c[0], 0x40207000, 0x1000 },
+ { "i2c1", make_unimp_dev, &mms->i2c[1], 0x40208000, 0x1000 },
+ { "i2c2", make_unimp_dev, &mms->i2c[2], 0x4020c000, 0x1000 },
+ { "i2c3", make_unimp_dev, &mms->i2c[3], 0x4020d000, 0x1000 },
+ },
+ }, {
+ .name = "apb_ppcexp2",
+ .ports = {
+ { "scc", make_scc, &mms->scc, 0x40300000, 0x1000 },
+ { "i2s-audio", make_unimp_dev, &mms->i2s_audio,
+ 0x40301000, 0x1000 },
+ { "fpgaio", make_fpgaio, &mms->fpgaio, 0x40302000, 0x1000 },
+ },
+ }, {
+ .name = "ahb_ppcexp0",
+ .ports = {
+ { "gfx", make_unimp_dev, &mms->gfx, 0x41000000, 0x140000 },
+ { "gpio0", make_unimp_dev, &mms->gpio[0], 0x40100000, 0x1000 },
+ { "gpio1", make_unimp_dev, &mms->gpio[1], 0x40101000, 0x1000 },
+ { "gpio2", make_unimp_dev, &mms->gpio[2], 0x40102000, 0x1000 },
+ { "gpio3", make_unimp_dev, &mms->gpio[3], 0x40103000, 0x1000 },
+ { "gpio4", make_unimp_dev, &mms->gpio[4], 0x40104000, 0x1000 },
+ },
+ }, {
+ .name = "ahb_ppcexp1",
+ .ports = {
+ { "dma0", make_unimp_dev, &mms->dma[0], 0x40110000, 0x1000 },
+ { "dma1", make_unimp_dev, &mms->dma[1], 0x40111000, 0x1000 },
+ { "dma2", make_unimp_dev, &mms->dma[2], 0x40112000, 0x1000 },
+ { "dma3", make_unimp_dev, &mms->dma[3], 0x40113000, 0x1000 },
+ },
+ },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(ppcs); i++) {
+ const PPCInfo *ppcinfo = &ppcs[i];
+ TZPPC *ppc = &mms->ppc[i];
+ DeviceState *ppcdev;
+ int port;
+ char *gpioname;
+
+ init_sysbus_child(OBJECT(machine), ppcinfo->name, ppc,
+ sizeof(TZPPC), TYPE_TZ_PPC);
+ ppcdev = DEVICE(ppc);
+
+ for (port = 0; port < TZ_NUM_PORTS; port++) {
+ const PPCPortInfo *pinfo = &ppcinfo->ports[port];
+ MemoryRegion *mr;
+ char *portname;
+
+ if (!pinfo->devfn) {
+ continue;
+ }
+
+ mr = pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->size);
+ portname = g_strdup_printf("port[%d]", port);
+ object_property_set_link(OBJECT(ppc), OBJECT(mr),
+ portname, &error_fatal);
+ g_free(portname);
+ }
+
+ object_property_set_bool(OBJECT(ppc), true, "realized", &error_fatal);
+
+ for (port = 0; port < TZ_NUM_PORTS; port++) {
+ const PPCPortInfo *pinfo = &ppcinfo->ports[port];
+
+ if (!pinfo->devfn) {
+ continue;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(ppc), port, pinfo->addr);
+
+ gpioname = g_strdup_printf("%s_nonsec", ppcinfo->name);
+ qdev_connect_gpio_out_named(iotkitdev, gpioname, port,
+ qdev_get_gpio_in_named(ppcdev,
+ "cfg_nonsec",
+ port));
+ g_free(gpioname);
+ gpioname = g_strdup_printf("%s_ap", ppcinfo->name);
+ qdev_connect_gpio_out_named(iotkitdev, gpioname, port,
+ qdev_get_gpio_in_named(ppcdev,
+ "cfg_ap", port));
+ g_free(gpioname);
+ }
+
+ gpioname = g_strdup_printf("%s_irq_enable", ppcinfo->name);
+ qdev_connect_gpio_out_named(iotkitdev, gpioname, 0,
+ qdev_get_gpio_in_named(ppcdev,
+ "irq_enable", 0));
+ g_free(gpioname);
+ gpioname = g_strdup_printf("%s_irq_clear", ppcinfo->name);
+ qdev_connect_gpio_out_named(iotkitdev, gpioname, 0,
+ qdev_get_gpio_in_named(ppcdev,
+ "irq_clear", 0));
+ g_free(gpioname);
+ gpioname = g_strdup_printf("%s_irq_status", ppcinfo->name);
+ qdev_connect_gpio_out_named(ppcdev, "irq", 0,
+ qdev_get_gpio_in_named(iotkitdev,
+ gpioname, 0));
+ g_free(gpioname);
+
+ qdev_connect_gpio_out(dev_splitter, i,
+ qdev_get_gpio_in_named(ppcdev,
+ "cfg_sec_resp", 0));
+ }
+
+ /* In hardware this is a LAN9220; the LAN9118 is software compatible
+ * except that it doesn't support the checksum-offload feature.
+ * The ethernet controller is not behind a PPC.
+ */
+ lan9118_init(&nd_table[0], 0x42000000,
+ qdev_get_gpio_in_named(iotkitdev, "EXP_IRQ", 16));
+
+ create_unimplemented_device("FPGA NS PC", 0x48007000, 0x1000);
+
+ armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x400000);
+}
+
+static void mps2tz_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->init = mps2tz_common_init;
+ mc->max_cpus = 1;
+}
+
+static void mps2tz_an505_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc);
+
+ mc->desc = "ARM MPS2 with AN505 FPGA image for Cortex-M33";
+ mmc->fpga_type = FPGA_AN505;
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33");
+ mmc->scc_id = 0x41040000 | (505 << 4);
+}
+
+static const TypeInfo mps2tz_info = {
+ .name = TYPE_MPS2TZ_MACHINE,
+ .parent = TYPE_MACHINE,
+ .abstract = true,
+ .instance_size = sizeof(MPS2TZMachineState),
+ .class_size = sizeof(MPS2TZMachineClass),
+ .class_init = mps2tz_class_init,
+};
+
+static const TypeInfo mps2tz_an505_info = {
+ .name = TYPE_MPS2TZ_AN505_MACHINE,
+ .parent = TYPE_MPS2TZ_MACHINE,
+ .class_init = mps2tz_an505_class_init,
+};
+
+static void mps2tz_machine_init(void)
+{
+ type_register_static(&mps2tz_info);
+ type_register_static(&mps2tz_an505_info);
+}
+
+type_init(mps2tz_machine_init);
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index dc5928ae1a..9fad79177a 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -29,6 +29,7 @@
#include "hw/arm/arm.h"
#include "hw/arm/primecell.h"
#include "hw/devices.h"
+#include "hw/i2c/i2c.h"
#include "net/net.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
@@ -537,6 +538,7 @@ static void vexpress_common_init(MachineState *machine)
uint32_t sys_id;
DriveInfo *dinfo;
pflash_t *pflash0;
+ I2CBus *i2c;
ram_addr_t vram_size, sram_size;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *vram = g_new(MemoryRegion, 1);
@@ -628,7 +630,9 @@ static void vexpress_common_init(MachineState *machine)
sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]);
sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]);
- /* VE_SERIALDVI: not modelled */
+ dev = sysbus_create_simple("versatile_i2c", map[VE_SERIALDVI], NULL);
+ i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
+ i2c_create_slave(i2c, "sii9022", 0x39);
sysbus_create_simple("pl031", map[VE_RTC], pic[4]); /* RTC */
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 4b93a3abd2..69227fd4c9 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -53,6 +53,9 @@
#define IPI_ADDR 0xFF300000
#define IPI_IRQ 64
+#define RTC_ADDR 0xffa60000
+#define RTC_IRQ 26
+
#define SDHCI_CAPABILITIES 0x280737ec6481 /* Datasheet: UG1085 (v1.7) */
static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = {
@@ -191,6 +194,9 @@ static void xlnx_zynqmp_init(Object *obj)
object_initialize(&s->ipi, sizeof(s->ipi), TYPE_XLNX_ZYNQMP_IPI);
qdev_set_parent_bus(DEVICE(&s->ipi), sysbus_get_default());
+
+ object_initialize(&s->rtc, sizeof(s->rtc), TYPE_XLNX_ZYNQMP_RTC);
+ qdev_set_parent_bus(DEVICE(&s->rtc), sysbus_get_default());
}
static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
@@ -476,6 +482,14 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ipi), 0, IPI_ADDR);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ipi), 0, gic_spi[IPI_IRQ]);
+
+ object_property_set_bool(OBJECT(&s->rtc), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, RTC_ADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0, gic_spi[RTC_IRQ]);
}
static Property xlnx_zynqmp_props[] = {
diff --git a/hw/block/block.c b/hw/block/block.c
index b0269c857f..b91e2b6d7e 100644
--- a/hw/block/block.c
+++ b/hw/block/block.c
@@ -12,6 +12,7 @@
#include "sysemu/block-backend.h"
#include "hw/block/block.h"
#include "qapi/error.h"
+#include "qapi/qapi-types-block.h"
#include "qemu/error-report.h"
void blkconf_serial(BlockConf *conf, char **serial)
diff --git a/hw/block/hd-geometry.c b/hw/block/hd-geometry.c
index 57ad5012a7..79384a2b0a 100644
--- a/hw/block/hd-geometry.c
+++ b/hw/block/hd-geometry.c
@@ -32,6 +32,7 @@
#include "qemu/osdep.h"
#include "sysemu/block-backend.h"
+#include "qapi/qapi-types-block.h"
#include "qemu/bswap.h"
#include "hw/block/block.h"
#include "trace.h"
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
index 4be5d4ee52..679a824888 100644
--- a/hw/char/virtio-console.c
+++ b/hw/char/virtio-console.c
@@ -15,8 +15,8 @@
#include "qemu/error-report.h"
#include "trace.h"
#include "hw/virtio/virtio-serial.h"
-#include "qapi-event.h"
#include "qapi/error.h"
+#include "qapi/qapi-events-char.h"
#define TYPE_VIRTIO_CONSOLE_SERIAL_PORT "virtserialport"
#define VIRTIO_CONSOLE(obj) \
diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index 1240728c87..eb88ca979e 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -18,6 +18,7 @@ common-obj-$(CONFIG_FITLOADER) += loader-fit.o
common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
common-obj-$(CONFIG_SOFTMMU) += register.o
common-obj-$(CONFIG_SOFTMMU) += or-irq.o
+common-obj-$(CONFIG_SOFTMMU) += split-irq.o
common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o
obj-$(CONFIG_SOFTMMU) += generic-loader.o
diff --git a/hw/core/loader.c b/hw/core/loader.c
index c08f130461..76b244c508 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -730,8 +730,14 @@ int load_uimage_as(const char *filename, hwaddr *ep, hwaddr *loadaddr,
/* Load a ramdisk. */
int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
{
+ return load_ramdisk_as(filename, addr, max_sz, NULL);
+}
+
+int load_ramdisk_as(const char *filename, hwaddr addr, uint64_t max_sz,
+ AddressSpace *as)
+{
return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK,
- NULL, NULL, NULL);
+ NULL, NULL, as);
}
/* Load a gzip-compressed kernel to a dynamically allocated buffer. */
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 5d445839e8..5e2bbcdace 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include "hw/boards.h"
#include "qapi/error.h"
-#include "qapi-visit.h"
+#include "qapi/qapi-visit-common.h"
#include "qapi/visitor.h"
#include "hw/sysbus.h"
#include "sysemu/sysemu.h"
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 7ed1f431f0..f6f92473b8 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -29,6 +29,7 @@
#include "hw/qdev.h"
#include "sysemu/sysemu.h"
#include "qapi/error.h"
+#include "qapi/qapi-events-misc.h"
#include "qapi/qmp/qerror.h"
#include "qapi/visitor.h"
#include "qemu/error-report.h"
@@ -36,7 +37,6 @@
#include "hw/hotplug.h"
#include "hw/boards.h"
#include "hw/sysbus.h"
-#include "qapi-event.h"
bool qdev_hotplug = false;
static bool qdev_hot_added = false;
@@ -385,15 +385,17 @@ static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev,
return ngl;
}
-void qdev_init_gpio_in_named(DeviceState *dev, qemu_irq_handler handler,
- const char *name, int n)
+void qdev_init_gpio_in_named_with_opaque(DeviceState *dev,
+ qemu_irq_handler handler,
+ void *opaque,
+ const char *name, int n)
{
int i;
NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
assert(gpio_list->num_out == 0 || !name);
gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler,
- dev, n);
+ opaque, n);
if (!name) {
name = "unnamed-gpio-in";
diff --git a/hw/core/register.c b/hw/core/register.c
index 900294b9c4..0741a1af32 100644
--- a/hw/core/register.c
+++ b/hw/core/register.c
@@ -159,13 +159,21 @@ uint64_t register_read(RegisterInfo *reg, uint64_t re, const char* prefix,
void register_reset(RegisterInfo *reg)
{
+ const RegisterAccessInfo *ac;
+
g_assert(reg);
if (!reg->data || !reg->access) {
return;
}
+ ac = reg->access;
+
register_write_val(reg, reg->access->reset);
+
+ if (ac->post_write) {
+ ac->post_write(reg, reg->access->reset);
+ }
}
void register_init(RegisterInfo *reg)
diff --git a/hw/core/split-irq.c b/hw/core/split-irq.c
new file mode 100644
index 0000000000..7e64cd4969
--- /dev/null
+++ b/hw/core/split-irq.c
@@ -0,0 +1,89 @@
+/*
+ * IRQ splitter device.
+ *
+ * Copyright (c) 2018 Linaro Limited.
+ * Written by Peter Maydell
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/split-irq.h"
+#include "qapi/error.h"
+
+static void split_irq_handler(void *opaque, int n, int level)
+{
+ SplitIRQ *s = SPLIT_IRQ(opaque);
+ int i;
+
+ for (i = 0; i < s->num_lines; i++) {
+ qemu_set_irq(s->out_irq[i], level);
+ }
+}
+
+static void split_irq_init(Object *obj)
+{
+ qdev_init_gpio_in(DEVICE(obj), split_irq_handler, 1);
+}
+
+static void split_irq_realize(DeviceState *dev, Error **errp)
+{
+ SplitIRQ *s = SPLIT_IRQ(dev);
+
+ if (s->num_lines < 1 || s->num_lines >= MAX_SPLIT_LINES) {
+ error_setg(errp,
+ "IRQ splitter number of lines %d is not between 1 and %d",
+ s->num_lines, MAX_SPLIT_LINES);
+ return;
+ }
+
+ qdev_init_gpio_out(dev, s->out_irq, s->num_lines);
+}
+
+static Property split_irq_properties[] = {
+ DEFINE_PROP_UINT16("num-lines", SplitIRQ, num_lines, 1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void split_irq_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ /* No state to reset or migrate */
+ dc->props = split_irq_properties;
+ dc->realize = split_irq_realize;
+
+ /* Reason: Needs to be wired up to work */
+ dc->user_creatable = false;
+}
+
+static const TypeInfo split_irq_type_info = {
+ .name = TYPE_SPLIT_IRQ,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SplitIRQ),
+ .instance_init = split_irq_init,
+ .class_init = split_irq_class_init,
+};
+
+static void split_irq_register_types(void)
+{
+ type_register_static(&split_irq_type_info);
+}
+
+type_init(split_irq_register_types)
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index d3a4cb396e..3c7c75b94d 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -3,6 +3,7 @@ common-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o
common-obj-$(CONFIG_G364FB) += g364fb.o
common-obj-$(CONFIG_JAZZ_LED) += jazz_led.o
common-obj-$(CONFIG_PL110) += pl110.o
+common-obj-$(CONFIG_SII9022) += sii9022.o
common-obj-$(CONFIG_SSD0303) += ssd0303.o
common-obj-$(CONFIG_SSD0323) += ssd0323.o
common-obj-$(CONFIG_XEN) += xenfb.o
diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c
index 819f8be05d..3d75394e77 100644
--- a/hw/display/g364fb.c
+++ b/hw/display/g364fb.c
@@ -207,6 +207,7 @@ done:
if (xmax || ymax) {
dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
}
+ g_free(snap);
}
static void g364fb_draw_blank(G364State *s)
diff --git a/hw/display/sii9022.c b/hw/display/sii9022.c
new file mode 100644
index 0000000000..eaf11a6e7b
--- /dev/null
+++ b/hw/display/sii9022.c
@@ -0,0 +1,191 @@
+/*
+ * Silicon Image SiI9022
+ *
+ * This is a pretty hollow emulation: all we do is acknowledge that we
+ * exist (chip ID) and confirm that we get switched over into DDC mode
+ * so the emulated host can proceed to read out EDID data. All subsequent
+ * set-up of connectors etc will be acknowledged and ignored.
+ *
+ * Copyright (C) 2018 Linus Walleij
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "hw/i2c/i2c.h"
+#include "hw/i2c/i2c-ddc.h"
+#include "trace.h"
+
+#define SII9022_SYS_CTRL_DATA 0x1a
+#define SII9022_SYS_CTRL_PWR_DWN 0x10
+#define SII9022_SYS_CTRL_AV_MUTE 0x08
+#define SII9022_SYS_CTRL_DDC_BUS_REQ 0x04
+#define SII9022_SYS_CTRL_DDC_BUS_GRTD 0x02
+#define SII9022_SYS_CTRL_OUTPUT_MODE 0x01
+#define SII9022_SYS_CTRL_OUTPUT_HDMI 1
+#define SII9022_SYS_CTRL_OUTPUT_DVI 0
+#define SII9022_REG_CHIPID 0x1b
+#define SII9022_INT_ENABLE 0x3c
+#define SII9022_INT_STATUS 0x3d
+#define SII9022_INT_STATUS_HOTPLUG 0x01;
+#define SII9022_INT_STATUS_PLUGGED 0x04;
+
+#define TYPE_SII9022 "sii9022"
+#define SII9022(obj) OBJECT_CHECK(sii9022_state, (obj), TYPE_SII9022)
+
+typedef struct sii9022_state {
+ I2CSlave parent_obj;
+ uint8_t ptr;
+ bool addr_byte;
+ bool ddc_req;
+ bool ddc_skip_finish;
+ bool ddc;
+} sii9022_state;
+
+static const VMStateDescription vmstate_sii9022 = {
+ .name = "sii9022",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_I2C_SLAVE(parent_obj, sii9022_state),
+ VMSTATE_UINT8(ptr, sii9022_state),
+ VMSTATE_BOOL(addr_byte, sii9022_state),
+ VMSTATE_BOOL(ddc_req, sii9022_state),
+ VMSTATE_BOOL(ddc_skip_finish, sii9022_state),
+ VMSTATE_BOOL(ddc, sii9022_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int sii9022_event(I2CSlave *i2c, enum i2c_event event)
+{
+ sii9022_state *s = SII9022(i2c);
+
+ switch (event) {
+ case I2C_START_SEND:
+ s->addr_byte = true;
+ break;
+ case I2C_START_RECV:
+ break;
+ case I2C_FINISH:
+ break;
+ case I2C_NACK:
+ break;
+ }
+
+ return 0;
+}
+
+static int sii9022_rx(I2CSlave *i2c)
+{
+ sii9022_state *s = SII9022(i2c);
+ uint8_t res = 0x00;
+
+ switch (s->ptr) {
+ case SII9022_SYS_CTRL_DATA:
+ if (s->ddc_req) {
+ /* Acknowledge DDC bus request */
+ res = SII9022_SYS_CTRL_DDC_BUS_GRTD | SII9022_SYS_CTRL_DDC_BUS_REQ;
+ }
+ break;
+ case SII9022_REG_CHIPID:
+ res = 0xb0;
+ break;
+ case SII9022_INT_STATUS:
+ /* Something is cold-plugged in, no interrupts */
+ res = SII9022_INT_STATUS_PLUGGED;
+ break;
+ default:
+ break;
+ }
+
+ trace_sii9022_read_reg(s->ptr, res);
+ s->ptr++;
+
+ return res;
+}
+
+static int sii9022_tx(I2CSlave *i2c, uint8_t data)
+{
+ sii9022_state *s = SII9022(i2c);
+
+ if (s->addr_byte) {
+ s->ptr = data;
+ s->addr_byte = false;
+ return 0;
+ }
+
+ switch (s->ptr) {
+ case SII9022_SYS_CTRL_DATA:
+ if (data & SII9022_SYS_CTRL_DDC_BUS_REQ) {
+ s->ddc_req = true;
+ if (data & SII9022_SYS_CTRL_DDC_BUS_GRTD) {
+ s->ddc = true;
+ /* Skip this finish since we just switched to DDC */
+ s->ddc_skip_finish = true;
+ trace_sii9022_switch_mode("DDC");
+ }
+ } else {
+ s->ddc_req = false;
+ s->ddc = false;
+ trace_sii9022_switch_mode("normal");
+ }
+ break;
+ default:
+ break;
+ }
+
+ trace_sii9022_write_reg(s->ptr, data);
+ s->ptr++;
+
+ return 0;
+}
+
+static void sii9022_reset(DeviceState *dev)
+{
+ sii9022_state *s = SII9022(dev);
+
+ s->ptr = 0;
+ s->addr_byte = false;
+ s->ddc_req = false;
+ s->ddc_skip_finish = false;
+ s->ddc = false;
+}
+
+static void sii9022_realize(DeviceState *dev, Error **errp)
+{
+ I2CBus *bus;
+
+ bus = I2C_BUS(qdev_get_parent_bus(dev));
+ i2c_create_slave(bus, TYPE_I2CDDC, 0x50);
+}
+
+static void sii9022_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->event = sii9022_event;
+ k->recv = sii9022_rx;
+ k->send = sii9022_tx;
+ dc->reset = sii9022_reset;
+ dc->realize = sii9022_realize;
+ dc->vmsd = &vmstate_sii9022;
+}
+
+static const TypeInfo sii9022_info = {
+ .name = TYPE_SII9022,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(sii9022_state),
+ .class_init = sii9022_class_init,
+};
+
+static void sii9022_register_types(void)
+{
+ type_register_static(&sii9022_info);
+}
+
+type_init(sii9022_register_types)
diff --git a/hw/display/trace-events b/hw/display/trace-events
index da498c1def..5a48c6cb6a 100644
--- a/hw/display/trace-events
+++ b/hw/display/trace-events
@@ -132,3 +132,8 @@ vga_cirrus_read_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x"
vga_cirrus_write_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x"
vga_cirrus_read_blt(uint32_t offset, uint32_t val) "offset 0x%x, val 0x%x"
vga_cirrus_write_blt(uint32_t offset, uint32_t val) "offset 0x%x, val 0x%x"
+
+# hw/display/sii9022.c
+sii9022_read_reg(uint8_t addr, uint8_t val) "addr 0x%02x, val 0x%02x"
+sii9022_write_reg(uint8_t addr, uint8_t val) "addr 0x%02x, val 0x%02x"
+sii9022_switch_mode(const char *mode) "mode: %s"
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index 59068f157e..cfccefca3d 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -10,31 +10,13 @@
#include "qemu/osdep.h"
#include "hw/i2c/i2c.h"
-typedef struct I2CNode I2CNode;
-
-struct I2CNode {
- I2CSlave *elt;
- QLIST_ENTRY(I2CNode) next;
-};
-
#define I2C_BROADCAST 0x00
-struct I2CBus
-{
- BusState qbus;
- QLIST_HEAD(, I2CNode) current_devs;
- uint8_t saved_address;
- bool broadcast;
-};
-
static Property i2c_props[] = {
DEFINE_PROP_UINT8("address", struct I2CSlave, address, 0),
DEFINE_PROP_END_OF_LIST(),
};
-#define TYPE_I2C_BUS "i2c-bus"
-#define I2C_BUS(obj) OBJECT_CHECK(I2CBus, (obj), TYPE_I2C_BUS)
-
static const TypeInfo i2c_bus_info = {
.name = TYPE_I2C_BUS,
.parent = TYPE_BUS,
diff --git a/hw/i2c/i2c-ddc.c b/hw/i2c/i2c-ddc.c
index 199dac9e41..bec0c91e2d 100644
--- a/hw/i2c/i2c-ddc.c
+++ b/hw/i2c/i2c-ddc.c
@@ -259,12 +259,12 @@ static int i2c_ddc_tx(I2CSlave *i2c, uint8_t data)
s->reg = data;
s->firstbyte = false;
DPRINTF("[EDID] Written new pointer: %u\n", data);
- return 1;
+ return 0;
}
/* Ignore all writes */
s->reg++;
- return 1;
+ return 0;
}
static void i2c_ddc_init(Object *obj)
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 2e841cde27..fb31de9416 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -2129,8 +2129,15 @@ static void vtd_mem_write(void *opaque, hwaddr addr,
/* Fault Event Address Register, 32-bit */
case DMAR_FEADDR_REG:
- assert(size == 4);
- vtd_set_long(s, addr, val);
+ if (size == 4) {
+ vtd_set_long(s, addr, val);
+ } else {
+ /*
+ * While the register is 32-bit only, some guests (Xen...) write to
+ * it with 64-bit.
+ */
+ vtd_set_quad(s, addr, val);
+ }
break;
/* Fault Event Upper Address Register, 32-bit */
diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c
index 46d9c68bf5..b9064264d8 100644
--- a/hw/i386/multiboot.c
+++ b/hw/i386/multiboot.c
@@ -31,12 +31,13 @@
#include "hw/loader.h"
#include "elf.h"
#include "sysemu/sysemu.h"
+#include "qemu/error-report.h"
/* Show multiboot debug output */
//#define DEBUG_MULTIBOOT
#ifdef DEBUG_MULTIBOOT
-#define mb_debug(a...) fprintf(stderr, ## a)
+#define mb_debug(a...) error_report(a)
#else
#define mb_debug(a...)
#endif
@@ -137,7 +138,7 @@ static void mb_add_mod(MultibootState *s,
stl_p(p + MB_MOD_END, end);
stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
- mb_debug("mod%02d: "TARGET_FMT_plx" - "TARGET_FMT_plx"\n",
+ mb_debug("mod%02d: "TARGET_FMT_plx" - "TARGET_FMT_plx,
s->mb_mods_count, start, end);
s->mb_mods_count++;
@@ -179,12 +180,12 @@ int load_multiboot(FWCfgState *fw_cfg,
if (!is_multiboot)
return 0; /* no multiboot */
- mb_debug("qemu: I believe we found a multiboot image!\n");
+ mb_debug("qemu: I believe we found a multiboot image!");
memset(bootinfo, 0, sizeof(bootinfo));
memset(&mbs, 0, sizeof(mbs));
if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */
- fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
+ error_report("qemu: multiboot knows VBE. we don't.");
}
if (!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */
uint64_t elf_entry;
@@ -193,7 +194,7 @@ int load_multiboot(FWCfgState *fw_cfg,
fclose(f);
if (((struct elf64_hdr*)header)->e_machine == EM_X86_64) {
- fprintf(stderr, "Cannot load x86-64 image, give a 32bit one.\n");
+ error_report("Cannot load x86-64 image, give a 32bit one.");
exit(1);
}
@@ -201,7 +202,7 @@ int load_multiboot(FWCfgState *fw_cfg,
&elf_low, &elf_high, 0, I386_ELF_MACHINE,
0, 0);
if (kernel_size < 0) {
- fprintf(stderr, "Error while loading elf kernel\n");
+ error_report("Error while loading elf kernel");
exit(1);
}
mh_load_addr = elf_low;
@@ -210,12 +211,13 @@ int load_multiboot(FWCfgState *fw_cfg,
mbs.mb_buf = g_malloc(mb_kernel_size);
if (rom_copy(mbs.mb_buf, mh_load_addr, mb_kernel_size) != mb_kernel_size) {
- fprintf(stderr, "Error while fetching elf kernel from rom\n");
+ error_report("Error while fetching elf kernel from rom");
exit(1);
}
- mb_debug("qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
- mb_kernel_size, (size_t)mh_entry_addr);
+ mb_debug("qemu: loading multiboot-elf kernel "
+ "(%#x bytes) with entry %#zx",
+ mb_kernel_size, (size_t)mh_entry_addr);
} else {
/* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
uint32_t mh_header_addr = ldl_p(header+i+12);
@@ -224,7 +226,7 @@ int load_multiboot(FWCfgState *fw_cfg,
mh_load_addr = ldl_p(header+i+16);
if (mh_header_addr < mh_load_addr) {
- fprintf(stderr, "invalid mh_load_addr address\n");
+ error_report("invalid load_addr address");
exit(1);
}
@@ -233,43 +235,39 @@ int load_multiboot(FWCfgState *fw_cfg,
mh_entry_addr = ldl_p(header+i+28);
if (mh_load_end_addr) {
- if (mh_bss_end_addr < mh_load_addr) {
- fprintf(stderr, "invalid mh_bss_end_addr address\n");
- exit(1);
- }
- mb_kernel_size = mh_bss_end_addr - mh_load_addr;
-
if (mh_load_end_addr < mh_load_addr) {
- fprintf(stderr, "invalid mh_load_end_addr address\n");
+ error_report("invalid load_end_addr address");
exit(1);
}
mb_load_size = mh_load_end_addr - mh_load_addr;
} else {
if (kernel_file_size < mb_kernel_text_offset) {
- fprintf(stderr, "invalid kernel_file_size\n");
+ error_report("invalid kernel_file_size");
exit(1);
}
- mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
- mb_load_size = mb_kernel_size;
+ mb_load_size = kernel_file_size - mb_kernel_text_offset;
+ }
+ if (mh_bss_end_addr) {
+ if (mh_bss_end_addr < (mh_load_addr + mb_load_size)) {
+ error_report("invalid bss_end_addr address");
+ exit(1);
+ }
+ mb_kernel_size = mh_bss_end_addr - mh_load_addr;
+ } else {
+ mb_kernel_size = mb_load_size;
}
- /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
- uint32_t mh_mode_type = ldl_p(header+i+32);
- uint32_t mh_width = ldl_p(header+i+36);
- uint32_t mh_height = ldl_p(header+i+40);
- uint32_t mh_depth = ldl_p(header+i+44); */
-
- mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
- mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
- mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
- mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
- mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
+ mb_debug("multiboot: header_addr = %#x", mh_header_addr);
+ mb_debug("multiboot: load_addr = %#x", mh_load_addr);
+ mb_debug("multiboot: load_end_addr = %#x", mh_load_end_addr);
+ mb_debug("multiboot: bss_end_addr = %#x", mh_bss_end_addr);
+ mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x",
mb_load_size, mh_load_addr);
mbs.mb_buf = g_malloc(mb_kernel_size);
fseek(f, mb_kernel_text_offset, SEEK_SET);
if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) {
- fprintf(stderr, "fread() failed\n");
+ error_report("fread() failed");
exit(1);
}
memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size);
@@ -323,10 +321,10 @@ int load_multiboot(FWCfgState *fw_cfg,
hwaddr c = mb_add_cmdline(&mbs, tmpbuf);
if ((next_space = strchr(tmpbuf, ' ')))
*next_space = '\0';
- mb_debug("multiboot loading module: %s\n", tmpbuf);
+ mb_debug("multiboot loading module: %s", tmpbuf);
mb_mod_length = get_image_size(tmpbuf);
if (mb_mod_length < 0) {
- fprintf(stderr, "Failed to open file '%s'\n", tmpbuf);
+ error_report("Failed to open file '%s'", tmpbuf);
exit(1);
}
@@ -337,7 +335,7 @@ int load_multiboot(FWCfgState *fw_cfg,
mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
mbs.mb_buf_phys + offs + mb_mod_length, c);
- mb_debug("mod_start: %p\nmod_end: %p\n cmdline: "TARGET_FMT_plx"\n",
+ mb_debug("mod_start: %p\nmod_end: %p\n cmdline: "TARGET_FMT_plx,
(char *)mbs.mb_buf + offs,
(char *)mbs.mb_buf + offs + mb_mod_length, c);
initrd_filename = next_initrd+1;
@@ -365,10 +363,11 @@ int load_multiboot(FWCfgState *fw_cfg,
stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
stl_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP);
- mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
- mb_debug(" mb_buf_phys = "TARGET_FMT_plx"\n", mbs.mb_buf_phys);
- mb_debug(" mod_start = "TARGET_FMT_plx"\n", mbs.mb_buf_phys + mbs.offset_mods);
- mb_debug(" mb_mods_count = %d\n", mbs.mb_mods_count);
+ mb_debug("multiboot: entry_addr = %#x", mh_entry_addr);
+ mb_debug(" mb_buf_phys = "TARGET_FMT_plx, mbs.mb_buf_phys);
+ mb_debug(" mod_start = "TARGET_FMT_plx,
+ mbs.mb_buf_phys + mbs.offset_mods);
+ mb_debug(" mb_mods_count = %d", mbs.mb_mods_count);
/* save bootinfo off the stack */
mb_bootinfo_data = g_memdup(bootinfo, sizeof(bootinfo));
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 55e69d66fe..35fcb6efdf 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -67,8 +67,8 @@
#include "acpi-build.h"
#include "hw/mem/pc-dimm.h"
#include "qapi/error.h"
+#include "qapi/qapi-visit-common.h"
#include "qapi/visitor.h"
-#include "qapi-visit.h"
#include "qom/cpu.h"
#include "hw/nmi.h"
#include "hw/i386/intel_iommu.h"
@@ -1636,23 +1636,6 @@ void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
rom_reset_order_override();
}
-void pc_pci_device_init(PCIBus *pci_bus)
-{
- int max_bus;
- int bus;
-
- /* Note: if=scsi is deprecated with PC machine types */
- max_bus = drive_get_max_bus(IF_SCSI);
- for (bus = 0; bus <= max_bus; bus++) {
- pci_create_simple(pci_bus, -1, "lsi53c895a");
- /*
- * By not creating frontends here, we make
- * scsi_legacy_handle_cmdline() create them, and warn that
- * this usage is deprecated.
- */
- }
-}
-
void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
{
DeviceState *dev;
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 456dc9e9f0..8658bcba63 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -295,10 +295,6 @@ static void pc_init1(MachineState *machine,
PC_MACHINE_ACPI_DEVICE_PROP, &error_abort);
}
- if (pcmc->pci_enabled) {
- pc_pci_device_init(pci_bus);
- }
-
if (pcms->acpi_nvdimm_state.is_enabled) {
nvdimm_init_acpi_state(&pcms->acpi_nvdimm_state, system_io,
pcms->fw_cfg, OBJECT(pcms));
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index aba7541a82..0c0bc48137 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -273,9 +273,6 @@ static void pc_q35_init(MachineState *machine)
/* the rest devices to which pci devfn is automatically assigned */
pc_vga_init(isa_bus, host_bus);
pc_nic_init(isa_bus, host_bus);
- if (pcmc->pci_enabled) {
- pc_pci_device_init(host_bus);
- }
if (pcms->acpi_nvdimm_state.is_enabled) {
nvdimm_init_acpi_state(&pcms->acpi_nvdimm_state, system_io,
diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c
index bfdbe55580..f24b7d4923 100644
--- a/hw/i386/xen/xen-hvm.c
+++ b/hw/i386/xen/xen-hvm.c
@@ -16,8 +16,8 @@
#include "hw/i386/apic-msidef.h"
#include "hw/xen/xen_common.h"
#include "hw/xen/xen_backend.h"
-#include "qmp-commands.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-misc.h"
#include "qemu/error-report.h"
#include "qemu/range.h"
#include "sysemu/xen-mapcache.h"
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 257b429381..139c843514 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1087,15 +1087,7 @@ static void ide_flush_cache(IDEState *s)
s->status |= BUSY_STAT;
ide_set_retry(s);
block_acct_start(blk_get_stats(s->blk), &s->acct, 0, BLOCK_ACCT_FLUSH);
-
- if (blk_bs(s->blk)) {
- s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
- } else {
- /* XXX blk_aio_flush() crashes when blk_bs(blk) is NULL, remove this
- * temporary workaround when blk_aio_*() functions handle NULL blk_bs.
- */
- ide_flush_cb(s, 0);
- }
+ s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
}
static void ide_cfata_metadata_inquiry(IDEState *s)
diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c
index 266aed1b7b..50b62712c8 100644
--- a/hw/input/adb-kbd.c
+++ b/hw/input/adb-kbd.c
@@ -258,6 +258,7 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
case ADB_CMD_CHANGE_ID_AND_ACT:
case ADB_CMD_CHANGE_ID_AND_ENABLE:
d->devaddr = buf[1] & 0xf;
+ trace_adb_kbd_request_change_addr(d->devaddr);
break;
default:
d->devaddr = buf[1] & 0xf;
@@ -269,6 +270,9 @@ static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) {
d->handler = buf[2];
}
+
+ trace_adb_kbd_request_change_addr_and_handler(d->devaddr,
+ d->handler);
break;
}
}
diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c
index 47e88faf25..3ba6027d33 100644
--- a/hw/input/adb-mouse.c
+++ b/hw/input/adb-mouse.c
@@ -118,6 +118,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
s->dx = 0;
s->dy = 0;
s->dz = 0;
+ trace_adb_mouse_flush();
return 0;
}
@@ -138,6 +139,7 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
case ADB_CMD_CHANGE_ID_AND_ACT:
case ADB_CMD_CHANGE_ID_AND_ENABLE:
d->devaddr = buf[1] & 0xf;
+ trace_adb_mouse_request_change_addr(d->devaddr);
break;
default:
d->devaddr = buf[1] & 0xf;
@@ -155,6 +157,9 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
if (buf[2] == 1 || buf[2] == 2) {
d->handler = buf[2];
}
+
+ trace_adb_mouse_request_change_addr_and_handler(d->devaddr,
+ d->handler);
break;
}
}
diff --git a/hw/input/trace-events b/hw/input/trace-events
index 5affabc81d..db72484a25 100644
--- a/hw/input/trace-events
+++ b/hw/input/trace-events
@@ -4,10 +4,15 @@
adb_kbd_no_key(void) "Ignoring NO_KEY"
adb_kbd_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x"
adb_kbd_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x"
+adb_kbd_request_change_addr(int devaddr) "change addr to 0x%x"
+adb_kbd_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x"
# hw/input/adb-mouse.c
+adb_mouse_flush(void) "flush"
adb_mouse_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x"
adb_mouse_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x"
+adb_mouse_request_change_addr(int devaddr) "change addr to 0x%x"
+adb_mouse_request_change_addr_and_handler(int devaddr, int handler) "change addr and handler to 0x%x, 0x%x"
# hw/input/ps2.c
ps2_put_keycode(void *opaque, int keycode) "%p keycode 0x%02x"
diff --git a/hw/intc/heathrow_pic.c b/hw/intc/heathrow_pic.c
index 171f5ed814..393fdd7326 100644
--- a/hw/intc/heathrow_pic.c
+++ b/hw/intc/heathrow_pic.c
@@ -25,78 +25,58 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/ppc/mac.h"
+#include "hw/intc/heathrow_pic.h"
+#include "trace.h"
-/* debug PIC */
-//#define DEBUG_PIC
-
-#ifdef DEBUG_PIC
-#define PIC_DPRINTF(fmt, ...) \
- do { printf("PIC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define PIC_DPRINTF(fmt, ...)
-#endif
-
-typedef struct HeathrowPIC {
- uint32_t events;
- uint32_t mask;
- uint32_t levels;
- uint32_t level_triggered;
-} HeathrowPIC;
-
-typedef struct HeathrowPICS {
- MemoryRegion mem;
- HeathrowPIC pics[2];
- qemu_irq *irqs;
-} HeathrowPICS;
-
-static inline int check_irq(HeathrowPIC *pic)
+static inline int heathrow_check_irq(HeathrowPICState *pic)
{
return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
}
/* update the CPU irq state */
-static void heathrow_pic_update(HeathrowPICS *s)
+static void heathrow_update_irq(HeathrowState *s)
{
- if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
+ if (heathrow_check_irq(&s->pics[0]) ||
+ heathrow_check_irq(&s->pics[1])) {
qemu_irq_raise(s->irqs[0]);
} else {
qemu_irq_lower(s->irqs[0]);
}
}
-static void pic_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
+static void heathrow_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
{
- HeathrowPICS *s = opaque;
- HeathrowPIC *pic;
+ HeathrowState *s = opaque;
+ HeathrowPICState *pic;
unsigned int n;
n = ((addr & 0xfff) - 0x10) >> 4;
- PIC_DPRINTF("writel: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
+ trace_heathrow_write(addr, n, value);
if (n >= 2)
return;
pic = &s->pics[n];
switch(addr & 0xf) {
case 0x04:
pic->mask = value;
- heathrow_pic_update(s);
+ heathrow_update_irq(s);
break;
case 0x08:
/* do not reset level triggered IRQs */
value &= ~pic->level_triggered;
pic->events &= ~value;
- heathrow_pic_update(s);
+ heathrow_update_irq(s);
break;
default:
break;
}
}
-static uint64_t pic_read(void *opaque, hwaddr addr,
- unsigned size)
+static uint64_t heathrow_read(void *opaque, hwaddr addr,
+ unsigned size)
{
- HeathrowPICS *s = opaque;
- HeathrowPIC *pic;
+ HeathrowState *s = opaque;
+ HeathrowPICState *pic;
unsigned int n;
uint32_t value;
@@ -120,40 +100,39 @@ static uint64_t pic_read(void *opaque, hwaddr addr,
break;
}
}
- PIC_DPRINTF("readl: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
+ trace_heathrow_read(addr, n, value);
return value;
}
-static const MemoryRegionOps heathrow_pic_ops = {
- .read = pic_read,
- .write = pic_write,
+static const MemoryRegionOps heathrow_ops = {
+ .read = heathrow_read,
+ .write = heathrow_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static void heathrow_pic_set_irq(void *opaque, int num, int level)
+static void heathrow_set_irq(void *opaque, int num, int level)
{
- HeathrowPICS *s = opaque;
- HeathrowPIC *pic;
+ HeathrowState *s = opaque;
+ HeathrowPICState *pic;
unsigned int irq_bit;
+ int last_level;
-#if defined(DEBUG)
- {
- static int last_level[64];
- if (last_level[num] != level) {
- PIC_DPRINTF("set_irq: num=0x%02x level=%d\n", num, level);
- last_level[num] = level;
- }
- }
-#endif
pic = &s->pics[1 - (num >> 5)];
irq_bit = 1 << (num & 0x1f);
+ last_level = (pic->levels & irq_bit) ? 1 : 0;
+
if (level) {
pic->events |= irq_bit & ~pic->level_triggered;
pic->levels |= irq_bit;
} else {
pic->levels &= ~irq_bit;
}
- heathrow_pic_update(s);
+
+ if (last_level != level) {
+ trace_heathrow_set_irq(num, level);
+ }
+
+ heathrow_update_irq(s);
}
static const VMStateDescription vmstate_heathrow_pic_one = {
@@ -161,54 +140,81 @@ static const VMStateDescription vmstate_heathrow_pic_one = {
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
- VMSTATE_UINT32(events, HeathrowPIC),
- VMSTATE_UINT32(mask, HeathrowPIC),
- VMSTATE_UINT32(levels, HeathrowPIC),
- VMSTATE_UINT32(level_triggered, HeathrowPIC),
+ VMSTATE_UINT32(events, HeathrowPICState),
+ VMSTATE_UINT32(mask, HeathrowPICState),
+ VMSTATE_UINT32(levels, HeathrowPICState),
+ VMSTATE_UINT32(level_triggered, HeathrowPICState),
VMSTATE_END_OF_LIST()
}
};
-static const VMStateDescription vmstate_heathrow_pic = {
+static const VMStateDescription vmstate_heathrow = {
.name = "heathrow_pic",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_STRUCT_ARRAY(pics, HeathrowPICS, 2, 1,
- vmstate_heathrow_pic_one, HeathrowPIC),
+ VMSTATE_STRUCT_ARRAY(pics, HeathrowState, 2, 1,
+ vmstate_heathrow_pic_one, HeathrowPICState),
VMSTATE_END_OF_LIST()
}
};
-static void heathrow_pic_reset_one(HeathrowPIC *s)
+static void heathrow_reset(DeviceState *d)
{
- memset(s, '\0', sizeof(HeathrowPIC));
+ HeathrowState *s = HEATHROW(d);
+
+ s->pics[0].level_triggered = 0;
+ s->pics[1].level_triggered = 0x1ff00000;
}
-static void heathrow_pic_reset(void *opaque)
+static void heathrow_init(Object *obj)
{
- HeathrowPICS *s = opaque;
-
- heathrow_pic_reset_one(&s->pics[0]);
- heathrow_pic_reset_one(&s->pics[1]);
+ HeathrowState *s = HEATHROW(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- s->pics[0].level_triggered = 0;
- s->pics[1].level_triggered = 0x1ff00000;
+ memory_region_init_io(&s->mem, OBJECT(s), &heathrow_ops, s,
+ "heathrow-pic", 0x1000);
+ sysbus_init_mmio(sbd, &s->mem);
}
-qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
- int nb_cpus, qemu_irq **irqs)
+DeviceState *heathrow_pic_init(int nb_cpus, qemu_irq **irqs,
+ qemu_irq **pic_irqs)
{
- HeathrowPICS *s;
+ DeviceState *d;
+ HeathrowState *s;
- s = g_malloc0(sizeof(HeathrowPICS));
+ d = qdev_create(NULL, TYPE_HEATHROW);
+ qdev_init_nofail(d);
+
+ s = HEATHROW(d);
/* only 1 CPU */
s->irqs = irqs[0];
- memory_region_init_io(&s->mem, NULL, &heathrow_pic_ops, s,
- "heathrow-pic", 0x1000);
- *pmem = &s->mem;
- vmstate_register(NULL, -1, &vmstate_heathrow_pic, s);
- qemu_register_reset(heathrow_pic_reset, s);
- return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64);
+ *pic_irqs = qemu_allocate_irqs(heathrow_set_irq, s, HEATHROW_NUM_IRQS);
+
+ return d;
+}
+
+static void heathrow_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->reset = heathrow_reset;
+ dc->vmsd = &vmstate_heathrow;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
+
+static const TypeInfo heathrow_type_info = {
+ .name = TYPE_HEATHROW,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(HeathrowState),
+ .instance_init = heathrow_init,
+ .class_init = heathrow_class_init,
+};
+
+static void heathrow_register_types(void)
+{
+ type_register_static(&heathrow_type_info);
+}
+
+type_init(heathrow_register_types)
diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
index 9159a06f07..811cee9b26 100644
--- a/hw/intc/openpic.c
+++ b/hw/intc/openpic.c
@@ -63,10 +63,6 @@ static int get_current_cpu(void);
} \
} while (0)
-#define MAX_CPU 32
-#define MAX_MSI 8
-#define VID 0x03 /* MPIC version ID */
-
/* OpenPIC capability flags */
#define OPENPIC_FLAG_IDR_CRIT (1 << 0)
#define OPENPIC_FLAG_ILR (2 << 0)
@@ -85,35 +81,6 @@ static int get_current_cpu(void);
#define OPENPIC_CPU_REG_START 0x20000
#define OPENPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000)
-/* Raven */
-#define RAVEN_MAX_CPU 2
-#define RAVEN_MAX_EXT 48
-#define RAVEN_MAX_IRQ 64
-#define RAVEN_MAX_TMR OPENPIC_MAX_TMR
-#define RAVEN_MAX_IPI OPENPIC_MAX_IPI
-
-/* KeyLargo */
-#define KEYLARGO_MAX_CPU 4
-#define KEYLARGO_MAX_EXT 64
-#define KEYLARGO_MAX_IPI 4
-#define KEYLARGO_MAX_IRQ (64 + KEYLARGO_MAX_IPI)
-#define KEYLARGO_MAX_TMR 0
-#define KEYLARGO_IPI_IRQ (KEYLARGO_MAX_EXT) /* First IPI IRQ */
-/* Timers don't exist but this makes the code happy... */
-#define KEYLARGO_TMR_IRQ (KEYLARGO_IPI_IRQ + KEYLARGO_MAX_IPI)
-
-/* Interrupt definitions */
-#define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */
-#define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */
-#define RAVEN_TMR_IRQ (RAVEN_MAX_EXT + 2) /* First timer IRQ */
-#define RAVEN_IPI_IRQ (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */
-/* First doorbell IRQ */
-#define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI))
-
-typedef struct FslMpicInfo {
- int max_ext;
-} FslMpicInfo;
-
static FslMpicInfo fsl_mpic_20 = {
.max_ext = 12,
};
@@ -211,55 +178,6 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
uint32_t val, int idx);
static void openpic_reset(DeviceState *d);
-typedef enum IRQType {
- IRQ_TYPE_NORMAL = 0,
- IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */
- IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */
-} IRQType;
-
-/* Round up to the nearest 64 IRQs so that the queue length
- * won't change when moving between 32 and 64 bit hosts.
- */
-#define IRQQUEUE_SIZE_BITS ((OPENPIC_MAX_IRQ + 63) & ~63)
-
-typedef struct IRQQueue {
- unsigned long *queue;
- int32_t queue_size; /* Only used for VMSTATE_BITMAP */
- int next;
- int priority;
-} IRQQueue;
-
-typedef struct IRQSource {
- uint32_t ivpr; /* IRQ vector/priority register */
- uint32_t idr; /* IRQ destination register */
- uint32_t destmask; /* bitmap of CPU destinations */
- int last_cpu;
- int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */
- int pending; /* TRUE if IRQ is pending */
- IRQType type;
- bool level:1; /* level-triggered */
- bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */
-} IRQSource;
-
-#define IVPR_MASK_SHIFT 31
-#define IVPR_MASK_MASK (1U << IVPR_MASK_SHIFT)
-#define IVPR_ACTIVITY_SHIFT 30
-#define IVPR_ACTIVITY_MASK (1U << IVPR_ACTIVITY_SHIFT)
-#define IVPR_MODE_SHIFT 29
-#define IVPR_MODE_MASK (1U << IVPR_MODE_SHIFT)
-#define IVPR_POLARITY_SHIFT 23
-#define IVPR_POLARITY_MASK (1U << IVPR_POLARITY_SHIFT)
-#define IVPR_SENSE_SHIFT 22
-#define IVPR_SENSE_MASK (1U << IVPR_SENSE_SHIFT)
-
-#define IVPR_PRIORITY_MASK (0xFU << 16)
-#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
-#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
-
-/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */
-#define IDR_EP 0x80000000 /* external pin */
-#define IDR_CI 0x40000000 /* critical interrupt */
-
/* Convert between openpic clock ticks and nanosecs. In the hardware the clock
frequency is driven by board inputs to the PIC which the PIC would then
divide by 4 or 8. For now hard code to 25MZ.
@@ -275,81 +193,6 @@ static inline uint64_t ticks_to_ns(uint64_t ticks)
return ticks * OPENPIC_TIMER_NS_PER_TICK;
}
-typedef struct OpenPICTimer {
- uint32_t tccr; /* Global timer current count register */
- uint32_t tbcr; /* Global timer base count register */
- int n_IRQ;
- bool qemu_timer_active; /* Is the qemu_timer is running? */
- struct QEMUTimer *qemu_timer;
- struct OpenPICState *opp; /* Device timer is part of. */
- /* The QEMU_CLOCK_VIRTUAL time (in ns) corresponding to the last
- current_count written or read, only defined if qemu_timer_active. */
- uint64_t origin_time;
-} OpenPICTimer;
-
-typedef struct OpenPICMSI {
- uint32_t msir; /* Shared Message Signaled Interrupt Register */
-} OpenPICMSI;
-
-typedef struct IRQDest {
- int32_t ctpr; /* CPU current task priority */
- IRQQueue raised;
- IRQQueue servicing;
- qemu_irq *irqs;
-
- /* Count of IRQ sources asserting on non-INT outputs */
- uint32_t outputs_active[OPENPIC_OUTPUT_NB];
-} IRQDest;
-
-#define OPENPIC(obj) OBJECT_CHECK(OpenPICState, (obj), TYPE_OPENPIC)
-
-typedef struct OpenPICState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion mem;
-
- /* Behavior control */
- FslMpicInfo *fsl;
- uint32_t model;
- uint32_t flags;
- uint32_t nb_irqs;
- uint32_t vid;
- uint32_t vir; /* Vendor identification register */
- uint32_t vector_mask;
- uint32_t tfrr_reset;
- uint32_t ivpr_reset;
- uint32_t idr_reset;
- uint32_t brr1;
- uint32_t mpic_mode_mask;
-
- /* Sub-regions */
- MemoryRegion sub_io_mem[6];
-
- /* Global registers */
- uint32_t frr; /* Feature reporting register */
- uint32_t gcr; /* Global configuration register */
- uint32_t pir; /* Processor initialization register */
- uint32_t spve; /* Spurious vector register */
- uint32_t tfrr; /* Timer frequency reporting register */
- /* Source registers */
- IRQSource src[OPENPIC_MAX_IRQ];
- /* Local registers per output pin */
- IRQDest dst[MAX_CPU];
- uint32_t nb_cpus;
- /* Timer registers */
- OpenPICTimer timers[OPENPIC_MAX_TMR];
- uint32_t max_tmr;
-
- /* Shared MSI registers */
- OpenPICMSI msi[MAX_MSI];
- uint32_t max_irq;
- uint32_t irq_ipi0;
- uint32_t irq_tim0;
- uint32_t irq_msi;
-} OpenPICState;
-
static inline void IRQ_setbit(IRQQueue *q, int n_IRQ)
{
set_bit(n_IRQ, q->queue);
diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c
index fa83420254..928bc04a4e 100644
--- a/hw/intc/openpic_kvm.c
+++ b/hw/intc/openpic_kvm.c
@@ -30,6 +30,7 @@
#include "exec/address-spaces.h"
#include "hw/hw.h"
#include "hw/ppc/openpic.h"
+#include "hw/ppc/openpic_kvm.h"
#include "hw/pci/msi.h"
#include "hw/sysbus.h"
#include "sysemu/kvm.h"
@@ -124,10 +125,6 @@ static void kvm_openpic_region_add(MemoryListener *listener,
uint64_t reg_base;
int ret;
- if (section->fv != address_space_to_flatview(&address_space_memory)) {
- abort();
- }
-
/* Ignore events on regions that are not us */
if (section->mr != &opp->mem) {
return;
diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c
index a85a149c6d..5f8168f0f0 100644
--- a/hw/intc/s390_flic.c
+++ b/hw/intc/s390_flic.c
@@ -192,8 +192,8 @@ static void qemu_s390_flic_notify(uint32_t type)
cs->interrupt_request |= CPU_INTERRUPT_HARD;
/* ignore CPUs that are not sleeping */
- if (s390_cpu_get_state(cpu) != CPU_STATE_OPERATING &&
- s390_cpu_get_state(cpu) != CPU_STATE_LOAD) {
+ if (s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING &&
+ s390_cpu_get_state(cpu) != S390_CPU_STATE_LOAD) {
continue;
}
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 4092d2825e..55e8c2570c 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -186,3 +186,8 @@ nvic_complete_irq(int irq, bool secure) "NVIC complete IRQ %d (secure %d)"
nvic_set_irq_level(int irq, int level) "NVIC external irq %d level set to %d"
nvic_sysreg_read(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
nvic_sysreg_write(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
+
+# hw/intc/heathrow_pic.c
+heathrow_write(uint64_t addr, unsigned int n, uint64_t value) "0x%"PRIx64" %u: 0x%"PRIx64
+heathrow_read(uint64_t addr, unsigned int n, uint64_t value) "0x%"PRIx64" %u: 0x%"PRIx64
+heathrow_set_irq(int num, int level) "set_irq: num=0x%02x level=%d"
diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c
index adbbf6e4a6..9be281fd87 100644
--- a/hw/ipmi/ipmi.c
+++ b/hw/ipmi/ipmi.c
@@ -26,9 +26,9 @@
#include "hw/hw.h"
#include "hw/ipmi/ipmi.h"
#include "sysemu/sysemu.h"
-#include "qmp-commands.h"
#include "qom/object_interfaces.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-misc.h"
#include "qapi/visitor.h"
static uint32_t ipmi_current_uuid = 1;
diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c
index 61e677f92f..acb656b672 100644
--- a/hw/mem/nvdimm.c
+++ b/hw/mem/nvdimm.c
@@ -25,7 +25,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
-#include "qapi-visit.h"
#include "hw/mem/nvdimm.h"
static void nvdimm_get_label_size(Object *obj, Visitor *v, const char *name,
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index f33b37a8e5..00e834d0f0 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -58,8 +58,12 @@ obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o
obj-$(CONFIG_MIPS_CPS) += mips_cmgcr.o
obj-$(CONFIG_MIPS_CPS) += mips_cpc.o
obj-$(CONFIG_MIPS_ITU) += mips_itu.o
+obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o
obj-$(CONFIG_MPS2_SCC) += mps2-scc.o
+obj-$(CONFIG_TZ_PPC) += tz-ppc.o
+obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o
+
obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
obj-$(CONFIG_AUX) += auxbus.o
diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c
new file mode 100644
index 0000000000..ddd1584d34
--- /dev/null
+++ b/hw/misc/iotkit-secctl.c
@@ -0,0 +1,704 @@
+/*
+ * Arm IoT Kit security controller
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "trace.h"
+#include "hw/sysbus.h"
+#include "hw/registerfields.h"
+#include "hw/misc/iotkit-secctl.h"
+
+/* Registers in the secure privilege control block */
+REG32(SECRESPCFG, 0x10)
+REG32(NSCCFG, 0x14)
+REG32(SECMPCINTSTATUS, 0x1c)
+REG32(SECPPCINTSTAT, 0x20)
+REG32(SECPPCINTCLR, 0x24)
+REG32(SECPPCINTEN, 0x28)
+REG32(SECMSCINTSTAT, 0x30)
+REG32(SECMSCINTCLR, 0x34)
+REG32(SECMSCINTEN, 0x38)
+REG32(BRGINTSTAT, 0x40)
+REG32(BRGINTCLR, 0x44)
+REG32(BRGINTEN, 0x48)
+REG32(AHBNSPPC0, 0x50)
+REG32(AHBNSPPCEXP0, 0x60)
+REG32(AHBNSPPCEXP1, 0x64)
+REG32(AHBNSPPCEXP2, 0x68)
+REG32(AHBNSPPCEXP3, 0x6c)
+REG32(APBNSPPC0, 0x70)
+REG32(APBNSPPC1, 0x74)
+REG32(APBNSPPCEXP0, 0x80)
+REG32(APBNSPPCEXP1, 0x84)
+REG32(APBNSPPCEXP2, 0x88)
+REG32(APBNSPPCEXP3, 0x8c)
+REG32(AHBSPPPC0, 0x90)
+REG32(AHBSPPPCEXP0, 0xa0)
+REG32(AHBSPPPCEXP1, 0xa4)
+REG32(AHBSPPPCEXP2, 0xa8)
+REG32(AHBSPPPCEXP3, 0xac)
+REG32(APBSPPPC0, 0xb0)
+REG32(APBSPPPC1, 0xb4)
+REG32(APBSPPPCEXP0, 0xc0)
+REG32(APBSPPPCEXP1, 0xc4)
+REG32(APBSPPPCEXP2, 0xc8)
+REG32(APBSPPPCEXP3, 0xcc)
+REG32(NSMSCEXP, 0xd0)
+REG32(PID4, 0xfd0)
+REG32(PID5, 0xfd4)
+REG32(PID6, 0xfd8)
+REG32(PID7, 0xfdc)
+REG32(PID0, 0xfe0)
+REG32(PID1, 0xfe4)
+REG32(PID2, 0xfe8)
+REG32(PID3, 0xfec)
+REG32(CID0, 0xff0)
+REG32(CID1, 0xff4)
+REG32(CID2, 0xff8)
+REG32(CID3, 0xffc)
+
+/* Registers in the non-secure privilege control block */
+REG32(AHBNSPPPC0, 0x90)
+REG32(AHBNSPPPCEXP0, 0xa0)
+REG32(AHBNSPPPCEXP1, 0xa4)
+REG32(AHBNSPPPCEXP2, 0xa8)
+REG32(AHBNSPPPCEXP3, 0xac)
+REG32(APBNSPPPC0, 0xb0)
+REG32(APBNSPPPC1, 0xb4)
+REG32(APBNSPPPCEXP0, 0xc0)
+REG32(APBNSPPPCEXP1, 0xc4)
+REG32(APBNSPPPCEXP2, 0xc8)
+REG32(APBNSPPPCEXP3, 0xcc)
+/* PID and CID registers are also present in the NS block */
+
+static const uint8_t iotkit_secctl_s_idregs[] = {
+ 0x04, 0x00, 0x00, 0x00,
+ 0x52, 0xb8, 0x0b, 0x00,
+ 0x0d, 0xf0, 0x05, 0xb1,
+};
+
+static const uint8_t iotkit_secctl_ns_idregs[] = {
+ 0x04, 0x00, 0x00, 0x00,
+ 0x53, 0xb8, 0x0b, 0x00,
+ 0x0d, 0xf0, 0x05, 0xb1,
+};
+
+/* The register sets for the various PPCs (AHB internal, APB internal,
+ * AHB expansion, APB expansion) are all set up so that they are
+ * in 16-aligned blocks so offsets 0xN0, 0xN4, 0xN8, 0xNC are PPCs
+ * 0, 1, 2, 3 of that type, so we can convert a register address offset
+ * into an an index into a PPC array easily.
+ */
+static inline int offset_to_ppc_idx(uint32_t offset)
+{
+ return extract32(offset, 2, 2);
+}
+
+typedef void PerPPCFunction(IoTKitSecCtlPPC *ppc);
+
+static void foreach_ppc(IoTKitSecCtl *s, PerPPCFunction *fn)
+{
+ int i;
+
+ for (i = 0; i < IOTS_NUM_APB_PPC; i++) {
+ fn(&s->apb[i]);
+ }
+ for (i = 0; i < IOTS_NUM_APB_EXP_PPC; i++) {
+ fn(&s->apbexp[i]);
+ }
+ for (i = 0; i < IOTS_NUM_AHB_EXP_PPC; i++) {
+ fn(&s->ahbexp[i]);
+ }
+}
+
+static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr,
+ uint64_t *pdata,
+ unsigned size, MemTxAttrs attrs)
+{
+ uint64_t r;
+ uint32_t offset = addr & ~0x3;
+ IoTKitSecCtl *s = IOTKIT_SECCTL(opaque);
+
+ switch (offset) {
+ case A_AHBNSPPC0:
+ case A_AHBSPPPC0:
+ r = 0;
+ break;
+ case A_SECRESPCFG:
+ r = s->secrespcfg;
+ break;
+ case A_NSCCFG:
+ r = s->nsccfg;
+ break;
+ case A_SECPPCINTSTAT:
+ r = s->secppcintstat;
+ break;
+ case A_SECPPCINTEN:
+ r = s->secppcinten;
+ break;
+ case A_BRGINTSTAT:
+ /* QEMU's bus fabric can never report errors as it doesn't buffer
+ * writes, so we never report bridge interrupts.
+ */
+ r = 0;
+ break;
+ case A_BRGINTEN:
+ r = s->brginten;
+ break;
+ case A_AHBNSPPCEXP0:
+ case A_AHBNSPPCEXP1:
+ case A_AHBNSPPCEXP2:
+ case A_AHBNSPPCEXP3:
+ r = s->ahbexp[offset_to_ppc_idx(offset)].ns;
+ break;
+ case A_APBNSPPC0:
+ case A_APBNSPPC1:
+ r = s->apb[offset_to_ppc_idx(offset)].ns;
+ break;
+ case A_APBNSPPCEXP0:
+ case A_APBNSPPCEXP1:
+ case A_APBNSPPCEXP2:
+ case A_APBNSPPCEXP3:
+ r = s->apbexp[offset_to_ppc_idx(offset)].ns;
+ break;
+ case A_AHBSPPPCEXP0:
+ case A_AHBSPPPCEXP1:
+ case A_AHBSPPPCEXP2:
+ case A_AHBSPPPCEXP3:
+ r = s->apbexp[offset_to_ppc_idx(offset)].sp;
+ break;
+ case A_APBSPPPC0:
+ case A_APBSPPPC1:
+ r = s->apb[offset_to_ppc_idx(offset)].sp;
+ break;
+ case A_APBSPPPCEXP0:
+ case A_APBSPPPCEXP1:
+ case A_APBSPPPCEXP2:
+ case A_APBSPPPCEXP3:
+ r = s->apbexp[offset_to_ppc_idx(offset)].sp;
+ break;
+ case A_SECMPCINTSTATUS:
+ case A_SECMSCINTSTAT:
+ case A_SECMSCINTEN:
+ case A_NSMSCEXP:
+ qemu_log_mask(LOG_UNIMP,
+ "IoTKit SecCtl S block read: "
+ "unimplemented offset 0x%x\n", offset);
+ r = 0;
+ break;
+ case A_PID4:
+ case A_PID5:
+ case A_PID6:
+ case A_PID7:
+ case A_PID0:
+ case A_PID1:
+ case A_PID2:
+ case A_PID3:
+ case A_CID0:
+ case A_CID1:
+ case A_CID2:
+ case A_CID3:
+ r = iotkit_secctl_s_idregs[(offset - A_PID4) / 4];
+ break;
+ case A_SECPPCINTCLR:
+ case A_SECMSCINTCLR:
+ case A_BRGINTCLR:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IotKit SecCtl S block read: write-only offset 0x%x\n",
+ offset);
+ r = 0;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IotKit SecCtl S block read: bad offset 0x%x\n", offset);
+ r = 0;
+ break;
+ }
+
+ if (size != 4) {
+ /* None of our registers are access-sensitive, so just pull the right
+ * byte out of the word read result.
+ */
+ r = extract32(r, (addr & 3) * 8, size * 8);
+ }
+
+ trace_iotkit_secctl_s_read(offset, r, size);
+ *pdata = r;
+ return MEMTX_OK;
+}
+
+static void iotkit_secctl_update_ppc_ap(IoTKitSecCtlPPC *ppc)
+{
+ int i;
+
+ for (i = 0; i < ppc->numports; i++) {
+ bool v;
+
+ if (extract32(ppc->ns, i, 1)) {
+ v = extract32(ppc->nsp, i, 1);
+ } else {
+ v = extract32(ppc->sp, i, 1);
+ }
+ qemu_set_irq(ppc->ap[i], v);
+ }
+}
+
+static void iotkit_secctl_ppc_ns_write(IoTKitSecCtlPPC *ppc, uint32_t value)
+{
+ int i;
+
+ ppc->ns = value & MAKE_64BIT_MASK(0, ppc->numports);
+ for (i = 0; i < ppc->numports; i++) {
+ qemu_set_irq(ppc->nonsec[i], extract32(ppc->ns, i, 1));
+ }
+ iotkit_secctl_update_ppc_ap(ppc);
+}
+
+static void iotkit_secctl_ppc_sp_write(IoTKitSecCtlPPC *ppc, uint32_t value)
+{
+ ppc->sp = value & MAKE_64BIT_MASK(0, ppc->numports);
+ iotkit_secctl_update_ppc_ap(ppc);
+}
+
+static void iotkit_secctl_ppc_nsp_write(IoTKitSecCtlPPC *ppc, uint32_t value)
+{
+ ppc->nsp = value & MAKE_64BIT_MASK(0, ppc->numports);
+ iotkit_secctl_update_ppc_ap(ppc);
+}
+
+static void iotkit_secctl_ppc_update_irq_clear(IoTKitSecCtlPPC *ppc)
+{
+ uint32_t value = ppc->parent->secppcintstat;
+
+ qemu_set_irq(ppc->irq_clear, extract32(value, ppc->irq_bit_offset, 1));
+}
+
+static void iotkit_secctl_ppc_update_irq_enable(IoTKitSecCtlPPC *ppc)
+{
+ uint32_t value = ppc->parent->secppcinten;
+
+ qemu_set_irq(ppc->irq_enable, extract32(value, ppc->irq_bit_offset, 1));
+}
+
+static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr,
+ uint64_t value,
+ unsigned size, MemTxAttrs attrs)
+{
+ IoTKitSecCtl *s = IOTKIT_SECCTL(opaque);
+ uint32_t offset = addr;
+ IoTKitSecCtlPPC *ppc;
+
+ trace_iotkit_secctl_s_write(offset, value, size);
+
+ if (size != 4) {
+ /* Byte and halfword writes are ignored */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IotKit SecCtl S block write: bad size, ignored\n");
+ return MEMTX_OK;
+ }
+
+ switch (offset) {
+ case A_NSCCFG:
+ s->nsccfg = value & 3;
+ qemu_set_irq(s->nsc_cfg_irq, s->nsccfg);
+ break;
+ case A_SECRESPCFG:
+ value &= 1;
+ s->secrespcfg = value;
+ qemu_set_irq(s->sec_resp_cfg, s->secrespcfg);
+ break;
+ case A_SECPPCINTCLR:
+ value &= 0x00f000f3;
+ foreach_ppc(s, iotkit_secctl_ppc_update_irq_clear);
+ break;
+ case A_SECPPCINTEN:
+ s->secppcinten = value & 0x00f000f3;
+ foreach_ppc(s, iotkit_secctl_ppc_update_irq_enable);
+ break;
+ case A_BRGINTCLR:
+ break;
+ case A_BRGINTEN:
+ s->brginten = value & 0xffff0000;
+ break;
+ case A_AHBNSPPCEXP0:
+ case A_AHBNSPPCEXP1:
+ case A_AHBNSPPCEXP2:
+ case A_AHBNSPPCEXP3:
+ ppc = &s->ahbexp[offset_to_ppc_idx(offset)];
+ iotkit_secctl_ppc_ns_write(ppc, value);
+ break;
+ case A_APBNSPPC0:
+ case A_APBNSPPC1:
+ ppc = &s->apb[offset_to_ppc_idx(offset)];
+ iotkit_secctl_ppc_ns_write(ppc, value);
+ break;
+ case A_APBNSPPCEXP0:
+ case A_APBNSPPCEXP1:
+ case A_APBNSPPCEXP2:
+ case A_APBNSPPCEXP3:
+ ppc = &s->apbexp[offset_to_ppc_idx(offset)];
+ iotkit_secctl_ppc_ns_write(ppc, value);
+ break;
+ case A_AHBSPPPCEXP0:
+ case A_AHBSPPPCEXP1:
+ case A_AHBSPPPCEXP2:
+ case A_AHBSPPPCEXP3:
+ ppc = &s->ahbexp[offset_to_ppc_idx(offset)];
+ iotkit_secctl_ppc_sp_write(ppc, value);
+ break;
+ case A_APBSPPPC0:
+ case A_APBSPPPC1:
+ ppc = &s->apb[offset_to_ppc_idx(offset)];
+ iotkit_secctl_ppc_sp_write(ppc, value);
+ break;
+ case A_APBSPPPCEXP0:
+ case A_APBSPPPCEXP1:
+ case A_APBSPPPCEXP2:
+ case A_APBSPPPCEXP3:
+ ppc = &s->apbexp[offset_to_ppc_idx(offset)];
+ iotkit_secctl_ppc_sp_write(ppc, value);
+ break;
+ case A_SECMSCINTCLR:
+ case A_SECMSCINTEN:
+ qemu_log_mask(LOG_UNIMP,
+ "IoTKit SecCtl S block write: "
+ "unimplemented offset 0x%x\n", offset);
+ break;
+ case A_SECMPCINTSTATUS:
+ case A_SECPPCINTSTAT:
+ case A_SECMSCINTSTAT:
+ case A_BRGINTSTAT:
+ case A_AHBNSPPC0:
+ case A_AHBSPPPC0:
+ case A_NSMSCEXP:
+ case A_PID4:
+ case A_PID5:
+ case A_PID6:
+ case A_PID7:
+ case A_PID0:
+ case A_PID1:
+ case A_PID2:
+ case A_PID3:
+ case A_CID0:
+ case A_CID1:
+ case A_CID2:
+ case A_CID3:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IoTKit SecCtl S block write: "
+ "read-only offset 0x%x\n", offset);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IotKit SecCtl S block write: bad offset 0x%x\n",
+ offset);
+ break;
+ }
+
+ return MEMTX_OK;
+}
+
+static MemTxResult iotkit_secctl_ns_read(void *opaque, hwaddr addr,
+ uint64_t *pdata,
+ unsigned size, MemTxAttrs attrs)
+{
+ IoTKitSecCtl *s = IOTKIT_SECCTL(opaque);
+ uint64_t r;
+ uint32_t offset = addr & ~0x3;
+
+ switch (offset) {
+ case A_AHBNSPPPC0:
+ r = 0;
+ break;
+ case A_AHBNSPPPCEXP0:
+ case A_AHBNSPPPCEXP1:
+ case A_AHBNSPPPCEXP2:
+ case A_AHBNSPPPCEXP3:
+ r = s->ahbexp[offset_to_ppc_idx(offset)].nsp;
+ break;
+ case A_APBNSPPPC0:
+ case A_APBNSPPPC1:
+ r = s->apb[offset_to_ppc_idx(offset)].nsp;
+ break;
+ case A_APBNSPPPCEXP0:
+ case A_APBNSPPPCEXP1:
+ case A_APBNSPPPCEXP2:
+ case A_APBNSPPPCEXP3:
+ r = s->apbexp[offset_to_ppc_idx(offset)].nsp;
+ break;
+ case A_PID4:
+ case A_PID5:
+ case A_PID6:
+ case A_PID7:
+ case A_PID0:
+ case A_PID1:
+ case A_PID2:
+ case A_PID3:
+ case A_CID0:
+ case A_CID1:
+ case A_CID2:
+ case A_CID3:
+ r = iotkit_secctl_ns_idregs[(offset - A_PID4) / 4];
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IotKit SecCtl NS block write: bad offset 0x%x\n",
+ offset);
+ r = 0;
+ break;
+ }
+
+ if (size != 4) {
+ /* None of our registers are access-sensitive, so just pull the right
+ * byte out of the word read result.
+ */
+ r = extract32(r, (addr & 3) * 8, size * 8);
+ }
+
+ trace_iotkit_secctl_ns_read(offset, r, size);
+ *pdata = r;
+ return MEMTX_OK;
+}
+
+static MemTxResult iotkit_secctl_ns_write(void *opaque, hwaddr addr,
+ uint64_t value,
+ unsigned size, MemTxAttrs attrs)
+{
+ IoTKitSecCtl *s = IOTKIT_SECCTL(opaque);
+ uint32_t offset = addr;
+ IoTKitSecCtlPPC *ppc;
+
+ trace_iotkit_secctl_ns_write(offset, value, size);
+
+ if (size != 4) {
+ /* Byte and halfword writes are ignored */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IotKit SecCtl NS block write: bad size, ignored\n");
+ return MEMTX_OK;
+ }
+
+ switch (offset) {
+ case A_AHBNSPPPCEXP0:
+ case A_AHBNSPPPCEXP1:
+ case A_AHBNSPPPCEXP2:
+ case A_AHBNSPPPCEXP3:
+ ppc = &s->ahbexp[offset_to_ppc_idx(offset)];
+ iotkit_secctl_ppc_nsp_write(ppc, value);
+ break;
+ case A_APBNSPPPC0:
+ case A_APBNSPPPC1:
+ ppc = &s->apb[offset_to_ppc_idx(offset)];
+ iotkit_secctl_ppc_nsp_write(ppc, value);
+ break;
+ case A_APBNSPPPCEXP0:
+ case A_APBNSPPPCEXP1:
+ case A_APBNSPPPCEXP2:
+ case A_APBNSPPPCEXP3:
+ ppc = &s->apbexp[offset_to_ppc_idx(offset)];
+ iotkit_secctl_ppc_nsp_write(ppc, value);
+ break;
+ case A_AHBNSPPPC0:
+ case A_PID4:
+ case A_PID5:
+ case A_PID6:
+ case A_PID7:
+ case A_PID0:
+ case A_PID1:
+ case A_PID2:
+ case A_PID3:
+ case A_CID0:
+ case A_CID1:
+ case A_CID2:
+ case A_CID3:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IoTKit SecCtl NS block write: "
+ "read-only offset 0x%x\n", offset);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "IotKit SecCtl NS block write: bad offset 0x%x\n",
+ offset);
+ break;
+ }
+
+ return MEMTX_OK;
+}
+
+static const MemoryRegionOps iotkit_secctl_s_ops = {
+ .read_with_attrs = iotkit_secctl_s_read,
+ .write_with_attrs = iotkit_secctl_s_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .impl.min_access_size = 1,
+ .impl.max_access_size = 4,
+};
+
+static const MemoryRegionOps iotkit_secctl_ns_ops = {
+ .read_with_attrs = iotkit_secctl_ns_read,
+ .write_with_attrs = iotkit_secctl_ns_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .impl.min_access_size = 1,
+ .impl.max_access_size = 4,
+};
+
+static void iotkit_secctl_reset_ppc(IoTKitSecCtlPPC *ppc)
+{
+ ppc->ns = 0;
+ ppc->sp = 0;
+ ppc->nsp = 0;
+}
+
+static void iotkit_secctl_reset(DeviceState *dev)
+{
+ IoTKitSecCtl *s = IOTKIT_SECCTL(dev);
+
+ s->secppcintstat = 0;
+ s->secppcinten = 0;
+ s->secrespcfg = 0;
+ s->nsccfg = 0;
+ s->brginten = 0;
+
+ foreach_ppc(s, iotkit_secctl_reset_ppc);
+}
+
+static void iotkit_secctl_ppc_irqstatus(void *opaque, int n, int level)
+{
+ IoTKitSecCtlPPC *ppc = opaque;
+ IoTKitSecCtl *s = IOTKIT_SECCTL(ppc->parent);
+ int irqbit = ppc->irq_bit_offset + n;
+
+ s->secppcintstat = deposit32(s->secppcintstat, irqbit, 1, level);
+}
+
+static void iotkit_secctl_init_ppc(IoTKitSecCtl *s,
+ IoTKitSecCtlPPC *ppc,
+ const char *name,
+ int numports,
+ int irq_bit_offset)
+{
+ char *gpioname;
+ DeviceState *dev = DEVICE(s);
+
+ ppc->numports = numports;
+ ppc->irq_bit_offset = irq_bit_offset;
+ ppc->parent = s;
+
+ gpioname = g_strdup_printf("%s_nonsec", name);
+ qdev_init_gpio_out_named(dev, ppc->nonsec, gpioname, numports);
+ g_free(gpioname);
+ gpioname = g_strdup_printf("%s_ap", name);
+ qdev_init_gpio_out_named(dev, ppc->ap, gpioname, numports);
+ g_free(gpioname);
+ gpioname = g_strdup_printf("%s_irq_enable", name);
+ qdev_init_gpio_out_named(dev, &ppc->irq_enable, gpioname, 1);
+ g_free(gpioname);
+ gpioname = g_strdup_printf("%s_irq_clear", name);
+ qdev_init_gpio_out_named(dev, &ppc->irq_clear, gpioname, 1);
+ g_free(gpioname);
+ gpioname = g_strdup_printf("%s_irq_status", name);
+ qdev_init_gpio_in_named_with_opaque(dev, iotkit_secctl_ppc_irqstatus,
+ ppc, gpioname, 1);
+ g_free(gpioname);
+}
+
+static void iotkit_secctl_init(Object *obj)
+{
+ IoTKitSecCtl *s = IOTKIT_SECCTL(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ DeviceState *dev = DEVICE(obj);
+ int i;
+
+ iotkit_secctl_init_ppc(s, &s->apb[0], "apb_ppc0",
+ IOTS_APB_PPC0_NUM_PORTS, 0);
+ iotkit_secctl_init_ppc(s, &s->apb[1], "apb_ppc1",
+ IOTS_APB_PPC1_NUM_PORTS, 1);
+
+ for (i = 0; i < IOTS_NUM_APB_EXP_PPC; i++) {
+ IoTKitSecCtlPPC *ppc = &s->apbexp[i];
+ char *ppcname = g_strdup_printf("apb_ppcexp%d", i);
+ iotkit_secctl_init_ppc(s, ppc, ppcname, IOTS_PPC_NUM_PORTS, 4 + i);
+ g_free(ppcname);
+ }
+ for (i = 0; i < IOTS_NUM_AHB_EXP_PPC; i++) {
+ IoTKitSecCtlPPC *ppc = &s->ahbexp[i];
+ char *ppcname = g_strdup_printf("ahb_ppcexp%d", i);
+ iotkit_secctl_init_ppc(s, ppc, ppcname, IOTS_PPC_NUM_PORTS, 20 + i);
+ g_free(ppcname);
+ }
+
+ qdev_init_gpio_out_named(dev, &s->sec_resp_cfg, "sec_resp_cfg", 1);
+ qdev_init_gpio_out_named(dev, &s->nsc_cfg_irq, "nsc_cfg", 1);
+
+ memory_region_init_io(&s->s_regs, obj, &iotkit_secctl_s_ops,
+ s, "iotkit-secctl-s-regs", 0x1000);
+ memory_region_init_io(&s->ns_regs, obj, &iotkit_secctl_ns_ops,
+ s, "iotkit-secctl-ns-regs", 0x1000);
+ sysbus_init_mmio(sbd, &s->s_regs);
+ sysbus_init_mmio(sbd, &s->ns_regs);
+}
+
+static const VMStateDescription iotkit_secctl_ppc_vmstate = {
+ .name = "iotkit-secctl-ppc",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(ns, IoTKitSecCtlPPC),
+ VMSTATE_UINT32(sp, IoTKitSecCtlPPC),
+ VMSTATE_UINT32(nsp, IoTKitSecCtlPPC),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription iotkit_secctl_vmstate = {
+ .name = "iotkit-secctl",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(secppcintstat, IoTKitSecCtl),
+ VMSTATE_UINT32(secppcinten, IoTKitSecCtl),
+ VMSTATE_UINT32(secrespcfg, IoTKitSecCtl),
+ VMSTATE_UINT32(nsccfg, IoTKitSecCtl),
+ VMSTATE_UINT32(brginten, IoTKitSecCtl),
+ VMSTATE_STRUCT_ARRAY(apb, IoTKitSecCtl, IOTS_NUM_APB_PPC, 1,
+ iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC),
+ VMSTATE_STRUCT_ARRAY(apbexp, IoTKitSecCtl, IOTS_NUM_APB_EXP_PPC, 1,
+ iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC),
+ VMSTATE_STRUCT_ARRAY(ahbexp, IoTKitSecCtl, IOTS_NUM_AHB_EXP_PPC, 1,
+ iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void iotkit_secctl_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &iotkit_secctl_vmstate;
+ dc->reset = iotkit_secctl_reset;
+}
+
+static const TypeInfo iotkit_secctl_info = {
+ .name = TYPE_IOTKIT_SECCTL,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IoTKitSecCtl),
+ .instance_init = iotkit_secctl_init,
+ .class_init = iotkit_secctl_class_init,
+};
+
+static void iotkit_secctl_register_types(void)
+{
+ type_register_static(&iotkit_secctl_info);
+}
+
+type_init(iotkit_secctl_register_types);
diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c
index 024f8557ab..af1bd46b4b 100644
--- a/hw/misc/macio/macio.c
+++ b/hw/misc/macio/macio.c
@@ -30,48 +30,11 @@
#include "hw/pci/pci.h"
#include "hw/ppc/mac_dbdma.h"
#include "hw/char/escc.h"
+#include "hw/misc/macio/macio.h"
+#include "hw/intc/heathrow_pic.h"
-#define TYPE_MACIO "macio"
-#define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO)
-
-typedef struct MacIOState
-{
- /*< private >*/
- PCIDevice parent;
- /*< public >*/
-
- MemoryRegion bar;
- CUDAState cuda;
- DBDMAState *dbdma;
- MemoryRegion *pic_mem;
- MemoryRegion *escc_mem;
- uint64_t frequency;
-} MacIOState;
-
-#define OLDWORLD_MACIO(obj) \
- OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO)
-
-typedef struct OldWorldMacIOState {
- /*< private >*/
- MacIOState parent_obj;
- /*< public >*/
-
- qemu_irq irqs[5];
-
- MacIONVRAMState nvram;
- MACIOIDEState ide[2];
-} OldWorldMacIOState;
-
-#define NEWWORLD_MACIO(obj) \
- OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO)
-
-typedef struct NewWorldMacIOState {
- /*< private >*/
- MacIOState parent_obj;
- /*< public >*/
- qemu_irq irqs[5];
- MACIOIDEState ide[2];
-} NewWorldMacIOState;
+/* Note: this code is strongly inspirated from the corresponding code
+ * in PearPC */
/*
* The mac-io has two interfaces to the ESCC. One is called "escc-legacy",
@@ -84,10 +47,12 @@ typedef struct NewWorldMacIOState {
*
* Reference: ftp://ftp.software.ibm.com/rs6000/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf
*/
-static void macio_escc_legacy_setup(MacIOState *macio_state)
+static void macio_escc_legacy_setup(MacIOState *s)
{
+ ESCCState *escc = ESCC(&s->escc);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(escc);
MemoryRegion *escc_legacy = g_new(MemoryRegion, 1);
- MemoryRegion *bar = &macio_state->bar;
+ MemoryRegion *bar = &s->bar;
int i;
static const int maps[] = {
0x00, 0x00, /* Command B */
@@ -102,25 +67,26 @@ static void macio_escc_legacy_setup(MacIOState *macio_state)
0xb0, 0xb0, /* Detect AB */
};
- memory_region_init(escc_legacy, OBJECT(macio_state), "escc-legacy", 256);
+ memory_region_init(escc_legacy, OBJECT(s), "escc-legacy", 256);
for (i = 0; i < ARRAY_SIZE(maps); i += 2) {
MemoryRegion *port = g_new(MemoryRegion, 1);
- memory_region_init_alias(port, OBJECT(macio_state), "escc-legacy-port",
- macio_state->escc_mem, maps[i+1], 0x2);
+ memory_region_init_alias(port, OBJECT(s), "escc-legacy-port",
+ sysbus_mmio_get_region(sbd, 0),
+ maps[i + 1], 0x2);
memory_region_add_subregion(escc_legacy, maps[i], port);
}
memory_region_add_subregion(bar, 0x12000, escc_legacy);
}
-static void macio_bar_setup(MacIOState *macio_state)
+static void macio_bar_setup(MacIOState *s)
{
- MemoryRegion *bar = &macio_state->bar;
+ ESCCState *escc = ESCC(&s->escc);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(escc);
+ MemoryRegion *bar = &s->bar;
- if (macio_state->escc_mem) {
- memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem);
- macio_escc_legacy_setup(macio_state);
- }
+ memory_region_add_subregion(bar, 0x13000, sysbus_mmio_get_region(sbd, 0));
+ macio_escc_legacy_setup(s);
}
static void macio_common_realize(PCIDevice *d, Error **errp)
@@ -129,15 +95,17 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
SysBusDevice *sysbus_dev;
Error *err = NULL;
- object_property_set_bool(OBJECT(s->dbdma), true, "realized", &err);
+ object_property_set_bool(OBJECT(&s->dbdma), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
- sysbus_dev = SYS_BUS_DEVICE(s->dbdma);
+ sysbus_dev = SYS_BUS_DEVICE(&s->dbdma);
memory_region_add_subregion(&s->bar, 0x08000,
sysbus_mmio_get_region(sysbus_dev, 0));
+ qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency",
+ s->frequency);
object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
if (err) {
error_propagate(errp, err);
@@ -147,6 +115,12 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
memory_region_add_subregion(&s->bar, 0x16000,
sysbus_mmio_get_region(sysbus_dev, 0));
+ object_property_set_bool(OBJECT(&s->escc), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
macio_bar_setup(s);
pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
}
@@ -161,7 +135,7 @@ static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide,
sysbus_connect_irq(sysbus_dev, 0, irq0);
sysbus_connect_irq(sysbus_dev, 1, irq1);
qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid);
- object_property_set_link(OBJECT(ide), OBJECT(s->dbdma), "dbdma", errp);
+ object_property_set_link(OBJECT(ide), OBJECT(&s->dbdma), "dbdma", errp);
macio_ide_register_dma(ide);
object_property_set_bool(OBJECT(ide), true, "realized", errp);
@@ -185,6 +159,10 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp)
sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
+ sysbus_dev = SYS_BUS_DEVICE(&s->escc);
+ sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
+ sysbus_connect_irq(sysbus_dev, 1, os->irqs[cur_irq++]);
+
object_property_set_bool(OBJECT(&os->nvram), true, "realized", &err);
if (err) {
error_propagate(errp, err);
@@ -195,10 +173,10 @@ static void macio_oldworld_realize(PCIDevice *d, Error **errp)
sysbus_mmio_get_region(sysbus_dev, 0));
pmac_format_nvram_partition(&os->nvram, os->nvram.size);
- if (s->pic_mem) {
- /* Heathrow PIC */
- memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem);
- }
+ /* Heathrow PIC */
+ sysbus_dev = SYS_BUS_DEVICE(os->pic);
+ memory_region_add_subregion(&s->bar, 0x0,
+ sysbus_mmio_get_region(sysbus_dev, 0));
/* IDE buses */
for (i = 0; i < ARRAY_SIZE(os->ide); i++) {
@@ -236,6 +214,11 @@ static void macio_oldworld_init(Object *obj)
qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs));
+ object_property_add_link(obj, "pic", TYPE_HEATHROW,
+ (Object **) &os->pic,
+ qdev_prop_allow_set_link_before_realize,
+ 0, NULL);
+
object_initialize(&os->nvram, sizeof(os->nvram), TYPE_MACIO_NVRAM);
dev = DEVICE(&os->nvram);
qdev_prop_set_uint32(dev, "size", 0x2000);
@@ -297,10 +280,14 @@ static void macio_newworld_realize(PCIDevice *d, Error **errp)
sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
- if (s->pic_mem) {
- /* OpenPIC */
- memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem);
- }
+ sysbus_dev = SYS_BUS_DEVICE(&s->escc);
+ sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
+ sysbus_connect_irq(sysbus_dev, 1, ns->irqs[cur_irq++]);
+
+ /* OpenPIC */
+ sysbus_dev = SYS_BUS_DEVICE(ns->pic);
+ memory_region_add_subregion(&s->bar, 0x40000,
+ sysbus_mmio_get_region(sysbus_dev, 0));
/* IDE buses */
for (i = 0; i < ARRAY_SIZE(ns->ide); i++) {
@@ -329,6 +316,11 @@ static void macio_newworld_init(Object *obj)
qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs));
+ object_property_add_link(obj, "pic", TYPE_OPENPIC,
+ (Object **) &ns->pic,
+ qdev_prop_allow_set_link_before_realize,
+ 0, NULL);
+
for (i = 0; i < 2; i++) {
macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i);
}
@@ -344,8 +336,20 @@ static void macio_instance_init(Object *obj)
qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
- s->dbdma = MAC_DBDMA(object_new(TYPE_MAC_DBDMA));
- object_property_add_child(obj, "dbdma", OBJECT(s->dbdma), NULL);
+ object_initialize(&s->dbdma, sizeof(s->dbdma), TYPE_MAC_DBDMA);
+ qdev_set_parent_bus(DEVICE(&s->dbdma), sysbus_get_default());
+ object_property_add_child(obj, "dbdma", OBJECT(&s->dbdma), NULL);
+
+ object_initialize(&s->escc, sizeof(s->escc), TYPE_ESCC);
+ qdev_prop_set_uint32(DEVICE(&s->escc), "disabled", 0);
+ qdev_prop_set_uint32(DEVICE(&s->escc), "frequency", ESCC_CLOCK);
+ qdev_prop_set_uint32(DEVICE(&s->escc), "it_shift", 4);
+ qdev_prop_set_chr(DEVICE(&s->escc), "chrA", serial_hds[0]);
+ qdev_prop_set_chr(DEVICE(&s->escc), "chrB", serial_hds[1]);
+ qdev_prop_set_uint32(DEVICE(&s->escc), "chnBtype", escc_serial);
+ qdev_prop_set_uint32(DEVICE(&s->escc), "chnAtype", escc_serial);
+ qdev_set_parent_bus(DEVICE(&s->escc), sysbus_get_default());
+ object_property_add_child(obj, "escc", OBJECT(&s->escc), NULL);
}
static const VMStateDescription vmstate_macio_oldworld = {
@@ -441,19 +445,3 @@ static void macio_register_types(void)
}
type_init(macio_register_types)
-
-void macio_init(PCIDevice *d,
- MemoryRegion *pic_mem,
- MemoryRegion *escc_mem)
-{
- MacIOState *macio_state = MACIO(d);
-
- macio_state->pic_mem = pic_mem;
- macio_state->escc_mem = escc_mem;
- /* Note: this code is strongly inspirated from the corresponding code
- in PearPC */
- qdev_prop_set_uint64(DEVICE(&macio_state->cuda), "timebase-frequency",
- macio_state->frequency);
-
- qdev_init_nofail(DEVICE(d));
-}
diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c
new file mode 100644
index 0000000000..7394a057d8
--- /dev/null
+++ b/hw/misc/mps2-fpgaio.c
@@ -0,0 +1,176 @@
+/*
+ * ARM MPS2 AN505 FPGAIO emulation
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+/* This is a model of the "FPGA system control and I/O" block found
+ * in the AN505 FPGA image for the MPS2 devboard.
+ * It is documented in AN505:
+ * http://infocenter.arm.com/help/topic/com.arm.doc.dai0505b/index.html
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "trace.h"
+#include "hw/sysbus.h"
+#include "hw/registerfields.h"
+#include "hw/misc/mps2-fpgaio.h"
+
+REG32(LED0, 0)
+REG32(BUTTON, 8)
+REG32(CLK1HZ, 0x10)
+REG32(CLK100HZ, 0x14)
+REG32(COUNTER, 0x18)
+REG32(PRESCALE, 0x1c)
+REG32(PSCNTR, 0x20)
+REG32(MISC, 0x4c)
+
+static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
+{
+ MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
+ uint64_t r;
+
+ switch (offset) {
+ case A_LED0:
+ r = s->led0;
+ break;
+ case A_BUTTON:
+ /* User-pressable board buttons. We don't model that, so just return
+ * zeroes.
+ */
+ r = 0;
+ break;
+ case A_PRESCALE:
+ r = s->prescale;
+ break;
+ case A_MISC:
+ r = s->misc;
+ break;
+ case A_CLK1HZ:
+ case A_CLK100HZ:
+ case A_COUNTER:
+ case A_PSCNTR:
+ /* These are all upcounters of various frequencies. */
+ qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n");
+ r = 0;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "MPS2 FPGAIO read: bad offset %x\n", (int) offset);
+ r = 0;
+ break;
+ }
+
+ trace_mps2_fpgaio_read(offset, r, size);
+ return r;
+}
+
+static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
+
+ trace_mps2_fpgaio_write(offset, value, size);
+
+ switch (offset) {
+ case A_LED0:
+ /* LED bits [1:0] control board LEDs. We don't currently have
+ * a mechanism for displaying this graphically, so use a trace event.
+ */
+ trace_mps2_fpgaio_leds(value & 0x02 ? '*' : '.',
+ value & 0x01 ? '*' : '.');
+ s->led0 = value & 0x3;
+ break;
+ case A_PRESCALE:
+ s->prescale = value;
+ break;
+ case A_MISC:
+ /* These are control bits for some of the other devices on the
+ * board (SPI, CLCD, etc). We don't implement that yet, so just
+ * make the bits read as written.
+ */
+ qemu_log_mask(LOG_UNIMP,
+ "MPS2 FPGAIO: MISC control bits unimplemented\n");
+ s->misc = value;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset);
+ break;
+ }
+}
+
+static const MemoryRegionOps mps2_fpgaio_ops = {
+ .read = mps2_fpgaio_read,
+ .write = mps2_fpgaio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void mps2_fpgaio_reset(DeviceState *dev)
+{
+ MPS2FPGAIO *s = MPS2_FPGAIO(dev);
+
+ trace_mps2_fpgaio_reset();
+ s->led0 = 0;
+ s->prescale = 0;
+ s->misc = 0;
+}
+
+static void mps2_fpgaio_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ MPS2FPGAIO *s = MPS2_FPGAIO(obj);
+
+ memory_region_init_io(&s->iomem, obj, &mps2_fpgaio_ops, s,
+ "mps2-fpgaio", 0x1000);
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static const VMStateDescription mps2_fpgaio_vmstate = {
+ .name = "mps2-fpgaio",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(led0, MPS2FPGAIO),
+ VMSTATE_UINT32(prescale, MPS2FPGAIO),
+ VMSTATE_UINT32(misc, MPS2FPGAIO),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property mps2_fpgaio_properties[] = {
+ /* Frequency of the prescale counter */
+ DEFINE_PROP_UINT32("prescale-clk", MPS2FPGAIO, prescale_clk, 20000000),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mps2_fpgaio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &mps2_fpgaio_vmstate;
+ dc->reset = mps2_fpgaio_reset;
+ dc->props = mps2_fpgaio_properties;
+}
+
+static const TypeInfo mps2_fpgaio_info = {
+ .name = TYPE_MPS2_FPGAIO,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MPS2FPGAIO),
+ .instance_init = mps2_fpgaio_init,
+ .class_init = mps2_fpgaio_class_init,
+};
+
+static void mps2_fpgaio_register_types(void)
+{
+ type_register_static(&mps2_fpgaio_info);
+}
+
+type_init(mps2_fpgaio_register_types);
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index b340d4e81c..562d9ed005 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -62,6 +62,12 @@ mps2_scc_leds(char led7, char led6, char led5, char led4, char led3, char led2,
mps2_scc_cfg_write(unsigned function, unsigned device, uint32_t value) "MPS2 SCC config write: function %d device %d data 0x%" PRIx32
mps2_scc_cfg_read(unsigned function, unsigned device, uint32_t value) "MPS2 SCC config read: function %d device %d data 0x%" PRIx32
+# hw/misc/mps2_fpgaio.c
+mps2_fpgaio_read(uint64_t offset, uint64_t data, unsigned size) "MPS2 FPGAIO read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+mps2_fpgaio_write(uint64_t offset, uint64_t data, unsigned size) "MPS2 FPGAIO write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+mps2_fpgaio_reset(void) "MPS2 FPGAIO: reset"
+mps2_fpgaio_leds(char led1, char led0) "MPS2 FPGAIO LEDs: %c%c"
+
# hw/misc/msf2-sysreg.c
msf2_sysreg_write(uint64_t offset, uint32_t val, uint32_t prev) "msf2-sysreg write: addr 0x%08" HWADDR_PRIx " data 0x%" PRIx32 " prev 0x%" PRIx32
msf2_sysreg_read(uint64_t offset, uint32_t val) "msf2-sysreg read: addr 0x%08" HWADDR_PRIx " data 0x%08" PRIx32
@@ -77,3 +83,21 @@ mos6522_get_next_irq_time(uint16_t latch, int64_t d, int64_t delta) "latch=%d co
mos6522_set_sr_int(void) "set sr_int"
mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64
mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x"
+
+# hw/misc/tz-ppc.c
+tz_ppc_reset(void) "TZ PPC: reset"
+tz_ppc_cfg_nonsec(int n, int level) "TZ PPC: cfg_nonsec[%d] = %d"
+tz_ppc_cfg_ap(int n, int level) "TZ PPC: cfg_ap[%d] = %d"
+tz_ppc_cfg_sec_resp(int level) "TZ PPC: cfg_sec_resp = %d"
+tz_ppc_irq_enable(int level) "TZ PPC: int_enable = %d"
+tz_ppc_irq_clear(int level) "TZ PPC: int_clear = %d"
+tz_ppc_update_irq(int level) "TZ PPC: setting irq line to %d"
+tz_ppc_read_blocked(int n, uint64_t offset, bool secure, bool user) "TZ PPC: port %d offset 0x%" PRIx64 " read (secure %d user %d) blocked"
+tz_ppc_write_blocked(int n, uint64_t offset, bool secure, bool user) "TZ PPC: port %d offset 0x%" PRIx64 " write (secure %d user %d) blocked"
+
+# hw/misc/iotkit-secctl.c
+iotkit_secctl_s_read(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl S regs read: offset 0x%x data 0x%" PRIx64 " size %u"
+iotkit_secctl_s_write(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl S regs write: offset 0x%x data 0x%" PRIx64 " size %u"
+iotkit_secctl_ns_read(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl NS regs read: offset 0x%x data 0x%" PRIx64 " size %u"
+iotkit_secctl_ns_write(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl NS regs write: offset 0x%x data 0x%" PRIx64 " size %u"
+iotkit_secctl_reset(void) "IoTKit SecCtl: reset"
diff --git a/hw/misc/tz-ppc.c b/hw/misc/tz-ppc.c
new file mode 100644
index 0000000000..3dd045c15f
--- /dev/null
+++ b/hw/misc/tz-ppc.c
@@ -0,0 +1,302 @@
+/*
+ * ARM TrustZone peripheral protection controller emulation
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "trace.h"
+#include "hw/sysbus.h"
+#include "hw/registerfields.h"
+#include "hw/misc/tz-ppc.h"
+
+static void tz_ppc_update_irq(TZPPC *s)
+{
+ bool level = s->irq_status && s->irq_enable;
+
+ trace_tz_ppc_update_irq(level);
+ qemu_set_irq(s->irq, level);
+}
+
+static void tz_ppc_cfg_nonsec(void *opaque, int n, int level)
+{
+ TZPPC *s = TZ_PPC(opaque);
+
+ assert(n < TZ_NUM_PORTS);
+ trace_tz_ppc_cfg_nonsec(n, level);
+ s->cfg_nonsec[n] = level;
+}
+
+static void tz_ppc_cfg_ap(void *opaque, int n, int level)
+{
+ TZPPC *s = TZ_PPC(opaque);
+
+ assert(n < TZ_NUM_PORTS);
+ trace_tz_ppc_cfg_ap(n, level);
+ s->cfg_ap[n] = level;
+}
+
+static void tz_ppc_cfg_sec_resp(void *opaque, int n, int level)
+{
+ TZPPC *s = TZ_PPC(opaque);
+
+ trace_tz_ppc_cfg_sec_resp(level);
+ s->cfg_sec_resp = level;
+}
+
+static void tz_ppc_irq_enable(void *opaque, int n, int level)
+{
+ TZPPC *s = TZ_PPC(opaque);
+
+ trace_tz_ppc_irq_enable(level);
+ s->irq_enable = level;
+ tz_ppc_update_irq(s);
+}
+
+static void tz_ppc_irq_clear(void *opaque, int n, int level)
+{
+ TZPPC *s = TZ_PPC(opaque);
+
+ trace_tz_ppc_irq_clear(level);
+
+ s->irq_clear = level;
+ if (level) {
+ s->irq_status = false;
+ tz_ppc_update_irq(s);
+ }
+}
+
+static bool tz_ppc_check(TZPPC *s, int n, MemTxAttrs attrs)
+{
+ /* Check whether to allow an access to port n; return true if
+ * the check passes, and false if the transaction must be blocked.
+ * If the latter, the caller must check cfg_sec_resp to determine
+ * whether to abort or RAZ/WI the transaction.
+ * The checks are:
+ * + nonsec_mask suppresses any check of the secure attribute
+ * + otherwise, block if cfg_nonsec is 1 and transaction is secure,
+ * or if cfg_nonsec is 0 and transaction is non-secure
+ * + block if transaction is usermode and cfg_ap is 0
+ */
+ if ((attrs.secure == s->cfg_nonsec[n] && !(s->nonsec_mask & (1 << n))) ||
+ (attrs.user && !s->cfg_ap[n])) {
+ /* Block the transaction. */
+ if (!s->irq_clear) {
+ /* Note that holding irq_clear high suppresses interrupts */
+ s->irq_status = true;
+ tz_ppc_update_irq(s);
+ }
+ return false;
+ }
+ return true;
+}
+
+static MemTxResult tz_ppc_read(void *opaque, hwaddr addr, uint64_t *pdata,
+ unsigned size, MemTxAttrs attrs)
+{
+ TZPPCPort *p = opaque;
+ TZPPC *s = p->ppc;
+ int n = p - s->port;
+ AddressSpace *as = &p->downstream_as;
+ uint64_t data;
+ MemTxResult res;
+
+ if (!tz_ppc_check(s, n, attrs)) {
+ trace_tz_ppc_read_blocked(n, addr, attrs.secure, attrs.user);
+ if (s->cfg_sec_resp) {
+ return MEMTX_ERROR;
+ } else {
+ *pdata = 0;
+ return MEMTX_OK;
+ }
+ }
+
+ switch (size) {
+ case 1:
+ data = address_space_ldub(as, addr, attrs, &res);
+ break;
+ case 2:
+ data = address_space_lduw_le(as, addr, attrs, &res);
+ break;
+ case 4:
+ data = address_space_ldl_le(as, addr, attrs, &res);
+ break;
+ case 8:
+ data = address_space_ldq_le(as, addr, attrs, &res);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ *pdata = data;
+ return res;
+}
+
+static MemTxResult tz_ppc_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size, MemTxAttrs attrs)
+{
+ TZPPCPort *p = opaque;
+ TZPPC *s = p->ppc;
+ AddressSpace *as = &p->downstream_as;
+ int n = p - s->port;
+ MemTxResult res;
+
+ if (!tz_ppc_check(s, n, attrs)) {
+ trace_tz_ppc_write_blocked(n, addr, attrs.secure, attrs.user);
+ if (s->cfg_sec_resp) {
+ return MEMTX_ERROR;
+ } else {
+ return MEMTX_OK;
+ }
+ }
+
+ switch (size) {
+ case 1:
+ address_space_stb(as, addr, val, attrs, &res);
+ break;
+ case 2:
+ address_space_stw_le(as, addr, val, attrs, &res);
+ break;
+ case 4:
+ address_space_stl_le(as, addr, val, attrs, &res);
+ break;
+ case 8:
+ address_space_stq_le(as, addr, val, attrs, &res);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return res;
+}
+
+static const MemoryRegionOps tz_ppc_ops = {
+ .read_with_attrs = tz_ppc_read,
+ .write_with_attrs = tz_ppc_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void tz_ppc_reset(DeviceState *dev)
+{
+ TZPPC *s = TZ_PPC(dev);
+
+ trace_tz_ppc_reset();
+ s->cfg_sec_resp = false;
+ memset(s->cfg_nonsec, 0, sizeof(s->cfg_nonsec));
+ memset(s->cfg_ap, 0, sizeof(s->cfg_ap));
+}
+
+static void tz_ppc_init(Object *obj)
+{
+ DeviceState *dev = DEVICE(obj);
+ TZPPC *s = TZ_PPC(obj);
+
+ qdev_init_gpio_in_named(dev, tz_ppc_cfg_nonsec, "cfg_nonsec", TZ_NUM_PORTS);
+ qdev_init_gpio_in_named(dev, tz_ppc_cfg_ap, "cfg_ap", TZ_NUM_PORTS);
+ qdev_init_gpio_in_named(dev, tz_ppc_cfg_sec_resp, "cfg_sec_resp", 1);
+ qdev_init_gpio_in_named(dev, tz_ppc_irq_enable, "irq_enable", 1);
+ qdev_init_gpio_in_named(dev, tz_ppc_irq_clear, "irq_clear", 1);
+ qdev_init_gpio_out_named(dev, &s->irq, "irq", 1);
+}
+
+static void tz_ppc_realize(DeviceState *dev, Error **errp)
+{
+ Object *obj = OBJECT(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ TZPPC *s = TZ_PPC(dev);
+ int i;
+
+ /* We can't create the upstream end of the port until realize,
+ * as we don't know the size of the MR used as the downstream until then.
+ */
+ for (i = 0; i < TZ_NUM_PORTS; i++) {
+ TZPPCPort *port = &s->port[i];
+ char *name;
+ uint64_t size;
+
+ if (!port->downstream) {
+ continue;
+ }
+
+ name = g_strdup_printf("tz-ppc-port[%d]", i);
+
+ port->ppc = s;
+ address_space_init(&port->downstream_as, port->downstream, name);
+
+ size = memory_region_size(port->downstream);
+ memory_region_init_io(&port->upstream, obj, &tz_ppc_ops,
+ port, name, size);
+ sysbus_init_mmio(sbd, &port->upstream);
+ g_free(name);
+ }
+}
+
+static const VMStateDescription tz_ppc_vmstate = {
+ .name = "tz-ppc",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL_ARRAY(cfg_nonsec, TZPPC, 16),
+ VMSTATE_BOOL_ARRAY(cfg_ap, TZPPC, 16),
+ VMSTATE_BOOL(cfg_sec_resp, TZPPC),
+ VMSTATE_BOOL(irq_enable, TZPPC),
+ VMSTATE_BOOL(irq_clear, TZPPC),
+ VMSTATE_BOOL(irq_status, TZPPC),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+#define DEFINE_PORT(N) \
+ DEFINE_PROP_LINK("port[" #N "]", TZPPC, port[N].downstream, \
+ TYPE_MEMORY_REGION, MemoryRegion *)
+
+static Property tz_ppc_properties[] = {
+ DEFINE_PROP_UINT32("NONSEC_MASK", TZPPC, nonsec_mask, 0),
+ DEFINE_PORT(0),
+ DEFINE_PORT(1),
+ DEFINE_PORT(2),
+ DEFINE_PORT(3),
+ DEFINE_PORT(4),
+ DEFINE_PORT(5),
+ DEFINE_PORT(6),
+ DEFINE_PORT(7),
+ DEFINE_PORT(8),
+ DEFINE_PORT(9),
+ DEFINE_PORT(10),
+ DEFINE_PORT(11),
+ DEFINE_PORT(12),
+ DEFINE_PORT(13),
+ DEFINE_PORT(14),
+ DEFINE_PORT(15),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tz_ppc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = tz_ppc_realize;
+ dc->vmsd = &tz_ppc_vmstate;
+ dc->reset = tz_ppc_reset;
+ dc->props = tz_ppc_properties;
+}
+
+static const TypeInfo tz_ppc_info = {
+ .name = TYPE_TZ_PPC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(TZPPC),
+ .instance_init = tz_ppc_init,
+ .class_init = tz_ppc_class_init,
+};
+
+static void tz_ppc_register_types(void)
+{
+ type_register_static(&tz_ppc_info);
+}
+
+type_init(tz_ppc_register_types);
diff --git a/hw/misc/unimp.c b/hw/misc/unimp.c
index bcbb585888..1c0ba2f0a7 100644
--- a/hw/misc/unimp.c
+++ b/hw/misc/unimp.c
@@ -18,16 +18,6 @@
#include "qemu/log.h"
#include "qapi/error.h"
-#define UNIMPLEMENTED_DEVICE(obj) \
- OBJECT_CHECK(UnimplementedDeviceState, (obj), TYPE_UNIMPLEMENTED_DEVICE)
-
-typedef struct {
- SysBusDevice parent_obj;
- MemoryRegion iomem;
- char *name;
- uint64_t size;
-} UnimplementedDeviceState;
-
static uint64_t unimp_read(void *opaque, hwaddr offset, unsigned size)
{
UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(opaque);
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index 804ec08721..c7f1695f57 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -30,7 +30,6 @@
#include "hw/pci/pci.h"
#include "net/net.h"
#include "net/checksum.h"
-#include "hw/loader.h"
#include "sysemu/sysemu.h"
#include "sysemu/dma.h"
#include "qemu/iov.h"
diff --git a/hw/net/lance.c b/hw/net/lance.c
index 0028bc525d..a08d5ac6a8 100644
--- a/hw/net/lance.c
+++ b/hw/net/lance.c
@@ -36,10 +36,7 @@
*/
#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
#include "qemu/timer.h"
-#include "qemu/sockets.h"
#include "hw/sparc/sparc32_dma.h"
#include "hw/net/lance.h"
#include "trace.h"
diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c
index 687ef84aac..3a9fc89e48 100644
--- a/hw/net/ne2000.c
+++ b/hw/net/ne2000.c
@@ -23,10 +23,8 @@
*/
#include "qemu/osdep.h"
#include "hw/pci/pci.h"
-#include "net/net.h"
#include "net/eth.h"
#include "ne2000.h"
-#include "hw/loader.h"
#include "sysemu/sysemu.h"
/* debug NE2000 card */
diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c
index e29c881bc2..162f802dd7 100644
--- a/hw/net/net_tx_pkt.c
+++ b/hw/net/net_tx_pkt.c
@@ -205,7 +205,7 @@ static bool net_tx_pkt_parse_headers(struct NetTxPkt *pkt)
return false;
}
- pkt->l4proto = ((struct ip_header *) l3_hdr->iov_base)->ip_p;
+ pkt->l4proto = IP_HDR_GET_P(l3_hdr->iov_base);
if (IP_HDR_GET_LEN(l3_hdr->iov_base) != sizeof(struct ip_header)) {
/* copy optional IPv4 header data if any*/
diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c
index 0ae5ca4701..70dc8b3f0c 100644
--- a/hw/net/pcnet-pci.c
+++ b/hw/net/pcnet-pci.c
@@ -30,7 +30,6 @@
#include "qemu/osdep.h"
#include "hw/pci/pci.h"
#include "net/net.h"
-#include "hw/loader.h"
#include "qemu/timer.h"
#include "sysemu/dma.h"
#include "sysemu/sysemu.h"
diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c
index 606b05c09f..0c44554168 100644
--- a/hw/net/pcnet.c
+++ b/hw/net/pcnet.c
@@ -40,7 +40,6 @@
#include "net/net.h"
#include "net/eth.h"
#include "qemu/timer.h"
-#include "qemu/sockets.h"
#include "sysemu/sysemu.h"
#include "trace.h"
diff --git a/hw/net/rocker/qmp-norocker.c b/hw/net/rocker/qmp-norocker.c
index 94c1e480ae..0d60513c01 100644
--- a/hw/net/rocker/qmp-norocker.c
+++ b/hw/net/rocker/qmp-norocker.c
@@ -17,8 +17,8 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
-#include "qmp-commands.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-rocker.h"
#include "qapi/qmp/qerror.h"
RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c
index a2a76c2a74..c02cbefece 100644
--- a/hw/net/rocker/rocker.c
+++ b/hw/net/rocker/rocker.c
@@ -22,9 +22,9 @@
#include "net/net.h"
#include "net/eth.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-rocker.h"
#include "qemu/iov.h"
#include "qemu/bitops.h"
-#include "qmp-commands.h"
#include "rocker.h"
#include "rocker_hw.h"
diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c
index 4b3c9847db..27b17c890f 100644
--- a/hw/net/rocker/rocker_fp.c
+++ b/hw/net/rocker/rocker_fp.c
@@ -16,7 +16,7 @@
#include "qemu/osdep.h"
#include "net/clients.h"
-
+#include "qapi/qapi-types-rocker.h"
#include "rocker.h"
#include "rocker_hw.h"
#include "rocker_fp.h"
diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c
index 9339df2d09..60046720a5 100644
--- a/hw/net/rocker/rocker_of_dpa.c
+++ b/hw/net/rocker/rocker_of_dpa.c
@@ -17,9 +17,9 @@
#include "qemu/osdep.h"
#include "net/eth.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-rocker.h"
#include "qemu/iov.h"
#include "qemu/timer.h"
-#include "qmp-commands.h"
#include "rocker.h"
#include "rocker_hw.h"
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index 1cc95b8cba..46daa16202 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -58,9 +58,7 @@
#include "qemu/timer.h"
#include "net/net.h"
#include "net/eth.h"
-#include "hw/loader.h"
#include "sysemu/sysemu.h"
-#include "qemu/iov.h"
/* debug RTL8139 card */
//#define DEBUG_RTL8139 1
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 369d40b378..188744e17d 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -23,7 +23,7 @@
#include "net/vhost_net.h"
#include "hw/virtio/virtio-bus.h"
#include "qapi/error.h"
-#include "qapi-event.h"
+#include "qapi/qapi-events-net.h"
#include "hw/virtio/virtio-access.h"
#include "migration/misc.h"
diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c
index 0843bf185c..fa001563d3 100644
--- a/hw/net/xgmac.c
+++ b/hw/net/xgmac.c
@@ -28,7 +28,6 @@
#include "hw/sysbus.h"
#include "qemu/log.h"
#include "net/net.h"
-#include "net/checksum.h"
#ifdef DEBUG_XGMAC
#define DEBUGF_BRK(message, args...) do { \
diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c
index 74ce7316da..b941a0e842 100644
--- a/hw/pci/pci-stub.c
+++ b/hw/pci/pci-stub.c
@@ -22,9 +22,9 @@
#include "sysemu/sysemu.h"
#include "monitor/monitor.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-misc.h"
#include "qapi/qmp/qerror.h"
#include "hw/pci/pci.h"
-#include "qmp-commands.h"
#include "hw/pci/msi.h"
bool msi_nonbroken;
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index e006b6ac71..2174c254eb 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -34,7 +34,6 @@
#include "hw/loader.h"
#include "qemu/error-report.h"
#include "qemu/range.h"
-#include "qmp-commands.h"
#include "trace.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
@@ -42,6 +41,7 @@
#include "hw/hotplug.h"
#include "hw/boards.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-misc.h"
#include "qemu/cutils.h"
//#define DEBUG_PCI
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index ad1928c5d8..86d82a6ec3 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -13,7 +13,8 @@ endif
obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o
# PowerPC 4xx boards
obj-y += ppc4xx_devs.o ppc405_uc.o
-obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o ppc440_bamboo.o
+obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o
+obj-$(CONFIG_PPC4XX) += ppc440_bamboo.o ppc440_pcix.o ppc440_uc.o sam460ex.o
# PReP
obj-$(CONFIG_PREP) += prep.o
obj-$(CONFIG_PREP) += prep_systemio.o
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index a40d3ec3e3..43c15d18c4 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -29,6 +29,7 @@
#include "kvm_ppc.h"
#include "sysemu/device_tree.h"
#include "hw/ppc/openpic.h"
+#include "hw/ppc/openpic_kvm.h"
#include "hw/ppc/ppc.h"
#include "hw/loader.h"
#include "elf.h"
@@ -119,7 +120,14 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
if (defcon) {
+ /*
+ * "linux,stdout-path" and "stdout" properties are deprecated by linux
+ * kernel. New platforms should only use the "stdout-path" property. Set
+ * the new property and continue using older property to remain
+ * compatible with the existing firmware.
+ */
qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
+ qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", ser);
}
}
@@ -784,8 +792,10 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
int initrd_size = 0;
hwaddr cur_base = 0;
char *filename;
+ const char *payload_name;
+ bool kernel_as_payload;
hwaddr bios_entry = 0;
- target_long bios_size;
+ target_long payload_size;
struct boot_info *boot_info;
int dt_size;
int i;
@@ -913,11 +923,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
/* Register spinning region */
sysbus_create_simple("e500-spin", params->spin_base, NULL);
- if (cur_base < (32 * 1024 * 1024)) {
- /* u-boot occupies memory up to 32MB, so load blobs above */
- cur_base = (32 * 1024 * 1024);
- }
-
if (params->has_mpc8xxx_gpio) {
qemu_irq poweroff_irq;
@@ -952,8 +957,61 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
sysbus_mmio_get_region(s, 0));
}
- /* Load kernel. */
- if (machine->kernel_filename) {
+ /*
+ * Smart firmware defaults ahead!
+ *
+ * We follow the following table to select which payload we execute.
+ *
+ * -kernel | -bios | payload
+ * ---------+-------+---------
+ * N | Y | u-boot
+ * N | N | u-boot
+ * Y | Y | u-boot
+ * Y | N | kernel
+ *
+ * This ensures backwards compatibility with how we used to expose
+ * -kernel to users but allows them to run through u-boot as well.
+ */
+ kernel_as_payload = false;
+ if (bios_name == NULL) {
+ if (machine->kernel_filename) {
+ payload_name = machine->kernel_filename;
+ kernel_as_payload = true;
+ } else {
+ payload_name = "u-boot.e500";
+ }
+ } else {
+ payload_name = bios_name;
+ }
+
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
+
+ payload_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
+ 1, PPC_ELF_MACHINE, 0, 0);
+ if (payload_size < 0) {
+ /*
+ * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
+ * ePAPR compliant kernel
+ */
+ payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
+ NULL, NULL);
+ if (payload_size < 0) {
+ error_report("qemu: could not load firmware '%s'", filename);
+ exit(1);
+ }
+ }
+
+ g_free(filename);
+
+ if (kernel_as_payload) {
+ kernel_base = loadaddr;
+ kernel_size = payload_size;
+ }
+
+ cur_base = loadaddr + payload_size;
+
+ /* Load bare kernel only if no bios/u-boot has been provided */
+ if (machine->kernel_filename && !kernel_as_payload) {
kernel_base = cur_base;
kernel_size = load_image_targphys(machine->kernel_filename,
cur_base,
@@ -967,6 +1025,11 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
cur_base += kernel_size;
}
+ if (cur_base < (32 * 1024 * 1024)) {
+ /* u-boot occupies memory up to 32MB, so load blobs above */
+ cur_base = (32 * 1024 * 1024);
+ }
+
/* Load initrd. */
if (machine->initrd_filename) {
initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
@@ -983,47 +1046,16 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
}
/*
- * Smart firmware defaults ahead!
- *
- * We follow the following table to select which payload we execute.
- *
- * -kernel | -bios | payload
- * ---------+-------+---------
- * N | Y | u-boot
- * N | N | u-boot
- * Y | Y | u-boot
- * Y | N | kernel
- *
- * This ensures backwards compatibility with how we used to expose
- * -kernel to users but allows them to run through u-boot as well.
+ * Reserve space for dtb behind the kernel image because Linux has a bug
+ * where it can only handle the dtb if it's within the first 64MB of where
+ * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
+ * ensures enough space between kernel and initrd.
*/
- if (bios_name == NULL) {
- if (machine->kernel_filename) {
- bios_name = machine->kernel_filename;
- } else {
- bios_name = "u-boot.e500";
- }
- }
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-
- bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
- 1, PPC_ELF_MACHINE, 0, 0);
- if (bios_size < 0) {
- /*
- * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
- * ePAPR compliant kernel
- */
- kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
- NULL, NULL);
- if (kernel_size < 0) {
- error_report("could not load firmware '%s'", filename);
+ dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
+ if (dt_base + DTB_MAX_SIZE > ram_size) {
+ error_report("qemu: not enough memory for device tree");
exit(1);
- }
}
- g_free(filename);
-
- /* Reserve space for dtb */
- dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
dt_size = ppce500_prep_device_tree(machine, params, dt_base,
initrd_base, initrd_size,
diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h
index 4702194f3f..a02f797598 100644
--- a/hw/ppc/mac.h
+++ b/hw/ppc/mac.h
@@ -47,9 +47,6 @@
/* MacIO */
-#define TYPE_OLDWORLD_MACIO "macio-oldworld"
-#define TYPE_NEWWORLD_MACIO "macio-newworld"
-
#define TYPE_MACIO_IDE "macio-ide"
#define MACIO_IDE(obj) OBJECT_CHECK(MACIOIDEState, (obj), TYPE_MACIO_IDE)
@@ -76,12 +73,11 @@ void macio_ide_init_drives(MACIOIDEState *ide, DriveInfo **hd_table);
void macio_ide_register_dma(MACIOIDEState *ide);
void macio_init(PCIDevice *dev,
- MemoryRegion *pic_mem,
- MemoryRegion *escc_mem);
+ MemoryRegion *pic_mem);
/* Heathrow PIC */
-qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
- int nb_cpus, qemu_irq **irqs);
+DeviceState *heathrow_pic_init(int nb_cpus, qemu_irq **irqs,
+ qemu_irq **pic_irqs);
/* Grackle PCI */
#define TYPE_GRACKLE_PCI_HOST_BRIDGE "grackle-pcihost"
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 4e1298ee50..a749e2565d 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -60,6 +60,7 @@
#include "hw/boards.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/char/escc.h"
+#include "hw/misc/macio/macio.h"
#include "hw/ppc/openpic.h"
#include "hw/ide.h"
#include "hw/loader.h"
@@ -153,20 +154,18 @@ static void ppc_core99_init(MachineState *machine)
hwaddr kernel_base, initrd_base, cmdline_base = 0;
long kernel_size, initrd_size;
PCIBus *pci_bus;
- PCIDevice *macio;
+ NewWorldMacIOState *macio;
MACIOIDEState *macio_ide;
BusState *adb_bus;
MacIONVRAMState *nvr;
int bios_size, ndrv_size;
uint8_t *ndrv_file;
- MemoryRegion *pic_mem, *escc_mem;
- MemoryRegion *escc_bar = g_new(MemoryRegion, 1);
int ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
void *fw_cfg;
int machine_arch;
SysBusDevice *s;
- DeviceState *dev;
+ DeviceState *dev, *pic_dev;
int *token = g_new(int, 1);
hwaddr nvram_addr = 0xFFF04000;
uint64_t tbfreq;
@@ -333,11 +332,10 @@ static void ppc_core99_init(MachineState *machine)
pic = g_new0(qemu_irq, 64);
- dev = qdev_create(NULL, TYPE_OPENPIC);
- qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_KEYLARGO);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- pic_mem = s->mmio[0].memory;
+ pic_dev = qdev_create(NULL, TYPE_OPENPIC);
+ qdev_prop_set_uint32(pic_dev, "model", OPENPIC_MODEL_KEYLARGO);
+ qdev_init_nofail(pic_dev);
+ s = SYS_BUS_DEVICE(pic_dev);
k = 0;
for (i = 0; i < smp_cpus; i++) {
for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
@@ -346,7 +344,7 @@ static void ppc_core99_init(MachineState *machine)
}
for (i = 0; i < 64; i++) {
- pic[i] = qdev_get_gpio_in(dev, i);
+ pic[i] = qdev_get_gpio_in(pic_dev, i);
}
if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
@@ -368,36 +366,20 @@ static void ppc_core99_init(MachineState *machine)
tbfreq = TBFREQ;
}
- /* init basic PC hardware */
-
- dev = qdev_create(NULL, TYPE_ESCC);
- qdev_prop_set_uint32(dev, "disabled", 0);
- qdev_prop_set_uint32(dev, "frequency", ESCC_CLOCK);
- qdev_prop_set_uint32(dev, "it_shift", 4);
- qdev_prop_set_chr(dev, "chrA", serial_hds[0]);
- qdev_prop_set_chr(dev, "chrB", serial_hds[1]);
- qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
- qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
- qdev_init_nofail(dev);
-
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, pic[0x24]);
- sysbus_connect_irq(s, 1, pic[0x25]);
-
- escc_mem = &ESCC(s)->mmio;
-
- memory_region_init_alias(escc_bar, NULL, "escc-bar",
- escc_mem, 0, memory_region_size(escc_mem));
-
- macio = pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO);
+ /* MacIO */
+ macio = NEWWORLD_MACIO(pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO));
dev = DEVICE(macio);
qdev_connect_gpio_out(dev, 0, pic[0x19]); /* CUDA */
- qdev_connect_gpio_out(dev, 1, pic[0x0d]); /* IDE */
- qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE DMA */
- qdev_connect_gpio_out(dev, 3, pic[0x0e]); /* IDE */
- qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE DMA */
+ qdev_connect_gpio_out(dev, 1, pic[0x24]); /* ESCC-B */
+ qdev_connect_gpio_out(dev, 2, pic[0x25]); /* ESCC-A */
+ qdev_connect_gpio_out(dev, 3, pic[0x0d]); /* IDE */
+ qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE DMA */
+ qdev_connect_gpio_out(dev, 5, pic[0x0e]); /* IDE */
+ qdev_connect_gpio_out(dev, 6, pic[0x03]); /* IDE DMA */
qdev_prop_set_uint64(dev, "frequency", tbfreq);
- macio_init(macio, pic_mem, escc_bar);
+ object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic",
+ &error_abort);
+ qdev_init_nofail(dev);
/* We only emulate 2 out of 3 IDE controllers for now */
ide_drive_get(hd, ARRAY_SIZE(hd));
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index d0d21d2392..935493c966 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -37,6 +37,7 @@
#include "hw/boards.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/char/escc.h"
+#include "hw/misc/macio/macio.h"
#include "hw/ide.h"
#include "hw/loader.h"
#include "elf.h"
@@ -92,19 +93,16 @@ static void ppc_heathrow_init(MachineState *machine)
uint32_t kernel_base, initrd_base, cmdline_base = 0;
int32_t kernel_size, initrd_size;
PCIBus *pci_bus;
- PCIDevice *macio;
+ OldWorldMacIOState *macio;
MACIOIDEState *macio_ide;
- DeviceState *dev;
+ DeviceState *dev, *pic_dev;
BusState *adb_bus;
int bios_size, ndrv_size;
uint8_t *ndrv_file;
- MemoryRegion *pic_mem;
- MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1);
uint16_t ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
void *fw_cfg;
uint64_t tbfreq;
- SysBusDevice *s;
linux_boot = (kernel_filename != NULL);
@@ -259,46 +257,32 @@ static void ppc_heathrow_init(MachineState *machine)
error_report("Only 6xx bus is supported on heathrow machine");
exit(1);
}
- pic = heathrow_pic_init(&pic_mem, 1, heathrow_irqs);
+ pic_dev = heathrow_pic_init(1, heathrow_irqs, &pic);
pci_bus = pci_grackle_init(0xfec00000, pic,
get_system_memory(),
get_system_io());
pci_vga_init(pci_bus);
- dev = qdev_create(NULL, TYPE_ESCC);
- qdev_prop_set_uint32(dev, "disabled", 0);
- qdev_prop_set_uint32(dev, "frequency", ESCC_CLOCK);
- qdev_prop_set_uint32(dev, "it_shift", 4);
- qdev_prop_set_chr(dev, "chrA", serial_hds[0]);
- qdev_prop_set_chr(dev, "chrB", serial_hds[1]);
- qdev_prop_set_uint32(dev, "chnBtype", escc_serial);
- qdev_prop_set_uint32(dev, "chnAtype", escc_serial);
- qdev_init_nofail(dev);
-
- s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, pic[0x10]);
- sysbus_connect_irq(s, 1, pic[0x0f]);
-
- escc_mem = &ESCC(s)->mmio;
-
- memory_region_init_alias(escc_bar, NULL, "escc-bar",
- escc_mem, 0, memory_region_size(escc_mem));
-
- for(i = 0; i < nb_nics; i++)
+ for (i = 0; i < nb_nics; i++) {
pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
-
+ }
ide_drive_get(hd, ARRAY_SIZE(hd));
- macio = pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO);
+ /* MacIO */
+ macio = OLDWORLD_MACIO(pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO));
dev = DEVICE(macio);
qdev_connect_gpio_out(dev, 0, pic[0x12]); /* CUDA */
- qdev_connect_gpio_out(dev, 1, pic[0x0D]); /* IDE-0 */
- qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE-0 DMA */
- qdev_connect_gpio_out(dev, 3, pic[0x0E]); /* IDE-1 */
- qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE-1 DMA */
+ qdev_connect_gpio_out(dev, 1, pic[0x10]); /* ESCC-B */
+ qdev_connect_gpio_out(dev, 2, pic[0x0F]); /* ESCC-A */
+ qdev_connect_gpio_out(dev, 3, pic[0x0D]); /* IDE-0 */
+ qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE-0 DMA */
+ qdev_connect_gpio_out(dev, 5, pic[0x0E]); /* IDE-1 */
+ qdev_connect_gpio_out(dev, 6, pic[0x03]); /* IDE-1 DMA */
qdev_prop_set_uint64(dev, "frequency", tbfreq);
- macio_init(macio, pic_mem, escc_bar);
+ object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic",
+ &error_abort);
+ qdev_init_nofail(dev);
macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
"ide[0]"));
diff --git a/hw/ppc/ppc440_pcix.c b/hw/ppc/ppc440_pcix.c
new file mode 100644
index 0000000000..ab2626a9de
--- /dev/null
+++ b/hw/ppc/ppc440_pcix.c
@@ -0,0 +1,528 @@
+/*
+ * Emulation of the ibm,plb-pcix PCI controller
+ * This is found in some 440 SoCs e.g. the 460EX.
+ *
+ * Copyright (c) 2016-2018 BALATON Zoltan
+ *
+ * Derived from ppc4xx_pci.c and pci-host/ppce500.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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 "qemu/error-report.h"
+#include "hw/hw.h"
+#include "hw/ppc/ppc.h"
+#include "hw/ppc/ppc4xx.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "exec/address-spaces.h"
+#include "trace.h"
+
+struct PLBOutMap {
+ uint64_t la;
+ uint64_t pcia;
+ uint32_t sa;
+ MemoryRegion mr;
+};
+
+struct PLBInMap {
+ uint64_t sa;
+ uint64_t la;
+ MemoryRegion mr;
+};
+
+#define TYPE_PPC440_PCIX_HOST_BRIDGE "ppc440-pcix-host"
+#define PPC440_PCIX_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(PPC440PCIXState, (obj), TYPE_PPC440_PCIX_HOST_BRIDGE)
+
+#define PPC440_PCIX_NR_POMS 3
+#define PPC440_PCIX_NR_PIMS 3
+
+typedef struct PPC440PCIXState {
+ PCIHostState parent_obj;
+
+ PCIDevice *dev;
+ struct PLBOutMap pom[PPC440_PCIX_NR_POMS];
+ struct PLBInMap pim[PPC440_PCIX_NR_PIMS];
+ uint32_t sts;
+ qemu_irq irq[PCI_NUM_PINS];
+ AddressSpace bm_as;
+ MemoryRegion bm;
+
+ MemoryRegion container;
+ MemoryRegion iomem;
+ MemoryRegion busmem;
+} PPC440PCIXState;
+
+#define PPC440_REG_BASE 0x80000
+#define PPC440_REG_SIZE 0xff
+
+#define PCIC0_CFGADDR 0x0
+#define PCIC0_CFGDATA 0x4
+
+#define PCIX0_POM0LAL 0x68
+#define PCIX0_POM0LAH 0x6c
+#define PCIX0_POM0SA 0x70
+#define PCIX0_POM0PCIAL 0x74
+#define PCIX0_POM0PCIAH 0x78
+#define PCIX0_POM1LAL 0x7c
+#define PCIX0_POM1LAH 0x80
+#define PCIX0_POM1SA 0x84
+#define PCIX0_POM1PCIAL 0x88
+#define PCIX0_POM1PCIAH 0x8c
+#define PCIX0_POM2SA 0x90
+
+#define PCIX0_PIM0SAL 0x98
+#define PCIX0_PIM0LAL 0x9c
+#define PCIX0_PIM0LAH 0xa0
+#define PCIX0_PIM1SA 0xa4
+#define PCIX0_PIM1LAL 0xa8
+#define PCIX0_PIM1LAH 0xac
+#define PCIX0_PIM2SAL 0xb0
+#define PCIX0_PIM2LAL 0xb4
+#define PCIX0_PIM2LAH 0xb8
+#define PCIX0_PIM0SAH 0xf8
+#define PCIX0_PIM2SAH 0xfc
+
+#define PCIX0_STS 0xe0
+
+#define PCI_ALL_SIZE (PPC440_REG_BASE + PPC440_REG_SIZE)
+
+static void ppc440_pcix_clear_region(MemoryRegion *parent,
+ MemoryRegion *mem)
+{
+ if (memory_region_is_mapped(mem)) {
+ memory_region_del_subregion(parent, mem);
+ object_unparent(OBJECT(mem));
+ }
+}
+
+/* DMA mapping */
+static void ppc440_pcix_update_pim(PPC440PCIXState *s, int idx)
+{
+ MemoryRegion *mem = &s->pim[idx].mr;
+ char *name;
+ uint64_t size;
+
+ /* Before we modify anything, unmap and destroy the region */
+ ppc440_pcix_clear_region(&s->bm, mem);
+
+ if (!(s->pim[idx].sa & 1)) {
+ /* Not enabled, nothing to do */
+ return;
+ }
+
+ name = g_strdup_printf("PCI Inbound Window %d", idx);
+ size = ~(s->pim[idx].sa & ~7ULL) + 1;
+ memory_region_init_alias(mem, OBJECT(s), name, get_system_memory(),
+ s->pim[idx].la, size);
+ memory_region_add_subregion_overlap(&s->bm, 0, mem, -1);
+ g_free(name);
+
+ trace_ppc440_pcix_update_pim(idx, size, s->pim[idx].la);
+}
+
+/* BAR mapping */
+static void ppc440_pcix_update_pom(PPC440PCIXState *s, int idx)
+{
+ MemoryRegion *mem = &s->pom[idx].mr;
+ MemoryRegion *address_space_mem = get_system_memory();
+ char *name;
+ uint32_t size;
+
+ /* Before we modify anything, unmap and destroy the region */
+ ppc440_pcix_clear_region(address_space_mem, mem);
+
+ if (!(s->pom[idx].sa & 1)) {
+ /* Not enabled, nothing to do */
+ return;
+ }
+
+ name = g_strdup_printf("PCI Outbound Window %d", idx);
+ size = ~(s->pom[idx].sa & 0xfffffffe) + 1;
+ if (!size) {
+ size = 0xffffffff;
+ }
+ memory_region_init_alias(mem, OBJECT(s), name, &s->busmem,
+ s->pom[idx].pcia, size);
+ memory_region_add_subregion(address_space_mem, s->pom[idx].la, mem);
+ g_free(name);
+
+ trace_ppc440_pcix_update_pom(idx, size, s->pom[idx].la, s->pom[idx].pcia);
+}
+
+static void ppc440_pcix_reg_write4(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ struct PPC440PCIXState *s = opaque;
+
+ trace_ppc440_pcix_reg_read(addr, val);
+ switch (addr) {
+ case PCI_VENDOR_ID ... PCI_MAX_LAT:
+ stl_le_p(s->dev->config + addr, val);
+ break;
+
+ case PCIX0_POM0LAL:
+ s->pom[0].la &= 0xffffffff00000000ULL;
+ s->pom[0].la |= val;
+ ppc440_pcix_update_pom(s, 0);
+ break;
+ case PCIX0_POM0LAH:
+ s->pom[0].la &= 0xffffffffULL;
+ s->pom[0].la |= val << 32;
+ ppc440_pcix_update_pom(s, 0);
+ break;
+ case PCIX0_POM0SA:
+ s->pom[0].sa = val;
+ ppc440_pcix_update_pom(s, 0);
+ break;
+ case PCIX0_POM0PCIAL:
+ s->pom[0].pcia &= 0xffffffff00000000ULL;
+ s->pom[0].pcia |= val;
+ ppc440_pcix_update_pom(s, 0);
+ break;
+ case PCIX0_POM0PCIAH:
+ s->pom[0].pcia &= 0xffffffffULL;
+ s->pom[0].pcia |= val << 32;
+ ppc440_pcix_update_pom(s, 0);
+ break;
+ case PCIX0_POM1LAL:
+ s->pom[1].la &= 0xffffffff00000000ULL;
+ s->pom[1].la |= val;
+ ppc440_pcix_update_pom(s, 1);
+ break;
+ case PCIX0_POM1LAH:
+ s->pom[1].la &= 0xffffffffULL;
+ s->pom[1].la |= val << 32;
+ ppc440_pcix_update_pom(s, 1);
+ break;
+ case PCIX0_POM1SA:
+ s->pom[1].sa = val;
+ ppc440_pcix_update_pom(s, 1);
+ break;
+ case PCIX0_POM1PCIAL:
+ s->pom[1].pcia &= 0xffffffff00000000ULL;
+ s->pom[1].pcia |= val;
+ ppc440_pcix_update_pom(s, 1);
+ break;
+ case PCIX0_POM1PCIAH:
+ s->pom[1].pcia &= 0xffffffffULL;
+ s->pom[1].pcia |= val << 32;
+ ppc440_pcix_update_pom(s, 1);
+ break;
+ case PCIX0_POM2SA:
+ s->pom[2].sa = val;
+ break;
+
+ case PCIX0_PIM0SAL:
+ s->pim[0].sa &= 0xffffffff00000000ULL;
+ s->pim[0].sa |= val;
+ ppc440_pcix_update_pim(s, 0);
+ break;
+ case PCIX0_PIM0LAL:
+ s->pim[0].la &= 0xffffffff00000000ULL;
+ s->pim[0].la |= val;
+ ppc440_pcix_update_pim(s, 0);
+ break;
+ case PCIX0_PIM0LAH:
+ s->pim[0].la &= 0xffffffffULL;
+ s->pim[0].la |= val << 32;
+ ppc440_pcix_update_pim(s, 0);
+ break;
+ case PCIX0_PIM1SA:
+ s->pim[1].sa = val;
+ ppc440_pcix_update_pim(s, 1);
+ break;
+ case PCIX0_PIM1LAL:
+ s->pim[1].la &= 0xffffffff00000000ULL;
+ s->pim[1].la |= val;
+ ppc440_pcix_update_pim(s, 1);
+ break;
+ case PCIX0_PIM1LAH:
+ s->pim[1].la &= 0xffffffffULL;
+ s->pim[1].la |= val << 32;
+ ppc440_pcix_update_pim(s, 1);
+ break;
+ case PCIX0_PIM2SAL:
+ s->pim[2].sa &= 0xffffffff00000000ULL;
+ s->pim[2].sa = val;
+ ppc440_pcix_update_pim(s, 2);
+ break;
+ case PCIX0_PIM2LAL:
+ s->pim[2].la &= 0xffffffff00000000ULL;
+ s->pim[2].la |= val;
+ ppc440_pcix_update_pim(s, 2);
+ break;
+ case PCIX0_PIM2LAH:
+ s->pim[2].la &= 0xffffffffULL;
+ s->pim[2].la |= val << 32;
+ ppc440_pcix_update_pim(s, 2);
+ break;
+
+ case PCIX0_STS:
+ s->sts = val;
+ break;
+
+ case PCIX0_PIM0SAH:
+ s->pim[0].sa &= 0xffffffffULL;
+ s->pim[0].sa |= val << 32;
+ ppc440_pcix_update_pim(s, 0);
+ break;
+ case PCIX0_PIM2SAH:
+ s->pim[2].sa &= 0xffffffffULL;
+ s->pim[2].sa |= val << 32;
+ ppc440_pcix_update_pim(s, 2);
+ break;
+
+ default:
+ error_report("%s: unhandled PCI internal register 0x%lx", __func__,
+ (unsigned long)addr);
+ break;
+ }
+}
+
+static uint64_t ppc440_pcix_reg_read4(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ struct PPC440PCIXState *s = opaque;
+ uint32_t val;
+
+ switch (addr) {
+ case PCI_VENDOR_ID ... PCI_MAX_LAT:
+ val = ldl_le_p(s->dev->config + addr);
+ break;
+
+ case PCIX0_POM0LAL:
+ val = s->pom[0].la;
+ break;
+ case PCIX0_POM0LAH:
+ val = s->pom[0].la >> 32;
+ break;
+ case PCIX0_POM0SA:
+ val = s->pom[0].sa;
+ break;
+ case PCIX0_POM0PCIAL:
+ val = s->pom[0].pcia;
+ break;
+ case PCIX0_POM0PCIAH:
+ val = s->pom[0].pcia >> 32;
+ break;
+ case PCIX0_POM1LAL:
+ val = s->pom[1].la;
+ break;
+ case PCIX0_POM1LAH:
+ val = s->pom[1].la >> 32;
+ break;
+ case PCIX0_POM1SA:
+ val = s->pom[1].sa;
+ break;
+ case PCIX0_POM1PCIAL:
+ val = s->pom[1].pcia;
+ break;
+ case PCIX0_POM1PCIAH:
+ val = s->pom[1].pcia >> 32;
+ break;
+ case PCIX0_POM2SA:
+ val = s->pom[2].sa;
+ break;
+
+ case PCIX0_PIM0SAL:
+ val = s->pim[0].sa;
+ break;
+ case PCIX0_PIM0LAL:
+ val = s->pim[0].la;
+ break;
+ case PCIX0_PIM0LAH:
+ val = s->pim[0].la >> 32;
+ break;
+ case PCIX0_PIM1SA:
+ val = s->pim[1].sa;
+ break;
+ case PCIX0_PIM1LAL:
+ val = s->pim[1].la;
+ break;
+ case PCIX0_PIM1LAH:
+ val = s->pim[1].la >> 32;
+ break;
+ case PCIX0_PIM2SAL:
+ val = s->pim[2].sa;
+ break;
+ case PCIX0_PIM2LAL:
+ val = s->pim[2].la;
+ break;
+ case PCIX0_PIM2LAH:
+ val = s->pim[2].la >> 32;
+ break;
+
+ case PCIX0_STS:
+ val = s->sts;
+ break;
+
+ case PCIX0_PIM0SAH:
+ val = s->pim[0].sa >> 32;
+ break;
+ case PCIX0_PIM2SAH:
+ val = s->pim[2].sa >> 32;
+ break;
+
+ default:
+ error_report("%s: invalid PCI internal register 0x%lx", __func__,
+ (unsigned long)addr);
+ val = 0;
+ }
+
+ trace_ppc440_pcix_reg_read(addr, val);
+ return val;
+}
+
+static const MemoryRegionOps pci_reg_ops = {
+ .read = ppc440_pcix_reg_read4,
+ .write = ppc440_pcix_reg_write4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ppc440_pcix_reset(DeviceState *dev)
+{
+ struct PPC440PCIXState *s = PPC440_PCIX_HOST_BRIDGE(dev);
+ int i;
+
+ for (i = 0; i < PPC440_PCIX_NR_POMS; i++) {
+ ppc440_pcix_clear_region(get_system_memory(), &s->pom[i].mr);
+ }
+ for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) {
+ ppc440_pcix_clear_region(&s->bm, &s->pim[i].mr);
+ }
+ memset(s->pom, 0, sizeof(s->pom));
+ memset(s->pim, 0, sizeof(s->pim));
+ for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) {
+ s->pim[i].sa = 0xffffffff00000000ULL;
+ }
+ s->sts = 0;
+}
+
+/* All pins from each slot are tied to a single board IRQ.
+ * This may need further refactoring for other boards. */
+static int ppc440_pcix_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+ int slot = pci_dev->devfn >> 3;
+ trace_ppc440_pcix_map_irq(pci_dev->devfn, irq_num, slot);
+ return slot - 1;
+}
+
+static void ppc440_pcix_set_irq(void *opaque, int irq_num, int level)
+{
+ qemu_irq *pci_irqs = opaque;
+
+ trace_ppc440_pcix_set_irq(irq_num);
+ if (irq_num < 0) {
+ error_report("%s: PCI irq %d", __func__, irq_num);
+ return;
+ }
+ qemu_set_irq(pci_irqs[irq_num], level);
+}
+
+static AddressSpace *ppc440_pcix_set_iommu(PCIBus *b, void *opaque, int devfn)
+{
+ PPC440PCIXState *s = opaque;
+
+ return &s->bm_as;
+}
+
+/* The default pci_host_data_{read,write} functions in pci/pci_host.c
+ * deny access to registers without bit 31 set but our clients want
+ * this to work so we have to override these here */
+static void pci_host_data_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned len)
+{
+ PCIHostState *s = opaque;
+ pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
+}
+
+static uint64_t pci_host_data_read(void *opaque,
+ hwaddr addr, unsigned len)
+{
+ PCIHostState *s = opaque;
+ uint32_t val;
+ val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
+ return val;
+}
+
+const MemoryRegionOps ppc440_pcix_host_data_ops = {
+ .read = pci_host_data_read,
+ .write = pci_host_data_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int ppc440_pcix_initfn(SysBusDevice *dev)
+{
+ PPC440PCIXState *s;
+ PCIHostState *h;
+ int i;
+
+ h = PCI_HOST_BRIDGE(dev);
+ s = PPC440_PCIX_HOST_BRIDGE(dev);
+
+ for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
+ sysbus_init_irq(dev, &s->irq[i]);
+ }
+
+ memory_region_init(&s->busmem, OBJECT(dev), "pci bus memory", UINT64_MAX);
+ h->bus = pci_register_root_bus(DEVICE(dev), NULL, ppc440_pcix_set_irq,
+ ppc440_pcix_map_irq, s->irq, &s->busmem,
+ get_system_io(), PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS);
+
+ s->dev = pci_create_simple(h->bus, PCI_DEVFN(0, 0), "ppc4xx-host-bridge");
+
+ memory_region_init(&s->bm, OBJECT(s), "bm-ppc440-pcix", UINT64_MAX);
+ memory_region_add_subregion(&s->bm, 0x0, &s->busmem);
+ address_space_init(&s->bm_as, &s->bm, "pci-bm");
+ pci_setup_iommu(h->bus, ppc440_pcix_set_iommu, s);
+
+ memory_region_init(&s->container, OBJECT(s), "pci-container", PCI_ALL_SIZE);
+ memory_region_init_io(&h->conf_mem, OBJECT(s), &pci_host_conf_le_ops,
+ h, "pci-conf-idx", 4);
+ memory_region_init_io(&h->data_mem, OBJECT(s), &ppc440_pcix_host_data_ops,
+ h, "pci-conf-data", 4);
+ memory_region_init_io(&s->iomem, OBJECT(s), &pci_reg_ops, s,
+ "pci.reg", PPC440_REG_SIZE);
+ memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem);
+ memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem);
+ memory_region_add_subregion(&s->container, PPC440_REG_BASE, &s->iomem);
+ sysbus_init_mmio(dev, &s->container);
+
+ return 0;
+}
+
+static void ppc440_pcix_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = ppc440_pcix_initfn;
+ dc->reset = ppc440_pcix_reset;
+}
+
+static const TypeInfo ppc440_pcix_info = {
+ .name = TYPE_PPC440_PCIX_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
+ .instance_size = sizeof(PPC440PCIXState),
+ .class_init = ppc440_pcix_class_init,
+};
+
+static void ppc440_pcix_register_types(void)
+{
+ type_register_static(&ppc440_pcix_info);
+}
+
+type_init(ppc440_pcix_register_types)
diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c
index 4e2523a64f..976ab2b5d8 100644
--- a/hw/ppc/ppc440_uc.c
+++ b/hw/ppc/ppc440_uc.c
@@ -1050,6 +1050,9 @@ static void ppc460ex_pcie_realize(DeviceState *dev, Error **errp)
case DCRN_PCIE1_BASE:
id = 1;
break;
+ default:
+ error_setg(errp, "invalid PCIe DCRN base");
+ return;
}
snprintf(buf, sizeof(buf), "pcie%d-io", id);
memory_region_init(&s->iomem, OBJECT(s), buf, UINT64_MAX);
diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
new file mode 100644
index 0000000000..70b8e76d9c
--- /dev/null
+++ b/hw/ppc/sam460ex.c
@@ -0,0 +1,603 @@
+/*
+ * QEMU aCube Sam460ex board emulation
+ *
+ * Copyright (c) 2012 François Revol
+ * Copyright (c) 2016-2018 BALATON Zoltan
+ *
+ * This file is derived from hw/ppc440_bamboo.c,
+ * the copyright for that material belongs to the original owners.
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/cutils.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "sysemu/blockdev.h"
+#include "hw/boards.h"
+#include "sysemu/kvm.h"
+#include "kvm_ppc.h"
+#include "sysemu/device_tree.h"
+#include "sysemu/block-backend.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "exec/address-spaces.h"
+#include "exec/memory.h"
+#include "hw/ppc/ppc440.h"
+#include "hw/ppc/ppc405.h"
+#include "hw/block/flash.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/qtest.h"
+#include "hw/sysbus.h"
+#include "hw/char/serial.h"
+#include "hw/i2c/ppc4xx_i2c.h"
+#include "hw/i2c/smbus.h"
+#include "hw/usb/hcd-ehci.h"
+
+#define BINARY_DEVICE_TREE_FILE "canyonlands.dtb"
+#define UBOOT_FILENAME "u-boot-sam460-20100605.bin"
+/* to extract the official U-Boot bin from the updater: */
+/* dd bs=1 skip=$(($(stat -c '%s' updater/updater-460) - 0x80000)) \
+ if=updater/updater-460 of=u-boot-sam460-20100605.bin */
+
+/* from Sam460 U-Boot include/configs/Sam460ex.h */
+#define FLASH_BASE 0xfff00000
+#define FLASH_BASE_H 0x4
+#define FLASH_SIZE (1 << 20)
+#define UBOOT_LOAD_BASE 0xfff80000
+#define UBOOT_SIZE 0x00080000
+#define UBOOT_ENTRY 0xfffffffc
+
+/* from U-Boot */
+#define EPAPR_MAGIC (0x45504150)
+#define KERNEL_ADDR 0x1000000
+#define FDT_ADDR 0x1800000
+#define RAMDISK_ADDR 0x1900000
+
+/* Sam460ex IRQ MAP:
+ IRQ0 = ETH_INT
+ IRQ1 = FPGA_INT
+ IRQ2 = PCI_INT (PCIA, PCIB, PCIC, PCIB)
+ IRQ3 = FPGA_INT2
+ IRQ11 = RTC_INT
+ IRQ12 = SM502_INT
+*/
+
+#define SDRAM_NR_BANKS 4
+
+/* FIXME: See u-boot.git 8ac41e, also fix in ppc440_uc.c */
+static const unsigned int ppc460ex_sdram_bank_sizes[] = {
+ 1024 << 20, 512 << 20, 256 << 20, 128 << 20, 64 << 20, 32 << 20, 0
+};
+
+struct boot_info {
+ uint32_t dt_base;
+ uint32_t dt_size;
+ uint32_t entry;
+};
+
+/*****************************************************************************/
+/* SPD eeprom content from mips_malta.c */
+
+struct _eeprom24c0x_t {
+ uint8_t tick;
+ uint8_t address;
+ uint8_t command;
+ uint8_t ack;
+ uint8_t scl;
+ uint8_t sda;
+ uint8_t data;
+ uint8_t contents[256];
+};
+
+typedef struct _eeprom24c0x_t eeprom24c0x_t;
+
+static eeprom24c0x_t spd_eeprom = {
+ .contents = {
+ /* 00000000: */ 0x80, 0x08, 0xFF, 0x0D, 0x0A, 0xFF, 0x40, 0x00,
+ /* 00000008: */ 0x04, 0x75, 0x54, 0x00, 0x82, 0x08, 0x00, 0x01,
+ /* 00000010: */ 0x8F, 0x04, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
+ /* 00000018: */ 0x00, 0x00, 0x00, 0x14, 0x0F, 0x14, 0x2D, 0xFF,
+ /* 00000020: */ 0x15, 0x08, 0x15, 0x08, 0x00, 0x00, 0x00, 0x00,
+ /* 00000028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xD0,
+ /* 00000040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 00000078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xF4,
+ },
+};
+
+static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size)
+{
+ enum { SDR = 0x4, DDR1 = 0x7, DDR2 = 0x8 } type;
+ uint8_t *spd = spd_eeprom.contents;
+ uint8_t nbanks = 0;
+ uint16_t density = 0;
+ int i;
+
+ /* work in terms of MB */
+ ram_size >>= 20;
+
+ while ((ram_size >= 4) && (nbanks <= 2)) {
+ int sz_log2 = MIN(31 - clz32(ram_size), 14);
+ nbanks++;
+ density |= 1 << (sz_log2 - 2);
+ ram_size -= 1 << sz_log2;
+ }
+
+ /* split to 2 banks if possible */
+ if ((nbanks == 1) && (density > 1)) {
+ nbanks++;
+ density >>= 1;
+ }
+
+ if (density & 0xff00) {
+ density = (density & 0xe0) | ((density >> 8) & 0x1f);
+ type = DDR2;
+ } else if (!(density & 0x1f)) {
+ type = DDR2;
+ } else {
+ type = SDR;
+ }
+
+ if (ram_size) {
+ warn_report("SPD cannot represent final " RAM_ADDR_FMT "MB"
+ " of SDRAM", ram_size);
+ }
+
+ /* fill in SPD memory information */
+ spd[2] = type;
+ spd[5] = nbanks;
+ spd[31] = density;
+
+ /* XXX: this is totally random */
+ spd[9] = 0x10; /* CAS tcyc */
+ spd[18] = 0x20; /* CAS bit */
+ spd[23] = 0x10; /* CAS tcyc */
+ spd[25] = 0x10; /* CAS tcyc */
+
+ /* checksum */
+ spd[63] = 0;
+ for (i = 0; i < 63; i++) {
+ spd[63] += spd[i];
+ }
+
+ /* copy for SMBUS */
+ memcpy(eeprom, spd, sizeof(spd_eeprom.contents));
+}
+
+static void generate_eeprom_serial(uint8_t *eeprom)
+{
+ int i, pos = 0;
+ uint8_t mac[6] = { 0x00 };
+ uint8_t sn[5] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
+
+ /* version */
+ eeprom[pos++] = 0x01;
+
+ /* count */
+ eeprom[pos++] = 0x02;
+
+ /* MAC address */
+ eeprom[pos++] = 0x01; /* MAC */
+ eeprom[pos++] = 0x06; /* length */
+ memcpy(&eeprom[pos], mac, sizeof(mac));
+ pos += sizeof(mac);
+
+ /* serial number */
+ eeprom[pos++] = 0x02; /* serial */
+ eeprom[pos++] = 0x05; /* length */
+ memcpy(&eeprom[pos], sn, sizeof(sn));
+ pos += sizeof(sn);
+
+ /* checksum */
+ eeprom[pos] = 0;
+ for (i = 0; i < pos; i++) {
+ eeprom[pos] += eeprom[i];
+ }
+}
+
+/*****************************************************************************/
+
+static int sam460ex_load_uboot(void)
+{
+ DriveInfo *dinfo;
+ BlockBackend *blk = NULL;
+ hwaddr base = FLASH_BASE | ((hwaddr)FLASH_BASE_H << 32);
+ long bios_size = FLASH_SIZE;
+ int fl_sectors;
+
+ dinfo = drive_get(IF_PFLASH, 0, 0);
+ if (dinfo) {
+ blk = blk_by_legacy_dinfo(dinfo);
+ bios_size = blk_getlength(blk);
+ }
+ fl_sectors = (bios_size + 65535) >> 16;
+
+ if (!pflash_cfi01_register(base, NULL, "sam460ex.flash", bios_size,
+ blk, (64 * 1024), fl_sectors,
+ 1, 0x89, 0x18, 0x0000, 0x0, 1)) {
+ error_report("qemu: Error registering flash memory.");
+ /* XXX: return an error instead? */
+ exit(1);
+ }
+
+ if (!blk) {
+ /*error_report("No flash image given with the 'pflash' parameter,"
+ " using default u-boot image");*/
+ base = UBOOT_LOAD_BASE | ((hwaddr)FLASH_BASE_H << 32);
+ rom_add_file_fixed(UBOOT_FILENAME, base, -1);
+ }
+
+ return 0;
+}
+
+static int sam460ex_load_device_tree(hwaddr addr,
+ uint32_t ramsize,
+ hwaddr initrd_base,
+ hwaddr initrd_size,
+ const char *kernel_cmdline)
+{
+ int ret = -1;
+ uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) };
+ char *filename;
+ int fdt_size;
+ void *fdt;
+ uint32_t tb_freq = 50000000;
+ uint32_t clock_freq = 50000000;
+
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+ if (!filename) {
+ goto out;
+ }
+ fdt = load_device_tree(filename, &fdt_size);
+ g_free(filename);
+ if (fdt == NULL) {
+ goto out;
+ }
+
+ /* Manipulate device tree in memory. */
+
+ ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
+ sizeof(mem_reg_property));
+ if (ret < 0) {
+ error_report("couldn't set /memory/reg");
+ }
+
+ /* default FDT doesn't have a /chosen node... */
+ qemu_fdt_add_subnode(fdt, "/chosen");
+
+ ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+ initrd_base);
+ if (ret < 0) {
+ error_report("couldn't set /chosen/linux,initrd-start");
+ }
+
+ ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+ (initrd_base + initrd_size));
+ if (ret < 0) {
+ error_report("couldn't set /chosen/linux,initrd-end");
+ }
+
+ ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
+ kernel_cmdline);
+ if (ret < 0) {
+ error_report("couldn't set /chosen/bootargs");
+ }
+
+ /* Copy data from the host device tree into the guest. Since the guest can
+ * directly access the timebase without host involvement, we must expose
+ * the correct frequencies. */
+ if (kvm_enabled()) {
+ tb_freq = kvmppc_get_tbfreq();
+ clock_freq = kvmppc_get_clockfreq();
+ }
+
+ qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
+ clock_freq);
+ qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
+ tb_freq);
+
+ rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
+ g_free(fdt);
+ ret = fdt_size;
+
+out:
+
+ return ret;
+}
+
+/* Create reset TLB entries for BookE, mapping only the flash memory. */
+static void mmubooke_create_initial_mapping_uboot(CPUPPCState *env)
+{
+ ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
+
+ /* on reset the flash is mapped by a shadow TLB,
+ * but since we don't implement them we need to use
+ * the same values U-Boot will use to avoid a fault.
+ */
+ tlb->attr = 0;
+ tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+ tlb->size = 0x10000000; /* up to 0xffffffff */
+ tlb->EPN = 0xf0000000 & TARGET_PAGE_MASK;
+ tlb->RPN = (0xf0000000 & TARGET_PAGE_MASK) | 0x4;
+ tlb->PID = 0;
+}
+
+/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
+static void mmubooke_create_initial_mapping(CPUPPCState *env,
+ target_ulong va,
+ hwaddr pa)
+{
+ ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
+
+ tlb->attr = 0;
+ tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+ tlb->size = 1 << 31; /* up to 0x80000000 */
+ tlb->EPN = va & TARGET_PAGE_MASK;
+ tlb->RPN = pa & TARGET_PAGE_MASK;
+ tlb->PID = 0;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+ PowerPCCPU *cpu = opaque;
+ CPUPPCState *env = &cpu->env;
+ struct boot_info *bi = env->load_info;
+
+ cpu_reset(CPU(cpu));
+
+ /* either we have a kernel to boot or we jump to U-Boot */
+ if (bi->entry != UBOOT_ENTRY) {
+ env->gpr[1] = (16 << 20) - 8;
+ env->gpr[3] = FDT_ADDR;
+ env->nip = bi->entry;
+
+ /* Create a mapping for the kernel. */
+ mmubooke_create_initial_mapping(env, 0, 0);
+ env->gpr[6] = tswap32(EPAPR_MAGIC);
+ env->gpr[7] = (16 << 20) - 8; /*bi->ima_size;*/
+
+ } else {
+ env->nip = UBOOT_ENTRY;
+ mmubooke_create_initial_mapping_uboot(env);
+ }
+}
+
+static void sam460ex_init(MachineState *machine)
+{
+ MemoryRegion *address_space_mem = get_system_memory();
+ MemoryRegion *isa = g_new(MemoryRegion, 1);
+ MemoryRegion *ram_memories = g_new(MemoryRegion, SDRAM_NR_BANKS);
+ hwaddr ram_bases[SDRAM_NR_BANKS];
+ hwaddr ram_sizes[SDRAM_NR_BANKS];
+ MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
+ qemu_irq *irqs, *uic[4];
+ PCIBus *pci_bus;
+ PowerPCCPU *cpu;
+ CPUPPCState *env;
+ PPC4xxI2CState *i2c[2];
+ hwaddr entry = UBOOT_ENTRY;
+ hwaddr loadaddr = 0;
+ target_long initrd_size = 0;
+ DeviceState *dev;
+ SysBusDevice *sbdev;
+ int success;
+ int i;
+ struct boot_info *boot_info;
+ const size_t smbus_eeprom_size = 8 * 256;
+ uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size);
+
+ cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
+ env = &cpu->env;
+ if (env->mmu_model != POWERPC_MMU_BOOKE) {
+ error_report("Only MMU model BookE is supported by this machine.");
+ exit(1);
+ }
+
+#ifdef TARGET_PPCEMB
+ if (!qtest_enabled()) {
+ warn_report("qemu-system-ppcemb is deprecated, "
+ "please use qemu-system-ppc instead.");
+ }
+#endif
+
+ qemu_register_reset(main_cpu_reset, cpu);
+ boot_info = g_malloc0(sizeof(*boot_info));
+ env->load_info = boot_info;
+
+ ppc_booke_timers_init(cpu, 50000000, 0);
+ ppc_dcr_init(env, NULL, NULL);
+
+ /* PLB arbitrer */
+ ppc4xx_plb_init(env);
+
+ /* interrupt controllers */
+ irqs = g_malloc0(sizeof(*irqs) * PPCUIC_OUTPUT_NB);
+ irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+ irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+ uic[0] = ppcuic_init(env, irqs, 0xc0, 0, 1);
+ uic[1] = ppcuic_init(env, &uic[0][30], 0xd0, 0, 1);
+ uic[2] = ppcuic_init(env, &uic[0][10], 0xe0, 0, 1);
+ uic[3] = ppcuic_init(env, &uic[0][16], 0xf0, 0, 1);
+
+ /* SDRAM controller */
+ memset(ram_bases, 0, sizeof(ram_bases));
+ memset(ram_sizes, 0, sizeof(ram_sizes));
+ /* put all RAM on first bank because board has one slot
+ * and firmware only checks that */
+ machine->ram_size = ppc4xx_sdram_adjust(machine->ram_size, 1,
+ ram_memories, ram_bases, ram_sizes,
+ ppc460ex_sdram_bank_sizes);
+
+ /* FIXME: does 460EX have ECC interrupts? */
+ ppc440_sdram_init(env, SDRAM_NR_BANKS, ram_memories,
+ ram_bases, ram_sizes, 1);
+
+ /* generate SPD EEPROM data */
+ for (i = 0; i < SDRAM_NR_BANKS; i++) {
+ generate_eeprom_spd(&smbus_eeprom_buf[i * 256], ram_sizes[i]);
+ }
+ generate_eeprom_serial(&smbus_eeprom_buf[4 * 256]);
+ generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]);
+
+ /* IIC controllers */
+ dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, uic[0][2]);
+ i2c[0] = PPC4xx_I2C(dev);
+ object_property_set_bool(OBJECT(dev), true, "realized", NULL);
+ smbus_eeprom_init(i2c[0]->bus, 8, smbus_eeprom_buf, smbus_eeprom_size);
+ g_free(smbus_eeprom_buf);
+
+ dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800, uic[0][3]);
+ i2c[1] = PPC4xx_I2C(dev);
+
+ /* External bus controller */
+ ppc405_ebc_init(env);
+
+ /* CPR */
+ ppc4xx_cpr_init(env);
+
+ /* PLB to AHB bridge */
+ ppc4xx_ahb_init(env);
+
+ /* System DCRs */
+ ppc4xx_sdr_init(env);
+
+ /* MAL */
+ ppc4xx_mal_init(env, 4, 16, &uic[2][3]);
+
+ /* 256K of L2 cache as memory */
+ ppc4xx_l2sram_init(env);
+ /* FIXME: remove this after fixing l2sram mapping in ppc440_uc.c? */
+ memory_region_init_ram(l2cache_ram, NULL, "ppc440.l2cache_ram", 256 << 10,
+ &error_abort);
+ memory_region_add_subregion(address_space_mem, 0x400000000LL, l2cache_ram);
+
+ /* USB */
+ sysbus_create_simple(TYPE_PPC4xx_EHCI, 0x4bffd0400, uic[2][29]);
+ dev = qdev_create(NULL, "sysbus-ohci");
+ qdev_prop_set_string(dev, "masterbus", "usb-bus.0");
+ qdev_prop_set_uint32(dev, "num-ports", 6);
+ qdev_init_nofail(dev);
+ sbdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(sbdev, 0, 0x4bffd0000);
+ sysbus_connect_irq(sbdev, 0, uic[2][30]);
+ usb_create_simple(usb_bus_find(-1), "usb-kbd");
+ usb_create_simple(usb_bus_find(-1), "usb-mouse");
+
+ /* PCI bus */
+ ppc460ex_pcie_init(env);
+ /* FIXME: is this correct? */
+ dev = sysbus_create_varargs("ppc440-pcix-host", 0xc0ec00000,
+ uic[1][0], uic[1][20], uic[1][21], uic[1][22],
+ NULL);
+ pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
+ if (!pci_bus) {
+ error_report("couldn't create PCI controller!");
+ exit(1);
+ }
+ memory_region_init_alias(isa, NULL, "isa_mmio", get_system_io(),
+ 0, 0x10000);
+ memory_region_add_subregion(get_system_memory(), 0xc08000000, isa);
+
+ /* PCI devices */
+ pci_create_simple(pci_bus, PCI_DEVFN(6, 0), "sm501");
+ /* SoC has a single SATA port but we don't emulate that yet
+ * However, firmware and usual clients have driver for SiI311x
+ * so add one for convenience by default */
+ if (defaults_enabled()) {
+ pci_create_simple(pci_bus, -1, "sii3112");
+ }
+
+ /* SoC has 4 UARTs
+ * but board has only one wired and two are present in fdt */
+ if (serial_hds[0] != NULL) {
+ serial_mm_init(address_space_mem, 0x4ef600300, 0, uic[1][1],
+ PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+ DEVICE_BIG_ENDIAN);
+ }
+ if (serial_hds[1] != NULL) {
+ serial_mm_init(address_space_mem, 0x4ef600400, 0, uic[0][1],
+ PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+ DEVICE_BIG_ENDIAN);
+ }
+
+ /* Load U-Boot image. */
+ if (!machine->kernel_filename) {
+ success = sam460ex_load_uboot();
+ if (success < 0) {
+ error_report("qemu: could not load firmware");
+ exit(1);
+ }
+ }
+
+ /* Load kernel. */
+ if (machine->kernel_filename) {
+ success = load_uimage(machine->kernel_filename, &entry, &loadaddr,
+ NULL, NULL, NULL);
+ if (success < 0) {
+ uint64_t elf_entry, elf_lowaddr;
+
+ success = load_elf(machine->kernel_filename, NULL, NULL, &elf_entry,
+ &elf_lowaddr, NULL, 1, PPC_ELF_MACHINE, 0, 0);
+ entry = elf_entry;
+ loadaddr = elf_lowaddr;
+ }
+ /* XXX try again as binary */
+ if (success < 0) {
+ error_report("qemu: could not load kernel '%s'",
+ machine->kernel_filename);
+ exit(1);
+ }
+ }
+
+ /* Load initrd. */
+ if (machine->initrd_filename) {
+ initrd_size = load_image_targphys(machine->initrd_filename,
+ RAMDISK_ADDR,
+ machine->ram_size - RAMDISK_ADDR);
+ if (initrd_size < 0) {
+ error_report("qemu: could not load ram disk '%s' at %x",
+ machine->initrd_filename, RAMDISK_ADDR);
+ exit(1);
+ }
+ }
+
+ /* If we're loading a kernel directly, we must load the device tree too. */
+ if (machine->kernel_filename) {
+ int dt_size;
+
+ dt_size = sam460ex_load_device_tree(FDT_ADDR, machine->ram_size,
+ RAMDISK_ADDR, initrd_size,
+ machine->kernel_cmdline);
+ if (dt_size < 0) {
+ error_report("couldn't load device tree");
+ exit(1);
+ }
+
+ boot_info->dt_base = FDT_ADDR;
+ boot_info->dt_size = dt_size;
+ }
+
+ boot_info->entry = entry;
+}
+
+static void sam460ex_machine_init(MachineClass *mc)
+{
+ mc->desc = "aCube Sam460ex";
+ mc->init = sam460ex_init;
+ mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("460exb");
+ mc->default_ram_size = 512 * M_BYTE;
+}
+
+DEFINE_MACHINE("sam460ex", sam460ex_machine_init)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 83c9d66dd5..7e1c858566 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -105,12 +105,14 @@
*/
static int spapr_vcpu_id(sPAPRMachineState *spapr, int cpu_index)
{
+ assert(spapr->vsmt);
return
(cpu_index / smp_threads) * spapr->vsmt + cpu_index % smp_threads;
}
static bool spapr_is_thread0_in_vcore(sPAPRMachineState *spapr,
PowerPCCPU *cpu)
{
+ assert(spapr->vsmt);
return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
}
@@ -177,13 +179,13 @@ static void pre_2_10_vmstate_unregister_dummy_icp(int i)
static int xics_max_server_number(sPAPRMachineState *spapr)
{
+ assert(spapr->vsmt);
return DIV_ROUND_UP(max_cpus * spapr->vsmt, smp_threads);
}
static void xics_system_init(MachineState *machine, int nr_irqs, Error **errp)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
if (kvm_enabled()) {
if (machine_kernel_irqchip_allowed(machine) &&
@@ -205,17 +207,6 @@ static void xics_system_init(MachineState *machine, int nr_irqs, Error **errp)
return;
}
}
-
- if (smc->pre_2_10_has_unused_icps) {
- int i;
-
- for (i = 0; i < xics_max_server_number(spapr); i++) {
- /* Dummy entries get deregistered when real ICPState objects
- * are registered during CPU core hotplug.
- */
- pre_2_10_vmstate_register_dummy_icp(i);
- }
- }
}
static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
@@ -1062,7 +1053,14 @@ static void spapr_dt_chosen(sPAPRMachineState *spapr, void *fdt)
}
if (!spapr->has_graphics && stdout_path) {
+ /*
+ * "linux,stdout-path" and "stdout" properties are deprecated by linux
+ * kernel. New platforms should only use the "stdout-path" property. Set
+ * the new property and continue using older property to remain
+ * compatible with the existing firmware.
+ */
_FDT(fdt_setprop_string(fdt, chosen, "linux,stdout-path", stdout_path));
+ _FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
}
spapr_dt_ov5_platform_support(fdt, chosen);
@@ -2232,61 +2230,6 @@ static CPUArchId *spapr_find_cpu_slot(MachineState *ms, uint32_t id, int *idx)
return &ms->possible_cpus->cpus[index];
}
-static void spapr_init_cpus(sPAPRMachineState *spapr)
-{
- MachineState *machine = MACHINE(spapr);
- MachineClass *mc = MACHINE_GET_CLASS(machine);
- const char *type = spapr_get_cpu_core_type(machine->cpu_type);
- const CPUArchIdList *possible_cpus;
- int boot_cores_nr = smp_cpus / smp_threads;
- int i;
-
- possible_cpus = mc->possible_cpu_arch_ids(machine);
- if (mc->has_hotpluggable_cpus) {
- if (smp_cpus % smp_threads) {
- error_report("smp_cpus (%u) must be multiple of threads (%u)",
- smp_cpus, smp_threads);
- exit(1);
- }
- if (max_cpus % smp_threads) {
- error_report("max_cpus (%u) must be multiple of threads (%u)",
- max_cpus, smp_threads);
- exit(1);
- }
- } else {
- if (max_cpus != smp_cpus) {
- error_report("This machine version does not support CPU hotplug");
- exit(1);
- }
- boot_cores_nr = possible_cpus->len;
- }
-
- for (i = 0; i < possible_cpus->len; i++) {
- int core_id = i * smp_threads;
-
- if (mc->has_hotpluggable_cpus) {
- spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
- spapr_vcpu_id(spapr, core_id));
- }
-
- if (i < boot_cores_nr) {
- Object *core = object_new(type);
- int nr_threads = smp_threads;
-
- /* Handle the partially filled core for older machine types */
- if ((i + 1) * smp_threads >= smp_cpus) {
- nr_threads = smp_cpus - i * smp_threads;
- }
-
- object_property_set_int(core, nr_threads, "nr-threads",
- &error_fatal);
- object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
- &error_fatal);
- object_property_set_bool(core, true, "realized", &error_fatal);
- }
- }
-}
-
static void spapr_set_vsmt_mode(sPAPRMachineState *spapr, Error **errp)
{
Error *local_err = NULL;
@@ -2359,6 +2302,78 @@ out:
error_propagate(errp, local_err);
}
+static void spapr_init_cpus(sPAPRMachineState *spapr)
+{
+ MachineState *machine = MACHINE(spapr);
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
+ const char *type = spapr_get_cpu_core_type(machine->cpu_type);
+ const CPUArchIdList *possible_cpus;
+ int boot_cores_nr = smp_cpus / smp_threads;
+ int i;
+
+ possible_cpus = mc->possible_cpu_arch_ids(machine);
+ if (mc->has_hotpluggable_cpus) {
+ if (smp_cpus % smp_threads) {
+ error_report("smp_cpus (%u) must be multiple of threads (%u)",
+ smp_cpus, smp_threads);
+ exit(1);
+ }
+ if (max_cpus % smp_threads) {
+ error_report("max_cpus (%u) must be multiple of threads (%u)",
+ max_cpus, smp_threads);
+ exit(1);
+ }
+ } else {
+ if (max_cpus != smp_cpus) {
+ error_report("This machine version does not support CPU hotplug");
+ exit(1);
+ }
+ boot_cores_nr = possible_cpus->len;
+ }
+
+ /* VSMT must be set in order to be able to compute VCPU ids, ie to
+ * call xics_max_server_number() or spapr_vcpu_id().
+ */
+ spapr_set_vsmt_mode(spapr, &error_fatal);
+
+ if (smc->pre_2_10_has_unused_icps) {
+ int i;
+
+ for (i = 0; i < xics_max_server_number(spapr); i++) {
+ /* Dummy entries get deregistered when real ICPState objects
+ * are registered during CPU core hotplug.
+ */
+ pre_2_10_vmstate_register_dummy_icp(i);
+ }
+ }
+
+ for (i = 0; i < possible_cpus->len; i++) {
+ int core_id = i * smp_threads;
+
+ if (mc->has_hotpluggable_cpus) {
+ spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_CPU,
+ spapr_vcpu_id(spapr, core_id));
+ }
+
+ if (i < boot_cores_nr) {
+ Object *core = object_new(type);
+ int nr_threads = smp_threads;
+
+ /* Handle the partially filled core for older machine types */
+ if ((i + 1) * smp_threads >= smp_cpus) {
+ nr_threads = smp_cpus - i * smp_threads;
+ }
+
+ object_property_set_int(core, nr_threads, "nr-threads",
+ &error_fatal);
+ object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
+ &error_fatal);
+ object_property_set_bool(core, true, "realized", &error_fatal);
+ }
+ }
+}
+
/* pSeries LPAR / sPAPR hardware init */
static void spapr_machine_init(MachineState *machine)
{
@@ -2486,8 +2501,6 @@ static void spapr_machine_init(MachineState *machine)
}
/* init CPUs */
- spapr_set_vsmt_mode(spapr, &error_fatal);
-
spapr_init_cpus(spapr);
if (kvm_enabled()) {
@@ -3810,13 +3823,7 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj,
int spapr_get_vcpu_id(PowerPCCPU *cpu)
{
- CPUState *cs = CPU(cpu);
-
- if (kvm_enabled()) {
- return kvm_arch_vcpu_id(cs);
- } else {
- return cs->cpu_index;
- }
+ return cpu->vcpu_id;
}
void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp)
@@ -3983,6 +3990,23 @@ static void spapr_machine_2_12_class_options(MachineClass *mc)
DEFINE_SPAPR_MACHINE(2_12, "2.12", true);
+static void spapr_machine_2_12_sxxm_instance_options(MachineState *machine)
+{
+ spapr_machine_2_12_instance_options(machine);
+}
+
+static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
+{
+ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+
+ spapr_machine_2_12_class_options(mc);
+ smc->default_caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_WORKAROUND;
+ smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_WORKAROUND;
+ smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_FIXED_CCD;
+}
+
+DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
+
/*
* pseries-2.11
*/
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index 99a4b71d19..531e145114 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -32,6 +32,20 @@
#include "hw/ppc/spapr.h"
+typedef struct sPAPRCapPossible {
+ int num; /* size of vals array below */
+ const char *help; /* help text for vals */
+ /*
+ * Note:
+ * - because of the way compatibility is determined vals MUST be ordered
+ * such that later options are a superset of all preceding options.
+ * - the order of vals must be preserved, that is their index is important,
+ * however vals may be added to the end of the list so long as the above
+ * point is observed
+ */
+ const char *vals[];
+} sPAPRCapPossible;
+
typedef struct sPAPRCapabilityInfo {
const char *name;
const char *description;
@@ -41,6 +55,8 @@ typedef struct sPAPRCapabilityInfo {
ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set;
const char *type;
+ /* Possible values if this is a custom string type */
+ sPAPRCapPossible *possible;
/* Make sure the virtual hardware can support this capability */
void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp);
} sPAPRCapabilityInfo;
@@ -73,41 +89,34 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF;
}
-static void spapr_cap_get_tristate(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
+
+static void spapr_cap_get_string(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
{
sPAPRCapabilityInfo *cap = opaque;
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
char *val = NULL;
uint8_t value = spapr_get_cap(spapr, cap->index);
- switch (value) {
- case SPAPR_CAP_BROKEN:
- val = g_strdup("broken");
- break;
- case SPAPR_CAP_WORKAROUND:
- val = g_strdup("workaround");
- break;
- case SPAPR_CAP_FIXED:
- val = g_strdup("fixed");
- break;
- default:
+ if (value >= cap->possible->num) {
error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name);
return;
}
+ val = g_strdup(cap->possible->vals[value]);
+
visit_type_str(v, name, &val, errp);
g_free(val);
}
-static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
+static void spapr_cap_set_string(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
{
sPAPRCapabilityInfo *cap = opaque;
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
- char *val;
Error *local_err = NULL;
- uint8_t value;
+ uint8_t i;
+ char *val;
visit_type_str(v, name, &val, &local_err);
if (local_err) {
@@ -115,20 +124,20 @@ static void spapr_cap_set_tristate(Object *obj, Visitor *v, const char *name,
return;
}
- if (!strcasecmp(val, "broken")) {
- value = SPAPR_CAP_BROKEN;
- } else if (!strcasecmp(val, "workaround")) {
- value = SPAPR_CAP_WORKAROUND;
- } else if (!strcasecmp(val, "fixed")) {
- value = SPAPR_CAP_FIXED;
- } else {
- error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
- cap->name);
+ if (!strcmp(val, "?")) {
+ error_setg(errp, "%s", cap->possible->help);
goto out;
}
+ for (i = 0; i < cap->possible->num; i++) {
+ if (!strcasecmp(val, cap->possible->vals[i])) {
+ spapr->cmd_line_caps[cap->index] = true;
+ spapr->eff.caps[cap->index] = i;
+ goto out;
+ }
+ }
- spapr->cmd_line_caps[cap->index] = true;
- spapr->eff.caps[cap->index] = value;
+ error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val,
+ cap->name);
out:
g_free(val);
}
@@ -180,38 +189,77 @@ static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
}
}
+sPAPRCapPossible cap_cfpc_possible = {
+ .num = 3,
+ .vals = {"broken", "workaround", "fixed"},
+ .help = "broken - no protection, workaround - workaround available,"
+ " fixed - fixed in hardware",
+};
+
static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val,
Error **errp)
{
+ uint8_t kvm_val = kvmppc_get_cap_safe_cache();
+
if (tcg_enabled() && val) {
/* TODO - for now only allow broken for TCG */
- error_setg(errp, "Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc");
- } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_cache())) {
- error_setg(errp, "Requested safe cache capability level not supported by kvm, try a different value for cap-cfpc");
+ error_setg(errp,
+"Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc");
+ } else if (kvm_enabled() && (val > kvm_val)) {
+ error_setg(errp,
+"Requested safe cache capability level not supported by kvm, try cap-cfpc=%s",
+ cap_cfpc_possible.vals[kvm_val]);
}
}
+sPAPRCapPossible cap_sbbc_possible = {
+ .num = 3,
+ .vals = {"broken", "workaround", "fixed"},
+ .help = "broken - no protection, workaround - workaround available,"
+ " fixed - fixed in hardware",
+};
+
static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val,
Error **errp)
{
+ uint8_t kvm_val = kvmppc_get_cap_safe_bounds_check();
+
if (tcg_enabled() && val) {
/* TODO - for now only allow broken for TCG */
- error_setg(errp, "Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc");
- } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_bounds_check())) {
- error_setg(errp, "Requested safe bounds check capability level not supported by kvm, try a different value for cap-sbbc");
+ error_setg(errp,
+"Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc");
+ } else if (kvm_enabled() && (val > kvm_val)) {
+ error_setg(errp,
+"Requested safe bounds check capability level not supported by kvm, try cap-sbbc=%s",
+ cap_sbbc_possible.vals[kvm_val]);
}
}
+sPAPRCapPossible cap_ibs_possible = {
+ .num = 4,
+ /* Note workaround only maintained for compatibility */
+ .vals = {"broken", "workaround", "fixed-ibs", "fixed-ccd"},
+ .help = "broken - no protection, fixed-ibs - indirect branch serialisation,"
+ " fixed-ccd - cache count disabled",
+};
+
static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr,
uint8_t val, Error **errp)
{
+ uint8_t kvm_val = kvmppc_get_cap_safe_indirect_branch();
+
if (val == SPAPR_CAP_WORKAROUND) { /* Can only be Broken or Fixed */
- error_setg(errp, "Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=fixed");
+ error_setg(errp,
+"Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=%s",
+ cap_ibs_possible.vals[kvm_val]);
} else if (tcg_enabled() && val) {
/* TODO - for now only allow broken for TCG */
- error_setg(errp, "Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs");
- } else if (kvm_enabled() && (val > kvmppc_get_cap_safe_indirect_branch())) {
- error_setg(errp, "Requested safe indirect branch capability level not supported by kvm, try a different value for cap-ibs");
+ error_setg(errp,
+"Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs");
+ } else if (kvm_enabled() && val && (val != kvm_val)) {
+ error_setg(errp,
+"Requested safe indirect branch capability level not supported by kvm, try cap-ibs=%s",
+ cap_ibs_possible.vals[kvm_val]);
}
}
@@ -249,27 +297,31 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
.name = "cfpc",
.description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE,
.index = SPAPR_CAP_CFPC,
- .get = spapr_cap_get_tristate,
- .set = spapr_cap_set_tristate,
+ .get = spapr_cap_get_string,
+ .set = spapr_cap_set_string,
.type = "string",
+ .possible = &cap_cfpc_possible,
.apply = cap_safe_cache_apply,
},
[SPAPR_CAP_SBBC] = {
.name = "sbbc",
.description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE,
.index = SPAPR_CAP_SBBC,
- .get = spapr_cap_get_tristate,
- .set = spapr_cap_set_tristate,
+ .get = spapr_cap_get_string,
+ .set = spapr_cap_set_string,
.type = "string",
+ .possible = &cap_sbbc_possible,
.apply = cap_safe_bounds_check_apply,
},
[SPAPR_CAP_IBS] = {
.name = "ibs",
- .description = "Indirect Branch Serialisation (broken, fixed)",
+ .description =
+ "Indirect Branch Speculation (broken, fixed-ibs, fixed-ccd)",
.index = SPAPR_CAP_IBS,
- .get = spapr_cap_get_tristate,
- .set = spapr_cap_set_tristate,
+ .get = spapr_cap_get_string,
+ .set = spapr_cap_set_string,
.type = "string",
+ .possible = &cap_ibs_possible,
.apply = cap_safe_indirect_branch_apply,
},
};
@@ -283,15 +335,26 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
caps = smc->default_caps;
+ if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00,
+ 0, spapr->max_compat_pvr)) {
+ caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN;
+ }
+
if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07,
0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
}
+ if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06_PLUS,
+ 0, spapr->max_compat_pvr)) {
+ caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN;
+ }
+
if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06,
0, spapr->max_compat_pvr)) {
caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF;
caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF;
+ caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
}
return caps;
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 1986560480..16bccdd5c0 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1705,7 +1705,10 @@ static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu,
}
switch (safe_indirect_branch) {
- case SPAPR_CAP_FIXED:
+ case SPAPR_CAP_FIXED_CCD:
+ characteristics |= H_CPU_CHAR_CACHE_COUNT_DIS;
+ break;
+ case SPAPR_CAP_FIXED_IBS:
characteristics |= H_CPU_CHAR_BCCTRL_SERIALISED;
break;
default: /* broken */
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 4bb939d3d1..0ec5fa4cfe 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -38,7 +38,6 @@
#include "hw/ppc/spapr_vio.h"
#include "hw/ppc/spapr_rtas.h"
#include "hw/ppc/ppc.h"
-#include "qapi-event.h"
#include "hw/boards.h"
#include <libfdt.h>
diff --git a/hw/ppc/spapr_rtc.c b/hw/ppc/spapr_rtc.c
index cfdb274bfd..a37360537e 100644
--- a/hw/ppc/spapr_rtc.c
+++ b/hw/ppc/spapr_rtc.c
@@ -30,8 +30,8 @@
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "hw/ppc/spapr.h"
-#include "qapi-event.h"
#include "qapi/error.h"
+#include "qapi/qapi-events-misc.h"
#include "qemu/cutils.h"
void spapr_rtc_read(sPAPRRTCState *rtc, struct tm *tm, uint32_t *ns)
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index b7c3e64b5e..66ec7eda6e 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -99,3 +99,11 @@ mac99_uninorth_read(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"P
# hw/ppc/ppc4xx_pci.c
ppc4xx_pci_map_irq(int32_t devfn, int irq_num, int slot) "devfn 0x%x irq %d -> %d"
ppc4xx_pci_set_irq(int irq_num) "PCI irq %d"
+
+# hw/ppc/ppc440_pcix.c
+ppc440_pcix_map_irq(int32_t devfn, int irq_num, int slot) "devfn 0x%x irq %d -> %d"
+ppc440_pcix_set_irq(int irq_num) "PCI irq %d"
+ppc440_pcix_update_pim(int idx, uint64_t size, uint64_t la) "Added window %d of size=0x%" PRIx64 " to CPU=0x%" PRIx64
+ppc440_pcix_update_pom(int idx, uint32_t size, uint64_t la, uint64_t pcia) "Added window %d of size=0x%x from CPU=0x%" PRIx64 " to PCI=0x%" PRIx64
+ppc440_pcix_reg_read(uint64_t addr, uint32_t val) "addr 0x%" PRIx64 " = 0x%" PRIx32
+ppc440_pcix_reg_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " = 0x%" PRIx64
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 0d06fc12b6..798e99aadf 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -23,6 +23,9 @@
#include "hw/s390x/ebcdic.h"
#include "ipl.h"
#include "qemu/error-report.h"
+#include "qemu/config-file.h"
+#include "qemu/cutils.h"
+#include "qemu/option.h"
#define KERN_IMAGE_START 0x010000UL
#define KERN_PARM_AREA 0x010480UL
@@ -219,6 +222,61 @@ static Property s390_ipl_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static void s390_ipl_set_boot_menu(S390IPLState *ipl)
+{
+ QemuOptsList *plist = qemu_find_opts("boot-opts");
+ QemuOpts *opts = QTAILQ_FIRST(&plist->head);
+ uint8_t *flags = &ipl->qipl.qipl_flags;
+ uint32_t *timeout = &ipl->qipl.boot_menu_timeout;
+ const char *tmp;
+ unsigned long splash_time = 0;
+
+ if (!get_boot_device(0)) {
+ if (boot_menu) {
+ error_report("boot menu requires a bootindex to be specified for "
+ "the IPL device.");
+ }
+ return;
+ }
+
+ switch (ipl->iplb.pbt) {
+ case S390_IPL_TYPE_CCW:
+ /* In the absence of -boot menu, use zipl parameters */
+ if (!qemu_opt_get(opts, "menu")) {
+ *flags |= QIPL_FLAG_BM_OPTS_ZIPL;
+ return;
+ }
+ break;
+ case S390_IPL_TYPE_QEMU_SCSI:
+ break;
+ default:
+ error_report("boot menu is not supported for this device type.");
+ return;
+ }
+
+ if (!boot_menu) {
+ return;
+ }
+
+ *flags |= QIPL_FLAG_BM_OPTS_CMD;
+
+ tmp = qemu_opt_get(opts, "splash-time");
+
+ if (tmp && qemu_strtoul(tmp, NULL, 10, &splash_time)) {
+ error_report("splash-time is invalid, forcing it to 0.");
+ *timeout = 0;
+ return;
+ }
+
+ if (splash_time > 0xffffffff) {
+ error_report("splash-time is too large, forcing it to max value.");
+ *timeout = 0xffffffff;
+ return;
+ }
+
+ *timeout = cpu_to_be32(splash_time);
+}
+
static bool s390_gen_initial_iplb(S390IPLState *ipl)
{
DeviceState *dev_st;
@@ -399,6 +457,21 @@ void s390_reipl_request(void)
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
}
+static void s390_ipl_prepare_qipl(S390CPU *cpu)
+{
+ S390IPLState *ipl = get_ipl_device();
+ uint8_t *addr;
+ uint64_t len = 4096;
+
+ addr = cpu_physical_memory_map(cpu->env.psa, &len, 1);
+ if (!addr || len < QIPL_ADDRESS + sizeof(QemuIplParameters)) {
+ error_report("Cannot set QEMU IPL parameters");
+ return;
+ }
+ memcpy(addr + QIPL_ADDRESS, &ipl->qipl, sizeof(QemuIplParameters));
+ cpu_physical_memory_unmap(addr, len, 1, len);
+}
+
void s390_ipl_prepare_cpu(S390CPU *cpu)
{
S390IPLState *ipl = get_ipl_device();
@@ -418,8 +491,10 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
error_report_err(err);
vm_stop(RUN_STATE_INTERNAL_ERROR);
}
- ipl->iplb.ccw.netboot_start_addr = cpu_to_be64(ipl->start_addr);
+ ipl->qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
}
+ s390_ipl_set_boot_menu(ipl);
+ s390_ipl_prepare_qipl(cpu);
}
static void s390_ipl_reset(DeviceState *dev)
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 8a705e0428..0570d0ad75 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -16,8 +16,7 @@
#include "cpu.h"
struct IplBlockCcw {
- uint64_t netboot_start_addr;
- uint8_t reserved0[77];
+ uint8_t reserved0[85];
uint8_t ssid;
uint16_t devno;
uint8_t vm_flags;
@@ -90,6 +89,33 @@ void s390_ipl_prepare_cpu(S390CPU *cpu);
IplParameterBlock *s390_ipl_get_iplb(void);
void s390_reipl_request(void);
+#define QIPL_ADDRESS 0xcc
+
+/* Boot Menu flags */
+#define QIPL_FLAG_BM_OPTS_CMD 0x80
+#define QIPL_FLAG_BM_OPTS_ZIPL 0x40
+
+/*
+ * The QEMU IPL Parameters will be stored at absolute address
+ * 204 (0xcc) which means it is 32-bit word aligned but not
+ * double-word aligned.
+ * Placement of data fields in this area must account for
+ * their alignment needs. E.g., netboot_start_address must
+ * have an offset of 4 + n * 8 bytes within the struct in order
+ * to keep it double-word aligned.
+ * The total size of the struct must never exceed 28 bytes.
+ * This definition must be kept in sync with the defininition
+ * in pc-bios/s390-ccw/iplb.h.
+ */
+struct QemuIplParameters {
+ uint8_t qipl_flags;
+ uint8_t reserved1[3];
+ uint64_t netboot_start_addr;
+ uint32_t boot_menu_timeout;
+ uint8_t reserved2[12];
+} QEMU_PACKED;
+typedef struct QemuIplParameters QemuIplParameters;
+
#define TYPE_S390_IPL "s390-ipl"
#define S390_IPL(obj) OBJECT_CHECK(S390IPLState, (obj), TYPE_S390_IPL)
@@ -105,6 +131,7 @@ struct S390IPLState {
bool iplb_valid;
bool reipl_requested;
bool netboot;
+ QemuIplParameters qipl;
/*< public >*/
char *kernel;
diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c
index 7fc1c603c0..214c940593 100644
--- a/hw/s390x/s390-ccw.c
+++ b/hw/s390x/s390-ccw.c
@@ -48,7 +48,7 @@ static void s390_ccw_get_dev_info(S390CCWDevice *cdev,
return;
}
- cdev->mdevid = g_strdup(basename(dev_path));
+ cdev->mdevid = g_path_get_basename(dev_path);
tmp = basename(dirname(dev_path));
if (sscanf(tmp, "%2x.%1x.%4x", &cssid, &ssid, &devid) != 3) {
diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c
index bdb6c18a0f..76241c240e 100644
--- a/hw/s390x/s390-skeys.c
+++ b/hw/s390x/s390-skeys.c
@@ -11,9 +11,9 @@
#include "qemu/osdep.h"
#include "hw/boards.h"
-#include "qmp-commands.h"
#include "hw/s390x/storage-keys.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-misc.h"
#include "qapi/qmp/qdict.h"
#include "qemu/error-report.h"
#include "sysemu/kvm.h"
diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c
index a1d2135a60..adf07ef312 100644
--- a/hw/s390x/s390-stattrib.c
+++ b/hw/s390x/s390-stattrib.c
@@ -365,22 +365,22 @@ static inline void s390_stattrib_set_migration_enabled(Object *obj, bool value,
s->migration_enabled = value;
}
+static SaveVMHandlers savevm_s390_stattrib_handlers = {
+ .save_setup = cmma_save_setup,
+ .save_live_iterate = cmma_save_iterate,
+ .save_live_complete_precopy = cmma_save_complete,
+ .save_live_pending = cmma_save_pending,
+ .save_cleanup = cmma_save_cleanup,
+ .load_state = cmma_load,
+ .is_active = cmma_active,
+};
+
static void s390_stattrib_instance_init(Object *obj)
{
S390StAttribState *sas = S390_STATTRIB(obj);
- SaveVMHandlers *ops;
-
- /* ops will always be freed by qemu when unregistering */
- ops = g_new0(SaveVMHandlers, 1);
-
- ops->save_setup = cmma_save_setup;
- ops->save_live_iterate = cmma_save_iterate;
- ops->save_live_complete_precopy = cmma_save_complete;
- ops->save_live_pending = cmma_save_pending;
- ops->save_cleanup = cmma_save_cleanup;
- ops->load_state = cmma_load;
- ops->is_active = cmma_active;
- register_savevm_live(NULL, TYPE_S390_STATTRIB, 0, 0, ops, sas);
+
+ register_savevm_live(NULL, TYPE_S390_STATTRIB, 0, 0,
+ &savevm_s390_stattrib_handlers, sas);
object_property_add_bool(obj, "migration-enabled",
s390_stattrib_get_migration_enabled,
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 4abbe89847..4d0c3deba6 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -368,7 +368,7 @@ static void s390_machine_reset(void)
/* all cpus are stopped - configure and start the ipl cpu only */
s390_ipl_prepare_cpu(ipl_cpu);
- s390_cpu_set_state(CPU_STATE_OPERATING, ipl_cpu);
+ s390_cpu_set_state(S390_CPU_STATE_OPERATING, ipl_cpu);
}
static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index 276972b59f..047d577313 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -15,9 +15,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "cpu.h"
-#include "exec/memory.h"
#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
#include "hw/boards.h"
#include "hw/s390x/sclp.h"
#include "hw/s390x/event-facility.h"
@@ -57,10 +55,8 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
{
ReadInfo *read_info = (ReadInfo *) sccb;
MachineState *machine = MACHINE(qdev_get_machine());
- sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
int cpu_count;
int rnsize, rnmax;
- int slots = MIN(machine->ram_slots, s390_get_memslot_count());
IplParameterBlock *ipib = s390_ipl_get_iplb();
/* CPU information */
@@ -80,36 +76,6 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO |
SCLP_HAS_IOA_RECONFIG);
- /* Memory Hotplug is only supported for the ccw machine type */
- if (mhd) {
- mhd->standby_subregion_size = MEM_SECTION_SIZE;
- /* Deduct the memory slot already used for core */
- if (slots > 0) {
- while ((mhd->standby_subregion_size * (slots - 1)
- < mhd->standby_mem_size)) {
- mhd->standby_subregion_size = mhd->standby_subregion_size << 1;
- }
- }
- /*
- * Initialize mapping of guest standby memory sections indicating which
- * are and are not online. Assume all standby memory begins offline.
- */
- if (mhd->standby_state_map == 0) {
- if (mhd->standby_mem_size % mhd->standby_subregion_size) {
- mhd->standby_state_map = g_malloc0((mhd->standby_mem_size /
- mhd->standby_subregion_size + 1) *
- (mhd->standby_subregion_size /
- MEM_SECTION_SIZE));
- } else {
- mhd->standby_state_map = g_malloc0(mhd->standby_mem_size /
- MEM_SECTION_SIZE);
- }
- }
- mhd->padded_ram_size = ram_size + mhd->pad_size;
- mhd->rzm = 1 << mhd->increment_size;
-
- read_info->facilities |= cpu_to_be64(SCLP_FC_ASSIGN_ATTACH_READ_STOR);
- }
read_info->mha_pow = s390_get_mha_pow();
read_info->hmfai = cpu_to_be32(s390_get_hmfai());
@@ -121,7 +87,8 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
read_info->rnsize2 = cpu_to_be32(rnsize);
}
- rnmax = machine->maxram_size >> sclp->increment_size;
+ /* we don't support standby memory, maxram_size is never exposed */
+ rnmax = machine->ram_size >> sclp->increment_size;
if (rnmax < 0x10000) {
read_info->rnmax = cpu_to_be16(rnmax);
} else {
@@ -139,195 +106,6 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
}
-static void read_storage_element0_info(SCLPDevice *sclp, SCCB *sccb)
-{
- int i, assigned;
- int subincrement_id = SCLP_STARTING_SUBINCREMENT_ID;
- ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb;
- sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
-
- if (!mhd) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
- return;
- }
-
- if ((ram_size >> mhd->increment_size) >= 0x10000) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION);
- return;
- }
-
- /* Return information regarding core memory */
- storage_info->max_id = cpu_to_be16(mhd->standby_mem_size ? 1 : 0);
- assigned = ram_size >> mhd->increment_size;
- storage_info->assigned = cpu_to_be16(assigned);
-
- for (i = 0; i < assigned; i++) {
- storage_info->entries[i] = cpu_to_be32(subincrement_id);
- subincrement_id += SCLP_INCREMENT_UNIT;
- }
- sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
-}
-
-static void read_storage_element1_info(SCLPDevice *sclp, SCCB *sccb)
-{
- ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb;
- sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
-
- if (!mhd) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
- return;
- }
-
- if ((mhd->standby_mem_size >> mhd->increment_size) >= 0x10000) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION);
- return;
- }
-
- /* Return information regarding standby memory */
- storage_info->max_id = cpu_to_be16(mhd->standby_mem_size ? 1 : 0);
- storage_info->assigned = cpu_to_be16(mhd->standby_mem_size >>
- mhd->increment_size);
- storage_info->standby = cpu_to_be16(mhd->standby_mem_size >>
- mhd->increment_size);
- sccb->h.response_code = cpu_to_be16(SCLP_RC_STANDBY_READ_COMPLETION);
-}
-
-static void attach_storage_element(SCLPDevice *sclp, SCCB *sccb,
- uint16_t element)
-{
- int i, assigned, subincrement_id;
- AttachStorageElement *attach_info = (AttachStorageElement *) sccb;
- sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
-
- if (!mhd) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
- return;
- }
-
- if (element != 1) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
- return;
- }
-
- assigned = mhd->standby_mem_size >> mhd->increment_size;
- attach_info->assigned = cpu_to_be16(assigned);
- subincrement_id = ((ram_size >> mhd->increment_size) << 16)
- + SCLP_STARTING_SUBINCREMENT_ID;
- for (i = 0; i < assigned; i++) {
- attach_info->entries[i] = cpu_to_be32(subincrement_id);
- subincrement_id += SCLP_INCREMENT_UNIT;
- }
- sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
-}
-
-static void assign_storage(SCLPDevice *sclp, SCCB *sccb)
-{
- MemoryRegion *mr = NULL;
- uint64_t this_subregion_size;
- AssignStorage *assign_info = (AssignStorage *) sccb;
- sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
- ram_addr_t assign_addr;
- MemoryRegion *sysmem = get_system_memory();
-
- if (!mhd) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
- return;
- }
- assign_addr = (be16_to_cpu(assign_info->rn) - 1) * mhd->rzm;
-
- if ((assign_addr % MEM_SECTION_SIZE == 0) &&
- (assign_addr >= mhd->padded_ram_size)) {
- /* Re-use existing memory region if found */
- mr = memory_region_find(sysmem, assign_addr, 1).mr;
- memory_region_unref(mr);
- if (!mr) {
-
- MemoryRegion *standby_ram = g_new(MemoryRegion, 1);
-
- /* offset to align to standby_subregion_size for allocation */
- ram_addr_t offset = assign_addr -
- (assign_addr - mhd->padded_ram_size)
- % mhd->standby_subregion_size;
-
- /* strlen("standby.ram") + 4 (Max of KVM_MEMORY_SLOTS) + NULL */
- char id[16];
- snprintf(id, 16, "standby.ram%d",
- (int)((offset - mhd->padded_ram_size) /
- mhd->standby_subregion_size) + 1);
-
- /* Allocate a subregion of the calculated standby_subregion_size */
- if (offset + mhd->standby_subregion_size >
- mhd->padded_ram_size + mhd->standby_mem_size) {
- this_subregion_size = mhd->padded_ram_size +
- mhd->standby_mem_size - offset;
- } else {
- this_subregion_size = mhd->standby_subregion_size;
- }
-
- memory_region_init_ram(standby_ram, NULL, id, this_subregion_size,
- &error_fatal);
- /* This is a hack to make memory hotunplug work again. Once we have
- * subdevices, we have to unparent them when unassigning memory,
- * instead of doing it via the ref count of the MemoryRegion. */
- object_ref(OBJECT(standby_ram));
- object_unparent(OBJECT(standby_ram));
- memory_region_add_subregion(sysmem, offset, standby_ram);
- }
- /* The specified subregion is no longer in standby */
- mhd->standby_state_map[(assign_addr - mhd->padded_ram_size)
- / MEM_SECTION_SIZE] = 1;
- }
- sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
-}
-
-static void unassign_storage(SCLPDevice *sclp, SCCB *sccb)
-{
- MemoryRegion *mr = NULL;
- AssignStorage *assign_info = (AssignStorage *) sccb;
- sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
- ram_addr_t unassign_addr;
- MemoryRegion *sysmem = get_system_memory();
-
- if (!mhd) {
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
- return;
- }
- unassign_addr = (be16_to_cpu(assign_info->rn) - 1) * mhd->rzm;
-
- /* if the addr is a multiple of 256 MB */
- if ((unassign_addr % MEM_SECTION_SIZE == 0) &&
- (unassign_addr >= mhd->padded_ram_size)) {
- mhd->standby_state_map[(unassign_addr -
- mhd->padded_ram_size) / MEM_SECTION_SIZE] = 0;
-
- /* find the specified memory region and destroy it */
- mr = memory_region_find(sysmem, unassign_addr, 1).mr;
- memory_region_unref(mr);
- if (mr) {
- int i;
- int is_removable = 1;
- ram_addr_t map_offset = (unassign_addr - mhd->padded_ram_size -
- (unassign_addr - mhd->padded_ram_size)
- % mhd->standby_subregion_size);
- /* Mark all affected subregions as 'standby' once again */
- for (i = 0;
- i < (mhd->standby_subregion_size / MEM_SECTION_SIZE);
- i++) {
-
- if (mhd->standby_state_map[i + map_offset / MEM_SECTION_SIZE]) {
- is_removable = 0;
- break;
- }
- }
- if (is_removable) {
- memory_region_del_subregion(sysmem, mr);
- object_unref(OBJECT(mr));
- }
- }
- }
- sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
-}
-
/* Provide information about the CPU */
static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb)
{
@@ -390,22 +168,6 @@ static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code)
case SCLP_CMDW_READ_CPU_INFO:
sclp_c->read_cpu_info(sclp, sccb);
break;
- case SCLP_READ_STORAGE_ELEMENT_INFO:
- if (code & 0xff00) {
- sclp_c->read_storage_element1_info(sclp, sccb);
- } else {
- sclp_c->read_storage_element0_info(sclp, sccb);
- }
- break;
- case SCLP_ATTACH_STORAGE_ELEMENT:
- sclp_c->attach_storage_element(sclp, sccb, (code & 0xff00) >> 8);
- break;
- case SCLP_ASSIGN_STORAGE:
- sclp_c->assign_storage(sclp, sccb);
- break;
- case SCLP_UNASSIGN_STORAGE:
- sclp_c->unassign_storage(sclp, sccb);
- break;
case SCLP_CMDW_CONFIGURE_IOA:
sclp_configure_io_adapter(sclp, sccb, true);
break;
@@ -540,9 +302,6 @@ static void sclp_memory_init(SCLPDevice *sclp)
{
MachineState *machine = MACHINE(qdev_get_machine());
ram_addr_t initial_mem = machine->ram_size;
- ram_addr_t max_mem = machine->maxram_size;
- ram_addr_t standby_mem = max_mem - initial_mem;
- ram_addr_t pad_mem = 0;
int increment_size = 20;
/* The storage increment size is a multiple of 1M and is a power of 2.
@@ -552,34 +311,14 @@ static void sclp_memory_init(SCLPDevice *sclp)
while ((initial_mem >> increment_size) > MAX_STORAGE_INCREMENTS) {
increment_size++;
}
- if (machine->ram_slots) {
- while ((standby_mem >> increment_size) > MAX_STORAGE_INCREMENTS) {
- increment_size++;
- }
- }
sclp->increment_size = increment_size;
- /* The core and standby memory areas need to be aligned with
- * the increment size. In effect, this can cause the
- * user-specified memory size to be rounded down to align
- * with the nearest increment boundary. */
+ /* The core memory area needs to be aligned with the increment size.
+ * In effect, this can cause the user-specified memory size to be rounded
+ * down to align with the nearest increment boundary. */
initial_mem = initial_mem >> increment_size << increment_size;
- standby_mem = standby_mem >> increment_size << increment_size;
-
- /* If the size of ram is not on a MEM_SECTION_SIZE boundary,
- calculate the pad size necessary to force this boundary. */
- if (machine->ram_slots && standby_mem) {
- sclpMemoryHotplugDev *mhd = init_sclp_memory_hotplug_dev();
- if (initial_mem % MEM_SECTION_SIZE) {
- pad_mem = MEM_SECTION_SIZE - initial_mem % MEM_SECTION_SIZE;
- }
- mhd->increment_size = increment_size;
- mhd->pad_size = pad_mem;
- mhd->standby_mem_size = standby_mem;
- }
machine->ram_size = initial_mem;
- machine->maxram_size = initial_mem + pad_mem + standby_mem;
/* let's propagate the changed ram size into the global variable. */
ram_size = initial_mem;
}
@@ -613,11 +352,6 @@ static void sclp_class_init(ObjectClass *oc, void *data)
dc->user_creatable = false;
sc->read_SCP_info = read_SCP_info;
- sc->read_storage_element0_info = read_storage_element0_info;
- sc->read_storage_element1_info = read_storage_element1_info;
- sc->attach_storage_element = attach_storage_element;
- sc->assign_storage = assign_storage;
- sc->unassign_storage = unassign_storage;
sc->read_cpu_info = sclp_read_cpu_info;
sc->execute = sclp_execute;
sc->service_interrupt = service_interrupt;
@@ -632,42 +366,8 @@ static TypeInfo sclp_info = {
.class_size = sizeof(SCLPDeviceClass),
};
-sclpMemoryHotplugDev *init_sclp_memory_hotplug_dev(void)
-{
- DeviceState *dev;
- dev = qdev_create(NULL, TYPE_SCLP_MEMORY_HOTPLUG_DEV);
- object_property_add_child(qdev_get_machine(),
- TYPE_SCLP_MEMORY_HOTPLUG_DEV,
- OBJECT(dev), NULL);
- qdev_init_nofail(dev);
- return SCLP_MEMORY_HOTPLUG_DEV(object_resolve_path(
- TYPE_SCLP_MEMORY_HOTPLUG_DEV, NULL));
-}
-
-sclpMemoryHotplugDev *get_sclp_memory_hotplug_dev(void)
-{
- return SCLP_MEMORY_HOTPLUG_DEV(object_resolve_path(
- TYPE_SCLP_MEMORY_HOTPLUG_DEV, NULL));
-}
-
-static void sclp_memory_hotplug_dev_class_init(ObjectClass *klass,
- void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static TypeInfo sclp_memory_hotplug_dev_info = {
- .name = TYPE_SCLP_MEMORY_HOTPLUG_DEV,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(sclpMemoryHotplugDev),
- .class_init = sclp_memory_hotplug_dev_class_init,
-};
-
static void register_types(void)
{
- type_register_static(&sclp_memory_hotplug_dev_info);
type_register_static(&sclp_info);
}
type_init(register_types);
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index 191505df5b..f3d4c4d230 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -2277,5 +2277,5 @@ void lsi53c895a_create(PCIBus *bus)
{
LSIState *s = LSI53C895A(pci_create_simple(bus, -1, "lsi53c895a"));
- scsi_bus_legacy_handle_cmdline(&s->bus, false);
+ scsi_bus_legacy_handle_cmdline(&s->bus);
}
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index b7bafbed6e..1eaeffc830 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -271,7 +271,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
return SCSI_DEVICE(dev);
}
-void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated)
+void scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
{
Location loc;
DriveInfo *dinfo;
@@ -284,59 +284,12 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated)
continue;
}
qemu_opts_loc_restore(dinfo->opts);
- if (deprecated) {
- /* Handling -drive not claimed by machine initialization */
- if (blk_get_attached_dev(blk_by_legacy_dinfo(dinfo))) {
- continue; /* claimed */
- }
- if (!dinfo->is_default) {
- warn_report("bus=%d,unit=%d is deprecated with this"
- " machine type",
- bus->busnr, unit);
- }
- }
scsi_bus_legacy_add_drive(bus, blk_by_legacy_dinfo(dinfo),
unit, false, -1, false, NULL, &error_fatal);
}
loc_pop(&loc);
}
-static bool is_scsi_hba_with_legacy_magic(Object *obj)
-{
- static const char *magic[] = {
- "am53c974", "dc390", "esp", "lsi53c810", "lsi53c895a",
- "megasas", "megasas-gen2", "mptsas1068", "spapr-vscsi",
- "virtio-scsi-device",
- NULL
- };
- const char *typename = object_get_typename(obj);
- int i;
-
- for (i = 0; magic[i]; i++)
- if (!strcmp(typename, magic[i])) {
- return true;
- }
-
- return false;
-}
-
-static int scsi_legacy_handle_cmdline_cb(Object *obj, void *opaque)
-{
- SCSIBus *bus = (SCSIBus *)object_dynamic_cast(obj, TYPE_SCSI_BUS);
-
- if (bus && is_scsi_hba_with_legacy_magic(OBJECT(bus->qbus.parent))) {
- scsi_bus_legacy_handle_cmdline(bus, true);
- }
-
- return 0;
-}
-
-void scsi_legacy_handle_cmdline(void)
-{
- object_child_foreach_recursive(object_get_root(),
- scsi_legacy_handle_cmdline_cb, NULL);
-}
-
static int32_t scsi_invalid_field(SCSIRequest *req, uint8_t *buf)
{
scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD));
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index 360db53ac8..a9e49c7cb5 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -1215,8 +1215,7 @@ void spapr_vscsi_create(VIOsPAPRBus *bus)
dev = qdev_create(&bus->bus, "spapr-vscsi");
qdev_init_nofail(dev);
- scsi_bus_legacy_handle_cmdline(&VIO_SPAPR_VSCSI_DEVICE(dev)->bus,
- false);
+ scsi_bus_legacy_handle_cmdline(&VIO_SPAPR_VSCSI_DEVICE(dev)->bus);
}
static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 8af36ca3d4..426f971311 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -223,7 +223,7 @@ static void xilinx_spips_update_cs(XilinxSPIPS *s, int field)
{
int i;
- for (i = 0; i < s->num_cs; i++) {
+ for (i = 0; i < s->num_cs * s->num_busses; i++) {
bool old_state = s->cs_lines_state[i];
bool new_state = field & (1 << i);
@@ -234,7 +234,7 @@ static void xilinx_spips_update_cs(XilinxSPIPS *s, int field)
}
qemu_set_irq(s->cs_lines[i], !new_state);
}
- if (!(field & ((1 << s->num_cs) - 1))) {
+ if (!(field & ((1 << (s->num_cs * s->num_busses)) - 1))) {
s->snoop_state = SNOOP_CHECKING;
s->cmd_dummies = 0;
s->link_state = 1;
@@ -248,7 +248,40 @@ static void xlnx_zynqmp_qspips_update_cs_lines(XlnxZynqMPQSPIPS *s)
{
if (s->regs[R_GQSPI_GF_SNAPSHOT]) {
int field = ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, CHIP_SELECT);
- xilinx_spips_update_cs(XILINX_SPIPS(s), field);
+ bool upper_cs_sel = field & (1 << 1);
+ bool lower_cs_sel = field & 1;
+ bool bus0_enabled;
+ bool bus1_enabled;
+ uint8_t buses;
+ int cs = 0;
+
+ buses = ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, DATA_BUS_SELECT);
+ bus0_enabled = buses & 1;
+ bus1_enabled = buses & (1 << 1);
+
+ if (bus0_enabled && bus1_enabled) {
+ if (lower_cs_sel) {
+ cs |= 1;
+ }
+ if (upper_cs_sel) {
+ cs |= 1 << 3;
+ }
+ } else if (bus0_enabled) {
+ if (lower_cs_sel) {
+ cs |= 1;
+ }
+ if (upper_cs_sel) {
+ cs |= 1 << 1;
+ }
+ } else if (bus1_enabled) {
+ if (lower_cs_sel) {
+ cs |= 1 << 2;
+ }
+ if (upper_cs_sel) {
+ cs |= 1 << 3;
+ }
+ }
+ xilinx_spips_update_cs(XILINX_SPIPS(s), cs);
}
}
@@ -260,7 +293,7 @@ static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
if (num_effective_busses(s) == 2) {
/* Single bit chip-select for qspi */
field &= 0x1;
- field |= field << 1;
+ field |= field << 3;
/* Dual stack U-Page */
} else if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM &&
s->regs[R_LQSPI_STS] & LQSPI_CFG_U_PAGE) {
@@ -544,7 +577,7 @@ static int xilinx_spips_num_dummies(XilinxQSPIPS *qs, uint8_t command)
return 2;
case QIOR:
case QIOR_4:
- return 5;
+ return 4;
default:
return -1;
}
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 8c19eac3b6..8b27a4b7ef 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -21,6 +21,7 @@ common-obj-$(CONFIG_IMX) += imx_epit.o
common-obj-$(CONFIG_IMX) += imx_gpt.o
common-obj-$(CONFIG_LM32) += lm32_timer.o
common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o
+common-obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp-rtc.o
obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index 9d93a16e0f..6f1f723b1f 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -31,9 +31,9 @@
#include "sysemu/replay.h"
#include "hw/timer/mc146818rtc.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-misc.h"
+#include "qapi/qapi-events-misc.h"
#include "qapi/visitor.h"
-#include "qapi-event.h"
-#include "qmp-commands.h"
#ifdef TARGET_I386
#include "hw/i386/apic.h"
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
index 640722b5d1..e6e042fddb 100644
--- a/hw/timer/trace-events
+++ b/hw/timer/trace-events
@@ -60,3 +60,6 @@ systick_write(uint64_t addr, uint32_t value, unsigned size) "systick write addr
cmsdk_apb_timer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB timer read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
cmsdk_apb_timer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB timer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
cmsdk_apb_timer_reset(void) "CMSDK APB timer: reset"
+
+# hw/timer/xlnx-zynqmp-rtc.c
+xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec) "Get time from host: %d-%d-%d %2d:%02d:%02d"
diff --git a/hw/timer/xlnx-zynqmp-rtc.c b/hw/timer/xlnx-zynqmp-rtc.c
new file mode 100644
index 0000000000..c98dc3d94e
--- /dev/null
+++ b/hw/timer/xlnx-zynqmp-rtc.c
@@ -0,0 +1,272 @@
+/*
+ * QEMU model of the Xilinx ZynqMP Real Time Clock (RTC).
+ *
+ * Copyright (c) 2017 Xilinx Inc.
+ *
+ * Written-by: Alistair Francis <alistair.francis@xilinx.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/register.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "hw/ptimer.h"
+#include "qemu/cutils.h"
+#include "sysemu/sysemu.h"
+#include "trace.h"
+#include "hw/timer/xlnx-zynqmp-rtc.h"
+
+#ifndef XLNX_ZYNQMP_RTC_ERR_DEBUG
+#define XLNX_ZYNQMP_RTC_ERR_DEBUG 0
+#endif
+
+static void rtc_int_update_irq(XlnxZynqMPRTC *s)
+{
+ bool pending = s->regs[R_RTC_INT_STATUS] & ~s->regs[R_RTC_INT_MASK];
+ qemu_set_irq(s->irq_rtc_int, pending);
+}
+
+static void addr_error_int_update_irq(XlnxZynqMPRTC *s)
+{
+ bool pending = s->regs[R_ADDR_ERROR] & ~s->regs[R_ADDR_ERROR_INT_MASK];
+ qemu_set_irq(s->irq_addr_error_int, pending);
+}
+
+static uint32_t rtc_get_count(XlnxZynqMPRTC *s)
+{
+ int64_t now = qemu_clock_get_ns(rtc_clock);
+ return s->tick_offset + now / NANOSECONDS_PER_SECOND;
+}
+
+static uint64_t current_time_postr(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
+
+ return rtc_get_count(s);
+}
+
+static void rtc_int_status_postw(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
+ rtc_int_update_irq(s);
+}
+
+static uint64_t rtc_int_en_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
+
+ s->regs[R_RTC_INT_MASK] &= (uint32_t) ~val64;
+ rtc_int_update_irq(s);
+ return 0;
+}
+
+static uint64_t rtc_int_dis_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
+
+ s->regs[R_RTC_INT_MASK] |= (uint32_t) val64;
+ rtc_int_update_irq(s);
+ return 0;
+}
+
+static void addr_error_postw(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
+ addr_error_int_update_irq(s);
+}
+
+static uint64_t addr_error_int_en_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
+
+ s->regs[R_ADDR_ERROR_INT_MASK] &= (uint32_t) ~val64;
+ addr_error_int_update_irq(s);
+ return 0;
+}
+
+static uint64_t addr_error_int_dis_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
+
+ s->regs[R_ADDR_ERROR_INT_MASK] |= (uint32_t) val64;
+ addr_error_int_update_irq(s);
+ return 0;
+}
+
+static const RegisterAccessInfo rtc_regs_info[] = {
+ { .name = "SET_TIME_WRITE", .addr = A_SET_TIME_WRITE,
+ .unimp = MAKE_64BIT_MASK(0, 32),
+ },{ .name = "SET_TIME_READ", .addr = A_SET_TIME_READ,
+ .ro = 0xffffffff,
+ .post_read = current_time_postr,
+ },{ .name = "CALIB_WRITE", .addr = A_CALIB_WRITE,
+ .unimp = MAKE_64BIT_MASK(0, 32),
+ },{ .name = "CALIB_READ", .addr = A_CALIB_READ,
+ .ro = 0x1fffff,
+ },{ .name = "CURRENT_TIME", .addr = A_CURRENT_TIME,
+ .ro = 0xffffffff,
+ .post_read = current_time_postr,
+ },{ .name = "CURRENT_TICK", .addr = A_CURRENT_TICK,
+ .ro = 0xffff,
+ },{ .name = "ALARM", .addr = A_ALARM,
+ },{ .name = "RTC_INT_STATUS", .addr = A_RTC_INT_STATUS,
+ .w1c = 0x3,
+ .post_write = rtc_int_status_postw,
+ },{ .name = "RTC_INT_MASK", .addr = A_RTC_INT_MASK,
+ .reset = 0x3,
+ .ro = 0x3,
+ },{ .name = "RTC_INT_EN", .addr = A_RTC_INT_EN,
+ .pre_write = rtc_int_en_prew,
+ },{ .name = "RTC_INT_DIS", .addr = A_RTC_INT_DIS,
+ .pre_write = rtc_int_dis_prew,
+ },{ .name = "ADDR_ERROR", .addr = A_ADDR_ERROR,
+ .w1c = 0x1,
+ .post_write = addr_error_postw,
+ },{ .name = "ADDR_ERROR_INT_MASK", .addr = A_ADDR_ERROR_INT_MASK,
+ .reset = 0x1,
+ .ro = 0x1,
+ },{ .name = "ADDR_ERROR_INT_EN", .addr = A_ADDR_ERROR_INT_EN,
+ .pre_write = addr_error_int_en_prew,
+ },{ .name = "ADDR_ERROR_INT_DIS", .addr = A_ADDR_ERROR_INT_DIS,
+ .pre_write = addr_error_int_dis_prew,
+ },{ .name = "CONTROL", .addr = A_CONTROL,
+ .reset = 0x1000000,
+ .rsvd = 0x70fffffe,
+ },{ .name = "SAFETY_CHK", .addr = A_SAFETY_CHK,
+ }
+};
+
+static void rtc_reset(DeviceState *dev)
+{
+ XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(dev);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
+ register_reset(&s->regs_info[i]);
+ }
+
+ rtc_int_update_irq(s);
+ addr_error_int_update_irq(s);
+}
+
+static const MemoryRegionOps rtc_ops = {
+ .read = register_read_memory,
+ .write = register_write_memory,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void rtc_init(Object *obj)
+{
+ XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ RegisterInfoArray *reg_array;
+ struct tm current_tm;
+
+ memory_region_init(&s->iomem, obj, TYPE_XLNX_ZYNQMP_RTC,
+ XLNX_ZYNQMP_RTC_R_MAX * 4);
+ reg_array =
+ register_init_block32(DEVICE(obj), rtc_regs_info,
+ ARRAY_SIZE(rtc_regs_info),
+ s->regs_info, s->regs,
+ &rtc_ops,
+ XLNX_ZYNQMP_RTC_ERR_DEBUG,
+ XLNX_ZYNQMP_RTC_R_MAX * 4);
+ memory_region_add_subregion(&s->iomem,
+ 0x0,
+ &reg_array->mem);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_init_irq(sbd, &s->irq_rtc_int);
+ sysbus_init_irq(sbd, &s->irq_addr_error_int);
+
+ qemu_get_timedate(&current_tm, 0);
+ s->tick_offset = mktimegm(&current_tm) -
+ qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND;
+
+ trace_xlnx_zynqmp_rtc_gettime(current_tm.tm_year, current_tm.tm_mon,
+ current_tm.tm_mday, current_tm.tm_hour,
+ current_tm.tm_min, current_tm.tm_sec);
+}
+
+static int rtc_pre_save(void *opaque)
+{
+ XlnxZynqMPRTC *s = opaque;
+ int64_t now = qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND;
+
+ /* Add the time at migration */
+ s->tick_offset = s->tick_offset + now;
+
+ return 0;
+}
+
+static int rtc_post_load(void *opaque, int version_id)
+{
+ XlnxZynqMPRTC *s = opaque;
+ int64_t now = qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND;
+
+ /* Subtract the time after migration. This combined with the pre_save
+ * action results in us having subtracted the time that the guest was
+ * stopped to the offset.
+ */
+ s->tick_offset = s->tick_offset - now;
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_rtc = {
+ .name = TYPE_XLNX_ZYNQMP_RTC,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = rtc_pre_save,
+ .post_load = rtc_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, XlnxZynqMPRTC, XLNX_ZYNQMP_RTC_R_MAX),
+ VMSTATE_UINT32(tick_offset, XlnxZynqMPRTC),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
+static void rtc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = rtc_reset;
+ dc->vmsd = &vmstate_rtc;
+}
+
+static const TypeInfo rtc_info = {
+ .name = TYPE_XLNX_ZYNQMP_RTC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(XlnxZynqMPRTC),
+ .class_init = rtc_class_init,
+ .instance_init = rtc_init,
+};
+
+static void rtc_register_types(void)
+{
+ type_register_static(&rtc_info);
+}
+
+type_init(rtc_register_types)
diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c
index d0da10a1a6..6418ef0831 100644
--- a/hw/tpm/tpm_emulator.c
+++ b/hw/tpm/tpm_emulator.c
@@ -38,6 +38,7 @@
#include "migration/blocker.h"
#include "qapi/error.h"
#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
#include "chardev/char-fe.h"
#include "trace.h"
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index 2589c4de76..479317ee50 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -30,6 +30,7 @@
#include "tpm_int.h"
#include "hw/hw.h"
#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-tpm.h"
#include "tpm_util.h"
#include "trace.h"
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 033cc8dea1..3ba3cbc146 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -2807,7 +2807,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
return;
}
- vdev->vbasedev.name = g_strdup(basename(vdev->vbasedev.sysfsdev));
+ vdev->vbasedev.name = g_path_get_basename(vdev->vbasedev.sysfsdev);
vdev->vbasedev.ops = &vfio_pci_ops;
vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI;
vdev->vbasedev.dev = &vdev->pdev.qdev;
diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c
index 0d4bc0aae8..5c921c27ba 100644
--- a/hw/vfio/platform.c
+++ b/hw/vfio/platform.c
@@ -561,7 +561,7 @@ static int vfio_base_device_init(VFIODevice *vbasedev, Error **errp)
/* @sysfsdev takes precedence over @host */
if (vbasedev->sysfsdev) {
g_free(vbasedev->name);
- vbasedev->name = g_strdup(basename(vbasedev->sysfsdev));
+ vbasedev->name = g_path_get_basename(vbasedev->sysfsdev);
} else {
if (!vbasedev->name || strchr(vbasedev->name, '/')) {
error_setg(errp, "wrong host device name");
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 6eb97980ad..41ff5cff41 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -17,6 +17,7 @@
#include "sysemu/kvm.h"
#include "qemu/error-report.h"
#include "qemu/sockets.h"
+#include "sysemu/cryptodev.h"
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -39,6 +40,7 @@ enum VhostUserProtocolFeature {
VHOST_USER_PROTOCOL_F_NET_MTU = 4,
VHOST_USER_PROTOCOL_F_SLAVE_REQ = 5,
VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6,
+ VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7,
VHOST_USER_PROTOCOL_F_MAX
};
@@ -72,6 +74,8 @@ typedef enum VhostUserRequest {
VHOST_USER_SET_VRING_ENDIAN = 23,
VHOST_USER_GET_CONFIG = 24,
VHOST_USER_SET_CONFIG = 25,
+ VHOST_USER_CREATE_CRYPTO_SESSION = 26,
+ VHOST_USER_CLOSE_CRYPTO_SESSION = 27,
VHOST_USER_MAX
} VhostUserRequest;
@@ -107,6 +111,17 @@ typedef struct VhostUserConfig {
uint8_t region[VHOST_USER_MAX_CONFIG_SIZE];
} VhostUserConfig;
+#define VHOST_CRYPTO_SYM_HMAC_MAX_KEY_LEN 512
+#define VHOST_CRYPTO_SYM_CIPHER_MAX_KEY_LEN 64
+
+typedef struct VhostUserCryptoSession {
+ /* session id for success, -1 on errors */
+ int64_t session_id;
+ CryptoDevBackendSymSessionInfo session_setup_data;
+ uint8_t key[VHOST_CRYPTO_SYM_CIPHER_MAX_KEY_LEN];
+ uint8_t auth_key[VHOST_CRYPTO_SYM_HMAC_MAX_KEY_LEN];
+} VhostUserCryptoSession;
+
static VhostUserConfig c __attribute__ ((unused));
#define VHOST_USER_CONFIG_HDR_SIZE (sizeof(c.offset) \
+ sizeof(c.size) \
@@ -132,6 +147,7 @@ typedef union {
VhostUserLog log;
struct vhost_iotlb_msg iotlb;
VhostUserConfig config;
+ VhostUserCryptoSession session;
} VhostUserPayload;
typedef struct VhostUserMsg {
@@ -1054,6 +1070,92 @@ static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data,
return 0;
}
+static int vhost_user_crypto_create_session(struct vhost_dev *dev,
+ void *session_info,
+ uint64_t *session_id)
+{
+ bool crypto_session = virtio_has_feature(dev->protocol_features,
+ VHOST_USER_PROTOCOL_F_CRYPTO_SESSION);
+ CryptoDevBackendSymSessionInfo *sess_info = session_info;
+ VhostUserMsg msg = {
+ .hdr.request = VHOST_USER_CREATE_CRYPTO_SESSION,
+ .hdr.flags = VHOST_USER_VERSION,
+ .hdr.size = sizeof(msg.payload.session),
+ };
+
+ assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
+
+ if (!crypto_session) {
+ error_report("vhost-user trying to send unhandled ioctl");
+ return -1;
+ }
+
+ memcpy(&msg.payload.session.session_setup_data, sess_info,
+ sizeof(CryptoDevBackendSymSessionInfo));
+ if (sess_info->key_len) {
+ memcpy(&msg.payload.session.key, sess_info->cipher_key,
+ sess_info->key_len);
+ }
+ if (sess_info->auth_key_len > 0) {
+ memcpy(&msg.payload.session.auth_key, sess_info->auth_key,
+ sess_info->auth_key_len);
+ }
+ if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
+ error_report("vhost_user_write() return -1, create session failed");
+ return -1;
+ }
+
+ if (vhost_user_read(dev, &msg) < 0) {
+ error_report("vhost_user_read() return -1, create session failed");
+ return -1;
+ }
+
+ if (msg.hdr.request != VHOST_USER_CREATE_CRYPTO_SESSION) {
+ error_report("Received unexpected msg type. Expected %d received %d",
+ VHOST_USER_CREATE_CRYPTO_SESSION, msg.hdr.request);
+ return -1;
+ }
+
+ if (msg.hdr.size != sizeof(msg.payload.session)) {
+ error_report("Received bad msg size.");
+ return -1;
+ }
+
+ if (msg.payload.session.session_id < 0) {
+ error_report("Bad session id: %" PRId64 "",
+ msg.payload.session.session_id);
+ return -1;
+ }
+ *session_id = msg.payload.session.session_id;
+
+ return 0;
+}
+
+static int
+vhost_user_crypto_close_session(struct vhost_dev *dev, uint64_t session_id)
+{
+ bool crypto_session = virtio_has_feature(dev->protocol_features,
+ VHOST_USER_PROTOCOL_F_CRYPTO_SESSION);
+ VhostUserMsg msg = {
+ .hdr.request = VHOST_USER_CLOSE_CRYPTO_SESSION,
+ .hdr.flags = VHOST_USER_VERSION,
+ .hdr.size = sizeof(msg.payload.u64),
+ };
+ msg.payload.u64 = session_id;
+
+ if (!crypto_session) {
+ error_report("vhost-user trying to send unhandled ioctl");
+ return -1;
+ }
+
+ if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
+ error_report("vhost_user_write() return -1, close session failed");
+ return -1;
+ }
+
+ return 0;
+}
+
const VhostOps user_ops = {
.backend_type = VHOST_BACKEND_TYPE_USER,
.vhost_backend_init = vhost_user_init,
@@ -1082,4 +1184,6 @@ const VhostOps user_ops = {
.vhost_send_device_iotlb_msg = vhost_user_send_device_iotlb_msg,
.vhost_get_config = vhost_user_get_config,
.vhost_set_config = vhost_user_set_config,
+ .vhost_crypto_create_session = vhost_user_crypto_create_session,
+ .vhost_crypto_close_session = vhost_user_crypto_close_session,
};
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 4a44e6e6bf..d8d0ef92e1 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -345,6 +345,10 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev,
for (i = 0; i < dev->nvqs; ++i) {
struct vhost_virtqueue *vq = dev->vqs + i;
+ if (vq->desc_phys == 0) {
+ continue;
+ }
+
j = 0;
r = vhost_verify_ring_part_mapping(
vq->desc, vq->desc_phys, vq->desc_size,
@@ -355,7 +359,7 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev,
j++;
r = vhost_verify_ring_part_mapping(
- vq->desc, vq->desc_phys, vq->desc_size,
+ vq->avail, vq->avail_phys, vq->avail_size,
reg_hva, reg_gpa, reg_size);
if (r) {
break;
@@ -363,7 +367,7 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev,
j++;
r = vhost_verify_ring_part_mapping(
- vq->desc, vq->desc_phys, vq->desc_size,
+ vq->used, vq->used_phys, vq->used_size,
reg_hva, reg_gpa, reg_size);
if (r) {
break;
@@ -881,6 +885,11 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
};
struct VirtQueue *vvq = virtio_get_queue(vdev, idx);
+ a = virtio_queue_get_desc_addr(vdev, idx);
+ if (a == 0) {
+ /* Queue might not be ready for start */
+ return 0;
+ }
vq->num = state.num = virtio_queue_get_num(vdev, idx);
r = dev->vhost_ops->vhost_set_vring_num(dev, &state);
@@ -906,7 +915,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
}
vq->desc_size = s = l = virtio_queue_get_desc_size(vdev, idx);
- vq->desc_phys = a = virtio_queue_get_desc_addr(vdev, idx);
+ vq->desc_phys = a;
vq->desc = vhost_memory_map(dev, a, &l, 0);
if (!vq->desc || l != s) {
r = -ENOMEM;
@@ -989,6 +998,13 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
.index = vhost_vq_index,
};
int r;
+ int a;
+
+ a = virtio_queue_get_desc_addr(vdev, idx);
+ if (a == 0) {
+ /* Don't stop the virtqueue which might have not been started */
+ return;
+ }
r = dev->vhost_ops->vhost_get_vring_base(dev, &state);
if (r < 0) {
@@ -1106,13 +1122,6 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
goto fail;
}
- if (used_memslots > hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) {
- error_report("vhost backend memory slots limit is less"
- " than current number of present memory slots");
- r = -1;
- goto fail;
- }
-
r = hdev->vhost_ops->vhost_set_owner(hdev);
if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_owner failed");
@@ -1192,6 +1201,18 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
hdev->started = false;
memory_listener_register(&hdev->memory_listener, &address_space_memory);
QLIST_INSERT_HEAD(&vhost_devices, hdev, entry);
+
+ if (used_memslots > hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) {
+ error_report("vhost backend memory slots limit is less"
+ " than current number of present memory slots");
+ r = -1;
+ if (busyloop_timeout) {
+ goto fail_busyloop;
+ } else {
+ goto fail;
+ }
+ }
+
return 0;
fail_busyloop:
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 48224493a0..f456cea2e7 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -24,8 +24,8 @@
#include "sysemu/kvm.h"
#include "exec/address-spaces.h"
#include "qapi/error.h"
+#include "qapi/qapi-events-misc.h"
#include "qapi/visitor.h"
-#include "qapi-event.h"
#include "trace.h"
#include "qemu/error-report.h"
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index 19c82e0432..9a9fa495d2 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -20,6 +20,7 @@
#include "hw/virtio/virtio-crypto.h"
#include "hw/virtio/virtio-access.h"
#include "standard-headers/linux/virtio_ids.h"
+#include "sysemu/cryptodev-vhost.h"
#define VIRTIO_CRYPTO_VM_VERSION 1
@@ -880,6 +881,72 @@ static void virtio_crypto_get_config(VirtIODevice *vdev, uint8_t *config)
memcpy(config, &crypto_cfg, c->config_size);
}
+static bool virtio_crypto_started(VirtIOCrypto *c, uint8_t status)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(c);
+ return (status & VIRTIO_CONFIG_S_DRIVER_OK) &&
+ (c->status & VIRTIO_CRYPTO_S_HW_READY) && vdev->vm_running;
+}
+
+static void virtio_crypto_vhost_status(VirtIOCrypto *c, uint8_t status)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(c);
+ int queues = c->multiqueue ? c->max_queues : 1;
+ CryptoDevBackend *b = c->cryptodev;
+ CryptoDevBackendClient *cc = b->conf.peers.ccs[0];
+
+ if (!cryptodev_get_vhost(cc, b, 0)) {
+ return;
+ }
+
+ if ((virtio_crypto_started(c, status)) == !!c->vhost_started) {
+ return;
+ }
+
+ if (!c->vhost_started) {
+ int r;
+
+ c->vhost_started = 1;
+ r = cryptodev_vhost_start(vdev, queues);
+ if (r < 0) {
+ error_report("unable to start vhost crypto: %d: "
+ "falling back on userspace virtio", -r);
+ c->vhost_started = 0;
+ }
+ } else {
+ cryptodev_vhost_stop(vdev, queues);
+ c->vhost_started = 0;
+ }
+}
+
+static void virtio_crypto_set_status(VirtIODevice *vdev, uint8_t status)
+{
+ VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
+
+ virtio_crypto_vhost_status(vcrypto, status);
+}
+
+static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx,
+ bool mask)
+{
+ VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
+ int queue = virtio_crypto_vq2q(idx);
+
+ assert(vcrypto->vhost_started);
+
+ cryptodev_vhost_virtqueue_mask(vdev, queue, idx, mask);
+}
+
+static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx)
+{
+ VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
+ int queue = virtio_crypto_vq2q(idx);
+
+ assert(vcrypto->vhost_started);
+
+ return cryptodev_vhost_virtqueue_pending(vdev, queue, idx);
+}
+
static void virtio_crypto_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -893,6 +960,9 @@ static void virtio_crypto_class_init(ObjectClass *klass, void *data)
vdc->get_config = virtio_crypto_get_config;
vdc->get_features = virtio_crypto_get_features;
vdc->reset = virtio_crypto_reset;
+ vdc->set_status = virtio_crypto_set_status;
+ vdc->guest_notifier_mask = virtio_crypto_guest_notifier_mask;
+ vdc->guest_notifier_pending = virtio_crypto_guest_notifier_pending;
}
static void virtio_crypto_instance_init(Object *obj)
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index b55dfcf05c..1e8ab7bbc5 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1585,7 +1585,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
if (legacy) {
if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) {
error_setg(errp, "VIRTIO_F_IOMMU_PLATFORM was supported by"
- "neither legacy nor transitional device.");
+ " neither legacy nor transitional device");
return ;
}
/*
diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c
index 98a5dd6689..6e8ba061d8 100644
--- a/hw/watchdog/watchdog.c
+++ b/hw/watchdog/watchdog.c
@@ -24,12 +24,12 @@
#include "qemu/config-file.h"
#include "qemu/queue.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-run-state.h"
+#include "qapi/qapi-events-run-state.h"
#include "sysemu/sysemu.h"
#include "sysemu/watchdog.h"
-#include "qapi-event.h"
#include "hw/nmi.h"
#include "qemu/help_option.h"
-#include "qmp-commands.h"
static WatchdogAction watchdog_action = WATCHDOG_ACTION_RESET;
static QLIST_HEAD(watchdog_list, WatchdogTimerModel) watchdog_list;