linux-user: arm: handle CPSR.E correctly in strex emulation

Now that CPSR.E is set correctly, prepare for when setend will be able
to change it; bswap data in and out of strex manually by comparing
SCTLR.B, CPSR.E and TARGET_WORDS_BIGENDIAN (we do not have the luxury
of using TCGMemOps).

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
[ PC changes:
  * Moved SCTLR/CPSR logic to arm_cpu_data_is_big_endian
]
Signed-off-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Paolo Bonzini 2016-03-04 11:30:19 +00:00 committed by Peter Maydell
parent 9c5a746038
commit c3ae85fc8f
2 changed files with 54 additions and 7 deletions

View file

@ -451,6 +451,38 @@ void cpu_loop(CPUX86State *env)
__r; \
})
#define get_user_data_u32(x, gaddr, env) \
({ abi_long __r = get_user_u32((x), (gaddr)); \
if (!__r && arm_cpu_bswap_data(env)) { \
(x) = bswap32(x); \
} \
__r; \
})
#define get_user_data_u16(x, gaddr, env) \
({ abi_long __r = get_user_u16((x), (gaddr)); \
if (!__r && arm_cpu_bswap_data(env)) { \
(x) = bswap16(x); \
} \
__r; \
})
#define put_user_data_u32(x, gaddr, env) \
({ typeof(x) __x = (x); \
if (arm_cpu_bswap_data(env)) { \
__x = bswap32(__x); \
} \
put_user_u32(__x, (gaddr)); \
})
#define put_user_data_u16(x, gaddr, env) \
({ typeof(x) __x = (x); \
if (arm_cpu_bswap_data(env)) { \
__x = bswap16(__x); \
} \
put_user_u16(__x, (gaddr)); \
})
#ifdef TARGET_ABI32
/* Commpage handling -- there is no commpage for AArch64 */
@ -610,11 +642,11 @@ static int do_strex(CPUARMState *env)
segv = get_user_u8(val, addr);
break;
case 1:
segv = get_user_u16(val, addr);
segv = get_user_data_u16(val, addr, env);
break;
case 2:
case 3:
segv = get_user_u32(val, addr);
segv = get_user_data_u32(val, addr, env);
break;
default:
abort();
@ -625,12 +657,16 @@ static int do_strex(CPUARMState *env)
}
if (size == 3) {
uint32_t valhi;
segv = get_user_u32(valhi, addr + 4);
segv = get_user_data_u32(valhi, addr + 4, env);
if (segv) {
env->exception.vaddress = addr + 4;
goto done;
}
val = deposit64(val, 32, 32, valhi);
if (arm_cpu_bswap_data(env)) {
val = deposit64((uint64_t)valhi, 32, 32, val);
} else {
val = deposit64(val, 32, 32, valhi);
}
}
if (val != env->exclusive_val) {
goto fail;
@ -642,11 +678,11 @@ static int do_strex(CPUARMState *env)
segv = put_user_u8(val, addr);
break;
case 1:
segv = put_user_u16(val, addr);
segv = put_user_data_u16(val, addr, env);
break;
case 2:
case 3:
segv = put_user_u32(val, addr);
segv = put_user_data_u32(val, addr, env);
break;
}
if (segv) {
@ -655,7 +691,7 @@ static int do_strex(CPUARMState *env)
}
if (size == 3) {
val = env->regs[(env->exclusive_info >> 12) & 0xf];
segv = put_user_u32(val, addr + 4);
segv = put_user_data_u32(val, addr + 4, env);
if (segv) {
env->exception.vaddress = addr + 4;
goto done;

View file

@ -2102,6 +2102,17 @@ static inline int fp_exception_el(CPUARMState *env)
return 0;
}
#ifdef CONFIG_USER_ONLY
static inline bool arm_cpu_bswap_data(CPUARMState *env)
{
return
#ifdef TARGET_WORDS_BIGENDIAN
1 ^
#endif
arm_cpu_data_is_big_endian(env);
}
#endif
static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
{