@@ -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
@@ -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 */
@@ -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;
}
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 <paulus@samba.org> --- 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(+)