qemu-devel
[Top][All Lists]
Advanced

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

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


From: Pavel Dovgaluk
Subject: [Qemu-devel] [RFC PATCH 22/22] Target i386 specific code
Date: Tue, 1 Jul 2014 15:34:49 +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.

These patches also add calls to update_fp_status() function from several
places where FPU state is changed. It is needed to eliminate some sources
of non-determinism.

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

diff --git a/target-i386/Makefile.objs b/target-i386/Makefile.objs
index 027b94e..657293c 100644
--- a/target-i386/Makefile.objs
+++ b/target-i386/Makefile.objs
@@ -1,4 +1,4 @@
-obj-y += translate.o helper.o cpu.o
+obj-y += translate.o helper.o cpu.o replay_helper.o
 obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o
 obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o
 obj-y += gdbstub.o
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 45c662d..27269ad
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -2573,6 +2573,7 @@ static void x86_cpu_reset(CPUState *s)
         env->fptags[i] = 1;
     }
     env->fpuc = 0x37f;
+    update_fp_status(env);
 
     env->mxcsr = 0x1f80;
     env->xstate_bv = XSTATE_FP | XSTATE_SSE;
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index e634d83..99f01fb
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -28,6 +28,13 @@
 #define TARGET_LONG_BITS 32
 #endif
 
+/* Maximum instruction code size */
+#ifdef TARGET_X86_64
+#define TARGET_MAX_INSN_SIZE 16
+#else
+#define TARGET_MAX_INSN_SIZE 16
+#endif
+
 /* target supports implicit self modifying code */
 #define TARGET_HAS_SMC
 /* support for self modifying code even if the modified instruction is
@@ -1250,6 +1257,8 @@ void QEMU_NORETURN raise_interrupt(CPUX86State *nenv, int 
intno, int is_int,
 extern const uint8_t parity_table[256];
 uint32_t cpu_cc_compute_all(CPUX86State *env1, int op);
 
+void update_fp_status(CPUX86State *env);
+
 static inline uint32_t cpu_compute_eflags(CPUX86State *env)
 {
     return env->eflags | cpu_cc_compute_all(env, CC_OP) | (env->df & DF_MASK);
@@ -1297,6 +1306,7 @@ void do_smm_enter(X86CPU *cpu);
 
 void cpu_report_tpr_access(CPUX86State *env, TPRAccess access);
 
+uint16_t compute_fptag(CPUX86State *env);
 void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
                                  uint32_t feat_add, uint32_t feat_remove);
 
diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c
index 1b2900d..552ffaf 100644
--- a/target-i386/fpu_helper.c
+++ b/target-i386/fpu_helper.c
@@ -537,7 +537,7 @@ uint32_t helper_fnstcw(CPUX86State *env)
     return env->fpuc;
 }
 
-static void update_fp_status(CPUX86State *env)
+void update_fp_status(CPUX86State *env)
 {
     int rnd_type;
 
@@ -961,13 +961,14 @@ void helper_fxam_ST0(CPUX86State *env)
     }
 }
 
-void helper_fstenv(CPUX86State *env, target_ulong ptr, int data32)
+
+uint16_t compute_fptag(CPUX86State *env)
 {
-    int fpus, fptag, exp, i;
+    uint16_t fptag;
+    int exp, i;
     uint64_t mant;
     CPU_LDoubleU tmp;
 
-    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
     fptag = 0;
     for (i = 7; i >= 0; i--) {
         fptag <<= 2;
@@ -987,15 +988,26 @@ void helper_fstenv(CPUX86State *env, target_ulong ptr, 
int data32)
             }
         }
     }
+
+    return fptag;
+}
+
+void helper_fstenv(CPUX86State *env, target_ulong ptr, int data32)
+{
+    int fpus, fptag;
+    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
+    fptag = compute_fptag(env);
     if (data32) {
         /* 32 bit */
-        cpu_stl_data(env, ptr, env->fpuc);
-        cpu_stl_data(env, ptr + 4, fpus);
-        cpu_stl_data(env, ptr + 8, fptag);
+        // We use 0xffff0000 mask, because real processor fill unused part
+        // of memory in the operation by 1s.
+        cpu_stl_data(env, ptr, env->fpuc | 0xffff0000);
+        cpu_stl_data(env, ptr + 4, fpus | 0xffff0000);
+        cpu_stl_data(env, ptr + 8, fptag | 0xffff0000);
         cpu_stl_data(env, ptr + 12, 0); /* fpip */
         cpu_stl_data(env, ptr + 16, 0); /* fpcs */
         cpu_stl_data(env, ptr + 20, 0); /* fpoo */
-        cpu_stl_data(env, ptr + 24, 0); /* fpos */
+        cpu_stl_data(env, ptr + 24, 0 | 0xffff0000); /* fpos */
     } else {
         /* 16 bit */
         cpu_stw_data(env, ptr, env->fpuc);
@@ -1027,6 +1039,7 @@ void helper_fldenv(CPUX86State *env, target_ulong ptr, 
int data32)
         env->fptags[i] = ((fptag & 3) == 3);
         fptag >>= 2;
     }
+    update_fp_status(env);
 }
 
 void helper_fsave(CPUX86State *env, target_ulong ptr, int data32)
@@ -1055,6 +1068,7 @@ void helper_fsave(CPUX86State *env, target_ulong ptr, int 
data32)
     env->fptags[5] = 1;
     env->fptags[6] = 1;
     env->fptags[7] = 1;
+    update_fp_status(env);
 }
 
 void helper_frstor(CPUX86State *env, target_ulong ptr, int data32)
@@ -1158,6 +1172,7 @@ void helper_fxrstor(CPUX86State *env, target_ulong ptr, 
int data64)
     }
 
     env->fpuc = cpu_lduw_data(env, ptr);
+    update_fp_status(env);
     fpus = cpu_lduw_data(env, ptr + 2);
     fptag = cpu_lduw_data(env, ptr + 4);
     env->fpstt = (fpus >> 11) & 7;
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 11ca864..c00747f 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -24,6 +24,8 @@
 #include "sysemu/sysemu.h"
 #include "monitor/monitor.h"
 #endif
+#include "qemu/log.h"
+#include "replay/replay.h"
 
 //#define DEBUG_MMU
 
diff --git a/target-i386/helper.h b/target-i386/helper.h
index 8eb0145..6d01528
--- a/target-i386/helper.h
+++ b/target-i386/helper.h
@@ -217,3 +217,11 @@ DEF_HELPER_3(rcrl, tl, env, tl, tl)
 DEF_HELPER_3(rclq, tl, env, tl, tl)
 DEF_HELPER_3(rcrq, tl, env, tl, tl)
 #endif
+
+DEF_HELPER_0(reverse_breakpoint, void)
+DEF_HELPER_1(replay_instruction, i32, env)
+DEF_HELPER_0(instruction_changed, void)
+DEF_HELPER_1(assert_eip, void, env)
+DEF_HELPER_1(assert_cpu, void, env)
+DEF_HELPER_1(assert_xmm, void, env)
+
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 16d2f6a..8170655
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -322,6 +322,7 @@ static int cpu_post_load(void *opaque, int version_id)
     for(i = 0; i < 8; i++) {
         env->fptags[i] = (env->fptag_vmstate >> i) & 1;
     }
+    update_fp_status(env);
 
     cpu_breakpoint_remove_all(cs, BP_CPU);
     cpu_watchpoint_remove_all(cs, BP_CPU);
@@ -702,6 +703,10 @@ VMStateDescription vmstate_x86_cpu = {
         VMSTATE_UINT64_V(env.xcr0, X86CPU, 12),
         VMSTATE_UINT64_V(env.xstate_bv, X86CPU, 12),
         VMSTATE_YMMH_REGS_VARS(env.ymmh_regs, X86CPU, CPU_NB_REGS, 12),
+        /* Fields required by replay */
+        VMSTATE_UINT32(parent_obj.interrupt_request, X86CPU),
+        VMSTATE_INT32(parent_obj.exit_request, X86CPU),
+        VMSTATE_INT32(parent_obj.exception_index, X86CPU),
         VMSTATE_END_OF_LIST()
         /* The above list is not sorted /wrt version numbers, watch out! */
     },
diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c
index 4aaf1e4..46fc86d
--- a/target-i386/misc_helper.c
+++ b/target-i386/misc_helper.c
@@ -21,6 +21,7 @@
 #include "exec/ioport.h"
 #include "exec/helper-proto.h"
 #include "exec/cpu_ldst.h"
+#include "replay/replay.h"
 
 void helper_outb(uint32_t port, uint32_t data)
 {
@@ -29,7 +30,9 @@ void helper_outb(uint32_t port, uint32_t data)
 
 target_ulong helper_inb(uint32_t port)
 {
-    return cpu_inb(port);
+    target_ulong ret = cpu_inb(port);
+    //REPLAY_ASSERT_M(ret, "inb");
+    return ret;
 }
 
 void helper_outw(uint32_t port, uint32_t data)
@@ -39,7 +42,9 @@ void helper_outw(uint32_t port, uint32_t data)
 
 target_ulong helper_inw(uint32_t port)
 {
-    return cpu_inw(port);
+    target_ulong ret = cpu_inw(port);
+    //REPLAY_ASSERT_M(ret, "inw");
+    return ret;
 }
 
 void helper_outl(uint32_t port, uint32_t data)
@@ -49,7 +54,9 @@ void helper_outl(uint32_t port, uint32_t data)
 
 target_ulong helper_inl(uint32_t port)
 {
-    return cpu_inl(port);
+    target_ulong ret = cpu_inl(port);
+    //REPLAY_ASSERT_M(ret, "inl");
+    return ret;
 }
 
 void helper_into(CPUX86State *env, int next_eip_addend)
diff --git a/target-i386/replay_helper.c b/target-i386/replay_helper.c
new file mode 100644
index 0000000..96e6e44
--- /dev/null
+++ b/target-i386/replay_helper.c
@@ -0,0 +1,81 @@
+#include "cpu.h"
+#include "exec/helper-proto.h"
+#include "replay/replay.h"
+
+void helper_reverse_breakpoint(void)
+{
+    replay_reverse_breakpoint();
+}
+
+uint32_t helper_replay_instruction(CPUX86State *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_instruction_changed(void)
+{
+    replay_instruction(0);
+}
+
+void helper_assert_eip(CPUX86State *env)
+{
+    REPLAY_ASSERT_M(env->eip, "EIP");
+}
+
+void helper_assert_cpu(CPUX86State *env)
+{
+    //int i;
+    //REPLAY_ASSERT_M(env->regs[0], "EAX");
+    //REPLAY_ASSERT_M(env->regs[1], "ECX");
+    //REPLAY_ASSERT_M(env->regs[2], "EDX");
+    //REPLAY_ASSERT_M(env->regs[3], "EBX");
+    //REPLAY_ASSERT_M(env->regs[4], "ESP");
+    //REPLAY_ASSERT_M(env->regs[5], "EBP");
+    //REPLAY_ASSERT_M(env->regs[6], "ESI");
+    REPLAY_ASSERT_M(env->regs[7], "EDI");
+    /*
+    REPLAY_ASSERT_M(env->fpstt, "FPSTT");
+    REPLAY_ASSERT_M(env->fpus, "FPUS");
+    REPLAY_ASSERT_M(env->fpuc, "FPUC");
+    char fpname[] = "FPREG0";
+    for (i = 0 ; i < 8 ; ++i) {
+        if (!env->fptags[i]) {
+            fpname[sizeof(fpname) - 2] = '0' + i;
+            REPLAY_ASSERT_M(env->fpregs[i].mmx.q, fpname);
+        }
+    }
+    */
+    /*char xmmname[] = "XMM0";
+    for (i = 0 ; i < CPU_NB_REGS ; ++i) {
+        xmmname[sizeof(xmmname) - 2] = '0' + i;
+        REPLAY_ASSERT_M(env->xmm_regs[i]._q[0], xmmname);
+        REPLAY_ASSERT_M(env->xmm_regs[i]._q[1], xmmname);
+    }*/
+
+    //REPLAY_ASSERT_M(env->fp_status.floatx80_rounding_precision, 
"floatx80_rounding_precision");
+}
+
+void helper_assert_xmm(CPUX86State *env)
+{
+    int i;
+    char xmmname[] = "XMM0";
+    for (i = 0 ; i < CPU_NB_REGS ; ++i) {
+        xmmname[sizeof(xmmname) - 2] = '0' + i;
+        REPLAY_ASSERT_M(env->xmm_regs[i]._q[0], xmmname);
+        REPLAY_ASSERT_M(env->xmm_regs[i]._q[1], xmmname);
+    }
+}
diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
index 2d970d0..46bbd01
--- a/target-i386/seg_helper.c
+++ b/target-i386/seg_helper.c
@@ -1208,6 +1208,7 @@ static void do_interrupt_all(X86CPU *cpu, int intno, int 
is_int,
             count++;
         }
     }
+
     if (env->cr[0] & CR0_PE_MASK) {
 #if !defined(CONFIG_USER_ONLY)
         if (env->hflags & HF_SVMI_MASK) {
diff --git a/target-i386/shift_helper_template.h 
b/target-i386/shift_helper_template.h
index cf91a2d..648a83a 100644
--- a/target-i386/shift_helper_template.h
+++ b/target-i386/shift_helper_template.h
@@ -63,9 +63,12 @@ target_ulong glue(helper_rcl, SUFFIX)(CPUX86State *env, 
target_ulong t0,
             res |= t0 >> (DATA_BITS + 1 - count);
         }
         t0 = res;
-        env->cc_src = (eflags & ~(CC_C | CC_O)) |
-            (lshift(src ^ t0, 11 - (DATA_BITS - 1)) & CC_O) |
+        env->cc_src = (eflags & ~CC_C) |
             ((src >> (DATA_BITS - count)) & CC_C);
+        if (count == 1) {
+            env->cc_src = (env->cc_src & ~CC_O) |
+                (lshift(src ^ t0, 11 - (DATA_BITS - 1)) & CC_O);
+        }   
     }
     return t0;
 }
@@ -93,9 +96,12 @@ target_ulong glue(helper_rcr, SUFFIX)(CPUX86State *env, 
target_ulong t0,
             res |= t0 << (DATA_BITS + 1 - count);
         }
         t0 = res;
-        env->cc_src = (eflags & ~(CC_C | CC_O)) |
-            (lshift(src ^ t0, 11 - (DATA_BITS - 1)) & CC_O) |
+        env->cc_src = (eflags & ~CC_C) |
             ((src >> (count - 1)) & CC_C);
+        if (count == 1) {
+            env->cc_src = (env->cc_src & ~CC_O) | 
+                (lshift(src ^ t0, 11 - (DATA_BITS - 1)) & CC_O);
+        }
     }
     return t0;
 }
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 6fcd824..874b9a8
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -28,6 +28,8 @@
 #include "disas/disas.h"
 #include "tcg-op.h"
 #include "exec/cpu_ldst.h"
+#include "replay/replay.h"
+#include "qemu/log.h"
 
 #include "exec/helper-proto.h"
 #include "exec/helper-gen.h"
@@ -112,6 +114,7 @@ typedef struct DisasContext {
     int tf;     /* TF cpu flag */
     int singlestep_enabled; /* "hardware" single step enabled */
     int jmp_opt; /* use direct block chaining for direct jumps */
+    int repz_opt; /* optimize jumps within repz instructions */
     int mem_index; /* select memory access functions */
     uint64_t flags; /* all execution flags */
     struct TranslationBlock *tb;
@@ -1096,6 +1099,8 @@ static inline void gen_jcc1(DisasContext *s, int b, int 
l1)
 {
     CCPrepare cc = gen_prepare_cc(s, b, cpu_T[0]);
 
+    //gen_helper_assert_cpu(cpu_env);
+    
     gen_update_cc_op(s);
     if (cc.mask != -1) {
         tcg_gen_andi_tl(cpu_T[0], cc.reg, cc.mask);
@@ -1212,7 +1217,7 @@ static inline void gen_repz_ ## op(DisasContext *s, 
TCGMemOp ot,
\
     gen_op_add_reg_im(s->aflag, R_ECX, -1);                                   \
     /* a loop would cause two single step exceptions if ECX = 1               \
        before rep string_insn */                                              \
-    if (!s->jmp_opt)                                                          \
+    if (!s->repz_opt)                                                         \
         gen_op_jz_ecx(s->aflag, l2);                                          \
     gen_jmp(s, cur_eip);                                                      \
 }
@@ -1230,7 +1235,7 @@ static inline void gen_repz_ ## op(DisasContext *s, 
TCGMemOp ot,
\
     gen_op_add_reg_im(s->aflag, R_ECX, -1);                                   \
     gen_update_cc_op(s);                                                      \
     gen_jcc1(s, (JCC_Z << 1) | (nz ^ 1), l2);                                 \
-    if (!s->jmp_opt)                                                          \
+    if (!s->repz_opt)                                                         \
         gen_op_jz_ecx(s->aflag, l2);                                          \
     gen_jmp(s, cur_eip);                                                      \
 }
@@ -2532,10 +2537,14 @@ static void gen_interrupt(DisasContext *s, int intno,
 
 static void gen_debug(DisasContext *s, target_ulong cur_eip)
 {
-    gen_update_cc_op(s);
-    gen_jmp_im(cur_eip);
-    gen_helper_debug(cpu_env);
-    s->is_jmp = DISAS_TB_JUMP;
+    if (replay_get_play_submode() == REPLAY_PLAY_REVERSE) {
+        gen_helper_reverse_breakpoint();
+    } else {
+        gen_update_cc_op(s);
+        gen_jmp_im(cur_eip);
+        gen_helper_debug(cpu_env);
+        s->is_jmp = DISAS_TB_JUMP;
+    }
 }
 
 /* generate a generic end of block. Trace exception is also generated
@@ -2978,6 +2987,8 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
     SSEFunc_0_eppt sse_fn_eppt;
     TCGMemOp ot;
 
+    //gen_helper_assert_xmm(cpu_env);
+    
     b &= 0xff;
     if (s->prefix & PREFIX_DATA)
         b1 = 1;
@@ -7887,6 +7898,56 @@ void optimize_flags_init(void)
     }
 }
 
+
+static void gen_instr_exit(DisasContext *s, target_ulong pc_ptr, long tb)
+{
+    //gen_update_cc_op(s);
+    // Don't reset dirty flag
+    if (s->cc_op_dirty) {
+        tcg_gen_movi_i32(cpu_cc_op, s->cc_op);
+    }
+    gen_jmp_im(pc_ptr - s->cs_base);
+    // TODO: io_end never needed in reptrace mode?
+    //gen_io_end();
+    tcg_gen_exit_tb(tb);
+}
+
+
+static void gen_instr_replay(DisasContext *s, target_ulong pc_ptr)
+{
+    int l1 = gen_new_label();
+
+    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);
+}
+
+
+static void gen_instructions_count(void)
+{
+    tcg_gen_ld_i32(cpu_tmp2_i32, cpu_env, offsetof(CPUState, 
instructions_count) - ENV_OFFSET);
+    tcg_gen_addi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 1);
+    tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, offsetof(CPUState, 
instructions_count) - ENV_OFFSET);
+}
+
+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. */
@@ -7948,6 +8009,19 @@ static inline void gen_intermediate_code_internal(X86CPU 
*cpu,
                     || (flags & HF_SOFTMMU_MASK)
 #endif
                     );
+    dc->repz_opt = dc->jmp_opt
+                    /* Do not optimize repz jumps at all in replay mode, 
because
+                       rep movsS instructions are execured with different paths
+                       in repz_opt and !repz_opt modes. The first one was used
+                       always except single step mode. And this setting
+                       disables jumps optimization and control paths become
+                       equivalent in run and single step modes.
+                       Now there will be no jump optimization for repz in
+                       trace and replay modes and there will always be an
+                       additional step for ecx=0.
+                     */
+                    || replay_mode != REPLAY_NONE
+                    ;
 #if 0
     /* check addseg logic */
     if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32))
@@ -7977,7 +8051,14 @@ static inline void gen_intermediate_code_internal(X86CPU 
*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);
+    }
+    
     for(;;) {
         if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
             QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
@@ -8000,9 +8081,34 @@ static inline void gen_intermediate_code_internal(X86CPU 
*cpu,
             tcg_ctx.gen_opc_instr_start[lj] = 1;
             tcg_ctx.gen_opc_icount[lj] = num_insns;
         }
-        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
-            gen_io_start();
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)
+            && replay_mode == REPLAY_NONE) {
+             gen_io_start();
+        }
 
+        /* generate exit code, if interrupt is pending (env->interrupt_request 
is set) */
+        /* Generate exit code, if cpu_exit was called by previous command and 
env->exit_request is
set.
+           exit_request may be set by "out" instructions, that's why it is 
needed in SAVE and PLAY
modes.
+         */
+        /* generate instruction counter code for replay */
+        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 ((pc_ptr == pc_start || replay_mode == REPLAY_PLAY) 
+                && replay_get_play_submode() != REPLAY_PLAY_CHANGED) {
+                gen_instr_replay(dc, pc_ptr);
+            } else {
+                gen_instructions_count();
+                //gen_instr_replay_save();
+            }
+        }
+
+        /* Write CPU state to the trace.
+           Do it just before the execution, because some conditions
+           above can exit the TB.
+           Information for writing is taken from env variable.
+        */
         pc_ptr = disas_insn(env, dc, pc_ptr);
         num_insns++;
         /* stop translation if indicated */
@@ -8013,6 +8119,7 @@ static inline void gen_intermediate_code_internal(X86CPU 
*cpu,
         /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
            the flag and abort the translation to give the irqs a
            change to be happen */
+        /* In trace mode we execute only one instruction in every block */
         if (dc->tf || dc->singlestep_enabled ||
             (flags & HF_INHIBIT_IRQ_MASK)) {
             gen_jmp_im(pc_ptr - dc->cs_base);
@@ -8027,15 +8134,31 @@ static inline void 
gen_intermediate_code_internal(X86CPU *cpu,
             gen_eob(dc);
             break;
         }
+        /* In replay mode do not cross the boundary of the pages,
+           it can cause an exception. Do it only when boundary is 
+           crossed by the first instruction in the block.
+           If current instruction already crossed the bound - it's ok,
+           because an exception hasn't stopped this code.
+         */
+        if (replay_mode != REPLAY_NONE
+            && ((pc_ptr & TARGET_PAGE_MASK) 
+                != ((pc_ptr + TARGET_MAX_INSN_SIZE - 1) & TARGET_PAGE_MASK)
+                || (pc_ptr & ~TARGET_PAGE_MASK) == 0)) {
+            gen_jmp_im(pc_ptr - dc->cs_base);
+            gen_eob(dc);
+            break;
+        }
         if (singlestep) {
             gen_jmp_im(pc_ptr - dc->cs_base);
             gen_eob(dc);
             break;
         }
     }
-    if (tb->cflags & CF_LAST_IO)
-        gen_io_end();
-    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;
     /* we don't forget to fill the last values */
     if (search_pc) {
@@ -8065,6 +8188,11 @@ static inline void gen_intermediate_code_internal(X86CPU 
*cpu,
         tb->size = pc_ptr - 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(CPUX86State *env, TranslationBlock *tb)




reply via email to

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