aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-02-13 11:19:22 +0000
committerPeter Maydell <peter.maydell@linaro.org>2015-02-13 11:19:22 +0000
commite344e7afc1a04ab11c843c069cef0cdcc1c7787e (patch)
tree1e027d72e5ded48160fa81aeff73453cbcf1ebef
parent449008f86418583a1f0fb946cf91ee7b4797317d (diff)
parentc2ebd862a54b7e12175d65c03ba259926cb2237a (diff)
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20150213' into staging
target-arm queue: * PCIe support in virt board * Support 32-bit guests on 64-bit KVM hosts in virt board * Fixes to avoid C undefined behaviour # gpg: Signature made Fri 13 Feb 2015 05:53:07 GMT using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" * remotes/pmaydell/tags/pull-target-arm-20150213: target-arm: A64: Avoid signed shifts in disas_ldst_pair() target-arm: A64: Avoid left shifting negative integers in disas_pc_rel_addr target-arm: A64: Fix handling of rotate in logic_imm_decode_wmask target-arm: A64: Fix shifts into sign bit target-arm: Add AArch32 guest support to KVM64 target-arm: Add 32/64-bit register sync target-arm: Add feature parsing to virt target-arm: Add CPU property to disable AArch64 pci: Move PCI VGA to pci.mak arm: Add PCIe host bridge in virt machine pci: Add generic PCIe host bridge pci: Allocate PCIe host bridge PCI ID Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--default-configs/alpha-softmmu.mak2
-rw-r--r--default-configs/arm-softmmu.mak2
-rw-r--r--default-configs/i386-softmmu.mak2
-rw-r--r--default-configs/mips-softmmu.mak2
-rw-r--r--default-configs/mips64-softmmu.mak2
-rw-r--r--default-configs/mips64el-softmmu.mak2
-rw-r--r--default-configs/mipsel-softmmu.mak2
-rw-r--r--default-configs/pci.mak2
-rw-r--r--default-configs/ppc-softmmu.mak2
-rw-r--r--default-configs/ppc64-softmmu.mak2
-rw-r--r--default-configs/ppcemb-softmmu.mak2
-rw-r--r--default-configs/sparc64-softmmu.mak2
-rw-r--r--default-configs/x86_64-softmmu.mak2
-rw-r--r--hw/arm/virt.c158
-rw-r--r--hw/pci-host/Makefile.objs1
-rw-r--r--hw/pci-host/gpex.c154
-rw-r--r--include/hw/pci-host/gpex.h56
-rw-r--r--include/hw/pci/pci.h1
-rw-r--r--include/sysemu/device_tree.h9
-rw-r--r--target-arm/cpu.c5
-rw-r--r--target-arm/cpu.h2
-rw-r--r--target-arm/cpu64.c39
-rw-r--r--target-arm/helper-a64.c5
-rw-r--r--target-arm/helper.c211
-rw-r--r--target-arm/kvm64.c36
-rw-r--r--target-arm/op_helper.c6
-rw-r--r--target-arm/translate-a64.c18
27 files changed, 678 insertions, 49 deletions
diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak
index bc07600f96..7f6161eba9 100644
--- a/default-configs/alpha-softmmu.mak
+++ b/default-configs/alpha-softmmu.mak
@@ -5,8 +5,6 @@ include usb.mak
CONFIG_SERIAL=y
CONFIG_I8254=y
CONFIG_PCKBD=y
-CONFIG_VGA=y
-CONFIG_VGA_PCI=y
CONFIG_VGA_CIRRUS=y
CONFIG_IDE_CORE=y
CONFIG_IDE_QDEV=y
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index f3513fa124..7671ee278a 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -82,6 +82,8 @@ CONFIG_ZYNQ=y
CONFIG_VERSATILE_PCI=y
CONFIG_VERSATILE_I2C=y
+CONFIG_PCI_GENERIC=y
+
CONFIG_SDHCI=y
CONFIG_INTEGRATOR_DEBUG=y
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 8e08841760..bd99af9942 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -3,9 +3,7 @@
include pci.mak
include sound.mak
include usb.mak
-CONFIG_VGA=y
CONFIG_QXL=$(CONFIG_SPICE)
-CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_CIRRUS=y
CONFIG_VMWARE_VGA=y
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index 2a80b04dc0..cce2c8116b 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -4,8 +4,6 @@ include pci.mak
include sound.mak
include usb.mak
CONFIG_ESP=y
-CONFIG_VGA=y
-CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_ISA_MM=y
CONFIG_VGA_CIRRUS=y
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index f1f933bc44..7a88a08adc 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -4,8 +4,6 @@ include pci.mak
include sound.mak
include usb.mak
CONFIG_ESP=y
-CONFIG_VGA=y
-CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_ISA_MM=y
CONFIG_VGA_CIRRUS=y
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index 317b151361..095de43186 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -4,8 +4,6 @@ include pci.mak
include sound.mak
include usb.mak
CONFIG_ESP=y
-CONFIG_VGA=y
-CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_ISA_MM=y
CONFIG_VGA_CIRRUS=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index 7708185f6b..0e25108b7f 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -4,8 +4,6 @@ include pci.mak
include sound.mak
include usb.mak
CONFIG_ESP=y
-CONFIG_VGA=y
-CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_ISA_MM=y
CONFIG_VGA_CIRRUS=y
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index 030cdc7d3d..bea6b01553 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -33,3 +33,5 @@ CONFIG_NVME_PCI=y
CONFIG_SD=y
CONFIG_SDHCI=y
CONFIG_EDU=y
+CONFIG_VGA=y
+CONFIG_VGA_PCI=y
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index d725b23312..aebfab92eb 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -6,8 +6,6 @@ include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
CONFIG_M48T59=y
-CONFIG_VGA=y
-CONFIG_VGA_PCI=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
CONFIG_I8254=y
diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
index bd30d69347..f195a8721a 100644
--- a/default-configs/ppc64-softmmu.mak
+++ b/default-configs/ppc64-softmmu.mak
@@ -6,8 +6,6 @@ include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
CONFIG_M48T59=y
-CONFIG_VGA=y
-CONFIG_VGA_PCI=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
CONFIG_I8254=y
diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
index e032761457..a1b3d5f35d 100644
--- a/default-configs/ppcemb-softmmu.mak
+++ b/default-configs/ppcemb-softmmu.mak
@@ -4,8 +4,6 @@ include pci.mak
include sound.mak
include usb.mak
CONFIG_M48T59=y
-CONFIG_VGA=y
-CONFIG_VGA_PCI=y
CONFIG_SERIAL=y
CONFIG_I8257=y
CONFIG_OPENPIC=y
diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak
index 299c97b715..123bb993ef 100644
--- a/default-configs/sparc64-softmmu.mak
+++ b/default-configs/sparc64-softmmu.mak
@@ -5,8 +5,6 @@ include usb.mak
CONFIG_ISA_MMIO=y
CONFIG_M48T59=y
CONFIG_PTIMER=y
-CONFIG_VGA=y
-CONFIG_VGA_PCI=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
CONFIG_PCKBD=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 66557ac590..e7c273417b 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -3,9 +3,7 @@
include pci.mak
include sound.mak
include usb.mak
-CONFIG_VGA=y
CONFIG_QXL=$(CONFIG_SPICE)
-CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_CIRRUS=y
CONFIG_VMWARE_VGA=y
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 34d9379032..69f51ac0da 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -42,6 +42,7 @@
#include "exec/address-spaces.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
+#include "hw/pci-host/gpex.h"
#define NUM_VIRTIO_TRANSPORTS 32
@@ -69,6 +70,7 @@ enum {
VIRT_MMIO,
VIRT_RTC,
VIRT_FW_CFG,
+ VIRT_PCIE,
};
typedef struct MemMapEntry {
@@ -129,13 +131,21 @@ static const MemMapEntry a15memmap[] = {
[VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
- /* 0x10000000 .. 0x40000000 reserved for PCI */
+ /*
+ * PCIE verbose map:
+ *
+ * MMIO window { 0x10000000, 0x2eff0000 },
+ * PIO window { 0x3eff0000, 0x00010000 },
+ * ECAM { 0x3f000000, 0x01000000 },
+ */
+ [VIRT_PCIE] = { 0x10000000, 0x30000000 },
[VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
};
static const int a15irqmap[] = {
[VIRT_UART] = 1,
[VIRT_RTC] = 2,
+ [VIRT_PCIE] = 3, /* ... to 6 */
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
};
@@ -312,7 +322,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
}
}
-static void fdt_add_gic_node(const VirtBoardInfo *vbi)
+static uint32_t fdt_add_gic_node(const VirtBoardInfo *vbi)
{
uint32_t gic_phandle;
@@ -331,9 +341,11 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi)
2, vbi->memmap[VIRT_GIC_CPU].base,
2, vbi->memmap[VIRT_GIC_CPU].size);
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle);
+
+ return gic_phandle;
}
-static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic)
+static uint32_t create_gic(const VirtBoardInfo *vbi, qemu_irq *pic)
{
/* We create a standalone GIC v2 */
DeviceState *gicdev;
@@ -380,7 +392,7 @@ static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic)
pic[i] = qdev_get_gpio_in(gicdev, i);
}
- fdt_add_gic_node(vbi);
+ return fdt_add_gic_node(vbi);
}
static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
@@ -585,6 +597,119 @@ static void create_fw_cfg(const VirtBoardInfo *vbi)
g_free(nodename);
}
+static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle,
+ int first_irq, const char *nodename)
+{
+ int devfn, pin;
+ uint32_t full_irq_map[4 * 4 * 8] = { 0 };
+ uint32_t *irq_map = full_irq_map;
+
+ for (devfn = 0; devfn <= 0x18; devfn += 0x8) {
+ for (pin = 0; pin < 4; pin++) {
+ int irq_type = GIC_FDT_IRQ_TYPE_SPI;
+ int irq_nr = first_irq + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS);
+ int irq_level = GIC_FDT_IRQ_FLAGS_LEVEL_HI;
+ int i;
+
+ uint32_t map[] = {
+ devfn << 8, 0, 0, /* devfn */
+ pin + 1, /* PCI pin */
+ gic_phandle, irq_type, irq_nr, irq_level }; /* GIC irq */
+
+ /* Convert map to big endian */
+ for (i = 0; i < 8; i++) {
+ irq_map[i] = cpu_to_be32(map[i]);
+ }
+ irq_map += 8;
+ }
+ }
+
+ qemu_fdt_setprop(vbi->fdt, nodename, "interrupt-map",
+ full_irq_map, sizeof(full_irq_map));
+
+ qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupt-map-mask",
+ 0x1800, 0, 0, /* devfn (PCI_SLOT(3)) */
+ 0x7 /* PCI irq */);
+}
+
+static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
+ uint32_t gic_phandle)
+{
+ hwaddr base = vbi->memmap[VIRT_PCIE].base;
+ hwaddr size = vbi->memmap[VIRT_PCIE].size;
+ hwaddr end = base + size;
+ hwaddr size_mmio;
+ hwaddr size_ioport = 64 * 1024;
+ int nr_pcie_buses = 16;
+ hwaddr size_ecam = PCIE_MMCFG_SIZE_MIN * nr_pcie_buses;
+ hwaddr base_mmio = base;
+ hwaddr base_ioport;
+ hwaddr base_ecam;
+ int irq = vbi->irqmap[VIRT_PCIE];
+ MemoryRegion *mmio_alias;
+ MemoryRegion *mmio_reg;
+ MemoryRegion *ecam_alias;
+ MemoryRegion *ecam_reg;
+ DeviceState *dev;
+ char *nodename;
+ int i;
+
+ base_ecam = QEMU_ALIGN_DOWN(end - size_ecam, size_ecam);
+ base_ioport = QEMU_ALIGN_DOWN(base_ecam - size_ioport, size_ioport);
+ size_mmio = base_ioport - base;
+
+ dev = qdev_create(NULL, TYPE_GPEX_HOST);
+ qdev_init_nofail(dev);
+
+ /* Map only the first size_ecam bytes of ECAM space */
+ ecam_alias = g_new0(MemoryRegion, 1);
+ ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+ memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
+ ecam_reg, 0, size_ecam);
+ memory_region_add_subregion(get_system_memory(), base_ecam, ecam_alias);
+
+ /* Map the MMIO window into system address space so as to expose
+ * the section of PCI MMIO space which starts at the same base address
+ * (ie 1:1 mapping for that part of PCI MMIO space visible through
+ * the window).
+ */
+ mmio_alias = g_new0(MemoryRegion, 1);
+ mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+ memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
+ mmio_reg, base_mmio, size_mmio);
+ memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias);
+
+ /* Map IO port space */
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_ioport);
+
+ for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
+ }
+
+ nodename = g_strdup_printf("/pcie@%" PRIx64, base);
+ qemu_fdt_add_subnode(vbi->fdt, nodename);
+ qemu_fdt_setprop_string(vbi->fdt, nodename,
+ "compatible", "pci-host-ecam-generic");
+ qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "pci");
+ qemu_fdt_setprop_cell(vbi->fdt, nodename, "#address-cells", 3);
+ qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2);
+ qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0,
+ nr_pcie_buses - 1);
+
+ qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
+ 2, base_ecam, 2, size_ecam);
+ qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
+ 1, FDT_PCI_RANGE_IOPORT, 2, 0,
+ 2, base_ioport, 2, size_ioport,
+ 1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
+ 2, base_mmio, 2, size_mmio);
+
+ qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1);
+ create_pcie_irq_map(vbi, gic_phandle, irq, nodename);
+
+ g_free(nodename);
+}
+
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
{
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
@@ -602,15 +727,20 @@ static void machvirt_init(MachineState *machine)
MemoryRegion *ram = g_new(MemoryRegion, 1);
const char *cpu_model = machine->cpu_model;
VirtBoardInfo *vbi;
+ uint32_t gic_phandle;
+ char **cpustr;
if (!cpu_model) {
cpu_model = "cortex-a15";
}
- vbi = find_machine_info(cpu_model);
+ /* Separate the actual CPU model name from any appended features */
+ cpustr = g_strsplit(cpu_model, ",", 2);
+
+ vbi = find_machine_info(cpustr[0]);
if (!vbi) {
- error_report("mach-virt: CPU %s not supported", cpu_model);
+ error_report("mach-virt: CPU %s not supported", cpustr[0]);
exit(1);
}
@@ -624,8 +754,10 @@ static void machvirt_init(MachineState *machine)
create_fdt(vbi);
for (n = 0; n < smp_cpus; n++) {
- ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
+ ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]);
+ CPUClass *cc = CPU_CLASS(oc);
Object *cpuobj;
+ Error *err = NULL;
if (!oc) {
fprintf(stderr, "Unable to find CPU definition\n");
@@ -633,6 +765,13 @@ static void machvirt_init(MachineState *machine)
}
cpuobj = object_new(object_class_get_name(oc));
+ /* Handle any CPU options specified by the user */
+ cc->parse_features(CPU(cpuobj), cpustr[1], &err);
+ if (err) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+
if (!vms->secure) {
object_property_set_bool(cpuobj, false, "has_el3", NULL);
}
@@ -652,6 +791,7 @@ static void machvirt_init(MachineState *machine)
object_property_set_bool(cpuobj, true, "realized", NULL);
}
+ g_strfreev(cpustr);
fdt_add_timer_nodes(vbi);
fdt_add_cpu_nodes(vbi);
fdt_add_psci_node(vbi);
@@ -663,12 +803,14 @@ static void machvirt_init(MachineState *machine)
create_flash(vbi);
- create_gic(vbi, pic);
+ gic_phandle = create_gic(vbi, pic);
create_uart(vbi, pic);
create_rtc(vbi, pic);
+ create_pcie(vbi, pic, gic_phandle);
+
/* Create mmio transports, so the user can create virtio backends
* (which will be automatically plugged in to the transports). If
* no backend is created the transport will just sit harmlessly idle.
diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs
index bb65f9c4d2..45f1f0ebab 100644
--- a/hw/pci-host/Makefile.objs
+++ b/hw/pci-host/Makefile.objs
@@ -15,3 +15,4 @@ common-obj-$(CONFIG_PCI_APB) += apb.o
common-obj-$(CONFIG_FULONG) += bonito.o
common-obj-$(CONFIG_PCI_PIIX) += piix.o
common-obj-$(CONFIG_PCI_Q35) += q35.o
+common-obj-$(CONFIG_PCI_GENERIC) += gpex.o
diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c
new file mode 100644
index 0000000000..9d8fb5a496
--- /dev/null
+++ b/hw/pci-host/gpex.c
@@ -0,0 +1,154 @@
+/*
+ * QEMU Generic PCI Express Bridge Emulation
+ *
+ * Copyright (C) 2015 Alexander Graf <agraf@suse.de>
+ *
+ * Code loosely based on q35.c.
+ *
+ * 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.
+ *
+ * Check out these documents for more information on the device:
+ *
+ * http://www.kernel.org/doc/Documentation/devicetree/bindings/pci/host-generic-pci.txt
+ * http://www.firmware.org/1275/practice/imap/imap0_9d.pdf
+ */
+#include "hw/hw.h"
+#include "hw/pci-host/gpex.h"
+
+/****************************************************************************
+ * GPEX host
+ */
+
+static void gpex_set_irq(void *opaque, int irq_num, int level)
+{
+ GPEXHost *s = opaque;
+
+ qemu_set_irq(s->irq[irq_num], level);
+}
+
+static void gpex_host_realize(DeviceState *dev, Error **errp)
+{
+ PCIHostState *pci = PCI_HOST_BRIDGE(dev);
+ GPEXHost *s = GPEX_HOST(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
+ int i;
+
+ pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX);
+ memory_region_init(&s->io_mmio, OBJECT(s), "gpex_mmio", UINT64_MAX);
+ memory_region_init(&s->io_ioport, OBJECT(s), "gpex_ioport", 64 * 1024);
+
+ sysbus_init_mmio(sbd, &pex->mmio);
+ sysbus_init_mmio(sbd, &s->io_mmio);
+ sysbus_init_mmio(sbd, &s->io_ioport);
+ for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ sysbus_init_irq(sbd, &s->irq[i]);
+ }
+
+ pci->bus = pci_register_bus(dev, "pcie.0", gpex_set_irq,
+ pci_swizzle_map_irq_fn, s, &s->io_mmio,
+ &s->io_ioport, 0, 4, TYPE_PCIE_BUS);
+
+ qdev_set_parent_bus(DEVICE(&s->gpex_root), BUS(pci->bus));
+ qdev_init_nofail(DEVICE(&s->gpex_root));
+}
+
+static const char *gpex_host_root_bus_path(PCIHostState *host_bridge,
+ PCIBus *rootbus)
+{
+ return "0000:00";
+}
+
+static void gpex_host_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
+
+ hc->root_bus_path = gpex_host_root_bus_path;
+ dc->realize = gpex_host_realize;
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->fw_name = "pci";
+}
+
+static void gpex_host_initfn(Object *obj)
+{
+ GPEXHost *s = GPEX_HOST(obj);
+ GPEXRootState *root = &s->gpex_root;
+
+ object_initialize(root, sizeof(*root), TYPE_GPEX_ROOT_DEVICE);
+ object_property_add_child(obj, "gpex_root", OBJECT(root), NULL);
+ qdev_prop_set_uint32(DEVICE(root), "addr", PCI_DEVFN(0, 0));
+ qdev_prop_set_bit(DEVICE(root), "multifunction", false);
+}
+
+static const TypeInfo gpex_host_info = {
+ .name = TYPE_GPEX_HOST,
+ .parent = TYPE_PCIE_HOST_BRIDGE,
+ .instance_size = sizeof(GPEXHost),
+ .instance_init = gpex_host_initfn,
+ .class_init = gpex_host_class_init,
+};
+
+/****************************************************************************
+ * GPEX Root D0:F0
+ */
+
+static const VMStateDescription vmstate_gpex_root = {
+ .name = "gpex_root",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(parent_obj, GPEXRootState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void gpex_root_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->desc = "QEMU generic PCIe host bridge";
+ dc->vmsd = &vmstate_gpex_root;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT;
+ k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_HOST;
+ k->revision = 0;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+ /*
+ * PCI-facing part of the host bridge, not usable without the
+ * host-facing part, which can't be device_add'ed, yet.
+ */
+ dc->cannot_instantiate_with_device_add_yet = true;
+}
+
+static const TypeInfo gpex_root_info = {
+ .name = TYPE_GPEX_ROOT_DEVICE,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(GPEXRootState),
+ .class_init = gpex_root_class_init,
+};
+
+static void gpex_register(void)
+{
+ type_register_static(&gpex_root_info);
+ type_register_static(&gpex_host_info);
+}
+
+type_init(gpex_register)
diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h
new file mode 100644
index 0000000000..68c93488c9
--- /dev/null
+++ b/include/hw/pci-host/gpex.h
@@ -0,0 +1,56 @@
+/*
+ * QEMU Generic PCI Express Bridge Emulation
+ *
+ * Copyright (C) 2015 Alexander Graf <agraf@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#ifndef HW_GPEX_H
+#define HW_GPEX_H
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pcie_host.h"
+
+#define TYPE_GPEX_HOST "gpex-pcihost"
+#define GPEX_HOST(obj) \
+ OBJECT_CHECK(GPEXHost, (obj), TYPE_GPEX_HOST)
+
+#define TYPE_GPEX_ROOT_DEVICE "gpex-root"
+#define MCH_PCI_DEVICE(obj) \
+ OBJECT_CHECK(GPEXRootState, (obj), TYPE_GPEX_ROOT_DEVICE)
+
+#define GPEX_NUM_IRQS 4
+
+typedef struct GPEXRootState {
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+} GPEXRootState;
+
+typedef struct GPEXHost {
+ /*< private >*/
+ PCIExpressHost parent_obj;
+ /*< public >*/
+
+ GPEXRootState gpex_root;
+
+ MemoryRegion io_ioport;
+ MemoryRegion io_mmio;
+ qemu_irq irq[GPEX_NUM_IRQS];
+} GPEXHost;
+
+#endif /* HW_GPEX_H */
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 97a83d362f..bdee464e61 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -89,6 +89,7 @@
#define PCI_DEVICE_ID_REDHAT_SERIAL4 0x0004
#define PCI_DEVICE_ID_REDHAT_TEST 0x0005
#define PCI_DEVICE_ID_REDHAT_SDHCI 0x0007
+#define PCI_DEVICE_ID_REDHAT_PCIE_HOST 0x0008
#define PCI_DEVICE_ID_REDHAT_QXL 0x0100
#define FMT_PCIBUS PRIx64
diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h
index 899f05c138..359e14304f 100644
--- a/include/sysemu/device_tree.h
+++ b/include/sysemu/device_tree.h
@@ -110,4 +110,13 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
qdt_tmp); \
})
+#define FDT_PCI_RANGE_RELOCATABLE 0x80000000
+#define FDT_PCI_RANGE_PREFETCHABLE 0x40000000
+#define FDT_PCI_RANGE_ALIASED 0x20000000
+#define FDT_PCI_RANGE_TYPE_MASK 0x03000000
+#define FDT_PCI_RANGE_MMIO_64BIT 0x03000000
+#define FDT_PCI_RANGE_MMIO 0x02000000
+#define FDT_PCI_RANGE_IOPORT 0x01000000
+#define FDT_PCI_RANGE_CONFIG 0x00000000
+
#endif /* __DEVICE_TREE_H__ */
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index d38af747ac..986f04cfd6 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -544,13 +544,16 @@ static ObjectClass *arm_cpu_class_by_name(const char *cpu_model)
{
ObjectClass *oc;
char *typename;
+ char **cpuname;
if (!cpu_model) {
return NULL;
}
- typename = g_strdup_printf("%s-" TYPE_ARM_CPU, cpu_model);
+ cpuname = g_strsplit(cpu_model, ",", 1);
+ typename = g_strdup_printf("%s-" TYPE_ARM_CPU, cpuname[0]);
oc = object_class_by_name(typename);
+ g_strfreev(cpuname);
g_free(typename);
if (!oc || !object_class_dynamic_cast(oc, TYPE_ARM_CPU) ||
object_class_is_abstract(oc)) {
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 1830a12d4a..11845a6644 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -495,6 +495,8 @@ typedef struct CPUARMState {
ARMCPU *cpu_arm_init(const char *cpu_model);
int cpu_arm_exec(CPUARMState *s);
uint32_t do_arm_semihosting(CPUARMState *env);
+void aarch64_sync_32_to_64(CPUARMState *env);
+void aarch64_sync_64_to_32(CPUARMState *env);
static inline bool is_a64(CPUARMState *env)
{
diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
index bb778b3d92..823c739f08 100644
--- a/target-arm/cpu64.c
+++ b/target-arm/cpu64.c
@@ -32,6 +32,11 @@ static inline void set_feature(CPUARMState *env, int feature)
env->features |= 1ULL << feature;
}
+static inline void unset_feature(CPUARMState *env, int feature)
+{
+ env->features &= ~(1ULL << feature);
+}
+
#ifndef CONFIG_USER_ONLY
static uint64_t a57_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
@@ -170,8 +175,42 @@ static const ARMCPUInfo aarch64_cpus[] = {
{ .name = NULL }
};
+static bool aarch64_cpu_get_aarch64(Object *obj, Error **errp)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+
+ return arm_feature(&cpu->env, ARM_FEATURE_AARCH64);
+}
+
+static void aarch64_cpu_set_aarch64(Object *obj, bool value, Error **errp)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+
+ /* At this time, this property is only allowed if KVM is enabled. This
+ * restriction allows us to avoid fixing up functionality that assumes a
+ * uniform execution state like do_interrupt.
+ */
+ if (!kvm_enabled()) {
+ error_setg(errp, "'aarch64' feature cannot be disabled "
+ "unless KVM is enabled");
+ return;
+ }
+
+ if (value == false) {
+ unset_feature(&cpu->env, ARM_FEATURE_AARCH64);
+ } else {
+ set_feature(&cpu->env, ARM_FEATURE_AARCH64);
+ }
+}
+
static void aarch64_cpu_initfn(Object *obj)
{
+ object_property_add_bool(obj, "aarch64", aarch64_cpu_get_aarch64,
+ aarch64_cpu_set_aarch64, NULL);
+ object_property_set_description(obj, "aarch64",
+ "Set on/off to enable/disable aarch64 "
+ "execution state ",
+ NULL);
}
static void aarch64_cpu_finalizefn(Object *obj)
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index 8aa40e9763..7e0d038563 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -466,7 +466,6 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
unsigned int new_el = arm_excp_target_el(cs, cs->exception_index);
target_ulong addr = env->cp15.vbar_el[new_el];
unsigned int new_mode = aarch64_pstate_mode(new_el, true);
- int i;
if (arm_current_el(env) < new_el) {
if (env->aarch64) {
@@ -530,9 +529,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
}
env->elr_el[new_el] = env->regs[15];
- for (i = 0; i < 15; i++) {
- env->xregs[i] = env->regs[i];
- }
+ aarch64_sync_32_to_64(env);
env->condexec_bits = 0;
}
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 1a1a00577e..3bc20af04f 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -4096,6 +4096,11 @@ unsigned int arm_excp_target_el(CPUState *cs, unsigned int excp_idx)
return 1;
}
+void aarch64_sync_64_to_32(CPUARMState *env)
+{
+ g_assert_not_reached();
+}
+
#else
/* Map CPU modes onto saved register banks. */
@@ -4425,6 +4430,212 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
env->thumb = addr & 1;
}
+/* Function used to synchronize QEMU's AArch64 register set with AArch32
+ * register set. This is necessary when switching between AArch32 and AArch64
+ * execution state.
+ */
+void aarch64_sync_32_to_64(CPUARMState *env)
+{
+ int i;
+ uint32_t mode = env->uncached_cpsr & CPSR_M;
+
+ /* We can blanket copy R[0:7] to X[0:7] */
+ for (i = 0; i < 8; i++) {
+ env->xregs[i] = env->regs[i];
+ }
+
+ /* Unless we are in FIQ mode, x8-x12 come from the user registers r8-r12.
+ * Otherwise, they come from the banked user regs.
+ */
+ if (mode == ARM_CPU_MODE_FIQ) {
+ for (i = 8; i < 13; i++) {
+ env->xregs[i] = env->usr_regs[i - 8];
+ }
+ } else {
+ for (i = 8; i < 13; i++) {
+ env->xregs[i] = env->regs[i];
+ }
+ }
+
+ /* Registers x13-x23 are the various mode SP and FP registers. Registers
+ * r13 and r14 are only copied if we are in that mode, otherwise we copy
+ * from the mode banked register.
+ */
+ if (mode == ARM_CPU_MODE_USR || mode == ARM_CPU_MODE_SYS) {
+ env->xregs[13] = env->regs[13];
+ env->xregs[14] = env->regs[14];
+ } else {
+ env->xregs[13] = env->banked_r13[bank_number(ARM_CPU_MODE_USR)];
+ /* HYP is an exception in that it is copied from r14 */
+ if (mode == ARM_CPU_MODE_HYP) {
+ env->xregs[14] = env->regs[14];
+ } else {
+ env->xregs[14] = env->banked_r14[bank_number(ARM_CPU_MODE_USR)];
+ }
+ }
+
+ if (mode == ARM_CPU_MODE_HYP) {
+ env->xregs[15] = env->regs[13];
+ } else {
+ env->xregs[15] = env->banked_r13[bank_number(ARM_CPU_MODE_HYP)];
+ }
+
+ if (mode == ARM_CPU_MODE_IRQ) {
+ env->xregs[16] = env->regs[13];
+ env->xregs[17] = env->regs[14];
+ } else {
+ env->xregs[16] = env->banked_r13[bank_number(ARM_CPU_MODE_IRQ)];
+ env->xregs[17] = env->banked_r14[bank_number(ARM_CPU_MODE_IRQ)];
+ }
+
+ if (mode == ARM_CPU_MODE_SVC) {
+ env->xregs[18] = env->regs[13];
+ env->xregs[19] = env->regs[14];
+ } else {
+ env->xregs[18] = env->banked_r13[bank_number(ARM_CPU_MODE_SVC)];
+ env->xregs[19] = env->banked_r14[bank_number(ARM_CPU_MODE_SVC)];
+ }
+
+ if (mode == ARM_CPU_MODE_ABT) {
+ env->xregs[20] = env->regs[13];
+ env->xregs[21] = env->regs[14];
+ } else {
+ env->xregs[20] = env->banked_r13[bank_number(ARM_CPU_MODE_ABT)];
+ env->xregs[21] = env->banked_r14[bank_number(ARM_CPU_MODE_ABT)];
+ }
+
+ if (mode == ARM_CPU_MODE_UND) {
+ env->xregs[22] = env->regs[13];
+ env->xregs[23] = env->regs[14];
+ } else {
+ env->xregs[22] = env->banked_r13[bank_number(ARM_CPU_MODE_UND)];
+ env->xregs[23] = env->banked_r14[bank_number(ARM_CPU_MODE_UND)];
+ }
+
+ /* Registers x24-x30 are mapped to r8-r14 in FIQ mode. If we are in FIQ
+ * mode, then we can copy from r8-r14. Otherwise, we copy from the
+ * FIQ bank for r8-r14.
+ */
+ if (mode == ARM_CPU_MODE_FIQ) {
+ for (i = 24; i < 31; i++) {
+ env->xregs[i] = env->regs[i - 16]; /* X[24:30] <- R[8:14] */
+ }
+ } else {
+ for (i = 24; i < 29; i++) {
+ env->xregs[i] = env->fiq_regs[i - 24];
+ }
+ env->xregs[29] = env->banked_r13[bank_number(ARM_CPU_MODE_FIQ)];
+ env->xregs[30] = env->banked_r14[bank_number(ARM_CPU_MODE_FIQ)];
+ }
+
+ env->pc = env->regs[15];
+}
+
+/* Function used to synchronize QEMU's AArch32 register set with AArch64
+ * register set. This is necessary when switching between AArch32 and AArch64
+ * execution state.
+ */
+void aarch64_sync_64_to_32(CPUARMState *env)
+{
+ int i;
+ uint32_t mode = env->uncached_cpsr & CPSR_M;
+
+ /* We can blanket copy X[0:7] to R[0:7] */
+ for (i = 0; i < 8; i++) {
+ env->regs[i] = env->xregs[i];
+ }
+
+ /* Unless we are in FIQ mode, r8-r12 come from the user registers x8-x12.
+ * Otherwise, we copy x8-x12 into the banked user regs.
+ */
+ if (mode == ARM_CPU_MODE_FIQ) {
+ for (i = 8; i < 13; i++) {
+ env->usr_regs[i - 8] = env->xregs[i];
+ }
+ } else {
+ for (i = 8; i < 13; i++) {
+ env->regs[i] = env->xregs[i];
+ }
+ }
+
+ /* Registers r13 & r14 depend on the current mode.
+ * If we are in a given mode, we copy the corresponding x registers to r13
+ * and r14. Otherwise, we copy the x register to the banked r13 and r14
+ * for the mode.
+ */
+ if (mode == ARM_CPU_MODE_USR || mode == ARM_CPU_MODE_SYS) {
+ env->regs[13] = env->xregs[13];
+ env->regs[14] = env->xregs[14];
+ } else {
+ env->banked_r13[bank_number(ARM_CPU_MODE_USR)] = env->xregs[13];
+
+ /* HYP is an exception in that it does not have its own banked r14 but
+ * shares the USR r14
+ */
+ if (mode == ARM_CPU_MODE_HYP) {
+ env->regs[14] = env->xregs[14];
+ } else {
+ env->banked_r14[bank_number(ARM_CPU_MODE_USR)] = env->xregs[14];
+ }
+ }
+
+ if (mode == ARM_CPU_MODE_HYP) {
+ env->regs[13] = env->xregs[15];
+ } else {
+ env->banked_r13[bank_number(ARM_CPU_MODE_HYP)] = env->xregs[15];
+ }
+
+ if (mode == ARM_CPU_MODE_IRQ) {
+ env->regs[13] = env->xregs[16];
+ env->regs[14] = env->xregs[17];
+ } else {
+ env->banked_r13[bank_number(ARM_CPU_MODE_IRQ)] = env->xregs[16];
+ env->banked_r14[bank_number(ARM_CPU_MODE_IRQ)] = env->xregs[17];
+ }
+
+ if (mode == ARM_CPU_MODE_SVC) {
+ env->regs[13] = env->xregs[18];
+ env->regs[14] = env->xregs[19];
+ } else {
+ env->banked_r13[bank_number(ARM_CPU_MODE_SVC)] = env->xregs[18];
+ env->banked_r14[bank_number(ARM_CPU_MODE_SVC)] = env->xregs[19];
+ }
+
+ if (mode == ARM_CPU_MODE_ABT) {
+ env->regs[13] = env->xregs[20];
+ env->regs[14] = env->xregs[21];
+ } else {
+ env->banked_r13[bank_number(ARM_CPU_MODE_ABT)] = env->xregs[20];
+ env->banked_r14[bank_number(ARM_CPU_MODE_ABT)] = env->xregs[21];
+ }
+
+ if (mode == ARM_CPU_MODE_UND) {
+ env->regs[13] = env->xregs[22];
+ env->regs[14] = env->xregs[23];
+ } else {
+ env->banked_r13[bank_number(ARM_CPU_MODE_UND)] = env->xregs[22];
+ env->banked_r14[bank_number(ARM_CPU_MODE_UND)] = env->xregs[23];
+ }
+
+ /* Registers x24-x30 are mapped to r8-r14 in FIQ mode. If we are in FIQ
+ * mode, then we can copy to r8-r14. Otherwise, we copy to the
+ * FIQ bank for r8-r14.
+ */
+ if (mode == ARM_CPU_MODE_FIQ) {
+ for (i = 24; i < 31; i++) {
+ env->regs[i - 16] = env->xregs[i]; /* X[24:30] -> R[8:14] */
+ }
+ } else {
+ for (i = 24; i < 29; i++) {
+ env->fiq_regs[i - 24] = env->xregs[i];
+ }
+ env->banked_r13[bank_number(ARM_CPU_MODE_FIQ)] = env->xregs[29];
+ env->banked_r14[bank_number(ARM_CPU_MODE_FIQ)] = env->xregs[30];
+ }
+
+ env->regs[15] = env->pc;
+}
+
/* Handle a CPU exception. */
void arm_cpu_do_interrupt(CPUState *cs)
{
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index 033babf551..8cf3a627ec 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -82,7 +82,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
ARMCPU *cpu = ARM_CPU(cs);
if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
- !arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
+ !object_dynamic_cast(OBJECT(cpu), TYPE_AARCH64_CPU)) {
fprintf(stderr, "KVM is not supported for this guest CPU type\n");
return -EINVAL;
}
@@ -96,6 +96,9 @@ int kvm_arch_init_vcpu(CPUState *cs)
cpu->psci_version = 2;
cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2;
}
+ if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
+ cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT;
+ }
/* Do KVM_ARM_VCPU_INIT ioctl */
ret = kvm_arm_vcpu_init(cs);
@@ -133,6 +136,13 @@ int kvm_arch_put_registers(CPUState *cs, int level)
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
+ /* If we are in AArch32 mode then we need to copy the AArch32 regs to the
+ * AArch64 registers before pushing them out to 64-bit KVM.
+ */
+ if (!is_a64(env)) {
+ aarch64_sync_32_to_64(env);
+ }
+
for (i = 0; i < 31; i++) {
reg.id = AARCH64_CORE_REG(regs.regs[i]);
reg.addr = (uintptr_t) &env->xregs[i];
@@ -162,7 +172,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
}
/* Note that KVM thinks pstate is 64 bit but we use a uint32_t */
- val = pstate_read(env);
+ if (is_a64(env)) {
+ val = pstate_read(env);
+ } else {
+ val = cpsr_read(env);
+ }
reg.id = AARCH64_CORE_REG(regs.pstate);
reg.addr = (uintptr_t) &val;
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
@@ -242,7 +256,14 @@ int kvm_arch_get_registers(CPUState *cs)
if (ret) {
return ret;
}
- pstate_write(env, val);
+
+ env->aarch64 = ((val & PSTATE_nRW) == 0);
+ if (is_a64(env)) {
+ pstate_write(env, val);
+ } else {
+ env->uncached_cpsr = val & CPSR_M;
+ cpsr_write(env, val, 0xffffffff);
+ }
/* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
* QEMU side we keep the current SP in xregs[31] as well.
@@ -256,6 +277,15 @@ int kvm_arch_get_registers(CPUState *cs)
return ret;
}
+ /* If we are in AArch32 mode then we need to sync the AArch32 regs with the
+ * incoming AArch64 regs received from 64-bit KVM.
+ * We must perform this after all of the registers have been acquired from
+ * the kernel.
+ */
+ if (!is_a64(env)) {
+ aarch64_sync_64_to_32(env);
+ }
+
reg.id = AARCH64_CORE_REG(elr_el1);
reg.addr = (uintptr_t) &env->elr_el[1];
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 2bed914770..7713022752 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -465,7 +465,7 @@ void HELPER(exception_return)(CPUARMState *env)
int cur_el = arm_current_el(env);
unsigned int spsr_idx = aarch64_banked_spsr_index(cur_el);
uint32_t spsr = env->banked_spsr[spsr_idx];
- int new_el, i;
+ int new_el;
aarch64_save_sp(env, cur_el);
@@ -491,9 +491,7 @@ void HELPER(exception_return)(CPUARMState *env)
if (!arm_singlestep_active(env)) {
env->uncached_cpsr &= ~PSTATE_SS;
}
- for (i = 0; i < 15; i++) {
- env->regs[i] = env->xregs[i];
- }
+ aarch64_sync_64_to_32(env);
env->regs[15] = env->elr_el[1] & ~0x1;
} else {
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index acf4b162bd..9f54501a9e 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1077,7 +1077,7 @@ static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
{
uint64_t addr = s->pc + sextract32(insn, 0, 26) * 4 - 4;
- if (insn & (1 << 31)) {
+ if (insn & (1U << 31)) {
/* C5.6.26 BL Branch with link */
tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
}
@@ -1271,7 +1271,7 @@ static void gen_get_nzcv(TCGv_i64 tcg_rt)
TCGv_i32 nzcv = tcg_temp_new_i32();
/* build bit 31, N */
- tcg_gen_andi_i32(nzcv, cpu_NF, (1 << 31));
+ tcg_gen_andi_i32(nzcv, cpu_NF, (1U << 31));
/* build bit 30, Z */
tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_ZF, 0);
tcg_gen_deposit_i32(nzcv, nzcv, tmp, 30, 1);
@@ -1296,7 +1296,7 @@ static void gen_set_nzcv(TCGv_i64 tcg_rt)
tcg_gen_trunc_i64_i32(nzcv, tcg_rt);
/* bit 31, N */
- tcg_gen_andi_i32(cpu_NF, nzcv, (1 << 31));
+ tcg_gen_andi_i32(cpu_NF, nzcv, (1U << 31));
/* bit 30, Z */
tcg_gen_andi_i32(cpu_ZF, nzcv, (1 << 30));
tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_ZF, cpu_ZF, 0);
@@ -1917,7 +1917,7 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
int rt = extract32(insn, 0, 5);
int rn = extract32(insn, 5, 5);
int rt2 = extract32(insn, 10, 5);
- int64_t offset = sextract32(insn, 15, 7);
+ uint64_t offset = sextract64(insn, 15, 7);
int index = extract32(insn, 23, 2);
bool is_vector = extract32(insn, 26, 1);
bool is_load = extract32(insn, 22, 1);
@@ -2662,11 +2662,12 @@ static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
{
unsigned int page, rd;
uint64_t base;
- int64_t offset;
+ uint64_t offset;
page = extract32(insn, 31, 1);
/* SignExtend(immhi:immlo) -> offset */
- offset = ((int64_t)sextract32(insn, 5, 19) << 2) | extract32(insn, 29, 2);
+ offset = sextract64(insn, 5, 19);
+ offset = offset << 2 | extract32(insn, 29, 2);
rd = extract32(insn, 0, 5);
base = s->pc - 4;
@@ -2820,7 +2821,10 @@ static bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn,
* by r within the element (which is e bits wide)...
*/
mask = bitmask64(s + 1);
- mask = (mask >> r) | (mask << (e - r));
+ if (r) {
+ mask = (mask >> r) | (mask << (e - r));
+ mask &= bitmask64(e);
+ }
/* ...then replicate the element over the whole 64 bit value */
mask = bitfield_replicate(mask, e);
*result = mask;