From ddbea9422c39d088b9181ab4fb0dca1fd01795a8 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Sun, 4 Mar 2018 00:49:03 -0500 Subject: [PATCH] target/mips: Add segmentation control registers The optional segmentation control registers CP0_SegCtl0, CP0_SegCtl1 & CP0_SegCtl2 control the behaviour and required privilege of the legacy virtual memory segments. Add them to the CP0 interface so they can be read and written when CP0_Config3.SC=1, and initialise them to describe the standard legacy layout so they can be used in future patches regardless of whether they are exposed to the guest. Backports commit cec56a733dd2c3fa81dbedbecf03922258747f7d from qemu --- qemu/header_gen.py | 3 ++ qemu/mips.h | 3 ++ qemu/mips64.h | 3 ++ qemu/mips64el.h | 3 ++ qemu/mipsel.h | 3 ++ qemu/target/mips/cpu.h | 30 ++++++++++++ qemu/target/mips/helper.h | 3 ++ qemu/target/mips/op_helper.c | 24 ++++++++++ qemu/target/mips/translate.c | 90 +++++++++++++++++++++++++++++++++++- 9 files changed, 161 insertions(+), 1 deletion(-) diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 8c980227..fceed1c7 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -4138,6 +4138,9 @@ mips_symbols = ( 'helper_mtc0_pagegrain', 'helper_mtc0_pagemask', 'helper_mtc0_performance0', + 'helper_mtc0_segctl0', + 'helper_mtc0_segctl1', + 'helper_mtc0_segctl2', 'helper_mtc0_srsconf0', 'helper_mtc0_srsconf1', 'helper_mtc0_srsconf2', diff --git a/qemu/mips.h b/qemu/mips.h index e5cd1993..4c7eb3dc 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -4074,6 +4074,9 @@ #define helper_mtc0_pagegrain helper_mtc0_pagegrain_mips #define helper_mtc0_pagemask helper_mtc0_pagemask_mips #define helper_mtc0_performance0 helper_mtc0_performance0_mips +#define helper_mtc0_segctl0 helper_mtc0_segctl0_mips +#define helper_mtc0_segctl1 helper_mtc0_segctl1_mips +#define helper_mtc0_segctl2 helper_mtc0_segctl2_mips #define helper_mtc0_srsconf0 helper_mtc0_srsconf0_mips #define helper_mtc0_srsconf1 helper_mtc0_srsconf1_mips #define helper_mtc0_srsconf2 helper_mtc0_srsconf2_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index f8a33bd7..191aa5cf 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -4074,6 +4074,9 @@ #define helper_mtc0_pagegrain helper_mtc0_pagegrain_mips64 #define helper_mtc0_pagemask helper_mtc0_pagemask_mips64 #define helper_mtc0_performance0 helper_mtc0_performance0_mips64 +#define helper_mtc0_segctl0 helper_mtc0_segctl0_mips64 +#define helper_mtc0_segctl1 helper_mtc0_segctl1_mips64 +#define helper_mtc0_segctl2 helper_mtc0_segctl2_mips64 #define helper_mtc0_srsconf0 helper_mtc0_srsconf0_mips64 #define helper_mtc0_srsconf1 helper_mtc0_srsconf1_mips64 #define helper_mtc0_srsconf2 helper_mtc0_srsconf2_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index cd23bab3..56bed548 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -4074,6 +4074,9 @@ #define helper_mtc0_pagegrain helper_mtc0_pagegrain_mips64el #define helper_mtc0_pagemask helper_mtc0_pagemask_mips64el #define helper_mtc0_performance0 helper_mtc0_performance0_mips64el +#define helper_mtc0_segctl0 helper_mtc0_segctl0_mips64el +#define helper_mtc0_segctl1 helper_mtc0_segctl1_mips64el +#define helper_mtc0_segctl2 helper_mtc0_segctl2_mips64el #define helper_mtc0_srsconf0 helper_mtc0_srsconf0_mips64el #define helper_mtc0_srsconf1 helper_mtc0_srsconf1_mips64el #define helper_mtc0_srsconf2 helper_mtc0_srsconf2_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 51aa4c0b..2a0d8d79 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -4074,6 +4074,9 @@ #define helper_mtc0_pagegrain helper_mtc0_pagegrain_mipsel #define helper_mtc0_pagemask helper_mtc0_pagemask_mipsel #define helper_mtc0_performance0 helper_mtc0_performance0_mipsel +#define helper_mtc0_segctl0 helper_mtc0_segctl0_mipsel +#define helper_mtc0_segctl1 helper_mtc0_segctl1_mipsel +#define helper_mtc0_segctl2 helper_mtc0_segctl2_mipsel #define helper_mtc0_srsconf0 helper_mtc0_srsconf0_mipsel #define helper_mtc0_srsconf1 helper_mtc0_srsconf1_mipsel #define helper_mtc0_srsconf2 helper_mtc0_srsconf2_mipsel diff --git a/qemu/target/mips/cpu.h b/qemu/target/mips/cpu.h index 321d6b7d..a513dd0c 100644 --- a/qemu/target/mips/cpu.h +++ b/qemu/target/mips/cpu.h @@ -307,6 +307,36 @@ struct CPUMIPSState { #define CP0PG_XIE 30 #define CP0PG_ELPA 29 #define CP0PG_IEC 27 + target_ulong CP0_SegCtl0; + target_ulong CP0_SegCtl1; + target_ulong CP0_SegCtl2; +#define CP0SC_PA 9 +#define CP0SC_PA_MASK (0x7FULL << CP0SC_PA) +#define CP0SC_PA_1GMASK (0x7EULL << CP0SC_PA) +#define CP0SC_AM 4 +#define CP0SC_AM_MASK (0x7ULL << CP0SC_AM) +#define CP0SC_AM_UK 0ULL +#define CP0SC_AM_MK 1ULL +#define CP0SC_AM_MSK 2ULL +#define CP0SC_AM_MUSK 3ULL +#define CP0SC_AM_MUSUK 4ULL +#define CP0SC_AM_USK 5ULL +#define CP0SC_AM_UUSK 7ULL +#define CP0SC_EU 3 +#define CP0SC_EU_MASK (1ULL << CP0SC_EU) +#define CP0SC_C 0 +#define CP0SC_C_MASK (0x7ULL << CP0SC_C) +#define CP0SC_MASK (CP0SC_C_MASK | CP0SC_EU_MASK | CP0SC_AM_MASK | \ + CP0SC_PA_MASK) +#define CP0SC_1GMASK (CP0SC_C_MASK | CP0SC_EU_MASK | CP0SC_AM_MASK | \ + CP0SC_PA_1GMASK) +#define CP0SC0_MASK (CP0SC_MASK | (CP0SC_MASK << 16)) +#define CP0SC1_XAM 59 +#define CP0SC1_XAM_MASK (0x7ULL << CP0SC1_XAM) +#define CP0SC1_MASK (CP0SC_MASK | (CP0SC_MASK << 16) | CP0SC1_XAM_MASK) +#define CP0SC2_XR 56 +#define CP0SC2_XR_MASK (0xFFULL << CP0SC2_XR) +#define CP0SC2_MASK (CP0SC_1GMASK | (CP0SC_1GMASK << 16) | CP0SC2_XR_MASK) int32_t CP0_Wired; int32_t CP0_SRSConf0_rw_bitmask; int32_t CP0_SRSConf0; diff --git a/qemu/target/mips/helper.h b/qemu/target/mips/helper.h index df350d4c..69274c4a 100644 --- a/qemu/target/mips/helper.h +++ b/qemu/target/mips/helper.h @@ -115,6 +115,9 @@ DEF_HELPER_2(mtc0_entrylo1, void, env, tl) DEF_HELPER_2(mtc0_context, void, env, tl) DEF_HELPER_2(mtc0_pagemask, void, env, tl) DEF_HELPER_2(mtc0_pagegrain, void, env, tl) +DEF_HELPER_2(mtc0_segctl0, void, env, tl) +DEF_HELPER_2(mtc0_segctl1, void, env, tl) +DEF_HELPER_2(mtc0_segctl2, void, env, tl) DEF_HELPER_2(mtc0_wired, void, env, tl) DEF_HELPER_2(mtc0_srsconf0, void, env, tl) DEF_HELPER_2(mtc0_srsconf1, void, env, tl) diff --git a/qemu/target/mips/op_helper.c b/qemu/target/mips/op_helper.c index 904b591e..8d0fa7b2 100644 --- a/qemu/target/mips/op_helper.c +++ b/qemu/target/mips/op_helper.c @@ -1318,6 +1318,30 @@ void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) restore_pamask(env); } +void helper_mtc0_segctl0(CPUMIPSState *env, target_ulong arg1) +{ + CPUState *cs = CPU(mips_env_get_cpu(env)); + + env->CP0_SegCtl0 = arg1 & CP0SC0_MASK; + tlb_flush(cs); +} + +void helper_mtc0_segctl1(CPUMIPSState *env, target_ulong arg1) +{ + CPUState *cs = CPU(mips_env_get_cpu(env)); + + env->CP0_SegCtl1 = arg1 & CP0SC1_MASK; + tlb_flush(cs); +} + +void helper_mtc0_segctl2(CPUMIPSState *env, target_ulong arg1) +{ + CPUState *cs = CPU(mips_env_get_cpu(env)); + + env->CP0_SegCtl2 = arg1 & CP0SC2_MASK; + tlb_flush(cs); +} + void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1) { if (env->insn_flags & ISA_MIPS32R6) { diff --git a/qemu/target/mips/translate.c b/qemu/target/mips/translate.c index 47dd5352..9cb5c10f 100644 --- a/qemu/target/mips/translate.c +++ b/qemu/target/mips/translate.c @@ -1434,6 +1434,7 @@ typedef struct DisasContext { uint64_t PAMask; bool mvh; bool eva; + bool sc; int CP0_LLAddr_shift; bool ps; bool vp; @@ -5309,7 +5310,24 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(ctx, arg, offsetof(CPUMIPSState, CP0_PageGrain)); rn = "PageGrain"; - ctx->bstate = BS_STOP; + break; + case 2: + CP0_CHECK(ctx->sc); + tcg_gen_ld_tl(tcg_ctx, arg, tcg_ctx->cpu_env, offsetof(CPUMIPSState, CP0_SegCtl0)); + tcg_gen_ext32s_tl(tcg_ctx, arg, arg); + rn = "SegCtl0"; + break; + case 3: + CP0_CHECK(ctx->sc); + tcg_gen_ld_tl(tcg_ctx, arg, tcg_ctx->cpu_env, offsetof(CPUMIPSState, CP0_SegCtl1)); + tcg_gen_ext32s_tl(tcg_ctx, arg, arg); + rn = "SegCtl1"; + break; + case 4: + CP0_CHECK(ctx->sc); + tcg_gen_ld_tl(tcg_ctx, arg, tcg_ctx->cpu_env, offsetof(CPUMIPSState, CP0_SegCtl2)); + tcg_gen_ext32s_tl(tcg_ctx, arg, arg); + rn = "SegCtl2"; break; default: goto cp0_unimplemented; @@ -5965,6 +5983,22 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_pagegrain(tcg_ctx, tcg_ctx->cpu_env, arg); rn = "PageGrain"; + ctx->bstate = BS_STOP; + break; + case 2: + CP0_CHECK(ctx->sc); + gen_helper_mtc0_segctl0(tcg_ctx, tcg_ctx->cpu_env, arg); + rn = "SegCtl0"; + break; + case 3: + CP0_CHECK(ctx->sc); + gen_helper_mtc0_segctl1(tcg_ctx, tcg_ctx->cpu_env, arg); + rn = "SegCtl1"; + break; + case 4: + CP0_CHECK(ctx->sc); + gen_helper_mtc0_segctl2(tcg_ctx, tcg_ctx->cpu_env, arg); + rn = "SegCtl2"; break; default: goto cp0_unimplemented; @@ -6634,6 +6668,21 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_mfc0_load32(ctx, arg, offsetof(CPUMIPSState, CP0_PageGrain)); rn = "PageGrain"; break; + case 2: + CP0_CHECK(ctx->sc); + tcg_gen_ld_tl(tcg_ctx, arg, tcg_ctx->cpu_env, offsetof(CPUMIPSState, CP0_SegCtl0)); + rn = "SegCtl0"; + break; + case 3: + CP0_CHECK(ctx->sc); + tcg_gen_ld_tl(tcg_ctx, arg, tcg_ctx->cpu_env, offsetof(CPUMIPSState, CP0_SegCtl1)); + rn = "SegCtl1"; + break; + case 4: + CP0_CHECK(ctx->sc); + tcg_gen_ld_tl(tcg_ctx, arg, tcg_ctx->cpu_env, offsetof(CPUMIPSState, CP0_SegCtl2)); + rn = "SegCtl2"; + break; default: goto cp0_unimplemented; } @@ -7267,6 +7316,21 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_helper_mtc0_pagegrain(tcg_ctx, tcg_ctx->cpu_env, arg); rn = "PageGrain"; break; + case 2: + CP0_CHECK(ctx->sc); + gen_helper_mtc0_segctl0(tcg_ctx, tcg_ctx->cpu_env, arg); + rn = "SegCtl0"; + break; + case 3: + CP0_CHECK(ctx->sc); + gen_helper_mtc0_segctl1(tcg_ctx, tcg_ctx->cpu_env, arg); + rn = "SegCtl1"; + break; + case 4: + CP0_CHECK(ctx->sc); + gen_helper_mtc0_segctl2(tcg_ctx, tcg_ctx->cpu_env, arg); + rn = "SegCtl2"; + break; default: goto cp0_unimplemented; } @@ -20322,6 +20386,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) ctx.PAMask = env->PAMask; ctx.mvh = (env->CP0_Config5 >> CP0C5_MVH) & 1; ctx.eva = (env->CP0_Config5 >> CP0C5_EVA) & 1; + ctx.sc = (env->CP0_Config3 >> CP0C3_SC) & 1; ctx.CP0_LLAddr_shift = env->CP0_LLAddr_shift; ctx.cmgcr = (env->CP0_Config3 >> CP0C3_CMGCR) & 1; /* Restore delay slot state from the tb context. */ @@ -20813,6 +20878,29 @@ void cpu_state_reset(CPUMIPSState *env) env->tcs[0].CP0_TCStatus = (1 << CP0TCSt_A); } } + + /* + * Configure default legacy segmentation control. We use this regardless of + * whether segmentation control is presented to the guest. + */ + /* KSeg3 (seg0 0xE0000000..0xFFFFFFFF) */ + env->CP0_SegCtl0 = (CP0SC_AM_MK << CP0SC_AM); + /* KSeg2 (seg1 0xC0000000..0xDFFFFFFF) */ + env->CP0_SegCtl0 |= ((CP0SC_AM_MSK << CP0SC_AM)) << 16; + /* KSeg1 (seg2 0xA0000000..0x9FFFFFFF) */ + env->CP0_SegCtl1 = (0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) | + (2 << CP0SC_C); + /* KSeg0 (seg3 0x80000000..0x9FFFFFFF) */ + env->CP0_SegCtl1 |= ((0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) | + (3 << CP0SC_C)) << 16; + /* USeg (seg4 0x40000000..0x7FFFFFFF) */ + env->CP0_SegCtl2 = (2 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) | + (1 << CP0SC_EU) | (2 << CP0SC_C); + /* USeg (seg5 0x00000000..0x3FFFFFFF) */ + env->CP0_SegCtl2 |= ((0 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) | + (1 << CP0SC_EU) | (2 << CP0SC_C)) << 16; + /* XKPhys (note, SegCtl2.XR = 0, so XAM won't be used) */ + env->CP0_SegCtl1 |= (CP0SC_AM_UK << CP0SC1_XAM); #endif if ((env->insn_flags & ISA_MIPS32R6) && (env->active_fpu.fcr0 & (1 << FCR0_F64))) {