From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Zhai, Edwin" Subject: Re: [PATCH] [HVM] enable MTF for guest single step debug Date: Fri, 12 Dec 2008 15:03:51 +0800 Message-ID: <49420CD7.3020706@intel.com> References: Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------090701000808080006020704" Return-path: In-Reply-To: List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xensource.com Errors-To: xen-devel-bounces@lists.xensource.com To: Keir Fraser Cc: Xen Developers , "Zhai, Edwin" List-Id: xen-devel@lists.xenproject.org This is a multi-part message in MIME format. --------------090701000808080006020704 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Thanks for comments. v2 comes :) Keir Fraser wrote: > On 11/12/2008 07:09, "Zhai, Edwin" 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@lists.xensource.com > http://lists.xensource.com/xen-devel > > -- best rgds, edwin --------------090701000808080006020704 Content-Type: text/plain; name="MTF_enable_r18891_v2.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="MTF_enable_r18891_v2.patch" 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, --------------090701000808080006020704 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel --------------090701000808080006020704--