diff --git a/qemu/aarch64.h b/qemu/aarch64.h index a014ce39..2b11142f 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -3301,6 +3301,7 @@ #define fp_exception_el fp_exception_el_aarch64 #define gen_a64_set_pc_im gen_a64_set_pc_im_aarch64 #define gen_cmtst_i64 gen_cmtst_i64_aarch64 +#define get_pmceid get_pmceid_aarch64 #define helper_advsimd_acge_f16 helper_advsimd_acge_f16_aarch64 #define helper_advsimd_acgt_f16 helper_advsimd_acgt_f16_aarch64 #define helper_advsimd_add2h helper_advsimd_add2h_aarch64 diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h index 54a40704..f0fe5462 100644 --- a/qemu/aarch64eb.h +++ b/qemu/aarch64eb.h @@ -3301,6 +3301,7 @@ #define fp_exception_el fp_exception_el_aarch64eb #define gen_a64_set_pc_im gen_a64_set_pc_im_aarch64eb #define gen_cmtst_i64 gen_cmtst_i64_aarch64eb +#define get_pmceid get_pmceid_aarch64eb #define helper_advsimd_acge_f16 helper_advsimd_acge_f16_aarch64eb #define helper_advsimd_acgt_f16 helper_advsimd_acgt_f16_aarch64eb #define helper_advsimd_add2h helper_advsimd_add2h_aarch64eb diff --git a/qemu/arm.h b/qemu/arm.h index ca52b50a..b8c7b1c1 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -3286,6 +3286,7 @@ #define cmtst_op cmtst_op_arm #define fp_exception_el fp_exception_el_arm #define gen_cmtst_i64 gen_cmtst_i64_arm +#define get_pmceid get_pmceid_arm #define mla_op mla_op_arm #define mls_op mls_op_arm #define pmccntr_op_start pmccntr_op_start_arm diff --git a/qemu/armeb.h b/qemu/armeb.h index c8d66b23..63326c86 100644 --- a/qemu/armeb.h +++ b/qemu/armeb.h @@ -3286,6 +3286,7 @@ #define cmtst_op cmtst_op_armeb #define fp_exception_el fp_exception_el_armeb #define gen_cmtst_i64 gen_cmtst_i64_armeb +#define get_pmceid get_pmceid_armeb #define mla_op mla_op_armeb #define mls_op mls_op_armeb #define pmccntr_op_start pmccntr_op_start_armeb diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 092a9cb6..e3aa8b9b 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -3295,6 +3295,7 @@ arm_symbols = ( 'cmtst_op', 'fp_exception_el', 'gen_cmtst_i64', + 'get_pmceid', 'mla_op', 'mls_op', 'pmccntr_op_start', @@ -3346,6 +3347,7 @@ aarch64_symbols = ( 'fp_exception_el', 'gen_a64_set_pc_im', 'gen_cmtst_i64', + 'get_pmceid', 'helper_advsimd_acge_f16', 'helper_advsimd_acgt_f16', 'helper_advsimd_add2h', diff --git a/qemu/target/arm/cpu.c b/qemu/target/arm/cpu.c index 1834faab..f32fb1bc 100644 --- a/qemu/target/arm/cpu.c +++ b/qemu/target/arm/cpu.c @@ -761,15 +761,19 @@ static int arm_cpu_realizefn(struct uc_struct *uc, DeviceState *dev, Error **err if (!cpu->has_pmu) { unset_feature(env, ARM_FEATURE_PMU); - cpu->id_aa64dfr0 &= ~0xf00; } - // Unicorn: Commented out -#if 0 - else if (!kvm_enabled()) { + + if (arm_feature(env, ARM_FEATURE_PMU)) { + cpu->pmceid0 = get_pmceid(&cpu->env, 0); + cpu->pmceid1 = get_pmceid(&cpu->env, 1); + arm_register_pre_el_change_hook(cpu, &pmu_pre_el_change, 0); arm_register_el_change_hook(cpu, &pmu_post_el_change, 0); + } else { + cpu->id_aa64dfr0 &= ~0xf00; + cpu->pmceid0 = 0; + cpu->pmceid1 = 0; } -#endif if (!arm_feature(env, ARM_FEATURE_EL2)) { /* Disable the hypervisor feature bits in the processor feature @@ -1410,8 +1414,6 @@ static void cortex_a7_initfn(struct uc_struct *uc, Object *obj, void *opaque) cpu->id_pfr0 = 0x00001131; cpu->id_pfr1 = 0x00011011; cpu->id_dfr0 = 0x02010555; - cpu->pmceid0 = 0x00000000; - cpu->pmceid1 = 0x00000000; cpu->id_afr0 = 0x00000000; cpu->id_mmfr0 = 0x10101105; cpu->id_mmfr1 = 0x40000000; @@ -1457,8 +1459,6 @@ static void cortex_a15_initfn(struct uc_struct *uc, Object *obj, void *opaque) cpu->id_pfr0 = 0x00001131; cpu->id_pfr1 = 0x00011011; cpu->id_dfr0 = 0x02010555; - cpu->pmceid0 = 0x00000000; - cpu->pmceid1 = 0x00000000; cpu->id_afr0 = 0x00000000; cpu->id_mmfr0 = 0x10201105; cpu->id_mmfr1 = 0x20000000; diff --git a/qemu/target/arm/cpu.h b/qemu/target/arm/cpu.h index 740ec04c..7f57bd1f 100644 --- a/qemu/target/arm/cpu.h +++ b/qemu/target/arm/cpu.h @@ -671,6 +671,17 @@ typedef struct CPUARMState { /* Store GICv3CPUState to access from this struct */ void *gicv3state; + // Note: The event map has been moved here in Unicorn to avoid non-const file-static state. + + /* + * Note: Before increasing MAX_EVENT_ID beyond 0x3f into the 0x40xx range of + * events (i.e. the statistical profiling extension), this implementation + * should first be updated to something sparse instead of the current + * supported_event_map[] array. + */ +#define MAX_EVENT_ID 0x0 + uint16_t supported_event_map[MAX_EVENT_ID + 1]; + // Unicorn engine struct uc_struct *uc; } CPUARMState; @@ -949,6 +960,16 @@ void pmu_op_finish(CPUARMState *env); void pmu_pre_el_change(ARMCPU *cpu, void *ignored); void pmu_post_el_change(ARMCPU *cpu, void *ignored); +/* + * get_pmceid + * @env: CPUARMState + * @which: which PMCEID register to return (0 or 1) + * + * Return the PMCEID[01]_EL0 register values corresponding to the counters + * which are supported given the current configuration + */ +uint64_t get_pmceid(CPUARMState *env, unsigned which); + /* SCTLR bit meanings. Several bits have been reused in newer * versions of the architecture; in that case we define constants * for both old and new bit meanings. Code which tests against those diff --git a/qemu/target/arm/cpu64.c b/qemu/target/arm/cpu64.c index adf14945..cd1a75c4 100644 --- a/qemu/target/arm/cpu64.c +++ b/qemu/target/arm/cpu64.c @@ -118,8 +118,6 @@ static void aarch64_a57_initfn(struct uc_struct *uc, Object *obj, void *opaque) cpu->isar.id_isar6 = 0; cpu->isar.id_aa64pfr0 = 0x00002222; cpu->id_aa64dfr0 = 0x10305106; - cpu->pmceid0 = 0x00000000; - cpu->pmceid1 = 0x00000000; cpu->isar.id_aa64isar0 = 0x00011120; cpu->isar.id_aa64mmfr0 = 0x00001124; cpu->dbgdidr = 0x3516d000; @@ -220,8 +218,6 @@ static void aarch64_a72_initfn(struct uc_struct *uc, Object *obj, void *opaque) cpu->isar.id_isar5 = 0x00011121; cpu->isar.id_aa64pfr0 = 0x00002222; cpu->id_aa64dfr0 = 0x10305106; - cpu->pmceid0 = 0x00000000; - cpu->pmceid1 = 0x00000000; cpu->isar.id_aa64isar0 = 0x00011120; cpu->isar.id_aa64mmfr0 = 0x00001124; cpu->dbgdidr = 0x3516d000; diff --git a/qemu/target/arm/helper.c b/qemu/target/arm/helper.c index 3fd669e3..f84f6f49 100644 --- a/qemu/target/arm/helper.c +++ b/qemu/target/arm/helper.c @@ -873,6 +873,55 @@ static inline uint64_t pmu_counter_mask(CPUARMState *env) return (1 << 31) | ((1 << pmu_num_counters(env)) - 1); } +typedef struct pm_event { + uint16_t number; /* PMEVTYPER.evtCount is 16 bits wide */ + /* If the event is supported on this CPU (used to generate PMCEID[01]) */ + bool (*supported)(CPUARMState *); + /* + * Retrieve the current count of the underlying event. The programmed + * counters hold a difference from the return value from this function + */ + uint64_t (*get_count)(CPUARMState *); +} pm_event; + +static const pm_event pm_events[] = { +}; + +#define UNSUPPORTED_EVENT UINT16_MAX + +/* + * Called upon initialization to build PMCEID0_EL0 or PMCEID1_EL0 (indicated by + * 'which'). We also use it to build a map of ARM event numbers to indices in + * our pm_events array. + * + * Note: Events in the 0x40XX range are not currently supported. + */ +uint64_t get_pmceid(CPUARMState *env, unsigned which) +{ + uint64_t pmceid = 0; + unsigned int i; + + assert(which <= 1); + + for (i = 0; i < ARRAY_SIZE(env->supported_event_map); i++) { + env->supported_event_map[i] = UNSUPPORTED_EVENT; + } + + for (i = 0; i < ARRAY_SIZE(pm_events); i++) { + const pm_event *cnt = &pm_events[i]; + assert(cnt->number <= MAX_EVENT_ID); + /* We do not currently support events in the 0x40xx range */ + assert(cnt->number <= 0x3f); + + if ((cnt->number & 0x20) == (which << 6) && + cnt->supported(env)) { + pmceid |= (1 << (cnt->number & 0x1f)); + env->supported_event_map[cnt->number] = i; + } + } + return pmceid; +} + static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) {