[xen-unstable] x86: single step after instruction emulation

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[xen-unstable] x86: single step after instruction emulation

Xen patchbot-unstable
# HG changeset patch
# User Keir Fraser <[hidden email]>
# 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 <[hidden email]>
Signed-off-by: Keir Fraser <[hidden email]>
---
 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
[hidden email]
http://lists.xensource.com/xen-changelog