Răsfoiți Sursa

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20150615' into staging

target-arm queue:
 * Handle "extended small page" descriptors correctly
 * Use extended address bits from supersection short descriptors
 * Update interrupt status for all cores in gic_update
 * Fix off-by-one in exynos4210_fimd bit-swap code
 * Remove stray unused 'pending_exception' field
 * Add Cortex-A53 KVM support
 * Fix reset value of REVIDR
 * Add AArch32 MIDR aliases for ARMv8 cores
 * MAINTAINERS update for ARM ACPI code
 * Trust the kernel's value of MPIDR if we're using KVM
 * Various pxa2xx device updates to avoid old APIs
 * Mark pxa2xx copro registers as ARM_CP_IO so -icount works
 * Correctly UNDEF Thumb2 DSP insns on Cortex-M3
 * Initial work towards implementing PMSAv7
 * Fix a reset order bug introduced recently
 * Correct "preferred return address" for cpreg access exceptions
 * Add ACPI SPCR table for the virt board

# gpg: Signature made Mon Jun 15 18:19:34 2015 BST using RSA key ID 14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"

* remotes/pmaydell/tags/pull-target-arm-20150615: (28 commits)
  hw/arm/virt-acpi-build: Add SPCR table
  ACPI: Add definitions for the SPCR table
  target-arm: Correct "preferred return address" for cpreg access exceptions
  hw/arm/boot: fix rom_reset notifier registration order
  arm: helper: rename get_phys_addr_mpu
  arm: Add has-mpu property
  arm: Implement uniprocessor with MP config
  arm: Refactor get_phys_addr FSR return mechanism
  arm: helper: Factor out CP regs common to [pv]msa
  arm: Don't add v7mp registers in MPU systems
  arm: Do not define TLBTR in PMSA systems
  target-arm: Add the THUMB_DSP feature
  hw/sd/pxa2xx_mmci: Stop using old_mmio in MemoryRegionOps
  hw/arm/pxa2xx: Convert pxa2xx-ssp to VMState
  hw/arm/pxa2xx: Add reset method for pxa2xx_ssp
  hw/arm/pxa2xx: Convert pxa2xx-fir to QOM and VMState
  hw/arm/pxa2xx: Mark coprocessor registers as ARM_CP_IO
  target-arm: Use the kernel's idea of MPIDR if we're using KVM
  MAINTAINERS: Add myself as ARM ACPI Subsystem maintainer
  target-arm: add AArch32 MIDR aliases in ARMv8
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Peter Maydell 10 ani în urmă
părinte
comite
1dfe73b94d

+ 7 - 0
MAINTAINERS

@@ -356,6 +356,13 @@ F: hw/misc/zynq_slcr.c
 F: hw/*/cadence_*
 F: hw/*/cadence_*
 F: hw/ssi/xilinx_spips.c
 F: hw/ssi/xilinx_spips.c
 
 
+ARM ACPI Subsystem
+M: Shannon Zhao <zhaoshenglong@huawei.com>
+M: Shannon Zhao <shannon.zhao@linaro.org>
+S: Maintained
+F: hw/arm/virt-acpi-build.c
+F: include/hw/arm/virt-acpi-build.h
+
 CRIS Machines
 CRIS Machines
 -------------
 -------------
 Axis Dev88
 Axis Dev88

+ 11 - 9
hw/arm/boot.c

@@ -574,15 +574,6 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
     struct arm_boot_info *info =
     struct arm_boot_info *info =
         container_of(n, struct arm_boot_info, load_kernel_notifier);
         container_of(n, struct arm_boot_info, load_kernel_notifier);
 
 
-    /* CPU objects (unlike devices) are not automatically reset on system
-     * reset, so we must always register a handler to do so. If we're
-     * actually loading a kernel, the handler is also responsible for
-     * arranging that we start it correctly.
-     */
-    for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) {
-        qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
-    }
-
     /* Load the kernel.  */
     /* Load the kernel.  */
     if (!info->kernel_filename || info->firmware_loaded) {
     if (!info->kernel_filename || info->firmware_loaded) {
 
 
@@ -783,7 +774,18 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
 
 
 void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
 void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
 {
 {
+    CPUState *cs;
+
     info->load_kernel_notifier.cpu = cpu;
     info->load_kernel_notifier.cpu = cpu;
     info->load_kernel_notifier.notifier.notify = arm_load_kernel_notify;
     info->load_kernel_notifier.notifier.notify = arm_load_kernel_notify;
     qemu_add_machine_init_done_notifier(&info->load_kernel_notifier.notifier);
     qemu_add_machine_init_done_notifier(&info->load_kernel_notifier.notifier);
+
+    /* CPU objects (unlike devices) are not automatically reset on system
+     * reset, so we must always register a handler to do so. If we're
+     * actually loading a kernel, the handler is also responsible for
+     * arranging that we start it correctly.
+     */
+    for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) {
+        qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
+    }
 }
 }

+ 137 - 111
hw/arm/pxa2xx.c

@@ -334,10 +334,10 @@ static uint64_t pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
 static const ARMCPRegInfo pxa_cp_reginfo[] = {
 static const ARMCPRegInfo pxa_cp_reginfo[] = {
     /* cp14 crm==1: perf registers */
     /* cp14 crm==1: perf registers */
     { .name = "CPPMNC", .cp = 14, .crn = 0, .crm = 1, .opc1 = 0, .opc2 = 0,
     { .name = "CPPMNC", .cp = 14, .crn = 0, .crm = 1, .opc1 = 0, .opc2 = 0,
-      .access = PL1_RW,
+      .access = PL1_RW, .type = ARM_CP_IO,
       .readfn = pxa2xx_cppmnc_read, .writefn = pxa2xx_cppmnc_write },
       .readfn = pxa2xx_cppmnc_read, .writefn = pxa2xx_cppmnc_write },
     { .name = "CPCCNT", .cp = 14, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
     { .name = "CPCCNT", .cp = 14, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
-      .access = PL1_RW,
+      .access = PL1_RW, .type = ARM_CP_IO,
       .readfn = pxa2xx_cpccnt_read, .writefn = arm_cp_write_ignore },
       .readfn = pxa2xx_cpccnt_read, .writefn = arm_cp_write_ignore },
     { .name = "CPINTEN", .cp = 14, .crn = 4, .crm = 1, .opc1 = 0, .opc2 = 0,
     { .name = "CPINTEN", .cp = 14, .crn = 4, .crm = 1, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
@@ -356,11 +356,11 @@ static const ARMCPRegInfo pxa_cp_reginfo[] = {
       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
       .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
     /* cp14 crn==6: CLKCFG */
     /* cp14 crn==6: CLKCFG */
     { .name = "CLKCFG", .cp = 14, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
     { .name = "CLKCFG", .cp = 14, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
-      .access = PL1_RW,
+      .access = PL1_RW, .type = ARM_CP_IO,
       .readfn = pxa2xx_clkcfg_read, .writefn = pxa2xx_clkcfg_write },
       .readfn = pxa2xx_clkcfg_read, .writefn = pxa2xx_clkcfg_write },
     /* cp14 crn==7: PWRMODE */
     /* cp14 crn==7: PWRMODE */
     { .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0,
     { .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0,
-      .access = PL1_RW,
+      .access = PL1_RW, .type = ARM_CP_IO,
       .readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write },
       .readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write },
     REGINFO_SENTINEL
     REGINFO_SENTINEL
 };
 };
@@ -457,7 +457,7 @@ typedef struct {
 
 
     MemoryRegion iomem;
     MemoryRegion iomem;
     qemu_irq irq;
     qemu_irq irq;
-    int enable;
+    uint32_t enable;
     SSIBus *bus;
     SSIBus *bus;
 
 
     uint32_t sscr[2];
     uint32_t sscr[2];
@@ -470,10 +470,39 @@ typedef struct {
     uint8_t ssacd;
     uint8_t ssacd;
 
 
     uint32_t rx_fifo[16];
     uint32_t rx_fifo[16];
-    int rx_level;
-    int rx_start;
+    uint32_t rx_level;
+    uint32_t rx_start;
 } PXA2xxSSPState;
 } PXA2xxSSPState;
 
 
+static bool pxa2xx_ssp_vmstate_validate(void *opaque, int version_id)
+{
+    PXA2xxSSPState *s = opaque;
+
+    return s->rx_start < sizeof(s->rx_fifo);
+}
+
+static const VMStateDescription vmstate_pxa2xx_ssp = {
+    .name = "pxa2xx-ssp",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(enable, PXA2xxSSPState),
+        VMSTATE_UINT32_ARRAY(sscr, PXA2xxSSPState, 2),
+        VMSTATE_UINT32(sspsp, PXA2xxSSPState),
+        VMSTATE_UINT32(ssto, PXA2xxSSPState),
+        VMSTATE_UINT32(ssitr, PXA2xxSSPState),
+        VMSTATE_UINT32(sssr, PXA2xxSSPState),
+        VMSTATE_UINT8(sstsa, PXA2xxSSPState),
+        VMSTATE_UINT8(ssrsa, PXA2xxSSPState),
+        VMSTATE_UINT8(ssacd, PXA2xxSSPState),
+        VMSTATE_UINT32(rx_level, PXA2xxSSPState),
+        VMSTATE_UINT32(rx_start, PXA2xxSSPState),
+        VMSTATE_VALIDATE("fifo is 16 bytes", pxa2xx_ssp_vmstate_validate),
+        VMSTATE_UINT32_ARRAY(rx_fifo, PXA2xxSSPState, 16),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 #define SSCR0	0x00	/* SSP Control register 0 */
 #define SSCR0	0x00	/* SSP Control register 0 */
 #define SSCR1	0x04	/* SSP Control register 1 */
 #define SSCR1	0x04	/* SSP Control register 1 */
 #define SSSR	0x08	/* SSP Status register */
 #define SSSR	0x08	/* SSP Status register */
@@ -705,55 +734,20 @@ static const MemoryRegionOps pxa2xx_ssp_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 };
 
 
-static void pxa2xx_ssp_save(QEMUFile *f, void *opaque)
+static void pxa2xx_ssp_reset(DeviceState *d)
 {
 {
-    PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
-    int i;
-
-    qemu_put_be32(f, s->enable);
+    PXA2xxSSPState *s = PXA2XX_SSP(d);
 
 
-    qemu_put_be32s(f, &s->sscr[0]);
-    qemu_put_be32s(f, &s->sscr[1]);
-    qemu_put_be32s(f, &s->sspsp);
-    qemu_put_be32s(f, &s->ssto);
-    qemu_put_be32s(f, &s->ssitr);
-    qemu_put_be32s(f, &s->sssr);
-    qemu_put_8s(f, &s->sstsa);
-    qemu_put_8s(f, &s->ssrsa);
-    qemu_put_8s(f, &s->ssacd);
-
-    qemu_put_byte(f, s->rx_level);
-    for (i = 0; i < s->rx_level; i ++)
-        qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 0xf]);
-}
-
-static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id)
-{
-    PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
-    int i, v;
-
-    s->enable = qemu_get_be32(f);
-
-    qemu_get_be32s(f, &s->sscr[0]);
-    qemu_get_be32s(f, &s->sscr[1]);
-    qemu_get_be32s(f, &s->sspsp);
-    qemu_get_be32s(f, &s->ssto);
-    qemu_get_be32s(f, &s->ssitr);
-    qemu_get_be32s(f, &s->sssr);
-    qemu_get_8s(f, &s->sstsa);
-    qemu_get_8s(f, &s->ssrsa);
-    qemu_get_8s(f, &s->ssacd);
-
-    v = qemu_get_byte(f);
-    if (v < 0 || v > ARRAY_SIZE(s->rx_fifo)) {
-        return -EINVAL;
-    }
-    s->rx_level = v;
-    s->rx_start = 0;
-    for (i = 0; i < s->rx_level; i ++)
-        s->rx_fifo[i] = qemu_get_byte(f);
-
-    return 0;
+    s->enable = 0;
+    s->sscr[0] = s->sscr[1] = 0;
+    s->sspsp = 0;
+    s->ssto = 0;
+    s->ssitr = 0;
+    s->sssr = 0;
+    s->sstsa = 0;
+    s->ssrsa = 0;
+    s->ssacd = 0;
+    s->rx_start = s->rx_level = 0;
 }
 }
 
 
 static int pxa2xx_ssp_init(SysBusDevice *sbd)
 static int pxa2xx_ssp_init(SysBusDevice *sbd)
@@ -766,8 +760,6 @@ static int pxa2xx_ssp_init(SysBusDevice *sbd)
     memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_ssp_ops, s,
     memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_ssp_ops, s,
                           "pxa2xx-ssp", 0x1000);
                           "pxa2xx-ssp", 0x1000);
     sysbus_init_mmio(sbd, &s->iomem);
     sysbus_init_mmio(sbd, &s->iomem);
-    register_savevm(dev, "pxa2xx_ssp", -1, 0,
-                    pxa2xx_ssp_save, pxa2xx_ssp_load, s);
 
 
     s->bus = ssi_create_bus(dev, "ssi");
     s->bus = ssi_create_bus(dev, "ssi");
     return 0;
     return 0;
@@ -1759,24 +1751,33 @@ static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem,
 }
 }
 
 
 /* PXA Fast Infra-red Communications Port */
 /* PXA Fast Infra-red Communications Port */
+#define TYPE_PXA2XX_FIR "pxa2xx-fir"
+#define PXA2XX_FIR(obj) OBJECT_CHECK(PXA2xxFIrState, (obj), TYPE_PXA2XX_FIR)
+
 struct PXA2xxFIrState {
 struct PXA2xxFIrState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    /*< public >*/
+
     MemoryRegion iomem;
     MemoryRegion iomem;
     qemu_irq irq;
     qemu_irq irq;
     qemu_irq rx_dma;
     qemu_irq rx_dma;
     qemu_irq tx_dma;
     qemu_irq tx_dma;
-    int enable;
+    uint32_t enable;
     CharDriverState *chr;
     CharDriverState *chr;
 
 
     uint8_t control[3];
     uint8_t control[3];
     uint8_t status[2];
     uint8_t status[2];
 
 
-    int rx_len;
-    int rx_start;
+    uint32_t rx_len;
+    uint32_t rx_start;
     uint8_t rx_fifo[64];
     uint8_t rx_fifo[64];
 };
 };
 
 
-static void pxa2xx_fir_reset(PXA2xxFIrState *s)
+static void pxa2xx_fir_reset(DeviceState *d)
 {
 {
+    PXA2xxFIrState *s = PXA2XX_FIR(d);
+
     s->control[0] = 0x00;
     s->control[0] = 0x00;
     s->control[1] = 0x00;
     s->control[1] = 0x00;
     s->control[2] = 0x00;
     s->control[2] = 0x00;
@@ -1953,73 +1954,94 @@ static void pxa2xx_fir_event(void *opaque, int event)
 {
 {
 }
 }
 
 
-static void pxa2xx_fir_save(QEMUFile *f, void *opaque)
+static void pxa2xx_fir_instance_init(Object *obj)
 {
 {
-    PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
-    int i;
+    PXA2xxFIrState *s = PXA2XX_FIR(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 
 
-    qemu_put_be32(f, s->enable);
-
-    qemu_put_8s(f, &s->control[0]);
-    qemu_put_8s(f, &s->control[1]);
-    qemu_put_8s(f, &s->control[2]);
-    qemu_put_8s(f, &s->status[0]);
-    qemu_put_8s(f, &s->status[1]);
-
-    qemu_put_byte(f, s->rx_len);
-    for (i = 0; i < s->rx_len; i ++)
-        qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 63]);
+    memory_region_init_io(&s->iomem, NULL, &pxa2xx_fir_ops, s,
+                          "pxa2xx-fir", 0x1000);
+    sysbus_init_mmio(sbd, &s->iomem);
+    sysbus_init_irq(sbd, &s->irq);
+    sysbus_init_irq(sbd, &s->rx_dma);
+    sysbus_init_irq(sbd, &s->tx_dma);
 }
 }
 
 
-static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id)
+static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
 {
 {
-    PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
-    int i;
-
-    s->enable = qemu_get_be32(f);
+    PXA2xxFIrState *s = PXA2XX_FIR(dev);
 
 
-    qemu_get_8s(f, &s->control[0]);
-    qemu_get_8s(f, &s->control[1]);
-    qemu_get_8s(f, &s->control[2]);
-    qemu_get_8s(f, &s->status[0]);
-    qemu_get_8s(f, &s->status[1]);
+    if (s->chr) {
+        qemu_chr_fe_claim_no_fail(s->chr);
+        qemu_chr_add_handlers(s->chr, pxa2xx_fir_is_empty,
+                        pxa2xx_fir_rx, pxa2xx_fir_event, s);
+    }
+}
 
 
-    s->rx_len = qemu_get_byte(f);
-    s->rx_start = 0;
-    for (i = 0; i < s->rx_len; i ++)
-        s->rx_fifo[i] = qemu_get_byte(f);
+static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id)
+{
+    PXA2xxFIrState *s = opaque;
 
 
-    return 0;
+    return s->rx_start < ARRAY_SIZE(s->rx_fifo);
 }
 }
 
 
-static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem,
-                hwaddr base,
-                qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma,
-                CharDriverState *chr)
-{
-    PXA2xxFIrState *s = (PXA2xxFIrState *)
-            g_malloc0(sizeof(PXA2xxFIrState));
+static const VMStateDescription pxa2xx_fir_vmsd = {
+    .name = "pxa2xx-fir",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(enable, PXA2xxFIrState),
+        VMSTATE_UINT8_ARRAY(control, PXA2xxFIrState, 3),
+        VMSTATE_UINT8_ARRAY(status, PXA2xxFIrState, 2),
+        VMSTATE_UINT32(rx_len, PXA2xxFIrState),
+        VMSTATE_UINT32(rx_start, PXA2xxFIrState),
+        VMSTATE_VALIDATE("fifo is 64 bytes", pxa2xx_fir_vmstate_validate),
+        VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxFIrState, 64),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
 
-    s->irq = irq;
-    s->rx_dma = rx_dma;
-    s->tx_dma = tx_dma;
-    s->chr = chr;
+static Property pxa2xx_fir_properties[] = {
+    DEFINE_PROP_CHR("chardev", PXA2xxFIrState, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
 
 
-    pxa2xx_fir_reset(s);
+static void pxa2xx_fir_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
 
 
-    memory_region_init_io(&s->iomem, NULL, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
+    dc->realize = pxa2xx_fir_realize;
+    dc->vmsd = &pxa2xx_fir_vmsd;
+    dc->props = pxa2xx_fir_properties;
+    dc->reset = pxa2xx_fir_reset;
+}
 
 
-    if (chr) {
-        qemu_chr_fe_claim_no_fail(chr);
-        qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty,
-                        pxa2xx_fir_rx, pxa2xx_fir_event, s);
-    }
+static const TypeInfo pxa2xx_fir_info = {
+    .name = TYPE_PXA2XX_FIR,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PXA2xxFIrState),
+    .class_init = pxa2xx_fir_class_init,
+    .instance_init = pxa2xx_fir_instance_init,
+};
 
 
-    register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save,
-                    pxa2xx_fir_load, s);
+static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem,
+                                       hwaddr base,
+                                       qemu_irq irq, qemu_irq rx_dma,
+                                       qemu_irq tx_dma,
+                                       CharDriverState *chr)
+{
+    DeviceState *dev;
+    SysBusDevice *sbd;
 
 
-    return s;
+    dev = qdev_create(NULL, TYPE_PXA2XX_FIR);
+    qdev_prop_set_chr(dev, "chardev", chr);
+    qdev_init_nofail(dev);
+    sbd = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(sbd, 0, base);
+    sysbus_connect_irq(sbd, 0, irq);
+    sysbus_connect_irq(sbd, 1, rx_dma);
+    sysbus_connect_irq(sbd, 2, tx_dma);
+    return PXA2XX_FIR(dev);
 }
 }
 
 
 static void pxa2xx_reset(void *opaque, int line, int level)
 static void pxa2xx_reset(void *opaque, int line, int level)
@@ -2306,8 +2328,11 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
 static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data)
 static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data)
 {
 {
     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
 
 
     sdc->init = pxa2xx_ssp_init;
     sdc->init = pxa2xx_ssp_init;
+    dc->reset = pxa2xx_ssp_reset;
+    dc->vmsd = &vmstate_pxa2xx_ssp;
 }
 }
 
 
 static const TypeInfo pxa2xx_ssp_info = {
 static const TypeInfo pxa2xx_ssp_info = {
@@ -2323,6 +2348,7 @@ static void pxa2xx_register_types(void)
     type_register_static(&pxa2xx_ssp_info);
     type_register_static(&pxa2xx_ssp_info);
     type_register_static(&pxa2xx_i2c_info);
     type_register_static(&pxa2xx_i2c_info);
     type_register_static(&pxa2xx_rtc_sysbus_info);
     type_register_static(&pxa2xx_rtc_sysbus_info);
+    type_register_static(&pxa2xx_fir_info);
 }
 }
 
 
 type_init(pxa2xx_register_types)
 type_init(pxa2xx_register_types)

+ 1 - 1
hw/arm/pxa2xx_pic.c

@@ -232,7 +232,7 @@ static void pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri,
 
 
 #define REGINFO_FOR_PIC_CP(NAME, CRN) \
 #define REGINFO_FOR_PIC_CP(NAME, CRN) \
     { .name = NAME, .cp = 6, .crn = CRN, .crm = 0, .opc1 = 0, .opc2 = 0, \
     { .name = NAME, .cp = 6, .crn = CRN, .crm = 0, .opc1 = 0, .opc2 = 0, \
-      .access = PL1_RW, \
+      .access = PL1_RW, .type = ARM_CP_IO, \
       .readfn = pxa2xx_pic_cp_read, .writefn = pxa2xx_pic_cp_write }
       .readfn = pxa2xx_pic_cp_read, .writefn = pxa2xx_pic_cp_write }
 
 
 static const ARMCPRegInfo pxa_pic_cp_reginfo[] = {
 static const ARMCPRegInfo pxa_pic_cp_reginfo[] = {

+ 42 - 1
hw/arm/virt-acpi-build.c

@@ -84,6 +84,12 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
                aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
                aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
                              AML_EXCLUSIVE, uart_irq));
                              AML_EXCLUSIVE, uart_irq));
     aml_append(dev, aml_name_decl("_CRS", crs));
     aml_append(dev, aml_name_decl("_CRS", crs));
+
+    /* The _ADR entry is used to link this device to the UART described
+     * in the SPCR table, i.e. SPCR.base_address.address == _ADR.
+     */
+    aml_append(dev, aml_name_decl("_ADR", aml_int(uart_memmap->base)));
+
     aml_append(scope, dev);
     aml_append(scope, dev);
 }
 }
 
 
@@ -333,6 +339,38 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
     return rsdp_table;
     return rsdp_table;
 }
 }
 
 
+static void
+build_spcr(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
+{
+    AcpiSerialPortConsoleRedirection *spcr;
+    const MemMapEntry *uart_memmap = &guest_info->memmap[VIRT_UART];
+    int irq = guest_info->irqmap[VIRT_UART] + ARM_SPI_BASE;
+
+    spcr = acpi_data_push(table_data, sizeof(*spcr));
+
+    spcr->interface_type = 0x3;    /* ARM PL011 UART */
+
+    spcr->base_address.space_id = AML_SYSTEM_MEMORY;
+    spcr->base_address.bit_width = 8;
+    spcr->base_address.bit_offset = 0;
+    spcr->base_address.access_width = 1;
+    spcr->base_address.address = cpu_to_le64(uart_memmap->base);
+
+    spcr->interrupt_types = (1 << 3); /* Bit[3] ARMH GIC interrupt */
+    spcr->gsi = cpu_to_le32(irq);  /* Global System Interrupt */
+
+    spcr->baud = 3;                /* Baud Rate: 3 = 9600 */
+    spcr->parity = 0;              /* No Parity */
+    spcr->stopbits = 1;            /* 1 Stop bit */
+    spcr->flowctrl = (1 << 1);     /* Bit[1] = RTS/CTS hardware flow control */
+    spcr->term_type = 0;           /* Terminal Type: 0 = VT100 */
+
+    spcr->pci_device_id = 0xffff;  /* PCI Device ID: not a PCI device */
+    spcr->pci_vendor_id = 0xffff;  /* PCI Vendor ID: not a PCI device */
+
+    build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2);
+}
+
 static void
 static void
 build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
 build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
 {
 {
@@ -514,7 +552,7 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
     dsdt = tables_blob->len;
     dsdt = tables_blob->len;
     build_dsdt(tables_blob, tables->linker, guest_info);
     build_dsdt(tables_blob, tables->linker, guest_info);
 
 
-    /* FADT MADT GTDT pointed to by RSDT */
+    /* FADT MADT GTDT SPCR pointed to by RSDT */
     acpi_add_table(table_offsets, tables_blob);
     acpi_add_table(table_offsets, tables_blob);
     build_fadt(tables_blob, tables->linker, dsdt);
     build_fadt(tables_blob, tables->linker, dsdt);
 
 
@@ -527,6 +565,9 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
     acpi_add_table(table_offsets, tables_blob);
     acpi_add_table(table_offsets, tables_blob);
     build_mcfg(tables_blob, tables->linker, guest_info);
     build_mcfg(tables_blob, tables->linker, guest_info);
 
 
+    acpi_add_table(table_offsets, tables_blob);
+    build_spcr(tables_blob, tables->linker, guest_info);
+
     /* RSDT is pointed to by RSDP */
     /* RSDT is pointed to by RSDP */
     rsdt = tables_blob->len;
     rsdt = tables_blob->len;
     build_rsdt(tables_blob, tables->linker, table_offsets);
     build_rsdt(tables_blob, tables->linker, table_offsets);

+ 6 - 1
hw/arm/virt.c

@@ -144,6 +144,11 @@ static VirtBoardInfo machines[] = {
         .memmap = a15memmap,
         .memmap = a15memmap,
         .irqmap = a15irqmap,
         .irqmap = a15irqmap,
     },
     },
+    {
+        .cpu_model = "cortex-a53",
+        .memmap = a15memmap,
+        .irqmap = a15irqmap,
+    },
     {
     {
         .cpu_model = "cortex-a57",
         .cpu_model = "cortex-a57",
         .memmap = a15memmap,
         .memmap = a15memmap,
@@ -306,7 +311,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
                                         "enable-method", "psci");
                                         "enable-method", "psci");
         }
         }
 
 
-        qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", cpu);
+        qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", armcpu->mp_affinity);
         g_free(nodename);
         g_free(nodename);
     }
     }
 }
 }

+ 1 - 1
hw/display/exynos4210_fimd.c

@@ -337,7 +337,7 @@ static inline void fimd_swap_data(unsigned int swap_ctl, uint64_t *data)
     if (swap_ctl & FIMD_WINCON_SWAP_BITS) {
     if (swap_ctl & FIMD_WINCON_SWAP_BITS) {
         res = 0;
         res = 0;
         for (i = 0; i < 64; i++) {
         for (i = 0; i < 64; i++) {
-            if (x & (1ULL << (64 - i))) {
+            if (x & (1ULL << (63 - i))) {
                 res |= (1ULL << i);
                 res |= (1ULL << i);
             }
             }
         }
         }

+ 1 - 1
hw/intc/arm_gic.c

@@ -71,7 +71,7 @@ void gic_update(GICState *s)
             || !(s->cpu_ctlr[cpu] & (GICC_CTLR_EN_GRP0 | GICC_CTLR_EN_GRP1))) {
             || !(s->cpu_ctlr[cpu] & (GICC_CTLR_EN_GRP0 | GICC_CTLR_EN_GRP1))) {
             qemu_irq_lower(s->parent_irq[cpu]);
             qemu_irq_lower(s->parent_irq[cpu]);
             qemu_irq_lower(s->parent_fiq[cpu]);
             qemu_irq_lower(s->parent_fiq[cpu]);
-            return;
+            continue;
         }
         }
         best_prio = 0x100;
         best_prio = 0x100;
         best_irq = 1023;
         best_irq = 1023;

+ 8 - 60
hw/sd/pxa2xx_mmci.c

@@ -48,7 +48,6 @@ struct PXA2xxMMCIState {
     int resp_len;
     int resp_len;
 
 
     int cmdreq;
     int cmdreq;
-    int ac_width;
 };
 };
 
 
 #define MMC_STRPCL	0x00	/* MMC Clock Start/Stop register */
 #define MMC_STRPCL	0x00	/* MMC Clock Start/Stop register */
@@ -215,7 +214,7 @@ static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
     pxa2xx_mmci_fifo_update(s);
     pxa2xx_mmci_fifo_update(s);
 }
 }
 
 
-static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset)
+static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size)
 {
 {
     PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
     PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
     uint32_t ret;
     uint32_t ret;
@@ -257,8 +256,8 @@ static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset)
         return 0;
         return 0;
     case MMC_RXFIFO:
     case MMC_RXFIFO:
         ret = 0;
         ret = 0;
-        while (s->ac_width -- && s->rx_len) {
-            ret |= s->rx_fifo[s->rx_start ++] << (s->ac_width << 3);
+        while (size-- && s->rx_len) {
+            ret |= s->rx_fifo[s->rx_start++] << (size << 3);
             s->rx_start &= 0x1f;
             s->rx_start &= 0x1f;
             s->rx_len --;
             s->rx_len --;
         }
         }
@@ -277,7 +276,7 @@ static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset)
 }
 }
 
 
 static void pxa2xx_mmci_write(void *opaque,
 static void pxa2xx_mmci_write(void *opaque,
-                hwaddr offset, uint32_t value)
+                              hwaddr offset, uint64_t value, unsigned size)
 {
 {
     PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
     PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
 
 
@@ -370,9 +369,9 @@ static void pxa2xx_mmci_write(void *opaque,
         break;
         break;
 
 
     case MMC_TXFIFO:
     case MMC_TXFIFO:
-        while (s->ac_width -- && s->tx_len < 0x20)
+        while (size-- && s->tx_len < 0x20)
             s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] =
             s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] =
-                    (value >> (s->ac_width << 3)) & 0xff;
+                    (value >> (size << 3)) & 0xff;
         s->intreq &= ~INT_TXFIFO_REQ;
         s->intreq &= ~INT_TXFIFO_REQ;
         pxa2xx_mmci_fifo_update(s);
         pxa2xx_mmci_fifo_update(s);
         break;
         break;
@@ -386,60 +385,9 @@ static void pxa2xx_mmci_write(void *opaque,
     }
     }
 }
 }
 
 
-static uint32_t pxa2xx_mmci_readb(void *opaque, hwaddr offset)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    s->ac_width = 1;
-    return pxa2xx_mmci_read(opaque, offset);
-}
-
-static uint32_t pxa2xx_mmci_readh(void *opaque, hwaddr offset)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    s->ac_width = 2;
-    return pxa2xx_mmci_read(opaque, offset);
-}
-
-static uint32_t pxa2xx_mmci_readw(void *opaque, hwaddr offset)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    s->ac_width = 4;
-    return pxa2xx_mmci_read(opaque, offset);
-}
-
-static void pxa2xx_mmci_writeb(void *opaque,
-                hwaddr offset, uint32_t value)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    s->ac_width = 1;
-    pxa2xx_mmci_write(opaque, offset, value);
-}
-
-static void pxa2xx_mmci_writeh(void *opaque,
-                hwaddr offset, uint32_t value)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    s->ac_width = 2;
-    pxa2xx_mmci_write(opaque, offset, value);
-}
-
-static void pxa2xx_mmci_writew(void *opaque,
-                hwaddr offset, uint32_t value)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    s->ac_width = 4;
-    pxa2xx_mmci_write(opaque, offset, value);
-}
-
 static const MemoryRegionOps pxa2xx_mmci_ops = {
 static const MemoryRegionOps pxa2xx_mmci_ops = {
-    .old_mmio = {
-        .read = { pxa2xx_mmci_readb,
-                  pxa2xx_mmci_readh,
-                  pxa2xx_mmci_readw, },
-        .write = { pxa2xx_mmci_writeb,
-                   pxa2xx_mmci_writeh,
-                   pxa2xx_mmci_writew, },
-    },
+    .read = pxa2xx_mmci_read,
+    .write = pxa2xx_mmci_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 };
 
 

+ 32 - 0
include/hw/acpi/acpi-defs.h

@@ -196,6 +196,38 @@ enum {
     ACPI_FADT_ARM_PSCI_USE_HVC = 1,
     ACPI_FADT_ARM_PSCI_USE_HVC = 1,
 };
 };
 
 
+/*
+ * Serial Port Console Redirection Table (SPCR), Rev. 1.02
+ *
+ * For .interface_type see Debug Port Table 2 (DBG2) serial port
+ * subtypes in Table 3, Rev. May 22, 2012
+ */
+struct AcpiSerialPortConsoleRedirection {
+    ACPI_TABLE_HEADER_DEF
+    uint8_t  interface_type;
+    uint8_t  reserved1[3];
+    struct AcpiGenericAddress base_address;
+    uint8_t  interrupt_types;
+    uint8_t  irq;
+    uint32_t gsi;
+    uint8_t  baud;
+    uint8_t  parity;
+    uint8_t  stopbits;
+    uint8_t  flowctrl;
+    uint8_t  term_type;
+    uint8_t  reserved2;
+    uint16_t pci_device_id;
+    uint16_t pci_vendor_id;
+    uint8_t  pci_bus;
+    uint8_t  pci_slot;
+    uint8_t  pci_func;
+    uint32_t pci_flags;
+    uint8_t  pci_seg;
+    uint32_t reserved3;
+} QEMU_PACKED;
+typedef struct AcpiSerialPortConsoleRedirection
+               AcpiSerialPortConsoleRedirection;
+
 /*
 /*
  * ACPI 1.0 Root System Description Table (RSDT)
  * ACPI 1.0 Root System Description Table (RSDT)
  */
  */

+ 8 - 0
target-arm/cpu-qom.h

@@ -103,6 +103,9 @@ typedef struct ARMCPU {
     /* CPU has security extension */
     /* CPU has security extension */
     bool has_el3;
     bool has_el3;
 
 
+    /* CPU has memory protection unit */
+    bool has_mpu;
+
     /* PSCI conduit used to invoke PSCI methods
     /* PSCI conduit used to invoke PSCI methods
      * 0 - disabled, 1 - smc, 2 - hvc
      * 0 - disabled, 1 - smc, 2 - hvc
      */
      */
@@ -116,6 +119,9 @@ typedef struct ARMCPU {
     /* KVM init features for this CPU */
     /* KVM init features for this CPU */
     uint32_t kvm_init_features[7];
     uint32_t kvm_init_features[7];
 
 
+    /* Uniprocessor system with MP extensions */
+    bool mp_is_up;
+
     /* The instance init functions for implementation-specific subclasses
     /* The instance init functions for implementation-specific subclasses
      * set these fields to specify the implementation-dependent values of
      * set these fields to specify the implementation-dependent values of
      * various constant registers and reset values of non-constant
      * various constant registers and reset values of non-constant
@@ -127,6 +133,7 @@ typedef struct ARMCPU {
      * prefix means a constant register.
      * prefix means a constant register.
      */
      */
     uint32_t midr;
     uint32_t midr;
+    uint32_t revidr;
     uint32_t reset_fpsid;
     uint32_t reset_fpsid;
     uint32_t mvfr0;
     uint32_t mvfr0;
     uint32_t mvfr1;
     uint32_t mvfr1;
@@ -159,6 +166,7 @@ typedef struct ARMCPU {
     uint64_t id_aa64mmfr1;
     uint64_t id_aa64mmfr1;
     uint32_t dbgdidr;
     uint32_t dbgdidr;
     uint32_t clidr;
     uint32_t clidr;
+    uint64_t mp_affinity; /* MP ID without feature bits */
     /* The elements of this array are the CCSIDR values for each cache,
     /* The elements of this array are the CCSIDR values for each cache,
      * in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
      * in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
      */
      */

+ 29 - 0
target-arm/cpu.c

@@ -383,17 +383,29 @@ static inline void unset_feature(CPUARMState *env, int feature)
     env->features &= ~(1ULL << feature);
     env->features &= ~(1ULL << feature);
 }
 }
 
 
+#define ARM_CPUS_PER_CLUSTER 8
+
 static void arm_cpu_initfn(Object *obj)
 static void arm_cpu_initfn(Object *obj)
 {
 {
     CPUState *cs = CPU(obj);
     CPUState *cs = CPU(obj);
     ARMCPU *cpu = ARM_CPU(obj);
     ARMCPU *cpu = ARM_CPU(obj);
     static bool inited;
     static bool inited;
+    uint32_t Aff1, Aff0;
 
 
     cs->env_ptr = &cpu->env;
     cs->env_ptr = &cpu->env;
     cpu_exec_init(&cpu->env);
     cpu_exec_init(&cpu->env);
     cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal,
     cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal,
                                          g_free, g_free);
                                          g_free, g_free);
 
 
+    /* This cpu-id-to-MPIDR affinity is used only for TCG; KVM will override it.
+     * We don't support setting cluster ID ([16..23]) (known as Aff2
+     * in later ARM ARM versions), or any of the higher affinity level fields,
+     * so these bits always RAZ.
+     */
+    Aff1 = cs->cpu_index / ARM_CPUS_PER_CLUSTER;
+    Aff0 = cs->cpu_index % ARM_CPUS_PER_CLUSTER;
+    cpu->mp_affinity = (Aff1 << 8) | Aff0;
+
 #ifndef CONFIG_USER_ONLY
 #ifndef CONFIG_USER_ONLY
     /* Our inbound IRQ and FIQ lines */
     /* Our inbound IRQ and FIQ lines */
     if (kvm_enabled()) {
     if (kvm_enabled()) {
@@ -442,6 +454,9 @@ static Property arm_cpu_rvbar_property =
 static Property arm_cpu_has_el3_property =
 static Property arm_cpu_has_el3_property =
             DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
             DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
 
 
+static Property arm_cpu_has_mpu_property =
+            DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true);
+
 static void arm_cpu_post_init(Object *obj)
 static void arm_cpu_post_init(Object *obj)
 {
 {
     ARMCPU *cpu = ARM_CPU(obj);
     ARMCPU *cpu = ARM_CPU(obj);
@@ -469,6 +484,12 @@ static void arm_cpu_post_init(Object *obj)
         qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el3_property,
         qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el3_property,
                                  &error_abort);
                                  &error_abort);
     }
     }
+
+    if (arm_feature(&cpu->env, ARM_FEATURE_MPU)) {
+        qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property,
+                                 &error_abort);
+    }
+
 }
 }
 
 
 static void arm_cpu_finalizefn(Object *obj)
 static void arm_cpu_finalizefn(Object *obj)
@@ -533,6 +554,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
     if (arm_feature(env, ARM_FEATURE_CBAR_RO)) {
     if (arm_feature(env, ARM_FEATURE_CBAR_RO)) {
         set_feature(env, ARM_FEATURE_CBAR);
         set_feature(env, ARM_FEATURE_CBAR);
     }
     }
+    if (arm_feature(env, ARM_FEATURE_THUMB2) &&
+        !arm_feature(env, ARM_FEATURE_M)) {
+        set_feature(env, ARM_FEATURE_THUMB_DSP);
+    }
 
 
     if (cpu->reset_hivecs) {
     if (cpu->reset_hivecs) {
             cpu->reset_sctlr |= (1 << 13);
             cpu->reset_sctlr |= (1 << 13);
@@ -551,6 +576,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
         cpu->id_aa64pfr0 &= ~0xf000;
         cpu->id_aa64pfr0 &= ~0xf000;
     }
     }
 
 
+    if (!cpu->has_mpu) {
+        unset_feature(env, ARM_FEATURE_MPU);
+    }
+
     register_cp_regs_for_features(cpu);
     register_cp_regs_for_features(cpu);
     arm_cpu_register_gdb_regs_for_features(cpu);
     arm_cpu_register_gdb_regs_for_features(cpu);
 
 

+ 1 - 1
target-arm/cpu.h

@@ -384,7 +384,6 @@ typedef struct CPUARMState {
         uint32_t control;
         uint32_t control;
         int current_sp;
         int current_sp;
         int exception;
         int exception;
-        int pending_exception;
     } v7m;
     } v7m;
 
 
     /* Information associated with an exception about to be taken:
     /* Information associated with an exception about to be taken:
@@ -890,6 +889,7 @@ enum arm_features {
     ARM_FEATURE_V8_SHA1, /* implements SHA1 part of v8 Crypto Extensions */
     ARM_FEATURE_V8_SHA1, /* implements SHA1 part of v8 Crypto Extensions */
     ARM_FEATURE_V8_SHA256, /* implements SHA256 part of v8 Crypto Extensions */
     ARM_FEATURE_V8_SHA256, /* implements SHA256 part of v8 Crypto Extensions */
     ARM_FEATURE_V8_PMULL, /* implements PMULL part of v8 Crypto Extensions */
     ARM_FEATURE_V8_PMULL, /* implements PMULL part of v8 Crypto Extensions */
+    ARM_FEATURE_THUMB_DSP, /* DSP insns supported in the Thumb encodings */
 };
 };
 
 
 static inline int arm_feature(CPUARMState *env, int feature)
 static inline int arm_feature(CPUARMState *env, int feature)

+ 3 - 0
target-arm/cpu64.c

@@ -110,6 +110,7 @@ static void aarch64_a57_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_CRC);
     set_feature(&cpu->env, ARM_FEATURE_CRC);
     cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
     cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
     cpu->midr = 0x411fd070;
     cpu->midr = 0x411fd070;
+    cpu->revidr = 0x00000000;
     cpu->reset_fpsid = 0x41034070;
     cpu->reset_fpsid = 0x41034070;
     cpu->mvfr0 = 0x10110222;
     cpu->mvfr0 = 0x10110222;
     cpu->mvfr1 = 0x12111111;
     cpu->mvfr1 = 0x12111111;
@@ -159,7 +160,9 @@ static void aarch64_a53_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V8_SHA256);
     set_feature(&cpu->env, ARM_FEATURE_V8_SHA256);
     set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
     set_feature(&cpu->env, ARM_FEATURE_V8_PMULL);
     set_feature(&cpu->env, ARM_FEATURE_CRC);
     set_feature(&cpu->env, ARM_FEATURE_CRC);
+    cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53;
     cpu->midr = 0x410fd034;
     cpu->midr = 0x410fd034;
+    cpu->revidr = 0x00000000;
     cpu->reset_fpsid = 0x41034070;
     cpu->reset_fpsid = 0x41034070;
     cpu->mvfr0 = 0x10110222;
     cpu->mvfr0 = 0x10110222;
     cpu->mvfr1 = 0x12111111;
     cpu->mvfr1 = 0x12111111;

+ 123 - 89
target-arm/helper.c

@@ -12,10 +12,10 @@
 #include <zlib.h> /* For crc32 */
 #include <zlib.h> /* For crc32 */
 
 
 #ifndef CONFIG_USER_ONLY
 #ifndef CONFIG_USER_ONLY
-static inline int get_phys_addr(CPUARMState *env, target_ulong address,
-                                int access_type, ARMMMUIdx mmu_idx,
-                                hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
-                                target_ulong *page_size);
+static inline bool get_phys_addr(CPUARMState *env, target_ulong address,
+                                 int access_type, ARMMMUIdx mmu_idx,
+                                 hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
+                                 target_ulong *page_size, uint32_t *fsr);
 
 
 /* Definitions for the PMCCNTR and PMCR registers */
 /* Definitions for the PMCCNTR and PMCR registers */
 #define PMCRD   0x8
 #define PMCRD   0x8
@@ -1495,19 +1495,20 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
     hwaddr phys_addr;
     hwaddr phys_addr;
     target_ulong page_size;
     target_ulong page_size;
     int prot;
     int prot;
-    int ret;
+    uint32_t fsr;
+    bool ret;
     uint64_t par64;
     uint64_t par64;
     MemTxAttrs attrs = {};
     MemTxAttrs attrs = {};
 
 
     ret = get_phys_addr(env, value, access_type, mmu_idx,
     ret = get_phys_addr(env, value, access_type, mmu_idx,
-                        &phys_addr, &attrs, &prot, &page_size);
+                        &phys_addr, &attrs, &prot, &page_size, &fsr);
     if (extended_addresses_enabled(env)) {
     if (extended_addresses_enabled(env)) {
-        /* ret is a DFSR/IFSR value for the long descriptor
+        /* fsr is a DFSR/IFSR value for the long descriptor
          * translation table format, but with WnR always clear.
          * translation table format, but with WnR always clear.
          * Convert it to a 64-bit PAR.
          * Convert it to a 64-bit PAR.
          */
          */
         par64 = (1 << 11); /* LPAE bit always set */
         par64 = (1 << 11); /* LPAE bit always set */
-        if (ret == 0) {
+        if (!ret) {
             par64 |= phys_addr & ~0xfffULL;
             par64 |= phys_addr & ~0xfffULL;
             if (!attrs.secure) {
             if (!attrs.secure) {
                 par64 |= (1 << 9); /* NS */
                 par64 |= (1 << 9); /* NS */
@@ -1515,18 +1516,18 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
             /* We don't set the ATTR or SH fields in the PAR. */
             /* We don't set the ATTR or SH fields in the PAR. */
         } else {
         } else {
             par64 |= 1; /* F */
             par64 |= 1; /* F */
-            par64 |= (ret & 0x3f) << 1; /* FS */
+            par64 |= (fsr & 0x3f) << 1; /* FS */
             /* Note that S2WLK and FSTAGE are always zero, because we don't
             /* Note that S2WLK and FSTAGE are always zero, because we don't
              * implement virtualization and therefore there can't be a stage 2
              * implement virtualization and therefore there can't be a stage 2
              * fault.
              * fault.
              */
              */
         }
         }
     } else {
     } else {
-        /* ret is a DFSR/IFSR value for the short descriptor
+        /* fsr is a DFSR/IFSR value for the short descriptor
          * translation table format (with WnR always clear).
          * translation table format (with WnR always clear).
          * Convert it to a 32-bit PAR.
          * Convert it to a 32-bit PAR.
          */
          */
-        if (ret == 0) {
+        if (!ret) {
             /* We do not set any attribute bits in the PAR */
             /* We do not set any attribute bits in the PAR */
             if (page_size == (1 << 24)
             if (page_size == (1 << 24)
                 && arm_feature(env, ARM_FEATURE_V7)) {
                 && arm_feature(env, ARM_FEATURE_V7)) {
@@ -1538,8 +1539,8 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
                 par64 |= (1 << 9); /* NS */
                 par64 |= (1 << 9); /* NS */
             }
             }
         } else {
         } else {
-            par64 = ((ret & (1 << 10)) >> 5) | ((ret & (1 << 12)) >> 6) |
-                    ((ret & 0xf) << 1) | 1;
+            par64 = ((fsr & (1 << 10)) >> 5) | ((fsr & (1 << 12)) >> 6) |
+                    ((fsr & 0xf) << 1) | 1;
         }
         }
     }
     }
     return par64;
     return par64;
@@ -1846,7 +1847,7 @@ static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
     raw_write(env, ri, value);
     raw_write(env, ri, value);
 }
 }
 
 
-static const ARMCPRegInfo vmsa_cp_reginfo[] = {
+static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = {
     { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
     { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .type = ARM_CP_ALIAS,
       .access = PL1_RW, .type = ARM_CP_ALIAS,
       .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dfsr_s),
       .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dfsr_s),
@@ -1856,6 +1857,18 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
       .access = PL1_RW, .resetvalue = 0,
       .access = PL1_RW, .resetvalue = 0,
       .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.ifsr_s),
       .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.ifsr_s),
                              offsetoflow32(CPUARMState, cp15.ifsr_ns) } },
                              offsetoflow32(CPUARMState, cp15.ifsr_ns) } },
+    { .name = "DFAR", .cp = 15, .opc1 = 0, .crn = 6, .crm = 0, .opc2 = 0,
+      .access = PL1_RW, .resetvalue = 0,
+      .bank_fieldoffsets = { offsetof(CPUARMState, cp15.dfar_s),
+                             offsetof(CPUARMState, cp15.dfar_ns) } },
+    { .name = "FAR_EL1", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
+      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]),
+      .resetvalue = 0, },
+    REGINFO_SENTINEL
+};
+
+static const ARMCPRegInfo vmsa_cp_reginfo[] = {
     { .name = "ESR_EL1", .state = ARM_CP_STATE_AA64,
     { .name = "ESR_EL1", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0,
       .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW,
       .access = PL1_RW,
@@ -1880,14 +1893,6 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
       .resetfn = arm_cp_reset_ignore, .raw_writefn = vmsa_ttbcr_raw_write,
       .resetfn = arm_cp_reset_ignore, .raw_writefn = vmsa_ttbcr_raw_write,
       .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tcr_el[3]),
       .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tcr_el[3]),
                              offsetoflow32(CPUARMState, cp15.tcr_el[1])} },
                              offsetoflow32(CPUARMState, cp15.tcr_el[1])} },
-    { .name = "FAR_EL1", .state = ARM_CP_STATE_AA64,
-      .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
-      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]),
-      .resetvalue = 0, },
-    { .name = "DFAR", .cp = 15, .opc1 = 0, .crn = 6, .crm = 0, .opc2 = 0,
-      .access = PL1_RW, .resetvalue = 0,
-      .bank_fieldoffsets = { offsetof(CPUARMState, cp15.dfar_s),
-                             offsetof(CPUARMState, cp15.dfar_ns) } },
     REGINFO_SENTINEL
     REGINFO_SENTINEL
 };
 };
 
 
@@ -2063,19 +2068,18 @@ static const ARMCPRegInfo strongarm_cp_reginfo[] = {
 
 
 static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
 static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
 {
 {
-    CPUState *cs = CPU(arm_env_get_cpu(env));
-    uint32_t mpidr = cs->cpu_index;
-    /* We don't support setting cluster ID ([8..11]) (known as Aff1
-     * in later ARM ARM versions), or any of the higher affinity level fields,
-     * so these bits always RAZ.
-     */
+    ARMCPU *cpu = ARM_CPU(arm_env_get_cpu(env));
+    uint64_t mpidr = cpu->mp_affinity;
+
     if (arm_feature(env, ARM_FEATURE_V7MP)) {
     if (arm_feature(env, ARM_FEATURE_V7MP)) {
         mpidr |= (1U << 31);
         mpidr |= (1U << 31);
         /* Cores which are uniprocessor (non-coherent)
         /* Cores which are uniprocessor (non-coherent)
          * but still implement the MP extensions set
          * but still implement the MP extensions set
-         * bit 30. (For instance, A9UP.) However we do
-         * not currently model any of those cores.
+         * bit 30. (For instance, Cortex-R5).
          */
          */
+        if (cpu->mp_is_up) {
+            mpidr |= (1u << 30);
+        }
     }
     }
     return mpidr;
     return mpidr;
 }
 }
@@ -3196,7 +3200,8 @@ void register_cp_regs_for_features(ARMCPU *cpu)
     if (arm_feature(env, ARM_FEATURE_V6K)) {
     if (arm_feature(env, ARM_FEATURE_V6K)) {
         define_arm_cp_regs(cpu, v6k_cp_reginfo);
         define_arm_cp_regs(cpu, v6k_cp_reginfo);
     }
     }
-    if (arm_feature(env, ARM_FEATURE_V7MP)) {
+    if (arm_feature(env, ARM_FEATURE_V7MP) &&
+        !arm_feature(env, ARM_FEATURE_MPU)) {
         define_arm_cp_regs(cpu, v7mp_cp_reginfo);
         define_arm_cp_regs(cpu, v7mp_cp_reginfo);
     }
     }
     if (arm_feature(env, ARM_FEATURE_V7)) {
     if (arm_feature(env, ARM_FEATURE_V7)) {
@@ -3348,6 +3353,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
         assert(!arm_feature(env, ARM_FEATURE_V6));
         assert(!arm_feature(env, ARM_FEATURE_V6));
         define_arm_cp_regs(cpu, pmsav5_cp_reginfo);
         define_arm_cp_regs(cpu, pmsav5_cp_reginfo);
     } else {
     } else {
+        define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo);
         define_arm_cp_regs(cpu, vmsa_cp_reginfo);
         define_arm_cp_regs(cpu, vmsa_cp_reginfo);
     }
     }
     if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
     if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
@@ -3423,16 +3429,19 @@ void register_cp_regs_for_features(ARMCPU *cpu)
             REGINFO_SENTINEL
             REGINFO_SENTINEL
         };
         };
         ARMCPRegInfo id_v8_midr_cp_reginfo[] = {
         ARMCPRegInfo id_v8_midr_cp_reginfo[] = {
-            /* v8 MIDR -- the wildcard isn't necessary, and nor is the
-             * variable-MIDR TI925 behaviour. Instead we have a single
-             * (strictly speaking IMPDEF) alias of the MIDR, REVIDR.
-             */
             { .name = "MIDR_EL1", .state = ARM_CP_STATE_BOTH,
             { .name = "MIDR_EL1", .state = ARM_CP_STATE_BOTH,
               .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 0,
               .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 0,
               .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->midr },
               .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->midr },
+            /* crn = 0 op1 = 0 crm = 0 op2 = 4,7 : AArch32 aliases of MIDR */
+            { .name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST,
+              .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 4,
+              .access = PL1_R, .resetvalue = cpu->midr },
+            { .name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST,
+              .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 7,
+              .access = PL1_R, .resetvalue = cpu->midr },
             { .name = "REVIDR_EL1", .state = ARM_CP_STATE_BOTH,
             { .name = "REVIDR_EL1", .state = ARM_CP_STATE_BOTH,
               .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 6,
               .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 6,
-              .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->midr },
+              .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->revidr },
             REGINFO_SENTINEL
             REGINFO_SENTINEL
         };
         };
         ARMCPRegInfo id_cp_reginfo[] = {
         ARMCPRegInfo id_cp_reginfo[] = {
@@ -3448,11 +3457,14 @@ void register_cp_regs_for_features(ARMCPU *cpu)
             { .name = "TCMTR",
             { .name = "TCMTR",
               .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 2,
               .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 2,
               .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
               .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
-            { .name = "TLBTR",
-              .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 3,
-              .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
             REGINFO_SENTINEL
             REGINFO_SENTINEL
         };
         };
+        /* TLBTR is specific to VMSA */
+        ARMCPRegInfo id_tlbtr_reginfo = {
+              .name = "TLBTR",
+              .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 3,
+              .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0,
+        };
         ARMCPRegInfo crn0_wi_reginfo = {
         ARMCPRegInfo crn0_wi_reginfo = {
             .name = "CRN0_WI", .cp = 15, .crn = 0, .crm = CP_ANY,
             .name = "CRN0_WI", .cp = 15, .crn = 0, .crm = CP_ANY,
             .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_W,
             .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_W,
@@ -3474,6 +3486,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
             for (r = id_cp_reginfo; r->type != ARM_CP_SENTINEL; r++) {
             for (r = id_cp_reginfo; r->type != ARM_CP_SENTINEL; r++) {
                 r->access = PL1_RW;
                 r->access = PL1_RW;
             }
             }
+            id_tlbtr_reginfo.access = PL1_RW;
         }
         }
         if (arm_feature(env, ARM_FEATURE_V8)) {
         if (arm_feature(env, ARM_FEATURE_V8)) {
             define_arm_cp_regs(cpu, id_v8_midr_cp_reginfo);
             define_arm_cp_regs(cpu, id_v8_midr_cp_reginfo);
@@ -3481,6 +3494,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
             define_arm_cp_regs(cpu, id_pre_v8_midr_cp_reginfo);
             define_arm_cp_regs(cpu, id_pre_v8_midr_cp_reginfo);
         }
         }
         define_arm_cp_regs(cpu, id_cp_reginfo);
         define_arm_cp_regs(cpu, id_cp_reginfo);
+        if (!arm_feature(env, ARM_FEATURE_MPU)) {
+            define_one_arm_cp_reg(cpu, &id_tlbtr_reginfo);
+        }
     }
     }
 
 
     if (arm_feature(env, ARM_FEATURE_MPIDR)) {
     if (arm_feature(env, ARM_FEATURE_MPIDR)) {
@@ -5229,9 +5245,10 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure)
     return address_space_ldq(cs->as, addr, attrs, NULL);
     return address_space_ldq(cs->as, addr, attrs, NULL);
 }
 }
 
 
-static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type,
-                            ARMMMUIdx mmu_idx, hwaddr *phys_ptr,
-                            int *prot, target_ulong *page_size)
+static bool get_phys_addr_v5(CPUARMState *env, uint32_t address,
+                             int access_type, ARMMMUIdx mmu_idx,
+                             hwaddr *phys_ptr, int *prot,
+                             target_ulong *page_size, uint32_t *fsr)
 {
 {
     CPUState *cs = CPU(arm_env_get_cpu(env));
     CPUState *cs = CPU(arm_env_get_cpu(env));
     int code;
     int code;
@@ -5302,20 +5319,25 @@ static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type,
             ap = (desc >> (4 + ((address >> 9) & 6))) & 3;
             ap = (desc >> (4 + ((address >> 9) & 6))) & 3;
             *page_size = 0x1000;
             *page_size = 0x1000;
             break;
             break;
-        case 3: /* 1k page.  */
+        case 3: /* 1k page, or ARMv6/XScale "extended small (4k) page" */
             if (type == 1) {
             if (type == 1) {
-                if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+                /* ARMv6/XScale extended small page format */
+                if (arm_feature(env, ARM_FEATURE_XSCALE)
+                    || arm_feature(env, ARM_FEATURE_V6)) {
                     phys_addr = (desc & 0xfffff000) | (address & 0xfff);
                     phys_addr = (desc & 0xfffff000) | (address & 0xfff);
+                    *page_size = 0x1000;
                 } else {
                 } else {
-                    /* Page translation fault.  */
+                    /* UNPREDICTABLE in ARMv5; we choose to take a
+                     * page translation fault.
+                     */
                     code = 7;
                     code = 7;
                     goto do_fault;
                     goto do_fault;
                 }
                 }
             } else {
             } else {
                 phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
                 phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
+                *page_size = 0x400;
             }
             }
             ap = (desc >> 4) & 3;
             ap = (desc >> 4) & 3;
-            *page_size = 0x400;
             break;
             break;
         default:
         default:
             /* Never happens, but compiler isn't smart enough to tell.  */
             /* Never happens, but compiler isn't smart enough to tell.  */
@@ -5330,15 +5352,16 @@ static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type,
         goto do_fault;
         goto do_fault;
     }
     }
     *phys_ptr = phys_addr;
     *phys_ptr = phys_addr;
-    return 0;
+    return false;
 do_fault:
 do_fault:
-    return code | (domain << 4);
+    *fsr = code | (domain << 4);
+    return true;
 }
 }
 
 
-static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
-                            ARMMMUIdx mmu_idx, hwaddr *phys_ptr,
-                            MemTxAttrs *attrs,
-                            int *prot, target_ulong *page_size)
+static bool get_phys_addr_v6(CPUARMState *env, uint32_t address,
+                             int access_type, ARMMMUIdx mmu_idx,
+                             hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
+                             target_ulong *page_size, uint32_t *fsr)
 {
 {
     CPUState *cs = CPU(arm_env_get_cpu(env));
     CPUState *cs = CPU(arm_env_get_cpu(env));
     int code;
     int code;
@@ -5392,6 +5415,8 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
         if (desc & (1 << 18)) {
         if (desc & (1 << 18)) {
             /* Supersection.  */
             /* Supersection.  */
             phys_addr = (desc & 0xff000000) | (address & 0x00ffffff);
             phys_addr = (desc & 0xff000000) | (address & 0x00ffffff);
+            phys_addr |= (uint64_t)extract32(desc, 20, 4) << 32;
+            phys_addr |= (uint64_t)extract32(desc, 5, 4) << 36;
             *page_size = 0x1000000;
             *page_size = 0x1000000;
         } else {
         } else {
             /* Section.  */
             /* Section.  */
@@ -5469,9 +5494,10 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type,
         attrs->secure = false;
         attrs->secure = false;
     }
     }
     *phys_ptr = phys_addr;
     *phys_ptr = phys_addr;
-    return 0;
+    return false;
 do_fault:
 do_fault:
-    return code | (domain << 4);
+    *fsr = code | (domain << 4);
+    return true;
 }
 }
 
 
 /* Fault type for long-descriptor MMU fault reporting; this corresponds
 /* Fault type for long-descriptor MMU fault reporting; this corresponds
@@ -5483,10 +5509,10 @@ typedef enum {
     permission_fault = 3,
     permission_fault = 3,
 } MMUFaultType;
 } MMUFaultType;
 
 
-static int get_phys_addr_lpae(CPUARMState *env, target_ulong address,
-                              int access_type, ARMMMUIdx mmu_idx,
-                              hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot,
-                              target_ulong *page_size_ptr)
+static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
+                               int access_type, ARMMMUIdx mmu_idx,
+                               hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot,
+                               target_ulong *page_size_ptr, uint32_t *fsr)
 {
 {
     CPUState *cs = CPU(arm_env_get_cpu(env));
     CPUState *cs = CPU(arm_env_get_cpu(env));
     /* Read an LPAE long-descriptor translation table. */
     /* Read an LPAE long-descriptor translation table. */
@@ -5725,16 +5751,17 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address,
     }
     }
     *phys_ptr = descaddr;
     *phys_ptr = descaddr;
     *page_size_ptr = page_size;
     *page_size_ptr = page_size;
-    return 0;
+    return false;
 
 
 do_fault:
 do_fault:
     /* Long-descriptor format IFSR/DFSR value */
     /* Long-descriptor format IFSR/DFSR value */
-    return (1 << 9) | (fault_type << 2) | level;
+    *fsr = (1 << 9) | (fault_type << 2) | level;
+    return true;
 }
 }
 
 
-static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
-                             int access_type, ARMMMUIdx mmu_idx,
-                             hwaddr *phys_ptr, int *prot)
+static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address,
+                                 int access_type, ARMMMUIdx mmu_idx,
+                                 hwaddr *phys_ptr, int *prot, uint32_t *fsr)
 {
 {
     int n;
     int n;
     uint32_t mask;
     uint32_t mask;
@@ -5756,7 +5783,8 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
         }
         }
     }
     }
     if (n < 0) {
     if (n < 0) {
-        return 2;
+        *fsr = 2;
+        return true;
     }
     }
 
 
     if (access_type == 2) {
     if (access_type == 2) {
@@ -5767,10 +5795,12 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
     mask = (mask >> (n * 4)) & 0xf;
     mask = (mask >> (n * 4)) & 0xf;
     switch (mask) {
     switch (mask) {
     case 0:
     case 0:
-        return 1;
+        *fsr = 1;
+        return true;
     case 1:
     case 1:
         if (is_user) {
         if (is_user) {
-            return 1;
+            *fsr = 1;
+            return true;
         }
         }
         *prot = PAGE_READ | PAGE_WRITE;
         *prot = PAGE_READ | PAGE_WRITE;
         break;
         break;
@@ -5785,7 +5815,8 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
         break;
         break;
     case 5:
     case 5:
         if (is_user) {
         if (is_user) {
-            return 1;
+            *fsr = 1;
+            return true;
         }
         }
         *prot = PAGE_READ;
         *prot = PAGE_READ;
         break;
         break;
@@ -5794,10 +5825,11 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
         break;
         break;
     default:
     default:
         /* Bad permission.  */
         /* Bad permission.  */
-        return 1;
+        *fsr = 1;
+        return true;
     }
     }
     *prot |= PAGE_EXEC;
     *prot |= PAGE_EXEC;
-    return 0;
+    return false;
 }
 }
 
 
 /* get_phys_addr - get the physical address for this virtual address
 /* get_phys_addr - get the physical address for this virtual address
@@ -5806,8 +5838,8 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
  * by doing a translation table walk on MMU based systems or using the
  * by doing a translation table walk on MMU based systems or using the
  * MPU state on MPU based systems.
  * MPU state on MPU based systems.
  *
  *
- * Returns 0 if the translation was successful. Otherwise, phys_ptr, attrs,
- * prot and page_size may not be filled in, and the return value provides
+ * Returns false if the translation was successful. Otherwise, phys_ptr, attrs,
+ * prot and page_size may not be filled in, and the populated fsr value provides
  * information on why the translation aborted, in the format of a
  * information on why the translation aborted, in the format of a
  * DFSR/IFSR fault register, with the following caveats:
  * DFSR/IFSR fault register, with the following caveats:
  *  * we honour the short vs long DFSR format differences.
  *  * we honour the short vs long DFSR format differences.
@@ -5823,11 +5855,12 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
  * @attrs: set to the memory transaction attributes to use
  * @attrs: set to the memory transaction attributes to use
  * @prot: set to the permissions for the page containing phys_ptr
  * @prot: set to the permissions for the page containing phys_ptr
  * @page_size: set to the size of the page containing phys_ptr
  * @page_size: set to the size of the page containing phys_ptr
+ * @fsr: set to the DFSR/IFSR value on failure
  */
  */
-static inline int get_phys_addr(CPUARMState *env, target_ulong address,
-                                int access_type, ARMMMUIdx mmu_idx,
-                                hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
-                                target_ulong *page_size)
+static inline bool get_phys_addr(CPUARMState *env, target_ulong address,
+                                 int access_type, ARMMMUIdx mmu_idx,
+                                 hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
+                                 target_ulong *page_size, uint32_t *fsr)
 {
 {
     if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) {
     if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) {
         /* TODO: when we support EL2 we should here call ourselves recursively
         /* TODO: when we support EL2 we should here call ourselves recursively
@@ -5869,28 +5902,28 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address,
 
 
     if (arm_feature(env, ARM_FEATURE_MPU)) {
     if (arm_feature(env, ARM_FEATURE_MPU)) {
         *page_size = TARGET_PAGE_SIZE;
         *page_size = TARGET_PAGE_SIZE;
-        return get_phys_addr_mpu(env, address, access_type, mmu_idx, phys_ptr,
-                                 prot);
+        return get_phys_addr_pmsav5(env, address, access_type, mmu_idx,
+                                    phys_ptr, prot, fsr);
     }
     }
 
 
     if (regime_using_lpae_format(env, mmu_idx)) {
     if (regime_using_lpae_format(env, mmu_idx)) {
         return get_phys_addr_lpae(env, address, access_type, mmu_idx, phys_ptr,
         return get_phys_addr_lpae(env, address, access_type, mmu_idx, phys_ptr,
-                                  attrs, prot, page_size);
+                                  attrs, prot, page_size, fsr);
     } else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) {
     } else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) {
         return get_phys_addr_v6(env, address, access_type, mmu_idx, phys_ptr,
         return get_phys_addr_v6(env, address, access_type, mmu_idx, phys_ptr,
-                                attrs, prot, page_size);
+                                attrs, prot, page_size, fsr);
     } else {
     } else {
         return get_phys_addr_v5(env, address, access_type, mmu_idx, phys_ptr,
         return get_phys_addr_v5(env, address, access_type, mmu_idx, phys_ptr,
-                                prot, page_size);
+                                prot, page_size, fsr);
     }
     }
 }
 }
 
 
 /* Walk the page table and (if the mapping exists) add the page
 /* Walk the page table and (if the mapping exists) add the page
- * to the TLB. Return 0 on success, or an ARM DFSR/IFSR fault
- * register format value on failure.
+ * to the TLB. Return false on success, or true on failure. Populate
+ * fsr with ARM DFSR/IFSR fault register format value on failure.
  */
  */
-int arm_tlb_fill(CPUState *cs, vaddr address,
-                 int access_type, int mmu_idx)
+bool arm_tlb_fill(CPUState *cs, vaddr address,
+                  int access_type, int mmu_idx, uint32_t *fsr)
 {
 {
     ARMCPU *cpu = ARM_CPU(cs);
     ARMCPU *cpu = ARM_CPU(cs);
     CPUARMState *env = &cpu->env;
     CPUARMState *env = &cpu->env;
@@ -5901,8 +5934,8 @@ int arm_tlb_fill(CPUState *cs, vaddr address,
     MemTxAttrs attrs = {};
     MemTxAttrs attrs = {};
 
 
     ret = get_phys_addr(env, address, access_type, mmu_idx, &phys_addr,
     ret = get_phys_addr(env, address, access_type, mmu_idx, &phys_addr,
-                        &attrs, &prot, &page_size);
-    if (ret == 0) {
+                        &attrs, &prot, &page_size, fsr);
+    if (!ret) {
         /* Map a single [sub]page.  */
         /* Map a single [sub]page.  */
         phys_addr &= TARGET_PAGE_MASK;
         phys_addr &= TARGET_PAGE_MASK;
         address &= TARGET_PAGE_MASK;
         address &= TARGET_PAGE_MASK;
@@ -5921,13 +5954,14 @@ hwaddr arm_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
     hwaddr phys_addr;
     hwaddr phys_addr;
     target_ulong page_size;
     target_ulong page_size;
     int prot;
     int prot;
-    int ret;
+    bool ret;
+    uint32_t fsr;
     MemTxAttrs attrs = {};
     MemTxAttrs attrs = {};
 
 
     ret = get_phys_addr(env, addr, 0, cpu_mmu_index(env), &phys_addr,
     ret = get_phys_addr(env, addr, 0, cpu_mmu_index(env), &phys_addr,
-                        &attrs, &prot, &page_size);
+                        &attrs, &prot, &page_size, &fsr);
 
 
-    if (ret != 0) {
+    if (ret) {
         return -1;
         return -1;
     }
     }
 
 

+ 2 - 1
target-arm/internals.h

@@ -388,6 +388,7 @@ void arm_handle_psci_call(ARMCPU *cpu);
 #endif
 #endif
 
 
 /* Do a page table walk and add page to TLB if possible */
 /* Do a page table walk and add page to TLB if possible */
-int arm_tlb_fill(CPUState *cpu, vaddr address, int rw, int mmu_idx);
+bool arm_tlb_fill(CPUState *cpu, vaddr address, int rw, int mmu_idx,
+                  uint32_t *fsr);
 
 
 #endif
 #endif

+ 4 - 0
target-arm/kvm-consts.h

@@ -127,6 +127,8 @@ MISMATCH_CHECK(QEMU_PSCI_RET_DISABLED, PSCI_RET_DISABLED)
 #define QEMU_KVM_ARM_TARGET_AEM_V8 0
 #define QEMU_KVM_ARM_TARGET_AEM_V8 0
 #define QEMU_KVM_ARM_TARGET_FOUNDATION_V8 1
 #define QEMU_KVM_ARM_TARGET_FOUNDATION_V8 1
 #define QEMU_KVM_ARM_TARGET_CORTEX_A57 2
 #define QEMU_KVM_ARM_TARGET_CORTEX_A57 2
+#define QEMU_KVM_ARM_TARGET_XGENE_POTENZA 3
+#define QEMU_KVM_ARM_TARGET_CORTEX_A53 4
 
 
 /* There's no kernel define for this: sentinel value which
 /* There's no kernel define for this: sentinel value which
  * matches no KVM target value for either 64 or 32 bit
  * matches no KVM target value for either 64 or 32 bit
@@ -137,6 +139,8 @@ MISMATCH_CHECK(QEMU_PSCI_RET_DISABLED, PSCI_RET_DISABLED)
 MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_AEM_V8, KVM_ARM_TARGET_AEM_V8)
 MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_AEM_V8, KVM_ARM_TARGET_AEM_V8)
 MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_FOUNDATION_V8, KVM_ARM_TARGET_FOUNDATION_V8)
 MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_FOUNDATION_V8, KVM_ARM_TARGET_FOUNDATION_V8)
 MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A57, KVM_ARM_TARGET_CORTEX_A57)
 MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A57, KVM_ARM_TARGET_CORTEX_A57)
+MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_XGENE_POTENZA, KVM_ARM_TARGET_XGENE_POTENZA)
+MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A53, KVM_ARM_TARGET_CORTEX_A53)
 #else
 #else
 MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A15, KVM_ARM_TARGET_CORTEX_A15)
 MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A15, KVM_ARM_TARGET_CORTEX_A15)
 MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A7, KVM_ARM_TARGET_CORTEX_A7)
 MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A7, KVM_ARM_TARGET_CORTEX_A7)

+ 15 - 0
target-arm/kvm32.c

@@ -153,10 +153,14 @@ bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx)
     }
     }
 }
 }
 
 
+#define ARM_MPIDR_HWID_BITMASK 0xFFFFFF
+#define ARM_CPU_ID_MPIDR       0, 0, 0, 5
+
 int kvm_arch_init_vcpu(CPUState *cs)
 int kvm_arch_init_vcpu(CPUState *cs)
 {
 {
     int ret;
     int ret;
     uint64_t v;
     uint64_t v;
+    uint32_t mpidr;
     struct kvm_one_reg r;
     struct kvm_one_reg r;
     ARMCPU *cpu = ARM_CPU(cs);
     ARMCPU *cpu = ARM_CPU(cs);
 
 
@@ -193,6 +197,17 @@ int kvm_arch_init_vcpu(CPUState *cs)
         return -EINVAL;
         return -EINVAL;
     }
     }
 
 
+    /*
+     * When KVM is in use, PSCI is emulated in-kernel and not by qemu.
+     * Currently KVM has its own idea about MPIDR assignment, so we
+     * override our defaults with what we get from KVM.
+     */
+    ret = kvm_get_one_reg(cs, ARM_CP15_REG32(ARM_CPU_ID_MPIDR), &mpidr);
+    if (ret) {
+        return ret;
+    }
+    cpu->mp_affinity = mpidr & ARM_MPIDR_HWID_BITMASK;
+
     return kvm_arm_init_cpreg_list(cpu);
     return kvm_arm_init_cpreg_list(cpu);
 }
 }
 
 

+ 15 - 0
target-arm/kvm64.c

@@ -77,9 +77,13 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc)
     return true;
     return true;
 }
 }
 
 
+#define ARM_MPIDR_HWID_BITMASK 0xFF00FFFFFFULL
+#define ARM_CPU_ID_MPIDR       3, 0, 0, 0, 5
+
 int kvm_arch_init_vcpu(CPUState *cs)
 int kvm_arch_init_vcpu(CPUState *cs)
 {
 {
     int ret;
     int ret;
+    uint64_t mpidr;
     ARMCPU *cpu = ARM_CPU(cs);
     ARMCPU *cpu = ARM_CPU(cs);
 
 
     if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
     if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
@@ -107,6 +111,17 @@ int kvm_arch_init_vcpu(CPUState *cs)
         return ret;
         return ret;
     }
     }
 
 
+    /*
+     * When KVM is in use, PSCI is emulated in-kernel and not by qemu.
+     * Currently KVM has its own idea about MPIDR assignment, so we
+     * override our defaults with what we get from KVM.
+     */
+    ret = kvm_get_one_reg(cs, ARM64_SYS_REG(ARM_CPU_ID_MPIDR), &mpidr);
+    if (ret) {
+        return ret;
+    }
+    cpu->mp_affinity = mpidr & ARM_MPIDR_HWID_BITMASK;
+
     return kvm_arm_init_cpreg_list(cpu);
     return kvm_arm_init_cpreg_list(cpu);
 }
 }
 
 

+ 6 - 5
target-arm/op_helper.c

@@ -81,9 +81,10 @@ uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def,
 void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
 void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
               uintptr_t retaddr)
               uintptr_t retaddr)
 {
 {
-    int ret;
+    bool ret;
+    uint32_t fsr = 0;
 
 
-    ret = arm_tlb_fill(cs, addr, is_write, mmu_idx);
+    ret = arm_tlb_fill(cs, addr, is_write, mmu_idx, &fsr);
     if (unlikely(ret)) {
     if (unlikely(ret)) {
         ARMCPU *cpu = ARM_CPU(cs);
         ARMCPU *cpu = ARM_CPU(cs);
         CPUARMState *env = &cpu->env;
         CPUARMState *env = &cpu->env;
@@ -96,7 +97,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
         }
         }
 
 
         /* AArch64 syndrome does not have an LPAE bit */
         /* AArch64 syndrome does not have an LPAE bit */
-        syn = ret & ~(1 << 9);
+        syn = fsr & ~(1 << 9);
 
 
         /* For insn and data aborts we assume there is no instruction syndrome
         /* For insn and data aborts we assume there is no instruction syndrome
          * information; this is always true for exceptions reported to EL1.
          * information; this is always true for exceptions reported to EL1.
@@ -107,13 +108,13 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
         } else {
         } else {
             syn = syn_data_abort(same_el, 0, 0, 0, is_write == 1, syn);
             syn = syn_data_abort(same_el, 0, 0, 0, is_write == 1, syn);
             if (is_write == 1 && arm_feature(env, ARM_FEATURE_V6)) {
             if (is_write == 1 && arm_feature(env, ARM_FEATURE_V6)) {
-                ret |= (1 << 11);
+                fsr |= (1 << 11);
             }
             }
             exc = EXCP_DATA_ABORT;
             exc = EXCP_DATA_ABORT;
         }
         }
 
 
         env->exception.vaddress = addr;
         env->exception.vaddress = addr;
-        env->exception.fsr = ret;
+        env->exception.fsr = fsr;
         raise_exception(env, exc, syn, exception_target_el(env));
         raise_exception(env, exc, syn, exception_target_el(env));
     }
     }
 }
 }

+ 17 - 2
target-arm/psci.c

@@ -72,6 +72,21 @@ bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
     }
     }
 }
 }
 
 
+static CPUState *get_cpu_by_id(uint64_t id)
+{
+    CPUState *cpu;
+
+    CPU_FOREACH(cpu) {
+        ARMCPU *armcpu = ARM_CPU(cpu);
+
+        if (armcpu->mp_affinity == id) {
+            return cpu;
+        }
+    }
+
+    return NULL;
+}
+
 void arm_handle_psci_call(ARMCPU *cpu)
 void arm_handle_psci_call(ARMCPU *cpu)
 {
 {
     /*
     /*
@@ -121,7 +136,7 @@ void arm_handle_psci_call(ARMCPU *cpu)
 
 
         switch (param[2]) {
         switch (param[2]) {
         case 0:
         case 0:
-            target_cpu_state = qemu_get_cpu(mpidr & 0xff);
+            target_cpu_state = get_cpu_by_id(mpidr);
             if (!target_cpu_state) {
             if (!target_cpu_state) {
                 ret = QEMU_PSCI_RET_INVALID_PARAMS;
                 ret = QEMU_PSCI_RET_INVALID_PARAMS;
                 break;
                 break;
@@ -153,7 +168,7 @@ void arm_handle_psci_call(ARMCPU *cpu)
         context_id = param[3];
         context_id = param[3];
 
 
         /* change to the cpu we are powering up */
         /* change to the cpu we are powering up */
-        target_cpu_state = qemu_get_cpu(mpidr & 0xff);
+        target_cpu_state = get_cpu_by_id(mpidr);
         if (!target_cpu_state) {
         if (!target_cpu_state) {
             ret = QEMU_PSCI_RET_INVALID_PARAMS;
             ret = QEMU_PSCI_RET_INVALID_PARAMS;
             break;
             break;

+ 103 - 11
target-arm/translate.c

@@ -7175,7 +7175,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
                 break;
                 break;
             }
             }
 
 
-            gen_set_pc_im(s, s->pc);
+            gen_set_pc_im(s, s->pc - 4);
             tmpptr = tcg_const_ptr(ri);
             tmpptr = tcg_const_ptr(ri);
             tcg_syn = tcg_const_i32(syndrome);
             tcg_syn = tcg_const_i32(syndrome);
             gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn);
             gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn);
@@ -9444,6 +9444,9 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
 
 
         op = (insn >> 21) & 0xf;
         op = (insn >> 21) & 0xf;
         if (op == 6) {
         if (op == 6) {
+            if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+                goto illegal_op;
+            }
             /* Halfword pack.  */
             /* Halfword pack.  */
             tmp = load_reg(s, rn);
             tmp = load_reg(s, rn);
             tmp2 = load_reg(s, rm);
             tmp2 = load_reg(s, rm);
@@ -9508,6 +9511,27 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
             store_reg_bx(s, rd, tmp);
             store_reg_bx(s, rd, tmp);
             break;
             break;
         case 1: /* Sign/zero extend.  */
         case 1: /* Sign/zero extend.  */
+            op = (insn >> 20) & 7;
+            switch (op) {
+            case 0: /* SXTAH, SXTH */
+            case 1: /* UXTAH, UXTH */
+            case 4: /* SXTAB, SXTB */
+            case 5: /* UXTAB, UXTB */
+                break;
+            case 2: /* SXTAB16, SXTB16 */
+            case 3: /* UXTAB16, UXTB16 */
+                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+                    goto illegal_op;
+                }
+                break;
+            default:
+                goto illegal_op;
+            }
+            if (rn != 15) {
+                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+                    goto illegal_op;
+                }
+            }
             tmp = load_reg(s, rm);
             tmp = load_reg(s, rm);
             shift = (insn >> 4) & 3;
             shift = (insn >> 4) & 3;
             /* ??? In many cases it's not necessary to do a
             /* ??? In many cases it's not necessary to do a
@@ -9522,7 +9546,8 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
             case 3: gen_uxtb16(tmp); break;
             case 3: gen_uxtb16(tmp); break;
             case 4: gen_sxtb(tmp);   break;
             case 4: gen_sxtb(tmp);   break;
             case 5: gen_uxtb(tmp);   break;
             case 5: gen_uxtb(tmp);   break;
-            default: goto illegal_op;
+            default:
+                g_assert_not_reached();
             }
             }
             if (rn != 15) {
             if (rn != 15) {
                 tmp2 = load_reg(s, rn);
                 tmp2 = load_reg(s, rn);
@@ -9536,6 +9561,9 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
             store_reg(s, rd, tmp);
             store_reg(s, rd, tmp);
             break;
             break;
         case 2: /* SIMD add/subtract.  */
         case 2: /* SIMD add/subtract.  */
+            if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+                goto illegal_op;
+            }
             op = (insn >> 20) & 7;
             op = (insn >> 20) & 7;
             shift = (insn >> 4) & 7;
             shift = (insn >> 4) & 7;
             if ((op & 3) == 3 || (shift & 3) == 3)
             if ((op & 3) == 3 || (shift & 3) == 3)
@@ -9550,6 +9578,9 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
             op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
             op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
             if (op < 4) {
             if (op < 4) {
                 /* Saturating add/subtract.  */
                 /* Saturating add/subtract.  */
+                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+                    goto illegal_op;
+                }
                 tmp = load_reg(s, rn);
                 tmp = load_reg(s, rn);
                 tmp2 = load_reg(s, rm);
                 tmp2 = load_reg(s, rm);
                 if (op & 1)
                 if (op & 1)
@@ -9560,6 +9591,31 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                     gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);
                     gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);
                 tcg_temp_free_i32(tmp2);
                 tcg_temp_free_i32(tmp2);
             } else {
             } else {
+                switch (op) {
+                case 0x0a: /* rbit */
+                case 0x08: /* rev */
+                case 0x09: /* rev16 */
+                case 0x0b: /* revsh */
+                case 0x18: /* clz */
+                    break;
+                case 0x10: /* sel */
+                    if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+                        goto illegal_op;
+                    }
+                    break;
+                case 0x20: /* crc32/crc32c */
+                case 0x21:
+                case 0x22:
+                case 0x28:
+                case 0x29:
+                case 0x2a:
+                    if (!arm_dc_feature(s, ARM_FEATURE_CRC)) {
+                        goto illegal_op;
+                    }
+                    break;
+                default:
+                    goto illegal_op;
+                }
                 tmp = load_reg(s, rn);
                 tmp = load_reg(s, rn);
                 switch (op) {
                 switch (op) {
                 case 0x0a: /* rbit */
                 case 0x0a: /* rbit */
@@ -9596,10 +9652,6 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                     uint32_t sz = op & 0x3;
                     uint32_t sz = op & 0x3;
                     uint32_t c = op & 0x8;
                     uint32_t c = op & 0x8;
 
 
-                    if (!arm_dc_feature(s, ARM_FEATURE_CRC)) {
-                        goto illegal_op;
-                    }
-
                     tmp2 = load_reg(s, rm);
                     tmp2 = load_reg(s, rm);
                     if (sz == 0) {
                     if (sz == 0) {
                         tcg_gen_andi_i32(tmp2, tmp2, 0xff);
                         tcg_gen_andi_i32(tmp2, tmp2, 0xff);
@@ -9617,12 +9669,26 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                     break;
                     break;
                 }
                 }
                 default:
                 default:
-                    goto illegal_op;
+                    g_assert_not_reached();
                 }
                 }
             }
             }
             store_reg(s, rd, tmp);
             store_reg(s, rd, tmp);
             break;
             break;
         case 4: case 5: /* 32-bit multiply.  Sum of absolute differences.  */
         case 4: case 5: /* 32-bit multiply.  Sum of absolute differences.  */
+            switch ((insn >> 20) & 7) {
+            case 0: /* 32 x 32 -> 32 */
+            case 7: /* Unsigned sum of absolute differences.  */
+                break;
+            case 1: /* 16 x 16 -> 32 */
+            case 2: /* Dual multiply add.  */
+            case 3: /* 32 * 16 -> 32msb */
+            case 4: /* Dual multiply subtract.  */
+            case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
+                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+                    goto illegal_op;
+                }
+                break;
+            }
             op = (insn >> 4) & 0xf;
             op = (insn >> 4) & 0xf;
             tmp = load_reg(s, rn);
             tmp = load_reg(s, rn);
             tmp2 = load_reg(s, rm);
             tmp2 = load_reg(s, rm);
@@ -9735,6 +9801,11 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                 store_reg(s, rd, tmp);
                 store_reg(s, rd, tmp);
             } else if ((op & 0xe) == 0xc) {
             } else if ((op & 0xe) == 0xc) {
                 /* Dual multiply accumulate long.  */
                 /* Dual multiply accumulate long.  */
+                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+                    tcg_temp_free_i32(tmp);
+                    tcg_temp_free_i32(tmp2);
+                    goto illegal_op;
+                }
                 if (op & 1)
                 if (op & 1)
                     gen_swap_half(tmp2);
                     gen_swap_half(tmp2);
                 gen_smul_dual(tmp, tmp2);
                 gen_smul_dual(tmp, tmp2);
@@ -9758,6 +9829,11 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                 } else {
                 } else {
                     if (op & 8) {
                     if (op & 8) {
                         /* smlalxy */
                         /* smlalxy */
+                        if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+                            tcg_temp_free_i32(tmp2);
+                            tcg_temp_free_i32(tmp);
+                            goto illegal_op;
+                        }
                         gen_mulxy(tmp, tmp2, op & 2, op & 1);
                         gen_mulxy(tmp, tmp2, op & 2, op & 1);
                         tcg_temp_free_i32(tmp2);
                         tcg_temp_free_i32(tmp2);
                         tmp64 = tcg_temp_new_i64();
                         tmp64 = tcg_temp_new_i64();
@@ -9770,6 +9846,10 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                 }
                 }
                 if (op & 4) {
                 if (op & 4) {
                     /* umaal */
                     /* umaal */
+                    if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+                        tcg_temp_free_i64(tmp64);
+                        goto illegal_op;
+                    }
                     gen_addq_lo(s, tmp64, rs);
                     gen_addq_lo(s, tmp64, rs);
                     gen_addq_lo(s, tmp64, rd);
                     gen_addq_lo(s, tmp64, rd);
                 } else if (op & 0x40) {
                 } else if (op & 0x40) {
@@ -10034,16 +10114,28 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                         tmp2 = tcg_const_i32(imm);
                         tmp2 = tcg_const_i32(imm);
                         if (op & 4) {
                         if (op & 4) {
                             /* Unsigned.  */
                             /* Unsigned.  */
-                            if ((op & 1) && shift == 0)
+                            if ((op & 1) && shift == 0) {
+                                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+                                    tcg_temp_free_i32(tmp);
+                                    tcg_temp_free_i32(tmp2);
+                                    goto illegal_op;
+                                }
                                 gen_helper_usat16(tmp, cpu_env, tmp, tmp2);
                                 gen_helper_usat16(tmp, cpu_env, tmp, tmp2);
-                            else
+                            } else {
                                 gen_helper_usat(tmp, cpu_env, tmp, tmp2);
                                 gen_helper_usat(tmp, cpu_env, tmp, tmp2);
+                            }
                         } else {
                         } else {
                             /* Signed.  */
                             /* Signed.  */
-                            if ((op & 1) && shift == 0)
+                            if ((op & 1) && shift == 0) {
+                                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
+                                    tcg_temp_free_i32(tmp);
+                                    tcg_temp_free_i32(tmp2);
+                                    goto illegal_op;
+                                }
                                 gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);
                                 gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);
-                            else
+                            } else {
                                 gen_helper_ssat(tmp, cpu_env, tmp, tmp2);
                                 gen_helper_ssat(tmp, cpu_env, tmp, tmp2);
+                            }
                         }
                         }
                         tcg_temp_free_i32(tmp2);
                         tcg_temp_free_i32(tmp2);
                         break;
                         break;