Skip to content

Commit

Permalink
linux-user: arm: handle CPSR.E correctly in strex emulation
Browse files Browse the repository at this point in the history
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 <[email protected]>
[ PC changes:
  * Moved SCTLR/CPSR logic to arm_cpu_data_is_big_endian
]
Signed-off-by: Peter Crosthwaite <[email protected]>
Reviewed-by: Peter Maydell <[email protected]>
Signed-off-by: Peter Maydell <[email protected]>
  • Loading branch information
bonzini authored and pm215 committed Mar 4, 2016
1 parent 9c5a746 commit c3ae85f
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 7 deletions.
50 changes: 43 additions & 7 deletions linux-user/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down Expand Up @@ -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();
Expand All @@ -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;
Expand All @@ -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) {
Expand All @@ -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;
Expand Down
11 changes: 11 additions & 0 deletions target-arm/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down

0 comments on commit c3ae85f

Please sign in to comment.