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:
parent
9c5a746038
commit
c3ae85fc8f
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user