[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] x86: single step after instruction emulation
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1195756127 0 # Node ID fd3f6d814f6dca9f46c95a5b808e2f47bdcd1715 # Parent ae087a0fa2c929842293b5c26dcd6acb9bdd748d 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@xxxxxxxxxx> Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxxxxx> --- xen/arch/x86/hvm/io.c | 2 xen/arch/x86/hvm/platform.c | 3 - xen/arch/x86/hvm/svm/svm.c | 101 +++++++++++++++++++++----------------- xen/arch/x86/hvm/vmx/vmx.c | 37 +++++++++++-- xen/arch/x86/traps.c | 20 +++++-- xen/arch/x86/x86_emulate.c | 1 xen/include/asm-x86/hvm/support.h | 2 xen/include/asm-x86/hvm/vmx/vmx.h | 6 +- 8 files changed, 108 insertions(+), 64 deletions(-) diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/arch/x86/hvm/io.c --- a/xen/arch/x86/hvm/io.c Thu Nov 22 17:44:51 2007 +0000 +++ b/xen/arch/x86/hvm/io.c Thu Nov 22 18:28:47 2007 +0000 @@ -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); diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/arch/x86/hvm/platform.c --- a/xen/arch/x86/hvm/platform.c Thu Nov 22 17:44:51 2007 +0000 +++ b/xen/arch/x86/hvm/platform.c Thu Nov 22 18:28:47 2007 +0000 @@ -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 " diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Thu Nov 22 17:44:51 2007 +0000 +++ b/xen/arch/x86/hvm/svm/svm.c Thu Nov 22 18:28:47 2007 +0000 @@ -64,6 +64,9 @@ static int svm_reset_to_realmode( static int svm_reset_to_realmode( struct vcpu *v, struct cpu_user_regs *regs); static void svm_update_guest_cr(struct vcpu *v, unsigned int cr); +static void svm_update_guest_efer(struct vcpu *v); +static void svm_inject_exception( + unsigned int trapnr, int errcode, unsigned long cr2); /* va of hardware host save area */ static void *hsa[NR_CPUS] __read_mostly; @@ -71,15 +74,15 @@ static void *hsa[NR_CPUS] __read_mostly; /* vmcb used for extended host state */ static void *root_vmcb[NR_CPUS] __read_mostly; -static void svm_update_guest_efer(struct vcpu *v); - static void inline __update_guest_eip( struct cpu_user_regs *regs, unsigned int inst_len) { + struct vcpu *curr = current; + if ( unlikely((inst_len == 0) || (inst_len > 15)) ) { gdprintk(XENLOG_ERR, "Bad instruction length %u\n", inst_len); - domain_crash(current->domain); + domain_crash(curr->domain); return; } @@ -88,28 +91,10 @@ static void inline __update_guest_eip( regs->eip += inst_len; regs->eflags &= ~X86_EFLAGS_RF; - current->arch.hvm_svm.vmcb->interrupt_shadow = 0; -} - -static void svm_inject_exception( - struct vcpu *v, int trap, int ev, int error_code) -{ - eventinj_t event; - struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; - - if ( trap == TRAP_page_fault ) - HVMTRACE_2D(PF_INJECT, v, v->arch.hvm_vcpu.guest_cr[2], error_code); - else - HVMTRACE_2D(INJ_EXC, v, trap, error_code); - - event.bytes = 0; - event.fields.v = 1; - event.fields.type = X86_EVENTTYPE_HW_EXCEPTION; - event.fields.vector = trap; - event.fields.ev = ev; - event.fields.errorcode = error_code; - - vmcb->eventinj = event; + curr->arch.hvm_svm.vmcb->interrupt_shadow = 0; + + if ( regs->eflags & X86_EFLAGS_TF ) + svm_inject_exception(TRAP_debug, HVM_DELIVER_NO_ERROR_CODE, 0); } static void svm_cpu_down(void) @@ -171,7 +156,9 @@ static void __restore_debug_registers(st { struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; - ASSERT(!v->arch.hvm_vcpu.flag_dr_dirty); + if ( v->arch.hvm_vcpu.flag_dr_dirty ) + return; + v->arch.hvm_vcpu.flag_dr_dirty = 1; vmcb->dr_intercepts = 0; @@ -868,13 +855,38 @@ static void svm_vcpu_destroy(struct vcpu svm_destroy_vmcb(v); } -static void svm_hvm_inject_exception( +static void svm_inject_exception( unsigned int trapnr, int errcode, unsigned long cr2) { - struct vcpu *v = current; + struct vcpu *curr = current; + struct vmcb_struct *vmcb = curr->arch.hvm_svm.vmcb; + eventinj_t event; + + event.bytes = 0; + event.fields.v = 1; + event.fields.type = X86_EVENTTYPE_HW_EXCEPTION; + event.fields.vector = trapnr; + event.fields.ev = (errcode != HVM_DELIVER_NO_ERROR_CODE); + event.fields.errorcode = errcode; + + vmcb->eventinj = event; + 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); + { + vmcb->cr2 = curr->arch.hvm_vcpu.guest_cr[2] = cr2; + HVMTRACE_2D(PF_INJECT, curr, curr->arch.hvm_vcpu.guest_cr[2], errcode); + } + else + { + HVMTRACE_2D(INJ_EXC, curr, trapnr, errcode); + } + + if ( (trapnr == TRAP_debug) && + (guest_cpu_user_regs()->eflags & X86_EFLAGS_TF) ) + { + __restore_debug_registers(curr); + vmcb->dr6 |= 0x4000; + } } static int svm_event_pending(struct vcpu *v) @@ -904,7 +916,7 @@ static struct hvm_function_table svm_fun .update_vtpr = svm_update_vtpr, .stts = svm_stts, .set_tsc_offset = svm_set_tsc_offset, - .inject_exception = svm_hvm_inject_exception, + .inject_exception = svm_inject_exception, .init_ap_context = svm_init_ap_context, .init_hypercall_page = svm_init_hypercall_page, .event_pending = svm_event_pending @@ -1274,7 +1286,7 @@ static int svm_get_io_address( if (!seg) /* If no prefix, used DS. */ seg = &vmcb->ds; if (!long_mode && (seg->attr.fields.type & 0xa) == 0x8) { - svm_inject_exception(v, TRAP_gp_fault, 1, 0); + svm_inject_exception(TRAP_gp_fault, 0, 0); return 0; } } @@ -1283,7 +1295,7 @@ static int svm_get_io_address( reg = regs->edi; seg = &vmcb->es; /* Note: This is ALWAYS ES. */ if (!long_mode && (seg->attr.fields.type & 0xa) != 0x2) { - svm_inject_exception(v, TRAP_gp_fault, 1, 0); + svm_inject_exception(TRAP_gp_fault, 0, 0); return 0; } } @@ -1291,7 +1303,7 @@ static int svm_get_io_address( /* If the segment isn't present, give GP fault! */ if (!long_mode && !seg->attr.fields.p) { - svm_inject_exception(v, TRAP_gp_fault, 1, 0); + svm_inject_exception(TRAP_gp_fault, 0, 0); return 0; } @@ -1316,7 +1328,7 @@ static int svm_get_io_address( *addr + size - 1 > seg->limit : *addr <= seg->limit) { - svm_inject_exception(v, TRAP_gp_fault, 1, 0); + svm_inject_exception(TRAP_gp_fault, 0, 0); return 0; } @@ -1371,7 +1383,7 @@ static int svm_get_io_address( if (!is_canonical_address(*addr) || !is_canonical_address(*addr + size - 1)) { - svm_inject_exception(v, TRAP_gp_fault, 1, 0); + svm_inject_exception(TRAP_gp_fault, 0, 0); return 0; } if (*count > (1UL << 48) / size) @@ -1472,7 +1484,7 @@ static void svm_io_instruction(struct vc { /* The guest does not have the RAM address mapped. * Need to send in a page fault */ - svm_hvm_inject_exception(TRAP_page_fault, pfec, addr); + svm_inject_exception(TRAP_page_fault, pfec, addr); return; } paddr = (paddr_t)gfn << PAGE_SHIFT | (addr & ~PAGE_MASK); @@ -1500,7 +1512,7 @@ static void svm_io_instruction(struct vc addr += size - rv; gdprintk(XENLOG_DEBUG, "Pagefault reading non-io side " "of a page-spanning PIO: va=%#lx\n", addr); - svm_hvm_inject_exception(TRAP_page_fault, 0, addr); + svm_inject_exception(TRAP_page_fault, 0, addr); return; } } @@ -1796,7 +1808,7 @@ static void svm_do_msr_access( break; case MSR_K8_VM_HSAVE_PA: - svm_inject_exception(v, TRAP_gp_fault, 1, 0); + svm_inject_exception(TRAP_gp_fault, 0, 0); break; case MSR_IA32_MCG_CAP: @@ -1839,7 +1851,7 @@ static void svm_do_msr_access( regs->edx = edx; goto done; } - svm_inject_exception(v, TRAP_gp_fault, 1, 0); + svm_inject_exception(TRAP_gp_fault, 0, 0); return; } regs->eax = msr_content & 0xFFFFFFFF; @@ -1870,7 +1882,7 @@ static void svm_do_msr_access( break; case MSR_K8_VM_HSAVE_PA: - svm_inject_exception(v, TRAP_gp_fault, 1, 0); + svm_inject_exception(TRAP_gp_fault, 0, 0); break; case MSR_IA32_DEBUGCTLMSR: @@ -1931,7 +1943,7 @@ static void svm_vmexit_do_hlt(struct vmc inst_len = __get_instruction_length(curr, INSTR_HLT, NULL); __update_guest_eip(regs, inst_len); - /* Check for interrupt not handled or new interrupt. */ + /* Check for pending exception or new interrupt. */ if ( vmcb->eventinj.fields.v || ((intack.source != hvm_intsrc_none) && !svm_interrupt_blocked(current, intack)) ) @@ -2197,8 +2209,7 @@ asmlinkage void svm_vmexit_handler(struc break; } - v->arch.hvm_vcpu.guest_cr[2] = vmcb->cr2 = va; - svm_inject_exception(v, TRAP_page_fault, 1, regs->error_code); + svm_inject_exception(TRAP_page_fault, regs->error_code, va); break; } @@ -2296,7 +2307,7 @@ asmlinkage void svm_vmexit_handler(struc case VMEXIT_STGI: case VMEXIT_CLGI: case VMEXIT_SKINIT: - svm_inject_exception(v, TRAP_invalid_op, 0, 0); + svm_inject_exception(TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE, 0); break; case VMEXIT_NPF: diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Thu Nov 22 17:44:51 2007 +0000 +++ b/xen/arch/x86/hvm/vmx/vmx.c Thu Nov 22 18:28:47 2007 +0000 @@ -14,7 +14,6 @@ * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. - * */ #include <xen/config.h> @@ -417,7 +416,9 @@ static void vmx_save_dr(struct vcpu *v) static void __restore_debug_registers(struct vcpu *v) { - ASSERT(!v->arch.hvm_vcpu.flag_dr_dirty); + if ( v->arch.hvm_vcpu.flag_dr_dirty ) + return; + v->arch.hvm_vcpu.flag_dr_dirty = 1; write_debugreg(0, v->arch.guest_context.debugreg[0]); @@ -1102,10 +1103,19 @@ static void vmx_inject_exception( static void vmx_inject_exception( unsigned int trapnr, int errcode, unsigned long cr2) { - struct vcpu *v = current; - vmx_inject_hw_exception(v, trapnr, errcode); + struct vcpu *curr = current; + + vmx_inject_hw_exception(curr, trapnr, errcode); + if ( trapnr == TRAP_page_fault ) - v->arch.hvm_vcpu.guest_cr[2] = cr2; + curr->arch.hvm_vcpu.guest_cr[2] = cr2; + + if ( (trapnr == TRAP_debug) && + (guest_cpu_user_regs()->eflags & X86_EFLAGS_TF) ) + { + __restore_debug_registers(curr); + write_debugreg(6, read_debugreg(6) | 0x4000); + } } static void vmx_update_vtpr(struct vcpu *v, unsigned long value) @@ -1211,6 +1221,9 @@ static void __update_guest_eip(unsigned x &= ~(VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS); __vmwrite(GUEST_INTERRUPTIBILITY_INFO, x); } + + if ( regs->eflags & X86_EFLAGS_TF ) + vmx_inject_exception(TRAP_debug, HVM_DELIVER_NO_ERROR_CODE, 0); } static void vmx_do_no_device_fault(void) @@ -2589,7 +2602,17 @@ gp_fault: static void vmx_do_hlt(struct cpu_user_regs *regs) { - HVMTRACE_0D(HLT, current); + unsigned long intr_info = __vmread(VM_ENTRY_INTR_INFO); + struct vcpu *curr = current; + + /* Check for pending exception. */ + if ( intr_info & INTR_INFO_VALID_MASK ) + { + HVMTRACE_1D(HLT, curr, /*int pending=*/ 1); + return; + } + + HVMTRACE_1D(HLT, curr, /*int pending=*/ 0); hvm_hlt(regs->eflags); } @@ -2904,7 +2927,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: diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/arch/x86/traps.c --- a/xen/arch/x86/traps.c Thu Nov 22 17:44:51 2007 +0000 +++ b/xen/arch/x86/traps.c Thu Nov 22 18:28:47 2007 +0000 @@ -414,6 +414,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,8 @@ 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); @@ -1953,8 +1964,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: @@ -2284,8 +2294,8 @@ static int emulate_gate_op(struct cpu_us else sel |= (regs->cs & 3); - regs->eip = off; regs->cs = sel; + instruction_done(regs, off); #endif return 0; diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/arch/x86/x86_emulate.c --- a/xen/arch/x86/x86_emulate.c Thu Nov 22 17:44:51 2007 +0000 +++ b/xen/arch/x86/x86_emulate.c Thu Nov 22 18:28:47 2007 +0000 @@ -1635,6 +1635,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; diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/include/asm-x86/hvm/support.h --- a/xen/include/asm-x86/hvm/support.h Thu Nov 22 17:44:51 2007 +0000 +++ b/xen/include/asm-x86/hvm/support.h Thu Nov 22 18:28:47 2007 +0000 @@ -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) diff -r ae087a0fa2c9 -r fd3f6d814f6d xen/include/asm-x86/hvm/vmx/vmx.h --- a/xen/include/asm-x86/hvm/vmx/vmx.h Thu Nov 22 17:44:51 2007 +0000 +++ b/xen/include/asm-x86/hvm/vmx/vmx.h Thu Nov 22 18:28:47 2007 +0000 @@ -269,7 +269,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; } @@ -291,13 +291,13 @@ static inline void vmx_inject_extint(str 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-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |