All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.