From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42152) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WiJfa-0007dN-Ju for qemu-devel@nongnu.org; Thu, 08 May 2014 04:27:12 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WiJfZ-0005tj-8t for qemu-devel@nongnu.org; Thu, 08 May 2014 04:27:10 -0400 Received: from mail-ve0-x249.google.com ([2607:f8b0:400c:c01::249]:48993) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WiJfZ-0005sk-4O for qemu-devel@nongnu.org; Thu, 08 May 2014 04:27:09 -0400 Received: by mail-ve0-f201.google.com with SMTP id db11so326662veb.2 for ; Thu, 08 May 2014 01:27:08 -0700 (PDT) From: Doug Kwan Date: Thu, 8 May 2014 01:26:42 -0700 Message-Id: <1399537603-6905-3-git-send-email-dougkwan@google.com> In-Reply-To: <1399537603-6905-1-git-send-email-dougkwan@google.com> References: <1399537603-6905-1-git-send-email-dougkwan@google.com> Subject: [Qemu-devel] [PATCH 2/3] PPC: Allow little-endian user mode. List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org, qemu-ppc@nongnu.org Cc: riku.voipio@iki.fi, Doug Kwan , agraf@suse.de This all running PPC64 little-endian in user mode if target is configured that way. In PPC64 LE user mode we set MSR.LE during initialization. Byteswapping logic is reversed also when QEMU is running in that mode. Signed-off-by: Doug Kwan --- target-ppc/mem_helper.c | 16 ++++++++++++++-- target-ppc/translate.c | 45 ++++++++++++++++++++++++++++++--------------- target-ppc/translate_init.c | 9 +++++++++ 3 files changed, 53 insertions(+), 17 deletions(-) diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c index f35ed03..7bacdab 100644 --- a/target-ppc/mem_helper.c +++ b/target-ppc/mem_helper.c @@ -202,6 +202,14 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg, #define LO_IDX 0 #endif +static inline bool element_needs_byteswap(CPUPPCState *env) { +#if defined(TARGET_WORDS_BIGENDIAN) + return msr_le; +#else + return !msr_le; +#endif +} + #define LVE(name, access, swap, element) \ void helper_##name(CPUPPCState *env, ppc_avr_t *r, \ target_ulong addr) \ @@ -210,9 +218,11 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg, int adjust = HI_IDX*(n_elems - 1); \ int sh = sizeof(r->element[0]) >> 1; \ int index = (addr & 0xf) >> sh; \ - \ if (msr_le) { \ index = n_elems - index - 1; \ + } \ + \ + if (element_needs_byteswap(env)) { \ r->element[LO_IDX ? index : (adjust - index)] = \ swap(access(env, addr)); \ } else { \ @@ -235,9 +245,11 @@ LVE(lvewx, cpu_ldl_data, bswap32, u32) int adjust = HI_IDX * (n_elems - 1); \ int sh = sizeof(r->element[0]) >> 1; \ int index = (addr & 0xf) >> sh; \ - \ if (msr_le) { \ index = n_elems - index - 1; \ + } \ + \ + if (element_needs_byteswap(env)) { \ access(env, addr, swap(r->element[LO_IDX ? index : \ (adjust - index)])); \ } else { \ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index e3fcb03..4b11c5a 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -210,6 +210,15 @@ typedef struct DisasContext { uint64_t insns_flags2; } DisasContext; +/* Return true iff byteswap is needed in a scalar memop */ +static inline bool need_byteswap(const DisasContext *ctx) { +#if defined(TARGET_WORDS_BIGENDIAN) + return ctx->le_mode; +#else + return !ctx->le_mode; +#endif +} + /* True when active word size < size of target_long. */ #ifdef TARGET_PPC64 # define NARROW_MODE(C) (!(C)->sf_mode) @@ -2653,14 +2662,14 @@ static inline void gen_qemu_ld8s(DisasContext *ctx, TCGv arg1, TCGv arg2) static inline void gen_qemu_ld16u(DisasContext *ctx, TCGv arg1, TCGv arg2) { tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx); - if (unlikely(ctx->le_mode)) { + if (unlikely(need_byteswap(ctx))) { tcg_gen_bswap16_tl(arg1, arg1); } } static inline void gen_qemu_ld16s(DisasContext *ctx, TCGv arg1, TCGv arg2) { - if (unlikely(ctx->le_mode)) { + if (unlikely(need_byteswap(ctx))) { tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx); tcg_gen_bswap16_tl(arg1, arg1); tcg_gen_ext16s_tl(arg1, arg1); @@ -2672,7 +2681,7 @@ static inline void gen_qemu_ld16s(DisasContext *ctx, TCGv arg1, TCGv arg2) static inline void gen_qemu_ld32u(DisasContext *ctx, TCGv arg1, TCGv arg2) { tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx); - if (unlikely(ctx->le_mode)) { + if (unlikely(need_byteswap(ctx))) { tcg_gen_bswap32_tl(arg1, arg1); } } @@ -2687,7 +2696,7 @@ static void gen_qemu_ld32u_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) static inline void gen_qemu_ld32s(DisasContext *ctx, TCGv arg1, TCGv arg2) { - if (unlikely(ctx->le_mode)) { + if (unlikely(need_byteswap(ctx))) { tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx); tcg_gen_bswap32_tl(arg1, arg1); tcg_gen_ext32s_tl(arg1, arg1); @@ -2706,7 +2715,7 @@ static void gen_qemu_ld32s_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) static inline void gen_qemu_ld64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) { tcg_gen_qemu_ld64(arg1, arg2, ctx->mem_idx); - if (unlikely(ctx->le_mode)) { + if (unlikely(need_byteswap(ctx))) { tcg_gen_bswap64_i64(arg1, arg1); } } @@ -2718,7 +2727,7 @@ static inline void gen_qemu_st8(DisasContext *ctx, TCGv arg1, TCGv arg2) static inline void gen_qemu_st16(DisasContext *ctx, TCGv arg1, TCGv arg2) { - if (unlikely(ctx->le_mode)) { + if (unlikely(need_byteswap(ctx))) { TCGv t0 = tcg_temp_new(); tcg_gen_ext16u_tl(t0, arg1); tcg_gen_bswap16_tl(t0, t0); @@ -2731,7 +2740,7 @@ static inline void gen_qemu_st16(DisasContext *ctx, TCGv arg1, TCGv arg2) static inline void gen_qemu_st32(DisasContext *ctx, TCGv arg1, TCGv arg2) { - if (unlikely(ctx->le_mode)) { + if (unlikely(need_byteswap(ctx))) { TCGv t0 = tcg_temp_new(); tcg_gen_ext32u_tl(t0, arg1); tcg_gen_bswap32_tl(t0, t0); @@ -2752,7 +2761,7 @@ static void gen_qemu_st32_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr) static inline void gen_qemu_st64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) { - if (unlikely(ctx->le_mode)) { + if (unlikely(need_byteswap(ctx))) { TCGv_i64 t0 = tcg_temp_new_i64(); tcg_gen_bswap64_i64(t0, arg1); tcg_gen_qemu_st64(t0, arg2, ctx->mem_idx); @@ -3049,11 +3058,17 @@ static void gen_std(DisasContext *ctx) } #endif /*** Integer load and store with byte reverse ***/ + +/* Logic for byteswap test is reversed since these instructions require + * a byteswap already. If we need another byteswap due to endianness of + * translation context, the two byteswaps cancel out each other. + */ + /* lhbrx */ static inline void gen_qemu_ld16ur(DisasContext *ctx, TCGv arg1, TCGv arg2) { tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx); - if (likely(!ctx->le_mode)) { + if (likely(!need_byteswap(ctx))) { tcg_gen_bswap16_tl(arg1, arg1); } } @@ -3063,7 +3078,7 @@ GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER); static inline void gen_qemu_ld32ur(DisasContext *ctx, TCGv arg1, TCGv arg2) { tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx); - if (likely(!ctx->le_mode)) { + if (likely(!need_byteswap(ctx))) { tcg_gen_bswap32_tl(arg1, arg1); } } @@ -3074,7 +3089,7 @@ GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER); static inline void gen_qemu_ld64ur(DisasContext *ctx, TCGv arg1, TCGv arg2) { tcg_gen_qemu_ld64(arg1, arg2, ctx->mem_idx); - if (likely(!ctx->le_mode)) { + if (likely(!need_byteswap(ctx))) { tcg_gen_bswap64_tl(arg1, arg1); } } @@ -3084,7 +3099,7 @@ GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX); /* sthbrx */ static inline void gen_qemu_st16r(DisasContext *ctx, TCGv arg1, TCGv arg2) { - if (likely(!ctx->le_mode)) { + if (likely(!need_byteswap(ctx))) { TCGv t0 = tcg_temp_new(); tcg_gen_ext16u_tl(t0, arg1); tcg_gen_bswap16_tl(t0, t0); @@ -3099,7 +3114,7 @@ GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER); /* stwbrx */ static inline void gen_qemu_st32r(DisasContext *ctx, TCGv arg1, TCGv arg2) { - if (likely(!ctx->le_mode)) { + if (likely(!need_byteswap(ctx))) { TCGv t0 = tcg_temp_new(); tcg_gen_ext32u_tl(t0, arg1); tcg_gen_bswap32_tl(t0, t0); @@ -3115,7 +3130,7 @@ GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER); /* stdbrx */ static inline void gen_qemu_st64r(DisasContext *ctx, TCGv arg1, TCGv arg2) { - if (likely(!ctx->le_mode)) { + if (likely(!need_byteswap(ctx))) { TCGv t0 = tcg_temp_new(); tcg_gen_bswap64_tl(t0, arg1); tcg_gen_qemu_st64(t0, arg2, ctx->mem_idx); @@ -11401,7 +11416,7 @@ static inline void gen_intermediate_code_internal(PowerPCCPU *cpu, ctx.nip, ctx.mem_idx, (int)msr_ir); if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) gen_io_start(); - if (unlikely(ctx.le_mode)) { + if (unlikely(need_byteswap(&ctx))) { ctx.opcode = bswap32(cpu_ldl_code(env, ctx.nip)); } else { ctx.opcode = cpu_ldl_code(env, ctx.nip); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 4d94015..84381ae 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -8418,6 +8418,9 @@ static void ppc_cpu_reset(CPUState *s) msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */ msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */ msr |= (target_ulong)1 << MSR_PR; +#if !defined(TARGET_WORDS_BIGENDIAN) + msr |= (target_ulong)1 << MSR_LE; /* Little-endian user mode */ +#endif #endif #if defined(TARGET_PPC64) @@ -8461,6 +8464,12 @@ static void ppc_cpu_reset(CPUState *s) /* Flush all TLBs */ tlb_flush(s, 1); + +#if defined(CONFIG_USER_ONLY) && !defined(TARGET_WORDS_BIGENDIAN) + if (!msr_le) { + cpu_abort(CPU(cpu), "Cannot set QEMU to little-endian user mode\n"); + } +#endif } static void ppc_cpu_initfn(Object *obj) -- 1.9.1.423.g4596e3a