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
|