diff options
-rw-r--r-- | target-ppc/helper.h | 1 | ||||
-rw-r--r-- | target-ppc/misc_helper.c | 41 | ||||
-rw-r--r-- | target-ppc/translate_init.c | 15 |
3 files changed, 54 insertions, 3 deletions
diff --git a/target-ppc/helper.h b/target-ppc/helper.h index f4410a8369..18eb52fc5d 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -670,3 +670,4 @@ DEF_HELPER_4(dscli, void, env, fprp, fprp, i32) DEF_HELPER_4(dscliq, void, env, fprp, fprp, i32) DEF_HELPER_1(tbegin, void, env) +DEF_HELPER_1(fixup_thrm, void, env) diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c index 7d41b017c8..cb5ebf56cf 100644 --- a/target-ppc/misc_helper.c +++ b/target-ppc/misc_helper.c @@ -166,3 +166,44 @@ void ppc_store_msr(CPUPPCState *env, target_ulong value) { hreg_store_msr(env, value, 0); } + +/* This code is lifted from MacOnLinux. It is called whenever + * THRM1,2 or 3 is read an fixes up the values in such a way + * that will make MacOS not hang. These registers exist on some + * 75x and 74xx processors. + */ +void helper_fixup_thrm(CPUPPCState *env) +{ + target_ulong v, t; + int i; + +#define THRM1_TIN (1 << 31) +#define THRM1_TIV (1 << 30) +#define THRM1_THRES(x) (((x) & 0x7f) << 23) +#define THRM1_TID (1 << 2) +#define THRM1_TIE (1 << 1) +#define THRM1_V (1 << 0) +#define THRM3_E (1 << 0) + + if (!(env->spr[SPR_THRM3] & THRM3_E)) { + return; + } + + /* Note: Thermal interrupts are unimplemented */ + for (i = SPR_THRM1; i <= SPR_THRM2; i++) { + v = env->spr[i]; + if (!(v & THRM1_V)) { + continue; + } + v |= THRM1_TIV; + v &= ~THRM1_TIN; + t = v & THRM1_THRES(127); + if ((v & THRM1_TID) && t < THRM1_THRES(24)) { + v |= THRM1_TIN; + } + if (!(v & THRM1_TID) && t > THRM1_THRES(24)) { + v |= THRM1_TIN; + } + env->spr[i] = v; + } +} diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index ca894ff4af..c847a3e562 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -1179,23 +1179,32 @@ static void gen_spr_amr(CPUPPCState *env, bool has_iamr) } #endif /* TARGET_PPC64 */ +#ifndef CONFIG_USER_ONLY +static void spr_read_thrm(DisasContext *ctx, int gprn, int sprn) +{ + gen_helper_fixup_thrm(cpu_env); + gen_load_spr(cpu_gpr[gprn], sprn); + spr_load_dump_spr(sprn); +} +#endif /* !CONFIG_USER_ONLY */ + static void gen_spr_thrm (CPUPPCState *env) { /* Thermal management */ /* XXX : not implemented */ spr_register(env, SPR_THRM1, "THRM1", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_thrm, &spr_write_generic, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_THRM2, "THRM2", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_thrm, &spr_write_generic, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_THRM3, "THRM3", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, + &spr_read_thrm, &spr_write_generic, 0x00000000); } |