aboutsummaryrefslogtreecommitdiff
path: root/target-arm/translate.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2011-03-22 12:16:16 +0000
committerPeter Maydell <peter.maydell@linaro.org>2011-06-22 15:02:08 +0000
commit74594c9d813e4d14e9c16cc71824d8905bedc19d (patch)
treec8bf7a0dffbcc6db04bafb63c87a2fcbb090c969 /target-arm/translate.c
parentb501b5e461fbf3f5c6cd91c8c933e6f4de627bee (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.c20
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;
}