Jan Beulich
2007-Nov-22 16:58 UTC
[Xen-devel] [PATCH] 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 <jbeulich@novell.com> Index: 2007-11-13/xen/arch/x86/hvm/io.c ==================================================================--- 2007-11-13.orig/xen/arch/x86/hvm/io.c 2007-11-21 08:47:45.000000000 +0100 +++ 2007-11-13/xen/arch/x86/hvm/io.c 2007-11-20 16:27:57.000000000 +0100 @@ -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); Index: 2007-11-13/xen/arch/x86/hvm/platform.c ==================================================================--- 2007-11-13.orig/xen/arch/x86/hvm/platform.c 2007-11-21 08:47:45.000000000 +0100 +++ 2007-11-13/xen/arch/x86/hvm/platform.c 2007-11-20 16:37:27.000000000 +0100 @@ -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 " Index: 2007-11-13/xen/arch/x86/hvm/svm/svm.c ==================================================================--- 2007-11-13.orig/xen/arch/x86/hvm/svm/svm.c 2007-11-21 08:47:45.000000000 +0100 +++ 2007-11-13/xen/arch/x86/hvm/svm/svm.c 2007-11-20 16:46:55.000000000 +0100 @@ -78,14 +78,6 @@ static void *root_vmcb[NR_CPUS] __read_m static void svm_update_guest_efer(struct vcpu *v); -static void inline __update_guest_eip( - struct cpu_user_regs *regs, int inst_len) -{ - ASSERT(inst_len > 0); - regs->eip += inst_len; - regs->eflags &= ~X86_EFLAGS_RF; -} - static void svm_inject_exception( struct vcpu *v, int trap, int ev, int error_code) { @@ -107,6 +99,20 @@ static void svm_inject_exception( vmcb->eventinj = event; } +static void inline __update_guest_eip(struct vcpu *v, + struct cpu_user_regs *regs, int inst_len) +{ + ASSERT(inst_len > 0); + regs->eip += inst_len; + regs->eflags &= ~X86_EFLAGS_RF; + if ( v && (regs->eflags & X86_EFLAGS_TF) ) + { + v->arch.guest_context.debugreg[6] + v->arch.hvm_svm.vmcb->dr6 |= 0x4000; + svm_inject_exception(v, TRAP_debug, 0, 0); + } +} + static void svm_cpu_down(void) { write_efer(read_efer() & ~EFER_SVME); @@ -868,7 +874,12 @@ static void svm_hvm_inject_exception( struct vcpu *v = current; 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); + if ( trapnr == TRAP_debug && + (guest_cpu_user_regs()->eflags & X86_EFLAGS_TF) ) + v->arch.guest_context.debugreg[6] + v->arch.hvm_svm.vmcb->dr6 |= 0x4000; + svm_inject_exception(v, trapnr, + (errcode != HVM_DELIVER_NO_ERROR_CODE), errcode); } static int svm_event_pending(struct vcpu *v) @@ -1083,7 +1094,7 @@ static void svm_vmexit_do_cpuid(struct v inst_len = __get_instruction_length(v, INSTR_CPUID, NULL); ASSERT(inst_len > 0); - __update_guest_eip(regs, inst_len); + __update_guest_eip(v, regs, inst_len); } static unsigned long *get_reg_p( @@ -1769,7 +1780,7 @@ static void svm_cr_access( ASSERT(inst_len); if ( result ) - __update_guest_eip(regs, inst_len); + __update_guest_eip(v, regs, inst_len); } static void svm_do_msr_access( @@ -1940,7 +1951,7 @@ static void svm_do_msr_access( inst_len = __get_instruction_length(v, INSTR_WRMSR, NULL); } - __update_guest_eip(regs, inst_len); + __update_guest_eip(v, regs, inst_len); } static void svm_vmexit_do_hlt(struct vmcb_struct *vmcb, @@ -1948,7 +1959,7 @@ static void svm_vmexit_do_hlt(struct vmc { struct hvm_intack intack = hvm_vcpu_has_pending_irq(current); - __update_guest_eip(regs, 1); + __update_guest_eip(NULL, regs, 1); /* Check for interrupt not handled or new interrupt. */ if ( vmcb->eventinj.fields.v || @@ -1978,7 +1989,7 @@ static void svm_vmexit_do_invalidate_cac inst_len = __get_instruction_length_from_list( curr, list, ARRAY_SIZE(list), NULL, NULL); - __update_guest_eip(regs, inst_len); + __update_guest_eip(curr, regs, inst_len); } void svm_handle_invlpg(const short invlpga, struct cpu_user_regs *regs) @@ -2003,7 +2014,7 @@ void svm_handle_invlpg(const short invlp { inst_len = __get_instruction_length(v, INSTR_INVLPGA, opcode); ASSERT(inst_len > 0); - __update_guest_eip(regs, inst_len); + __update_guest_eip(v, regs, inst_len); /* * The address is implicit on this instruction. At the moment, we don''t @@ -2030,7 +2041,7 @@ void svm_handle_invlpg(const short invlp &opcode[inst_len], &length); inst_len += length; - __update_guest_eip(regs, inst_len); + __update_guest_eip(v, regs, inst_len); } HVMTRACE_3D(INVLPG, v, (invlpga?1:0), g_vaddr, (invlpga?regs->ecx:0)); @@ -2186,7 +2197,7 @@ asmlinkage void svm_vmexit_handler(struc goto exit_and_crash; /* AMD Vol2, 15.11: INT3, INTO, BOUND intercepts do not update RIP. */ inst_len = __get_instruction_length(v, INSTR_INT3, NULL); - __update_guest_eip(regs, inst_len); + __update_guest_eip(NULL, regs, inst_len); domain_pause_for_debugger(); break; @@ -2268,7 +2279,7 @@ asmlinkage void svm_vmexit_handler(struc rc = hvm_do_hypercall(regs); if ( rc != HVM_HCALL_preempted ) { - __update_guest_eip(regs, inst_len); + __update_guest_eip(v, regs, inst_len); if ( rc == HVM_HCALL_invalidate ) send_invalidate_req(); } Index: 2007-11-13/xen/arch/x86/hvm/vmx/vmx.c ==================================================================--- 2007-11-13.orig/xen/arch/x86/hvm/vmx/vmx.c 2007-11-21 08:47:45.000000000 +0100 +++ 2007-11-13/xen/arch/x86/hvm/vmx/vmx.c 2007-11-20 16:32:57.000000000 +0100 @@ -1093,6 +1093,14 @@ static void vmx_inject_exception( vmx_inject_hw_exception(v, trapnr, errcode); if ( trapnr == TRAP_page_fault ) v->arch.hvm_vcpu.guest_cr[2] = cr2; + if ( trapnr == TRAP_debug && + (guest_cpu_user_regs()->eflags & X86_EFLAGS_TF) ) + { + unsigned long dr6 = read_debugreg(6); + + v->arch.guest_context.debugreg[6] = dr6 |= 0x4000; + write_debugreg(6, dr6); + } } static void vmx_update_vtpr(struct vcpu *v, unsigned long value) @@ -1184,13 +1192,20 @@ static int __get_instruction_length(void return len; } -static void __update_guest_eip(unsigned long inst_len) +static void __update_guest_eip(struct vcpu *v, unsigned long inst_len) { struct cpu_user_regs *regs = guest_cpu_user_regs(); unsigned long x; regs->eip += inst_len; regs->eflags &= ~X86_EFLAGS_RF; + if ( v && (regs->eflags & X86_EFLAGS_TF) ) + { + x = read_debugreg(6); + v->arch.guest_context.debugreg[6] = x |= 0x4000; + write_debugreg(6, x); + vmx_inject_hw_exception(v, TRAP_debug, HVM_DELIVER_NO_ERROR_CODE); + } x = __vmread(GUEST_INTERRUPTIBILITY_INFO); if ( x & (VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS) ) @@ -2824,18 +2839,18 @@ asmlinkage void vmx_vmexit_handler(struc } case EXIT_REASON_CPUID: inst_len = __get_instruction_length(); /* Safe: CPUID */ - __update_guest_eip(inst_len); + __update_guest_eip(v, inst_len); vmx_do_cpuid(regs); break; case EXIT_REASON_HLT: inst_len = __get_instruction_length(); /* Safe: HLT */ - __update_guest_eip(inst_len); + __update_guest_eip(NULL, inst_len); vmx_do_hlt(regs); break; case EXIT_REASON_INVLPG: { inst_len = __get_instruction_length(); /* Safe: INVLPG */ - __update_guest_eip(inst_len); + __update_guest_eip(v, inst_len); exit_qualification = __vmread(EXIT_QUALIFICATION); vmx_do_invlpg(exit_qualification); break; @@ -2848,7 +2863,7 @@ asmlinkage void vmx_vmexit_handler(struc rc = hvm_do_hypercall(regs); if ( rc != HVM_HCALL_preempted ) { - __update_guest_eip(inst_len); + __update_guest_eip(v, inst_len); if ( rc == HVM_HCALL_invalidate ) send_invalidate_req(); } @@ -2859,7 +2874,7 @@ asmlinkage void vmx_vmexit_handler(struc exit_qualification = __vmread(EXIT_QUALIFICATION); inst_len = __get_instruction_length(); /* Safe: MOV Cn, LMSW, CLTS */ if ( vmx_cr_access(exit_qualification, regs) ) - __update_guest_eip(inst_len); + __update_guest_eip(v, inst_len); break; } case EXIT_REASON_DR_ACCESS: @@ -2874,12 +2889,12 @@ asmlinkage void vmx_vmexit_handler(struc case EXIT_REASON_MSR_READ: inst_len = __get_instruction_length(); /* Safe: RDMSR */ if ( vmx_do_msr_read(regs) ) - __update_guest_eip(inst_len); + __update_guest_eip(v, inst_len); break; case EXIT_REASON_MSR_WRITE: inst_len = __get_instruction_length(); /* Safe: WRMSR */ if ( vmx_do_msr_write(regs) ) - __update_guest_eip(inst_len); + __update_guest_eip(v, inst_len); break; case EXIT_REASON_MWAIT_INSTRUCTION: @@ -2893,7 +2908,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: @@ -2911,7 +2926,7 @@ asmlinkage void vmx_vmexit_handler(struc case EXIT_REASON_WBINVD: { inst_len = __get_instruction_length(); /* Safe: INVD, WBINVD */ - __update_guest_eip(inst_len); + __update_guest_eip(v, inst_len); if ( !list_empty(&(domain_hvm_iommu(v->domain)->pdev_list)) ) { wbinvd(); Index: 2007-11-13/xen/arch/x86/traps.c ==================================================================--- 2007-11-13.orig/xen/arch/x86/traps.c 2007-11-21 08:47:45.000000000 +0100 +++ 2007-11-13/xen/arch/x86/traps.c 2007-11-20 15:46:19.000000000 +0100 @@ -412,6 +412,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,7 @@ 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); @@ -1950,8 +1960,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: @@ -2280,8 +2289,8 @@ static int emulate_gate_op(struct cpu_u else sel |= (regs->cs & 3); - regs->eip = off; regs->cs = sel; + instruction_done(regs, off); #endif return 0; Index: 2007-11-13/xen/arch/x86/x86_emulate.c ==================================================================--- 2007-11-13.orig/xen/arch/x86/x86_emulate.c 2007-11-21 08:47:45.000000000 +0100 +++ 2007-11-13/xen/arch/x86/x86_emulate.c 2007-11-20 15:38:30.000000000 +0100 @@ -1615,6 +1615,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; Index: 2007-11-13/xen/include/asm-x86/hvm/support.h ==================================================================--- 2007-11-13.orig/xen/include/asm-x86/hvm/support.h 2007-11-21 08:47:45.000000000 +0100 +++ 2007-11-13/xen/include/asm-x86/hvm/support.h 2007-11-20 15:58:09.000000000 +0100 @@ -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) Index: 2007-11-13/xen/include/asm-x86/hvm/vmx/vmx.h ==================================================================--- 2007-11-13.orig/xen/include/asm-x86/hvm/vmx/vmx.h 2007-11-21 08:47:45.000000000 +0100 +++ 2007-11-13/xen/include/asm-x86/hvm/vmx/vmx.h 2007-11-20 15:58:49.000000000 +0100 @@ -272,7 +272,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; } @@ -294,13 +294,13 @@ static inline void vmx_inject_hw_excepti 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-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel