Blame 0019-target-ppc-kvm-fix-floating-point-registers-sync-on-.patch

7d975d
From: Greg Kurz <gkurz@linux.vnet.ibm.com>
7d975d
Date: Fri, 15 Jan 2016 16:00:12 +0100
7d975d
Subject: [PATCH] target-ppc: kvm: fix floating point registers sync on
7d975d
 little-endian hosts
7d975d
7d975d
On VSX capable CPUs, the 32 FP registers are mapped to the high-bits
7d975d
of the 32 first VSX registers. So if you have:
7d975d
7d975d
VSR31 = (uint128) 0x0102030405060708090a0b0c0d0e0f00
7d975d
7d975d
then
7d975d
7d975d
FPR31 = (uint64) 0x0102030405060708
7d975d
7d975d
The kernel stores the VSX registers in the fp_state struct following the
7d975d
host endian element ordering.
7d975d
7d975d
On big-endian:
7d975d
7d975d
fp_state.fpr[31][0] = 0x0102030405060708
7d975d
fp_state.fpr[31][1] = 0x090a0b0c0d0e0f00
7d975d
7d975d
On little-endian:
7d975d
7d975d
fp_state.fpr[31][0] = 0x090a0b0c0d0e0f00
7d975d
fp_state.fpr[31][1] = 0x0102030405060708
7d975d
7d975d
The KVM_GET_ONE_REG and KVM_SET_ONE_REG ioctls preserve this ordering, but
7d975d
QEMU considers it as big-endian and always copies element [0] to the
7d975d
fpr[] array and element [1] to the vsr[] array. This does not work with
7d975d
little-endian hosts, and you will get:
7d975d
7d975d
(qemu) p $f31
7d975d
0x90a0b0c0d0e0f00
7d975d
7d975d
instead of:
7d975d
7d975d
(qemu) p $f31
7d975d
0x102030405060708
7d975d
7d975d
This patch fixes the element ordering for little-endian hosts.
7d975d
7d975d
Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
7d975d
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
7d975d
(cherry picked from commit 3a4b791b4c13e02537a5cc572fa3de70bc5f68da)
7d975d
---
7d975d
 target-ppc/kvm.c | 12 ++++++++++++
7d975d
 1 file changed, 12 insertions(+)
7d975d
7d975d
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
7d975d
index ac70f08..acd3275 100644
7d975d
--- a/target-ppc/kvm.c
7d975d
+++ b/target-ppc/kvm.c
7d975d
@@ -650,8 +650,13 @@ static int kvm_put_fp(CPUState *cs)
7d975d
         for (i = 0; i < 32; i++) {
7d975d
             uint64_t vsr[2];
7d975d
 
7d975d
+#ifdef HOST_WORDS_BIGENDIAN
7d975d
             vsr[0] = float64_val(env->fpr[i]);
7d975d
             vsr[1] = env->vsr[i];
7d975d
+#else
7d975d
+            vsr[0] = env->vsr[i];
7d975d
+            vsr[1] = float64_val(env->fpr[i]);
7d975d
+#endif
7d975d
             reg.addr = (uintptr_t) &vsr;
7d975d
             reg.id = vsx ? KVM_REG_PPC_VSR(i) : KVM_REG_PPC_FPR(i);
7d975d
 
7d975d
@@ -721,10 +726,17 @@ static int kvm_get_fp(CPUState *cs)
7d975d
                         vsx ? "VSR" : "FPR", i, strerror(errno));
7d975d
                 return ret;
7d975d
             } else {
7d975d
+#ifdef HOST_WORDS_BIGENDIAN
7d975d
                 env->fpr[i] = vsr[0];
7d975d
                 if (vsx) {
7d975d
                     env->vsr[i] = vsr[1];
7d975d
                 }
7d975d
+#else
7d975d
+                env->fpr[i] = vsr[1];
7d975d
+                if (vsx) {
7d975d
+                    env->vsr[i] = vsr[0];
7d975d
+                }
7d975d
+#endif
7d975d
             }
7d975d
         }
7d975d
     }