From 62c688693bf2f0355fc5bad5dcc59c1cd2a51f1a Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Mon, 16 Mar 2015 16:54:42 +0000 Subject: [PATCH 1/3] target-mips: fix CP0.BadVAddr by stopping translation on Address Error CP0.BadVAddr is supposed to capture the most recent virtual address that caused the exception. Currently this does not work correctly for unaligned instruction fetch as translation is not stopped and CP0.BadVAddr is updated with subsequent addresses. Signed-off-by: Leon Alrae --- target-mips/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index 9059bfd9f1..0e2443a032 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -18438,6 +18438,7 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx) if (ctx->pc & 0x3) { env->CP0_BadVAddr = ctx->pc; generate_exception_err(ctx, EXCP_AdEL, EXCP_INST_NOTAVAIL); + ctx->bstate = BS_STOP; return; } From a5f533909e746ca6e534b232fb42c9c6fd81b468 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Thu, 29 Jan 2015 16:15:00 +0000 Subject: [PATCH 2/3] target-mips: fix hflags modified in delay / forbidden slot All instructions which may change hflags terminate tb. However, this doesn't work if such an instruction is placed in delay or forbidden slot. gen_branch() clears MIPS_HFLAG_BMASK in ctx->hflags and then generates code to overwrite hflags with ctx->hflags, consequently we loose any execution-time hflags modifications. For example, in the following scenario hflag related to Status.CU1 will not be updated: /* Set Status.CU1 in delay slot */ mfc0 $24, $12, 0 lui $25, 0x2000 or $25, $25, $24 b check_Status_CU1 mtc0 $25, $12, 0 With this change we clear MIPS_HFLAG_BMASK in execution-time hflags if instruction in delay or forbidden slot wants to terminate tb for some reason (i.e. ctx->bstate != BS_NONE). Also, die early and loudly if "unknown branch" is encountered as this should never happen. Signed-off-by: Leon Alrae --- target-mips/translate.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 0e2443a032..a91e5037f5 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -10531,14 +10531,25 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd) tcg_temp_free(t0); } +static inline void clear_branch_hflags(DisasContext *ctx) +{ + ctx->hflags &= ~MIPS_HFLAG_BMASK; + if (ctx->bstate == BS_NONE) { + save_cpu_state(ctx, 0); + } else { + /* it is not safe to save ctx->hflags as hflags may be changed + in execution time by the instruction in delay / forbidden slot. */ + tcg_gen_andi_i32(hflags, hflags, ~MIPS_HFLAG_BMASK); + } +} + static void gen_branch(DisasContext *ctx, int insn_bytes) { if (ctx->hflags & MIPS_HFLAG_BMASK) { int proc_hflags = ctx->hflags & MIPS_HFLAG_BMASK; /* Branches completion */ - ctx->hflags &= ~MIPS_HFLAG_BMASK; + clear_branch_hflags(ctx); ctx->bstate = BS_BRANCH; - save_cpu_state(ctx, 0); /* FIXME: Need to clear can_do_io. */ switch (proc_hflags & MIPS_HFLAG_BMASK_BASE) { case MIPS_HFLAG_FBNSLOT: @@ -10596,8 +10607,8 @@ static void gen_branch(DisasContext *ctx, int insn_bytes) tcg_gen_exit_tb(0); break; default: - MIPS_DEBUG("unknown branch"); - break; + fprintf(stderr, "unknown branch 0x%x\n", proc_hflags); + abort(); } } } From 0af7a37054310384e00209e0a43efe95b7c19ef0 Mon Sep 17 00:00:00 2001 From: Leon Alrae Date: Mon, 16 Mar 2015 16:29:34 +0000 Subject: [PATCH 3/3] target-mips: save cpu state before calling MSA load and store helpers PC needs to be saved if an exception can be generated by an helper. This fixes a problem related to resuming the execution at unexpected address after an exception (caused by MSA load/store instruction) has been serviced. Signed-off-by: Leon Alrae --- target-mips/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index a91e5037f5..fd063a2aae 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -18414,12 +18414,14 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) case OPC_LD_H: case OPC_LD_W: case OPC_LD_D: + save_cpu_state(ctx, 1); gen_helper_msa_ld_df(cpu_env, tdf, twd, trs, ts10); break; case OPC_ST_B: case OPC_ST_H: case OPC_ST_W: case OPC_ST_D: + save_cpu_state(ctx, 1); gen_helper_msa_st_df(cpu_env, tdf, twd, trs, ts10); break; }