Correctly implement save/restore of the tstate field in
sparc64_get_context() and sparc64_set_context():
* Don't use the CWP value from the guest in set_context
* Construct and save a tstate value rather than leaving
it as zero in get_context
To do this we factor out the "calculate TSTATE value from CPU state"
code from sparc_cpu_do_interrupt() into its own sparc64_tstate()
function; that in turn requires us to move some of the function
prototypes out from inside a CPU_NO_IO_DEFS ifdef guard.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target/sparc/cpu.h | 24 ++++++++++++++++++++----
linux-user/sparc/signal.c | 7 +++----
target/sparc/int64_helper.c | 5 +----
3 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 277254732b9..4b2290650be 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -608,10 +608,6 @@ target_ulong cpu_get_psr(CPUSPARCState *env1);
void cpu_put_psr(CPUSPARCState *env1, target_ulong val);
void cpu_put_psr_raw(CPUSPARCState *env1, target_ulong val);
#ifdef TARGET_SPARC64
-target_ulong cpu_get_ccr(CPUSPARCState *env1);
-void cpu_put_ccr(CPUSPARCState *env1, target_ulong val);
-target_ulong cpu_get_cwp64(CPUSPARCState *env1);
-void cpu_put_cwp64(CPUSPARCState *env1, int cwp);
void cpu_change_pstate(CPUSPARCState *env1, uint32_t new_pstate);
void cpu_gl_switch_gregs(CPUSPARCState *env, uint32_t new_gl);
#endif
@@ -829,4 +825,24 @@ static inline bool tb_am_enabled(int tb_flags)
#endif
}
+#ifdef TARGET_SPARC64
+/* win_helper.c */
+target_ulong cpu_get_ccr(CPUSPARCState *env1);
+void cpu_put_ccr(CPUSPARCState *env1, target_ulong val);
+target_ulong cpu_get_cwp64(CPUSPARCState *env1);
+void cpu_put_cwp64(CPUSPARCState *env1, int cwp);
+
+static inline uint64_t sparc64_tstate(CPUSPARCState *env)
+{
+ uint64_t tstate = (cpu_get_ccr(env) << 32) |
+ ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
+ cpu_get_cwp64(env);
+
+ if (env->def.features & CPU_FEATURE_GL) {
+ tstate |= (env->gl & 7ULL) << 40;
+ }
+ return tstate;
+}
+#endif
+
#endif
diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c
index ed32c7abd17..a6c7c7664a2 100644
--- a/linux-user/sparc/signal.c
+++ b/linux-user/sparc/signal.c
@@ -438,9 +438,9 @@ void sparc64_set_context(CPUSPARCState *env)
env->npc = npc;
__get_user(env->y, &((*grp)[SPARC_MC_Y]));
__get_user(tstate, &((*grp)[SPARC_MC_TSTATE]));
+ /* Honour TSTATE_ASI, TSTATE_ICC and TSTATE_XCC only */
env->asi = (tstate >> 24) & 0xff;
- cpu_put_ccr(env, tstate >> 32);
- cpu_put_cwp64(env, tstate & 0x1f);
+ cpu_put_ccr(env, (tstate >> 32) & 0xff);
__get_user(env->gregs[1], (&(*grp)[SPARC_MC_G1]));
__get_user(env->gregs[2], (&(*grp)[SPARC_MC_G2]));
__get_user(env->gregs[3], (&(*grp)[SPARC_MC_G3]));
@@ -557,8 +557,7 @@ void sparc64_get_context(CPUSPARCState *env)
}
}
- /* XXX: tstate must be saved properly */
- // __put_user(env->tstate, &((*grp)[SPARC_MC_TSTATE]));
+ __put_user(sparc64_tstate(env), &((*grp)[SPARC_MC_TSTATE]));
__put_user(env->pc, &((*grp)[SPARC_MC_PC]));
__put_user(env->npc, &((*grp)[SPARC_MC_NPC]));
__put_user(env->y, &((*grp)[SPARC_MC_Y]));
diff --git a/target/sparc/int64_helper.c b/target/sparc/int64_helper.c
index f3e7f32de61..735668f5006 100644
--- a/target/sparc/int64_helper.c
+++ b/target/sparc/int64_helper.c
@@ -131,9 +131,7 @@ void sparc_cpu_do_interrupt(CPUState *cs)
}
tsptr = cpu_tsptr(env);
- tsptr->tstate = (cpu_get_ccr(env) << 32) |
- ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
- cpu_get_cwp64(env);
+ tsptr->tstate = sparc64_tstate(env);
tsptr->tpc = env->pc;
tsptr->tnpc = env->npc;
tsptr->tt = intno;
@@ -148,7 +146,6 @@ void sparc_cpu_do_interrupt(CPUState *cs)
}
if (env->def.features & CPU_FEATURE_GL) {
- tsptr->tstate |= (env->gl & 7ULL) << 40;
cpu_gl_switch_gregs(env, env->gl + 1);
env->gl++;
}
--
2.20.1
Le 06/11/2020 à 16:27, Peter Maydell a écrit :
> Correctly implement save/restore of the tstate field in
> sparc64_get_context() and sparc64_set_context():
> * Don't use the CWP value from the guest in set_context
> * Construct and save a tstate value rather than leaving
> it as zero in get_context
>
> To do this we factor out the "calculate TSTATE value from CPU state"
> code from sparc_cpu_do_interrupt() into its own sparc64_tstate()
> function; that in turn requires us to move some of the function
> prototypes out from inside a CPU_NO_IO_DEFS ifdef guard.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> target/sparc/cpu.h | 24 ++++++++++++++++++++----
> linux-user/sparc/signal.c | 7 +++----
> target/sparc/int64_helper.c | 5 +----
> 3 files changed, 24 insertions(+), 12 deletions(-)
>
> diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
> index 277254732b9..4b2290650be 100644
> --- a/target/sparc/cpu.h
> +++ b/target/sparc/cpu.h
> @@ -608,10 +608,6 @@ target_ulong cpu_get_psr(CPUSPARCState *env1);
> void cpu_put_psr(CPUSPARCState *env1, target_ulong val);
> void cpu_put_psr_raw(CPUSPARCState *env1, target_ulong val);
> #ifdef TARGET_SPARC64
> -target_ulong cpu_get_ccr(CPUSPARCState *env1);
> -void cpu_put_ccr(CPUSPARCState *env1, target_ulong val);
> -target_ulong cpu_get_cwp64(CPUSPARCState *env1);
> -void cpu_put_cwp64(CPUSPARCState *env1, int cwp);
> void cpu_change_pstate(CPUSPARCState *env1, uint32_t new_pstate);
> void cpu_gl_switch_gregs(CPUSPARCState *env, uint32_t new_gl);
> #endif
> @@ -829,4 +825,24 @@ static inline bool tb_am_enabled(int tb_flags)
> #endif
> }
>
> +#ifdef TARGET_SPARC64
> +/* win_helper.c */
> +target_ulong cpu_get_ccr(CPUSPARCState *env1);
> +void cpu_put_ccr(CPUSPARCState *env1, target_ulong val);
> +target_ulong cpu_get_cwp64(CPUSPARCState *env1);
> +void cpu_put_cwp64(CPUSPARCState *env1, int cwp);
> +
> +static inline uint64_t sparc64_tstate(CPUSPARCState *env)
> +{
> + uint64_t tstate = (cpu_get_ccr(env) << 32) |
> + ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
> + cpu_get_cwp64(env);
> +
> + if (env->def.features & CPU_FEATURE_GL) {
> + tstate |= (env->gl & 7ULL) << 40;
> + }
> + return tstate;
> +}
> +#endif
> +
> #endif
> diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c
> index ed32c7abd17..a6c7c7664a2 100644
> --- a/linux-user/sparc/signal.c
> +++ b/linux-user/sparc/signal.c
> @@ -438,9 +438,9 @@ void sparc64_set_context(CPUSPARCState *env)
> env->npc = npc;
> __get_user(env->y, &((*grp)[SPARC_MC_Y]));
> __get_user(tstate, &((*grp)[SPARC_MC_TSTATE]));
> + /* Honour TSTATE_ASI, TSTATE_ICC and TSTATE_XCC only */
> env->asi = (tstate >> 24) & 0xff;
> - cpu_put_ccr(env, tstate >> 32);
> - cpu_put_cwp64(env, tstate & 0x1f);
> + cpu_put_ccr(env, (tstate >> 32) & 0xff);
> __get_user(env->gregs[1], (&(*grp)[SPARC_MC_G1]));
> __get_user(env->gregs[2], (&(*grp)[SPARC_MC_G2]));
> __get_user(env->gregs[3], (&(*grp)[SPARC_MC_G3]));
> @@ -557,8 +557,7 @@ void sparc64_get_context(CPUSPARCState *env)
> }
> }
>
> - /* XXX: tstate must be saved properly */
> - // __put_user(env->tstate, &((*grp)[SPARC_MC_TSTATE]));
> + __put_user(sparc64_tstate(env), &((*grp)[SPARC_MC_TSTATE]));
> __put_user(env->pc, &((*grp)[SPARC_MC_PC]));
> __put_user(env->npc, &((*grp)[SPARC_MC_NPC]));
> __put_user(env->y, &((*grp)[SPARC_MC_Y]));
> diff --git a/target/sparc/int64_helper.c b/target/sparc/int64_helper.c
> index f3e7f32de61..735668f5006 100644
> --- a/target/sparc/int64_helper.c
> +++ b/target/sparc/int64_helper.c
> @@ -131,9 +131,7 @@ void sparc_cpu_do_interrupt(CPUState *cs)
> }
> tsptr = cpu_tsptr(env);
>
> - tsptr->tstate = (cpu_get_ccr(env) << 32) |
> - ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
> - cpu_get_cwp64(env);
> + tsptr->tstate = sparc64_tstate(env);
> tsptr->tpc = env->pc;
> tsptr->tnpc = env->npc;
> tsptr->tt = intno;
> @@ -148,7 +146,6 @@ void sparc_cpu_do_interrupt(CPUState *cs)
> }
>
> if (env->def.features & CPU_FEATURE_GL) {
> - tsptr->tstate |= (env->gl & 7ULL) << 40;
> cpu_gl_switch_gregs(env, env->gl + 1);
> env->gl++;
> }
>
Applied to my linux-user-for-6.0 branch.
Thanks,
Laurent
On 11/6/20 7:27 AM, Peter Maydell wrote:
> +#ifdef TARGET_SPARC64
> +/* win_helper.c */
> +target_ulong cpu_get_ccr(CPUSPARCState *env1);
> +void cpu_put_ccr(CPUSPARCState *env1, target_ulong val);
> +target_ulong cpu_get_cwp64(CPUSPARCState *env1);
> +void cpu_put_cwp64(CPUSPARCState *env1, int cwp);
> +
> +static inline uint64_t sparc64_tstate(CPUSPARCState *env)
> +{
> + uint64_t tstate = (cpu_get_ccr(env) << 32) |
> + ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
> + cpu_get_cwp64(env);
> +
> + if (env->def.features & CPU_FEATURE_GL) {
> + tstate |= (env->gl & 7ULL) << 40;
> + }
> + return tstate;
> +}
> +#endif
Given that this inline function calls 2 other out-of-line functions, I think it
might as well be out-of-line itself.
I'd place it in win_helper.c alongside the functions that it calls.
But either way,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
© 2016 - 2026 Red Hat, Inc.