diff options
Diffstat (limited to 'target-arm/translate.c')
-rw-r--r-- | target-arm/translate.c | 51 |
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; |