From mboxrd@z Thu Jan 1 00:00:00 1970 From: Christoph Egger Subject: [PATCH] nestedsvm: fix fpu context switch Date: Thu, 12 May 2011 14:44:55 +0200 Message-ID: <4DCBD647.9080702@amd.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------080304030209040906010801" Return-path: List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xensource.com Errors-To: xen-devel-bounces@lists.xensource.com To: "xen-devel@lists.xensource.com" List-Id: xen-devel@lists.xenproject.org --------------080304030209040906010801 Content-Type: text/plain; charset="ISO-8859-15"; format=flowed Content-Transfer-Encoding: 7bit Two different vmcb's are used to run l1 guest and l2 guest. When host xen switches physical FPU to a different cpu while l1 or l2 guest is running we need to sync CR0.TS bit in the other vmcb. Signed-off-by: Christoph Egger Reviewed-by: Uwe Dannowski Reviewed-by: Wei Huang -- ---to satisfy European Law for business letters: Advanced Micro Devices GmbH Einsteinring 24, 85689 Dornach b. Muenchen Geschaeftsfuehrer: Alberto Bozzo, Andrew Bowd Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen Registergericht Muenchen, HRB Nr. 43632 --------------080304030209040906010801 Content-Type: text/plain; name="xen_nh_fpu.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="xen_nh_fpu.diff" Content-Description: xen_nh_fpu.diff diff -r 666ad2e07bbc -r faff8d5c6f33 xen/arch/x86/hvm/svm/nestedsvm.c --- a/xen/arch/x86/hvm/svm/nestedsvm.c +++ b/xen/arch/x86/hvm/svm/nestedsvm.c @@ -165,6 +165,45 @@ int nsvm_vcpu_reset(struct vcpu *v) return 0; } +static uint64_t nestedsvm_fpu_vmentry(uint64_t n1cr0, + struct vmcb_struct *vvmcb, + struct vmcb_struct *n1vmcb, struct vmcb_struct *n2vmcb) +{ + uint64_t vcr0; + + vcr0 = vvmcb->_cr0; + if ( !(n1cr0 & X86_CR0_TS) && (n1vmcb->_cr0 & X86_CR0_TS) ) { + /* svm_fpu_leave() run while l1 guest was running. + * Sync FPU state with l2 guest. + */ + vcr0 |= X86_CR0_TS; + n2vmcb->_exception_intercepts |= (1U << TRAP_no_device); + } else if ( !(vcr0 & X86_CR0_TS) && (n2vmcb->_cr0 & X86_CR0_TS) ) { + /* svm_fpu_enter() run while l1 guest was running. + * Sync FPU state with l2 guest. */ + vcr0 &= ~X86_CR0_TS; + n2vmcb->_exception_intercepts &= ~(1U << TRAP_no_device); + } + + return vcr0; +} + +static void nestedsvm_fpu_vmexit(struct vmcb_struct *n1vmcb, + struct vmcb_struct *n2vmcb, uint64_t n1cr0, uint64_t guest_cr0) +{ + if ( !(guest_cr0 & X86_CR0_TS) && (n2vmcb->_cr0 & X86_CR0_TS) ) { + /* svm_fpu_leave() run while l2 guest was running. + * Sync FPU state with l1 guest. */ + n1vmcb->_cr0 |= X86_CR0_TS; + n1vmcb->_exception_intercepts |= (1U << TRAP_no_device); + } else if ( !(n1cr0 & X86_CR0_TS) && (n1vmcb->_cr0 & X86_CR0_TS) ) { + /* svm_fpu_enter() run while l2 guest was running. + * Sync FPU state with l1 guest. */ + n1vmcb->_cr0 &= ~X86_CR0_TS; + n1vmcb->_exception_intercepts &= ~(1U << TRAP_no_device); + } +} + static int nsvm_vcpu_hostsave(struct vcpu *v, unsigned int inst_len) { struct nestedsvm *svm = &vcpu_nestedsvm(v); @@ -176,6 +215,13 @@ static int nsvm_vcpu_hostsave(struct vcp n1vmcb->rip += inst_len; + /* Save shadowed values. This ensures that the l1 guest + * cannot override them to break out. */ + n1vmcb->_efer = v->arch.hvm_vcpu.guest_efer; + n1vmcb->_cr0 = v->arch.hvm_vcpu.guest_cr[0]; + n1vmcb->_cr2 = v->arch.hvm_vcpu.guest_cr[2]; + n1vmcb->_cr4 = v->arch.hvm_vcpu.guest_cr[4]; + /* Remember the host interrupt flag */ svm->ns_hostflags.fields.rflagsif = (n1vmcb->rflags & X86_EFLAGS_IF) ? 1 : 0; @@ -186,6 +232,7 @@ static int nsvm_vcpu_hostsave(struct vcp int nsvm_vcpu_hostrestore(struct vcpu *v, struct cpu_user_regs *regs) { struct nestedvcpu *nv = &vcpu_nestedhvm(v); + struct nestedsvm *svm = &vcpu_nestedsvm(v); struct vmcb_struct *n1vmcb, *n2vmcb; int rc; @@ -215,11 +262,14 @@ int nsvm_vcpu_hostrestore(struct vcpu *v gdprintk(XENLOG_ERR, "hvm_set_cr4 failed, rc: %u\n", rc); /* CR0 */ + nestedsvm_fpu_vmexit(n1vmcb, n2vmcb, + svm->ns_cr0, v->arch.hvm_vcpu.guest_cr[0]); v->arch.hvm_vcpu.guest_cr[0] = n1vmcb->_cr0 | X86_CR0_PE; n1vmcb->rflags &= ~X86_EFLAGS_VM; rc = hvm_set_cr0(n1vmcb->_cr0 | X86_CR0_PE); if (rc != X86EMUL_OKAY) gdprintk(XENLOG_ERR, "hvm_set_cr0 failed, rc: %u\n", rc); + svm->ns_cr0 = v->arch.hvm_vcpu.guest_cr[0]; /* CR2 */ v->arch.hvm_vcpu.guest_cr[2] = n1vmcb->_cr2; @@ -336,6 +386,7 @@ static int nsvm_vmcb_prepare4vmrun(struc struct vmcb_struct *ns_vmcb, *n1vmcb, *n2vmcb; bool_t vcleanbits_valid; int rc; + uint64_t cr0; ns_vmcb = nv->nv_vvmcx; n1vmcb = nv->nv_n1vmcx; @@ -470,8 +521,10 @@ static int nsvm_vmcb_prepare4vmrun(struc gdprintk(XENLOG_ERR, "hvm_set_cr4 failed, rc: %u\n", rc); /* CR0 */ + svm->ns_cr0 = v->arch.hvm_vcpu.guest_cr[0]; + cr0 = nestedsvm_fpu_vmentry(svm->ns_cr0, ns_vmcb, n1vmcb, n2vmcb); v->arch.hvm_vcpu.guest_cr[0] = ns_vmcb->_cr0; - rc = hvm_set_cr0(ns_vmcb->_cr0); + rc = hvm_set_cr0(cr0); if (rc != X86EMUL_OKAY) gdprintk(XENLOG_ERR, "hvm_set_cr0 failed, rc: %u\n", rc); diff -r 666ad2e07bbc -r faff8d5c6f33 xen/include/asm-x86/hvm/svm/nestedsvm.h --- a/xen/include/asm-x86/hvm/svm/nestedsvm.h +++ b/xen/include/asm-x86/hvm/svm/nestedsvm.h @@ -56,6 +56,9 @@ struct nestedsvm { /* Shadow io permission map */ unsigned long *ns_iomap; + uint64_t ns_cr0; /* Cached guest_cr[0] of l1 guest while l2 guest runs. + * Needed to handle FPU context switching */ + /* Cache guest cr3/host cr3 the guest sets up for the l2 guest. * Used by Shadow-on-Shadow and Nested-on-Nested. * ns_vmcb_guestcr3: in l2 guest physical address space and points to --------------080304030209040906010801 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel --------------080304030209040906010801--