target-mips: implement UserLocal Register
From MIPS documentation (Volume III): UserLocal Register (CP0 Register 4, Select 2) Compliance Level: Recommended. The UserLocal register is a read-write register that is not interpreted by the hardware and conditionally readable via the RDHWR instruction. This register only exists if the Config3-ULRI register field is set. Privileged software may write this register with arbitrary information and make it accessible to unprivileged software via register 29 (ULR) of the RDHWR instruction. To do so, bit 29 of the HWREna register must be set to a 1 to enable unprivileged access to the register. Signed-off-by: Petar Jovanovic <petar.jovanovic@imgtec.com> Reviewed-by: Andreas Färber <afaerber@suse.de> Reviewed-by: Aurelien Jarno <aurelien@aurel32.net> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
parent
739b7a9075
commit
d279279e2b
@ -30,7 +30,7 @@ static inline void cpu_clone_regs(CPUMIPSState *env, target_ulong newsp)
|
||||
|
||||
static inline void cpu_set_tls(CPUMIPSState *env, target_ulong newtls)
|
||||
{
|
||||
env->tls_value = newtls;
|
||||
env->active_tc.CP0_UserLocal = newtls;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -8702,7 +8702,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
#ifdef TARGET_NR_set_thread_area
|
||||
case TARGET_NR_set_thread_area:
|
||||
#if defined(TARGET_MIPS)
|
||||
((CPUMIPSState *) cpu_env)->tls_value = arg1;
|
||||
((CPUMIPSState *) cpu_env)->active_tc.CP0_UserLocal = arg1;
|
||||
ret = 0;
|
||||
break;
|
||||
#elif defined(TARGET_CRIS)
|
||||
|
@ -168,6 +168,7 @@ struct TCState {
|
||||
target_ulong CP0_TCSchedule;
|
||||
target_ulong CP0_TCScheFBack;
|
||||
int32_t CP0_Debug_tcstatus;
|
||||
target_ulong CP0_UserLocal;
|
||||
};
|
||||
|
||||
typedef struct CPUMIPSState CPUMIPSState;
|
||||
@ -362,6 +363,7 @@ struct CPUMIPSState {
|
||||
int32_t CP0_Config3;
|
||||
#define CP0C3_M 31
|
||||
#define CP0C3_ISA_ON_EXC 16
|
||||
#define CP0C3_ULRI 13
|
||||
#define CP0C3_DSPP 10
|
||||
#define CP0C3_LPA 7
|
||||
#define CP0C3_VEIC 6
|
||||
@ -470,6 +472,8 @@ struct CPUMIPSState {
|
||||
/* MIPS DSP resources access. */
|
||||
#define MIPS_HFLAG_DSP 0x40000 /* Enable access to MIPS DSP resources. */
|
||||
#define MIPS_HFLAG_DSPR2 0x80000 /* Enable access to MIPS DSPR2 resources. */
|
||||
/* Extra flag about HWREna register. */
|
||||
#define MIPS_HFLAG_HWRENA_ULR 0x100000 /* ULR bit from HWREna is set. */
|
||||
target_ulong btarget; /* Jump / branch target */
|
||||
target_ulong bcond; /* Branch condition (if needed) */
|
||||
|
||||
@ -479,8 +483,6 @@ struct CPUMIPSState {
|
||||
uint32_t CP0_TCStatus_rw_bitmask; /* Read/write bits in CP0_TCStatus */
|
||||
int insn_flags; /* Supported instruction set */
|
||||
|
||||
target_ulong tls_value; /* For usermode emulation */
|
||||
|
||||
CPU_COMMON
|
||||
|
||||
/* Fields from here on are preserved across CPU reset. */
|
||||
@ -523,7 +525,7 @@ void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf);
|
||||
extern void cpu_wrdsp(uint32_t rs, uint32_t mask_num, CPUMIPSState *env);
|
||||
extern uint32_t cpu_rddsp(uint32_t mask_num, CPUMIPSState *env);
|
||||
|
||||
#define CPU_SAVE_VERSION 3
|
||||
#define CPU_SAVE_VERSION 4
|
||||
|
||||
/* MMU modes definitions. We carefully match the indices with our
|
||||
hflags layout. */
|
||||
@ -682,7 +684,8 @@ static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc,
|
||||
{
|
||||
*pc = env->active_tc.PC;
|
||||
*cs_base = 0;
|
||||
*flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
|
||||
*flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK |
|
||||
MIPS_HFLAG_HWRENA_ULR);
|
||||
}
|
||||
|
||||
static inline int mips_vpe_active(CPUMIPSState *env)
|
||||
|
@ -25,6 +25,7 @@ static void save_tc(QEMUFile *f, TCState *tc)
|
||||
qemu_put_betls(f, &tc->CP0_TCSchedule);
|
||||
qemu_put_betls(f, &tc->CP0_TCScheFBack);
|
||||
qemu_put_sbe32s(f, &tc->CP0_Debug_tcstatus);
|
||||
qemu_put_betls(f, &tc->CP0_UserLocal);
|
||||
}
|
||||
|
||||
static void save_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
|
||||
@ -151,7 +152,7 @@ void cpu_save(QEMUFile *f, void *opaque)
|
||||
save_fpu(f, &env->fpus[i]);
|
||||
}
|
||||
|
||||
static void load_tc(QEMUFile *f, TCState *tc)
|
||||
static void load_tc(QEMUFile *f, TCState *tc, int version_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -173,6 +174,9 @@ static void load_tc(QEMUFile *f, TCState *tc)
|
||||
qemu_get_betls(f, &tc->CP0_TCSchedule);
|
||||
qemu_get_betls(f, &tc->CP0_TCScheFBack);
|
||||
qemu_get_sbe32s(f, &tc->CP0_Debug_tcstatus);
|
||||
if (version_id >= 4) {
|
||||
qemu_get_betls(f, &tc->CP0_UserLocal);
|
||||
}
|
||||
}
|
||||
|
||||
static void load_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
|
||||
@ -194,11 +198,12 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
||||
MIPSCPU *cpu = mips_env_get_cpu(env);
|
||||
int i;
|
||||
|
||||
if (version_id != 3)
|
||||
if (version_id < 3) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Load active TC */
|
||||
load_tc(f, &env->active_tc);
|
||||
load_tc(f, &env->active_tc, version_id);
|
||||
|
||||
/* Load active FPU */
|
||||
load_fpu(f, &env->active_fpu);
|
||||
@ -298,8 +303,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
||||
qemu_get_sbe32s(f, &env->CP0_DESAVE);
|
||||
|
||||
/* Load inactive TC state */
|
||||
for (i = 0; i < MIPS_SHADOW_SET_MAX; i++)
|
||||
load_tc(f, &env->tcs[i]);
|
||||
for (i = 0; i < MIPS_SHADOW_SET_MAX; i++) {
|
||||
load_tc(f, &env->tcs[i], version_id);
|
||||
}
|
||||
for (i = 0; i < MIPS_FPU_MAX; i++)
|
||||
load_fpu(f, &env->fpus[i]);
|
||||
|
||||
|
@ -1297,7 +1297,19 @@ void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1)
|
||||
|
||||
void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
|
||||
{
|
||||
env->CP0_HWREna = arg1 & 0x0000000F;
|
||||
uint32_t mask = 0x0000000F;
|
||||
|
||||
if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
|
||||
mask |= (1 << 29);
|
||||
|
||||
if (arg1 & (1 << 29)) {
|
||||
env->hflags |= MIPS_HFLAG_HWRENA_ULR;
|
||||
} else {
|
||||
env->hflags &= ~MIPS_HFLAG_HWRENA_ULR;
|
||||
}
|
||||
}
|
||||
|
||||
env->CP0_HWREna = arg1 & mask;
|
||||
}
|
||||
|
||||
void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
|
||||
|
@ -1072,6 +1072,7 @@ typedef struct DisasContext {
|
||||
uint32_t hflags, saved_hflags;
|
||||
int bstate;
|
||||
target_ulong btarget;
|
||||
bool ulri;
|
||||
} DisasContext;
|
||||
|
||||
enum {
|
||||
@ -4215,7 +4216,18 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
|
||||
case 1:
|
||||
// gen_helper_mfc0_contextconfig(arg); /* SmartMIPS ASE */
|
||||
rn = "ContextConfig";
|
||||
goto die;
|
||||
// break;
|
||||
case 2:
|
||||
if (ctx->ulri) {
|
||||
tcg_gen_ld32s_tl(arg, cpu_env,
|
||||
offsetof(CPUMIPSState,
|
||||
active_tc.CP0_UserLocal));
|
||||
rn = "UserLocal";
|
||||
} else {
|
||||
tcg_gen_movi_tl(arg, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto die;
|
||||
}
|
||||
@ -4802,7 +4814,15 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
|
||||
case 1:
|
||||
// gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */
|
||||
rn = "ContextConfig";
|
||||
goto die;
|
||||
// break;
|
||||
case 2:
|
||||
if (ctx->ulri) {
|
||||
tcg_gen_st_tl(arg, cpu_env,
|
||||
offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
|
||||
rn = "UserLocal";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto die;
|
||||
}
|
||||
@ -4862,6 +4882,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
|
||||
case 0:
|
||||
check_insn(ctx, ISA_MIPS32R2);
|
||||
gen_helper_mtc0_hwrena(cpu_env, arg);
|
||||
ctx->bstate = BS_STOP;
|
||||
rn = "HWREna";
|
||||
break;
|
||||
default:
|
||||
@ -5406,7 +5427,17 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
|
||||
case 1:
|
||||
// gen_helper_dmfc0_contextconfig(arg); /* SmartMIPS ASE */
|
||||
rn = "ContextConfig";
|
||||
goto die;
|
||||
// break;
|
||||
case 2:
|
||||
if (ctx->ulri) {
|
||||
tcg_gen_ld_tl(arg, cpu_env,
|
||||
offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
|
||||
rn = "UserLocal";
|
||||
} else {
|
||||
tcg_gen_movi_tl(arg, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto die;
|
||||
}
|
||||
@ -5978,7 +6009,15 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
|
||||
case 1:
|
||||
// gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */
|
||||
rn = "ContextConfig";
|
||||
goto die;
|
||||
// break;
|
||||
case 2:
|
||||
if (ctx->ulri) {
|
||||
tcg_gen_st_tl(arg, cpu_env,
|
||||
offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
|
||||
rn = "UserLocal";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto die;
|
||||
}
|
||||
@ -6038,6 +6077,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
|
||||
case 0:
|
||||
check_insn(ctx, ISA_MIPS32R2);
|
||||
gen_helper_mtc0_hwrena(cpu_env, arg);
|
||||
ctx->bstate = BS_STOP;
|
||||
rn = "HWREna";
|
||||
break;
|
||||
default:
|
||||
@ -9060,12 +9100,20 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd)
|
||||
break;
|
||||
case 29:
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUMIPSState, tls_value));
|
||||
tcg_gen_ld_tl(t0, cpu_env,
|
||||
offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
|
||||
gen_store_gpr(t0, rt);
|
||||
break;
|
||||
#else
|
||||
/* XXX: Some CPUs implement this in hardware.
|
||||
Not supported yet. */
|
||||
if ((ctx->hflags & MIPS_HFLAG_CP0) ||
|
||||
(ctx->hflags & MIPS_HFLAG_HWRENA_ULR)) {
|
||||
tcg_gen_ld_tl(t0, cpu_env,
|
||||
offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
|
||||
gen_store_gpr(t0, rt);
|
||||
} else {
|
||||
generate_exception(ctx, EXCP_RI);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default: /* Invalid */
|
||||
MIPS_INVAL("rdhwr");
|
||||
@ -15609,6 +15657,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
|
||||
ctx.bstate = BS_NONE;
|
||||
/* Restore delay slot state from the tb context. */
|
||||
ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */
|
||||
ctx.ulri = env->CP0_Config3 & (1 << CP0C3_ULRI);
|
||||
restore_cpu_state(env, &ctx);
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
ctx.mem_idx = MIPS_HFLAG_UM;
|
||||
|
Loading…
Reference in New Issue
Block a user