diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/mips/translate.c | 47 |
1 files changed, 34 insertions, 13 deletions
diff --git a/target/mips/translate.c b/target/mips/translate.c index 88f518b43c..ba6b8f567f 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -5334,8 +5334,10 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_io_end(); } /* Break the TB to be able to take timer interrupts immediately - after reading count. */ - ctx->bstate = BS_STOP; + after reading count. BS_STOP isn't sufficient, we need to ensure + we break completely out of translated code. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; rn = "Count"; break; /* 6,7 are implementation dependent */ @@ -6061,6 +6063,11 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 0: save_cpu_state(ctx, 1); gen_helper_mtc0_cause(cpu_env, arg); + /* Stop translation as we may have triggered an interrupt. BS_STOP + * isn't sufficient, we need to ensure we break out of translated + * code to check for pending interrupts. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; rn = "Cause"; break; default: @@ -6395,7 +6402,10 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) /* For simplicity assume that all writes can cause interrupts. */ if (ctx->tb->cflags & CF_USE_ICOUNT) { gen_io_end(); - ctx->bstate = BS_STOP; + /* BS_STOP isn't sufficient, we need to ensure we break out of + * translated code to check for pending interrupts. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; } return; @@ -6676,8 +6686,10 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_io_end(); } /* Break the TB to be able to take timer interrupts immediately - after reading count. */ - ctx->bstate = BS_STOP; + after reading count. BS_STOP isn't sufficient, we need to ensure + we break completely out of translated code. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; rn = "Count"; break; /* 6,7 are implementation dependent */ @@ -7398,8 +7410,11 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) if (ctx->tb->cflags & CF_USE_ICOUNT) { gen_io_end(); } - /* Stop translation as we may have triggered an intetrupt */ - ctx->bstate = BS_STOP; + /* Stop translation as we may have triggered an intetrupt. BS_STOP + * isn't sufficient, we need to ensure we break out of translated + * code to check for pending interrupts. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; rn = "Cause"; break; default: @@ -7721,7 +7736,10 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) /* For simplicity assume that all writes can cause interrupts. */ if (ctx->tb->cflags & CF_USE_ICOUNT) { gen_io_end(); - ctx->bstate = BS_STOP; + /* BS_STOP isn't sufficient, we need to ensure we break out of + * translated code to check for pending interrupts. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; } return; @@ -13565,8 +13583,10 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) save_cpu_state(ctx, 1); gen_helper_ei(t0, cpu_env); gen_store_gpr(t0, rs); - /* Stop translation as we may have switched the execution mode */ - ctx->bstate = BS_STOP; + /* BS_STOP isn't sufficient, we need to ensure we break out + of translated code to check for pending interrupts. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; tcg_temp_free(t0); } break; @@ -19688,9 +19708,10 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) save_cpu_state(ctx, 1); gen_helper_ei(t0, cpu_env); gen_store_gpr(t0, rt); - /* Stop translation as we may have switched - the execution mode. */ - ctx->bstate = BS_STOP; + /* BS_STOP isn't sufficient, we need to ensure we break out + of translated code to check for pending interrupts. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; break; default: /* Invalid */ MIPS_INVAL("mfmc0"); |