aboutsummaryrefslogtreecommitdiff
path: root/target-arm/translate.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-09-29 18:48:48 +0100
committerPeter Maydell <peter.maydell@linaro.org>2014-09-29 18:48:48 +0100
commitc0f4af171999eda4e49de5169906ce98246457f0 (patch)
treef49424c8ec77adc33a948e299259c8f30966cd66 /target-arm/translate.c
parentf59492b984934170f624487ffdec983a0102ba96 (diff)
downloadqemu-arm-c0f4af171999eda4e49de5169906ce98246457f0.tar.gz
target-arm: Don't handle c15_cpar changes via tb_flush()
At the moment we try to handle c15_cpar with the strategy of: * emit generated code which makes assumptions about its value * when the register value changes call tb_flush() to throw away the now-invalid generated code This works because XScale CPUs are always uniprocessor, but it's confusing because it suggests that the same approach can be taken for other registers. It also means we do a tb_flush() on CPU reset, which makes multithreaded linux-user binaries even more likely to fail than would otherwise be the case. Replace it with a combination of TB flags for the access checks done on cp0/cp1 for the XScale and iwMMXt instructions, plus a runtime check for cp2..cp13 coprocessor accesses. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1411056959-23070-1-git-send-email-peter.maydell@linaro.org
Diffstat (limited to 'target-arm/translate.c')
-rw-r--r--target-arm/translate.c40
1 files changed, 21 insertions, 19 deletions
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 2c0b1deaea..8a2994fcb4 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -7001,22 +7001,18 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
const ARMCPRegInfo *ri;
cpnum = (insn >> 8) & 0xf;
- if (arm_feature(env, ARM_FEATURE_XSCALE)
- && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum)))
- return 1;
-
- /* First check for coprocessor space used for actual instructions */
- switch (cpnum) {
- case 0:
- case 1:
- if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
- return disas_iwmmxt_insn(env, s, insn);
- } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
- return disas_dsp_insn(env, s, insn);
- }
- return 1;
- default:
- break;
+
+ /* First check for coprocessor space used for XScale/iwMMXt insns */
+ if (arm_feature(env, ARM_FEATURE_XSCALE) && (cpnum < 2)) {
+ if (extract32(s->c15_cpar, cpnum, 1) == 0) {
+ return 1;
+ }
+ if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+ return disas_iwmmxt_insn(env, s, insn);
+ } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+ return disas_dsp_insn(env, s, insn);
+ }
+ return 1;
}
/* Otherwise treat as a generic register access */
@@ -7049,9 +7045,12 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
return 1;
}
- if (ri->accessfn) {
+ if (ri->accessfn ||
+ (arm_feature(env, ARM_FEATURE_XSCALE) && cpnum < 14)) {
/* Emit code to perform further access permissions checks at
* runtime; this may result in an exception.
+ * Note that on XScale all cp0..c13 registers do an access check
+ * call in order to handle c15_cpar.
*/
TCGv_ptr tmpptr;
TCGv_i32 tcg_syn;
@@ -7675,9 +7674,11 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
} else if ((insn & 0x0e000f00) == 0x0c000100) {
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
/* iWMMXt register transfer. */
- if (env->cp15.c15_cpar & (1 << 1))
- if (!disas_iwmmxt_insn(env, s, insn))
+ if (extract32(s->c15_cpar, 1, 1)) {
+ if (!disas_iwmmxt_insn(env, s, insn)) {
return;
+ }
+ }
}
} else if ((insn & 0x0fe00000) == 0x0c400000) {
/* Coprocessor double register transfer. */
@@ -10942,6 +10943,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
+ dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(tb->flags);
dc->cp_regs = cpu->cp_regs;
dc->current_pl = arm_current_pl(env);
dc->features = env->features;