summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target/mips/translate.c47
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");