aboutsummaryrefslogtreecommitdiff
path: root/target-ppc/misc_helper.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2016-06-20 11:27:14 +1000
committerDavid Gibson <david@gibson.dropbear.id.au>2016-06-22 11:12:17 +1000
commitf0278900d38b2d8d9531c484bd088d9a7d5d4ea2 (patch)
tree87f334374778673b1f16d31fed49195d8eff6cc4 /target-ppc/misc_helper.c
parent820724d170dd97bd216810c6965ee1ebd0ba01e8 (diff)
downloadqemu-arm-f0278900d38b2d8d9531c484bd088d9a7d5d4ea2.tar.gz
ppc: Improve emulation of THRM registers
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 <benh@kernel.crashing.org> [dwg: Fixed typo in comment, a number of minor checkpatch warnings, and a compile failure with CONFIG_USER_ONLY] Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'target-ppc/misc_helper.c')
-rw-r--r--target-ppc/misc_helper.c41
1 files changed, 41 insertions, 0 deletions
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;
+ }
+}