[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] hvm: Clean up EFER handling. Check CR0/CR4/EFER on HVM restore.



# HG changeset patch
# User Keir Fraser <keir@xxxxxxxxxxxxx>
# Date 1190991644 -3600
# Node ID ff4ff3e3ebbee196efdaf036688fed89cd19e721
# Parent  96f46954c7f1e47624f4fd762ccbaf87378fcc7d
hvm: Clean up EFER handling. Check CR0/CR4/EFER on HVM restore.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 xen/arch/x86/hvm/hvm.c            |   61 ++++++++++++++++++++++++++++
 xen/arch/x86/hvm/svm/svm.c        |   80 ++++----------------------------------
 xen/arch/x86/hvm/vmx/vmx.c        |   61 ++++------------------------
 xen/include/asm-x86/hvm/support.h |    1 
 4 files changed, 82 insertions(+), 121 deletions(-)

diff -r 96f46954c7f1 -r ff4ff3e3ebbe xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Fri Sep 28 15:05:11 2007 +0100
+++ b/xen/arch/x86/hvm/hvm.c    Fri Sep 28 16:00:44 2007 +0100
@@ -337,6 +337,34 @@ static int hvm_load_cpu_ctxt(struct doma
     if ( hvm_load_entry(CPU, h, &ctxt) != 0 ) 
         return -EINVAL;
 
+    /* Sanity check some control registers. */
+    if ( (ctxt.cr0 & HVM_CR0_GUEST_RESERVED_BITS) ||
+         !(ctxt.cr0 & X86_CR0_ET) ||
+         ((ctxt.cr0 & (X86_CR0_PE|X86_CR0_PG)) == X86_CR0_PG) )
+    {
+        gdprintk(XENLOG_ERR, "HVM restore: bad CR0 0x%"PRIx64"\n",
+                 ctxt.msr_efer);
+        return -EINVAL;
+    }
+
+    if ( ctxt.cr4 & HVM_CR4_GUEST_RESERVED_BITS )
+    {
+        gdprintk(XENLOG_ERR, "HVM restore: bad CR4 0x%"PRIx64"\n",
+                 ctxt.msr_efer);
+        return -EINVAL;
+    }
+
+    if ( (ctxt.msr_efer & ~(EFER_LME | EFER_NX | EFER_SCE)) ||
+         ((sizeof(long) != 8) && (ctxt.msr_efer & EFER_LME)) ||
+         (!cpu_has_nx && (ctxt.msr_efer & EFER_NX)) ||
+         (!cpu_has_syscall && (ctxt.msr_efer & EFER_SCE)) ||
+         ((ctxt.msr_efer & (EFER_LME|EFER_LMA)) == EFER_LMA) )
+    {
+        gdprintk(XENLOG_ERR, "HVM restore: bad EFER 0x%"PRIx64"\n",
+                 ctxt.msr_efer);
+        return -EINVAL;
+    }
+
     /* Architecture-specific vmcs/vmcb bits */
     if ( hvm_funcs.load_cpu_ctxt(v, &ctxt) < 0 )
         return -EINVAL;
@@ -530,6 +558,39 @@ void hvm_triple_fault(void)
     gdprintk(XENLOG_INFO, "Triple fault on VCPU%d - "
              "invoking HVM system reset.\n", v->vcpu_id);
     domain_shutdown(v->domain, SHUTDOWN_reboot);
+}
+
+int hvm_set_efer(uint64_t value)
+{
+    struct vcpu *v = current;
+
+    value &= ~EFER_LMA;
+
+    if ( (value & ~(EFER_LME | EFER_NX | EFER_SCE)) ||
+         ((sizeof(long) != 8) && (value & EFER_LME)) ||
+         (!cpu_has_nx && (value & EFER_NX)) ||
+         (!cpu_has_syscall && (value & EFER_SCE)) )
+    {
+        gdprintk(XENLOG_WARNING, "Trying to set reserved bit in "
+                 "EFER: %"PRIx64"\n", value);
+        hvm_inject_exception(TRAP_gp_fault, 0, 0);
+        return 0;
+    }
+
+    if ( ((value ^ v->arch.hvm_vcpu.guest_efer) & EFER_LME) &&
+         hvm_paging_enabled(v) )
+    {
+        gdprintk(XENLOG_WARNING,
+                 "Trying to change EFER.LME with paging enabled\n");
+        hvm_inject_exception(TRAP_gp_fault, 0, 0);
+        return 0;
+    }
+
+    value |= v->arch.hvm_vcpu.guest_efer & EFER_LMA;
+    v->arch.hvm_vcpu.guest_efer = value;
+    hvm_update_guest_efer(v);
+
+    return 1;
 }
 
 int hvm_set_cr0(unsigned long value)
diff -r 96f46954c7f1 -r ff4ff3e3ebbe xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Fri Sep 28 15:05:11 2007 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c        Fri Sep 28 16:00:44 2007 +0100
@@ -69,6 +69,8 @@ static void *hsa[NR_CPUS] __read_mostly;
 /* vmcb used for extended host state */
 static void *root_vmcb[NR_CPUS] __read_mostly;
 
+static void svm_update_guest_efer(struct vcpu *v);
+
 static void inline __update_guest_eip(
     struct cpu_user_regs *regs, int inst_len) 
 {
@@ -103,22 +105,10 @@ static void svm_cpu_down(void)
     write_efer(read_efer() & ~EFER_SVME);
 }
 
-static int svm_lme_is_set(struct vcpu *v)
-{
-#ifdef __x86_64__
-    u64 guest_efer = v->arch.hvm_vcpu.guest_efer;
-    return guest_efer & EFER_LME;
-#else
-    return 0;
-#endif
-}
-
 static enum handler_return long_mode_do_msr_write(struct cpu_user_regs *regs)
 {
     u64 msr_content = (u32)regs->eax | ((u64)regs->edx << 32);
     u32 ecx = regs->ecx;
-    struct vcpu *v = current;
-    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
 
     HVM_DBG_LOG(DBG_LEVEL_0, "msr %x msr_content %"PRIx64,
                 ecx, msr_content);
@@ -126,47 +116,8 @@ static enum handler_return long_mode_do_
     switch ( ecx )
     {
     case MSR_EFER:
-        /* Offending reserved bit will cause #GP. */
-#ifdef __x86_64__
-        if ( (msr_content & ~(EFER_LME | EFER_LMA | EFER_NX | EFER_SCE)) ||
-#else
-        if ( (msr_content & ~(EFER_NX | EFER_SCE)) ||
-#endif
-             (!cpu_has_nx && (msr_content & EFER_NX)) ||
-             (!cpu_has_syscall && (msr_content & EFER_SCE)) )
-        {
-            gdprintk(XENLOG_WARNING, "Trying to set reserved bit in "
-                     "EFER: %"PRIx64"\n", msr_content);
-            goto gp_fault;
-        }
-
-        if ( (msr_content & EFER_LME) && !svm_lme_is_set(v) )
-        {
-            /* EFER.LME transition from 0 to 1. */
-            if ( hvm_paging_enabled(v) ||
-                 !(v->arch.hvm_vcpu.guest_cr[4] & X86_CR4_PAE) )
-            {
-                gdprintk(XENLOG_WARNING, "Trying to set LME bit when "
-                         "in paging mode or PAE bit is not set\n");
-                goto gp_fault;
-            }
-        }
-        else if ( !(msr_content & EFER_LME) && svm_lme_is_set(v) )
-        {
-            /* EFER.LME transistion from 1 to 0. */
-            if ( hvm_paging_enabled(v) )
-            {
-                gdprintk(XENLOG_WARNING, 
-                         "Trying to clear EFER.LME while paging enabled\n");
-                goto gp_fault;
-            }
-        }
-
-        v->arch.hvm_vcpu.guest_efer = msr_content;
-        vmcb->efer = msr_content | EFER_SVME;
-        if ( !hvm_paging_enabled(v) )
-            vmcb->efer &= ~(EFER_LME | EFER_LMA);
-
+        if ( !hvm_set_efer(msr_content) )
+            return HNDL_exception_raised;
         break;
 
     case MSR_K8_MC4_MISC: /* Threshold register */
@@ -182,10 +133,6 @@ static enum handler_return long_mode_do_
     }
 
     return HNDL_done;
-
- gp_fault:
-    svm_inject_exception(v, TRAP_gp_fault, 1, 0);
-    return HNDL_exception_raised;
 }
 
 
@@ -449,11 +396,7 @@ static void svm_load_cpu_state(struct vc
     vmcb->cstar      = data->msr_cstar;
     vmcb->sfmask     = data->msr_syscall_mask;
     v->arch.hvm_vcpu.guest_efer = data->msr_efer;
-    vmcb->efer       = data->msr_efer | EFER_SVME;
-    /* VMCB's EFER.LME isn't set unless we're actually in long mode
-     * (see long_mode_do_msr_write()) */
-    if ( !(vmcb->efer & EFER_LMA) )
-        vmcb->efer &= ~EFER_LME;
+    svm_update_guest_efer(v);
 
     hvm_set_guest_time(v, data->tsc);
 }
@@ -543,14 +486,11 @@ static void svm_update_guest_cr(struct v
 
 static void svm_update_guest_efer(struct vcpu *v)
 {
-#ifdef __x86_64__
-    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
-
-    if ( v->arch.hvm_vcpu.guest_efer & EFER_LMA )
-        vmcb->efer |= EFER_LME | EFER_LMA;
-    else
-        vmcb->efer &= ~(EFER_LME | EFER_LMA);
-#endif
+    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+
+    vmcb->efer = (v->arch.hvm_vcpu.guest_efer | EFER_SVME) & ~EFER_LME;
+    if ( vmcb->efer & EFER_LMA )
+        vmcb->efer |= EFER_LME;
 }
 
 static void svm_flush_guest_tlbs(void)
diff -r 96f46954c7f1 -r ff4ff3e3ebbe xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Fri Sep 28 15:05:11 2007 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Fri Sep 28 16:00:44 2007 +0100
@@ -199,42 +199,8 @@ static enum handler_return long_mode_do_
     switch ( ecx )
     {
     case MSR_EFER:
-        /* offending reserved bit will cause #GP */
-        if ( (msr_content & ~(EFER_LME | EFER_LMA | EFER_NX | EFER_SCE)) ||
-             (!cpu_has_nx && (msr_content & EFER_NX)) ||
-             (!cpu_has_syscall && (msr_content & EFER_SCE)) )
-        {
-            gdprintk(XENLOG_WARNING, "Trying to set reserved bit in "
-                     "EFER: %"PRIx64"\n", msr_content);
-            goto gp_fault;
-        }
-
-        if ( (msr_content & EFER_LME)
-             &&  !(v->arch.hvm_vcpu.guest_efer & EFER_LME) )
-        {
-            if ( unlikely(hvm_paging_enabled(v)) )
-            {
-                gdprintk(XENLOG_WARNING,
-                         "Trying to set EFER.LME with paging enabled\n");
-                goto gp_fault;
-            }
-        }
-        else if ( !(msr_content & EFER_LME)
-                  && (v->arch.hvm_vcpu.guest_efer & EFER_LME) )
-        {
-            if ( unlikely(hvm_paging_enabled(v)) )
-            {
-                gdprintk(XENLOG_WARNING,
-                         "Trying to clear EFER.LME with paging enabled\n");
-                goto gp_fault;
-            }
-        }
-
-        if ( (msr_content ^ v->arch.hvm_vcpu.guest_efer) & (EFER_NX|EFER_SCE) )
-            write_efer((read_efer() & ~(EFER_NX|EFER_SCE)) |
-                       (msr_content & (EFER_NX|EFER_SCE)));
-
-        v->arch.hvm_vcpu.guest_efer = msr_content;
+        if ( !hvm_set_efer(msr_content) )
+            goto exception_raised;
         break;
 
     case MSR_FS_BASE:
@@ -285,6 +251,7 @@ static enum handler_return long_mode_do_
     HVM_DBG_LOG(DBG_LEVEL_0, "Not cano address of msr write %x", ecx);
  gp_fault:
     vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
+ exception_raised:
     return HNDL_exception_raised;
 }
 
@@ -380,7 +347,8 @@ static enum handler_return long_mode_do_
     u64 msr_content = 0;
     struct vcpu *v = current;
 
-    switch ( regs->ecx ) {
+    switch ( regs->ecx )
+    {
     case MSR_EFER:
         msr_content = v->arch.hvm_vcpu.guest_efer;
         break;
@@ -398,25 +366,12 @@ static enum handler_return long_mode_do_
 static enum handler_return long_mode_do_msr_write(struct cpu_user_regs *regs)
 {
     u64 msr_content = regs->eax | ((u64)regs->edx << 32);
-    struct vcpu *v = current;
 
     switch ( regs->ecx )
     {
     case MSR_EFER:
-        /* offending reserved bit will cause #GP */
-        if ( (msr_content & ~EFER_NX) ||
-             (!cpu_has_nx && (msr_content & EFER_NX)) )
-        {
-            gdprintk(XENLOG_WARNING, "Trying to set reserved bit in "
-                     "EFER: %"PRIx64"\n", msr_content);
-            vmx_inject_hw_exception(v, TRAP_gp_fault, 0);
+        if ( !hvm_set_efer(msr_content) )
             return HNDL_exception_raised;
-        }
-
-        if ( (msr_content ^ v->arch.hvm_vcpu.guest_efer) & EFER_NX )
-            write_efer((read_efer() & ~EFER_NX) | (msr_content & EFER_NX));
-
-        v->arch.hvm_vcpu.guest_efer = msr_content;
         break;
 
     default:
@@ -1096,6 +1051,10 @@ static void vmx_update_guest_efer(struct
 
     vmx_vmcs_exit(v);
 #endif
+
+    if ( v == current )
+        write_efer((read_efer() & ~(EFER_NX|EFER_SCE)) |
+                   (v->arch.hvm_vcpu.guest_efer & (EFER_NX|EFER_SCE)));
 }
 
 static void vmx_flush_guest_tlbs(void)
diff -r 96f46954c7f1 -r ff4ff3e3ebbe xen/include/asm-x86/hvm/support.h
--- a/xen/include/asm-x86/hvm/support.h Fri Sep 28 15:05:11 2007 +0100
+++ b/xen/include/asm-x86/hvm/support.h Fri Sep 28 16:00:44 2007 +0100
@@ -234,6 +234,7 @@ void hvm_hlt(unsigned long rflags);
 void hvm_hlt(unsigned long rflags);
 void hvm_triple_fault(void);
 
+int hvm_set_efer(uint64_t value);
 int hvm_set_cr0(unsigned long value);
 int hvm_set_cr3(unsigned long value);
 int hvm_set_cr4(unsigned long value);

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.