From patchwork Thu May 27 09:50:38 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sheng Yang X-Patchwork-Id: 102594 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 o4R9ntQP027402 for ; Thu, 27 May 2010 09:49:55 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757778Ab0E0Jtx (ORCPT ); Thu, 27 May 2010 05:49:53 -0400 Received: from mga03.intel.com ([143.182.124.21]:55351 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757706Ab0E0Jtw (ORCPT ); Thu, 27 May 2010 05:49:52 -0400 Received: from azsmga001.ch.intel.com ([10.2.17.19]) by azsmga101.ch.intel.com with ESMTP; 27 May 2010 02:49:52 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.53,310,1272870000"; d="scan'208";a="281969406" 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:49:49 -0700 Received: from yasker by syang10-desktop with local (Exim 4.71) (envelope-from ) id 1OHZje-0001P4-NM; Thu, 27 May 2010 17:50:42 +0800 From: Sheng Yang To: Avi Kivity , Marcelo Tosatti , Anthony Liguori Cc: kvm@vger.kernel.org, qemu-devel@nongnu.org, Sheng Yang Subject: [PATCH] qemu: kvm: Enable XSAVE live migration support Date: Thu, 27 May 2010 17:50:38 +0800 Message-Id: <1274953838-5369-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:49:56 +0000 (UTC) diff --git a/qemu-kvm-x86.c b/qemu-kvm-x86.c index 73b4af7..a2e2896 100644 --- a/qemu-kvm-x86.c +++ b/qemu-kvm-x86.c @@ -776,6 +776,7 @@ void kvm_arch_load_regs(CPUState *env, int level) { struct kvm_regs regs; struct kvm_fpu fpu; + struct kvm_xsave xsave; struct kvm_sregs sregs; struct kvm_msr_entry msrs[100]; int rc, n, i; @@ -806,16 +807,35 @@ void kvm_arch_load_regs(CPUState *env, int level) kvm_set_regs(env, ®s); - memset(&fpu, 0, sizeof fpu); - fpu.fsw = env->fpus & ~(7 << 11); - fpu.fsw |= (env->fpstt & 7) << 11; - fpu.fcw = env->fpuc; - for (i = 0; i < 8; ++i) - fpu.ftwx |= (!env->fptags[i]) << i; - memcpy(fpu.fpr, env->fpregs, sizeof env->fpregs); - memcpy(fpu.xmm, env->xmm_regs, sizeof env->xmm_regs); - fpu.mxcsr = env->mxcsr; - kvm_set_fpu(env, &fpu); + if (kvm_check_extension(kvm_state, KVM_CAP_XSAVE)) { + memset(&xsave, 0, sizeof xsave); + xsave.i387.swd = env->fpus & ~(7 << 11); + xsave.i387.swd |= (env->fpstt & 7) << 11; + xsave.i387.cwd = env->fpuc; + for (i = 0; i < 8; ++i) + xsave.i387.twd |= (!env->fptags[i]) << i; + memcpy(xsave.i387.st_space, env->fpregs, + sizeof env->fpregs); + memcpy(xsave.i387.xmm_space, env->xmm_regs, + sizeof env->xmm_regs); + xsave.i387.mxcsr = env->mxcsr; + xsave.xsave_hdr.xstate_bv = env->xstate_bv; + memcpy(xsave.ymmh.ymmh_space, env->ymmh_regs, + sizeof env->ymmh_regs); + xsave.xcr0 = env->xcr0; + kvm_set_xsave(env, &xsave); + } else { + memset(&fpu, 0, sizeof fpu); + fpu.fsw = env->fpus & ~(7 << 11); + fpu.fsw |= (env->fpstt & 7) << 11; + fpu.fcw = env->fpuc; + for (i = 0; i < 8; ++i) + fpu.ftwx |= (!env->fptags[i]) << i; + memcpy(fpu.fpr, env->fpregs, sizeof env->fpregs); + memcpy(fpu.xmm, env->xmm_regs, sizeof env->xmm_regs); + fpu.mxcsr = env->mxcsr; + kvm_set_fpu(env, &fpu); + } memset(sregs.interrupt_bitmap, 0, sizeof(sregs.interrupt_bitmap)); if (env->interrupt_injected >= 0) { @@ -938,6 +958,7 @@ void kvm_arch_save_regs(CPUState *env) { struct kvm_regs regs; struct kvm_fpu fpu; + struct kvm_xsave xsave; struct kvm_sregs sregs; struct kvm_msr_entry msrs[100]; uint32_t hflags; @@ -969,15 +990,33 @@ void kvm_arch_save_regs(CPUState *env) env->eflags = regs.rflags; env->eip = regs.rip; - kvm_get_fpu(env, &fpu); - env->fpstt = (fpu.fsw >> 11) & 7; - env->fpus = fpu.fsw; - env->fpuc = fpu.fcw; - for (i = 0; i < 8; ++i) - env->fptags[i] = !((fpu.ftwx >> i) & 1); - memcpy(env->fpregs, fpu.fpr, sizeof env->fpregs); - memcpy(env->xmm_regs, fpu.xmm, sizeof env->xmm_regs); - env->mxcsr = fpu.mxcsr; + if (kvm_check_extension(kvm_state, KVM_CAP_XSAVE)) { + kvm_get_xsave(env, &xsave); + env->fpstt = (xsave.i387.swd >> 11) & 7; + env->fpus = xsave.i387.swd; + env->fpuc = xsave.i387.cwd; + for (i = 0; i < 8; ++i) + env->fptags[i] = !((xsave.i387.twd >> i) & 1); + memcpy(env->fpregs, xsave.i387.st_space, + sizeof env->fpregs); + memcpy(env->xmm_regs, xsave.i387.xmm_space, + sizeof env->xmm_regs); + env->mxcsr = xsave.i387.mxcsr; + env->xstate_bv = xsave.xsave_hdr.xstate_bv; + memcpy(env->ymmh_regs, xsave.ymmh.ymmh_space, + sizeof env->ymmh_regs); + env->xcr0 = xsave.xcr0; + } else { + kvm_get_fpu(env, &fpu); + env->fpstt = (fpu.fsw >> 11) & 7; + env->fpus = fpu.fsw; + env->fpuc = fpu.fcw; + for (i = 0; i < 8; ++i) + env->fptags[i] = !((fpu.ftwx >> i) & 1); + memcpy(env->fpregs, fpu.fpr, sizeof env->fpregs); + memcpy(env->xmm_regs, fpu.xmm, sizeof env->xmm_regs); + env->mxcsr = fpu.mxcsr; + } kvm_get_sregs(env, &sregs); diff --git a/qemu-kvm.c b/qemu-kvm.c index 35a4c8a..c472b96 100644 --- a/qemu-kvm.c +++ b/qemu-kvm.c @@ -485,6 +485,18 @@ int kvm_set_mpstate(CPUState *env, struct kvm_mp_state *mp_state) } #endif +#ifdef KVM_CAP_XSAVE +int kvm_get_xsave(CPUState *env, struct kvm_xsave *xsave) +{ + return kvm_vcpu_ioctl(env, KVM_GET_XSAVE, xsave); +} + +int kvm_set_xsave(CPUState *env, struct kvm_xsave *xsave) +{ + return kvm_vcpu_ioctl(env, KVM_SET_XSAVE, xsave); +} +#endif + static int handle_mmio(CPUState *env) { unsigned long addr = env->kvm_run->mmio.phys_addr; diff --git a/qemu-kvm.h b/qemu-kvm.h index 6f6c6d8..0fb4638 100644 --- a/qemu-kvm.h +++ b/qemu-kvm.h @@ -300,6 +300,20 @@ int kvm_get_mpstate(CPUState *env, struct kvm_mp_state *mp_state); int kvm_set_mpstate(CPUState *env, struct kvm_mp_state *mp_state); #endif +#ifdef KVM_CAP_XSAVE +/*! + * * \brief Read VCPU xsave state + * + */ +int kvm_get_xsave(CPUState *env, struct kvm_xsave *xsave); + +/*! + * * \brief Write VCPU xsave state + * + */ +int kvm_set_xsave(CPUState *env, struct kvm_xsave *xsave); +#endif + /*! * \brief Simulate an external vectored interrupt * diff --git a/target-i386/cpu.h b/target-i386/cpu.h index e989040..c32f854 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -736,6 +736,11 @@ typedef struct CPUX86State { uint16_t fpregs_format_vmstate; int kvm_vcpu_update_vapic; + + uint64_t xstate_bv; + XMMReg ymmh_regs[CPU_NB_REGS]; + + uint64_t xcr0; } CPUX86State; CPUX86State *cpu_x86_init(const char *cpu_model); diff --git a/target-i386/machine.c b/target-i386/machine.c index b547e2a..6c89a08 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -47,6 +47,22 @@ static const VMStateDescription vmstate_xmm_reg = { #define VMSTATE_XMM_REGS(_field, _state, _n) \ VMSTATE_STRUCT_ARRAY(_field, _state, _n, 0, vmstate_xmm_reg, XMMReg) +/* YMMH format is the same as XMM */ +static const VMStateDescription vmstate_ymmh_reg = { + .name = "ymmh_reg", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT64(XMM_Q(0), XMMReg), + VMSTATE_UINT64(XMM_Q(1), XMMReg), + VMSTATE_END_OF_LIST() + } +}; + +#define VMSTATE_YMMH_REGS_VARS(_field, _state, _n, _v) \ + VMSTATE_STRUCT_ARRAY(_field, _state, _n, _v, vmstate_ymmh_reg, XMMReg) + static const VMStateDescription vmstate_mtrr_var = { .name = "mtrr_var", .version_id = 1, @@ -453,6 +469,10 @@ static const VMStateDescription vmstate_cpu = { /* KVM pvclock msr */ VMSTATE_UINT64_V(system_time_msr, CPUState, 11), VMSTATE_UINT64_V(wall_clock_msr, CPUState, 11), + + VMSTATE_UINT64_V(xcr0, CPUState, 12), + VMSTATE_UINT64_V(xstate_bv, CPUState, 12), + VMSTATE_YMMH_REGS_VARS(ymmh_regs, CPUState, CPU_NB_REGS, 12), VMSTATE_END_OF_LIST() /* The above list is not sorted /wrt version numbers, watch out! */ }