From patchwork Thu May 27 09:48:40 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sheng Yang X-Patchwork-Id: 102592 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o4R9ls4l026973 for ; Thu, 27 May 2010 09:47:54 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757660Ab0E0Jrw (ORCPT ); Thu, 27 May 2010 05:47:52 -0400 Received: from mga14.intel.com ([143.182.124.37]:24452 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757581Ab0E0Jrv (ORCPT ); Thu, 27 May 2010 05:47:51 -0400 Received: from azsmga001.ch.intel.com ([10.2.17.19]) by azsmga102.ch.intel.com with ESMTP; 27 May 2010 02:47:50 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.53,310,1272870000"; d="scan'208";a="281968783" Received: from syang10-desktop.sh.intel.com (HELO syang10-desktop) ([10.239.36.64]) by azsmga001.ch.intel.com with ESMTP; 27 May 2010 02:47:49 -0700 Received: from yasker by syang10-desktop with local (Exim 4.71) (envelope-from ) id 1OHZhi-0001KD-JA; Thu, 27 May 2010 17:48:42 +0800 From: Sheng Yang To: Avi Kivity , Marcelo Tosatti Cc: kvm@vger.kernel.org, Sheng Yang Subject: [PATCH] KVM: x86: XSAVE/XRSTOR live migration support Date: Thu, 27 May 2010 17:48:40 +0800 Message-Id: <1274953721-5068-1-git-send-email-sheng@linux.intel.com> X-Mailer: git-send-email 1.7.0.4 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Thu, 27 May 2010 09:47:55 +0000 (UTC) diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h index ff90055..d3f4d9f 100644 --- a/arch/x86/include/asm/kvm.h +++ b/arch/x86/include/asm/kvm.h @@ -22,6 +22,7 @@ #define __KVM_HAVE_XEN_HVM #define __KVM_HAVE_VCPU_EVENTS #define __KVM_HAVE_DEBUGREGS +#define __KVM_HAVE_XSAVE /* Architectural interrupt line count. */ #define KVM_NR_INTERRUPTS 256 @@ -299,4 +300,32 @@ struct kvm_debugregs { __u64 reserved[9]; }; +/* for KVM_CAP_XSAVE */ +struct kvm_xsave { + struct { + __u16 cwd; + __u16 swd; + __u16 twd; + __u16 fop; + __u64 rip; + __u64 rdp; + __u32 mxcsr; + __u32 mxcsr_mask; + __u32 st_space[32]; + __u32 xmm_space[64]; + __u32 padding[12]; + __u32 sw_reserved[12]; + } i387; + struct { + __u64 xstate_bv; + __u64 reserved1[2]; + __u64 reserved2[5]; + } xsave_hdr; + struct { + __u32 ymmh_space[64]; + } ymmh; + __u64 xcr0; + __u32 padding[256]; +}; + #endif /* _ASM_X86_KVM_H */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index e7acc9d..5badba2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1711,6 +1711,9 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_MCE: r = KVM_MAX_MCE_BANKS; break; + case KVM_CAP_XSAVE: + r = cpu_has_xsave; + break; default: r = 0; break; @@ -2363,6 +2366,59 @@ 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) +{ + struct xsave_struct *xsave = &vcpu->arch.guest_fpu.state->xsave; + + if (!cpu_has_xsave) + return; + + guest_xsave->i387.cwd = xsave->i387.cwd; + guest_xsave->i387.swd = xsave->i387.swd; + guest_xsave->i387.twd = xsave->i387.twd; + guest_xsave->i387.fop = xsave->i387.fop; + guest_xsave->i387.rip = xsave->i387.rip; + guest_xsave->i387.rdp = xsave->i387.rdp; + memcpy(guest_xsave->i387.st_space, xsave->i387.st_space, 128); + memcpy(guest_xsave->i387.xmm_space, xsave->i387.xmm_space, + sizeof guest_xsave->i387.xmm_space); + + guest_xsave->xsave_hdr.xstate_bv = xsave->xsave_hdr.xstate_bv; + memcpy(guest_xsave->ymmh.ymmh_space, xsave->ymmh.ymmh_space, + sizeof xsave->ymmh.ymmh_space); + + guest_xsave->xcr0 = vcpu->arch.xcr0; +} + +static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu, + struct kvm_xsave *guest_xsave) +{ + struct xsave_struct *xsave = &vcpu->arch.guest_fpu.state->xsave; + + if (!cpu_has_xsave) + return -EINVAL; + + xsave->i387.cwd = guest_xsave->i387.cwd; + xsave->i387.swd = guest_xsave->i387.swd; + xsave->i387.twd = guest_xsave->i387.twd; + xsave->i387.fop = guest_xsave->i387.fop; + xsave->i387.rip = guest_xsave->i387.rip; + xsave->i387.rdp = guest_xsave->i387.rdp; + memcpy(xsave->i387.st_space, guest_xsave->i387.st_space, 128); + memcpy(xsave->i387.xmm_space, guest_xsave->i387.xmm_space, + sizeof guest_xsave->i387.xmm_space); + + xsave->xsave_hdr.xstate_bv = guest_xsave->xsave_hdr.xstate_bv; + memcpy(xsave->ymmh.ymmh_space, guest_xsave->ymmh.ymmh_space, + sizeof guest_xsave->ymmh.ymmh_space); + + /* set_xsave may override the initial value of xcr0... */ + if (guest_xsave->xcr0 != 0) + kvm_set_xcr0(vcpu, guest_xsave->xcr0); + return 0; +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -2564,6 +2620,29 @@ 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; + + 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; + + r = -EFAULT; + if (copy_from_user(&xsave, argp, + sizeof(struct kvm_xsave))) + break; + + r = kvm_vcpu_ioctl_x86_set_xsave(vcpu, &xsave); + break; + } default: r = -EINVAL; } diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 23ea022..5006761 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -524,6 +524,9 @@ 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_CAP_IRQ_ROUTING @@ -714,6 +717,9 @@ 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) #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)