Skip to contentSkip to conversation

x86: single step after instruction emulation

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

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 x86: single step after instruction emulation

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

xen/arch/x86/hvm/io.c +2 -0
Index: 2007-11-13/xen/arch/x86/hvm/io.c
===================================================================
@@ -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);
xen/arch/x86/hvm/platform.c +0 -3
Index: 2007-11-13/xen/arch/x86/hvm/platform.c
===================================================================
@@ -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 "
xen/arch/x86/hvm/svm/svm.c +29 -18

119 lines not on this page · raw message

xen/arch/x86/hvm/vmx/vmx.c +25 -10
Index: 2007-11-13/xen/arch/x86/hvm/vmx/vmx.c
===================================================================
@@ -1093,6 +1093,14 @@ static void vmx_inject_exception(
     vmx_inject_hw_exception(v, trapnr, errcode);
     if ( trapnr == TRAP_page_fault )
         v->arch.hvm_vcpu.guest_cr[2] = cr2;
+    if ( trapnr == TRAP_debug &&
+         (guest_cpu_user_regs()->eflags & X86_EFLAGS_TF) )
+    {
+        unsigned long dr6 = read_debugreg(6);
+
+        v->arch.guest_context.debugreg[6] = dr6 |= 0x4000;
+        write_debugreg(6, dr6);
+    }
 }
 
 static void vmx_update_vtpr(struct vcpu *v, unsigned long value)
@@ -1184,13 +1192,20 @@ static int __get_instruction_length(void
     return len;
 }
 
-static void __update_guest_eip(unsigned long inst_len)
+static void __update_guest_eip(struct vcpu *v, unsigned long inst_len)
 {
     struct cpu_user_regs *regs = guest_cpu_user_regs();
     unsigned long x;
 
     regs->eip += inst_len;
     regs->eflags &= ~X86_EFLAGS_RF;
+    if ( v && (regs->eflags & X86_EFLAGS_TF) )
+    {
+        x = read_debugreg(6);
+        v->arch.guest_context.debugreg[6] = x |= 0x4000;
+        write_debugreg(6, x);
+        vmx_inject_hw_exception(v, TRAP_debug, HVM_DELIVER_NO_ERROR_CODE);
+    }
 
     x = __vmread(GUEST_INTERRUPTIBILITY_INFO);
     if ( x & (VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS) )
@@ -2824,18 +2839,18 @@ asmlinkage void vmx_vmexit_handler(struc
     }
     case EXIT_REASON_CPUID:
         inst_len = __get_instruction_length(); /* Safe: CPUID */
-        __update_guest_eip(inst_len);
+        __update_guest_eip(v, inst_len);
         vmx_do_cpuid(regs);
         break;
     case EXIT_REASON_HLT:
         inst_len = __get_instruction_length(); /* Safe: HLT */
-        __update_guest_eip(inst_len);
+        __update_guest_eip(NULL, inst_len);
         vmx_do_hlt(regs);
         break;
     case EXIT_REASON_INVLPG:
     {
         inst_len = __get_instruction_length(); /* Safe: INVLPG */
-        __update_guest_eip(inst_len);
+        __update_guest_eip(v, inst_len);
         exit_qualification = __vmread(EXIT_QUALIFICATION);
         vmx_do_invlpg(exit_qualification);
         break;
@@ -2848,7 +2863,7 @@ asmlinkage void vmx_vmexit_handler(struc
         rc = hvm_do_hypercall(regs);
         if ( rc != HVM_HCALL_preempted )
         {
-            __update_guest_eip(inst_len);
+            __update_guest_eip(v, inst_len);
             if ( rc == HVM_HCALL_invalidate )
                 send_invalidate_req();
         }
@@ -2859,7 +2874,7 @@ asmlinkage void vmx_vmexit_handler(struc
         exit_qualification = __vmread(EXIT_QUALIFICATION);
         inst_len = __get_instruction_length(); /* Safe: MOV Cn, LMSW, CLTS */
         if ( vmx_cr_access(exit_qualification, regs) )
-            __update_guest_eip(inst_len);
+            __update_guest_eip(v, inst_len);
         break;
     }
     case EXIT_REASON_DR_ACCESS:
@@ -2874,12 +2889,12 @@ asmlinkage void vmx_vmexit_handler(struc
     case EXIT_REASON_MSR_READ:
         inst_len = __get_instruction_length(); /* Safe: RDMSR */
         if ( vmx_do_msr_read(regs) )
-            __update_guest_eip(inst_len);
+            __update_guest_eip(v, inst_len);
         break;
     case EXIT_REASON_MSR_WRITE:
         inst_len = __get_instruction_length(); /* Safe: WRMSR */
         if ( vmx_do_msr_write(regs) )
-            __update_guest_eip(inst_len);
+            __update_guest_eip(v, inst_len);
         break;
 
     case EXIT_REASON_MWAIT_INSTRUCTION:
@@ -2893,7 +2908,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:
@@ -2911,7 +2926,7 @@ asmlinkage void vmx_vmexit_handler(struc
     case EXIT_REASON_WBINVD:
     {
         inst_len = __get_instruction_length(); /* Safe: INVD, WBINVD */
-        __update_guest_eip(inst_len);
+        __update_guest_eip(v, inst_len);
         if ( !list_empty(&(domain_hvm_iommu(v->domain)->pdev_list)) )
         {
             wbinvd();
xen/arch/x86/traps.c +14 -5
Index: 2007-11-13/xen/arch/x86/traps.c
===================================================================
@@ -412,6 +412,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,7 @@ 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);
 
@@ -1950,8 +1960,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:
@@ -2280,8 +2289,8 @@ static int emulate_gate_op(struct cpu_u
     else
         sel |= (regs->cs & 3);
 
-    regs->eip = off;
     regs->cs = sel;
+    instruction_done(regs, off);
 #endif
 
     return 0;
xen/arch/x86/x86_emulate.c +1 -0
Index: 2007-11-13/xen/arch/x86/x86_emulate.c
===================================================================
@@ -1615,6 +1615,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;
xen/include/asm-x86/hvm/support.h +1 -1
Index: 2007-11-13/xen/include/asm-x86/hvm/support.h
===================================================================
@@ -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)
xen/include/asm-x86/hvm/vmx/vmx.h +3 -3
Index: 2007-11-13/xen/include/asm-x86/hvm/vmx/vmx.h
===================================================================
@@ -272,7 +272,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;
     }
@@ -294,13 +294,13 @@ static inline void vmx_inject_hw_excepti
 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__ */