From a4c483454542c7369aa968013371ceb3d84d4385 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sun, 11 Feb 2018 16:20:45 -0500 Subject: [PATCH] target-mips: Fix CP0.Config3.ISAOnExc write accesses Fix CP0.Config3.ISAOnExc write accesses on microMIPS processors. This bit is mandatory for any processor that implements the microMIPS instruction set. This bit is r/w for processors that implement both the standard MIPS and the microMIPS instruction set. This bit is r/o and hardwired to 1 if only the microMIPS instruction set is implemented. There is no other bit ever writable in CP0.Config3 so defining a corresponding `CP0_Config3_rw_bitmask' member in `CPUMIPSState' is I think an overkill. Therefore make the ability to write the bit rely on the presence of ASE_MICROMIPS set in the instruction flags. The read-only case of the microMIPS instruction set being implemented only can be added when we add support for such a configuration. We do not currently have such support, we have no instruction flag that would control the presence of the standard MIPS instruction set nor any associated code in instruction decoding. This change is needed to boot a microMIPS Linux kernel successfully, otherwise it hangs early on as interrupts are enabled and then the exception handler invoked loops as its first instruction is interpreted in the wrong execution mode and triggers another exception right away. And then over and over again. We already check the current setting of the CP0.Config3.ISAOnExc in `set_hflags_for_handler' to set the ISA bit correctly on the exception handler entry so it is the ability to set it that is missing only. Backports commit 90f12d735d66ac1196d9a2bced039a432eefc03d from qemu --- qemu/header_gen.py | 1 + qemu/mips.h | 1 + qemu/mips64.h | 1 + qemu/mips64el.h | 1 + qemu/mipsel.h | 1 + qemu/target-mips/helper.h | 1 + qemu/target-mips/op_helper.c | 8 ++++++++ qemu/target-mips/translate.c | 8 ++++++-- 8 files changed, 20 insertions(+), 2 deletions(-) diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 087bace4..10532b56 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -3593,6 +3593,7 @@ mips_symbols = ( 'helper_mftc0_configx', 'helper_mtc0_config0', 'helper_mtc0_config2', + 'helper_mtc0_config3', 'helper_mtc0_config4', 'helper_mtc0_config5', 'helper_mtc0_lladdr', diff --git a/qemu/mips.h b/qemu/mips.h index db1921c1..ef77a2d0 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -3540,6 +3540,7 @@ #define helper_mftc0_configx helper_mftc0_configx_mips #define helper_mtc0_config0 helper_mtc0_config0_mips #define helper_mtc0_config2 helper_mtc0_config2_mips +#define helper_mtc0_config3 helper_mtc0_config3_mips #define helper_mtc0_config4 helper_mtc0_config4_mips #define helper_mtc0_config5 helper_mtc0_config5_mips #define helper_mtc0_lladdr helper_mtc0_lladdr_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index fcd563f7..8676be2e 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -3540,6 +3540,7 @@ #define helper_mftc0_configx helper_mftc0_configx_mips64 #define helper_mtc0_config0 helper_mtc0_config0_mips64 #define helper_mtc0_config2 helper_mtc0_config2_mips64 +#define helper_mtc0_config3 helper_mtc0_config3_mips64 #define helper_mtc0_config4 helper_mtc0_config4_mips64 #define helper_mtc0_config5 helper_mtc0_config5_mips64 #define helper_mtc0_lladdr helper_mtc0_lladdr_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index a999b8df..2ca995e9 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -3540,6 +3540,7 @@ #define helper_mftc0_configx helper_mftc0_configx_mips64el #define helper_mtc0_config0 helper_mtc0_config0_mips64el #define helper_mtc0_config2 helper_mtc0_config2_mips64el +#define helper_mtc0_config3 helper_mtc0_config3_mips64el #define helper_mtc0_config4 helper_mtc0_config4_mips64el #define helper_mtc0_config5 helper_mtc0_config5_mips64el #define helper_mtc0_lladdr helper_mtc0_lladdr_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 79d37508..6b3d29d0 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -3540,6 +3540,7 @@ #define helper_mftc0_configx helper_mftc0_configx_mipsel #define helper_mtc0_config0 helper_mtc0_config0_mipsel #define helper_mtc0_config2 helper_mtc0_config2_mipsel +#define helper_mtc0_config3 helper_mtc0_config3_mipsel #define helper_mtc0_config4 helper_mtc0_config4_mipsel #define helper_mtc0_config5 helper_mtc0_config5_mipsel #define helper_mtc0_lladdr helper_mtc0_lladdr_mipsel diff --git a/qemu/target-mips/helper.h b/qemu/target-mips/helper.h index 1924bf6f..e64339a6 100644 --- a/qemu/target-mips/helper.h +++ b/qemu/target-mips/helper.h @@ -139,6 +139,7 @@ DEF_HELPER_2(mtc0_ebase, void, env, tl) DEF_HELPER_2(mttc0_ebase, void, env, tl) DEF_HELPER_2(mtc0_config0, void, env, tl) DEF_HELPER_2(mtc0_config2, void, env, tl) +DEF_HELPER_2(mtc0_config3, void, env, tl) DEF_HELPER_2(mtc0_config4, void, env, tl) DEF_HELPER_2(mtc0_config5, void, env, tl) DEF_HELPER_2(mtc0_lladdr, void, env, tl) diff --git a/qemu/target-mips/op_helper.c b/qemu/target-mips/op_helper.c index e2b225f5..3499fc92 100644 --- a/qemu/target-mips/op_helper.c +++ b/qemu/target-mips/op_helper.c @@ -1502,6 +1502,14 @@ void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1) env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF); } +void helper_mtc0_config3(CPUMIPSState *env, target_ulong arg1) +{ + if (env->insn_flags & ASE_MICROMIPS) { + env->CP0_Config3 = (env->CP0_Config3 & ~(1 << CP0C3_ISA_ON_EXC)) | + (arg1 & (1 << CP0C3_ISA_ON_EXC)); + } +} + void helper_mtc0_config4(CPUMIPSState *env, target_ulong arg1) { env->CP0_Config4 = (env->CP0_Config4 & (~env->CP0_Config4_rw_bitmask)) | diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index 6996b142..a11f4f52 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -5912,8 +5912,10 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) ctx->bstate = BS_STOP; break; case 3: - /* ignored, read only */ + gen_helper_mtc0_config3(tcg_ctx, tcg_ctx->cpu_env, arg); rn = "Config3"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 4: gen_helper_mtc0_config4(tcg_ctx, tcg_ctx->cpu_env, arg); @@ -7165,8 +7167,10 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) ctx->bstate = BS_STOP; break; case 3: - /* ignored */ + gen_helper_mtc0_config3(tcg_ctx, tcg_ctx->cpu_env, arg); rn = "Config3"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 4: /* currently ignored */