From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42371) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aL3zk-0002x4-TJ for qemu-devel@nongnu.org; Mon, 18 Jan 2016 02:12:57 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aL3zj-00071s-Is for qemu-devel@nongnu.org; Mon, 18 Jan 2016 02:12:56 -0500 From: Peter Crosthwaite Date: Sun, 17 Jan 2016 23:12:30 -0800 Message-Id: In-Reply-To: References: In-Reply-To: References: Subject: [Qemu-devel] [PATCH v1 03/17] linux-user: arm: handle CPSR.E correctly in strex emulation List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: peter.maydell@linaro.org, Peter Crosthwaite , alistair.francis@xilinx.com, sridhar_kulk@yahoo.com, qemu-arm@nongnu.org, pbonzini@redhat.com, piotr.krol@3mdeb.com From: Paolo Bonzini 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). Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini [ PC changes: * Remove BE32 support ] Signed-off-by: Peter Crosthwaite --- linux-user/main.c | 50 +++++++++++++++++++++++++++++++++++++++++++------- target-arm/cpu.h | 21 +++++++++++++++++++++ 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 4f8ea9c..8348ddc 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -455,6 +455,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 */ @@ -614,11 +646,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(); @@ -629,12 +661,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; @@ -646,11 +682,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) { @@ -659,7 +695,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; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 815fef8..f83070a 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -1934,6 +1934,27 @@ static inline int fp_exception_el(CPUARMState *env) return 0; } +#ifdef CONFIG_USER_ONLY +/* get_user and put_user respectively return and expect data according + * to TARGET_WORDS_BIGENDIAN, but ldrex/strex emulation needs to take + * into account CPSR.E. + * + * TARGET_WORDS_BIGENDIAN CPSR.E need swap? + * LE/LE no 0 no + * LE/BE no 1 yes + * BE8/LE yes 0 yes + * BE8/BE yes 1 no + */ +static inline bool arm_cpu_bswap_data(CPUARMState *env) +{ + return +#ifdef TARGET_WORDS_BIGENDIAN + ! +#endif + !(env->uncached_cpsr & CPSR_E); +} +#endif + static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, target_ulong *cs_base, int *flags) { -- 1.9.1