From c652028eb51f9c595ca9fd2a33fab5e8c75d0b1e Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Tue, 6 Mar 2018 08:08:12 -0500 Subject: [PATCH] target/m68k: add chk and chk2 chk and chk2 compare a value to boundaries, and trigger a CHK exception if the value is out of bounds. Backports commit 8bf6cbaf396a8b54b138bb8a7c3377f2868ed16e from qemu --- qemu/target/m68k/cpu.c | 2 + qemu/target/m68k/cpu.h | 1 + qemu/target/m68k/helper.h | 2 + qemu/target/m68k/op_helper.c | 60 +++++++++++++++++++++++++++ qemu/target/m68k/translate.c | 79 +++++++++++++++++++++++++++++++++++- 5 files changed, 143 insertions(+), 1 deletion(-) diff --git a/qemu/target/m68k/cpu.c b/qemu/target/m68k/cpu.c index 6e0943f1..944e383b 100644 --- a/qemu/target/m68k/cpu.c +++ b/qemu/target/m68k/cpu.c @@ -128,6 +128,7 @@ static void m68020_cpu_initfn(struct uc_struct *uc, Object *obj, void *opaque) m68k_set_feature(env, M68K_FEATURE_CAS); m68k_set_feature(env, M68K_FEATURE_BKPT); m68k_set_feature(env, M68K_FEATURE_RTD); + m68k_set_feature(env, M68K_FEATURE_CHK2); } #define m68030_cpu_initfn m68020_cpu_initfn #define m68040_cpu_initfn m68020_cpu_initfn @@ -150,6 +151,7 @@ static void m68060_cpu_initfn(struct uc_struct *uc, Object *obj, void *opaque) m68k_set_feature(env, M68K_FEATURE_CAS); m68k_set_feature(env, M68K_FEATURE_BKPT); m68k_set_feature(env, M68K_FEATURE_RTD); + m68k_set_feature(env, M68K_FEATURE_CHK2); } static void m5208_cpu_initfn(struct uc_struct *uc, Object *obj, void *opaque) diff --git a/qemu/target/m68k/cpu.h b/qemu/target/m68k/cpu.h index b1a7dd19..1416bdd2 100644 --- a/qemu/target/m68k/cpu.h +++ b/qemu/target/m68k/cpu.h @@ -303,6 +303,7 @@ enum m68k_features { M68K_FEATURE_CAS, M68K_FEATURE_BKPT, M68K_FEATURE_RTD, + M68K_FEATURE_CHK2, }; static inline int m68k_feature(CPUM68KState *env, int feature) diff --git a/qemu/target/m68k/helper.h b/qemu/target/m68k/helper.h index 71eb6ea0..61b773bf 100644 --- a/qemu/target/m68k/helper.h +++ b/qemu/target/m68k/helper.h @@ -96,3 +96,5 @@ DEF_HELPER_FLAGS_4(bfclr_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32) DEF_HELPER_FLAGS_4(bfset_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32) DEF_HELPER_FLAGS_4(bfffo_mem, TCG_CALL_NO_WG, i64, env, i32, s32, i32) +DEF_HELPER_3(chk, void, env, s32, s32) +DEF_HELPER_4(chk2, void, env, s32, s32, s32) diff --git a/qemu/target/m68k/op_helper.c b/qemu/target/m68k/op_helper.c index 8325eff3..9b61f0bb 100644 --- a/qemu/target/m68k/op_helper.c +++ b/qemu/target/m68k/op_helper.c @@ -947,3 +947,63 @@ uint64_t HELPER(bfffo_mem)(CPUM68KState *env, uint32_t addr, return n | ffo; } +void HELPER(chk)(CPUM68KState *env, int32_t val, int32_t ub) +{ + /* From the specs: + * X: Not affected, C,V,Z: Undefined, + * N: Set if val < 0; cleared if val > ub, undefined otherwise + * We implement here values found from a real MC68040: + * X,V,Z: Not affected + * N: Set if val < 0; cleared if val >= 0 + * C: if 0 <= ub: set if val < 0 or val > ub, cleared otherwise + * if 0 > ub: set if val > ub and val < 0, cleared otherwise + */ + env->cc_n = val; + env->cc_c = 0 <= ub ? val < 0 || val > ub : val > ub && val < 0; + + if (val < 0 || val > ub) { + CPUState *cs = CPU(m68k_env_get_cpu(env)); + + /* Recover PC and CC_OP for the beginning of the insn. */ + cpu_restore_state(cs, GETPC()); + + /* flags have been modified by gen_flush_flags() */ + env->cc_op = CC_OP_FLAGS; + /* Adjust PC to end of the insn. */ + env->pc += 2; + + cs->exception_index = EXCP_CHK; + cpu_loop_exit(cs); + } +} + +void HELPER(chk2)(CPUM68KState *env, int32_t val, int32_t lb, int32_t ub) +{ + /* From the specs: + * X: Not affected, N,V: Undefined, + * Z: Set if val is equal to lb or ub + * C: Set if val < lb or val > ub, cleared otherwise + * We implement here values found from a real MC68040: + * X,N,V: Not affected + * Z: Set if val is equal to lb or ub + * C: if lb <= ub: set if val < lb or val > ub, cleared otherwise + * if lb > ub: set if val > ub and val < lb, cleared otherwise + */ + env->cc_z = val != lb && val != ub; + env->cc_c = lb <= ub ? val < lb || val > ub : val > ub && val < lb; + + if (env->cc_c) { + CPUState *cs = CPU(m68k_env_get_cpu(env)); + + /* Recover PC and CC_OP for the beginning of the insn. */ + cpu_restore_state(cs, GETPC()); + + /* flags have been modified by gen_flush_flags() */ + env->cc_op = CC_OP_FLAGS; + /* Adjust PC to end of the insn. */ + env->pc += 4; + + cs->exception_index = EXCP_CHK; + cpu_loop_exit(cs); + } +} diff --git a/qemu/target/m68k/translate.c b/qemu/target/m68k/translate.c index 72fe9753..ecafdcd7 100644 --- a/qemu/target/m68k/translate.c +++ b/qemu/target/m68k/translate.c @@ -4369,6 +4369,82 @@ DISAS_INSN(ff1) gen_helper_ff1(tcg_ctx, reg, reg); } +DISAS_INSN(chk) +{ + TCGContext *tcg_ctx = s->uc->tcg_ctx; + TCGv src, reg; + int opsize; + + switch ((insn >> 7) & 3) { + case 3: + opsize = OS_WORD; + break; + case 2: + if (m68k_feature(env, M68K_FEATURE_CHK2)) { + opsize = OS_LONG; + break; + } + /* fallthru */ + default: + gen_exception(s, s->insn_pc, EXCP_ILLEGAL); + return; + } + SRC_EA(env, src, opsize, 1, NULL); + reg = gen_extend(s, DREG(insn, 9), opsize, 1); + + gen_flush_flags(s); + gen_helper_chk(tcg_ctx, tcg_ctx->cpu_env, reg, src); +} + +DISAS_INSN(chk2) +{ + TCGContext *tcg_ctx = s->uc->tcg_ctx; + uint16_t ext; + TCGv addr1, addr2, bound1, bound2, reg; + int opsize; + + switch ((insn >> 9) & 3) { + case 0: + opsize = OS_BYTE; + break; + case 1: + opsize = OS_WORD; + break; + case 2: + opsize = OS_LONG; + break; + default: + gen_exception(s, s->insn_pc, EXCP_ILLEGAL); + return; + } + + ext = read_im16(env, s); + if ((ext & 0x0800) == 0) { + gen_exception(s, s->insn_pc, EXCP_ILLEGAL); + return; + } + + addr1 = gen_lea(env, s, insn, OS_UNSIZED); + addr2 = tcg_temp_new(tcg_ctx); + tcg_gen_addi_i32(tcg_ctx, addr2, addr1, opsize_bytes(opsize)); + + bound1 = gen_load(s, opsize, addr1, 1); + tcg_temp_free(tcg_ctx, addr1); + bound2 = gen_load(s, opsize, addr2, 1); + tcg_temp_free(tcg_ctx, addr2); + + reg = tcg_temp_new(tcg_ctx); + if (ext & 0x8000) { + tcg_gen_mov_i32(tcg_ctx, reg, AREG(ext, 12)); + } else { + gen_ext(s, reg, DREG(ext, 12), opsize, 1); + } + + gen_flush_flags(s); + gen_helper_chk2(tcg_ctx, tcg_ctx->cpu_env, reg, bound1, bound2); + tcg_temp_free(tcg_ctx, reg); +} + static TCGv gen_get_sr(DisasContext *s) { TCGContext *tcg_ctx = s->uc->tcg_ctx; @@ -5508,7 +5584,7 @@ void register_m68k_insns (CPUM68KState *env) BASE(undef, 0000, 0000); INSN(arith_im, 0080, fff8, CF_ISA_A); INSN(arith_im, 0000, ff00, M68000); - INSN(undef, 00c0, ffc0, M68000); + INSN(chk2, 00c0, f9c0, CHK2); INSN(bitrev, 00c0, fff8, CF_ISA_APLUSC); BASE(bitop_reg, 0100, f1c0); BASE(bitop_reg, 0140, f1c0); @@ -5541,6 +5617,7 @@ void register_m68k_insns (CPUM68KState *env) BASE(move, 1000, f000); BASE(move, 2000, f000); BASE(move, 3000, f000); + INSN(chk, 4000, f040, M68000); INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC); INSN(negx, 4080, fff8, CF_ISA_A); INSN(negx, 4000, ff00, M68000);