]> Git Repo - qemu.git/commitdiff
ppc: Improve emulation of THRM registers
authorBenjamin Herrenschmidt <[email protected]>
Mon, 20 Jun 2016 01:27:14 +0000 (11:27 +1000)
committerDavid Gibson <[email protected]>
Wed, 22 Jun 2016 01:12:17 +0000 (11:12 +1000)
The 75x and 74xx processors have some thermal monitoring SPRs that
some OSes such as MacOS do use. Our current "dumb" implementation
isn't good enough and will cause some versions of MacOS to hang during
boot.

This lifts an improved emulation from MacOnLinux and adapts it to
qemu, thus fixing the problem.

Signed-off-by: Benjamin Herrenschmidt <[email protected]>
[dwg: Fixed typo in comment, a number of minor checkpatch warnings,
 and a compile failure with CONFIG_USER_ONLY]
Signed-off-by: David Gibson <[email protected]>
target-ppc/helper.h
target-ppc/misc_helper.c
target-ppc/translate_init.c

index f4410a8369543bb87839ca408474c6d1f98edfb4..18eb52fc5d1fa636c833d5e839039ff9e4c0aad9 100644 (file)
@@ -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)
index 7d41b017c8358e9014ab19d30d0933921752f557..cb5ebf56cf317bca386c86929a6a10da2d8361d1 100644 (file)
@@ -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;
+    }
+}
index ca894ff4af45855a0b91632b08b479eda25e77ef..c847a3e56227a9404f6396b54afb6a75df15e635 100644 (file)
@@ -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);
 }
 
This page took 0.036444 seconds and 4 git commands to generate.