aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-arm/translate.c51
1 files changed, 33 insertions, 18 deletions
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 34d5e6ef1a..c7961b8097 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -2498,12 +2498,6 @@ static int cp15_user_ok(CPUState *env, uint32_t insn)
if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT)))
return 1;
}
- if (cpn == 7) {
- /* ISB, DSB, DMB. */
- if ((cpm == 5 && op == 4)
- || (cpm == 10 && (op == 4 || op == 5)))
- return 1;
- }
return 0;
}
@@ -2579,39 +2573,60 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
/* cdp */
return 1;
}
- if (IS_USER(s) && !cp15_user_ok(env, insn)) {
- return 1;
- }
-
- /* Pre-v7 versions of the architecture implemented WFI via coprocessor
- * instructions rather than a separate instruction.
+ /* We special case a number of cp15 instructions which were used
+ * for things which are real instructions in ARMv7. This allows
+ * them to work in linux-user mode which doesn't provide functional
+ * get_cp15/set_cp15 helpers, and is more efficient anyway.
*/
- if ((insn & 0x0fff0fff) == 0x0e070f90) {
+ switch ((insn & 0x0fff0fff)) {
+ case 0x0e070f90:
/* 0,c7,c0,4: Standard v6 WFI (also used in some pre-v6 cores).
* In v7, this must NOP.
*/
+ if (IS_USER(s)) {
+ return 1;
+ }
if (!arm_feature(env, ARM_FEATURE_V7)) {
/* Wait for interrupt. */
gen_set_pc_im(s->pc);
s->is_jmp = DISAS_WFI;
}
return 0;
- }
-
- if ((insn & 0x0fff0fff) == 0x0e070f58) {
+ case 0x0e070f58:
/* 0,c7,c8,2: Not all pre-v6 cores implemented this WFI,
* so this is slightly over-broad.
*/
- if (!arm_feature(env, ARM_FEATURE_V6)) {
+ if (!IS_USER(s) && !arm_feature(env, ARM_FEATURE_V6)) {
/* Wait for interrupt. */
gen_set_pc_im(s->pc);
s->is_jmp = DISAS_WFI;
return 0;
}
- /* Otherwise fall through to handle via helper function.
+ /* Otherwise continue to handle via helper function.
* In particular, on v7 and some v6 cores this is one of
* the VA-PA registers.
*/
+ break;
+ case 0x0e070f3d:
+ /* 0,c7,c13,1: prefetch-by-MVA in v6, NOP in v7 */
+ if (arm_feature(env, ARM_FEATURE_V6)) {
+ return IS_USER(s) ? 1 : 0;
+ }
+ break;
+ case 0x0e070f95: /* 0,c7,c5,4 : ISB */
+ case 0x0e070f9a: /* 0,c7,c10,4: DSB */
+ case 0x0e070fba: /* 0,c7,c10,5: DMB */
+ /* Barriers in both v6 and v7 */
+ if (arm_feature(env, ARM_FEATURE_V6)) {
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (IS_USER(s) && !cp15_user_ok(env, insn)) {
+ return 1;
}
rd = (insn >> 12) & 0xf;