diff options
Diffstat (limited to 'target-arm')
| -rw-r--r-- | target-arm/cpu.h | 2 | ||||
| -rw-r--r-- | target-arm/helper.c | 5 | ||||
| -rw-r--r-- | target-arm/kvm32.c | 6 | ||||
| -rw-r--r-- | target-arm/kvm64.c | 46 | ||||
| -rw-r--r-- | target-arm/kvm_arm.h | 7 | ||||
| -rw-r--r-- | target-arm/translate.c | 28 |
6 files changed, 93 insertions, 1 deletions
diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 17d80510da..942aa36d9b 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -572,6 +572,8 @@ struct ARMCPU { bool powered_off; /* CPU has security extension */ bool has_el3; + /* CPU has PMU (Performance Monitor Unit) */ + bool has_pmu; /* CPU has memory protection unit */ bool has_mpu; diff --git a/target-arm/helper.c b/target-arm/helper.c index 862e7808a2..c9730d6678 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3765,8 +3765,11 @@ static const ARMCPRegInfo el3_cp_reginfo[] = { .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 2, .access = PL3_RW, /* no .writefn needed as this can't cause an ASID change; - * no .raw_writefn or .resetfn needed as we never use mask/base_mask + * we must provide a .raw_writefn and .resetfn because we handle + * reset and migration for the AArch32 TTBCR(S), which might be + * using mask and base_mask. */ + .resetfn = vmsa_ttbcr_reset, .raw_writefn = vmsa_ttbcr_raw_write, .fieldoffset = offsetof(CPUARMState, cp15.tcr_el[3]) }, { .name = "ELR_EL3", .state = ARM_CP_STATE_AA64, .type = ARM_CP_ALIAS, diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c index c03e3e526a..c35c676e14 100644 --- a/target-arm/kvm32.c +++ b/target-arm/kvm32.c @@ -522,3 +522,9 @@ bool kvm_arm_hw_debug_active(CPUState *cs) { return false; } + +int kvm_arm_pmu_create(CPUState *cs, int irq) +{ + qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); + return 0; +} diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c index e2a34f67a4..2d6a310ebb 100644 --- a/target-arm/kvm64.c +++ b/target-arm/kvm64.c @@ -382,6 +382,47 @@ static CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, target_ulong addr) return NULL; } +static bool kvm_arm_pmu_support_ctrl(CPUState *cs, struct kvm_device_attr *attr) +{ + return kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr) == 0; +} + +int kvm_arm_pmu_create(CPUState *cs, int irq) +{ + int err; + + struct kvm_device_attr attr = { + .group = KVM_ARM_VCPU_PMU_V3_CTRL, + .addr = (intptr_t)&irq, + .attr = KVM_ARM_VCPU_PMU_V3_IRQ, + .flags = 0, + }; + + if (!kvm_arm_pmu_support_ctrl(cs, &attr)) { + return 0; + } + + err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, &attr); + if (err < 0) { + fprintf(stderr, "KVM_SET_DEVICE_ATTR failed: %s\n", + strerror(-err)); + abort(); + } + + attr.group = KVM_ARM_VCPU_PMU_V3_CTRL; + attr.attr = KVM_ARM_VCPU_PMU_V3_INIT; + attr.addr = 0; + attr.flags = 0; + + err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, &attr); + if (err < 0) { + fprintf(stderr, "KVM_SET_DEVICE_ATTR failed: %s\n", + strerror(-err)); + abort(); + } + + return 1; +} static inline void set_feature(uint64_t *features, int feature) { @@ -461,6 +502,11 @@ int kvm_arch_init_vcpu(CPUState *cs) if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT; } + if (kvm_irqchip_in_kernel() && + kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3)) { + cpu->has_pmu = true; + cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3; + } /* Do KVM_ARM_VCPU_INIT ioctl */ ret = kvm_arm_vcpu_init(cs); diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h index 345233c18b..a4193684a8 100644 --- a/target-arm/kvm_arm.h +++ b/target-arm/kvm_arm.h @@ -194,6 +194,8 @@ int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu); int kvm_arm_vgic_probe(void); +int kvm_arm_pmu_create(CPUState *cs, int irq); + #else static inline int kvm_arm_vgic_probe(void) @@ -201,6 +203,11 @@ static inline int kvm_arm_vgic_probe(void) return 0; } +static inline int kvm_arm_pmu_create(CPUState *cs, int irq) +{ + return 0; +} + #endif static inline const char *gic_class_name(void) diff --git a/target-arm/translate.c b/target-arm/translate.c index 6815bc1a79..3e7146769d 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -5311,6 +5311,30 @@ static int neon_2rm_is_float_op(int op) op >= NEON_2RM_VRECPE_F); } +static bool neon_2rm_is_v8_op(int op) +{ + /* Return true if this neon 2reg-misc op is ARMv8 and up */ + switch (op) { + case NEON_2RM_VRINTN: + case NEON_2RM_VRINTA: + case NEON_2RM_VRINTM: + case NEON_2RM_VRINTP: + case NEON_2RM_VRINTZ: + case NEON_2RM_VRINTX: + case NEON_2RM_VCVTAU: + case NEON_2RM_VCVTAS: + case NEON_2RM_VCVTNU: + case NEON_2RM_VCVTNS: + case NEON_2RM_VCVTPU: + case NEON_2RM_VCVTPS: + case NEON_2RM_VCVTMU: + case NEON_2RM_VCVTMS: + return true; + default: + return false; + } +} + /* Each entry in this array has bit n set if the insn allows * size value n (otherwise it will UNDEF). Since unallocated * op values will have no bits set they always UNDEF. @@ -6798,6 +6822,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) if ((neon_2rm_sizes[op] & (1 << size)) == 0) { return 1; } + if (neon_2rm_is_v8_op(op) && + !arm_dc_feature(s, ARM_FEATURE_V8)) { + return 1; + } if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) && q && ((rm | rd) & 1)) { return 1; |