diff options
Diffstat (limited to 'target-arm')
-rw-r--r-- | target-arm/cpu.h | 11 | ||||
-rw-r--r-- | target-arm/helper.c | 23 |
2 files changed, 34 insertions, 0 deletions
diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 60dea03092..51bedc8262 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -353,6 +353,17 @@ int cpu_arm_signal_handler(int host_signum, void *pinfo, int arm_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw, int mmu_idx); +/** + * pmccntr_sync + * @env: CPUARMState + * + * Synchronises the counter in the PMCCNTR. This must always be called twice, + * once before any action that might affect the timer and again afterwards. + * The function is used to swap the state of the register if required. + * This only happens when not in user mode (!CONFIG_USER_ONLY) + */ +void pmccntr_sync(CPUARMState *env); + /* 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/target-arm/helper.c b/target-arm/helper.c index e6c82ab0b8..fa79dfa614 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -560,6 +560,23 @@ static inline bool arm_ccnt_enabled(CPUARMState *env) return true; } +void pmccntr_sync(CPUARMState *env) +{ + uint64_t temp_ticks; + + temp_ticks = muldiv64(qemu_clock_get_us(QEMU_CLOCK_VIRTUAL), + get_ticks_per_sec(), 1000000); + + if (env->cp15.c9_pmcr & PMCRD) { + /* Increment once every 64 processor clock cycles */ + temp_ticks /= 64; + } + + if (arm_ccnt_enabled(env)) { + env->cp15.c15_ccnt = temp_ticks - env->cp15.c15_ccnt; + } +} + static void pmcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { @@ -644,6 +661,12 @@ 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_sync(CPUARMState *env) +{ +} + #endif static void pmcntenset_write(CPUARMState *env, const ARMCPRegInfo *ri, |