qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC PATCH 21/22] Target ARM specific code


From: Pavel Dovgaluk
Subject: [Qemu-devel] [RFC PATCH 21/22] Target ARM specific code
Date: Tue, 1 Jul 2014 15:34:01 +0400

Platform-specific chanches to i386 simulation for deterministic replay
and reverse debugging.

We insert instruction-counting code before executing every instruction.
In replay mode this code also breaks execution of TB, when any of the events
are found in the replay log.

Signed-off-by: Pavel Dovgalyuk <address@hidden>
---

diff --git a/target-arm/helper.h b/target-arm/helper.h
index facfcd2..3f7a4f5
--- a/target-arm/helper.h
+++ b/target-arm/helper.h
@@ -1,3 +1,4 @@
+DEF_HELPER_1(assert_cpu, void, env)
 DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i32, i32)
 DEF_HELPER_FLAGS_1(sxtb16, TCG_CALL_NO_RWG_SE, i32, i32)
 DEF_HELPER_FLAGS_1(uxtb16, TCG_CALL_NO_RWG_SE, i32, i32)
@@ -506,6 +507,9 @@ DEF_HELPER_3(neon_zip16, void, env, i32, i32)
 DEF_HELPER_3(neon_qzip8, void, env, i32, i32)
 DEF_HELPER_3(neon_qzip16, void, env, i32, i32)
 DEF_HELPER_3(neon_qzip32, void, env, i32, i32)
+DEF_HELPER_1(replay_instruction, i32, env)
+DEF_HELPER_0(instruction_changed, void)
+DEF_HELPER_0(reverse_breakpoint, void)
 
 DEF_HELPER_4(crypto_aese, void, env, i32, i32, i32)
 DEF_HELPER_4(crypto_aesmc, void, env, i32, i32, i32)
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 3bcc7cc..18b4dd5 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -259,6 +259,10 @@ const VMStateDescription vmstate_arm_cpu = {
         VMSTATE_UINT64(env.exception.vaddress, ARMCPU),
         VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU),
         VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU),
+        /* Fields required by replay */
+        VMSTATE_UINT32(parent_obj.interrupt_request, ARMCPU),
+        VMSTATE_INT32(parent_obj.exit_request, ARMCPU),
+        VMSTATE_INT32(parent_obj.exception_index, ARMCPU),
         VMSTATE_END_OF_LIST()
     },
     .subsections = (VMStateSubsection[]) {
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 9c1ef52..3452e35 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -500,3 +500,58 @@ uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, 
uint32_t i)
         return ((uint32_t)x >> shift) | (x << (32 - shift));
     }
 }
+
+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_timer_request();
+    replay_instruction(timer);
+    return timer;
+}
+
+void helper_reverse_breakpoint(void)
+{
+    replay_reverse_breakpoint();
+}
+
+void helper_assert_cpu(CPUARMState *env)
+{
+    if (replay_get_current_step() > 16000000000)
+    {
+    //int i;
+    //REPLAY_ASSERT_M(env->regs[0], "r0");
+    //REPLAY_ASSERT_M(env->regs[1], "r1");
+    //REPLAY_ASSERT_M(env->regs[2], "r2");
+    //REPLAY_ASSERT_M(env->regs[3], "r3");
+    //REPLAY_ASSERT_M(env->regs[4], "r4");
+    //REPLAY_ASSERT_M(env->regs[5], "r5");
+    //REPLAY_ASSERT_M(env->regs[6], "r6");
+    //REPLAY_ASSERT_M(env->regs[7], "r7");
+    REPLAY_ASSERT_M(env->regs[8], "r8");
+    REPLAY_ASSERT_M(env->regs[9], "r9");
+    REPLAY_ASSERT_M(env->regs[10], "r10");
+    REPLAY_ASSERT_M(env->regs[11], "r11");
+    REPLAY_ASSERT_M(env->regs[12], "r12");
+    REPLAY_ASSERT_M(env->regs[13], "r13");
+    REPLAY_ASSERT_M(env->regs[14], "r14");
+    }
+    //REPLAY_ASSERT_M(env->regs[15], "r15");
+    //REPLAY_ASSERT_M(env->fp_status.floatx80_rounding_precision, 
"floatx80_rounding_precision");
+}
+
+void helper_instruction_changed(void)
+{
+    replay_instruction(0);
+}
+
diff --git a/target-arm/translate.c b/target-arm/translate.c
index cf4e767..4df38f7
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -35,6 +35,7 @@
 #include "exec/helper-proto.h"
 #include "exec/helper-gen.h"
 
+
 #define ENABLE_ARCH_4T    arm_feature(env, ARM_FEATURE_V4T)
 #define ENABLE_ARCH_5     arm_feature(env, ARM_FEATURE_V5)
 /* currently all emulated v5 cores are also v5TE, so don't bother */
@@ -509,6 +510,16 @@ static void shifter_out_im(TCGv_i32 var, int shift)
     }
 }
 
+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);
+}
+
+
 /* Shift by immediate.  Includes special handling for shift == 0.  */
 static inline void gen_arm_shift_im(TCGv_i32 var, int shiftop,
                                     int shift, int flags)
@@ -10858,6 +10869,24 @@ undef:
     gen_exception_insn(s, 2, EXCP_UDEF, syn_uncategorized());
 }
 
+static void gen_icount_step(DisasContext *s, target_ulong pc_ptr);
+static void gen_instr_replay(DisasContext *s, target_ulong pc_ptr);
+static void gen_instr_exit(DisasContext *s, target_ulong pc_ptr, long tb);
+
+static void gen_replay_run_tb_start(TranslationBlock *tb)
+{
+    TCGv_i32 flag = tcg_temp_new_i32();
+    int label = gen_new_label();
+
+    tcg_gen_ld_i32(flag, cpu_env,
+                   offsetof(CPUState, tcg_exit_req) - ENV_OFFSET);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, flag, 0, label);
+    tcg_temp_free_i32(flag);
+    tcg_gen_exit_tb((tcg_target_long)tb + TB_EXIT_REQUESTED);
+    gen_set_label(label);
+    gen_helper_instruction_changed();
+}
+
 /* 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. */
@@ -10928,7 +10957,15 @@ static inline void 
gen_intermediate_code_internal(ARMCPU *cpu,
     if (max_insns == 0)
         max_insns = CF_COUNT_MASK;
 
-    gen_tb_start();
+    if (replay_mode == REPLAY_NONE) {
+        gen_tb_start();
+    }
+
+    if (replay_mode == REPLAY_PLAY
+        && replay_get_play_submode() == REPLAY_PLAY_CHANGED) {
+        gen_replay_run_tb_start(tb);
+    }
+
 
     tcg_clear_temp_count();
 
@@ -11015,12 +11052,29 @@ 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 timer event 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)
+                && replay_get_play_submode() != REPLAY_PLAY_CHANGED) {
+                gen_instr_replay(dc, dc->pc);
+            } else {
+                gen_instructions_count();
+            }
+        }
+        
+        /* icount mode support */
+        if (replay_mode != REPLAY_NONE) {
+            gen_icount_step(dc, dc->pc);
+        }
+
 
         if (dc->thumb) {
             disas_thumb_insn(env, dc);
@@ -11054,7 +11108,8 @@ 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) {
@@ -11134,7 +11189,11 @@ static inline void 
gen_intermediate_code_internal(ARMCPU *cpu,
     }
 
 done_generating:
-    gen_tb_end(tb, num_insns);
+    if (replay_mode == REPLAY_NONE) {
+        if (tb->cflags & CF_LAST_IO)
+            gen_io_end();
+        gen_tb_end(tb, num_insns);
+    }
     *tcg_ctx.gen_opc_ptr = INDEX_op_end;
 
 #ifdef DEBUG_DISAS
@@ -11155,6 +11214,10 @@ done_generating:
         tb->size = dc->pc - pc_start;
         tb->icount = num_insns;
     }
+    if (tcg_ctx.gen_opc_ptr > tcg_ctx.gen_opc_buf + OPC_BUF_SIZE) {
+        fprintf(stderr, "TCG buffer overflow\n");
+        exit(1);
+    }
 }
 
 void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
@@ -11231,3 +11294,41 @@ void restore_state_to_opc(CPUARMState *env, 
TranslationBlock *tb, int
pc_pos)
         env->condexec_bits = gen_opc_condexec_bits[pc_pos];
     }
 }
+
+static void gen_instr_exit(DisasContext *s, target_ulong pc_ptr, long tb)
+{
+    gen_set_condexec(s);
+    gen_set_pc_im(s, pc_ptr);
+    tcg_gen_exit_tb(tb);
+}
+
+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_instr_exit(s, pc_ptr, 0);
+    gen_set_label(l1);
+    tcg_temp_free(cpu_tmp2_i32);
+}
+
+static void gen_icount_step(DisasContext *s, target_ulong pc_ptr)
+{
+    if (!use_icount)
+        return;
+
+    int l1 = gen_new_label();
+    TCGv_i32 cpu_tmp2_i32 = tcg_temp_new();
+    tcg_gen_ld_i32(cpu_tmp2_i32, cpu_env, offsetof(CPUState, icount_decr.u32) 
- ENV_OFFSET);
+    tcg_gen_brcondi_i32(TCG_COND_NE, cpu_tmp2_i32, 0, l1);
+
+    gen_instr_exit(s, pc_ptr, 2);
+
+    gen_set_label(l1);
+    tcg_gen_subi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 1);
+    tcg_gen_st16_i32(cpu_tmp2_i32, cpu_env, offsetof(CPUState, 
icount_decr.u16.low) - ENV_OFFSET);
+    tcg_temp_free(cpu_tmp2_i32);
+}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]