xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Christoph Egger <Christoph.Egger@amd.com>
To: "xen-devel@lists.xensource.com" <xen-devel@lists.xensource.com>
Subject: [PATCH] nestedsvm: fix fpu context switch
Date: Thu, 12 May 2011 14:44:55 +0200	[thread overview]
Message-ID: <4DCBD647.9080702@amd.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 611 bytes --]


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 <Christoph.Egger@amd.com>
Reviewed-by: Uwe Dannowski <Uwe.Dannowski@amd.com>
Reviewed-by: Wei Huang <Wei.Huang2@amd.com>

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

[-- Attachment #2: xen_nh_fpu.diff --]
[-- Type: text/plain, Size: 4611 bytes --]

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

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

                 reply	other threads:[~2011-05-12 12:44 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4DCBD647.9080702@amd.com \
    --to=christoph.egger@amd.com \
    --cc=xen-devel@lists.xensource.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).