Skip to contentSkip to conversation

x86: emulate I/O port access breakpoints

PATCH New Jan Beulich 1 participant 1 message Nov 22, 2007

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 x86: emulate I/O port access breakpoints

Emulate the trapping on I/O port accesses when emulating IN/OUT.

Also allow 8-byte breakpoints on x86-64 (and on i686 if the hardware supports them), and tighten the condition for loading debug registers during context switch.

This patch depends on the prior single step injection patch.

xen/arch/x86/domain.c +3 -2
Index: 2007-11-13/xen/arch/x86/domain.c
===================================================================
@@ -42,6 +42,7 @@
 #include <asm/hypercall.h>
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/support.h>
+#include <asm/debugreg.h>
 #include <asm/msr.h>
 #include <asm/nmi.h>
 #include <asm/iommu.h>
@@ -1219,7 +1220,7 @@ static void paravirt_ctxt_switch_from(st
      * 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]) )
+    if ( unlikely(v->arch.guest_context.debugreg[7] & DR7_ACTIVE_MASK) )
         write_debugreg(7, 0);
 }
 
@@ -1234,7 +1235,7 @@ static void paravirt_ctxt_switch_to(stru
     if ( unlikely(cr4 != read_cr4()) )
         write_cr4(cr4);
 
-    if ( unlikely(v->arch.guest_context.debugreg[7]) )
+    if ( unlikely(v->arch.guest_context.debugreg[7] & DR7_ACTIVE_MASK) )
     {
         write_debugreg(0, v->arch.guest_context.debugreg[0]);
         write_debugreg(1, v->arch.guest_context.debugreg[1]);
xen/arch/x86/domctl.c +6 -0
Index: 2007-11-13/xen/arch/x86/domctl.c
===================================================================
@@ -825,12 +825,18 @@ void arch_get_info_guest(struct vcpu *v,
                 c.nat->ctrlreg[1] = xen_pfn_to_cr3(
                     pagetable_get_pfn(v->arch.guest_table_user));
 #endif
+
+            c.nat->debugreg[7] |= c.nat->debugreg[5];
+            c.nat->debugreg[5] = 0;
         }
 #ifdef CONFIG_COMPAT
         else
         {
             l4_pgentry_t *l4e = __va(pagetable_get_paddr(v->arch.guest_table));
             c.cmp->ctrlreg[3] = compat_pfn_to_cr3(l4e_get_pfn(*l4e));
+
+            c.cmp->debugreg[7] |= c.cmp->debugreg[5];
+            c.cmp->debugreg[5] = 0;
         }
 #endif
 
xen/arch/x86/hvm/svm/svm.c +1 -2
Index: 2007-11-13/xen/arch/x86/hvm/svm/svm.c
===================================================================
@@ -34,6 +34,7 @@
 #include <asm/cpufeature.h>
 #include <asm/processor.h>
 #include <asm/types.h>
+#include <asm/debugreg.h>
 #include <asm/msr.h>
 #include <asm/spinlock.h>
 #include <asm/hvm/hvm.h>
@@ -189,8 +190,6 @@ static void __restore_debug_registers(st
  * 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) )
xen/arch/x86/hvm/vmx/vmx.c +1 -2
Index: 2007-11-13/xen/arch/x86/hvm/vmx/vmx.c
===================================================================
@@ -33,6 +33,7 @@
 #include <asm/cpufeature.h>
 #include <asm/processor.h>
 #include <asm/types.h>
+#include <asm/debugreg.h>
 #include <asm/msr.h>
 #include <asm/spinlock.h>
 #include <asm/paging.h>
@@ -434,8 +435,6 @@ static void __restore_debug_registers(st
  * 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. */
xen/arch/x86/traps.c +94 -27

238 lines not on this page · raw message

xen/include/asm-x86/debugreg.h +9 -3
Index: 2007-11-13/xen/include/asm-x86/debugreg.h
===================================================================
@@ -33,11 +33,13 @@
 
 #define DR_RW_EXECUTE (0x0)   /* Settings for the access types to trap on */
 #define DR_RW_WRITE (0x1)
+#define DR_IO (0x2)
 #define DR_RW_READ (0x3)
 
 #define DR_LEN_1 (0x0) /* Settings for data length to trap on */
 #define DR_LEN_2 (0x4)
 #define DR_LEN_4 (0xC)
+#define DR_LEN_8 (0x8)
 
 /* The low byte to the control register determine which registers are
    enabled.  There are 4 fields of two bits.  One bit is "local", meaning
@@ -53,12 +55,16 @@
 #define DR_LOCAL_ENABLE_MASK (0x55)  /* Set  local bits for all 4 regs */
 #define DR_GLOBAL_ENABLE_MASK (0xAA) /* Set global bits for all 4 regs */
 
+#define DR7_ACTIVE_MASK (DR_LOCAL_ENABLE_MASK|DR_GLOBAL_ENABLE_MASK)
+
 /* The second byte to the control register has a few special things.
    We can slow the instruction pipeline for instructions coming via the
    gdt or the ldt if we want to.  I am not sure why this is an advantage */
 
-#define DR_CONTROL_RESERVED (~0xFFFF03FFUL) /* Reserved by Intel */
-#define DR_LOCAL_SLOWDOWN (0x100)   /* Local slow the pipeline */
-#define DR_GLOBAL_SLOWDOWN (0x200)  /* Global slow the pipeline */
+#define DR_CONTROL_RESERVED_ZERO (~0xFFFF23FFUL) /* Reserved, read as zero */
+#define DR_CONTROL_RESERVED_ONE  ( 0x00000400  ) /* Reserved, read as one */
+#define DR_LOCAL_EXACT_ENABLE    ( 0x00000100  ) /* Local exact enable */
+#define DR_GLOBAL_EXACT_ENABLE   ( 0x00000200  ) /* Global exact enable */
+#define DR_GENERAL_DETECT        ( 0x00002000  ) /* General detect enable */
 
 #endif /* _X86_DEBUGREG_H */