diff --git a/qemu/header_gen.py b/qemu/header_gen.py index cd6943cd..a9c1cad9 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -4491,6 +4491,7 @@ sparc_symbols = ( 'helper_taddcctv', 'helper_tsubcctv', 'helper_udiv_cc', + 'helper_wrgl', 'sparc_cpu_do_interrupt', 'sparc_cpu_do_unaligned_access', 'sparc_cpu_get_phys_page_debug', diff --git a/qemu/sparc.h b/qemu/sparc.h index c9df1da2..735b8ff3 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -3483,6 +3483,7 @@ #define helper_taddcctv helper_taddcctv_sparc #define helper_tsubcctv helper_tsubcctv_sparc #define helper_udiv_cc helper_udiv_cc_sparc +#define helper_wrgl helper_wrgl_sparc #define sparc_cpu_do_interrupt sparc_cpu_do_interrupt_sparc #define sparc_cpu_do_unaligned_access sparc_cpu_do_unaligned_access_sparc #define sparc_cpu_get_phys_page_debug sparc_cpu_get_phys_page_debug_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index ed92ed5a..f1546036 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -3483,6 +3483,7 @@ #define helper_taddcctv helper_taddcctv_sparc64 #define helper_tsubcctv helper_tsubcctv_sparc64 #define helper_udiv_cc helper_udiv_cc_sparc64 +#define helper_wrgl helper_wrgl_sparc64 #define sparc_cpu_do_interrupt sparc_cpu_do_interrupt_sparc64 #define sparc_cpu_do_unaligned_access sparc_cpu_do_unaligned_access_sparc64 #define sparc_cpu_get_phys_page_debug sparc_cpu_get_phys_page_debug_sparc64 diff --git a/qemu/target-sparc/cpu.c b/qemu/target-sparc/cpu.c index ac2eefa6..b1f5edc7 100644 --- a/qemu/target-sparc/cpu.c +++ b/qemu/target-sparc/cpu.c @@ -57,9 +57,13 @@ static void sparc_cpu_reset(CPUState *s) env->psrps = 1; #endif #ifdef TARGET_SPARC64 - env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG; + env->pstate = PS_PRIV | PS_RED | PS_PEF; + if (!cpu_has_hypervisor(env)) { + env->pstate |= PS_AG; + } env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0; env->tl = env->maxtl; + env->gl = 2; cpu_tsptr(env)->tt = TT_POWER_ON_RESET; env->lsu = 0; #else @@ -780,14 +784,17 @@ void sparc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT); cpu_fprintf(f, " xcc: "); cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4)); - cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl, - env->psrpil); + cpu_fprintf(f, ") asi: %02x tl: %d pil: %x gl: %d\n", env->asi, env->tl, + env->psrpil, env->gl); + cpu_fprintf(f, "tbr: " TARGET_FMT_lx " hpstate: " TARGET_FMT_lx " htba: " + TARGET_FMT_lx "\n", env->tbr, env->hpstate, env->htba); cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d " "cleanwin: %d cwp: %d\n", env->cansave, env->canrestore, env->otherwin, env->wstate, env->cleanwin, env->nwindows - 1 - env->cwp); cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: " TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs); + #else cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env)); cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env)); diff --git a/qemu/target-sparc/cpu.h b/qemu/target-sparc/cpu.h index 4bde5096..b56ade30 100644 --- a/qemu/target-sparc/cpu.h +++ b/qemu/target-sparc/cpu.h @@ -509,6 +509,7 @@ struct CPUSPARCState { uint64_t bgregs[8]; /* backup for normal global registers */ uint64_t igregs[8]; /* interrupt general registers */ uint64_t mgregs[8]; /* mmu general registers */ + uint64_t glregs[8 * MAXTL_MAX]; uint64_t fprs; uint64_t tick_cmpr, stick_cmpr; CPUTimer *tick, *stick; @@ -607,6 +608,7 @@ 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 int cpu_cwp_inc(CPUSPARCState *env1, int cwp); int cpu_cwp_dec(CPUSPARCState *env1, int cwp); diff --git a/qemu/target-sparc/helper.h b/qemu/target-sparc/helper.h index e65ff275..5dde807e 100644 --- a/qemu/target-sparc/helper.h +++ b/qemu/target-sparc/helper.h @@ -7,6 +7,7 @@ DEF_HELPER_2(wrpsr, void, env, tl) DEF_HELPER_1(rdpsr, tl, env) #else DEF_HELPER_FLAGS_2(wrpil, TCG_CALL_NO_RWG, void, env, tl) +DEF_HELPER_2(wrgl, void, env, tl) DEF_HELPER_2(wrpstate, void, env, tl) DEF_HELPER_1(done, void, env) DEF_HELPER_1(retry, void, env) diff --git a/qemu/target-sparc/int64_helper.c b/qemu/target-sparc/int64_helper.c index 88982367..4f30dcb9 100644 --- a/qemu/target-sparc/int64_helper.c +++ b/qemu/target-sparc/int64_helper.c @@ -66,6 +66,12 @@ 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++; + } + switch (intno) { case TT_IVEC: if (!cpu_has_hypervisor(env)) { diff --git a/qemu/target-sparc/translate.c b/qemu/target-sparc/translate.c index 7b917bb3..1b72a49a 100644 --- a/qemu/target-sparc/translate.c +++ b/qemu/target-sparc/translate.c @@ -4760,8 +4760,7 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn, bool hook_ins break; case 16: // UA2005 gl CHECK_IU_FEATURE(dc, GL); - tcg_gen_st32_tl(tcg_ctx, cpu_tmp0, tcg_ctx->cpu_env, - offsetof(CPUSPARCState, gl)); + gen_helper_wrgl(tcg_ctx, tcg_ctx->cpu_env, cpu_tmp0); break; case 26: // UA2005 strand status CHECK_IU_FEATURE(dc, HYPV); diff --git a/qemu/target-sparc/win_helper.c b/qemu/target-sparc/win_helper.c index 5a9f155e..a8dd53fa 100644 --- a/qemu/target-sparc/win_helper.c +++ b/qemu/target-sparc/win_helper.c @@ -291,6 +291,10 @@ void helper_wrcwp(CPUSPARCState *env, target_ulong new_cwp) static inline uint64_t *get_gregset(CPUSPARCState *env, uint32_t pstate) { + if (env->def->features & CPU_FEATURE_GL) { + return env->glregs + (env->gl & 7) * 8; + } + switch (pstate) { default: //trace_win_helper_gregset_error(pstate); @@ -306,14 +310,40 @@ static inline uint64_t *get_gregset(CPUSPARCState *env, uint32_t pstate) } } +static inline uint64_t *get_gl_gregset(CPUSPARCState *env, uint32_t gl) +{ + return env->glregs + (gl & 7) * 8; +} + +/* Switch global register bank */ +void cpu_gl_switch_gregs(CPUSPARCState *env, uint32_t new_gl) +{ + uint64_t *src, *dst; + src = get_gl_gregset(env, new_gl); + dst = get_gl_gregset(env, env->gl); + + if (src != dst) { + memcpy32(dst, env->gregs); + memcpy32(env->gregs, src); + } +} + +void helper_wrgl(CPUSPARCState *env, target_ulong new_gl) +{ + cpu_gl_switch_gregs(env, new_gl & 7); + env->gl = new_gl & 7; +} + void cpu_change_pstate(CPUSPARCState *env, uint32_t new_pstate) { uint32_t pstate_regs, new_pstate_regs; uint64_t *src, *dst; if (env->def->features & CPU_FEATURE_GL) { - /* PS_AG is not implemented in this case */ - new_pstate &= ~PS_AG; + /* PS_AG, IG and MG are not implemented in this case */ + new_pstate &= ~(PS_AG | PS_IG | PS_MG); + env->pstate = new_pstate; + return; } pstate_regs = env->pstate & 0xc01; @@ -367,6 +397,12 @@ void helper_done(CPUSPARCState *env) env->asi = (tsptr->tstate >> 24) & 0xff; cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f); cpu_put_cwp64(env, tsptr->tstate & 0xff); + if (cpu_has_hypervisor(env)) { + uint32_t new_gl = (tsptr->tstate >> 40) & 7; + env->hpstate = env->htstate[env->tl]; + cpu_gl_switch_gregs(env, new_gl); + env->gl = new_gl; + } env->tl--; //trace_win_helper_done(env->tl); @@ -388,6 +424,12 @@ void helper_retry(CPUSPARCState *env) env->asi = (tsptr->tstate >> 24) & 0xff; cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f); cpu_put_cwp64(env, tsptr->tstate & 0xff); + if (cpu_has_hypervisor(env)) { + uint32_t new_gl = (tsptr->tstate >> 40) & 7; + env->hpstate = env->htstate[env->tl]; + cpu_gl_switch_gregs(env, new_gl); + env->gl = new_gl; + } env->tl--; //trace_win_helper_retry(env->tl);