[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH] [HVM] enable MTF for guest single step debug



Thanks for comments.
v2 comes :)



Keir Fraser wrote:
On 11/12/2008 07:09, "Zhai, Edwin" <edwin.zhai@xxxxxxxxx> wrote:

Monitor Trap Flag (MTF), is a debugging feature that cause vmexit on
certain instruction boundaries, which can be used for HVM single step.
We prefer MTF over TF, as it make TF free for guest use.

This patch try to enable MTF for single step in gdb, and keep backward
compatibility on old processor.

Pls. see MTF details @ SDM 3b 21.7.2

Don't need EVENTTYPE_OTHER. Don't need to modify svm.c at all. The hvm_param
is gross since there is no obvious symmetric get() to go with your set() --
please just hack in a domctl, that'd be neater in this case imo even though
specific right now to x86 hvm.

That'll do for comments on patch v1... :-)

 -- Keir



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


--
best rgds,
edwin

Index: hv/tools/libxc/xc_ptrace.c
===================================================================
--- hv.orig/tools/libxc/xc_ptrace.c
+++ hv/tools/libxc/xc_ptrace.c
@@ -524,10 +524,20 @@ xc_ptrace(
         /*  XXX we can still have problems if the user switches threads
          *  during single-stepping - but that just seems retarded
          */
-        ctxt[cpu].c.user_regs.eflags |= PSL_T;
-        if ((retval = xc_vcpu_setcontext(xc_handle, current_domid, cpu,
-                                &ctxt[cpu])))
-            goto out_error_domctl;
+        /* Try to enalbe Monitor Trap Flag for HVM, and fall back to TF
+         * if no MTF support
+         */
+        if ( !current_is_hvm ||
+             xc_domain_debug_control(xc_handle,
+                                     current_domid,
+                                     XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_ON,
+                                     cpu) )
+        {
+            ctxt[cpu].c.user_regs.eflags |= PSL_T;
+            if ((retval = xc_vcpu_setcontext(xc_handle, current_domid, cpu,
+                                    &ctxt[cpu])))
+                goto out_error_domctl;
+        }
         /* FALLTHROUGH */
 
     case PTRACE_CONT:
@@ -538,15 +548,22 @@ xc_ptrace(
         {
             FOREACH_CPU(cpumap, index) {
                 cpu = index - 1;
-                if (fetch_regs(xc_handle, cpu, NULL))
-                    goto out_error;
-                /* Clear trace flag */
-                if ( ctxt[cpu].c.user_regs.eflags & PSL_T )
+                if ( !current_is_hvm ||
+                      xc_domain_debug_control(xc_handle,
+                                              current_domid,
+                                              
XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF,
+                                              cpu) )
                 {
-                    ctxt[cpu].c.user_regs.eflags &= ~PSL_T;
-                    if ((retval = xc_vcpu_setcontext(xc_handle, current_domid,
-                                                cpu, &ctxt[cpu])))
-                        goto out_error_domctl;
+                    if (fetch_regs(xc_handle, cpu, NULL))
+                        goto out_error;
+                    /* Clear trace flag */
+                    if ( ctxt[cpu].c.user_regs.eflags & PSL_T )
+                    {
+                        ctxt[cpu].c.user_regs.eflags &= ~PSL_T;
+                        if ((retval = xc_vcpu_setcontext(xc_handle, 
current_domid,
+                                        cpu, &ctxt[cpu])))
+                            goto out_error_domctl;
+                    }
                 }
             }
         }
Index: hv/xen/arch/x86/hvm/vmx/intr.c
===================================================================
--- hv.orig/xen/arch/x86/hvm/vmx/intr.c
+++ hv/xen/arch/x86/hvm/vmx/intr.c
@@ -117,6 +117,17 @@ asmlinkage void vmx_intr_assist(void)
     unsigned int tpr_threshold = 0;
     enum hvm_intblk intblk;
 
+    /* Block event injection when single step with MTF,
+     * or else step into the guest event handler(SDM 3b 21.7.2)
+     */
+    if ( cpu_has_monitor_trap_flag && v->arch.hvm_vcpu.single_step )
+    {
+        v->arch.hvm_vmx.exec_control |= CPU_BASED_MONITOR_TRAP_FLAG;
+        __vmwrite(CPU_BASED_VM_EXEC_CONTROL, v->arch.hvm_vmx.exec_control);
+
+        return;
+    }
+
     /* Crank the handle on interrupt state. */
     pt_update_irq(v);
     hvm_dirq_assist(v);
Index: hv/xen/arch/x86/hvm/vmx/vmcs.c
===================================================================
--- hv.orig/xen/arch/x86/hvm/vmx/vmcs.c
+++ hv/xen/arch/x86/hvm/vmx/vmcs.c
@@ -99,6 +99,7 @@ static void vmx_init_vmcs_config(void)
            (opt_softtsc ? CPU_BASED_RDTSC_EXITING : 0));
     opt = (CPU_BASED_ACTIVATE_MSR_BITMAP |
            CPU_BASED_TPR_SHADOW |
+           CPU_BASED_MONITOR_TRAP_FLAG |
            CPU_BASED_ACTIVATE_SECONDARY_CONTROLS);
     _vmx_cpu_based_exec_control = adjust_vmx_controls(
         min, opt, MSR_IA32_VMX_PROCBASED_CTLS);
@@ -515,6 +516,9 @@ static int construct_vmcs(struct vcpu *v
         v->arch.hvm_vmx.secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_EPT;
     }
 
+    /* Do not enable Monitor Trap Flag unless start single step debug */
+    v->arch.hvm_vmx.exec_control &= ~CPU_BASED_MONITOR_TRAP_FLAG;
+
     __vmwrite(CPU_BASED_VM_EXEC_CONTROL, v->arch.hvm_vmx.exec_control);
     if ( cpu_has_vmx_secondary_exec_control )
         __vmwrite(SECONDARY_VM_EXEC_CONTROL,
@@ -867,7 +871,13 @@ void vmx_do_resume(struct vcpu *v)
     if ( unlikely(v->arch.hvm_vcpu.debug_state_latch != debug_state) )
     {
         unsigned long intercepts = __vmread(EXCEPTION_BITMAP);
-        unsigned long mask = (1U << TRAP_debug) | (1U << TRAP_int3);
+        unsigned long mask = (1U << TRAP_int3);
+
+        if ( !cpu_has_monitor_trap_flag )
+        {
+            mask |= (1U << TRAP_debug);
+        }
+
         v->arch.hvm_vcpu.debug_state_latch = debug_state;
         if ( debug_state )
             intercepts |= mask;
Index: hv/xen/arch/x86/hvm/vmx/vmx.c
===================================================================
--- hv.orig/xen/arch/x86/hvm/vmx/vmx.c
+++ hv/xen/arch/x86/hvm/vmx/vmx.c
@@ -1258,6 +1258,11 @@ void vmx_inject_hw_exception(int trap, i
     switch ( trap )
     {
     case TRAP_debug:
+        /* If has MTF, TF is free for guest use */
+        if ( cpu_has_monitor_trap_flag )
+        {
+            break;
+        }
         if ( guest_cpu_user_regs()->eflags & X86_EFLAGS_TF )
         {
             __restore_debug_registers(curr);
@@ -2342,6 +2347,13 @@ asmlinkage void vmx_vmexit_handler(struc
         switch ( vector )
         {
         case TRAP_debug:
+            /* If has MTF, use it for single step rather than TF*/
+            if ( cpu_has_monitor_trap_flag )
+            {
+                gdprintk(XENLOG_ERR, "Unexpected TRAP_debug vmexit!");
+                goto exit_and_crash;
+            }
+
             /*
              * Updates DR6 where debugger can peek (See 3B 23.2.1,
              * Table 23-1, "Exit Qualification for Debug Exceptions").
@@ -2538,6 +2550,19 @@ asmlinkage void vmx_vmexit_handler(struc
         break;
     }
 
+    case EXIT_REASON_MONITOR_TRAP_FLAG:
+    {
+        if ( !v->domain->debugger_attached )
+            goto exit_and_crash;
+
+        v->arch.hvm_vmx.exec_control &= ~CPU_BASED_MONITOR_TRAP_FLAG;
+        __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
+                  v->arch.hvm_vmx.exec_control);
+
+        domain_pause_for_debugger();
+        break;
+    }
+
     default:
     exit_and_crash:
         gdprintk(XENLOG_ERR, "Bad vmexit (reason %x)\n", exit_reason);
Index: hv/xen/include/asm-x86/hvm/vmx/vmcs.h
===================================================================
--- hv.orig/xen/include/asm-x86/hvm/vmx/vmcs.h
+++ hv/xen/include/asm-x86/hvm/vmx/vmcs.h
@@ -142,6 +142,7 @@ void vmx_vmcs_exit(struct vcpu *v);
 #define CPU_BASED_MOV_DR_EXITING              0x00800000
 #define CPU_BASED_UNCOND_IO_EXITING           0x01000000
 #define CPU_BASED_ACTIVATE_IO_BITMAP          0x02000000
+#define CPU_BASED_MONITOR_TRAP_FLAG           0x08000000
 #define CPU_BASED_ACTIVATE_MSR_BITMAP         0x10000000
 #define CPU_BASED_MONITOR_EXITING             0x20000000
 #define CPU_BASED_PAUSE_EXITING               0x40000000
@@ -186,6 +187,8 @@ extern bool_t cpu_has_vmx_ins_outs_instr
     (vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT)
 #define cpu_has_vmx_vpid \
     (vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_VPID)
+#define cpu_has_monitor_trap_flag \
+    (vmx_cpu_based_exec_control & CPU_BASED_MONITOR_TRAP_FLAG)
 
 /* GUEST_INTERRUPTIBILITY_INFO flags. */
 #define VMX_INTR_SHADOW_STI             0x00000001
Index: hv/xen/include/asm-x86/hvm/vmx/vmx.h
===================================================================
--- hv.orig/xen/include/asm-x86/hvm/vmx/vmx.h
+++ hv/xen/include/asm-x86/hvm/vmx/vmx.h
@@ -96,6 +96,7 @@ void vmx_realmode(struct cpu_user_regs *
 #define EXIT_REASON_INVALID_GUEST_STATE 33
 #define EXIT_REASON_MSR_LOADING         34
 #define EXIT_REASON_MWAIT_INSTRUCTION   36
+#define EXIT_REASON_MONITOR_TRAP_FLAG   37
 #define EXIT_REASON_MONITOR_INSTRUCTION 39
 #define EXIT_REASON_PAUSE_INSTRUCTION   40
 #define EXIT_REASON_MACHINE_CHECK       41
Index: hv/tools/libxc/xc_domain.c
===================================================================
--- hv.orig/tools/libxc/xc_domain.c
+++ hv/tools/libxc/xc_domain.c
@@ -1061,6 +1061,20 @@ int xc_domain_suppress_spurious_page_fau
 
 }
 
+int xc_domain_debug_control(int xc, uint32_t domid, uint32_t sop, uint32_t 
vcpu)
+{
+    DECLARE_DOMCTL;
+
+    memset(&domctl, 0, sizeof(domctl));
+    domctl.domain = (domid_t)domid;
+    domctl.cmd = XEN_DOMCTL_debug_op;
+    domctl.u.debug_op.op     = sop;
+    domctl.u.debug_op.vcpu   = vcpu;
+
+    return do_domctl(xc, &domctl);
+}
+
+
 /*
  * Local variables:
  * mode: C
Index: hv/xen/arch/x86/domctl.c
===================================================================
--- hv.orig/xen/arch/x86/domctl.c
+++ hv/xen/arch/x86/domctl.c
@@ -1037,6 +1037,34 @@ long arch_do_domctl(
     }
     break;
 
+    case XEN_DOMCTL_debug_op:
+    {
+        struct domain *d;
+        struct vcpu *v;
+
+        ret = -ESRCH;
+        d = rcu_lock_domain_by_id(domctl->domain);
+        if ( d == NULL )
+            break;
+
+        if ( (domctl->u.debug_op.vcpu >= MAX_VIRT_CPUS) ||
+             ((v = d->vcpu[domctl->u.debug_op.vcpu]) == NULL) )
+            goto debug_op_out;
+
+        /* Only HVM domain likely to debug with HV's help,
+         * PV handle debug in xc_ptrace
+         */
+        if ( !is_hvm_domain(d))
+            goto debug_op_out;
+
+        ret = hvm_debug_op(v, domctl->u.debug_op.op);
+
+    debug_op_out:
+        rcu_unlock_domain(d);
+
+    }
+    break;
+
     default:
         ret = -ENOSYS;
         break;
Index: hv/xen/arch/x86/hvm/hvm.c
===================================================================
--- hv.orig/xen/arch/x86/hvm/hvm.c
+++ hv/xen/arch/x86/hvm/hvm.c
@@ -2700,6 +2700,28 @@ long do_hvm_op(unsigned long op, XEN_GUE
     return rc;
 }
 
+int hvm_debug_op(struct vcpu *v, int32_t op)
+{
+    int rc = -ENOSYS;
+
+    switch ( op )
+    {
+        case XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_ON:
+        case XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF:
+            if ( !cpu_has_monitor_trap_flag )
+                break;
+            rc = 0;
+            v->arch.hvm_vcpu.single_step =
+                ( op == XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF ) ?  0 : 1;
+            break;
+        default:
+            rc = -ENOSYS;
+    }
+
+    return rc;
+}
+
+
 /*
  * Local variables:
  * mode: C
Index: hv/xen/include/asm-x86/hvm/hvm.h
===================================================================
--- hv.orig/xen/include/asm-x86/hvm/hvm.h
+++ hv/xen/include/asm-x86/hvm/hvm.h
@@ -321,4 +321,6 @@ static inline void hvm_set_info_guest(st
         return hvm_funcs.set_info_guest(v);
 }
 
+int hvm_debug_op(struct vcpu *v, int32_t op);
+
 #endif /* __ASM_X86_HVM_HVM_H__ */
Index: hv/xen/include/asm-x86/hvm/vcpu.h
===================================================================
--- hv.orig/xen/include/asm-x86/hvm/vcpu.h
+++ hv/xen/include/asm-x86/hvm/vcpu.h
@@ -96,6 +96,7 @@ struct hvm_vcpu {
     /* We may write up to m128 as a number of device-model transactions. */
     paddr_t mmio_large_write_pa;
     unsigned int mmio_large_write_bytes;
+    unsigned int single_step;
 };
 
 #endif /* __ASM_X86_HVM_VCPU_H__ */
Index: hv/xen/include/public/domctl.h
===================================================================
--- hv.orig/xen/include/public/domctl.h
+++ hv/xen/include/public/domctl.h
@@ -619,6 +619,17 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_subsc
  */
 #define XEN_DOMCTL_suppress_spurious_page_faults 53
 
+#define XEN_DOMCTL_debug_op    54
+#define XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF         0
+#define XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_ON          1
+struct xen_domctl_debug_op {
+    uint32_t op;   /* IN */
+    uint32_t vcpu; /* IN */
+};
+typedef struct xen_domctl_debug_op xen_domctl_debug_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_debug_op_t);
+
+
 struct xen_domctl {
     uint32_t cmd;
     uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */
@@ -658,6 +669,7 @@ struct xen_domctl {
         struct xen_domctl_set_opt_feature   set_opt_feature;
         struct xen_domctl_set_target        set_target;
         struct xen_domctl_subscribe         subscribe;
+        struct xen_domctl_debug_op          debug_op;
 #if defined(__i386__) || defined(__x86_64__)
         struct xen_domctl_cpuid             cpuid;
 #endif
Index: hv/tools/libxc/xenctrl.h
===================================================================
--- hv.orig/tools/libxc/xenctrl.h
+++ hv/tools/libxc/xenctrl.h
@@ -1111,6 +1111,12 @@ int xc_domain_set_target(int xc_handle,
                          uint32_t domid,
                          uint32_t target);
 
+/* Control the domain for debug */
+int xc_domain_debug_control(int xc_handle,
+                            uint32_t domid,
+                            uint32_t sop,
+                            uint32_t vcpu);
+
 #if defined(__i386__) || defined(__x86_64__)
 int xc_cpuid_check(int xc,
                    const unsigned int *input,
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.