WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-3.1-testing] x86: Fix various problems with debug-r

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-3.1-testing] x86: Fix various problems with debug-register handling.
From: "Xen patchbot-3.1-testing" <patchbot-3.1-testing@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 02 Nov 2007 07:30:16 -0700
Delivery-date: Fri, 02 Nov 2007 07:30:47 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir@xxxxxxxxxxxxx>
# Date 1193934398 0
# Node ID 27347d6d73a359aa8aece2ad10d9cc8b924b3990
# Parent  86e6b3f8d26e3d03e834636c79625637c145aeba
x86: Fix various problems with debug-register handling.
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
xen-unstable changeset:   16287:338f3c34e65605d9beb96176ef1a71c1262dbf14
xen-unstable date:        Thu Nov 01 16:16:25 2007 +0000
---
 xen/arch/x86/domain.c              |   42 ++++++++++++----------
 xen/arch/x86/hvm/svm/svm.c         |   70 +++++++++++++++++--------------------
 xen/arch/x86/hvm/svm/vmcb.c        |    2 -
 xen/arch/x86/hvm/vmx/vmx.c         |   69 ++++++++++++++++--------------------
 xen/arch/x86/traps.c               |   38 ++++++++++----------
 xen/include/asm-x86/hvm/svm/vmcb.h |    7 ---
 xen/include/asm-x86/processor.h    |    9 ++++
 7 files changed, 118 insertions(+), 119 deletions(-)

diff -r 86e6b3f8d26e -r 27347d6d73a3 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Wed Oct 31 16:22:12 2007 +0000
+++ b/xen/arch/x86/domain.c     Thu Nov 01 16:26:38 2007 +0000
@@ -631,13 +631,13 @@ int arch_set_info_guest(
         hvm_load_cpu_guest_regs(v, &v->arch.guest_context.user_regs);
     }
 
-    if ( v->is_initialised )
-        goto out;
-
     memset(v->arch.guest_context.debugreg, 0,
            sizeof(v->arch.guest_context.debugreg));
     for ( i = 0; i < 8; i++ )
         (void)set_debugreg(v, i, c(debugreg[i]));
+
+    if ( v->is_initialised )
+        goto out;
 
     if ( v->vcpu_id == 0 )
         d->vm_assist = c(vm_assist);
@@ -1156,16 +1156,32 @@ static void paravirt_ctxt_switch_from(st
 static void paravirt_ctxt_switch_from(struct vcpu *v)
 {
     save_segments(v);
+
+    /*
+     * Disable debug breakpoints. We do this aggressively because if we switch
+     * to an HVM guest we may load DR0-DR3 with values that can cause #DE
+     * inside Xen, before we get a chance to reload DR7, and this cannot always
+     * safely be handled.
+     */
+    if ( unlikely(v->arch.guest_context.debugreg[7]) )
+        write_debugreg(7, 0);
 }
 
 static void paravirt_ctxt_switch_to(struct vcpu *v)
 {
     set_int80_direct_trap(v);
     switch_kernel_stack(v);
-}
-
-#define loaddebug(_v,_reg) \
-    __asm__ __volatile__ ("mov %0,%%db" #_reg : : "r" ((_v)->debugreg[_reg]))
+
+    if ( unlikely(v->arch.guest_context.debugreg[7]) )
+    {
+        write_debugreg(0, v->arch.guest_context.debugreg[0]);
+        write_debugreg(1, v->arch.guest_context.debugreg[1]);
+        write_debugreg(2, v->arch.guest_context.debugreg[2]);
+        write_debugreg(3, v->arch.guest_context.debugreg[3]);
+        write_debugreg(6, v->arch.guest_context.debugreg[6]);
+        write_debugreg(7, v->arch.guest_context.debugreg[7]);
+    }
+}
 
 static void __context_switch(void)
 {
@@ -1191,18 +1207,6 @@ static void __context_switch(void)
         memcpy(stack_regs,
                &n->arch.guest_context.user_regs,
                CTXT_SWITCH_STACK_BYTES);
-
-        /* Maybe switch the debug registers. */
-        if ( unlikely(n->arch.guest_context.debugreg[7]) )
-        {
-            loaddebug(&n->arch.guest_context, 0);
-            loaddebug(&n->arch.guest_context, 1);
-            loaddebug(&n->arch.guest_context, 2);
-            loaddebug(&n->arch.guest_context, 3);
-            /* no 4 and 5 */
-            loaddebug(&n->arch.guest_context, 6);
-            loaddebug(&n->arch.guest_context, 7);
-        }
         n->arch.ctxt_switch_to(n);
     }
 
diff -r 86e6b3f8d26e -r 27347d6d73a3 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Wed Oct 31 16:22:12 2007 +0000
+++ b/xen/arch/x86/hvm/svm/svm.c        Thu Nov 01 16:26:38 2007 +0000
@@ -247,12 +247,6 @@ static int long_mode_do_msr_write(struct
     return 0;
 }
 
-
-#define loaddebug(_v,_reg) \
-    asm volatile ("mov %0,%%db" #_reg : : "r" ((_v)->debugreg[_reg]))
-#define savedebug(_v,_reg) \
-    asm volatile ("mov %%db" #_reg ",%0" : : "r" ((_v)->debugreg[_reg]))
-
 static void svm_save_dr(struct vcpu *v)
 {
     struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
@@ -262,26 +256,45 @@ static void svm_save_dr(struct vcpu *v)
 
     /* Clear the DR dirty flag and re-enable intercepts for DR accesses. */
     v->arch.hvm_vcpu.flag_dr_dirty = 0;
-    v->arch.hvm_svm.vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES;
-
-    savedebug(&v->arch.guest_context, 0);
-    savedebug(&v->arch.guest_context, 1);
-    savedebug(&v->arch.guest_context, 2);
-    savedebug(&v->arch.guest_context, 3);
+    v->arch.hvm_svm.vmcb->dr_intercepts = ~0u;
+
+    v->arch.guest_context.debugreg[0] = read_debugreg(0);
+    v->arch.guest_context.debugreg[1] = read_debugreg(1);
+    v->arch.guest_context.debugreg[2] = read_debugreg(2);
+    v->arch.guest_context.debugreg[3] = read_debugreg(3);
     v->arch.guest_context.debugreg[6] = vmcb->dr6;
     v->arch.guest_context.debugreg[7] = vmcb->dr7;
 }
 
-
 static void __restore_debug_registers(struct vcpu *v)
 {
-    loaddebug(&v->arch.guest_context, 0);
-    loaddebug(&v->arch.guest_context, 1);
-    loaddebug(&v->arch.guest_context, 2);
-    loaddebug(&v->arch.guest_context, 3);
-    /* DR6 and DR7 are loaded from the VMCB. */
-}
-
+    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+
+    ASSERT(!v->arch.hvm_vcpu.flag_dr_dirty);
+    v->arch.hvm_vcpu.flag_dr_dirty = 1;
+    vmcb->dr_intercepts = 0;
+
+    write_debugreg(0, v->arch.guest_context.debugreg[0]);
+    write_debugreg(1, v->arch.guest_context.debugreg[1]);
+    write_debugreg(2, v->arch.guest_context.debugreg[2]);
+    write_debugreg(3, v->arch.guest_context.debugreg[3]);
+    vmcb->dr6 = v->arch.guest_context.debugreg[6];
+    vmcb->dr7 = v->arch.guest_context.debugreg[7];
+}
+
+/*
+ * DR7 is saved and restored on every vmexit.  Other debug registers only
+ * need to be restored if their value is going to affect execution -- i.e.,
+ * if one of the breakpoints is enabled.  So mask out all bits that don't
+ * enable some breakpoint functionality.
+ */
+#define DR7_ACTIVE_MASK 0xff
+
+static void svm_restore_dr(struct vcpu *v)
+{
+    if ( unlikely(v->arch.guest_context.debugreg[7] & DR7_ACTIVE_MASK) )
+        __restore_debug_registers(v);
+}
 
 int svm_vmcb_save(struct vcpu *v, struct hvm_hw_cpu *c)
 {
@@ -523,9 +536,6 @@ int svm_vmcb_restore(struct vcpu *v, str
         vmcb->h_cr3 = pagetable_get_paddr(v->domain->arch.phys_table);
     }
 
-    vmcb->dr6 = c->dr6;
-    vmcb->dr7 = c->dr7;
-
     if ( c->pending_valid ) 
     {
         gdprintk(XENLOG_INFO, "Re-injecting 0x%"PRIx32", 0x%"PRIx32"\n",
@@ -611,12 +621,6 @@ static int svm_load_vmcb_ctxt(struct vcp
     }
 
     return 0;
-}
-
-static void svm_restore_dr(struct vcpu *v)
-{
-    if ( unlikely(v->arch.guest_context.debugreg[7] & 0xFF) )
-        __restore_debug_registers(v);
 }
 
 static int svm_interrupts_enabled(struct vcpu *v)
@@ -1257,16 +1261,8 @@ static void set_reg(
 
 static void svm_dr_access(struct vcpu *v, struct cpu_user_regs *regs)
 {
-    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
-
     HVMTRACE_0D(DR_WRITE, v);
-
-    v->arch.hvm_vcpu.flag_dr_dirty = 1;
-
     __restore_debug_registers(v);
-
-    /* allow the guest full access to the debug registers */
-    vmcb->dr_intercepts = 0;
 }
 
 
diff -r 86e6b3f8d26e -r 27347d6d73a3 xen/arch/x86/hvm/svm/vmcb.c
--- a/xen/arch/x86/hvm/svm/vmcb.c       Wed Oct 31 16:22:12 2007 +0000
+++ b/xen/arch/x86/hvm/svm/vmcb.c       Thu Nov 01 16:26:38 2007 +0000
@@ -127,7 +127,7 @@ static int construct_vmcb(struct vcpu *v
         GENERAL2_INTERCEPT_SKINIT | GENERAL2_INTERCEPT_RDTSCP;
 
     /* Intercept all debug-register writes. */
-    vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES;
+    vmcb->dr_intercepts = ~0u;
 
     /* Intercept all control-register accesses, except to CR2. */
     vmcb->cr_intercepts = ~(CR_INTERCEPT_CR2_READ | CR_INTERCEPT_CR2_WRITE);
diff -r 86e6b3f8d26e -r 27347d6d73a3 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Wed Oct 31 16:22:12 2007 +0000
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Thu Nov 01 16:26:38 2007 +0000
@@ -471,11 +471,6 @@ static int long_mode_do_msr_write(struct
 
 #endif /* __i386__ */
 
-#define loaddebug(_v,_reg)  \
-    __asm__ __volatile__ ("mov %0,%%db" #_reg : : "r" ((_v)->debugreg[_reg]))
-#define savedebug(_v,_reg)  \
-    __asm__ __volatile__ ("mov %%db" #_reg ",%0" : : "r" 
((_v)->debugreg[_reg]))
-
 static int vmx_guest_x86_mode(struct vcpu *v)
 {
     unsigned int cs_ar_bytes;
@@ -503,23 +498,41 @@ static void vmx_save_dr(struct vcpu *v)
     v->arch.hvm_vmx.exec_control |= CPU_BASED_MOV_DR_EXITING;
     __vmwrite(CPU_BASED_VM_EXEC_CONTROL, v->arch.hvm_vmx.exec_control);
 
-    savedebug(&v->arch.guest_context, 0);
-    savedebug(&v->arch.guest_context, 1);
-    savedebug(&v->arch.guest_context, 2);
-    savedebug(&v->arch.guest_context, 3);
-    savedebug(&v->arch.guest_context, 6);
+    v->arch.guest_context.debugreg[0] = read_debugreg(0);
+    v->arch.guest_context.debugreg[1] = read_debugreg(1);
+    v->arch.guest_context.debugreg[2] = read_debugreg(2);
+    v->arch.guest_context.debugreg[3] = read_debugreg(3);
+    v->arch.guest_context.debugreg[6] = read_debugreg(6);
+    /* DR7 must be saved as it is used by vmx_restore_dr(). */
     v->arch.guest_context.debugreg[7] = __vmread(GUEST_DR7);
 }
 
 static void __restore_debug_registers(struct vcpu *v)
 {
-    loaddebug(&v->arch.guest_context, 0);
-    loaddebug(&v->arch.guest_context, 1);
-    loaddebug(&v->arch.guest_context, 2);
-    loaddebug(&v->arch.guest_context, 3);
-    /* No 4 and 5 */
-    loaddebug(&v->arch.guest_context, 6);
+    ASSERT(!v->arch.hvm_vcpu.flag_dr_dirty);
+    v->arch.hvm_vcpu.flag_dr_dirty = 1;
+
+    write_debugreg(0, v->arch.guest_context.debugreg[0]);
+    write_debugreg(1, v->arch.guest_context.debugreg[1]);
+    write_debugreg(2, v->arch.guest_context.debugreg[2]);
+    write_debugreg(3, v->arch.guest_context.debugreg[3]);
+    write_debugreg(6, v->arch.guest_context.debugreg[6]);
     /* DR7 is loaded from the VMCS. */
+}
+
+/*
+ * DR7 is saved and restored on every vmexit.  Other debug registers only
+ * need to be restored if their value is going to affect execution -- i.e.,
+ * if one of the breakpoints is enabled.  So mask out all bits that don't
+ * enable some breakpoint functionality.
+ */
+#define DR7_ACTIVE_MASK 0xff
+
+static void vmx_restore_dr(struct vcpu *v)
+{
+    /* NB. __vmread() is not usable here, so we cannot read from the VMCS. */
+    if ( unlikely(v->arch.guest_context.debugreg[7] & DR7_ACTIVE_MASK) )
+        __restore_debug_registers(v);
 }
 
 void vmx_vmcs_save(struct vcpu *v, struct hvm_hw_cpu *c)
@@ -858,21 +871,6 @@ static int vmx_load_vmcs_ctxt(struct vcp
     }
 
     return 0;
-}
-
-/*
- * DR7 is saved and restored on every vmexit.  Other debug registers only
- * need to be restored if their value is going to affect execution -- i.e.,
- * if one of the breakpoints is enabled.  So mask out all bits that don't
- * enable some breakpoint functionality.
- */
-#define DR7_ACTIVE_MASK 0xff
-
-static void vmx_restore_dr(struct vcpu *v)
-{
-    /* NB. __vmread() is not usable here, so we cannot read from the VMCS. */
-    if ( unlikely(v->arch.guest_context.debugreg[7] & DR7_ACTIVE_MASK) )
-        __restore_debug_registers(v);
 }
 
 static void vmx_ctxt_switch_from(struct vcpu *v)
@@ -1462,15 +1460,12 @@ static void vmx_dr_access(unsigned long 
 
     HVMTRACE_0D(DR_WRITE, v);
 
-    v->arch.hvm_vcpu.flag_dr_dirty = 1;
-
-    /* We could probably be smarter about this */
-    __restore_debug_registers(v);
+    if ( !v->arch.hvm_vcpu.flag_dr_dirty )
+        __restore_debug_registers(v);
 
     /* Allow guest direct access to DR registers */
     v->arch.hvm_vmx.exec_control &= ~CPU_BASED_MOV_DR_EXITING;
-    __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
-              v->arch.hvm_vmx.exec_control);
+    __vmwrite(CPU_BASED_VM_EXEC_CONTROL, v->arch.hvm_vmx.exec_control);
 }
 
 /*
diff -r 86e6b3f8d26e -r 27347d6d73a3 xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c      Wed Oct 31 16:22:12 2007 +0000
+++ b/xen/arch/x86/traps.c      Thu Nov 01 16:26:38 2007 +0000
@@ -2008,18 +2008,7 @@ asmlinkage int math_state_restore(struct
 
 asmlinkage int do_debug(struct cpu_user_regs *regs)
 {
-    unsigned long condition;
     struct vcpu *v = current;
-
-    __asm__ __volatile__("mov %%db6,%0" : "=r" (condition));
-
-    /* Mask out spurious debug traps due to lazy DR7 setting */
-    if ( (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) &&
-         (v->arch.guest_context.debugreg[7] == 0) )
-    {
-        __asm__("mov %0,%%db7" : : "r" (0UL));
-        goto out;
-    }
 
     DEBUGGER_trap_entry(TRAP_debug, regs);
 
@@ -2037,7 +2026,7 @@ asmlinkage int do_debug(struct cpu_user_
     } 
 
     /* Save debug status register where guest OS can peek at it */
-    v->arch.guest_context.debugreg[6] = condition;
+    v->arch.guest_context.debugreg[6] = read_debugreg(6);
 
     return do_guest_trap(TRAP_debug, regs, 0);
 
@@ -2186,25 +2175,25 @@ long set_debugreg(struct vcpu *p, int re
         if ( !access_ok(value, sizeof(long)) )
             return -EPERM;
         if ( p == current ) 
-            __asm__ ( "mov %0, %%db0" : : "r" (value) );
+            write_debugreg(0, value);
         break;
     case 1: 
         if ( !access_ok(value, sizeof(long)) )
             return -EPERM;
         if ( p == current ) 
-            __asm__ ( "mov %0, %%db1" : : "r" (value) );
+            write_debugreg(1, value);
         break;
     case 2: 
         if ( !access_ok(value, sizeof(long)) )
             return -EPERM;
         if ( p == current ) 
-            __asm__ ( "mov %0, %%db2" : : "r" (value) );
+            write_debugreg(2, value);
         break;
     case 3:
         if ( !access_ok(value, sizeof(long)) )
             return -EPERM;
         if ( p == current ) 
-            __asm__ ( "mov %0, %%db3" : : "r" (value) );
+            write_debugreg(3, value);
         break;
     case 6:
         /*
@@ -2214,7 +2203,7 @@ long set_debugreg(struct vcpu *p, int re
         value &= 0xffffefff; /* reserved bits => 0 */
         value |= 0xffff0ff0; /* reserved bits => 1 */
         if ( p == current ) 
-            __asm__ ( "mov %0, %%db6" : : "r" (value) );
+            write_debugreg(6, value);
         break;
     case 7:
         /*
@@ -2233,9 +2222,22 @@ long set_debugreg(struct vcpu *p, int re
             if ( (value & (1<<13)) != 0 ) return -EPERM;
             for ( i = 0; i < 16; i += 2 )
                 if ( ((value >> (i+16)) & 3) == 2 ) return -EPERM;
+            /*
+             * If DR7 was previously clear then we need to load all other
+             * debug registers at this point as they were not restored during
+             * context switch.
+             */
+            if ( (p == current) && (p->arch.guest_context.debugreg[7] == 0) )
+            {
+                write_debugreg(0, p->arch.guest_context.debugreg[0]);
+                write_debugreg(1, p->arch.guest_context.debugreg[1]);
+                write_debugreg(2, p->arch.guest_context.debugreg[2]);
+                write_debugreg(3, p->arch.guest_context.debugreg[3]);
+                write_debugreg(6, p->arch.guest_context.debugreg[6]);
+            }
         }
         if ( p == current ) 
-            __asm__ ( "mov %0, %%db7" : : "r" (value) );
+            write_debugreg(7, value);
         break;
     default:
         return -EINVAL;
diff -r 86e6b3f8d26e -r 27347d6d73a3 xen/include/asm-x86/hvm/svm/vmcb.h
--- a/xen/include/asm-x86/hvm/svm/vmcb.h        Wed Oct 31 16:22:12 2007 +0000
+++ b/xen/include/asm-x86/hvm/svm/vmcb.h        Thu Nov 01 16:26:38 2007 +0000
@@ -150,13 +150,6 @@ enum DRInterceptBits
     DR_INTERCEPT_DR14_WRITE = 1 << 30,
     DR_INTERCEPT_DR15_WRITE = 1 << 31,
 };
-
-/* for lazy save/restore we'd like to intercept all DR writes */
-#define DR_INTERCEPT_ALL_WRITES \
-    (DR_INTERCEPT_DR0_WRITE|DR_INTERCEPT_DR1_WRITE|DR_INTERCEPT_DR2_WRITE \
-    |DR_INTERCEPT_DR3_WRITE|DR_INTERCEPT_DR4_WRITE|DR_INTERCEPT_DR5_WRITE \
-    |DR_INTERCEPT_DR6_WRITE|DR_INTERCEPT_DR7_WRITE) 
-
 
 enum VMEXIT_EXITCODE
 {
diff -r 86e6b3f8d26e -r 27347d6d73a3 xen/include/asm-x86/processor.h
--- a/xen/include/asm-x86/processor.h   Wed Oct 31 16:22:12 2007 +0000
+++ b/xen/include/asm-x86/processor.h   Thu Nov 01 16:26:38 2007 +0000
@@ -484,6 +484,15 @@ long set_gdt(struct vcpu *d,
              unsigned long *frames, 
              unsigned int entries);
 
+#define write_debugreg(reg, val) do {                       \
+    unsigned long __val = val;                              \
+    asm volatile ( "mov %0,%%db" #reg : : "r" (__val) );    \
+} while (0)
+#define read_debugreg(reg) ({                               \
+    unsigned long __val;                                    \
+    asm volatile ( "mov %%db" #reg ",%0" : "=r" (__val) );  \
+    __val;                                                  \
+})
 long set_debugreg(struct vcpu *p, int reg, unsigned long value);
 
 struct microcode_header {

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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-3.1-testing] x86: Fix various problems with debug-register handling., Xen patchbot-3.1-testing <=