Message ID | 20211227150127.2659293-5-richard.henderson@linaro.org |
---|---|
State | Superseded |
Headers | show |
Series | linux-user: prctl improvements | expand |
Le 27/12/2021 à 16:01, Richard Henderson a écrit : > Leave TARGET_ALIGNED_ONLY set, but use the new CPUState > flag to set MO_UNALN for the instructions that the kernel > handles in the unaligned trap. > > Signed-off-by: Richard Henderson <richard.henderson@linaro.org> > --- > linux-user/alpha/target_prctl.h | 2 +- > target/alpha/cpu.h | 5 +++++ > target/alpha/translate.c | 31 ++++++++++++++++++++++--------- > 3 files changed, 28 insertions(+), 10 deletions(-) Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Le 27/12/2021 à 16:01, Richard Henderson a écrit : > Leave TARGET_ALIGNED_ONLY set, but use the new CPUState > flag to set MO_UNALN for the instructions that the kernel > handles in the unaligned trap. > > Signed-off-by: Richard Henderson <richard.henderson@linaro.org> > --- > linux-user/alpha/target_prctl.h | 2 +- > target/alpha/cpu.h | 5 +++++ > target/alpha/translate.c | 31 ++++++++++++++++++++++--------- > 3 files changed, 28 insertions(+), 10 deletions(-) > > diff --git a/linux-user/alpha/target_prctl.h b/linux-user/alpha/target_prctl.h > index eb53b31ad5..5629ddbf39 100644 > --- a/linux-user/alpha/target_prctl.h > +++ b/linux-user/alpha/target_prctl.h > @@ -1 +1 @@ > -/* No special prctl support required. */ > +#include "../generic/target_prctl_unalign.h" > diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h > index afd975c878..e819211503 100644 > --- a/target/alpha/cpu.h > +++ b/target/alpha/cpu.h > @@ -383,6 +383,8 @@ enum { > #define ENV_FLAG_TB_MASK \ > (ENV_FLAG_PAL_MODE | ENV_FLAG_PS_USER | ENV_FLAG_FEN) > > +#define TB_FLAG_UNALIGN (1u << 1) > + > static inline int cpu_mmu_index(CPUAlphaState *env, bool ifetch) > { > int ret = env->flags & ENV_FLAG_PS_USER ? MMU_USER_IDX : MMU_KERNEL_IDX; > @@ -470,6 +472,9 @@ static inline void cpu_get_tb_cpu_state(CPUAlphaState *env, target_ulong *pc, > *pc = env->pc; > *cs_base = 0; > *pflags = env->flags & ENV_FLAG_TB_MASK; > +#ifdef CONFIG_USER_ONLY > + *pflags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; > +#endif > } > > #ifdef CONFIG_USER_ONLY > diff --git a/target/alpha/translate.c b/target/alpha/translate.c > index a4c3f43e72..208ae5fbd5 100644 > --- a/target/alpha/translate.c > +++ b/target/alpha/translate.c > @@ -45,7 +45,9 @@ typedef struct DisasContext DisasContext; > struct DisasContext { > DisasContextBase base; > > -#ifndef CONFIG_USER_ONLY > +#ifdef CONFIG_USER_ONLY > + MemOp unalign; > +#else > uint64_t palbr; > #endif > uint32_t tbflags; > @@ -68,6 +70,12 @@ struct DisasContext { > TCGv sink; > }; > > +#ifdef CONFIG_USER_ONLY > +#define UNALIGN(C) (C)->unalign > +#else > +#define UNALIGN(C) 0 > +#endif > + > /* Target-specific return values from translate_one, indicating the > state of the TB. Note that DISAS_NEXT indicates that we are not > exiting the TB. */ > @@ -270,7 +278,7 @@ static inline DisasJumpType gen_invalid(DisasContext *ctx) > static void gen_ldf(DisasContext *ctx, TCGv dest, TCGv addr) > { > TCGv_i32 tmp32 = tcg_temp_new_i32(); > - tcg_gen_qemu_ld_i32(tmp32, addr, ctx->mem_idx, MO_LEUL); > + tcg_gen_qemu_ld_i32(tmp32, addr, ctx->mem_idx, MO_LEUL | UNALIGN(ctx)); > gen_helper_memory_to_f(dest, tmp32); > tcg_temp_free_i32(tmp32); > } > @@ -278,7 +286,7 @@ static void gen_ldf(DisasContext *ctx, TCGv dest, TCGv addr) > static void gen_ldg(DisasContext *ctx, TCGv dest, TCGv addr) > { > TCGv tmp = tcg_temp_new(); > - tcg_gen_qemu_ld_i64(tmp, addr, ctx->mem_idx, MO_LEQ); > + tcg_gen_qemu_ld_i64(tmp, addr, ctx->mem_idx, MO_LEQ | UNALIGN(ctx)); > gen_helper_memory_to_g(dest, tmp); > tcg_temp_free(tmp); > } > @@ -286,14 +294,14 @@ static void gen_ldg(DisasContext *ctx, TCGv dest, TCGv addr) > static void gen_lds(DisasContext *ctx, TCGv dest, TCGv addr) > { > TCGv_i32 tmp32 = tcg_temp_new_i32(); > - tcg_gen_qemu_ld_i32(tmp32, addr, ctx->mem_idx, MO_LEUL); > + tcg_gen_qemu_ld_i32(tmp32, addr, ctx->mem_idx, MO_LEUL | UNALIGN(ctx)); > gen_helper_memory_to_s(dest, tmp32); > tcg_temp_free_i32(tmp32); > } > > static void gen_ldt(DisasContext *ctx, TCGv dest, TCGv addr) > { > - tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_LEQ); > + tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_LEQ | UNALIGN(ctx)); > } > > static void gen_load_fp(DisasContext *ctx, int ra, int rb, int32_t disp16, > @@ -324,6 +332,8 @@ static void gen_load_int(DisasContext *ctx, int ra, int rb, int32_t disp16, > tcg_gen_addi_i64(addr, load_gpr(ctx, rb), disp16); > if (clear) { > tcg_gen_andi_i64(addr, addr, ~0x7); > + } else if (!locked) { > + op |= UNALIGN(ctx); > } > > dest = ctx->ir[ra]; > @@ -340,7 +350,7 @@ static void gen_stf(DisasContext *ctx, TCGv src, TCGv addr) > { > TCGv_i32 tmp32 = tcg_temp_new_i32(); > gen_helper_f_to_memory(tmp32, addr); > - tcg_gen_qemu_st_i32(tmp32, addr, ctx->mem_idx, MO_LEUL); > + tcg_gen_qemu_st_i32(tmp32, addr, ctx->mem_idx, MO_LEUL | UNALIGN(ctx)); > tcg_temp_free_i32(tmp32); > } > > @@ -348,7 +358,7 @@ static void gen_stg(DisasContext *ctx, TCGv src, TCGv addr) > { > TCGv tmp = tcg_temp_new(); > gen_helper_g_to_memory(tmp, src); > - tcg_gen_qemu_st_i64(tmp, addr, ctx->mem_idx, MO_LEQ); > + tcg_gen_qemu_st_i64(tmp, addr, ctx->mem_idx, MO_LEQ | UNALIGN(ctx)); > tcg_temp_free(tmp); > } > > @@ -356,13 +366,13 @@ static void gen_sts(DisasContext *ctx, TCGv src, TCGv addr) > { > TCGv_i32 tmp32 = tcg_temp_new_i32(); > gen_helper_s_to_memory(tmp32, src); > - tcg_gen_qemu_st_i32(tmp32, addr, ctx->mem_idx, MO_LEUL); > + tcg_gen_qemu_st_i32(tmp32, addr, ctx->mem_idx, MO_LEUL | UNALIGN(ctx)); > tcg_temp_free_i32(tmp32); > } > > static void gen_stt(DisasContext *ctx, TCGv src, TCGv addr) > { > - tcg_gen_qemu_st_i64(src, addr, ctx->mem_idx, MO_LEQ); > + tcg_gen_qemu_st_i64(src, addr, ctx->mem_idx, MO_LEQ | UNALIGN(ctx)); > } > > static void gen_store_fp(DisasContext *ctx, int ra, int rb, int32_t disp16, > @@ -383,6 +393,8 @@ static void gen_store_int(DisasContext *ctx, int ra, int rb, int32_t disp16, > tcg_gen_addi_i64(addr, load_gpr(ctx, rb), disp16); > if (clear) { > tcg_gen_andi_i64(addr, addr, ~0x7); > + } else { > + op |= UNALIGN(ctx); > } > > src = load_gpr(ctx, ra); > @@ -2942,6 +2954,7 @@ static void alpha_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) > > #ifdef CONFIG_USER_ONLY > ctx->ir = cpu_std_ir; > + ctx->unalign = (ctx->tbflags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN); > #else > ctx->palbr = env->palbr; > ctx->ir = (ctx->tbflags & ENV_FLAG_PAL_MODE ? cpu_pal_ir : cpu_std_ir); Applied to my linux-user-for-7.0 branch. Thanks, Laurent
diff --git a/linux-user/alpha/target_prctl.h b/linux-user/alpha/target_prctl.h index eb53b31ad5..5629ddbf39 100644 --- a/linux-user/alpha/target_prctl.h +++ b/linux-user/alpha/target_prctl.h @@ -1 +1 @@ -/* No special prctl support required. */ +#include "../generic/target_prctl_unalign.h" diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h index afd975c878..e819211503 100644 --- a/target/alpha/cpu.h +++ b/target/alpha/cpu.h @@ -383,6 +383,8 @@ enum { #define ENV_FLAG_TB_MASK \ (ENV_FLAG_PAL_MODE | ENV_FLAG_PS_USER | ENV_FLAG_FEN) +#define TB_FLAG_UNALIGN (1u << 1) + static inline int cpu_mmu_index(CPUAlphaState *env, bool ifetch) { int ret = env->flags & ENV_FLAG_PS_USER ? MMU_USER_IDX : MMU_KERNEL_IDX; @@ -470,6 +472,9 @@ static inline void cpu_get_tb_cpu_state(CPUAlphaState *env, target_ulong *pc, *pc = env->pc; *cs_base = 0; *pflags = env->flags & ENV_FLAG_TB_MASK; +#ifdef CONFIG_USER_ONLY + *pflags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; +#endif } #ifdef CONFIG_USER_ONLY diff --git a/target/alpha/translate.c b/target/alpha/translate.c index a4c3f43e72..208ae5fbd5 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -45,7 +45,9 @@ typedef struct DisasContext DisasContext; struct DisasContext { DisasContextBase base; -#ifndef CONFIG_USER_ONLY +#ifdef CONFIG_USER_ONLY + MemOp unalign; +#else uint64_t palbr; #endif uint32_t tbflags; @@ -68,6 +70,12 @@ struct DisasContext { TCGv sink; }; +#ifdef CONFIG_USER_ONLY +#define UNALIGN(C) (C)->unalign +#else +#define UNALIGN(C) 0 +#endif + /* Target-specific return values from translate_one, indicating the state of the TB. Note that DISAS_NEXT indicates that we are not exiting the TB. */ @@ -270,7 +278,7 @@ static inline DisasJumpType gen_invalid(DisasContext *ctx) static void gen_ldf(DisasContext *ctx, TCGv dest, TCGv addr) { TCGv_i32 tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld_i32(tmp32, addr, ctx->mem_idx, MO_LEUL); + tcg_gen_qemu_ld_i32(tmp32, addr, ctx->mem_idx, MO_LEUL | UNALIGN(ctx)); gen_helper_memory_to_f(dest, tmp32); tcg_temp_free_i32(tmp32); } @@ -278,7 +286,7 @@ static void gen_ldf(DisasContext *ctx, TCGv dest, TCGv addr) static void gen_ldg(DisasContext *ctx, TCGv dest, TCGv addr) { TCGv tmp = tcg_temp_new(); - tcg_gen_qemu_ld_i64(tmp, addr, ctx->mem_idx, MO_LEQ); + tcg_gen_qemu_ld_i64(tmp, addr, ctx->mem_idx, MO_LEQ | UNALIGN(ctx)); gen_helper_memory_to_g(dest, tmp); tcg_temp_free(tmp); } @@ -286,14 +294,14 @@ static void gen_ldg(DisasContext *ctx, TCGv dest, TCGv addr) static void gen_lds(DisasContext *ctx, TCGv dest, TCGv addr) { TCGv_i32 tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld_i32(tmp32, addr, ctx->mem_idx, MO_LEUL); + tcg_gen_qemu_ld_i32(tmp32, addr, ctx->mem_idx, MO_LEUL | UNALIGN(ctx)); gen_helper_memory_to_s(dest, tmp32); tcg_temp_free_i32(tmp32); } static void gen_ldt(DisasContext *ctx, TCGv dest, TCGv addr) { - tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_LEQ); + tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_LEQ | UNALIGN(ctx)); } static void gen_load_fp(DisasContext *ctx, int ra, int rb, int32_t disp16, @@ -324,6 +332,8 @@ static void gen_load_int(DisasContext *ctx, int ra, int rb, int32_t disp16, tcg_gen_addi_i64(addr, load_gpr(ctx, rb), disp16); if (clear) { tcg_gen_andi_i64(addr, addr, ~0x7); + } else if (!locked) { + op |= UNALIGN(ctx); } dest = ctx->ir[ra]; @@ -340,7 +350,7 @@ static void gen_stf(DisasContext *ctx, TCGv src, TCGv addr) { TCGv_i32 tmp32 = tcg_temp_new_i32(); gen_helper_f_to_memory(tmp32, addr); - tcg_gen_qemu_st_i32(tmp32, addr, ctx->mem_idx, MO_LEUL); + tcg_gen_qemu_st_i32(tmp32, addr, ctx->mem_idx, MO_LEUL | UNALIGN(ctx)); tcg_temp_free_i32(tmp32); } @@ -348,7 +358,7 @@ static void gen_stg(DisasContext *ctx, TCGv src, TCGv addr) { TCGv tmp = tcg_temp_new(); gen_helper_g_to_memory(tmp, src); - tcg_gen_qemu_st_i64(tmp, addr, ctx->mem_idx, MO_LEQ); + tcg_gen_qemu_st_i64(tmp, addr, ctx->mem_idx, MO_LEQ | UNALIGN(ctx)); tcg_temp_free(tmp); } @@ -356,13 +366,13 @@ static void gen_sts(DisasContext *ctx, TCGv src, TCGv addr) { TCGv_i32 tmp32 = tcg_temp_new_i32(); gen_helper_s_to_memory(tmp32, src); - tcg_gen_qemu_st_i32(tmp32, addr, ctx->mem_idx, MO_LEUL); + tcg_gen_qemu_st_i32(tmp32, addr, ctx->mem_idx, MO_LEUL | UNALIGN(ctx)); tcg_temp_free_i32(tmp32); } static void gen_stt(DisasContext *ctx, TCGv src, TCGv addr) { - tcg_gen_qemu_st_i64(src, addr, ctx->mem_idx, MO_LEQ); + tcg_gen_qemu_st_i64(src, addr, ctx->mem_idx, MO_LEQ | UNALIGN(ctx)); } static void gen_store_fp(DisasContext *ctx, int ra, int rb, int32_t disp16, @@ -383,6 +393,8 @@ static void gen_store_int(DisasContext *ctx, int ra, int rb, int32_t disp16, tcg_gen_addi_i64(addr, load_gpr(ctx, rb), disp16); if (clear) { tcg_gen_andi_i64(addr, addr, ~0x7); + } else { + op |= UNALIGN(ctx); } src = load_gpr(ctx, ra); @@ -2942,6 +2954,7 @@ static void alpha_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) #ifdef CONFIG_USER_ONLY ctx->ir = cpu_std_ir; + ctx->unalign = (ctx->tbflags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN); #else ctx->palbr = env->palbr; ctx->ir = (ctx->tbflags & ENV_FLAG_PAL_MODE ? cpu_pal_ir : cpu_std_ir);
Leave TARGET_ALIGNED_ONLY set, but use the new CPUState flag to set MO_UNALN for the instructions that the kernel handles in the unaligned trap. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/alpha/target_prctl.h | 2 +- target/alpha/cpu.h | 5 +++++ target/alpha/translate.c | 31 ++++++++++++++++++++++--------- 3 files changed, 28 insertions(+), 10 deletions(-)