]> rtime.felk.cvut.cz Git - linux-imx.git/commitdiff
KVM: PPC: Book3S: Get/set guest FP regs using the GET/SET_ONE_REG interface
authorPaul Mackerras <paulus@samba.org>
Tue, 25 Sep 2012 20:32:30 +0000 (20:32 +0000)
committerAlexander Graf <agraf@suse.de>
Fri, 5 Oct 2012 21:38:54 +0000 (23:38 +0200)
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).

Most of these are implemented in common Book 3S code, except for VSX
on POWER7.  Because HV and PR differ in how they store the FP and VSX
registers on POWER7, the code for these cases is not common.  On POWER7,
the FP registers are the upper halves of the VSX registers vsr0 - vsr31.
PR KVM stores vsr0 - vsr31 in two halves, with the upper halves in the
arch.fpr[] array and the lower halves in the arch.vsr[] array, whereas
HV KVM on POWER7 stores the whole VSX register in arch.vsr[].

Signed-off-by: Paul Mackerras <paulus@samba.org>
[agraf: fix whitespace, vsx compilation]
Signed-off-by: Alexander Graf <agraf@suse.de>
Documentation/virtual/kvm/api.txt
arch/powerpc/include/asm/kvm.h
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/kvm/book3s.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_pr.c

index af9b7a06bcae5502a30739640dd513fd544903ad..71dc7e2ec8eb63f58c4839e399a8196979acf619 100644 (file)
@@ -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
 
index 9557576a532551b42c2debfdf52e2eb09b9d61b7..1466975129c7b21ec508b767dd629a7a95b816fd 100644 (file)
@@ -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 */
index 709f0ddae1f14901d582c3c29fc34c3ca785cb70..51604a16c8a5a50f20bd030f6d806865717c9905 100644 (file)
@@ -200,6 +200,8 @@ static inline u32 kvmppc_set_field(u64 inst, int msb, int lsb, int value)
 union kvmppc_one_reg {
        u32     wval;
        u64     dval;
+       vector128 vval;
+       u64     vsxval[2];
 };
 
 #define one_reg_size(id)       \
index a5af28fc3a8fa8ebbc43f01b6fd3c95f32a18e47..a4b64528524098633bcec777404c2fcbf5ac2fe6 100644 (file)
@@ -490,6 +490,7 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
        int r;
        union kvmppc_one_reg val;
        int size;
+       long int i;
 
        size = one_reg_size(reg->id);
        if (size > sizeof(val))
@@ -506,6 +507,29 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
                case KVM_REG_PPC_DSISR:
                        val = get_reg_val(reg->id, vcpu->arch.shared->dsisr);
                        break;
+               case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
+                       i = reg->id - KVM_REG_PPC_FPR0;
+                       val = get_reg_val(reg->id, vcpu->arch.fpr[i]);
+                       break;
+               case KVM_REG_PPC_FPSCR:
+                       val = get_reg_val(reg->id, vcpu->arch.fpscr);
+                       break;
+#ifdef CONFIG_ALTIVEC
+               case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31:
+                       if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
+                               r = -ENXIO;
+                               break;
+                       }
+                       val.vval = vcpu->arch.vr[reg->id - KVM_REG_PPC_VR0];
+                       break;
+               case KVM_REG_PPC_VSCR:
+                       if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
+                               r = -ENXIO;
+                               break;
+                       }
+                       val = get_reg_val(reg->id, vcpu->arch.vscr.u[3]);
+                       break;
+#endif /* CONFIG_ALTIVEC */
                default:
                        r = -EINVAL;
                        break;
@@ -525,6 +549,7 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
        int r;
        union kvmppc_one_reg val;
        int size;
+       long int i;
 
        size = one_reg_size(reg->id);
        if (size > sizeof(val))
@@ -544,6 +569,29 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
                case KVM_REG_PPC_DSISR:
                        vcpu->arch.shared->dsisr = set_reg_val(reg->id, val);
                        break;
+               case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
+                       i = reg->id - KVM_REG_PPC_FPR0;
+                       vcpu->arch.fpr[i] = set_reg_val(reg->id, val);
+                       break;
+               case KVM_REG_PPC_FPSCR:
+                       vcpu->arch.fpscr = set_reg_val(reg->id, val);
+                       break;
+#ifdef CONFIG_ALTIVEC
+               case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31:
+                       if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
+                               r = -ENXIO;
+                               break;
+                       }
+                       vcpu->arch.vr[reg->id - KVM_REG_PPC_VR0] = val.vval;
+                       break;
+               case KVM_REG_PPC_VSCR:
+                       if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
+                               r = -ENXIO;
+                               break;
+                       }
+                       vcpu->arch.vscr.u[3] = set_reg_val(reg->id, val);
+                       break;
+#endif /* CONFIG_ALTIVEC */
                default:
                        r = -EINVAL;
                        break;
index 1cc6b77fa63d9975f6b153f1d2234e4ff38ef8f9..94ec0e30969d1b58dada27eca491ed0eacff827c 100644 (file)
@@ -579,6 +579,27 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
                i = id - KVM_REG_PPC_PMC1;
                *val = get_reg_val(id, vcpu->arch.pmc[i]);
                break;
+#ifdef CONFIG_VSX
+       case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
+               if (cpu_has_feature(CPU_FTR_VSX)) {
+                       /* VSX => FP reg i is stored in arch.vsr[2*i] */
+                       long int i = id - KVM_REG_PPC_FPR0;
+                       *val = get_reg_val(id, vcpu->arch.vsr[2 * i]);
+               } else {
+                       /* let generic code handle it */
+                       r = -EINVAL;
+               }
+               break;
+       case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31:
+               if (cpu_has_feature(CPU_FTR_VSX)) {
+                       long int i = id - KVM_REG_PPC_VSR0;
+                       val->vsxval[0] = vcpu->arch.vsr[2 * i];
+                       val->vsxval[1] = vcpu->arch.vsr[2 * i + 1];
+               } else {
+                       r = -ENXIO;
+               }
+               break;
+#endif /* CONFIG_VSX */
        default:
                r = -EINVAL;
                break;
@@ -624,6 +645,27 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
                i = id - KVM_REG_PPC_PMC1;
                vcpu->arch.pmc[i] = set_reg_val(id, *val);
                break;
+#ifdef CONFIG_VSX
+       case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
+               if (cpu_has_feature(CPU_FTR_VSX)) {
+                       /* VSX => FP reg i is stored in arch.vsr[2*i] */
+                       long int i = id - KVM_REG_PPC_FPR0;
+                       vcpu->arch.vsr[2 * i] = set_reg_val(id, *val);
+               } else {
+                       /* let generic code handle it */
+                       r = -EINVAL;
+               }
+               break;
+       case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31:
+               if (cpu_has_feature(CPU_FTR_VSX)) {
+                       long int i = id - KVM_REG_PPC_VSR0;
+                       vcpu->arch.vsr[2 * i] = val->vsxval[0];
+                       vcpu->arch.vsr[2 * i + 1] = val->vsxval[1];
+               } else {
+                       r = -ENXIO;
+               }
+               break;
+#endif /* CONFIG_VSX */
        default:
                r = -EINVAL;
                break;
index c81109f3a3766d6b5e9fdb3cd4b5eea0b2a82232..b853696b6d8e30ad63ce3ef2d3db1bc07c67c1af 100644 (file)
@@ -953,6 +953,19 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
        case KVM_REG_PPC_HIOR:
                *val = get_reg_val(id, to_book3s(vcpu)->hior);
                break;
+#ifdef CONFIG_VSX
+       case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: {
+               long int i = id - KVM_REG_PPC_VSR0;
+
+               if (!cpu_has_feature(CPU_FTR_VSX)) {
+                       r = -ENXIO;
+                       break;
+               }
+               val->vsxval[0] = vcpu->arch.fpr[i];
+               val->vsxval[1] = vcpu->arch.vsr[i];
+               break;
+       }
+#endif /* CONFIG_VSX */
        default:
                r = -EINVAL;
                break;
@@ -970,6 +983,19 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
                to_book3s(vcpu)->hior = set_reg_val(id, *val);
                to_book3s(vcpu)->hior_explicit = true;
                break;
+#ifdef CONFIG_VSX
+       case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: {
+               long int i = id - KVM_REG_PPC_VSR0;
+
+               if (!cpu_has_feature(CPU_FTR_VSX)) {
+                       r = -ENXIO;
+                       break;
+               }
+               vcpu->arch.fpr[i] = val->vsxval[0];
+               vcpu->arch.vsr[i] = val->vsxval[1];
+               break;
+       }
+#endif /* CONFIG_VSX */
        default:
                r = -EINVAL;
                break;