This patch enable save/restore of xsave state.

Signed-off-by: Sheng Yang <[email protected]>
---
 Documentation/kvm/api.txt  |   76 ++++++++++++++++++++++++++++++
 arch/x86/include/asm/kvm.h |   24 ++++++++++
 arch/x86/kvm/x86.c         |  110 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/kvm.h        |   12 +++++
 4 files changed, 222 insertions(+), 0 deletions(-)

diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt
index 159b4ef..cb0afa2 100644
--- a/Documentation/kvm/api.txt
+++ b/Documentation/kvm/api.txt
@@ -922,6 +922,82 @@ Define which vcpu is the Bootstrap Processor (BSP).  
Values are the same
 as the vcpu id in KVM_CREATE_VCPU.  If this ioctl is not called, the default
 is vcpu 0.
 
+4.41 KVM_GET_XSAVE
+
+Capability: KVM_CAP_XSAVE
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xsave (out)
+Returns: 0 on success, -1 on error
+
+struct kvm_xsave {
+       __u32 size;
+       __u32 region[1000];
+};
+
+This ioctl would copy current vcpu's xsave struct to the userspace.
+
+4.42 KVM_SET_XSAVE
+
+Capability: KVM_CAP_XSAVE
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xsave (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_xsave {
+       __u32 size;
+       __u32 region[1000];
+};
+
+This ioctl would copy userspace's xsave struct to the kernel.
+
+4.43 KVM_GET_XCRS
+
+Capability: KVM_CAP_XCRS
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xcrs (out)
+Returns: 0 on success, -1 on error
+
+struct kvm_xcr {
+       __u32 xcr;
+       __u32 reserved;
+       __u64 value;
+};
+
+struct kvm_xcrs {
+       __u32 nr_xcrs;
+       __u32 flags;
+       struct kvm_xcr xcrs[KVM_MAX_XCRS];
+       __u64 padding[16];
+};
+
+This ioctl would copy current vcpu's xcrs to the userspace.
+
+4.44 KVM_SET_XCRS
+
+Capability: KVM_CAP_XCRS
+Architectures: x86
+Type: vcpu ioctl
+Parameters: struct kvm_xcrs (in)
+Returns: 0 on success, -1 on error
+
+struct kvm_xcr {
+       __u32 xcr;
+       __u32 reserved;
+       __u64 value;
+};
+
+struct kvm_xcrs {
+       __u32 nr_xcrs;
+       __u32 flags;
+       struct kvm_xcr xcrs[KVM_MAX_XCRS];
+       __u64 padding[16];
+};
+
+This ioctl would set vcpu's xcr to the value userspace specified.
+
 5. The kvm_run structure
 
 Application code obtains a pointer to the kvm_run structure by
diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
index ff90055..a12a24a 100644
--- a/arch/x86/include/asm/kvm.h
+++ b/arch/x86/include/asm/kvm.h
@@ -22,6 +22,8 @@
 #define __KVM_HAVE_XEN_HVM
 #define __KVM_HAVE_VCPU_EVENTS
 #define __KVM_HAVE_DEBUGREGS
+#define __KVM_HAVE_XSAVE
+#define __KVM_HAVE_XCRS
 
 /* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
@@ -299,4 +301,26 @@ struct kvm_debugregs {
        __u64 reserved[9];
 };
 
+/* for KVM_CAP_XSAVE */
+struct kvm_xsave {
+       __u32 size;
+       __u32 reserved[3];
+       __u32 region[1020];
+};
+
+#define KVM_MAX_XCRS   1
+
+struct kvm_xcr {
+       __u32 xcr;
+       __u32 reserved;
+       __u64 value;
+};
+
+struct kvm_xcrs {
+       __u32 nr_xcrs;
+       __u32 flags;
+       struct kvm_xcr xcrs[KVM_MAX_XCRS];
+       __u64 padding[16];
+};
+
 #endif /* _ASM_X86_KVM_H */
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 7a4073b..0fed328 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1698,6 +1698,8 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_PCI_SEGMENT:
        case KVM_CAP_DEBUGREGS:
        case KVM_CAP_X86_ROBUST_SINGLESTEP:
+       case KVM_CAP_XSAVE:
+       case KVM_CAP_XCRS:
                r = 1;
                break;
        case KVM_CAP_COALESCED_MMIO:
@@ -2373,6 +2375,60 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct 
kvm_vcpu *vcpu,
        return 0;
 }
 
+static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu,
+                                       struct kvm_xsave *guest_xsave)
+{
+       u32 size;
+
+       if (cpu_has_xsave)
+               size = sizeof(struct xsave_struct);
+       else
+               size = sizeof(struct i387_fxsave_struct);
+
+       guest_xsave->size = size;
+       memcpy(guest_xsave->region, &vcpu->arch.guest_fpu.state->xsave, size);
+}
+
+static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
+                                       struct kvm_xsave *guest_xsave)
+{
+       u32 size;
+
+       if (cpu_has_xsave)
+               size = sizeof(struct xsave_struct);
+       else
+               size = sizeof(struct i387_fxsave_struct);
+
+       if (guest_xsave->size > size)
+               return -EFAULT;
+       else
+               size = guest_xsave->size;
+       memcpy(&vcpu->arch.guest_fpu.state->xsave, guest_xsave->region, size);
+       return 0;
+}
+
+static void kvm_vcpu_ioctl_x86_get_xcrs(struct kvm_vcpu *vcpu,
+                                       struct kvm_xcrs *guest_xcrs)
+{
+       guest_xcrs->nr_xcrs = 1;
+       guest_xcrs->flags = 0;
+       guest_xcrs->xcrs[0].value = vcpu->arch.xcr0;
+}
+
+static int kvm_vcpu_ioctl_x86_set_xcrs(struct kvm_vcpu *vcpu,
+                                      struct kvm_xcrs *guest_xcrs)
+{
+       if (guest_xcrs->nr_xcrs < 1)
+               return 1;
+
+       /* Userspace may override the initial value of xcr0... */
+       if (guest_xcrs->xcrs[0].value != 0) {
+               vcpu->arch.xcr0 = guest_xcrs->xcrs[0].value;
+               vcpu->guest_xcr0_loaded = 0;
+       }
+       return 0;
+}
+
 long kvm_arch_vcpu_ioctl(struct file *filp,
                         unsigned int ioctl, unsigned long arg)
 {
@@ -2574,6 +2630,60 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                r = kvm_vcpu_ioctl_x86_set_debugregs(vcpu, &dbgregs);
                break;
        }
+       case KVM_GET_XSAVE: {
+               struct kvm_xsave *xsave;
+
+               xsave = kzalloc(sizeof(struct kvm_xsave), GFP_KERNEL);
+               r = -ENOMEM;
+               if (!xsave)
+                       break;
+
+               kvm_vcpu_ioctl_x86_get_xsave(vcpu, xsave);
+
+               r = -EFAULT;
+               if (copy_to_user(argp, xsave, sizeof(struct kvm_xsave)))
+                       break;
+               r = 0;
+               break;
+       }
+       case KVM_SET_XSAVE: {
+               struct kvm_xsave *xsave;
+
+               xsave = kzalloc(sizeof(struct kvm_xsave), GFP_KERNEL);
+               r = -ENOMEM;
+               if (!xsave)
+                       break;
+
+               r = -EFAULT;
+               if (copy_from_user(xsave, argp, sizeof(struct kvm_xsave)))
+                       break;
+
+               r = kvm_vcpu_ioctl_x86_set_xsave(vcpu, xsave);
+               break;
+       }
+       case KVM_GET_XCRS: {
+               struct kvm_xcrs xcrs;
+
+               kvm_vcpu_ioctl_x86_get_xcrs(vcpu, &xcrs);
+
+               r = -EFAULT;
+               if (copy_to_user(argp, &xcrs,
+                                sizeof(struct kvm_xcrs)))
+                       break;
+               r = 0;
+               break;
+       }
+       case KVM_SET_XCRS: {
+               struct kvm_xcrs xcrs;
+
+               r = -EFAULT;
+               if (copy_from_user(&xcrs, argp,
+                                  sizeof(struct kvm_xcrs)))
+                       break;
+
+               r = kvm_vcpu_ioctl_x86_set_xcrs(vcpu, &xcrs);
+               break;
+       }
        default:
                r = -EINVAL;
        }
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 23ea022..6fd40f5 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -524,6 +524,12 @@ struct kvm_enable_cap {
 #define KVM_CAP_PPC_OSI 52
 #define KVM_CAP_PPC_UNSET_IRQ 53
 #define KVM_CAP_ENABLE_CAP 54
+#ifdef __KVM_HAVE_XSAVE
+#define KVM_CAP_XSAVE 55
+#endif
+#ifdef __KVM_HAVE_XCRS
+#define KVM_CAP_XCRS 56
+#endif
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -714,6 +720,12 @@ struct kvm_clock_data {
 #define KVM_GET_DEBUGREGS         _IOR(KVMIO,  0xa1, struct kvm_debugregs)
 #define KVM_SET_DEBUGREGS         _IOW(KVMIO,  0xa2, struct kvm_debugregs)
 #define KVM_ENABLE_CAP            _IOW(KVMIO,  0xa3, struct kvm_enable_cap)
+/* Available with KVM_CAP_XSAVE */
+#define KVM_GET_XSAVE            _IOR(KVMIO,  0xa4, struct kvm_xsave)
+#define KVM_SET_XSAVE            _IOW(KVMIO,  0xa5, struct kvm_xsave)
+/* Available with KVM_CAP_XCRS */
+#define KVM_GET_XCRS             _IOR(KVMIO,  0xa6, struct kvm_xcrs)
+#define KVM_SET_XCRS             _IOW(KVMIO,  0xa7, struct kvm_xcrs)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU    (1 << 0)
 
-- 
1.7.0.1

--
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