On 06/09/2016 12:03, James Hogan wrote: > 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. > > Signed-off-by: James Hogan <james.ho...@imgtec.com> > Cc: Leon Alrae <leon.al...@imgtec.com> > Cc: Aurelien Jarno <aurel...@aurel32.net> > --- > target-mips/cpu.h | 31 ++++++++++++++++- > target-mips/helper.h | 3 ++- > target-mips/machine.c | 7 ++-- > target-mips/op_helper.c | 24 ++++++++++++- > target-mips/translate.c | 84 ++++++++++++++++++++++++++++++++++++++++++- > 5 files changed, 147 insertions(+), 2 deletions(-) > > diff --git a/target-mips/cpu.h b/target-mips/cpu.h > index 2abb330272d9..fd8292eaa9c3 100644 > --- a/target-mips/cpu.h > +++ b/target-mips/cpu.h > @@ -306,6 +306,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))
Defining 16 as a macro would be preferable. > +#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; > @@ -449,6 +479,7 @@ struct CPUMIPSState { > #define CP0C3_MSAP 28 > #define CP0C3_BP 27 > #define CP0C3_BI 26 > +#define CP0C3_SC 25 > #define CP0C3_IPLW 21 > #define CP0C3_MMAR 18 > #define CP0C3_MCU 17 > diff --git a/target-mips/helper.h b/target-mips/helper.h > index 666936c81bfe..961741370ad2 100644 > --- a/target-mips/helper.h > +++ b/target-mips/helper.h > @@ -122,6 +122,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/target-mips/machine.c b/target-mips/machine.c > index e795fecaa0d6..d90f217c3fe5 100644 > --- a/target-mips/machine.c > +++ b/target-mips/machine.c > @@ -206,8 +206,8 @@ const VMStateDescription vmstate_tlb = { > > const VMStateDescription vmstate_mips_cpu = { > .name = "cpu", > - .version_id = 9, > - .minimum_version_id = 9, > + .version_id = 10, > + .minimum_version_id = 10, > .post_load = cpu_post_load, > .fields = (VMStateField[]) { > /* Active TC */ > @@ -247,6 +247,9 @@ const VMStateDescription vmstate_mips_cpu = { > VMSTATE_UINTTL(env.CP0_Context, MIPSCPU), > VMSTATE_INT32(env.CP0_PageMask, MIPSCPU), > VMSTATE_INT32(env.CP0_PageGrain, MIPSCPU), > + VMSTATE_UINTTL(env.CP0_SegCtl0, MIPSCPU), > + VMSTATE_UINTTL(env.CP0_SegCtl1, MIPSCPU), > + VMSTATE_UINTTL(env.CP0_SegCtl2, MIPSCPU), > VMSTATE_INT32(env.CP0_Wired, MIPSCPU), > VMSTATE_INT32(env.CP0_SRSConf0, MIPSCPU), > VMSTATE_INT32(env.CP0_SRSConf1, MIPSCPU), > diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c > index 829ab0bc3cca..983de785b318 100644 > --- a/target-mips/op_helper.c > +++ b/target-mips/op_helper.c > @@ -1337,6 +1337,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; Writes of unsupported values to the C field require to leave the field unmodified in the R6. Permit 2 (Uncached) only? > + tlb_flush(cs, 1); cpu_mips_tlb_flush()? > +} > + > +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, 1); > +} > + > +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, 1); > +} > + > void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1) > { > if (env->insn_flags & ISA_MIPS32R6) { > diff --git a/target-mips/translate.c b/target-mips/translate.c > index af17fc95eb8f..28d93bb56cd0 100644 > --- a/target-mips/translate.c > +++ b/target-mips/translate.c > @@ -1449,6 +1449,7 @@ typedef struct DisasContext { > uint64_t PAMask; > bool mvh; > bool eva; > + bool sc; > int CP0_LLAddr_shift; > bool ps; > bool vp; > @@ -5216,6 +5217,21 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int > reg, int sel) > gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageGrain)); > rn = "PageGrain"; > break; > + case 2: > + CP0_CHECK(ctx->sc); > + tcg_gen_ld32s_tl(arg, cpu_env, offsetof(CPUMIPSState, > CP0_SegCtl0)); This might cause problem in 64-bit guest with big-endian host. Replace it with tcg_gen_ld_tl() and tcg_gen_ext32s_tl(). > + rn = "SegCtl0"; > + break; > + case 3: > + CP0_CHECK(ctx->sc); > + tcg_gen_ld32s_tl(arg, cpu_env, offsetof(CPUMIPSState, > CP0_SegCtl1)); same as above > + rn = "SegCtl1"; > + break; > + case 4: > + CP0_CHECK(ctx->sc); > + tcg_gen_ld32s_tl(arg, cpu_env, offsetof(CPUMIPSState, > CP0_SegCtl2)); and here. > + rn = "SegCtl2"; > + break; > default: > goto cp0_unimplemented; > } > @@ -5872,6 +5888,21 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int > reg, int sel) > rn = "PageGrain"; > ctx->bstate = BS_STOP; > break; > + case 2: > + CP0_CHECK(ctx->sc); > + gen_helper_mtc0_segctl0(cpu_env, arg); > + rn = "SegCtl0"; > + break; > + case 3: > + CP0_CHECK(ctx->sc); > + gen_helper_mtc0_segctl1(cpu_env, arg); > + rn = "SegCtl1"; > + break; > + case 4: > + CP0_CHECK(ctx->sc); > + gen_helper_mtc0_segctl2(cpu_env, arg); > + rn = "SegCtl2"; > + break; > default: > goto cp0_unimplemented; > } > @@ -6534,6 +6565,20 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int > reg, int sel) > gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageGrain)); > rn = "PageGrain"; > break; > + case 2: > + CP0_CHECK(ctx->sc); > + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl0)); > + rn = "SegCtl0"; > + break; > + case 3: > + CP0_CHECK(ctx->sc); > + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl1)); > + rn = "SegCtl1"; > + break; > + case 4: > + CP0_CHECK(ctx->sc); > + tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl2)); > + rn = "SegCtl2"; > default: > goto cp0_unimplemented; > } > @@ -7172,6 +7217,21 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int > reg, int sel) > gen_helper_mtc0_pagegrain(cpu_env, arg); > rn = "PageGrain"; > break; > + case 2: > + CP0_CHECK(ctx->sc); > + gen_helper_mtc0_segctl0(cpu_env, arg); > + rn = "SegCtl0"; > + break; > + case 3: > + CP0_CHECK(ctx->sc); > + gen_helper_mtc0_segctl1(cpu_env, arg); > + rn = "SegCtl1"; > + break; > + case 4: > + CP0_CHECK(ctx->sc); > + gen_helper_mtc0_segctl2(cpu_env, arg); > + rn = "SegCtl2"; > + break; > default: > goto cp0_unimplemented; > } > @@ -19989,6 +20049,7 @@ void gen_intermediate_code(CPUMIPSState *env, 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. */ > @@ -20463,6 +20524,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); Reset value of C is Undefined in the spec? > + /* USeg (seg5 0x00000000..0x3FFFFFFF) */ > + env->CP0_SegCtl2 |= ((0 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) | > + (1 << CP0SC_EU) | (2 << CP0SC_C)) << 16; Same here > + /* XKPhys (note, SegCtl2.XR = 0, so XAM won't be used) */ > + env->CP0_SegCtl1 |= (CP0SC_AM_UK << CP0SC1_XAM); SegCtl1.XAM is undefined too? > #endif > if ((env->insn_flags & ISA_MIPS32R6) && > (env->active_fpu.fcr0 & (1 << FCR0_F64))) { > Regards, Yongbok