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-unstable] x86: single step after instruction emulat

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] x86: single step after instruction emulation
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 23 Nov 2007 07:40:09 -0800
Delivery-date: Fri, 23 Nov 2007 07:40:45 -0800
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.fraser@xxxxxxxxxx>
# Date 1195756127 0
# Node ID fd3f6d814f6dca9f46c95a5b808e2f47bdcd1715
# Parent  ae087a0fa2c929842293b5c26dcd6acb9bdd748d
x86: single step after instruction emulation

Inject single step trap after emulating instructions if guest's
EFLAGS.TF is set.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxxxxx>
---
 xen/arch/x86/hvm/io.c             |    2 
 xen/arch/x86/hvm/platform.c       |    3 -
 xen/arch/x86/hvm/svm/svm.c        |  101 +++++++++++++++++++++-----------------
 xen/arch/x86/hvm/vmx/vmx.c        |   37 +++++++++++--
 xen/arch/x86/traps.c              |   20 +++++--
 xen/arch/x86/x86_emulate.c        |    1 
 xen/include/asm-x86/hvm/support.h |    2 
 xen/include/asm-x86/hvm/vmx/vmx.h |    6 +-
 8 files changed, 108 insertions(+), 64 deletions(-)

diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/arch/x86/hvm/io.c
--- a/xen/arch/x86/hvm/io.c     Thu Nov 22 17:44:51 2007 +0000
+++ b/xen/arch/x86/hvm/io.c     Thu Nov 22 18:28:47 2007 +0000
@@ -863,6 +863,8 @@ void hvm_io_assist(void)
     /* Copy register changes back into current guest state. */
     regs->eflags &= ~X86_EFLAGS_RF;
     memcpy(guest_cpu_user_regs(), regs, HVM_CONTEXT_STACK_BYTES);
+    if ( regs->eflags & X86_EFLAGS_TF )
+        hvm_inject_exception(TRAP_debug, HVM_DELIVER_NO_ERROR_CODE, 0);
 
  out:
     vcpu_end_shutdown_deferral(v);
diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/arch/x86/hvm/platform.c
--- a/xen/arch/x86/hvm/platform.c       Thu Nov 22 17:44:51 2007 +0000
+++ b/xen/arch/x86/hvm/platform.c       Thu Nov 22 18:28:47 2007 +0000
@@ -1061,7 +1061,6 @@ void handle_mmio(unsigned long gpa)
     }
 
     regs->eip += inst_len; /* advance %eip */
-    regs->eflags &= ~X86_EFLAGS_RF;
 
     switch ( mmio_op->instr ) {
     case INSTR_MOV:
@@ -1121,7 +1120,6 @@ void handle_mmio(unsigned long gpa)
             /* The guest does not have the non-mmio address mapped. 
              * Need to send in a page fault */
             regs->eip -= inst_len; /* do not advance %eip */
-            regs->eflags |= X86_EFLAGS_RF; /* RF was set by original #PF */
             hvm_inject_exception(TRAP_page_fault, pfec, addr);
             return;
         }
@@ -1150,7 +1148,6 @@ void handle_mmio(unsigned long gpa)
                         /* Failed on the page-spanning copy.  Inject PF into
                          * the guest for the address where we failed */
                         regs->eip -= inst_len; /* do not advance %eip */
-                        regs->eflags |= X86_EFLAGS_RF; /* RF was set by #PF */
                         /* Must set CR2 at the failing address */ 
                         addr += size - rv;
                         gdprintk(XENLOG_DEBUG, "Pagefault on non-io side of a "
diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Thu Nov 22 17:44:51 2007 +0000
+++ b/xen/arch/x86/hvm/svm/svm.c        Thu Nov 22 18:28:47 2007 +0000
@@ -64,6 +64,9 @@ static int svm_reset_to_realmode(
 static int svm_reset_to_realmode(
     struct vcpu *v, struct cpu_user_regs *regs);
 static void svm_update_guest_cr(struct vcpu *v, unsigned int cr);
+static void svm_update_guest_efer(struct vcpu *v);
+static void svm_inject_exception(
+    unsigned int trapnr, int errcode, unsigned long cr2);
 
 /* va of hardware host save area     */
 static void *hsa[NR_CPUS] __read_mostly;
@@ -71,15 +74,15 @@ 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, unsigned int inst_len)
 {
+    struct vcpu *curr = current;
+
     if ( unlikely((inst_len == 0) || (inst_len > 15)) )
     {
         gdprintk(XENLOG_ERR, "Bad instruction length %u\n", inst_len);
-        domain_crash(current->domain);
+        domain_crash(curr->domain);
         return;
     }
 
@@ -88,28 +91,10 @@ static void inline __update_guest_eip(
     regs->eip += inst_len;
     regs->eflags &= ~X86_EFLAGS_RF;
 
-    current->arch.hvm_svm.vmcb->interrupt_shadow = 0;
-}
-
-static void svm_inject_exception(
-    struct vcpu *v, int trap, int ev, int error_code)
-{
-    eventinj_t event;
-    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
-
-    if ( trap == TRAP_page_fault )
-        HVMTRACE_2D(PF_INJECT, v, v->arch.hvm_vcpu.guest_cr[2], error_code);
-    else
-        HVMTRACE_2D(INJ_EXC, v, trap, error_code);
-
-    event.bytes = 0;            
-    event.fields.v = 1;
-    event.fields.type = X86_EVENTTYPE_HW_EXCEPTION;
-    event.fields.vector = trap;
-    event.fields.ev = ev;
-    event.fields.errorcode = error_code;
-
-    vmcb->eventinj = event;
+    curr->arch.hvm_svm.vmcb->interrupt_shadow = 0;
+
+    if ( regs->eflags & X86_EFLAGS_TF )
+        svm_inject_exception(TRAP_debug, HVM_DELIVER_NO_ERROR_CODE, 0);
 }
 
 static void svm_cpu_down(void)
@@ -171,7 +156,9 @@ static void __restore_debug_registers(st
 {
     struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
 
-    ASSERT(!v->arch.hvm_vcpu.flag_dr_dirty);
+    if ( v->arch.hvm_vcpu.flag_dr_dirty )
+        return;
+
     v->arch.hvm_vcpu.flag_dr_dirty = 1;
     vmcb->dr_intercepts = 0;
 
@@ -868,13 +855,38 @@ static void svm_vcpu_destroy(struct vcpu
     svm_destroy_vmcb(v);
 }
 
-static void svm_hvm_inject_exception(
+static void svm_inject_exception(
     unsigned int trapnr, int errcode, unsigned long cr2)
 {
-    struct vcpu *v = current;
+    struct vcpu *curr = current;
+    struct vmcb_struct *vmcb = curr->arch.hvm_svm.vmcb;
+    eventinj_t event;
+
+    event.bytes = 0;
+    event.fields.v = 1;
+    event.fields.type = X86_EVENTTYPE_HW_EXCEPTION;
+    event.fields.vector = trapnr;
+    event.fields.ev = (errcode != HVM_DELIVER_NO_ERROR_CODE);
+    event.fields.errorcode = errcode;
+
+    vmcb->eventinj = event;
+
     if ( trapnr == TRAP_page_fault )
-        v->arch.hvm_svm.vmcb->cr2 = v->arch.hvm_vcpu.guest_cr[2] = cr2;
-    svm_inject_exception(v, trapnr, (errcode != -1), errcode);
+    {
+        vmcb->cr2 = curr->arch.hvm_vcpu.guest_cr[2] = cr2;
+        HVMTRACE_2D(PF_INJECT, curr, curr->arch.hvm_vcpu.guest_cr[2], errcode);
+    }
+    else
+    {
+        HVMTRACE_2D(INJ_EXC, curr, trapnr, errcode);
+    }
+
+    if ( (trapnr == TRAP_debug) &&
+         (guest_cpu_user_regs()->eflags & X86_EFLAGS_TF) )
+    {
+        __restore_debug_registers(curr);
+        vmcb->dr6 |= 0x4000;
+    }
 }
 
 static int svm_event_pending(struct vcpu *v)
@@ -904,7 +916,7 @@ static struct hvm_function_table svm_fun
     .update_vtpr          = svm_update_vtpr,
     .stts                 = svm_stts,
     .set_tsc_offset       = svm_set_tsc_offset,
-    .inject_exception     = svm_hvm_inject_exception,
+    .inject_exception     = svm_inject_exception,
     .init_ap_context      = svm_init_ap_context,
     .init_hypercall_page  = svm_init_hypercall_page,
     .event_pending        = svm_event_pending
@@ -1274,7 +1286,7 @@ static int svm_get_io_address(
         if (!seg)               /* If no prefix, used DS. */
             seg = &vmcb->ds;
         if (!long_mode && (seg->attr.fields.type & 0xa) == 0x8) {
-            svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+            svm_inject_exception(TRAP_gp_fault, 0, 0);
             return 0;
         }
     }
@@ -1283,7 +1295,7 @@ static int svm_get_io_address(
         reg = regs->edi;
         seg = &vmcb->es;        /* Note: This is ALWAYS ES. */
         if (!long_mode && (seg->attr.fields.type & 0xa) != 0x2) {
-            svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+            svm_inject_exception(TRAP_gp_fault, 0, 0);
             return 0;
         }
     }
@@ -1291,7 +1303,7 @@ static int svm_get_io_address(
     /* If the segment isn't present, give GP fault! */
     if (!long_mode && !seg->attr.fields.p) 
     {
-        svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+        svm_inject_exception(TRAP_gp_fault, 0, 0);
         return 0;
     }
 
@@ -1316,7 +1328,7 @@ static int svm_get_io_address(
             *addr + size - 1 > seg->limit :
             *addr <= seg->limit)
         {
-            svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+            svm_inject_exception(TRAP_gp_fault, 0, 0);
             return 0;
         }
 
@@ -1371,7 +1383,7 @@ static int svm_get_io_address(
         if (!is_canonical_address(*addr) ||
             !is_canonical_address(*addr + size - 1))
         {
-            svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+            svm_inject_exception(TRAP_gp_fault, 0, 0);
             return 0;
         }
         if (*count > (1UL << 48) / size)
@@ -1472,7 +1484,7 @@ static void svm_io_instruction(struct vc
         {
             /* The guest does not have the RAM address mapped. 
              * Need to send in a page fault */
-            svm_hvm_inject_exception(TRAP_page_fault, pfec, addr);
+            svm_inject_exception(TRAP_page_fault, pfec, addr);
             return;
         }
         paddr = (paddr_t)gfn << PAGE_SHIFT | (addr & ~PAGE_MASK);
@@ -1500,7 +1512,7 @@ static void svm_io_instruction(struct vc
                         addr += size - rv;
                         gdprintk(XENLOG_DEBUG, "Pagefault reading non-io side "
                                  "of a page-spanning PIO: va=%#lx\n", addr);
-                        svm_hvm_inject_exception(TRAP_page_fault, 0, addr);
+                        svm_inject_exception(TRAP_page_fault, 0, addr);
                         return;
                     }
                 }
@@ -1796,7 +1808,7 @@ static void svm_do_msr_access(
             break;
 
         case MSR_K8_VM_HSAVE_PA:
-            svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+            svm_inject_exception(TRAP_gp_fault, 0, 0);
             break;
 
         case MSR_IA32_MCG_CAP:
@@ -1839,7 +1851,7 @@ static void svm_do_msr_access(
                 regs->edx = edx;
                 goto done;
             }
-            svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+            svm_inject_exception(TRAP_gp_fault, 0, 0);
             return;
         }
         regs->eax = msr_content & 0xFFFFFFFF;
@@ -1870,7 +1882,7 @@ static void svm_do_msr_access(
             break;
 
         case MSR_K8_VM_HSAVE_PA:
-            svm_inject_exception(v, TRAP_gp_fault, 1, 0);
+            svm_inject_exception(TRAP_gp_fault, 0, 0);
             break;
 
         case MSR_IA32_DEBUGCTLMSR:
@@ -1931,7 +1943,7 @@ static void svm_vmexit_do_hlt(struct vmc
     inst_len = __get_instruction_length(curr, INSTR_HLT, NULL);
     __update_guest_eip(regs, inst_len);
 
-    /* Check for interrupt not handled or new interrupt. */
+    /* Check for pending exception or new interrupt. */
     if ( vmcb->eventinj.fields.v ||
          ((intack.source != hvm_intsrc_none) &&
           !svm_interrupt_blocked(current, intack)) )
@@ -2197,8 +2209,7 @@ asmlinkage void svm_vmexit_handler(struc
             break;
         }
 
-        v->arch.hvm_vcpu.guest_cr[2] = vmcb->cr2 = va;
-        svm_inject_exception(v, TRAP_page_fault, 1, regs->error_code);
+        svm_inject_exception(TRAP_page_fault, regs->error_code, va);
         break;
     }
 
@@ -2296,7 +2307,7 @@ asmlinkage void svm_vmexit_handler(struc
     case VMEXIT_STGI:
     case VMEXIT_CLGI:
     case VMEXIT_SKINIT:
-        svm_inject_exception(v, TRAP_invalid_op, 0, 0);
+        svm_inject_exception(TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE, 0);
         break;
 
     case VMEXIT_NPF:
diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Thu Nov 22 17:44:51 2007 +0000
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Thu Nov 22 18:28:47 2007 +0000
@@ -14,7 +14,6 @@
  * You should have received a copy of the GNU General Public License along with
  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
  */
 
 #include <xen/config.h>
@@ -417,7 +416,9 @@ static void vmx_save_dr(struct vcpu *v)
 
 static void __restore_debug_registers(struct vcpu *v)
 {
-    ASSERT(!v->arch.hvm_vcpu.flag_dr_dirty);
+    if ( v->arch.hvm_vcpu.flag_dr_dirty )
+        return;
+
     v->arch.hvm_vcpu.flag_dr_dirty = 1;
 
     write_debugreg(0, v->arch.guest_context.debugreg[0]);
@@ -1102,10 +1103,19 @@ static void vmx_inject_exception(
 static void vmx_inject_exception(
     unsigned int trapnr, int errcode, unsigned long cr2)
 {
-    struct vcpu *v = current;
-    vmx_inject_hw_exception(v, trapnr, errcode);
+    struct vcpu *curr = current;
+
+    vmx_inject_hw_exception(curr, trapnr, errcode);
+
     if ( trapnr == TRAP_page_fault )
-        v->arch.hvm_vcpu.guest_cr[2] = cr2;
+        curr->arch.hvm_vcpu.guest_cr[2] = cr2;
+
+    if ( (trapnr == TRAP_debug) &&
+         (guest_cpu_user_regs()->eflags & X86_EFLAGS_TF) )
+    {
+        __restore_debug_registers(curr);
+        write_debugreg(6, read_debugreg(6) | 0x4000);
+    }
 }
 
 static void vmx_update_vtpr(struct vcpu *v, unsigned long value)
@@ -1211,6 +1221,9 @@ static void __update_guest_eip(unsigned 
         x &= ~(VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS);
         __vmwrite(GUEST_INTERRUPTIBILITY_INFO, x);
     }
+
+    if ( regs->eflags & X86_EFLAGS_TF )
+        vmx_inject_exception(TRAP_debug, HVM_DELIVER_NO_ERROR_CODE, 0);
 }
 
 static void vmx_do_no_device_fault(void)
@@ -2589,7 +2602,17 @@ gp_fault:
 
 static void vmx_do_hlt(struct cpu_user_regs *regs)
 {
-    HVMTRACE_0D(HLT, current);
+    unsigned long intr_info = __vmread(VM_ENTRY_INTR_INFO);
+    struct vcpu *curr = current;
+
+    /* Check for pending exception. */
+    if ( intr_info & INTR_INFO_VALID_MASK )
+    {
+        HVMTRACE_1D(HLT, curr, /*int pending=*/ 1);
+        return;
+    }
+
+    HVMTRACE_1D(HLT, curr, /*int pending=*/ 0);
     hvm_hlt(regs->eflags);
 }
 
@@ -2904,7 +2927,7 @@ asmlinkage void vmx_vmexit_handler(struc
     case EXIT_REASON_VMWRITE:
     case EXIT_REASON_VMXOFF:
     case EXIT_REASON_VMXON:
-        vmx_inject_hw_exception(v, TRAP_invalid_op, VMX_DELIVER_NO_ERROR_CODE);
+        vmx_inject_hw_exception(v, TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE);
         break;
 
     case EXIT_REASON_TPR_BELOW_THRESHOLD:
diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c      Thu Nov 22 17:44:51 2007 +0000
+++ b/xen/arch/x86/traps.c      Thu Nov 22 18:28:47 2007 +0000
@@ -414,6 +414,17 @@ static int do_guest_trap(
     return 0;
 }
 
+static void instruction_done(struct cpu_user_regs *regs, unsigned long eip)
+{
+    regs->eip = eip;
+    regs->eflags &= ~X86_EFLAGS_RF;
+    if ( regs->eflags & X86_EFLAGS_TF )
+    {
+        current->arch.guest_context.debugreg[6] |= 0xffff4ff0;
+        do_guest_trap(TRAP_debug, regs, 0);
+    }
+}
+
 /*
  * Called from asm to set up the NMI trapbounce info.
  * Returns 0 if no callback is set up, else 1.
@@ -657,8 +668,8 @@ static int emulate_forced_invalid_op(str
     regs->ebx = b;
     regs->ecx = c;
     regs->edx = d;
-    regs->eip = eip;
-    regs->eflags &= ~X86_EFLAGS_RF;
+
+    instruction_done(regs, eip);
 
     trace_trap_one_addr(TRC_PV_FORCED_INVALID_OP, regs->eip);
 
@@ -1953,8 +1964,7 @@ static int emulate_privileged_op(struct 
 #undef rd_ad
 
  done:
-    regs->eip = eip;
-    regs->eflags &= ~X86_EFLAGS_RF;
+    instruction_done(regs, eip);
     return EXCRET_fault_fixed;
 
  fail:
@@ -2284,8 +2294,8 @@ static int emulate_gate_op(struct cpu_us
     else
         sel |= (regs->cs & 3);
 
-    regs->eip = off;
     regs->cs = sel;
+    instruction_done(regs, off);
 #endif
 
     return 0;
diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/arch/x86/x86_emulate.c
--- a/xen/arch/x86/x86_emulate.c        Thu Nov 22 17:44:51 2007 +0000
+++ b/xen/arch/x86/x86_emulate.c        Thu Nov 22 18:28:47 2007 +0000
@@ -1635,6 +1635,7 @@ x86_emulate(
     /* Commit shadow register state. */
     _regs.eflags &= ~EFLG_RF;
     *ctxt->regs = _regs;
+    /* FIXME generate_exception_if(_regs.eflags & EFLG_TF, EXC_DB); */
 
  done:
     return rc;
diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/include/asm-x86/hvm/support.h
--- a/xen/include/asm-x86/hvm/support.h Thu Nov 22 17:44:51 2007 +0000
+++ b/xen/include/asm-x86/hvm/support.h Thu Nov 22 18:28:47 2007 +0000
@@ -50,7 +50,7 @@ static inline vcpu_iodata_t *get_ioreq(s
 #define TYPE_CLTS               (2 << 4)
 #define TYPE_LMSW               (3 << 4)
 
-#define VMX_DELIVER_NO_ERROR_CODE  -1
+#define HVM_DELIVER_NO_ERROR_CODE  -1
 
 #if HVM_DEBUG
 #define DBG_LEVEL_0                 (1 << 0)
diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/include/asm-x86/hvm/vmx/vmx.h
--- a/xen/include/asm-x86/hvm/vmx/vmx.h Thu Nov 22 17:44:51 2007 +0000
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h Thu Nov 22 18:28:47 2007 +0000
@@ -269,7 +269,7 @@ static inline void __vmx_inject_exceptio
      */
 
     intr_fields = (INTR_INFO_VALID_MASK | (type<<8) | trap);
-    if ( error_code != VMX_DELIVER_NO_ERROR_CODE ) {
+    if ( error_code != HVM_DELIVER_NO_ERROR_CODE ) {
         __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
         intr_fields |= INTR_INFO_DELIVER_CODE_MASK;
     }
@@ -291,13 +291,13 @@ static inline void vmx_inject_extint(str
 static inline void vmx_inject_extint(struct vcpu *v, int trap)
 {
     __vmx_inject_exception(v, trap, X86_EVENTTYPE_EXT_INTR,
-                           VMX_DELIVER_NO_ERROR_CODE);
+                           HVM_DELIVER_NO_ERROR_CODE);
 }
 
 static inline void vmx_inject_nmi(struct vcpu *v)
 {
     __vmx_inject_exception(v, 2, X86_EVENTTYPE_NMI,
-                           VMX_DELIVER_NO_ERROR_CODE);
+                           HVM_DELIVER_NO_ERROR_CODE);
 }
 
 #endif /* __ASM_X86_HVM_VMX_VMX_H__ */

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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] x86: single step after instruction emulation, Xen patchbot-unstable <=