target/openrisc: Allow fpcsr access in user mode
As per OpenRISC spec 1.4 FPCSR can be read and written in user mode. Update mtspr and mfspr helpers to support this by moving the is_user check into the helper. Link: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf Signed-off-by: Stafford Horne <shorne@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
c1eb2ddf0f
commit
08f021de3a
@ -29,17 +29,37 @@
|
|||||||
|
|
||||||
#define TO_SPR(group, number) (((group) << 11) + (number))
|
#define TO_SPR(group, number) (((group) << 11) + (number))
|
||||||
|
|
||||||
|
static inline bool is_user(CPUOpenRISCState *env)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return (env->sr & SR_SM) == 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb)
|
void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_USER_ONLY
|
|
||||||
OpenRISCCPU *cpu = env_archcpu(env);
|
OpenRISCCPU *cpu = env_archcpu(env);
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
CPUState *cs = env_cpu(env);
|
CPUState *cs = env_cpu(env);
|
||||||
target_ulong mr;
|
target_ulong mr;
|
||||||
int idx;
|
int idx;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Handle user accessible SPRs first. */
|
||||||
switch (spr) {
|
switch (spr) {
|
||||||
|
case TO_SPR(0, 20): /* FPCSR */
|
||||||
|
cpu_set_fpcsr(env, rb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_user(env)) {
|
||||||
|
raise_exception(cpu, EXCP_ILLEGAL);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
switch (spr) {
|
||||||
case TO_SPR(0, 11): /* EVBAR */
|
case TO_SPR(0, 11): /* EVBAR */
|
||||||
env->evbar = rb;
|
env->evbar = rb;
|
||||||
break;
|
break;
|
||||||
@ -187,27 +207,33 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb)
|
|||||||
cpu_openrisc_timer_update(cpu);
|
cpu_openrisc_timer_update(cpu);
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
|
|
||||||
case TO_SPR(0, 20): /* FPCSR */
|
|
||||||
cpu_set_fpcsr(env, rb);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd,
|
target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd,
|
||||||
target_ulong spr)
|
target_ulong spr)
|
||||||
{
|
{
|
||||||
|
OpenRISCCPU *cpu = env_archcpu(env);
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
uint64_t data[TARGET_INSN_START_WORDS];
|
uint64_t data[TARGET_INSN_START_WORDS];
|
||||||
MachineState *ms = MACHINE(qdev_get_machine());
|
MachineState *ms = MACHINE(qdev_get_machine());
|
||||||
OpenRISCCPU *cpu = env_archcpu(env);
|
|
||||||
CPUState *cs = env_cpu(env);
|
CPUState *cs = env_cpu(env);
|
||||||
int idx;
|
int idx;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Handle user accessible SPRs first. */
|
||||||
switch (spr) {
|
switch (spr) {
|
||||||
|
case TO_SPR(0, 20): /* FPCSR */
|
||||||
|
return env->fpcsr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_user(env)) {
|
||||||
|
raise_exception(cpu, EXCP_ILLEGAL);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
switch (spr) {
|
||||||
case TO_SPR(0, 0): /* VR */
|
case TO_SPR(0, 0): /* VR */
|
||||||
return env->vr;
|
return env->vr;
|
||||||
|
|
||||||
@ -324,11 +350,8 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd,
|
|||||||
cpu_openrisc_count_update(cpu);
|
cpu_openrisc_count_update(cpu);
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
return cpu_openrisc_count_get(cpu);
|
return cpu_openrisc_count_get(cpu);
|
||||||
#endif
|
|
||||||
|
|
||||||
case TO_SPR(0, 20): /* FPCSR */
|
|
||||||
return env->fpcsr;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* for rd is passed in, if rd unchanged, just keep it back. */
|
/* for rd is passed in, if rd unchanged, just keep it back. */
|
||||||
return rd;
|
return rd;
|
||||||
|
@ -819,13 +819,10 @@ static bool trans_l_xori(DisasContext *dc, arg_rri *a)
|
|||||||
|
|
||||||
static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a)
|
static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a)
|
||||||
{
|
{
|
||||||
check_r0_write(dc, a->d);
|
|
||||||
|
|
||||||
if (is_user(dc)) {
|
|
||||||
gen_illegal_exception(dc);
|
|
||||||
} else {
|
|
||||||
TCGv spr = tcg_temp_new();
|
TCGv spr = tcg_temp_new();
|
||||||
|
|
||||||
|
check_r0_write(dc, a->d);
|
||||||
|
|
||||||
if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
|
if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
|
||||||
gen_io_start();
|
gen_io_start();
|
||||||
if (dc->delayed_branch) {
|
if (dc->delayed_branch) {
|
||||||
@ -839,21 +836,18 @@ static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a)
|
|||||||
|
|
||||||
tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
|
tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
|
||||||
gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr);
|
gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr);
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a)
|
static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a)
|
||||||
{
|
{
|
||||||
if (is_user(dc)) {
|
TCGv spr = tcg_temp_new();
|
||||||
gen_illegal_exception(dc);
|
|
||||||
} else {
|
|
||||||
TCGv spr;
|
|
||||||
|
|
||||||
if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
|
if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
|
||||||
gen_io_start();
|
gen_io_start();
|
||||||
}
|
}
|
||||||
/* For SR, we will need to exit the TB to recognize the new
|
/*
|
||||||
|
* For SR, we will need to exit the TB to recognize the new
|
||||||
* exception state. For NPC, in theory this counts as a branch
|
* exception state. For NPC, in theory this counts as a branch
|
||||||
* (although the SPR only exists for use by an ICE). Save all
|
* (although the SPR only exists for use by an ICE). Save all
|
||||||
* of the cpu state first, allowing it to be overwritten.
|
* of the cpu state first, allowing it to be overwritten.
|
||||||
@ -866,10 +860,8 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a)
|
|||||||
}
|
}
|
||||||
dc->base.is_jmp = DISAS_EXIT;
|
dc->base.is_jmp = DISAS_EXIT;
|
||||||
|
|
||||||
spr = tcg_temp_new();
|
|
||||||
tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
|
tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k);
|
||||||
gen_helper_mtspr(cpu_env, spr, cpu_R(dc, a->b));
|
gen_helper_mtspr(cpu_env, spr, cpu_R(dc, a->b));
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user