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-devel

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

To: Xen Developers <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH] [HVM] enable MTF for guest single step debug
From: "Zhai, Edwin" <edwin.zhai@xxxxxxxxx>
Date: Thu, 11 Dec 2008 15:09:47 +0800
Cc: "Zhai, Edwin" <edwin.zhai@xxxxxxxxx>
Delivery-date: Wed, 10 Dec 2008 23:10:29 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Thunderbird 2.0.0.17 (X11/20080914)
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

Thanks,


--
best rgds,
edwin

Enable MTF for HVM guest single step in gdb
Signed-off-by: Edwin Zhai <edwin.zhai@xxxxxxxxx>

Index: hv/tools/libxc/xc_ptrace.c
===================================================================
--- hv.orig/tools/libxc/xc_ptrace.c
+++ hv/tools/libxc/xc_ptrace.c
@@ -524,10 +524,18 @@ 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_set_hvm_param(xc_handle, current_domid, HVM_PARAM_MTF,
+                              (cpu << 1) | 1))
+        {
+            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 +546,20 @@ 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_set_hvm_param(xc_handle, current_domid, HVM_PARAM_MTF,
+                                       (cpu << 1) | 0))
                 {
-                    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/hvm.c
===================================================================
--- hv.orig/xen/arch/x86/hvm/hvm.c
+++ hv/xen/arch/x86/hvm/hvm.c
@@ -2504,6 +2504,24 @@ long do_hvm_op(unsigned long op, XEN_GUE
                     rc = -EINVAL;
 
                 break;
+            case HVM_PARAM_MTF:
+                rc = -EPERM;
+                if ( !IS_PRIV(current->domain) )
+                    break;
+
+                rc = -EINVAL;
+                /* format:   cpu | function
+                 * function: 1-enable; 0-disable
+                 */
+                if ( (a.value >> 1) >= MAX_VIRT_CPUS ||
+                     (v = d->vcpu[a.value >> 1]) == NULL )
+                    break;
+
+                if ( !d->debugger_attached )
+                    break;
+
+                rc = hvm_single_step(v, (a.value & 0x1));
+                break;
             }
 
             if ( rc == 0 )
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_vmx.activate_mtf )
+    {
+        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);
@@ -1336,6 +1341,15 @@ static void vmx_set_info_guest(struct vc
     vmx_vmcs_exit(v);
 }
 
+static int vmx_single_step(struct vcpu *v, int enable)
+{
+    if ( !cpu_has_monitor_trap_flag )
+        return -1;
+
+    v->arch.hvm_vmx.activate_mtf = enable;
+    return 0;
+}
+
 static struct hvm_function_table vmx_function_table = {
     .name                 = "VMX",
     .domain_initialise    = vmx_domain_initialise,
@@ -1367,7 +1381,8 @@ static struct hvm_function_table vmx_fun
     .msr_write_intercept  = vmx_msr_write_intercept,
     .invlpg_intercept     = vmx_invlpg_intercept,
     .set_uc_mode          = vmx_set_uc_mode,
-    .set_info_guest       = vmx_set_info_guest
+    .set_info_guest       = vmx_set_info_guest,
+    .single_step          = vmx_single_step
 };
 
 static unsigned long *vpid_bitmap;
@@ -2342,6 +2357,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 +2560,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
@@ -119,6 +119,9 @@ struct arch_vmx_struct {
     struct segment_register vm86_saved_seg[x86_seg_tr + 1];
     /* Remember EFLAGS while in virtual 8086 mode */
     uint32_t             vm86_saved_eflags;
+
+    /* If need activate MTF for guest single step deubg ?*/
+    uint8_t              activate_mtf;
 };
 
 int vmx_create_vmcs(struct vcpu *v);
@@ -142,6 +145,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 +190,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/xen/include/public/hvm/params.h
===================================================================
--- hv.orig/xen/include/public/hvm/params.h
+++ hv/xen/include/public/hvm/params.h
@@ -103,6 +103,9 @@
 /* TSS used on Intel when CR0.PE=0. */
 #define HVM_PARAM_VM86_TSS     15
 
-#define HVM_NR_PARAMS          16
+/* HVM MTF(Monitor Trap Flag) Enabling for debug */
+#define HVM_PARAM_MTF          16
+
+#define HVM_NR_PARAMS          17
 
 #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
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
@@ -129,6 +129,7 @@ struct hvm_function_table {
     void (*invlpg_intercept)(unsigned long vaddr);
     void (*set_uc_mode)(struct vcpu *v);
     void (*set_info_guest)(struct vcpu *v);
+    int  (*single_step)(struct vcpu *v, int enable);
 };
 
 extern struct hvm_function_table hvm_funcs;
@@ -277,6 +278,7 @@ static inline int hvm_do_pmu_interrupt(s
 #define X86_EVENTTYPE_HW_EXCEPTION          3    /* hardware exception */
 #define X86_EVENTTYPE_SW_INTERRUPT          4    /* software interrupt */
 #define X86_EVENTTYPE_SW_EXCEPTION          6    /* software exception */
+#define X86_EVENTTYPE_OTHER                 7    /* other event        */
 
 int hvm_event_needs_reinjection(uint8_t type, uint8_t vector);
 
@@ -321,4 +323,13 @@ static inline void hvm_set_info_guest(st
         return hvm_funcs.set_info_guest(v);
 }
 
+static inline int hvm_single_step(struct vcpu *v, int enable)
+{
+    if ( hvm_funcs.single_step )
+        return hvm_funcs.single_step(v, enable);
+
+    /* return -1, ask gdb to handle */
+    return -1;
+}
+
 #endif /* __ASM_X86_HVM_HVM_H__ */
Index: hv/xen/arch/x86/hvm/svm/svm.c
===================================================================
--- hv.orig/xen/arch/x86/hvm/svm/svm.c
+++ hv/xen/arch/x86/hvm/svm/svm.c
@@ -795,6 +795,11 @@ static int svm_do_pmu_interrupt(struct c
     return 0;
 }
 
+static int svm_single_step(struct vcpu *v, int enable)
+{
+    return -1;
+}
+
 static struct hvm_function_table svm_function_table = {
     .name                 = "SVM",
     .cpu_down             = svm_cpu_down,
@@ -823,7 +828,8 @@ static struct hvm_function_table svm_fun
     .fpu_dirty_intercept  = svm_fpu_dirty_intercept,
     .msr_read_intercept   = svm_msr_read_intercept,
     .msr_write_intercept  = svm_msr_write_intercept,
-    .invlpg_intercept     = svm_invlpg_intercept
+    .invlpg_intercept     = svm_invlpg_intercept,
+    .single_step          = svm_single_step
 };
 
 int start_svm(struct cpuinfo_x86 *c)
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
<Prev in Thread] Current Thread [Next in Thread>