target/arm: PMU: Add instruction and cycle events

The instruction event is only enabled when icount is used, cycles are
always supported. Always defining get_cycle_count (but altering its
behavior depending on CONFIG_USER_ONLY) allows us to remove some
CONFIG_USER_ONLY #defines throughout the rest of the code.

Backports commit b2e2372511946fae86fbb8709edec7a41c6f3167 from qemu
This commit is contained in:
Aaron Lindsay 2019-01-22 18:48:50 -05:00 committed by Lioncash
parent 1a815a1afc
commit dede23994a
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
2 changed files with 49 additions and 46 deletions

View file

@ -682,7 +682,7 @@ typedef struct CPUARMState {
* should first be updated to something sparse instead of the current
* supported_event_map[] array.
*/
#define MAX_EVENT_ID 0x0
#define MAX_EVENT_ID 0x11
uint16_t supported_event_map[MAX_EVENT_ID + 1];
// Unicorn engine

View file

@ -4,6 +4,7 @@
#include "exec/helper-proto.h"
#include "qemu/host-utils.h"
#include "sysemu/sysemu.h"
#include "sysemu/cpus.h"
#include "qemu/bitops.h"
#include "qemu/crc32c.h"
#include "exec/exec-all.h"
@ -12,6 +13,8 @@
#include "fpu/softfloat.h"
#include "qemu/range.h"
#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
#ifndef CONFIG_USER_ONLY
/* Cacheability and shareability attributes for a memory access */
typedef struct ARMCacheAttrs {
@ -885,7 +888,51 @@ typedef struct pm_event {
uint64_t (*get_count)(CPUARMState *);
} pm_event;
static bool event_always_supported(CPUARMState *env)
{
return true;
}
/*
* Return the underlying cycle count for the PMU cycle counters. If we're in
* usermode, simply return 0.
*/
static uint64_t cycles_get_count(CPUARMState *env)
{
#ifndef CONFIG_USER_ONLY
return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
ARM_CPU_FREQ, NANOSECONDS_PER_SECOND);
#else
return 0;
#endif
}
#ifndef CONFIG_USER_ONLY
static bool instructions_supported(CPUARMState *env)
{
return 0; /* Precise instruction counting */
}
static uint64_t instructions_get_count(CPUARMState *env)
{
return 0;
}
#endif
static const pm_event pm_events[] = {
#ifndef CONFIG_USER_ONLY
{
0x008, /* INST_RETIRED, Instruction architecturally executed */
instructions_supported,
instructions_get_count,
},
{
0x011, /* CPU_CYCLES, Cycle */
event_always_supported,
cycles_get_count,
}
#endif
};
#define UNSUPPORTED_EVENT UINT16_MAX
@ -987,8 +1034,6 @@ static CPAccessResult pmreg_access_swinc(CPUARMState *env,
return pmreg_access(env, ri, isread);
}
#ifndef CONFIG_USER_ONLY
static CPAccessResult pmreg_access_selr(CPUARMState *env,
const ARMCPRegInfo *ri,
bool isread)
@ -1099,9 +1144,7 @@ static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter)
*/
void pmccntr_op_start(CPUARMState *env)
{
uint64_t cycles = 0;
cycles = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
NANOSECONDS_PER_SECOND, 1000000);
uint64_t cycles = cycles_get_count(env);
if (pmu_counter_enabled(env, 31)) {
uint64_t eff_cycles = cycles;
@ -1247,42 +1290,6 @@ static void pmccntr_write32(CPUARMState *env, const ARMCPRegInfo *ri,
pmccntr_write(env, ri, deposit64(cur_val, 0, 32, value));
}
#else /* CONFIG_USER_ONLY */
void pmccntr_op_start(CPUARMState *env)
{
}
void pmccntr_op_finish(CPUARMState *env)
{
}
void pmevcntr_op_start(CPUARMState *env, uint8_t i)
{
}
void pmevcntr_op_finish(CPUARMState *env, uint8_t i)
{
}
void pmu_op_start(CPUARMState *env)
{
}
void pmu_op_finish(CPUARMState *env)
{
}
void pmu_pre_el_change(ARMCPU *cpu, void *ignored)
{
}
void pmu_post_el_change(ARMCPU *cpu, void *ignored)
{
}
#endif
static void pmccfiltr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
@ -1663,7 +1670,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
{ "PMSWINC", 15,9,12, 0,0,4, 0,
ARM_CP_NOP, PL0_W, 0, NULL, 0, 0, {0, 0},
pmreg_access_swinc },
#ifndef CONFIG_USER_ONLY
{ "PMSELR", 15,9,12, 0,0,5, 0, ARM_CP_ALIAS,
PL0_RW, 0, NULL, 0, offsetoflow32(CPUARMState, cp15.c9_pmselr), {0, 0},
pmreg_access_selr, NULL, pmselr_write, NULL, raw_write},
@ -1676,7 +1682,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
{ "PMCCNTR_EL0", 0,9,13, 3,3,0, ARM_CP_STATE_AA64,
ARM_CP_IO, PL0_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.c15_ccnt), {0, 0},
pmreg_access_ccntr, pmccntr_read, pmccntr_write, raw_read, raw_write },
#endif
{ "PMCCFILTR", 15,14,15, 0,0,7, 0, ARM_CP_ALIAS | ARM_CP_IO, PL0_RW, 0,
NULL, 0, 0, {0, 0}, pmreg_access, pmccfiltr_read_a32, pmccfiltr_write_a32 },
{ "PMCCFILTR_EL0", 0,14,15, 3,3,7, ARM_CP_STATE_AA64,
@ -5026,7 +5031,6 @@ void register_cp_regs_for_features(ARMCPU *cpu)
* count register.
*/
unsigned int i, pmcrn = 0;
#ifndef CONFIG_USER_ONLY
ARMCPRegInfo pmcr = {
"PMCR", 15,9,12, 0,0,0, 0,
ARM_CP_IO | ARM_CP_ALIAS, PL0_RW, 0, NULL, 0, offsetoflow32(CPUARMState, cp15.c9_pmcr), {0, 0},
@ -5067,7 +5071,6 @@ void register_cp_regs_for_features(ARMCPU *cpu)
g_free(pmevtyper_name);
g_free(pmevtyper_el0_name);
}
#endif
ARMCPRegInfo clidr = {
"CLIDR", 0,0,0, 3,1,1, ARM_CP_STATE_BOTH,
ARM_CP_CONST, PL1_R, 0, NULL, cpu->clidr