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