Commit ec7b4ce4 authored by Alistair Francis's avatar Alistair Francis Committed by Peter Maydell
Browse files

target-arm: Implement pmccntr_sync function



This is used to synchronise the PMCCNTR counter and swap its
state between enabled and disabled if required. It must always
be called twice, both before and after any logic that could
change the state of the PMCCNTR counter.

Signed-off-by: default avatarAlistair Francis <alistair.francis@xilinx.com>
Signed-off-by: default avatarPeter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: 62811d4c0f7b1384f7aab62ea2fcfda3dcb0db50.1409025949.git.peter.crosthwaite@xilinx.com
[PMM: fixed minor typos in pmccntr_sync doc comment]
Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parent 87124fde
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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
+23 −0
Original line number Diff line number Diff line
@@ -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,