aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-ppc/helper.h1
-rw-r--r--target-ppc/misc_helper.c41
-rw-r--r--target-ppc/translate_init.c15
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);
}