From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53705) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WyKsb-0002Yt-RS for qemu-devel@nongnu.org; Sat, 21 Jun 2014 08:59:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WyKsS-0007W0-Cw for qemu-devel@nongnu.org; Sat, 21 Jun 2014 08:58:49 -0400 Received: from mail-we0-x22d.google.com ([2a00:1450:400c:c03::22d]:58211) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WyKsS-0007VL-35 for qemu-devel@nongnu.org; Sat, 21 Jun 2014 08:58:40 -0400 Received: by mail-we0-f173.google.com with SMTP id t60so4868711wes.18 for ; Sat, 21 Jun 2014 05:58:39 -0700 (PDT) Sender: Paolo Bonzini From: Paolo Bonzini Date: Sat, 21 Jun 2014 14:58:16 +0200 Message-Id: <1403355502-12288-6-git-send-email-pbonzini@redhat.com> In-Reply-To: <1403355502-12288-1-git-send-email-pbonzini@redhat.com> References: <1403355502-12288-1-git-send-email-pbonzini@redhat.com> Subject: [Qemu-devel] [PATCH v3 05/11] 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 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 --- linux-user/main.c | 50 +++++++++++++++++++++++++++++++++++++++++++------- target-arm/cpu.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 795a407..9782c13 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -449,6 +449,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; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index cb5be84..defd65e 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -1192,6 +1192,34 @@ static inline bool bswap_code(bool sctlr_b) #endif } +#ifdef CONFIG_USER_ONLY +/* get_user and put_user respectivaly return and expect data according + * to TARGET_WORDS_BIGENDIAN, but ldrex/strex emulation needs to take + * into account CPSR.E. Similar to bwap_code, a XOR gives exactly the + * required result, we just throw CPSR.E into the mix too: + * + * TARGET_WORDS_BIGENDIAN SCTLR.B CPSR.E need swap? + * LE/LE no 0 0 no + * LE/BE no 0 1 yes + * BE8/LE yes 0 0 yes + * BE8/BE yes 0 1 no + * BE32/BE yes 1 0 no + * (BE32/LE) yes 1 1 yes + * + * Officially, BE32 with CPSR.E=1 has "unpredictable" results. We + * implement it as big-endian code, little-endian data. + */ +static inline bool arm_cpu_bswap_data(CPUARMState *env) +{ + return +#ifdef TARGET_WORDS_BIGENDIAN + 1 ^ +#endif + arm_sctlr_b(env) ^ + !!(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.3