This patch adds instructions counting into the target-specific part of arm simulator. In record/replay mode it inserts replay functions calls and instructions counter increment into the translated code.
Signed-off-by: Pavel Dovgalyuk <pavel.dovga...@ispras.ru> --- target-arm/Makefile.objs | 1 + target-arm/helper.h | 2 ++ target-arm/replay_helper.c | 33 ++++++++++++++++++++++++++++++ target-arm/translate.c | 48 +++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 81 insertions(+), 3 deletions(-) create mode 100755 target-arm/replay_helper.c diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs index dcd167e..b8f61df 100644 --- a/target-arm/Makefile.objs +++ b/target-arm/Makefile.objs @@ -9,3 +9,4 @@ obj-y += neon_helper.o iwmmxt_helper.o obj-y += gdbstub.o obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o obj-y += crypto_helper.o +obj-y += replay_helper.o diff --git a/target-arm/helper.h b/target-arm/helper.h index facfcd2..0233b64 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -529,3 +529,5 @@ DEF_HELPER_FLAGS_2(neon_pmull_64_hi, TCG_CALL_NO_RWG_SE, i64, i64, i64) #ifdef TARGET_AARCH64 #include "helper-a64.h" #endif + +DEF_HELPER_1(replay_instruction, i32, env) diff --git a/target-arm/replay_helper.c b/target-arm/replay_helper.c new file mode 100755 index 0000000..736cd51 --- /dev/null +++ b/target-arm/replay_helper.c @@ -0,0 +1,33 @@ +/* + * replay_helper.c + * + * Copyright (c) 2010-2014 Institute for System Programming + * of the Russian Academy of Sciences. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "cpu.h" +#include "exec/helper-proto.h" +#include "replay/replay.h" + +uint32_t helper_replay_instruction(CPUARMState *env) +{ + CPUState *cpu = ENV_GET_CPU(env); + if (replay_mode == REPLAY_PLAY + && !replay_has_instruction()) { + cpu->exception_index = EXCP_REPLAY; + return 1; + } + + if (cpu->exit_request) { + cpu->exception_index = EXCP_REPLAY; + return 1; + } + + int timer = replay_has_async_request(); + replay_instruction(timer); + return timer; +} diff --git a/target-arm/translate.c b/target-arm/translate.c index cf4e767..dd40998 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -31,6 +31,7 @@ #include "qemu/log.h" #include "qemu/bitops.h" #include "arm_ldst.h" +#include "replay/replay.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" @@ -10858,6 +10859,32 @@ undef: gen_exception_insn(s, 2, EXCP_UDEF, syn_uncategorized()); } +static void gen_instructions_count(void) +{ + TCGv_i32 cpu_tmp_i32 = tcg_temp_new(); + tcg_gen_ld_i32(cpu_tmp_i32, cpu_env, + offsetof(CPUState, instructions_count) - ENV_OFFSET); + tcg_gen_addi_i32(cpu_tmp_i32, cpu_tmp_i32, 1); + tcg_gen_st_i32(cpu_tmp_i32, cpu_env, + offsetof(CPUState, instructions_count) - ENV_OFFSET); + tcg_temp_free(cpu_tmp_i32); +} + +static void gen_instr_replay(DisasContext *s, target_ulong pc_ptr) +{ + int l1 = gen_new_label(); + TCGv_i32 cpu_tmp2_i32 = tcg_temp_new(); + + gen_helper_replay_instruction(cpu_tmp2_i32, cpu_env); + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_tmp2_i32, 0, l1); + + gen_set_condexec(s); + gen_set_pc_im(s, pc_ptr); + tcg_gen_exit_tb(0); + gen_set_label(l1); + tcg_temp_free(cpu_tmp2_i32); +} + /* generate intermediate code in gen_opc_buf and gen_opparam_buf for basic block 'tb'. If search_pc is TRUE, also generate PC information for each intermediate instruction. */ @@ -11015,13 +11042,27 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, tcg_ctx.gen_opc_icount[lj] = num_insns; } - if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO) + && replay_mode == REPLAY_NONE) { gen_io_start(); + } if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { tcg_gen_debug_insn_start(dc->pc); } + if (replay_mode != REPLAY_NONE) { + /* In PLAY mode check events at every instruction, not only at + the beginning of the block. This is needed, when replaying + has changed the bounds of translation blocks. + */ + if (dc->pc == pc_start || replay_mode == REPLAY_PLAY) { + gen_instr_replay(dc, dc->pc); + } else { + gen_instructions_count(); + } + } + if (dc->thumb) { disas_thumb_insn(env, dc); if (dc->condexec_mask) { @@ -11054,10 +11095,11 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end && !cs->singlestep_enabled && !singlestep && - dc->pc < next_page_start && + /* +3 is for unaligned Thumb2 instructions */ + dc->pc + 3 < next_page_start && num_insns < max_insns); - if (tb->cflags & CF_LAST_IO) { + if ((tb->cflags & CF_LAST_IO) && replay_mode == REPLAY_NONE) { if (dc->condjmp) { /* FIXME: This can theoretically happen with self-modifying code. */