This patch enable save/restore of xsave state. Signed-off-by: Sheng Yang <sheng@xxxxxxxxxxxxxxx> --- arch/x86/include/asm/kvm.h | 29 ++++++++++++++++ arch/x86/kvm/x86.c | 79 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/kvm.h | 6 +++ 3 files changed, 114 insertions(+), 0 deletions(-) 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) -- 1.7.0.1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html