Message ID | 20211227150127.2659293-7-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. > > The Linux kernel does not handle all memory operations: no > floating-point and no MAC. > > Signed-off-by: Richard Henderson <richard.henderson@linaro.org> > --- > linux-user/sh4/target_prctl.h | 2 +- > target/sh4/cpu.h | 4 +++ > target/sh4/translate.c | 50 ++++++++++++++++++++++++----------- > 3 files changed, 39 insertions(+), 17 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. > > The Linux kernel does not handle all memory operations: no > floating-point and no MAC. > > Signed-off-by: Richard Henderson <richard.henderson@linaro.org> > --- > linux-user/sh4/target_prctl.h | 2 +- > target/sh4/cpu.h | 4 +++ > target/sh4/translate.c | 50 ++++++++++++++++++++++++----------- > 3 files changed, 39 insertions(+), 17 deletions(-) > > diff --git a/linux-user/sh4/target_prctl.h b/linux-user/sh4/target_prctl.h > index eb53b31ad5..5629ddbf39 100644 > --- a/linux-user/sh4/target_prctl.h > +++ b/linux-user/sh4/target_prctl.h > @@ -1 +1 @@ > -/* No special prctl support required. */ > +#include "../generic/target_prctl_unalign.h" > diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h > index 4cfb109f56..fb9dd9db2f 100644 > --- a/target/sh4/cpu.h > +++ b/target/sh4/cpu.h > @@ -83,6 +83,7 @@ > #define DELAY_SLOT_RTE (1 << 2) > > #define TB_FLAG_PENDING_MOVCA (1 << 3) > +#define TB_FLAG_UNALIGN (1 << 4) > > #define GUSA_SHIFT 4 > #ifdef CONFIG_USER_ONLY > @@ -373,6 +374,9 @@ static inline void cpu_get_tb_cpu_state(CPUSH4State *env, target_ulong *pc, > | (env->sr & ((1u << SR_MD) | (1u << SR_RB))) /* Bits 29-30 */ > | (env->sr & (1u << SR_FD)) /* Bit 15 */ > | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 3 */ > +#ifdef CONFIG_USER_ONLY > + *flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; > +#endif > } > > #endif /* SH4_CPU_H */ > diff --git a/target/sh4/translate.c b/target/sh4/translate.c > index ce5d674a52..50493c61ea 100644 > --- a/target/sh4/translate.c > +++ b/target/sh4/translate.c > @@ -50,8 +50,10 @@ typedef struct DisasContext { > > #if defined(CONFIG_USER_ONLY) > #define IS_USER(ctx) 1 > +#define UNALIGN(C) (ctx->tbflags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN) > #else > #define IS_USER(ctx) (!(ctx->tbflags & (1u << SR_MD))) > +#define UNALIGN(C) 0 > #endif > > /* Target-specific values for ctx->base.is_jmp. */ > @@ -495,7 +497,8 @@ static void _decode_opc(DisasContext * ctx) > { > TCGv addr = tcg_temp_new(); > tcg_gen_addi_i32(addr, REG(B11_8), B3_0 * 4); > - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL); > + tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, > + MO_TEUL | UNALIGN(ctx)); > tcg_temp_free(addr); > } > return; > @@ -503,7 +506,8 @@ static void _decode_opc(DisasContext * ctx) > { > TCGv addr = tcg_temp_new(); > tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 4); > - tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL); > + tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, > + MO_TESL | UNALIGN(ctx)); > tcg_temp_free(addr); > } > return; > @@ -558,19 +562,23 @@ static void _decode_opc(DisasContext * ctx) > tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, MO_UB); > return; > case 0x2001: /* mov.w Rm,@Rn */ > - tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, MO_TEUW); > + tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, > + MO_TEUW | UNALIGN(ctx)); > return; > case 0x2002: /* mov.l Rm,@Rn */ > - tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, MO_TEUL); > + tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, > + MO_TEUL | UNALIGN(ctx)); > return; > case 0x6000: /* mov.b @Rm,Rn */ > tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_SB); > return; > case 0x6001: /* mov.w @Rm,Rn */ > - tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESW); > + tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, > + MO_TESW | UNALIGN(ctx)); > return; > case 0x6002: /* mov.l @Rm,Rn */ > - tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESL); > + tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, > + MO_TESL | UNALIGN(ctx)); > return; > case 0x2004: /* mov.b Rm,@-Rn */ > { > @@ -586,7 +594,8 @@ static void _decode_opc(DisasContext * ctx) > { > TCGv addr = tcg_temp_new(); > tcg_gen_subi_i32(addr, REG(B11_8), 2); > - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUW); > + tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, > + MO_TEUW | UNALIGN(ctx)); > tcg_gen_mov_i32(REG(B11_8), addr); > tcg_temp_free(addr); > } > @@ -595,7 +604,8 @@ static void _decode_opc(DisasContext * ctx) > { > TCGv addr = tcg_temp_new(); > tcg_gen_subi_i32(addr, REG(B11_8), 4); > - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL); > + tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, > + MO_TEUL | UNALIGN(ctx)); > tcg_gen_mov_i32(REG(B11_8), addr); > tcg_temp_free(addr); > } > @@ -606,12 +616,14 @@ static void _decode_opc(DisasContext * ctx) > tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 1); > return; > case 0x6005: /* mov.w @Rm+,Rn */ > - tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESW); > + tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, > + MO_TESW | UNALIGN(ctx)); > if ( B11_8 != B7_4 ) > tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2); > return; > case 0x6006: /* mov.l @Rm+,Rn */ > - tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESL); > + tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, > + MO_TESL | UNALIGN(ctx)); > if ( B11_8 != B7_4 ) > tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4); > return; > @@ -627,7 +639,8 @@ static void _decode_opc(DisasContext * ctx) > { > TCGv addr = tcg_temp_new(); > tcg_gen_add_i32(addr, REG(B11_8), REG(0)); > - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUW); > + tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, > + MO_TEUW | UNALIGN(ctx)); > tcg_temp_free(addr); > } > return; > @@ -635,7 +648,8 @@ static void _decode_opc(DisasContext * ctx) > { > TCGv addr = tcg_temp_new(); > tcg_gen_add_i32(addr, REG(B11_8), REG(0)); > - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL); > + tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, > + MO_TEUL | UNALIGN(ctx)); > tcg_temp_free(addr); > } > return; > @@ -651,7 +665,8 @@ static void _decode_opc(DisasContext * ctx) > { > TCGv addr = tcg_temp_new(); > tcg_gen_add_i32(addr, REG(B7_4), REG(0)); > - tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESW); > + tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, > + MO_TESW | UNALIGN(ctx)); > tcg_temp_free(addr); > } > return; > @@ -659,7 +674,8 @@ static void _decode_opc(DisasContext * ctx) > { > TCGv addr = tcg_temp_new(); > tcg_gen_add_i32(addr, REG(B7_4), REG(0)); > - tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL); > + tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, > + MO_TESL | UNALIGN(ctx)); > tcg_temp_free(addr); > } > return; > @@ -1253,7 +1269,8 @@ static void _decode_opc(DisasContext * ctx) > { > TCGv addr = tcg_temp_new(); > tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 2); > - tcg_gen_qemu_st_i32(REG(0), addr, ctx->memidx, MO_TEUW); > + tcg_gen_qemu_st_i32(REG(0), addr, ctx->memidx, > + MO_TEUW | UNALIGN(ctx)); > tcg_temp_free(addr); > } > return; > @@ -1269,7 +1286,8 @@ static void _decode_opc(DisasContext * ctx) > { > TCGv addr = tcg_temp_new(); > tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 2); > - tcg_gen_qemu_ld_i32(REG(0), addr, ctx->memidx, MO_TESW); > + tcg_gen_qemu_ld_i32(REG(0), addr, ctx->memidx, > + MO_TESW | UNALIGN(ctx)); > tcg_temp_free(addr); > } > return; Applied to my linux-user-for-7.0 branch. Thanks, Laurent
diff --git a/linux-user/sh4/target_prctl.h b/linux-user/sh4/target_prctl.h index eb53b31ad5..5629ddbf39 100644 --- a/linux-user/sh4/target_prctl.h +++ b/linux-user/sh4/target_prctl.h @@ -1 +1 @@ -/* No special prctl support required. */ +#include "../generic/target_prctl_unalign.h" diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index 4cfb109f56..fb9dd9db2f 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -83,6 +83,7 @@ #define DELAY_SLOT_RTE (1 << 2) #define TB_FLAG_PENDING_MOVCA (1 << 3) +#define TB_FLAG_UNALIGN (1 << 4) #define GUSA_SHIFT 4 #ifdef CONFIG_USER_ONLY @@ -373,6 +374,9 @@ static inline void cpu_get_tb_cpu_state(CPUSH4State *env, target_ulong *pc, | (env->sr & ((1u << SR_MD) | (1u << SR_RB))) /* Bits 29-30 */ | (env->sr & (1u << SR_FD)) /* Bit 15 */ | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 3 */ +#ifdef CONFIG_USER_ONLY + *flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; +#endif } #endif /* SH4_CPU_H */ diff --git a/target/sh4/translate.c b/target/sh4/translate.c index ce5d674a52..50493c61ea 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -50,8 +50,10 @@ typedef struct DisasContext { #if defined(CONFIG_USER_ONLY) #define IS_USER(ctx) 1 +#define UNALIGN(C) (ctx->tbflags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN) #else #define IS_USER(ctx) (!(ctx->tbflags & (1u << SR_MD))) +#define UNALIGN(C) 0 #endif /* Target-specific values for ctx->base.is_jmp. */ @@ -495,7 +497,8 @@ static void _decode_opc(DisasContext * ctx) { TCGv addr = tcg_temp_new(); tcg_gen_addi_i32(addr, REG(B11_8), B3_0 * 4); - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL); + tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, + MO_TEUL | UNALIGN(ctx)); tcg_temp_free(addr); } return; @@ -503,7 +506,8 @@ static void _decode_opc(DisasContext * ctx) { TCGv addr = tcg_temp_new(); tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 4); - tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL); + tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, + MO_TESL | UNALIGN(ctx)); tcg_temp_free(addr); } return; @@ -558,19 +562,23 @@ static void _decode_opc(DisasContext * ctx) tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, MO_UB); return; case 0x2001: /* mov.w Rm,@Rn */ - tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, MO_TEUW); + tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, + MO_TEUW | UNALIGN(ctx)); return; case 0x2002: /* mov.l Rm,@Rn */ - tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, MO_TEUL); + tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, + MO_TEUL | UNALIGN(ctx)); return; case 0x6000: /* mov.b @Rm,Rn */ tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_SB); return; case 0x6001: /* mov.w @Rm,Rn */ - tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESW); + tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, + MO_TESW | UNALIGN(ctx)); return; case 0x6002: /* mov.l @Rm,Rn */ - tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESL); + tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, + MO_TESL | UNALIGN(ctx)); return; case 0x2004: /* mov.b Rm,@-Rn */ { @@ -586,7 +594,8 @@ static void _decode_opc(DisasContext * ctx) { TCGv addr = tcg_temp_new(); tcg_gen_subi_i32(addr, REG(B11_8), 2); - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUW); + tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, + MO_TEUW | UNALIGN(ctx)); tcg_gen_mov_i32(REG(B11_8), addr); tcg_temp_free(addr); } @@ -595,7 +604,8 @@ static void _decode_opc(DisasContext * ctx) { TCGv addr = tcg_temp_new(); tcg_gen_subi_i32(addr, REG(B11_8), 4); - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL); + tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, + MO_TEUL | UNALIGN(ctx)); tcg_gen_mov_i32(REG(B11_8), addr); tcg_temp_free(addr); } @@ -606,12 +616,14 @@ static void _decode_opc(DisasContext * ctx) tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 1); return; case 0x6005: /* mov.w @Rm+,Rn */ - tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESW); + tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, + MO_TESW | UNALIGN(ctx)); if ( B11_8 != B7_4 ) tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2); return; case 0x6006: /* mov.l @Rm+,Rn */ - tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, MO_TESL); + tcg_gen_qemu_ld_i32(REG(B11_8), REG(B7_4), ctx->memidx, + MO_TESL | UNALIGN(ctx)); if ( B11_8 != B7_4 ) tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4); return; @@ -627,7 +639,8 @@ static void _decode_opc(DisasContext * ctx) { TCGv addr = tcg_temp_new(); tcg_gen_add_i32(addr, REG(B11_8), REG(0)); - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUW); + tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, + MO_TEUW | UNALIGN(ctx)); tcg_temp_free(addr); } return; @@ -635,7 +648,8 @@ static void _decode_opc(DisasContext * ctx) { TCGv addr = tcg_temp_new(); tcg_gen_add_i32(addr, REG(B11_8), REG(0)); - tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL); + tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, + MO_TEUL | UNALIGN(ctx)); tcg_temp_free(addr); } return; @@ -651,7 +665,8 @@ static void _decode_opc(DisasContext * ctx) { TCGv addr = tcg_temp_new(); tcg_gen_add_i32(addr, REG(B7_4), REG(0)); - tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESW); + tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, + MO_TESW | UNALIGN(ctx)); tcg_temp_free(addr); } return; @@ -659,7 +674,8 @@ static void _decode_opc(DisasContext * ctx) { TCGv addr = tcg_temp_new(); tcg_gen_add_i32(addr, REG(B7_4), REG(0)); - tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL); + tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, + MO_TESL | UNALIGN(ctx)); tcg_temp_free(addr); } return; @@ -1253,7 +1269,8 @@ static void _decode_opc(DisasContext * ctx) { TCGv addr = tcg_temp_new(); tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 2); - tcg_gen_qemu_st_i32(REG(0), addr, ctx->memidx, MO_TEUW); + tcg_gen_qemu_st_i32(REG(0), addr, ctx->memidx, + MO_TEUW | UNALIGN(ctx)); tcg_temp_free(addr); } return; @@ -1269,7 +1286,8 @@ static void _decode_opc(DisasContext * ctx) { TCGv addr = tcg_temp_new(); tcg_gen_addi_i32(addr, REG(B7_4), B3_0 * 2); - tcg_gen_qemu_ld_i32(REG(0), addr, ctx->memidx, MO_TESW); + tcg_gen_qemu_ld_i32(REG(0), addr, ctx->memidx, + MO_TESW | UNALIGN(ctx)); tcg_temp_free(addr); } return;
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. The Linux kernel does not handle all memory operations: no floating-point and no MAC. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sh4/target_prctl.h | 2 +- target/sh4/cpu.h | 4 +++ target/sh4/translate.c | 50 ++++++++++++++++++++++++----------- 3 files changed, 39 insertions(+), 17 deletions(-)