diff --git a/MAINTAINERS b/MAINTAINERS index b66c46dcb9..c258391cad 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -613,6 +613,7 @@ S: Maintained F: hw/arm/integratorcp.c F: hw/misc/arm_integrator_debug.c F: include/hw/misc/arm_integrator_debug.h +F: tests/acceptance/machine_arm_integratorcp.py MCIMX6UL EVK / i.MX6ul M: Peter Maydell @@ -686,6 +687,7 @@ F: hw/rtc/twl92230.c F: include/hw/display/blizzard.h F: include/hw/input/tsc2xxx.h F: include/hw/misc/cbus.h +F: tests/acceptance/machine_arm_n8x0.py Palm M: Andrzej Zaborowski diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 3d86691ae0..61635f52c4 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -69,6 +69,7 @@ config INTEGRATOR select INTEGRATOR_DEBUG select PL011 # UART select PL031 # RTC + select PL041 # audio select PL050 # keyboard/mouse select PL110 # pl111 LCD controller select PL181 # display diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index cc845b8534..6d69010d06 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -642,6 +642,7 @@ static void integratorcp_init(MachineState *machine) qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_WPROT, 0)); qdev_connect_gpio_out(dev, 1, qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_CARDIN, 0)); + sysbus_create_varargs("pl041", 0x1d000000, pic[25], NULL); if (nd_table[0].used) smc91c111_init(&nd_table[0], 0xc8000000, pic[27]); diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 1cba9fc302..8409ba853d 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -39,6 +39,7 @@ #include "hw/pci-host/gpex.h" #include "hw/qdev-properties.h" #include "hw/usb.h" +#include "hw/char/pl011.h" #include "net/net.h" #define RAMLIMIT_GB 8192 @@ -409,7 +410,7 @@ static void create_uart(const SBSAMachineState *sms, int uart, { hwaddr base = sbsa_ref_memmap[uart].base; int irq = sbsa_ref_irqmap[uart]; - DeviceState *dev = qdev_create(NULL, "pl011"); + DeviceState *dev = qdev_create(NULL, TYPE_PL011); SysBusDevice *s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index a8191a3e75..856808599d 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -74,6 +74,7 @@ #include "hw/mem/nvdimm.h" #include "hw/acpi/generic_event_device.h" #include "hw/virtio/virtio-iommu.h" +#include "hw/char/pl011.h" #define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ @@ -727,7 +728,7 @@ static void create_uart(const VirtMachineState *vms, int uart, int irq = vms->irqmap[uart]; const char compat[] = "arm,pl011\0arm,primecell"; const char clocknames[] = "uartclk\0apb_pclk"; - DeviceState *dev = qdev_create(NULL, "pl011"); + DeviceState *dev = qdev_create(NULL, TYPE_PL011); SysBusDevice *s = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", chr); diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 3d439a45d5..571cdcd599 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -29,6 +29,7 @@ #include "hw/loader.h" #include "hw/misc/zynq-xadc.h" #include "hw/ssi/ssi.h" +#include "hw/usb/chipidea.h" #include "qemu/error-report.h" #include "hw/sd/sdhci.h" #include "hw/char/cadence_uart.h" @@ -225,8 +226,8 @@ static void zynq_init(MachineState *machine) zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false); zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true); - sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]); - sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]); + sysbus_create_simple(TYPE_CHIPIDEA, 0xE0002000, pic[53 - IRQ_OFFSET]); + sysbus_create_simple(TYPE_CHIPIDEA, 0xE0003000, pic[76 - IRQ_OFFSET]); cadence_uart_create(0xE0000000, pic[59 - IRQ_OFFSET], serial_hd(0)); cadence_uart_create(0xE0001000, pic[82 - IRQ_OFFSET], serial_hd(1)); diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 1cf3daaf4f..403fc7b881 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -22,6 +22,7 @@ #include "hw/misc/unimp.h" #include "hw/intc/arm_gicv3_common.h" #include "hw/arm/xlnx-versal.h" +#include "hw/char/pl011.h" #define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72") #define GEM_REVISION 0x40070106 @@ -144,7 +145,7 @@ static void versal_create_uarts(Versal *s, qemu_irq *pic) DeviceState *dev; MemoryRegion *mr; - dev = qdev_create(NULL, "pl011"); + dev = qdev_create(NULL, TYPE_PL011); s->lpd.iou.uart[i] = SYS_BUS_DEVICE(dev); qdev_prop_set_chr(dev, "chardev", serial_hd(i)); object_property_add_child(OBJECT(s), name, OBJECT(dev), &error_fatal); diff --git a/hw/cpu/a9mpcore.c b/hw/cpu/a9mpcore.c index 1f8bc8a196..b4f6a7e8a5 100644 --- a/hw/cpu/a9mpcore.c +++ b/hw/cpu/a9mpcore.c @@ -16,6 +16,8 @@ #include "hw/qdev-properties.h" #include "hw/core/cpu.h" +#define A9_GIC_NUM_PRIORITY_BITS 5 + static void a9mp_priv_set_irq(void *opaque, int irq, int level) { A9MPPrivState *s = (A9MPPrivState *)opaque; @@ -68,6 +70,8 @@ static void a9mp_priv_realize(DeviceState *dev, Error **errp) gicdev = DEVICE(&s->gic); qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu); qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq); + qdev_prop_set_uint32(gicdev, "num-priority-bits", + A9_GIC_NUM_PRIORITY_BITS); /* Make the GIC's TZ support match the CPUs. We assume that * either all the CPUs have TZ, or none do. diff --git a/hw/cpu/arm11mpcore.c b/hw/cpu/arm11mpcore.c index 2e3e87cc1b..ab9fadb67c 100644 --- a/hw/cpu/arm11mpcore.c +++ b/hw/cpu/arm11mpcore.c @@ -15,6 +15,7 @@ #include "hw/irq.h" #include "hw/qdev-properties.h" +#define ARM11MPCORE_NUM_GIC_PRIORITY_BITS 4 static void mpcore_priv_set_irq(void *opaque, int irq, int level) { @@ -86,6 +87,10 @@ static void mpcore_priv_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(gicdev, "num-cpu", s->num_cpu); qdev_prop_set_uint32(gicdev, "num-irq", s->num_irq); + qdev_prop_set_uint32(gicdev, "num-priority-bits", + ARM11MPCORE_NUM_GIC_PRIORITY_BITS); + + object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); if (err != NULL) { error_propagate(errp, err); diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 1d7da7baa2..c60dc6b5e6 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -641,6 +641,23 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) return ret; } +static uint32_t gic_fullprio_mask(GICState *s, int cpu) +{ + /* + * Return a mask word which clears the unimplemented priority + * bits from a priority value for an interrupt. (Not to be + * confused with the group priority, whose mask depends on BPR.) + */ + int priBits; + + if (gic_is_vcpu(cpu)) { + priBits = GIC_VIRT_MAX_GROUP_PRIO_BITS; + } else { + priBits = s->n_prio_bits; + } + return ~0U << (8 - priBits); +} + void gic_dist_set_priority(GICState *s, int cpu, int irq, uint8_t val, MemTxAttrs attrs) { @@ -651,6 +668,8 @@ void gic_dist_set_priority(GICState *s, int cpu, int irq, uint8_t val, val = 0x80 | (val >> 1); /* Non-secure view */ } + val &= gic_fullprio_mask(s, cpu); + if (irq < GIC_INTERNAL) { s->priority1[irq][cpu] = val; } else { @@ -669,7 +688,7 @@ static uint32_t gic_dist_get_priority(GICState *s, int cpu, int irq, } prio = (prio << 1) & 0xff; /* Non-secure view */ } - return prio; + return prio & gic_fullprio_mask(s, cpu); } static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask, @@ -684,7 +703,7 @@ static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask, return; } } - s->priority_mask[cpu] = pmask; + s->priority_mask[cpu] = pmask & gic_fullprio_mask(s, cpu); } static uint32_t gic_get_priority_mask(GICState *s, int cpu, MemTxAttrs attrs) @@ -2055,6 +2074,16 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) return; } + if (s->n_prio_bits > GIC_MAX_PRIORITY_BITS || + (s->virt_extn ? s->n_prio_bits < GIC_VIRT_MAX_GROUP_PRIO_BITS : + s->n_prio_bits < GIC_MIN_PRIORITY_BITS)) { + error_setg(errp, "num-priority-bits cannot be greater than %d" + " or less than %d", GIC_MAX_PRIORITY_BITS, + s->virt_extn ? GIC_VIRT_MAX_GROUP_PRIO_BITS : + GIC_MIN_PRIORITY_BITS); + return; + } + /* This creates distributor, main CPU interface (s->cpuiomem[0]) and if * enabled, virtualization extensions related interfaces (main virtual * interface (s->vifaceiomem[0]) and virtual CPU interface). diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index e6c4fe7a5a..7b44d5625b 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -357,6 +357,7 @@ static Property arm_gic_common_properties[] = { DEFINE_PROP_BOOL("has-security-extensions", GICState, security_extn, 0), /* True if the GIC should implement the virtualization extensions */ DEFINE_PROP_BOOL("has-virtualization-extensions", GICState, virt_extn, 0), + DEFINE_PROP_UINT32("num-priority-bits", GICState, n_prio_bits, 8), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 9deb15e7e6..d7df423a7a 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -551,7 +551,16 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, &error_abort); } + } else if (kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) { + error_setg_errno(errp, -ret, "error creating in-kernel VGIC"); + error_append_hint(errp, + "Perhaps the host CPU does not support GICv2?\n"); } else if (ret != -ENODEV && ret != -ENOTSUP) { + /* + * Very ancient kernel without KVM_CAP_DEVICE_CTRL: assume that + * ENODEV or ENOTSUP mean "can't create GICv2 with KVM_CREATE_DEVICE", + * and that we will get a GICv2 via KVM_CREATE_IRQCHIP. + */ error_setg_errno(errp, -ret, "error creating in-kernel VGIC"); return; } diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 22a43e4984..a62587eb3f 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -1262,12 +1262,12 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) case 0xd84: /* CSSELR */ return cpu->env.v7m.csselr[attrs.secure]; case 0xd88: /* CPACR */ - if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) { + if (!cpu_isar_feature(aa32_vfp_simd, cpu)) { return 0; } return cpu->env.v7m.cpacr[attrs.secure]; case 0xd8c: /* NSACR */ - if (!attrs.secure || !arm_feature(&cpu->env, ARM_FEATURE_VFP)) { + if (!attrs.secure || !cpu_isar_feature(aa32_vfp_simd, cpu)) { return 0; } return cpu->env.v7m.nsacr; @@ -1417,7 +1417,7 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) } return cpu->env.v7m.sfar; case 0xf34: /* FPCCR */ - if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) { + if (!cpu_isar_feature(aa32_vfp_simd, cpu)) { return 0; } if (attrs.secure) { @@ -1444,12 +1444,12 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) return value; } case 0xf38: /* FPCAR */ - if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) { + if (!cpu_isar_feature(aa32_vfp_simd, cpu)) { return 0; } return cpu->env.v7m.fpcar[attrs.secure]; case 0xf3c: /* FPDSCR */ - if (!arm_feature(&cpu->env, ARM_FEATURE_VFP)) { + if (!cpu_isar_feature(aa32_vfp_simd, cpu)) { return 0; } return cpu->env.v7m.fpdscr[attrs.secure]; @@ -1711,13 +1711,13 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, } break; case 0xd88: /* CPACR */ - if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) { + if (cpu_isar_feature(aa32_vfp_simd, cpu)) { /* We implement only the Floating Point extension's CP10/CP11 */ cpu->env.v7m.cpacr[attrs.secure] = value & (0xf << 20); } break; case 0xd8c: /* NSACR */ - if (attrs.secure && arm_feature(&cpu->env, ARM_FEATURE_VFP)) { + if (attrs.secure && cpu_isar_feature(aa32_vfp_simd, cpu)) { /* We implement only the Floating Point extension's CP10/CP11 */ cpu->env.v7m.nsacr = value & (3 << 10); } @@ -1951,7 +1951,7 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, break; } case 0xf34: /* FPCCR */ - if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) { + if (cpu_isar_feature(aa32_vfp_simd, cpu)) { /* Not all bits here are banked. */ uint32_t fpccr_s; @@ -2005,13 +2005,13 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, } break; case 0xf38: /* FPCAR */ - if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) { + if (cpu_isar_feature(aa32_vfp_simd, cpu)) { value &= ~7; cpu->env.v7m.fpcar[attrs.secure] = value; } break; case 0xf3c: /* FPDSCR */ - if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) { + if (cpu_isar_feature(aa32_vfp_simd, cpu)) { value &= 0x07c00000; cpu->env.v7m.fpdscr[attrs.secure] = value; } diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index b22fb258be..5b7991cffe 100644 --- a/hw/usb/hcd-ehci-sysbus.c +++ b/hw/usb/hcd-ehci-sysbus.c @@ -115,22 +115,6 @@ static const TypeInfo ehci_platform_type_info = { .class_init = ehci_platform_class_init, }; -static void ehci_xlnx_class_init(ObjectClass *oc, void *data) -{ - SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); - DeviceClass *dc = DEVICE_CLASS(oc); - - set_bit(DEVICE_CATEGORY_USB, dc->categories); - sec->capsbase = 0x100; - sec->opregbase = 0x140; -} - -static const TypeInfo ehci_xlnx_type_info = { - .name = "xlnx,ps7-usb", - .parent = TYPE_SYS_BUS_EHCI, - .class_init = ehci_xlnx_class_init, -}; - static void ehci_exynos4210_class_init(ObjectClass *oc, void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); @@ -267,7 +251,6 @@ static void ehci_sysbus_register_types(void) { type_register_static(&ehci_type_info); type_register_static(&ehci_platform_type_info); - type_register_static(&ehci_xlnx_type_info); type_register_static(&ehci_exynos4210_type_info); type_register_static(&ehci_tegra2_type_info); type_register_static(&ehci_ppc4xx_type_info); diff --git a/include/hw/intc/arm_gic.h b/include/hw/intc/arm_gic.h index ed703a1720..303b9748cb 100644 --- a/include/hw/intc/arm_gic.h +++ b/include/hw/intc/arm_gic.h @@ -68,6 +68,8 @@ /* Number of SGI target-list bits */ #define GIC_TARGETLIST_BITS 8 +#define GIC_MAX_PRIORITY_BITS 8 +#define GIC_MIN_PRIORITY_BITS 4 #define TYPE_ARM_GIC "arm_gic" #define ARM_GIC(obj) \ diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h index b5585fec45..6e0d6b8a88 100644 --- a/include/hw/intc/arm_gic_common.h +++ b/include/hw/intc/arm_gic_common.h @@ -96,6 +96,7 @@ typedef struct GICState { uint16_t priority_mask[GIC_NCPU_VCPU]; uint16_t running_priority[GIC_NCPU_VCPU]; uint16_t current_pending[GIC_NCPU_VCPU]; + uint32_t n_prio_bits; /* If we present the GICv2 without security extensions to a guest, * the guest can configure the GICC_CTLR to configure group 1 binary point diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c index b0e753801b..d96fc27ce1 100644 --- a/linux-user/arm/signal.c +++ b/linux-user/arm/signal.c @@ -346,7 +346,7 @@ static void setup_sigframe_v2(struct target_ucontext_v2 *uc, setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]); /* Save coprocessor signal frame. */ regspace = uc->tuc_regspace; - if (arm_feature(env, ARM_FEATURE_VFP)) { + if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) { regspace = setup_sigframe_v2_vfp(regspace, env); } if (arm_feature(env, ARM_FEATURE_IWMMXT)) { @@ -671,7 +671,7 @@ static int do_sigframe_return_v2(CPUARMState *env, /* Restore coprocessor signal frame */ regspace = uc->tuc_regspace; - if (arm_feature(env, ARM_FEATURE_VFP)) { + if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) { regspace = restore_sigframe_v2_vfp(env, regspace); if (!regspace) { return 1; diff --git a/linux-user/elfload.c b/linux-user/elfload.c index b1a895f24c..db748c5877 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -468,22 +468,25 @@ static uint32_t get_elf_hwcap(void) /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */ GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP); - GET_FEATURE(ARM_FEATURE_VFP, ARM_HWCAP_ARM_VFP); GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT); GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE); GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON); - GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPv3); GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS); - GET_FEATURE(ARM_FEATURE_VFP4, ARM_HWCAP_ARM_VFPv4); + GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE); GET_FEATURE_ID(aa32_arm_div, ARM_HWCAP_ARM_IDIVA); GET_FEATURE_ID(aa32_thumb_div, ARM_HWCAP_ARM_IDIVT); - /* All QEMU's VFPv3 CPUs have 32 registers, see VFP_DREG in translate.c. - * Note that the ARM_HWCAP_ARM_VFPv3D16 bit is always the inverse of - * ARM_HWCAP_ARM_VFPD32 (and so always clear for QEMU); it is unrelated - * to our VFP_FP16 feature bit. - */ - GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPD32); - GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE); + GET_FEATURE_ID(aa32_vfp, ARM_HWCAP_ARM_VFP); + + if (cpu_isar_feature(aa32_fpsp_v3, cpu) || + cpu_isar_feature(aa32_fpdp_v3, cpu)) { + hwcaps |= ARM_HWCAP_ARM_VFPv3; + if (cpu_isar_feature(aa32_simd_r32, cpu)) { + hwcaps |= ARM_HWCAP_ARM_VFPD32; + } else { + hwcaps |= ARM_HWCAP_ARM_VFPv3D16; + } + } + GET_FEATURE_ID(aa32_simdfmac, ARM_HWCAP_ARM_VFPv4); return hwcaps; } @@ -658,6 +661,8 @@ static uint32_t get_elf_hwcap(void) GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB); GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM); GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP); + GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC); + GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC); return hwcaps; } diff --git a/target/arm/arch_dump.c b/target/arm/arch_dump.c index 2345dec3c2..7693e17e96 100644 --- a/target/arm/arch_dump.c +++ b/target/arm/arch_dump.c @@ -363,9 +363,11 @@ int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, int cpuid, void *opaque) { struct arm_note note; - CPUARMState *env = &ARM_CPU(cs)->env; + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; DumpState *s = opaque; - int ret, i, fpvalid = !!arm_feature(env, ARM_FEATURE_VFP); + int ret, i; + bool fpvalid = cpu_isar_feature(aa32_vfp_simd, cpu); arm_note_init(¬e, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus)); @@ -444,7 +446,6 @@ int cpu_get_dump_info(ArchDumpInfo *info, ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) { ARMCPU *cpu = ARM_CPU(first_cpu); - CPUARMState *env = &cpu->env; size_t note_size; if (class == ELFCLASS64) { @@ -452,12 +453,12 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) note_size += AARCH64_PRFPREG_NOTE_SIZE; #ifdef TARGET_AARCH64 if (cpu_isar_feature(aa64_sve, cpu)) { - note_size += AARCH64_SVE_NOTE_SIZE(env); + note_size += AARCH64_SVE_NOTE_SIZE(&cpu->env); } #endif } else { note_size = ARM_PRSTATUS_NOTE_SIZE; - if (arm_feature(env, ARM_FEATURE_VFP)) { + if (cpu_isar_feature(aa32_vfp_simd, cpu)) { note_size += ARM_VFP_NOTE_SIZE; } } diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 2eadf4dcb8..e6016e33ce 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -293,7 +293,7 @@ static void arm_cpu_reset(CPUState *s) env->v7m.ccr[M_REG_S] |= R_V7M_CCR_UNALIGN_TRP_MASK; } - if (arm_feature(env, ARM_FEATURE_VFP)) { + if (cpu_isar_feature(aa32_vfp_simd, cpu)) { env->v7m.fpccr[M_REG_NS] = R_V7M_FPCCR_ASPEN_MASK; env->v7m.fpccr[M_REG_S] = R_V7M_FPCCR_ASPEN_MASK | R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK; @@ -1011,7 +1011,7 @@ static void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags) int numvfpregs = 0; if (cpu_isar_feature(aa32_simd_r32, cpu)) { numvfpregs = 32; - } else if (arm_feature(env, ARM_FEATURE_VFP)) { + } else if (cpu_isar_feature(aa32_vfp_simd, cpu)) { numvfpregs = 16; } for (i = 0; i < numvfpregs; i++) { @@ -1208,13 +1208,6 @@ void arm_cpu_post_init(Object *obj) if (arm_feature(&cpu->env, ARM_FEATURE_M)) { set_feature(&cpu->env, ARM_FEATURE_PMSA); } - /* Similarly for the VFP feature bits */ - if (arm_feature(&cpu->env, ARM_FEATURE_VFP4)) { - set_feature(&cpu->env, ARM_FEATURE_VFP3); - } - if (arm_feature(&cpu->env, ARM_FEATURE_VFP3)) { - set_feature(&cpu->env, ARM_FEATURE_VFP); - } if (arm_feature(&cpu->env, ARM_FEATURE_CBAR) || arm_feature(&cpu->env, ARM_FEATURE_CBAR_RO)) { @@ -1260,7 +1253,9 @@ void arm_cpu_post_init(Object *obj) * KVM does not currently allow us to lie to the guest about its * ID/feature registers, so the guest always sees what the host has. */ - if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) { + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) + ? cpu_isar_feature(aa64_fp_simd, cpu) + : cpu_isar_feature(aa32_vfp, cpu)) { cpu->has_vfp = true; if (!kvm_enabled()) { qdev_property_add_static(DEVICE(obj), &arm_cpu_has_vfp_property); @@ -1440,10 +1435,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) uint64_t t; uint32_t u; - unset_feature(env, ARM_FEATURE_VFP); - unset_feature(env, ARM_FEATURE_VFP3); - unset_feature(env, ARM_FEATURE_VFP4); - t = cpu->isar.id_aa64isar1; t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 0); cpu->isar.id_aa64isar1 = t; @@ -1510,7 +1501,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) u = FIELD_DP32(u, MVFR1, SIMDINT, 0); u = FIELD_DP32(u, MVFR1, SIMDSP, 0); u = FIELD_DP32(u, MVFR1, SIMDHP, 0); - u = FIELD_DP32(u, MVFR1, SIMDFMAC, 0); cpu->isar.mvfr1 = u; u = cpu->isar.mvfr2; @@ -1533,6 +1523,11 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) u = cpu->isar.mvfr0; u = FIELD_DP32(u, MVFR0, SIMDREG, 0); cpu->isar.mvfr0 = u; + + /* Despite the name, this field covers both VFP and Neon */ + u = cpu->isar.mvfr1; + u = FIELD_DP32(u, MVFR1, SIMDFMAC, 0); + cpu->isar.mvfr1 = u; } if (arm_feature(env, ARM_FEATURE_M) && !cpu->has_dsp) { @@ -1636,8 +1631,9 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) * We rely on no XScale CPU having VFP so we can use the same bits in the * TB flags field for VECSTRIDE and XSCALE_CPAR. */ - assert(!(arm_feature(env, ARM_FEATURE_VFP) && - arm_feature(env, ARM_FEATURE_XSCALE))); + assert(arm_feature(&cpu->env, ARM_FEATURE_AARCH64) || + !cpu_isar_feature(aa32_vfp_simd, cpu) || + !arm_feature(env, ARM_FEATURE_XSCALE)); if (arm_feature(env, ARM_FEATURE_V7) && !arm_feature(env, ARM_FEATURE_M) && @@ -1858,7 +1854,6 @@ static void arm926_initfn(Object *obj) cpu->dtb_compatible = "arm,arm926"; set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_VFP); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN); cpu->midr = 0x41069265; @@ -1899,7 +1894,6 @@ static void arm1026_initfn(Object *obj) cpu->dtb_compatible = "arm,arm1026"; set_feature(&cpu->env, ARM_FEATURE_V5); - set_feature(&cpu->env, ARM_FEATURE_VFP); set_feature(&cpu->env, ARM_FEATURE_AUXCR); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN); @@ -1947,7 +1941,6 @@ static void arm1136_r2_initfn(Object *obj) cpu->dtb_compatible = "arm,arm1136"; set_feature(&cpu->env, ARM_FEATURE_V6); - set_feature(&cpu->env, ARM_FEATURE_VFP); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); @@ -1979,7 +1972,6 @@ static void arm1136_initfn(Object *obj) cpu->dtb_compatible = "arm,arm1136"; set_feature(&cpu->env, ARM_FEATURE_V6K); set_feature(&cpu->env, ARM_FEATURE_V6); - set_feature(&cpu->env, ARM_FEATURE_VFP); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS); @@ -2010,7 +2002,6 @@ static void arm1176_initfn(Object *obj) cpu->dtb_compatible = "arm,arm1176"; set_feature(&cpu->env, ARM_FEATURE_V6K); - set_feature(&cpu->env, ARM_FEATURE_VFP); set_feature(&cpu->env, ARM_FEATURE_VAPA); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG); @@ -2043,7 +2034,6 @@ static void arm11mpcore_initfn(Object *obj) cpu->dtb_compatible = "arm,arm11mpcore"; set_feature(&cpu->env, ARM_FEATURE_V6K); - set_feature(&cpu->env, ARM_FEATURE_VFP); set_feature(&cpu->env, ARM_FEATURE_VAPA); set_feature(&cpu->env, ARM_FEATURE_MPIDR); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); @@ -2109,7 +2099,6 @@ static void cortex_m4_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_M); set_feature(&cpu->env, ARM_FEATURE_M_MAIN); set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); - set_feature(&cpu->env, ARM_FEATURE_VFP4); cpu->midr = 0x410fc240; /* r0p0 */ cpu->pmsav7_dregion = 8; cpu->isar.mvfr0 = 0x10110021; @@ -2140,7 +2129,6 @@ static void cortex_m7_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_M); set_feature(&cpu->env, ARM_FEATURE_M_MAIN); set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); - set_feature(&cpu->env, ARM_FEATURE_VFP4); cpu->midr = 0x411fc272; /* r1p2 */ cpu->pmsav7_dregion = 8; cpu->isar.mvfr0 = 0x10110221; @@ -2172,7 +2160,6 @@ static void cortex_m33_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_M_MAIN); set_feature(&cpu->env, ARM_FEATURE_M_SECURITY); set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP); - set_feature(&cpu->env, ARM_FEATURE_VFP4); cpu->midr = 0x410fd213; /* r0p3 */ cpu->pmsav7_dregion = 16; cpu->sau_sregion = 8; @@ -2256,7 +2243,6 @@ static void cortex_r5f_initfn(Object *obj) ARMCPU *cpu = ARM_CPU(obj); cortex_r5_initfn(obj); - set_feature(&cpu->env, ARM_FEATURE_VFP3); cpu->isar.mvfr0 = 0x10110221; cpu->isar.mvfr1 = 0x00000011; } @@ -2275,7 +2261,6 @@ static void cortex_a8_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a8"; set_feature(&cpu->env, ARM_FEATURE_V7); - set_feature(&cpu->env, ARM_FEATURE_VFP3); set_feature(&cpu->env, ARM_FEATURE_NEON); set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS); @@ -2343,7 +2328,6 @@ static void cortex_a9_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a9"; set_feature(&cpu->env, ARM_FEATURE_V7); - set_feature(&cpu->env, ARM_FEATURE_VFP3); set_feature(&cpu->env, ARM_FEATURE_NEON); set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); set_feature(&cpu->env, ARM_FEATURE_EL3); @@ -2408,7 +2392,6 @@ static void cortex_a7_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a7"; set_feature(&cpu->env, ARM_FEATURE_V7VE); - set_feature(&cpu->env, ARM_FEATURE_VFP4); set_feature(&cpu->env, ARM_FEATURE_NEON); set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); @@ -2454,7 +2437,6 @@ static void cortex_a15_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a15"; set_feature(&cpu->env, ARM_FEATURE_V7VE); - set_feature(&cpu->env, ARM_FEATURE_VFP4); set_feature(&cpu->env, ARM_FEATURE_NEON); set_feature(&cpu->env, ARM_FEATURE_THUMB2EE); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 65171cb30e..0b84742b66 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -904,7 +904,7 @@ struct ARMCPU { /* The elements of this array are the CCSIDR values for each cache, * in the order L1DCache, L1ICache, L2DCache, L2ICache, etc. */ - uint32_t ccsidr[16]; + uint64_t ccsidr[16]; uint64_t reset_cbar; uint32_t reset_auxcr; bool reset_hivecs; @@ -1880,7 +1880,6 @@ QEMU_BUILD_BUG_ON(ARRAY_SIZE(((ARMCPU *)0)->ccsidr) <= R_V7M_CSSELR_INDEX_MASK); * mapping in linux-user/elfload.c:get_elf_hwcap(). */ enum arm_features { - ARM_FEATURE_VFP, ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */ ARM_FEATURE_XSCALE, /* Intel XScale extensions. */ ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */ @@ -1889,7 +1888,6 @@ enum arm_features { ARM_FEATURE_V7, ARM_FEATURE_THUMB2, ARM_FEATURE_PMSA, /* no MMU; may have Memory Protection Unit */ - ARM_FEATURE_VFP3, ARM_FEATURE_NEON, ARM_FEATURE_M, /* Microcontroller profile. */ ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */ @@ -1900,7 +1898,6 @@ enum arm_features { ARM_FEATURE_V5, ARM_FEATURE_STRONGARM, ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */ - ARM_FEATURE_VFP4, /* VFPv4 (implies that NEON is v2) */ ARM_FEATURE_GENERIC_TIMER, ARM_FEATURE_MVFR, /* Media and VFP Feature Registers 0 and 1 */ ARM_FEATURE_DUMMY_C15_REGS, /* RAZ/WI all of cp15 crn=15 */ @@ -3450,6 +3447,15 @@ static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) == 1; } +static inline bool isar_feature_aa32_vfp_simd(const ARMISARegisters *id) +{ + /* + * Return true if either VFP or SIMD is implemented. + * In this case, a minimum of VFP w/ D0-D15. + */ + return FIELD_EX32(id->mvfr0, MVFR0, SIMDREG) > 0; +} + static inline bool isar_feature_aa32_simd_r32(const ARMISARegisters *id) { /* Return true if D16-D31 are implemented */ @@ -3461,12 +3467,35 @@ static inline bool isar_feature_aa32_fpshvec(const ARMISARegisters *id) return FIELD_EX32(id->mvfr0, MVFR0, FPSHVEC) > 0; } -static inline bool isar_feature_aa32_fpdp(const ARMISARegisters *id) +static inline bool isar_feature_aa32_fpsp_v2(const ARMISARegisters *id) { - /* Return true if CPU supports double precision floating point */ + /* Return true if CPU supports single precision floating point, VFPv2 */ + return FIELD_EX32(id->mvfr0, MVFR0, FPSP) > 0; +} + +static inline bool isar_feature_aa32_fpsp_v3(const ARMISARegisters *id) +{ + /* Return true if CPU supports single precision floating point, VFPv3 */ + return FIELD_EX32(id->mvfr0, MVFR0, FPSP) >= 2; +} + +static inline bool isar_feature_aa32_fpdp_v2(const ARMISARegisters *id) +{ + /* Return true if CPU supports double precision floating point, VFPv2 */ return FIELD_EX32(id->mvfr0, MVFR0, FPDP) > 0; } +static inline bool isar_feature_aa32_fpdp_v3(const ARMISARegisters *id) +{ + /* Return true if CPU supports double precision floating point, VFPv3 */ + return FIELD_EX32(id->mvfr0, MVFR0, FPDP) >= 2; +} + +static inline bool isar_feature_aa32_vfp(const ARMISARegisters *id) +{ + return isar_feature_aa32_fpsp_v2(id) || isar_feature_aa32_fpdp_v2(id); +} + /* * We always set the FP and SIMD FP16 fields to indicate identical * levels of support (assuming SIMD is implemented at all), so @@ -3482,6 +3511,18 @@ static inline bool isar_feature_aa32_fp16_dpconv(const ARMISARegisters *id) return FIELD_EX32(id->mvfr1, MVFR1, FPHP) > 1; } +/* + * Note that this ID register field covers both VFP and Neon FMAC, + * so should usually be tested in combination with some other + * check that confirms the presence of whichever of VFP or Neon is + * relevant, to avoid accidentally enabling a Neon feature on + * a VFP-no-Neon core or vice-versa. + */ +static inline bool isar_feature_aa32_simdfmac(const ARMISARegisters *id) +{ + return FIELD_EX32(id->mvfr1, MVFR1, SIMDFMAC) != 0; +} + static inline bool isar_feature_aa32_vsel(const ARMISARegisters *id) { return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 1; @@ -3536,6 +3577,11 @@ static inline bool isar_feature_aa32_ac2(const ARMISARegisters *id) return FIELD_EX32(id->id_mmfr4, ID_MMFR4, AC2) != 0; } +static inline bool isar_feature_aa32_ccidx(const ARMISARegisters *id) +{ + return FIELD_EX32(id->id_mmfr4, ID_MMFR4, CCIDX) != 0; +} + /* * 64-bit feature tests via id registers. */ @@ -3669,6 +3715,12 @@ static inline bool isar_feature_aa64_dcpodp(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) >= 2; } +static inline bool isar_feature_aa64_fp_simd(const ARMISARegisters *id) +{ + /* We always set the AdvSIMD and FP fields identically. */ + return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) != 0xf; +} + static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id) { /* We always set the AdvSIMD and FP fields identically wrt FP16. */ @@ -3723,8 +3775,23 @@ static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id) static inline bool isar_feature_aa64_pmu_8_4(const ARMISARegisters *id) { - return FIELD_EX32(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 5 && - FIELD_EX32(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; + return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 5 && + FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf; +} + +static inline bool isar_feature_aa64_rcpc_8_3(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) != 0; +} + +static inline bool isar_feature_aa64_rcpc_8_4(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) >= 2; +} + +static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0; } /* @@ -3750,6 +3817,11 @@ static inline bool isar_feature_any_pmu_8_4(const ARMISARegisters *id) return isar_feature_aa64_pmu_8_4(id) || isar_feature_aa32_pmu_8_4(id); } +static inline bool isar_feature_any_ccidx(const ARMISARegisters *id) +{ + return isar_feature_aa64_ccidx(id) || isar_feature_aa32_ccidx(id); +} + /* * Forward to the above feature tests given an ARMCPU pointer. */ diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 0929401a4d..b842e2b664 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -102,7 +102,6 @@ static void aarch64_a57_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a57"; set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_VFP4); set_feature(&cpu->env, ARM_FEATURE_NEON); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_AARCH64); @@ -156,7 +155,6 @@ static void aarch64_a53_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a53"; set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_VFP4); set_feature(&cpu->env, ARM_FEATURE_NEON); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_AARCH64); @@ -210,7 +208,6 @@ static void aarch64_a72_initfn(Object *obj) cpu->dtb_compatible = "arm,cortex-a72"; set_feature(&cpu->env, ARM_FEATURE_V8); - set_feature(&cpu->env, ARM_FEATURE_VFP4); set_feature(&cpu->env, ARM_FEATURE_NEON); set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); set_feature(&cpu->env, ARM_FEATURE_AARCH64); @@ -657,6 +654,7 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* ARMv8.4-RCPC */ cpu->isar.id_aa64isar1 = t; t = cpu->isar.id_aa64pfr0; @@ -704,6 +702,7 @@ static void aarch64_max_initfn(Object *obj) cpu->isar.id_mmfr3 = u; u = cpu->isar.id_mmfr4; + u = FIELD_DP32(u, ID_MMFR4, HPDS, 1); /* AA32HPD */ u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ cpu->isar.id_mmfr4 = u; diff --git a/target/arm/helper.c b/target/arm/helper.c index 79db169e04..6be9ffa09e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -894,7 +894,7 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, * ASEDIS [31] and D32DIS [30] are both UNK/SBZP without VFP. * TRCDIS [28] is RAZ/WI since we do not implement a trace macrocell. */ - if (arm_feature(env, ARM_FEATURE_VFP)) { + if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) { /* VFP coprocessor: cp10 & cp11 [23:20] */ mask |= (1 << 31) | (1 << 30) | (0xf << 20); @@ -6726,6 +6726,21 @@ static const ARMCPRegInfo predinv_reginfo[] = { REGINFO_SENTINEL }; +static uint64_t ccsidr2_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + /* Read the high 32 bits of the current CCSIDR */ + return extract64(ccsidr_read(env, ri), 32, 32); +} + +static const ARMCPRegInfo ccsidr2_reginfo[] = { + { .name = "CCSIDR2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 1, .crn = 0, .crm = 0, .opc2 = 2, + .access = PL1_R, + .accessfn = access_aa64_tid2, + .readfn = ccsidr2_read, .type = ARM_CP_NO_RAW }, + REGINFO_SENTINEL +}; + static CPAccessResult access_aa64_tid3(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { @@ -7788,6 +7803,10 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, predinv_reginfo); } + if (cpu_isar_feature(any_ccidx, cpu)) { + define_arm_cp_regs(cpu, ccsidr2_reginfo); + } + #ifndef CONFIG_USER_ONLY /* * Register redirections and aliases must be done last, @@ -7814,7 +7833,7 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu) } else if (cpu_isar_feature(aa32_simd_r32, cpu)) { gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg, 35, "arm-vfp3.xml", 0); - } else if (arm_feature(env, ARM_FEATURE_VFP)) { + } else if (cpu_isar_feature(aa32_vfp_simd, cpu)) { gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg, 19, "arm-vfp.xml", 0); } diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c index 7981ae3bc4..f703c4fcad 100644 --- a/target/arm/kvm32.c +++ b/target/arm/kvm32.c @@ -147,7 +147,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) * bits, but a few must be tested. */ set_feature(&features, ARM_FEATURE_V7VE); - set_feature(&features, ARM_FEATURE_VFP3); set_feature(&features, ARM_FEATURE_GENERIC_TIMER); if (extract32(id_pfr0, 12, 4) == 1) { @@ -156,10 +155,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) if (extract32(ahcf->isar.mvfr1, 12, 4) == 1) { set_feature(&features, ARM_FEATURE_NEON); } - if (extract32(ahcf->isar.mvfr1, 28, 4) == 1) { - /* FMAC support implies VFPv4 */ - set_feature(&features, ARM_FEATURE_VFP4); - } ahcf->features = features; diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index 0ad96c3500..93ba1448da 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -649,7 +649,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) * feature bits. */ set_feature(&features, ARM_FEATURE_V8); - set_feature(&features, ARM_FEATURE_VFP4); set_feature(&features, ARM_FEATURE_NEON); set_feature(&features, ARM_FEATURE_AARCH64); set_feature(&features, ARM_FEATURE_PMU); diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index 33d414a684..5e8a795d20 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -738,7 +738,8 @@ static uint32_t v7m_integrity_sig(CPUARMState *env, uint32_t lr) */ uint32_t sig = 0xfefa125a; - if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MASK)) { + if (!cpu_isar_feature(aa32_vfp_simd, env_archcpu(env)) + || (lr & R_V7M_EXCRET_FTYPE_MASK)) { sig |= 1; } return sig; @@ -841,7 +842,7 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain, if (dotailchain) { /* Sanitize LR FType and PREFIX bits */ - if (!arm_feature(env, ARM_FEATURE_VFP)) { + if (!cpu_isar_feature(aa32_vfp_simd, cpu)) { lr |= R_V7M_EXCRET_FTYPE_MASK; } lr = deposit32(lr, 24, 8, 0xff); @@ -1373,7 +1374,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu) ftype = excret & R_V7M_EXCRET_FTYPE_MASK; - if (!arm_feature(env, ARM_FEATURE_VFP) && !ftype) { + if (!ftype && !cpu_isar_feature(aa32_vfp_simd, cpu)) { qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero FTYPE in exception " "exit PC value 0x%" PRIx32 " is UNPREDICTABLE " "if FPU not present\n", @@ -2450,7 +2451,7 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 0, * RES0 if the FPU is not present, and is stored in the S bank */ - if (arm_feature(env, ARM_FEATURE_VFP) && + if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env)) && extract32(env->v7m.nsacr, 10, 1)) { env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK; env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK; @@ -2565,7 +2566,7 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK; env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK; } - if (arm_feature(env, ARM_FEATURE_VFP)) { + if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) { /* * SFPA is RAZ/WI from NS or if no FPU. * FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present. diff --git a/target/arm/machine.c b/target/arm/machine.c index 241890ac8c..c5a2114f51 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -9,9 +9,10 @@ static bool vfp_needed(void *opaque) { ARMCPU *cpu = opaque; - CPUARMState *env = &cpu->env; - return arm_feature(env, ARM_FEATURE_VFP); + return (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) + ? cpu_isar_feature(aa64_fp_simd, cpu) + : cpu_isar_feature(aa32_vfp_simd, cpu)); } static int get_fpscr(QEMUFile *f, void *opaque, size_t size, diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 596bf4cf73..579180af0a 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -3142,6 +3142,8 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn, int rs = extract32(insn, 16, 5); int rn = extract32(insn, 5, 5); int o3_opc = extract32(insn, 12, 4); + bool r = extract32(insn, 22, 1); + bool a = extract32(insn, 23, 1); TCGv_i64 tcg_rs, clean_addr; AtomicThreeOpFn *fn; @@ -3177,6 +3179,13 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn, case 010: /* SWP */ fn = tcg_gen_atomic_xchg_i64; break; + case 014: /* LDAPR, LDAPRH, LDAPRB */ + if (!dc_isar_feature(aa64_rcpc_8_3, s) || + rs != 31 || a != 1 || r != 0) { + unallocated_encoding(s); + return; + } + break; default: unallocated_encoding(s); return; @@ -3186,6 +3195,21 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn, gen_check_sp_alignment(s); } clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn)); + + if (o3_opc == 014) { + /* + * LDAPR* are a special case because they are a simple load, not a + * fetch-and-do-something op. + * The architectural consistency requirements here are weaker than + * full load-acquire (we only need "load-acquire processor consistent"), + * but we choose to implement them as full LDAQ. + */ + do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, false, false, + true, rt, disas_ldst_compute_iss_sf(size, false, 0), true); + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); + return; + } + tcg_rs = read_cpu_reg(s, rs, true); if (o3_opc == 1) { /* LDCLR */ @@ -3259,6 +3283,88 @@ static void disas_ldst_pac(DisasContext *s, uint32_t insn, } } +/* + * LDAPR/STLR (unscaled immediate) + * + * 31 30 24 22 21 12 10 5 0 + * +------+-------------+-----+---+--------+-----+----+-----+ + * | size | 0 1 1 0 0 1 | opc | 0 | imm9 | 0 0 | Rn | Rt | + * +------+-------------+-----+---+--------+-----+----+-----+ + * + * Rt: source or destination register + * Rn: base register + * imm9: unscaled immediate offset + * opc: 00: STLUR*, 01/10/11: various LDAPUR* + * size: size of load/store + */ +static void disas_ldst_ldapr_stlr(DisasContext *s, uint32_t insn) +{ + int rt = extract32(insn, 0, 5); + int rn = extract32(insn, 5, 5); + int offset = sextract32(insn, 12, 9); + int opc = extract32(insn, 22, 2); + int size = extract32(insn, 30, 2); + TCGv_i64 clean_addr, dirty_addr; + bool is_store = false; + bool is_signed = false; + bool extend = false; + bool iss_sf; + + if (!dc_isar_feature(aa64_rcpc_8_4, s)) { + unallocated_encoding(s); + return; + } + + switch (opc) { + case 0: /* STLURB */ + is_store = true; + break; + case 1: /* LDAPUR* */ + break; + case 2: /* LDAPURS* 64-bit variant */ + if (size == 3) { + unallocated_encoding(s); + return; + } + is_signed = true; + break; + case 3: /* LDAPURS* 32-bit variant */ + if (size > 1) { + unallocated_encoding(s); + return; + } + is_signed = true; + extend = true; /* zero-extend 32->64 after signed load */ + break; + default: + g_assert_not_reached(); + } + + iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc); + + if (rn == 31) { + gen_check_sp_alignment(s); + } + + dirty_addr = read_cpu_reg_sp(s, rn, 1); + tcg_gen_addi_i64(dirty_addr, dirty_addr, offset); + clean_addr = clean_data_tbi(s, dirty_addr); + + if (is_store) { + /* Store-Release semantics */ + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); + do_gpr_st(s, cpu_reg(s, rt), clean_addr, size, true, rt, iss_sf, true); + } else { + /* + * Load-AcquirePC semantics; we implement as the slightly more + * restrictive Load-Acquire. + */ + do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, is_signed, extend, + true, rt, iss_sf, true); + tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); + } +} + /* Load/store register (all forms) */ static void disas_ldst_reg(DisasContext *s, uint32_t insn) { @@ -3610,6 +3716,14 @@ static void disas_ldst(DisasContext *s, uint32_t insn) case 0x0d: /* AdvSIMD load/store single structure */ disas_ldst_single_struct(s, insn); break; + case 0x19: /* LDAPR/STLR (unscaled immediate) */ + if (extract32(insn, 10, 2) != 0 || + extract32(insn, 21, 1) != 0) { + unallocated_encoding(s); + break; + } + disas_ldst_ldapr_stlr(s, insn); + break; default: unallocated_encoding(s); break; diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c index ba46e2557a..b087bbd812 100644 --- a/target/arm/translate-vfp.inc.c +++ b/target/arm/translate-vfp.inc.c @@ -200,13 +200,13 @@ static bool trans_VSEL(DisasContext *s, arg_VSEL *a) return false; } - /* UNDEF accesses to D16-D31 if they don't exist */ - if (dp && !dc_isar_feature(aa32_simd_r32, s) && - ((a->vm | a->vn | a->vd) & 0x10)) { + if (dp && !dc_isar_feature(aa32_fpdp_v2, s)) { return false; } - if (dp && !dc_isar_feature(aa32_fpdp, s)) { + /* UNDEF accesses to D16-D31 if they don't exist */ + if (dp && !dc_isar_feature(aa32_simd_r32, s) && + ((a->vm | a->vn | a->vd) & 0x10)) { return false; } @@ -322,79 +322,6 @@ static bool trans_VSEL(DisasContext *s, arg_VSEL *a) return true; } -static bool trans_VMINMAXNM(DisasContext *s, arg_VMINMAXNM *a) -{ - uint32_t rd, rn, rm; - bool dp = a->dp; - bool vmin = a->op; - TCGv_ptr fpst; - - if (!dc_isar_feature(aa32_vminmaxnm, s)) { - return false; - } - - /* UNDEF accesses to D16-D31 if they don't exist */ - if (dp && !dc_isar_feature(aa32_simd_r32, s) && - ((a->vm | a->vn | a->vd) & 0x10)) { - return false; - } - - if (dp && !dc_isar_feature(aa32_fpdp, s)) { - return false; - } - - rd = a->vd; - rn = a->vn; - rm = a->vm; - - if (!vfp_access_check(s)) { - return true; - } - - fpst = get_fpstatus_ptr(0); - - if (dp) { - TCGv_i64 frn, frm, dest; - - frn = tcg_temp_new_i64(); - frm = tcg_temp_new_i64(); - dest = tcg_temp_new_i64(); - - neon_load_reg64(frn, rn); - neon_load_reg64(frm, rm); - if (vmin) { - gen_helper_vfp_minnumd(dest, frn, frm, fpst); - } else { - gen_helper_vfp_maxnumd(dest, frn, frm, fpst); - } - neon_store_reg64(dest, rd); - tcg_temp_free_i64(frn); - tcg_temp_free_i64(frm); - tcg_temp_free_i64(dest); - } else { - TCGv_i32 frn, frm, dest; - - frn = tcg_temp_new_i32(); - frm = tcg_temp_new_i32(); - dest = tcg_temp_new_i32(); - - neon_load_reg32(frn, rn); - neon_load_reg32(frm, rm); - if (vmin) { - gen_helper_vfp_minnums(dest, frn, frm, fpst); - } else { - gen_helper_vfp_maxnums(dest, frn, frm, fpst); - } - neon_store_reg32(dest, rd); - tcg_temp_free_i32(frn); - tcg_temp_free_i32(frm); - tcg_temp_free_i32(dest); - } - - tcg_temp_free_ptr(fpst); - return true; -} - /* * Table for converting the most common AArch32 encoding of * rounding mode to arm_fprounding order (which matches the @@ -419,13 +346,13 @@ static bool trans_VRINT(DisasContext *s, arg_VRINT *a) return false; } - /* UNDEF accesses to D16-D31 if they don't exist */ - if (dp && !dc_isar_feature(aa32_simd_r32, s) && - ((a->vm | a->vd) & 0x10)) { + if (dp && !dc_isar_feature(aa32_fpdp_v2, s)) { return false; } - if (dp && !dc_isar_feature(aa32_fpdp, s)) { + /* UNDEF accesses to D16-D31 if they don't exist */ + if (dp && !dc_isar_feature(aa32_simd_r32, s) && + ((a->vm | a->vd) & 0x10)) { return false; } @@ -483,12 +410,12 @@ static bool trans_VCVT(DisasContext *s, arg_VCVT *a) return false; } - /* UNDEF accesses to D16-D31 if they don't exist */ - if (dp && !dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { + if (dp && !dc_isar_feature(aa32_fpdp_v2, s)) { return false; } - if (dp && !dc_isar_feature(aa32_fpdp, s)) { + /* UNDEF accesses to D16-D31 if they don't exist */ + if (dp && !dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { return false; } @@ -555,6 +482,13 @@ static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a) int pass; uint32_t offset; + /* SIZE == 2 is a VFP instruction; otherwise NEON. */ + if (a->size == 2 + ? !dc_isar_feature(aa32_fpsp_v2, s) + : !arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + /* UNDEF accesses to D16-D31 if they don't exist */ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) { return false; @@ -564,10 +498,6 @@ static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a) pass = extract32(offset, 2, 1); offset = extract32(offset, 0, 2) * 8; - if (a->size != 2 && !arm_dc_feature(s, ARM_FEATURE_NEON)) { - return false; - } - if (!vfp_access_check(s)) { return true; } @@ -614,6 +544,13 @@ static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a) int pass; uint32_t offset; + /* SIZE == 2 is a VFP instruction; otherwise NEON. */ + if (a->size == 2 + ? !dc_isar_feature(aa32_fpsp_v2, s) + : !arm_dc_feature(s, ARM_FEATURE_NEON)) { + return false; + } + /* UNDEF accesses to D16-D31 if they don't exist */ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) { return false; @@ -623,10 +560,6 @@ static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a) pass = extract32(offset, 2, 1); offset = extract32(offset, 0, 2) * 8; - if (a->size != 2 && !arm_dc_feature(s, ARM_FEATURE_NEON)) { - return false; - } - if (!vfp_access_check(s)) { return true; } @@ -700,6 +633,10 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a) TCGv_i32 tmp; bool ignore_vfp_enabled = false; + if (!dc_isar_feature(aa32_fpsp_v2, s)) { + return false; + } + if (arm_dc_feature(s, ARM_FEATURE_M)) { /* * The only M-profile VFP vmrs/vmsr sysreg is FPSCR. @@ -717,7 +654,7 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a) * VFPv2 allows access to FPSID from userspace; VFPv3 restricts * all ID registers to privileged access only. */ - if (IS_USER(s) && arm_dc_feature(s, ARM_FEATURE_VFP3)) { + if (IS_USER(s) && dc_isar_feature(aa32_fpsp_v3, s)) { return false; } ignore_vfp_enabled = true; @@ -746,7 +683,7 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a) case ARM_VFP_FPINST: case ARM_VFP_FPINST2: /* Not present in VFPv3 */ - if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_VFP3)) { + if (IS_USER(s) || dc_isar_feature(aa32_fpsp_v3, s)) { return false; } break; @@ -844,6 +781,10 @@ static bool trans_VMOV_single(DisasContext *s, arg_VMOV_single *a) { TCGv_i32 tmp; + if (!dc_isar_feature(aa32_fpsp_v2, s)) { + return false; + } + if (!vfp_access_check(s)) { return true; } @@ -873,6 +814,10 @@ static bool trans_VMOV_64_sp(DisasContext *s, arg_VMOV_64_sp *a) { TCGv_i32 tmp; + if (!dc_isar_feature(aa32_fpsp_v2, s)) { + return false; + } + /* * VMOV between two general-purpose registers and two single precision * floating point registers @@ -908,8 +853,12 @@ static bool trans_VMOV_64_dp(DisasContext *s, arg_VMOV_64_dp *a) /* * VMOV between two general-purpose registers and one double precision - * floating point register + * floating point register. Note that this does not require support + * for double precision arithmetic. */ + if (!dc_isar_feature(aa32_fpsp_v2, s)) { + return false; + } /* UNDEF accesses to D16-D31 if they don't exist */ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { @@ -946,6 +895,10 @@ static bool trans_VLDR_VSTR_sp(DisasContext *s, arg_VLDR_VSTR_sp *a) uint32_t offset; TCGv_i32 addr, tmp; + if (!dc_isar_feature(aa32_fpsp_v2, s)) { + return false; + } + if (!vfp_access_check(s)) { return true; } @@ -977,6 +930,11 @@ static bool trans_VLDR_VSTR_dp(DisasContext *s, arg_VLDR_VSTR_dp *a) TCGv_i32 addr; TCGv_i64 tmp; + /* Note that this does not require support for double arithmetic. */ + if (!dc_isar_feature(aa32_fpsp_v2, s)) { + return false; + } + /* UNDEF accesses to D16-D31 if they don't exist */ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { return false; @@ -1013,6 +971,10 @@ static bool trans_VLDM_VSTM_sp(DisasContext *s, arg_VLDM_VSTM_sp *a) TCGv_i32 addr, tmp; int i, n; + if (!dc_isar_feature(aa32_fpsp_v2, s)) { + return false; + } + n = a->imm; if (n == 0 || (a->vd + n) > 32) { @@ -1086,6 +1048,11 @@ static bool trans_VLDM_VSTM_dp(DisasContext *s, arg_VLDM_VSTM_dp *a) TCGv_i64 tmp; int i, n; + /* Note that this does not require support for double arithmetic. */ + if (!dc_isar_feature(aa32_fpsp_v2, s)) { + return false; + } + n = a->imm >> 1; if (n == 0 || (a->vd + n) > 32 || n > 16) { @@ -1234,6 +1201,10 @@ static bool do_vfp_3op_sp(DisasContext *s, VFPGen3OpSPFn *fn, TCGv_i32 f0, f1, fd; TCGv_ptr fpst; + if (!dc_isar_feature(aa32_fpsp_v2, s)) { + return false; + } + if (!dc_isar_feature(aa32_fpshvec, s) && (veclen != 0 || s->vec_stride != 0)) { return false; @@ -1308,12 +1279,12 @@ static bool do_vfp_3op_dp(DisasContext *s, VFPGen3OpDPFn *fn, TCGv_i64 f0, f1, fd; TCGv_ptr fpst; - /* UNDEF accesses to D16-D31 if they don't exist */ - if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vn | vm) & 0x10)) { + if (!dc_isar_feature(aa32_fpdp_v2, s)) { return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { + /* UNDEF accesses to D16-D31 if they don't exist */ + if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vn | vm) & 0x10)) { return false; } @@ -1388,6 +1359,10 @@ static bool do_vfp_2op_sp(DisasContext *s, VFPGen2OpSPFn *fn, int vd, int vm) int veclen = s->vec_len; TCGv_i32 f0, fd; + if (!dc_isar_feature(aa32_fpsp_v2, s)) { + return false; + } + if (!dc_isar_feature(aa32_fpshvec, s) && (veclen != 0 || s->vec_stride != 0)) { return false; @@ -1457,12 +1432,12 @@ static bool do_vfp_2op_dp(DisasContext *s, VFPGen2OpDPFn *fn, int vd, int vm) int veclen = s->vec_len; TCGv_i64 f0, fd; - /* UNDEF accesses to D16-D31 if they don't exist */ - if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vm) & 0x10)) { + if (!dc_isar_feature(aa32_fpdp_v2, s)) { return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { + /* UNDEF accesses to D16-D31 if they don't exist */ + if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vm) & 0x10)) { return false; } @@ -1736,7 +1711,43 @@ static bool trans_VDIV_dp(DisasContext *s, arg_VDIV_dp *a) return do_vfp_3op_dp(s, gen_helper_vfp_divd, a->vd, a->vn, a->vm, false); } -static bool trans_VFM_sp(DisasContext *s, arg_VFM_sp *a) +static bool trans_VMINNM_sp(DisasContext *s, arg_VMINNM_sp *a) +{ + if (!dc_isar_feature(aa32_vminmaxnm, s)) { + return false; + } + return do_vfp_3op_sp(s, gen_helper_vfp_minnums, + a->vd, a->vn, a->vm, false); +} + +static bool trans_VMAXNM_sp(DisasContext *s, arg_VMAXNM_sp *a) +{ + if (!dc_isar_feature(aa32_vminmaxnm, s)) { + return false; + } + return do_vfp_3op_sp(s, gen_helper_vfp_maxnums, + a->vd, a->vn, a->vm, false); +} + +static bool trans_VMINNM_dp(DisasContext *s, arg_VMINNM_dp *a) +{ + if (!dc_isar_feature(aa32_vminmaxnm, s)) { + return false; + } + return do_vfp_3op_dp(s, gen_helper_vfp_minnumd, + a->vd, a->vn, a->vm, false); +} + +static bool trans_VMAXNM_dp(DisasContext *s, arg_VMAXNM_dp *a) +{ + if (!dc_isar_feature(aa32_vminmaxnm, s)) { + return false; + } + return do_vfp_3op_dp(s, gen_helper_vfp_maxnumd, + a->vd, a->vn, a->vm, false); +} + +static bool do_vfm_sp(DisasContext *s, arg_VFMA_sp *a, bool neg_n, bool neg_d) { /* * VFNMA : fd = muladd(-fd, fn, fm) @@ -1755,11 +1766,18 @@ static bool trans_VFM_sp(DisasContext *s, arg_VFM_sp *a) /* * Present in VFPv4 only. + * Note that we can't rely on the SIMDFMAC check alone, because + * in a Neon-no-VFP core that ID register field will be non-zero. + */ + if (!dc_isar_feature(aa32_simdfmac, s) || + !dc_isar_feature(aa32_fpsp_v2, s)) { + return false; + } + /* * In v7A, UNPREDICTABLE with non-zero vector length/stride; from * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A. */ - if (!arm_dc_feature(s, ARM_FEATURE_VFP4) || - (s->vec_len != 0 || s->vec_stride != 0)) { + if (s->vec_len != 0 || s->vec_stride != 0) { return false; } @@ -1773,12 +1791,12 @@ static bool trans_VFM_sp(DisasContext *s, arg_VFM_sp *a) neon_load_reg32(vn, a->vn); neon_load_reg32(vm, a->vm); - if (a->o2) { + if (neg_n) { /* VFNMS, VFMS */ gen_helper_vfp_negs(vn, vn); } neon_load_reg32(vd, a->vd); - if (a->o1 & 1) { + if (neg_d) { /* VFNMA, VFNMS */ gen_helper_vfp_negs(vd, vd); } @@ -1794,7 +1812,27 @@ static bool trans_VFM_sp(DisasContext *s, arg_VFM_sp *a) return true; } -static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a) +static bool trans_VFMA_sp(DisasContext *s, arg_VFMA_sp *a) +{ + return do_vfm_sp(s, a, false, false); +} + +static bool trans_VFMS_sp(DisasContext *s, arg_VFMS_sp *a) +{ + return do_vfm_sp(s, a, true, false); +} + +static bool trans_VFNMA_sp(DisasContext *s, arg_VFNMA_sp *a) +{ + return do_vfm_sp(s, a, false, true); +} + +static bool trans_VFNMS_sp(DisasContext *s, arg_VFNMS_sp *a) +{ + return do_vfm_sp(s, a, true, true); +} + +static bool do_vfm_dp(DisasContext *s, arg_VFMA_dp *a, bool neg_n, bool neg_d) { /* * VFNMA : fd = muladd(-fd, fn, fm) @@ -1813,11 +1851,18 @@ static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a) /* * Present in VFPv4 only. + * Note that we can't rely on the SIMDFMAC check alone, because + * in a Neon-no-VFP core that ID register field will be non-zero. + */ + if (!dc_isar_feature(aa32_simdfmac, s) || + !dc_isar_feature(aa32_fpdp_v2, s)) { + return false; + } + /* * In v7A, UNPREDICTABLE with non-zero vector length/stride; from * v8A, must UNDEF. We choose to UNDEF for both v7A and v8A. */ - if (!arm_dc_feature(s, ARM_FEATURE_VFP4) || - (s->vec_len != 0 || s->vec_stride != 0)) { + if (s->vec_len != 0 || s->vec_stride != 0) { return false; } @@ -1827,7 +1872,9 @@ static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a) return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && + ((a->vd | a->vn | a->vm) & 0x10)) { return false; } @@ -1841,12 +1888,12 @@ static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a) neon_load_reg64(vn, a->vn); neon_load_reg64(vm, a->vm); - if (a->o2) { + if (neg_n) { /* VFNMS, VFMS */ gen_helper_vfp_negd(vn, vn); } neon_load_reg64(vd, a->vd); - if (a->o1 & 1) { + if (neg_d) { /* VFNMA, VFNMS */ gen_helper_vfp_negd(vd, vd); } @@ -1862,6 +1909,26 @@ static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a) return true; } +static bool trans_VFMA_dp(DisasContext *s, arg_VFMA_dp *a) +{ + return do_vfm_dp(s, a, false, false); +} + +static bool trans_VFMS_dp(DisasContext *s, arg_VFMS_dp *a) +{ + return do_vfm_dp(s, a, true, false); +} + +static bool trans_VFNMA_dp(DisasContext *s, arg_VFNMA_dp *a) +{ + return do_vfm_dp(s, a, false, true); +} + +static bool trans_VFNMS_dp(DisasContext *s, arg_VFNMS_dp *a) +{ + return do_vfm_dp(s, a, true, true); +} + static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a) { uint32_t delta_d = 0; @@ -1871,12 +1938,12 @@ static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a) vd = a->vd; - if (!dc_isar_feature(aa32_fpshvec, s) && - (veclen != 0 || s->vec_stride != 0)) { + if (!dc_isar_feature(aa32_fpsp_v3, s)) { return false; } - if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) { + if (!dc_isar_feature(aa32_fpshvec, s) && + (veclen != 0 || s->vec_stride != 0)) { return false; } @@ -1921,24 +1988,20 @@ static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a) vd = a->vd; + if (!dc_isar_feature(aa32_fpdp_v3, s)) { + return false; + } + /* UNDEF accesses to D16-D31 if they don't exist. */ if (!dc_isar_feature(aa32_simd_r32, s) && (vd & 0x10)) { return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { - return false; - } - if (!dc_isar_feature(aa32_fpshvec, s) && (veclen != 0 || s->vec_stride != 0)) { return false; } - if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) { - return false; - } - if (!vfp_access_check(s)) { return true; } @@ -2025,6 +2088,10 @@ static bool trans_VCMP_sp(DisasContext *s, arg_VCMP_sp *a) { TCGv_i32 vd, vm; + if (!dc_isar_feature(aa32_fpsp_v2, s)) { + return false; + } + /* Vm/M bits must be zero for the Z variant */ if (a->z && a->vm != 0) { return false; @@ -2060,6 +2127,10 @@ static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a) { TCGv_i64 vd, vm; + if (!dc_isar_feature(aa32_fpdp_v2, s)) { + return false; + } + /* Vm/M bits must be zero for the Z variant */ if (a->z && a->vm != 0) { return false; @@ -2070,10 +2141,6 @@ static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a) return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { - return false; - } - if (!vfp_access_check(s)) { return true; } @@ -2134,6 +2201,10 @@ static bool trans_VCVT_f64_f16(DisasContext *s, arg_VCVT_f64_f16 *a) TCGv_i32 tmp; TCGv_i64 vd; + if (!dc_isar_feature(aa32_fpdp_v2, s)) { + return false; + } + if (!dc_isar_feature(aa32_fp16_dpconv, s)) { return false; } @@ -2143,10 +2214,6 @@ static bool trans_VCVT_f64_f16(DisasContext *s, arg_VCVT_f64_f16 *a) return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { - return false; - } - if (!vfp_access_check(s)) { return true; } @@ -2200,6 +2267,10 @@ static bool trans_VCVT_f16_f64(DisasContext *s, arg_VCVT_f16_f64 *a) TCGv_i32 tmp; TCGv_i64 vm; + if (!dc_isar_feature(aa32_fpdp_v2, s)) { + return false; + } + if (!dc_isar_feature(aa32_fp16_dpconv, s)) { return false; } @@ -2209,10 +2280,6 @@ static bool trans_VCVT_f16_f64(DisasContext *s, arg_VCVT_f16_f64 *a) return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { - return false; - } - if (!vfp_access_check(s)) { return true; } @@ -2260,6 +2327,10 @@ static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_dp *a) TCGv_ptr fpst; TCGv_i64 tmp; + if (!dc_isar_feature(aa32_fpdp_v2, s)) { + return false; + } + if (!dc_isar_feature(aa32_vrint, s)) { return false; } @@ -2269,10 +2340,6 @@ static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_dp *a) return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { - return false; - } - if (!vfp_access_check(s)) { return true; } @@ -2321,6 +2388,10 @@ static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_dp *a) TCGv_i64 tmp; TCGv_i32 tcg_rmode; + if (!dc_isar_feature(aa32_fpdp_v2, s)) { + return false; + } + if (!dc_isar_feature(aa32_vrint, s)) { return false; } @@ -2330,10 +2401,6 @@ static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_dp *a) return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { - return false; - } - if (!vfp_access_check(s)) { return true; } @@ -2380,6 +2447,10 @@ static bool trans_VRINTX_dp(DisasContext *s, arg_VRINTX_dp *a) TCGv_ptr fpst; TCGv_i64 tmp; + if (!dc_isar_feature(aa32_fpdp_v2, s)) { + return false; + } + if (!dc_isar_feature(aa32_vrint, s)) { return false; } @@ -2389,10 +2460,6 @@ static bool trans_VRINTX_dp(DisasContext *s, arg_VRINTX_dp *a) return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { - return false; - } - if (!vfp_access_check(s)) { return true; } @@ -2412,12 +2479,12 @@ static bool trans_VCVT_sp(DisasContext *s, arg_VCVT_sp *a) TCGv_i64 vd; TCGv_i32 vm; - /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + if (!dc_isar_feature(aa32_fpdp_v2, s)) { return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { return false; } @@ -2440,12 +2507,12 @@ static bool trans_VCVT_dp(DisasContext *s, arg_VCVT_dp *a) TCGv_i64 vm; TCGv_i32 vd; - /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { + if (!dc_isar_feature(aa32_fpdp_v2, s)) { return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { return false; } @@ -2468,6 +2535,10 @@ static bool trans_VCVT_int_sp(DisasContext *s, arg_VCVT_int_sp *a) TCGv_i32 vm; TCGv_ptr fpst; + if (!dc_isar_feature(aa32_fpsp_v2, s)) { + return false; + } + if (!vfp_access_check(s)) { return true; } @@ -2494,12 +2565,12 @@ static bool trans_VCVT_int_dp(DisasContext *s, arg_VCVT_int_dp *a) TCGv_i64 vd; TCGv_ptr fpst; - /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { + if (!dc_isar_feature(aa32_fpdp_v2, s)) { return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) { return false; } @@ -2530,6 +2601,10 @@ static bool trans_VJCVT(DisasContext *s, arg_VJCVT *a) TCGv_i32 vd; TCGv_i64 vm; + if (!dc_isar_feature(aa32_fpdp_v2, s)) { + return false; + } + if (!dc_isar_feature(aa32_jscvt, s)) { return false; } @@ -2539,10 +2614,6 @@ static bool trans_VJCVT(DisasContext *s, arg_VJCVT *a) return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { - return false; - } - if (!vfp_access_check(s)) { return true; } @@ -2563,7 +2634,7 @@ static bool trans_VCVT_fix_sp(DisasContext *s, arg_VCVT_fix_sp *a) TCGv_ptr fpst; int frac_bits; - if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) { + if (!dc_isar_feature(aa32_fpsp_v3, s)) { return false; } @@ -2623,7 +2694,7 @@ static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a) TCGv_ptr fpst; int frac_bits; - if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) { + if (!dc_isar_feature(aa32_fpdp_v3, s)) { return false; } @@ -2632,10 +2703,6 @@ static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a) return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { - return false; - } - if (!vfp_access_check(s)) { return true; } @@ -2690,6 +2757,10 @@ static bool trans_VCVT_sp_int(DisasContext *s, arg_VCVT_sp_int *a) TCGv_i32 vm; TCGv_ptr fpst; + if (!dc_isar_feature(aa32_fpsp_v2, s)) { + return false; + } + if (!vfp_access_check(s)) { return true; } @@ -2723,12 +2794,12 @@ static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a) TCGv_i64 vm; TCGv_ptr fpst; - /* UNDEF accesses to D16-D31 if they don't exist. */ - if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { + if (!dc_isar_feature(aa32_fpdp_v2, s)) { return false; } - if (!dc_isar_feature(aa32_fpdp, s)) { + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) { return false; } @@ -2760,3 +2831,42 @@ static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a) tcg_temp_free_ptr(fpst); return true; } + +/* + * Decode VLLDM and VLSTM are nonstandard because: + * * if there is no FPU then these insns must NOP in + * Secure state and UNDEF in Nonsecure state + * * if there is an FPU then these insns do not have + * the usual behaviour that vfp_access_check() provides of + * being controlled by CPACR/NSACR enable bits or the + * lazy-stacking logic. + */ +static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a) +{ + TCGv_i32 fptr; + + if (!arm_dc_feature(s, ARM_FEATURE_M) || + !arm_dc_feature(s, ARM_FEATURE_V8)) { + return false; + } + /* If not secure, UNDEF. */ + if (!s->v8m_secure) { + return false; + } + /* If no fpu, NOP. */ + if (!dc_isar_feature(aa32_vfp, s)) { + return true; + } + + fptr = load_reg(s, a->rn); + if (a->l) { + gen_helper_v7m_vlldm(cpu_env, fptr); + } else { + gen_helper_v7m_vlstm(cpu_env, fptr); + } + tcg_temp_free_i32(fptr); + + /* End the TB, because we have updated FP control bits */ + s->base.is_jmp = DISAS_UPDATE; + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 79880adaad..6259064ea7 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2646,35 +2646,6 @@ static void gen_neon_dup_high16(TCGv_i32 var) tcg_temp_free_i32(tmp); } -/* - * Disassemble a VFP instruction. Returns nonzero if an error occurred - * (ie. an undefined instruction). - */ -static int disas_vfp_insn(DisasContext *s, uint32_t insn) -{ - if (!arm_dc_feature(s, ARM_FEATURE_VFP)) { - return 1; - } - - /* - * If the decodetree decoder handles this insn it will always - * emit code to either execute the insn or generate an appropriate - * exception; so we don't need to ever return non-zero to tell - * the calling code to emit an UNDEF exception. - */ - if (extract32(insn, 28, 4) == 0xf) { - if (disas_vfp_uncond(s, insn)) { - return 0; - } - } else { - if (disas_vfp(s, insn)) { - return 0; - } - } - /* If the decodetree decoder didn't handle this insn, it must be UNDEF */ - return 1; -} - static inline bool use_goto_tb(DisasContext *s, target_ulong dest) { #ifndef CONFIG_USER_ONLY @@ -5150,7 +5121,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } break; case NEON_3R_VFM_VQRDMLSH: - if (!arm_dc_feature(s, ARM_FEATURE_VFP4)) { + if (!dc_isar_feature(aa32_simdfmac, s)) { return 1; } break; @@ -10782,7 +10753,9 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) ARCH(5); /* Unconditional instructions. */ - if (disas_a32_uncond(s, insn)) { + /* TODO: Perhaps merge these into one decodetree output file. */ + if (disas_a32_uncond(s, insn) || + disas_vfp_uncond(s, insn)) { return; } /* fall back to legacy decoder */ @@ -10809,13 +10782,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) } return; } - if ((insn & 0x0f000e10) == 0x0e000a00) { - /* VFP. */ - if (disas_vfp_insn(s, insn)) { - goto illegal_op; - } - return; - } if ((insn & 0x0e000f00) == 0x0c000100) { if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) { /* iWMMXt register transfer. */ @@ -10846,7 +10812,9 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) arm_skip_unless(s, cond); } - if (disas_a32(s, insn)) { + /* TODO: Perhaps merge these into one decodetree output file. */ + if (disas_a32(s, insn) || + disas_vfp(s, insn)) { return; } /* fall back to legacy decoder */ @@ -10856,11 +10824,10 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) case 0xd: case 0xe: if (((insn >> 8) & 0xe) == 10) { - /* VFP. */ - if (disas_vfp_insn(s, insn)) { - goto illegal_op; - } - } else if (disas_coproc_insn(s, insn)) { + /* VFP, but failed disas_vfp. */ + goto illegal_op; + } + if (disas_coproc_insn(s, insn)) { /* Coprocessor. */ goto illegal_op; } @@ -10949,7 +10916,14 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) ARCH(6T2); } - if (disas_t32(s, insn)) { + /* + * TODO: Perhaps merge these into one decodetree output file. + * Note disas_vfp is written for a32 with cond field in the + * top nibble. The t32 encoding requires 0xe in the top nibble. + */ + if (disas_t32(s, insn) || + disas_vfp_uncond(s, insn) || + ((insn >> 28) == 0xe && disas_vfp(s, insn))) { return; } /* fall back to legacy decoder */ @@ -10966,53 +10940,16 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) goto illegal_op; /* op0 = 0b11 : unallocated */ } - /* - * Decode VLLDM and VLSTM first: these are nonstandard because: - * * if there is no FPU then these insns must NOP in - * Secure state and UNDEF in Nonsecure state - * * if there is an FPU then these insns do not have - * the usual behaviour that disas_vfp_insn() provides of - * being controlled by CPACR/NSACR enable bits or the - * lazy-stacking logic. - */ - if (arm_dc_feature(s, ARM_FEATURE_V8) && - (insn & 0xffa00f00) == 0xec200a00) { - /* 0b1110_1100_0x1x_xxxx_xxxx_1010_xxxx_xxxx - * - VLLDM, VLSTM - * We choose to UNDEF if the RAZ bits are non-zero. - */ - if (!s->v8m_secure || (insn & 0x0040f0ff)) { - goto illegal_op; - } - - if (arm_dc_feature(s, ARM_FEATURE_VFP)) { - uint32_t rn = (insn >> 16) & 0xf; - TCGv_i32 fptr = load_reg(s, rn); - - if (extract32(insn, 20, 1)) { - gen_helper_v7m_vlldm(cpu_env, fptr); - } else { - gen_helper_v7m_vlstm(cpu_env, fptr); - } - tcg_temp_free_i32(fptr); - - /* End the TB, because we have updated FP control bits */ - s->base.is_jmp = DISAS_UPDATE; - } - break; - } - if (arm_dc_feature(s, ARM_FEATURE_VFP) && - ((insn >> 8) & 0xe) == 10) { + if (((insn >> 8) & 0xe) == 10 && + dc_isar_feature(aa32_fpsp_v2, s)) { /* FP, and the CPU supports it */ - if (disas_vfp_insn(s, insn)) { - goto illegal_op; - } - break; + goto illegal_op; + } else { + /* All other insns: NOCP */ + gen_exception_insn(s, s->pc_curr, EXCP_NOCP, + syn_uncategorized(), + default_exception_el(s)); } - - /* All other insns: NOCP */ - gen_exception_insn(s, s->pc_curr, EXCP_NOCP, syn_uncategorized(), - default_exception_el(s)); break; } if ((insn & 0xfe000a00) == 0xfc000800 @@ -11034,9 +10971,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) goto illegal_op; } } else if (((insn >> 8) & 0xe) == 10) { - if (disas_vfp_insn(s, insn)) { - goto illegal_op; - } + /* VFP, but failed disas_vfp. */ + goto illegal_op; } else { if (insn & (1 << 28)) goto illegal_op; diff --git a/target/arm/vfp-uncond.decode b/target/arm/vfp-uncond.decode index 5af1f2ee66..34ca164266 100644 --- a/target/arm/vfp-uncond.decode +++ b/target/arm/vfp-uncond.decode @@ -41,15 +41,19 @@ %vd_dp 22:1 12:4 %vd_sp 12:4 22:1 +@vfp_dnm_s ................................ vm=%vm_sp vn=%vn_sp vd=%vd_sp +@vfp_dnm_d ................................ vm=%vm_dp vn=%vn_dp vd=%vd_dp + VSEL 1111 1110 0. cc:2 .... .... 1010 .0.0 .... \ vm=%vm_sp vn=%vn_sp vd=%vd_sp dp=0 VSEL 1111 1110 0. cc:2 .... .... 1011 .0.0 .... \ vm=%vm_dp vn=%vn_dp vd=%vd_dp dp=1 -VMINMAXNM 1111 1110 1.00 .... .... 1010 . op:1 .0 .... \ - vm=%vm_sp vn=%vn_sp vd=%vd_sp dp=0 -VMINMAXNM 1111 1110 1.00 .... .... 1011 . op:1 .0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp dp=1 +VMAXNM_sp 1111 1110 1.00 .... .... 1010 .0.0 .... @vfp_dnm_s +VMINNM_sp 1111 1110 1.00 .... .... 1010 .1.0 .... @vfp_dnm_s + +VMAXNM_dp 1111 1110 1.00 .... .... 1011 .0.0 .... @vfp_dnm_d +VMINNM_dp 1111 1110 1.00 .... .... 1011 .1.0 .... @vfp_dnm_d VRINT 1111 1110 1.11 10 rm:2 .... 1010 01.0 .... \ vm=%vm_sp vd=%vd_sp dp=0 diff --git a/target/arm/vfp.decode b/target/arm/vfp.decode index a67b3f29ee..5fd70f975a 100644 --- a/target/arm/vfp.decode +++ b/target/arm/vfp.decode @@ -46,6 +46,14 @@ %vmov_imm 16:4 0:4 +@vfp_dnm_s ................................ vm=%vm_sp vn=%vn_sp vd=%vd_sp +@vfp_dnm_d ................................ vm=%vm_dp vn=%vn_dp vd=%vd_dp + +@vfp_dm_ss ................................ vm=%vm_sp vd=%vd_sp +@vfp_dm_dd ................................ vm=%vm_dp vd=%vd_dp +@vfp_dm_ds ................................ vm=%vm_sp vd=%vd_dp +@vfp_dm_sd ................................ vm=%vm_dp vd=%vd_sp + # VMOV scalar to general-purpose register; note that this does # include some Neon cases. VMOV_to_gp ---- 1110 u:1 1. 1 .... rt:4 1011 ... 1 0000 \ @@ -66,20 +74,15 @@ VDUP ---- 1110 1 b:1 q:1 0 .... rt:4 1011 . 0 e:1 1 0000 \ vn=%vn_dp VMSR_VMRS ---- 1110 111 l:1 reg:4 rt:4 1010 0001 0000 -VMOV_single ---- 1110 000 l:1 .... rt:4 1010 . 001 0000 \ - vn=%vn_sp +VMOV_single ---- 1110 000 l:1 .... rt:4 1010 . 001 0000 vn=%vn_sp -VMOV_64_sp ---- 1100 010 op:1 rt2:4 rt:4 1010 00.1 .... \ - vm=%vm_sp -VMOV_64_dp ---- 1100 010 op:1 rt2:4 rt:4 1011 00.1 .... \ - vm=%vm_dp +VMOV_64_sp ---- 1100 010 op:1 rt2:4 rt:4 1010 00.1 .... vm=%vm_sp +VMOV_64_dp ---- 1100 010 op:1 rt2:4 rt:4 1011 00.1 .... vm=%vm_dp # Note that the half-precision variants of VLDR and VSTR are # not part of this decodetree at all because they have bits [9:8] == 0b01 -VLDR_VSTR_sp ---- 1101 u:1 .0 l:1 rn:4 .... 1010 imm:8 \ - vd=%vd_sp -VLDR_VSTR_dp ---- 1101 u:1 .0 l:1 rn:4 .... 1011 imm:8 \ - vd=%vd_dp +VLDR_VSTR_sp ---- 1101 u:1 .0 l:1 rn:4 .... 1010 imm:8 vd=%vd_sp +VLDR_VSTR_dp ---- 1101 u:1 .0 l:1 rn:4 .... 1011 imm:8 vd=%vd_dp # We split the load/store multiple up into two patterns to avoid # overlap with other insns in the "Advanced SIMD load/store and 64-bit move" @@ -100,84 +103,59 @@ VLDM_VSTM_dp ---- 1101 0.1 l:1 rn:4 .... 1011 imm:8 \ vd=%vd_dp p=1 u=0 w=1 # 3-register VFP data-processing; bits [23,21:20,6] identify the operation. -VMLA_sp ---- 1110 0.00 .... .... 1010 .0.0 .... \ - vm=%vm_sp vn=%vn_sp vd=%vd_sp -VMLA_dp ---- 1110 0.00 .... .... 1011 .0.0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp +VMLA_sp ---- 1110 0.00 .... .... 1010 .0.0 .... @vfp_dnm_s +VMLA_dp ---- 1110 0.00 .... .... 1011 .0.0 .... @vfp_dnm_d -VMLS_sp ---- 1110 0.00 .... .... 1010 .1.0 .... \ - vm=%vm_sp vn=%vn_sp vd=%vd_sp -VMLS_dp ---- 1110 0.00 .... .... 1011 .1.0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp +VMLS_sp ---- 1110 0.00 .... .... 1010 .1.0 .... @vfp_dnm_s +VMLS_dp ---- 1110 0.00 .... .... 1011 .1.0 .... @vfp_dnm_d -VNMLS_sp ---- 1110 0.01 .... .... 1010 .0.0 .... \ - vm=%vm_sp vn=%vn_sp vd=%vd_sp -VNMLS_dp ---- 1110 0.01 .... .... 1011 .0.0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp +VNMLS_sp ---- 1110 0.01 .... .... 1010 .0.0 .... @vfp_dnm_s +VNMLS_dp ---- 1110 0.01 .... .... 1011 .0.0 .... @vfp_dnm_d -VNMLA_sp ---- 1110 0.01 .... .... 1010 .1.0 .... \ - vm=%vm_sp vn=%vn_sp vd=%vd_sp -VNMLA_dp ---- 1110 0.01 .... .... 1011 .1.0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp +VNMLA_sp ---- 1110 0.01 .... .... 1010 .1.0 .... @vfp_dnm_s +VNMLA_dp ---- 1110 0.01 .... .... 1011 .1.0 .... @vfp_dnm_d -VMUL_sp ---- 1110 0.10 .... .... 1010 .0.0 .... \ - vm=%vm_sp vn=%vn_sp vd=%vd_sp -VMUL_dp ---- 1110 0.10 .... .... 1011 .0.0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp +VMUL_sp ---- 1110 0.10 .... .... 1010 .0.0 .... @vfp_dnm_s +VMUL_dp ---- 1110 0.10 .... .... 1011 .0.0 .... @vfp_dnm_d -VNMUL_sp ---- 1110 0.10 .... .... 1010 .1.0 .... \ - vm=%vm_sp vn=%vn_sp vd=%vd_sp -VNMUL_dp ---- 1110 0.10 .... .... 1011 .1.0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp +VNMUL_sp ---- 1110 0.10 .... .... 1010 .1.0 .... @vfp_dnm_s +VNMUL_dp ---- 1110 0.10 .... .... 1011 .1.0 .... @vfp_dnm_d -VADD_sp ---- 1110 0.11 .... .... 1010 .0.0 .... \ - vm=%vm_sp vn=%vn_sp vd=%vd_sp -VADD_dp ---- 1110 0.11 .... .... 1011 .0.0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp +VADD_sp ---- 1110 0.11 .... .... 1010 .0.0 .... @vfp_dnm_s +VADD_dp ---- 1110 0.11 .... .... 1011 .0.0 .... @vfp_dnm_d -VSUB_sp ---- 1110 0.11 .... .... 1010 .1.0 .... \ - vm=%vm_sp vn=%vn_sp vd=%vd_sp -VSUB_dp ---- 1110 0.11 .... .... 1011 .1.0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp +VSUB_sp ---- 1110 0.11 .... .... 1010 .1.0 .... @vfp_dnm_s +VSUB_dp ---- 1110 0.11 .... .... 1011 .1.0 .... @vfp_dnm_d -VDIV_sp ---- 1110 1.00 .... .... 1010 .0.0 .... \ - vm=%vm_sp vn=%vn_sp vd=%vd_sp -VDIV_dp ---- 1110 1.00 .... .... 1011 .0.0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp +VDIV_sp ---- 1110 1.00 .... .... 1010 .0.0 .... @vfp_dnm_s +VDIV_dp ---- 1110 1.00 .... .... 1011 .0.0 .... @vfp_dnm_d -VFM_sp ---- 1110 1.01 .... .... 1010 . o2:1 . 0 .... \ - vm=%vm_sp vn=%vn_sp vd=%vd_sp o1=1 -VFM_dp ---- 1110 1.01 .... .... 1011 . o2:1 . 0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp o1=1 -VFM_sp ---- 1110 1.10 .... .... 1010 . o2:1 . 0 .... \ - vm=%vm_sp vn=%vn_sp vd=%vd_sp o1=2 -VFM_dp ---- 1110 1.10 .... .... 1011 . o2:1 . 0 .... \ - vm=%vm_dp vn=%vn_dp vd=%vd_dp o1=2 +VFMA_sp ---- 1110 1.10 .... .... 1010 .0. 0 .... @vfp_dnm_s +VFMS_sp ---- 1110 1.10 .... .... 1010 .1. 0 .... @vfp_dnm_s +VFNMA_sp ---- 1110 1.01 .... .... 1010 .0. 0 .... @vfp_dnm_s +VFNMS_sp ---- 1110 1.01 .... .... 1010 .1. 0 .... @vfp_dnm_s + +VFMA_dp ---- 1110 1.10 .... .... 1011 .0.0 .... @vfp_dnm_d +VFMS_dp ---- 1110 1.10 .... .... 1011 .1.0 .... @vfp_dnm_d +VFNMA_dp ---- 1110 1.01 .... .... 1011 .0.0 .... @vfp_dnm_d +VFNMS_dp ---- 1110 1.01 .... .... 1011 .1.0 .... @vfp_dnm_d VMOV_imm_sp ---- 1110 1.11 .... .... 1010 0000 .... \ vd=%vd_sp imm=%vmov_imm VMOV_imm_dp ---- 1110 1.11 .... .... 1011 0000 .... \ vd=%vd_dp imm=%vmov_imm -VMOV_reg_sp ---- 1110 1.11 0000 .... 1010 01.0 .... \ - vd=%vd_sp vm=%vm_sp -VMOV_reg_dp ---- 1110 1.11 0000 .... 1011 01.0 .... \ - vd=%vd_dp vm=%vm_dp +VMOV_reg_sp ---- 1110 1.11 0000 .... 1010 01.0 .... @vfp_dm_ss +VMOV_reg_dp ---- 1110 1.11 0000 .... 1011 01.0 .... @vfp_dm_dd -VABS_sp ---- 1110 1.11 0000 .... 1010 11.0 .... \ - vd=%vd_sp vm=%vm_sp -VABS_dp ---- 1110 1.11 0000 .... 1011 11.0 .... \ - vd=%vd_dp vm=%vm_dp +VABS_sp ---- 1110 1.11 0000 .... 1010 11.0 .... @vfp_dm_ss +VABS_dp ---- 1110 1.11 0000 .... 1011 11.0 .... @vfp_dm_dd -VNEG_sp ---- 1110 1.11 0001 .... 1010 01.0 .... \ - vd=%vd_sp vm=%vm_sp -VNEG_dp ---- 1110 1.11 0001 .... 1011 01.0 .... \ - vd=%vd_dp vm=%vm_dp +VNEG_sp ---- 1110 1.11 0001 .... 1010 01.0 .... @vfp_dm_ss +VNEG_dp ---- 1110 1.11 0001 .... 1011 01.0 .... @vfp_dm_dd -VSQRT_sp ---- 1110 1.11 0001 .... 1010 11.0 .... \ - vd=%vd_sp vm=%vm_sp -VSQRT_dp ---- 1110 1.11 0001 .... 1011 11.0 .... \ - vd=%vd_dp vm=%vm_dp +VSQRT_sp ---- 1110 1.11 0001 .... 1010 11.0 .... @vfp_dm_ss +VSQRT_dp ---- 1110 1.11 0001 .... 1011 11.0 .... @vfp_dm_dd VCMP_sp ---- 1110 1.11 010 z:1 .... 1010 e:1 1.0 .... \ vd=%vd_sp vm=%vm_sp @@ -190,32 +168,26 @@ VCVT_f32_f16 ---- 1110 1.11 0010 .... 1010 t:1 1.0 .... \ VCVT_f64_f16 ---- 1110 1.11 0010 .... 1011 t:1 1.0 .... \ vd=%vd_dp vm=%vm_sp -# VCVTB and VCVTT to f16: Vd format is always vd_sp; Vm format depends on size bit +# VCVTB and VCVTT to f16: Vd format is always vd_sp; +# Vm format depends on size bit VCVT_f16_f32 ---- 1110 1.11 0011 .... 1010 t:1 1.0 .... \ vd=%vd_sp vm=%vm_sp VCVT_f16_f64 ---- 1110 1.11 0011 .... 1011 t:1 1.0 .... \ vd=%vd_sp vm=%vm_dp -VRINTR_sp ---- 1110 1.11 0110 .... 1010 01.0 .... \ - vd=%vd_sp vm=%vm_sp -VRINTR_dp ---- 1110 1.11 0110 .... 1011 01.0 .... \ - vd=%vd_dp vm=%vm_dp +VRINTR_sp ---- 1110 1.11 0110 .... 1010 01.0 .... @vfp_dm_ss +VRINTR_dp ---- 1110 1.11 0110 .... 1011 01.0 .... @vfp_dm_dd -VRINTZ_sp ---- 1110 1.11 0110 .... 1010 11.0 .... \ - vd=%vd_sp vm=%vm_sp -VRINTZ_dp ---- 1110 1.11 0110 .... 1011 11.0 .... \ - vd=%vd_dp vm=%vm_dp +VRINTZ_sp ---- 1110 1.11 0110 .... 1010 11.0 .... @vfp_dm_ss +VRINTZ_dp ---- 1110 1.11 0110 .... 1011 11.0 .... @vfp_dm_dd -VRINTX_sp ---- 1110 1.11 0111 .... 1010 01.0 .... \ - vd=%vd_sp vm=%vm_sp -VRINTX_dp ---- 1110 1.11 0111 .... 1011 01.0 .... \ - vd=%vd_dp vm=%vm_dp +VRINTX_sp ---- 1110 1.11 0111 .... 1010 01.0 .... @vfp_dm_ss +VRINTX_dp ---- 1110 1.11 0111 .... 1011 01.0 .... @vfp_dm_dd -# VCVT between single and double: Vm precision depends on size; Vd is its reverse -VCVT_sp ---- 1110 1.11 0111 .... 1010 11.0 .... \ - vd=%vd_dp vm=%vm_sp -VCVT_dp ---- 1110 1.11 0111 .... 1011 11.0 .... \ - vd=%vd_sp vm=%vm_dp +# VCVT between single and double: +# Vm precision depends on size; Vd is its reverse +VCVT_sp ---- 1110 1.11 0111 .... 1010 11.0 .... @vfp_dm_ds +VCVT_dp ---- 1110 1.11 0111 .... 1011 11.0 .... @vfp_dm_sd # VCVT from integer to floating point: Vm always single; Vd depends on size VCVT_int_sp ---- 1110 1.11 1000 .... 1010 s:1 1.0 .... \ @@ -224,8 +196,7 @@ VCVT_int_dp ---- 1110 1.11 1000 .... 1011 s:1 1.0 .... \ vd=%vd_dp vm=%vm_sp # VJCVT is always dp to sp -VJCVT ---- 1110 1.11 1001 .... 1011 11.0 .... \ - vd=%vd_sp vm=%vm_dp +VJCVT ---- 1110 1.11 1001 .... 1011 11.0 .... @vfp_dm_sd # VCVT between floating-point and fixed-point. The immediate value # is in the same format as a Vm single-precision register number. @@ -242,3 +213,5 @@ VCVT_sp_int ---- 1110 1.11 110 s:1 .... 1010 rz:1 1.0 .... \ vd=%vd_sp vm=%vm_sp VCVT_dp_int ---- 1110 1.11 110 s:1 .... 1011 rz:1 1.0 .... \ vd=%vd_sp vm=%vm_dp + +VLLDM_VLSTM 1110 1100 001 l:1 rn:4 0000 1010 0000 0000 diff --git a/tests/acceptance/machine_arm_integratorcp.py b/tests/acceptance/machine_arm_integratorcp.py new file mode 100644 index 0000000000..49c8ebff78 --- /dev/null +++ b/tests/acceptance/machine_arm_integratorcp.py @@ -0,0 +1,99 @@ +# Functional test that boots a Linux kernel and checks the console +# +# Copyright (c) 2020 Red Hat, Inc. +# +# Author: +# Thomas Huth +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. + +import os +import logging + +from avocado import skipUnless +from avocado_qemu import Test +from avocado_qemu import wait_for_console_pattern + + +NUMPY_AVAILABLE = True +try: + import numpy as np +except ImportError: + NUMPY_AVAILABLE = False + +CV2_AVAILABLE = True +try: + import cv2 +except ImportError: + CV2_AVAILABLE = False + + +class IntegratorMachine(Test): + + timeout = 90 + + def boot_integratorcp(self): + kernel_url = ('https://github.com/zayac/qemu-arm/raw/master/' + 'arm-test/kernel/zImage.integrator') + kernel_hash = '0d7adba893c503267c946a3cbdc63b4b54f25468' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + + initrd_url = ('https://github.com/zayac/qemu-arm/raw/master/' + 'arm-test/kernel/arm_root.img') + initrd_hash = 'b51e4154285bf784e017a37586428332d8c7bd8b' + initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash) + + self.vm.set_console() + self.vm.add_args('-kernel', kernel_path, + '-initrd', initrd_path, + '-append', 'printk.time=0 console=ttyAMA0') + self.vm.launch() + + @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code') + def test_integratorcp_console(self): + """ + Boots the Linux kernel and checks that the console is operational + :avocado: tags=arch:arm + :avocado: tags=machine:integratorcp + :avocado: tags=device:pl011 + """ + self.boot_integratorcp() + wait_for_console_pattern(self, 'Log in as root') + + @skipUnless(NUMPY_AVAILABLE, 'Python NumPy not installed') + @skipUnless(CV2_AVAILABLE, 'Python OpenCV not installed') + @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code') + def test_framebuffer_tux_logo(self): + """ + Boot Linux and verify the Tux logo is displayed on the framebuffer. + :avocado: tags=arch:arm + :avocado: tags=machine:integratorcp + :avocado: tags=device:pl110 + :avocado: tags=device:framebuffer + """ + screendump_path = os.path.join(self.workdir, "screendump.pbm") + tuxlogo_url = ('https://github.com/torvalds/linux/raw/v2.6.12/' + 'drivers/video/logo/logo_linux_vga16.ppm') + tuxlogo_hash = '3991c2ddbd1ddaecda7601f8aafbcf5b02dc86af' + tuxlogo_path = self.fetch_asset(tuxlogo_url, asset_hash=tuxlogo_hash) + + self.boot_integratorcp() + framebuffer_ready = 'Console: switching to colour frame buffer device' + wait_for_console_pattern(self, framebuffer_ready) + self.vm.command('human-monitor-command', command_line='stop') + self.vm.command('human-monitor-command', + command_line='screendump %s' % screendump_path) + logger = logging.getLogger('framebuffer') + + cpu_count = 1 + match_threshold = 0.92 + screendump_bgr = cv2.imread(screendump_path) + screendump_gray = cv2.cvtColor(screendump_bgr, cv2.COLOR_BGR2GRAY) + result = cv2.matchTemplate(screendump_gray, cv2.imread(tuxlogo_path, 0), + cv2.TM_CCOEFF_NORMED) + loc = np.where(result >= match_threshold) + tux_count = 0 + for tux_count, pt in enumerate(zip(*loc[::-1]), start=1): + logger.debug('found Tux at position [x, y] = %s', pt) + self.assertGreaterEqual(tux_count, cpu_count) diff --git a/tests/acceptance/machine_arm_n8x0.py b/tests/acceptance/machine_arm_n8x0.py new file mode 100644 index 0000000000..e5741f2d8d --- /dev/null +++ b/tests/acceptance/machine_arm_n8x0.py @@ -0,0 +1,49 @@ +# Functional test that boots a Linux kernel and checks the console +# +# Copyright (c) 2020 Red Hat, Inc. +# +# Author: +# Thomas Huth +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. + +import os + +from avocado import skipUnless +from avocado_qemu import Test +from avocado_qemu import wait_for_console_pattern + +class N8x0Machine(Test): + """Boots the Linux kernel and checks that the console is operational""" + + timeout = 90 + + def __do_test_n8x0(self): + kernel_url = ('http://stskeeps.subnetmask.net/meego-n8x0/' + 'meego-arm-n8x0-1.0.80.20100712.1431-' + 'vmlinuz-2.6.35~rc4-129.1-n8x0') + kernel_hash = 'e9d5ab8d7548923a0061b6fbf601465e479ed269' + kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) + + self.vm.set_console(console_index=1) + self.vm.add_args('-kernel', kernel_path, + '-append', 'printk.time=0 console=ttyS1') + self.vm.launch() + wait_for_console_pattern(self, 'TSC2005 driver initializing') + + @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code') + def test_n800(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:n800 + """ + self.__do_test_n8x0() + + @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code') + def test_n810(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:n810 + """ + self.__do_test_n8x0()