diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2011-03-22 12:16:16 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2011-06-22 15:02:08 +0000 |
commit | 74594c9d813e4d14e9c16cc71824d8905bedc19d (patch) | |
tree | c8bf7a0dffbcc6db04bafb63c87a2fcbb090c969 /target-arm/translate.c | |
parent | b501b5e461fbf3f5c6cd91c8c933e6f4de627bee (diff) |
target-arm: Minimal implementation of performance counters
Newer Linux kernels assume the existence of the performance counter
cp15 registers. Provide a minimal implementation of these registers.
We support no events. This should be compliant with the ARM ARM,
except that we don't implement the cycle counter.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-arm/translate.c')
-rw-r--r-- | target-arm/translate.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/target-arm/translate.c b/target-arm/translate.c index 0273deb11a..3e431e15cb 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2472,12 +2472,28 @@ static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn) return 0; } -static int cp15_user_ok(uint32_t insn) +static int cp15_user_ok(CPUState *env, uint32_t insn) { int cpn = (insn >> 16) & 0xf; int cpm = insn & 0xf; int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38); + if (arm_feature(env, ARM_FEATURE_V7) && cpn == 9) { + /* Performance monitor registers fall into three categories: + * (a) always UNDEF in usermode + * (b) UNDEF only if PMUSERENR.EN is 0 + * (c) always read OK and UNDEF on write (PMUSERENR only) + */ + if ((cpm == 12 && (op < 6)) || + (cpm == 13 && (op < 3))) { + return env->cp15.c9_pmuserenr; + } else if (cpm == 14 && op == 0 && (insn & ARM_CP_RW_BIT)) { + /* PMUSERENR, read only */ + return 1; + } + return 0; + } + if (cpn == 13 && cpm == 0) { /* TLS register. */ if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT))) @@ -2564,7 +2580,7 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn) /* cdp */ return 1; } - if (IS_USER(s) && !cp15_user_ok(insn)) { + if (IS_USER(s) && !cp15_user_ok(env, insn)) { return 1; } |