This enables userspace to get and set all the guest floating-point
state using the KVM_[GS]ET_ONE_REG ioctls.  The floating-point state
includes all of the traditional floating-point registers and the
FPSCR (floating point status/control register), all the VMX/Altivec
vector registers and the VSCR (vector status/control register), and
on POWER7, the vector-scalar registers (note that each FP register
is the high-order half of the corresponding VSR).

Signed-off-by: Paul Mackerras <[email protected]>
---
 Documentation/virtual/kvm/api.txt |   11 ++++
 arch/powerpc/include/asm/kvm.h    |   20 +++++++
 arch/powerpc/kvm/book3s_hv.c      |  112 +++++++++++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+)

diff --git a/Documentation/virtual/kvm/api.txt 
b/Documentation/virtual/kvm/api.txt
index 407556f..a02f0de 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1759,6 +1759,17 @@ registers, find a list below:
   PPC   | KVM_REG_PPC_PMC6      | 32
   PPC   | KVM_REG_PPC_PMC7      | 32
   PPC   | KVM_REG_PPC_PMC8      | 32
+  PPC   | KVM_REG_PPC_FPR0     | 64
+          ...
+  PPC   | KVM_REG_PPC_FPR31     | 64
+  PPC   | KVM_REG_PPC_VR0      | 128
+          ...
+  PPC   | KVM_REG_PPC_VR31      | 128
+  PPC   | KVM_REG_PPC_VSR0     | 128
+          ...
+  PPC   | KVM_REG_PPC_VSR31     | 128
+  PPC   | KVM_REG_PPC_FPSCR     | 64
+  PPC   | KVM_REG_PPC_VSCR      | 32
 
 4.69 KVM_GET_ONE_REG
 
diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h
index 9557576..1466975 100644
--- a/arch/powerpc/include/asm/kvm.h
+++ b/arch/powerpc/include/asm/kvm.h
@@ -360,4 +360,24 @@ struct kvm_book3e_206_tlb_params {
 #define KVM_REG_PPC_PMC7       (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1e)
 #define KVM_REG_PPC_PMC8       (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1f)
 
+/* 32 floating-point registers */
+#define KVM_REG_PPC_FPR0       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x20)
+#define KVM_REG_PPC_FPR(n)     (KVM_REG_PPC_FPR0 + (n))
+#define KVM_REG_PPC_FPR31      (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3f)
+
+/* 32 VMX/Altivec vector registers */
+#define KVM_REG_PPC_VR0                (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x40)
+#define KVM_REG_PPC_VR(n)      (KVM_REG_PPC_VR0 + (n))
+#define KVM_REG_PPC_VR31       (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x5f)
+
+/* 32 double-width FP registers for VSX */
+/* High-order halves overlap with FP regs */
+#define KVM_REG_PPC_VSR0       (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x60)
+#define KVM_REG_PPC_VSR(n)     (KVM_REG_PPC_VSR0 + (n))
+#define KVM_REG_PPC_VSR31      (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x7f)
+
+/* FP and vector status/control registers */
+#define KVM_REG_PPC_FPSCR      (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x80)
+#define KVM_REG_PPC_VSCR       (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x81)
+
 #endif /* __LINUX_KVM_POWERPC_H */
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index c4b5636..32defa0 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -585,6 +585,54 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, 
struct kvm_one_reg *reg)
                i = reg->id - KVM_REG_PPC_PMC1;
                r = put_user(vcpu->arch.pmc[i], (u32 __user *)reg->addr);
                break;
+
+       case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
+               i = reg->id - KVM_REG_PPC_FPR0;
+#ifdef CONFIG_VSX
+               if (cpu_has_feature(CPU_FTR_VSX)) {
+                       /* VSX => FP reg i is stored in arch.vsr[2*i] */
+                       r = put_user(vcpu->arch.vsr[2 * i],
+                                    (u64 __user *)reg->addr);
+                       break;
+               }
+#endif
+               r = put_user(vcpu->arch.fpr[i], (u64 __user *)reg->addr);
+               break;
+       case KVM_REG_PPC_FPSCR:
+               r = put_user(vcpu->arch.fpscr, (u64 __user *)reg->addr);
+               break;
+
+#ifdef CONFIG_ALTIVEC
+       case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31:
+               r = -ENXIO;
+               if (!cpu_has_feature(CPU_FTR_ALTIVEC))
+                       break;
+               i = reg->id - KVM_REG_PPC_VR0;
+               r = -EFAULT;
+               if (!copy_to_user((char __user *)reg->addr,
+                                 &vcpu->arch.vr[i], sizeof(vector128)))
+                       r = 0;
+               break;
+       case KVM_REG_PPC_VSCR:
+               r = -ENXIO;
+               if (!cpu_has_feature(CPU_FTR_ALTIVEC))
+                       break;
+               r = put_user(vcpu->arch.vscr.u[3], (u32 __user *)reg->addr);
+               break;
+#endif
+
+#ifdef CONFIG_VSX
+       case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31:
+               r = -ENXIO;
+               if (!cpu_has_feature(CPU_FTR_VSX))
+                       break;
+               i = (reg->id - KVM_REG_PPC_VR0) * 2;
+               r = -EFAULT;
+               if (!copy_to_user((char __user *)reg->addr,
+                                 &vcpu->arch.vsr[i], 2 * sizeof(u64)))
+                       r = 0;
+               break;
+#endif
        default:
                break;
        }
@@ -661,6 +709,70 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, 
struct kvm_one_reg *reg)
                if (!r)
                        vcpu->arch.pmc[i] = wval;
                break;
+
+       case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
+               i = reg->id - KVM_REG_PPC_FPR0;
+               r = get_user(val, (u64 __user *)reg->addr);
+               if (r)
+                       break;
+#ifdef CONFIG_VSX
+               if (cpu_has_feature(CPU_FTR_VSX)) {
+                       /* VSX => FP reg i is stored in arch.vsr[2*i] */
+                       vcpu->arch.vsr[2 * i] = val;
+                       break;
+               }
+#endif
+               vcpu->arch.fpr[i] = r;
+               break;
+       case KVM_REG_PPC_FPSCR:
+               r = get_user(val, (u64 __user *)reg->addr);
+               if (!r)
+                       vcpu->arch.fpscr = val;
+               break;
+
+#ifdef CONFIG_ALTIVEC
+       case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31: {
+               vector128 tmp;
+
+               r = -ENXIO;
+               if (!cpu_has_feature(CPU_FTR_ALTIVEC))
+                       break;
+               i = reg->id - KVM_REG_PPC_VR0;
+               r = -EFAULT;
+               if (copy_from_user(&tmp, (char __user *)reg->addr,
+                                  sizeof(vector128)))
+                       break;
+               r = 0;
+               vcpu->arch.vr[i] = tmp;
+               break;
+       }
+       case KVM_REG_PPC_VSCR:
+               r = -ENXIO;
+               if (!cpu_has_feature(CPU_FTR_ALTIVEC))
+                       break;
+               r = get_user(wval, (u32 __user *)reg->addr);
+               if (!r)
+                       vcpu->arch.vscr.u[3] = wval;
+               break;
+#endif
+#ifdef CONFIG_VSX
+       case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: {
+               u64 tmp[2];
+
+               r = -ENXIO;
+               if (!cpu_has_feature(CPU_FTR_VSX))
+                       break;
+               i = (reg->id - KVM_REG_PPC_VSR0) * 2;
+               r = -EFAULT;
+               if (copy_from_user(tmp, (char __user *)reg->addr,
+                                  2 * sizeof(u64)))
+                       break;
+               r = 0;
+               vcpu->arch.vsr[i] = tmp[0];
+               vcpu->arch.vsr[i + 1] = tmp[1];
+               break;
+       }
+#endif
        default:
                break;
        }
-- 
1.7.10.rc3.219.g53414

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to