target/arm: Send interrupts on PMU counter overflow

Whenever we notice that a counter overflow has occurred, send an
interrupt. This is made more reliable with the addition of a timer in a
follow-on commit.

Backports commit f4efb4b2a17528837cb445f9bdfaef8df4a5acf7 from qemu
This commit is contained in:
Aaron Lindsay OS 2019-02-03 17:45:26 -05:00 committed by Lioncash
parent edfb13f8eb
commit 0dd5bf84fc
No known key found for this signature in database
GPG Key ID: 4E3C3CC1031BA9C7

View File

@ -843,6 +843,7 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
/* Definitions for the PMU registers */
#define PMCRN_MASK 0xf800
#define PMCRN_SHIFT 11
#define PMCRLC 0x40
#define PMCRDP 0x10
#define PMCRD 0x8
#define PMCRC 0x4
@ -1155,6 +1156,14 @@ static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter)
return enabled && !prohibited && !filtered;
}
static void pmu_update_irq(CPUARMState *env)
{
/* Unicorn: Commented out
ARMCPU *cpu = arm_env_get_cpu(env);
qemu_set_irq(cpu->pmu_interrupt, (env->cp15.c9_pmcr & PMCRE) &&
(env->cp15.c9_pminten & env->cp15.c9_pmovsr));*/
}
/*
* Ensure c15_ccnt is the guest-visible count so that operations such as
* enabling/disabling the counter or filtering, modifying the count itself,
@ -1172,7 +1181,16 @@ void pmccntr_op_start(CPUARMState *env)
eff_cycles /= 64;
}
env->cp15.c15_ccnt = eff_cycles - env->cp15.c15_ccnt_delta;
uint64_t new_pmccntr = eff_cycles - env->cp15.c15_ccnt_delta;
uint64_t overflow_mask = env->cp15.c9_pmcr & PMCRLC ? \
1ull << 63 : 1ull << 31;
if (env->cp15.c15_ccnt & ~new_pmccntr & overflow_mask) {
env->cp15.c9_pmovsr |= (1 << 31);
pmu_update_irq(env);
}
env->cp15.c15_ccnt = new_pmccntr;
}
env->cp15.c15_ccnt_delta = cycles;
}
@ -1207,8 +1225,13 @@ static void pmevcntr_op_start(CPUARMState *env, uint8_t counter)
}
if (pmu_counter_enabled(env, counter)) {
env->cp15.c14_pmevcntr[counter] =
count - env->cp15.c14_pmevcntr_delta[counter];
uint32_t new_pmevcntr = count - env->cp15.c14_pmevcntr_delta[counter];
if (env->cp15.c14_pmevcntr[counter] & ~new_pmevcntr & INT32_MIN) {
env->cp15.c9_pmovsr |= (1 << counter);
pmu_update_irq(env);
}
env->cp15.c14_pmevcntr[counter] = new_pmevcntr;
}
env->cp15.c14_pmevcntr_delta[counter] = count;
}
@ -1285,7 +1308,20 @@ static void pmswinc_write(CPUARMState *env, const ARMCPRegInfo *ri,
/* counter is SW_INCR */
(env->cp15.c14_pmevtyper[i] & PMXEVTYPER_EVTCOUNT) == 0x0) {
pmevcntr_op_start(env, i);
env->cp15.c14_pmevcntr[i]++;
/*
* Detect if this write causes an overflow since we can't predict
* PMSWINC overflows like we can for other events
*/
uint32_t new_pmswinc = env->cp15.c14_pmevcntr[i] + 1;
if (env->cp15.c14_pmevcntr[i] & ~new_pmswinc & INT32_MIN) {
env->cp15.c9_pmovsr |= (1 << i);
pmu_update_irq(env);
}
env->cp15.c14_pmevcntr[i] = new_pmswinc;
pmevcntr_op_finish(env, i);
}
}
@ -1370,6 +1406,7 @@ static void pmovsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
{
value &= pmu_counter_mask(env);
env->cp15.c9_pmovsr &= ~value;
pmu_update_irq(env);
}
static void pmovsset_write(CPUARMState *env, const ARMCPRegInfo *ri,
@ -1377,6 +1414,7 @@ static void pmovsset_write(CPUARMState *env, const ARMCPRegInfo *ri,
{
value &= pmu_counter_mask(env);
env->cp15.c9_pmovsr |= value;
pmu_update_irq(env);
}
static void pmevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri,
@ -1564,6 +1602,7 @@ static void pmintenset_write(CPUARMState *env, const ARMCPRegInfo *ri,
/* We have no event counters so only the C bit can be changed */
value &= pmu_counter_mask(env);
env->cp15.c9_pminten |= value;
pmu_update_irq(env);
}
static void pmintenclr_write(CPUARMState *env, const ARMCPRegInfo *ri,
@ -1571,6 +1610,7 @@ static void pmintenclr_write(CPUARMState *env, const ARMCPRegInfo *ri,
{
value &= pmu_counter_mask(env);
env->cp15.c9_pminten &= ~value;
pmu_update_irq(env);
}
static void vbar_write(CPUARMState *env, const ARMCPRegInfo *ri,
@ -1698,16 +1738,16 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
ARM_CP_ALIAS, PL0_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.c9_pmcnten), {0, 0},
pmreg_access, NULL, pmcntenclr_write },
{ "PMOVSR", 15,9,12, 0,0,3, 0,
0, PL0_RW, 0, NULL, 0, offsetoflow32(CPUARMState, cp15.c9_pmovsr), {0, 0},
ARM_CP_IO, PL0_RW, 0, NULL, 0, offsetoflow32(CPUARMState, cp15.c9_pmovsr), {0, 0},
pmreg_access, NULL, pmovsr_write, NULL, raw_write },
{ "PMOVSCLR_EL0", 0,9,12, 3,3,3, ARM_CP_STATE_AA64, ARM_CP_ALIAS,
{ "PMOVSCLR_EL0", 0,9,12, 3,3,3, ARM_CP_STATE_AA64, ARM_CP_ALIAS | ARM_CP_IO,
PL0_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.c9_pmovsr), {0, 0},
pmreg_access, NULL, pmovsr_write, NULL, raw_write },
{ "PMSWINC", 15,9,12, 0,0,4, 0,
ARM_CP_NO_RAW, PL0_W, 0, NULL, 0, 0, {0, 0},
ARM_CP_NO_RAW | ARM_CP_IO, PL0_W, 0, NULL, 0, 0, {0, 0},
pmreg_access_swinc, NULL, pmswinc_write },
{ "PMSWINC_EL0", 0,9,12, 3,3,4, ARM_CP_STATE_AA64,
ARM_CP_NO_RAW, PL0_W, 0, NULL, 0, 0, {0, 0},
ARM_CP_NO_RAW | ARM_CP_IO, PL0_W, 0, NULL, 0, 0, {0, 0},
pmreg_access_swinc, NULL, pmswinc_write },
{ "PMSELR", 15,9,12, 0,0,5, 0, ARM_CP_ALIAS,
PL0_RW, 0, NULL, 0, offsetoflow32(CPUARMState, cp15.c9_pmselr), {0, 0},
@ -1855,10 +1895,10 @@ static const ARMCPRegInfo v7mp_cp_reginfo[] = {
static const ARMCPRegInfo pmovsset_cp_reginfo[] = {
/* PMOVSSET is not implemented in v7 before v7ve */
{ "PMOVSSET", 15,9,14, 0,0,3, 0, ARM_CP_ALIAS, PL0_RW, 0,
{ "PMOVSSET", 15,9,14, 0,0,3, 0, ARM_CP_ALIAS | ARM_CP_IO, PL0_RW, 0,
NULL, 0, offsetoflow32(CPUARMState, cp15.c9_pmovsr), {0, 0},
pmreg_access, NULL, pmovsset_write, NULL, raw_write },
{ "PMOVSSET_EL0", 0,9,14, 3,3,3, ARM_CP_STATE_AA64, ARM_CP_ALIAS, PL0_RW, 0,
{ "PMOVSSET_EL0", 0,9,14, 3,3,3, ARM_CP_STATE_AA64, ARM_CP_ALIAS | ARM_CP_IO, PL0_RW, 0,
NULL, 0, offsetof(CPUARMState, cp15.c9_pmovsr), {0, 0},
pmreg_access, NULL, pmovsset_write, NULL, raw_write },
REGINFO_SENTINEL