@@ -2422,6 +2422,14 @@ static bool cf_check svm_get_pending_event(
info->type = vmcb->event_inj.type;
info->error_code = vmcb->event_inj.ec;
+ if ( info->type == X86_EVENTTYPE_HW_EXCEPTION &&
+ info->vector == X86_EXC_DB )
+ {
+ unsigned long dr6 = v->arch.hvm.flag_dr_dirty ?
+ vmcb_get_dr6(vmcb) : v->arch.dr6;
+ info->extra = dr6 & ~DR_STATUS_RESERVED_ONE;
+ }
+
return true;
}
@@ -2733,16 +2741,28 @@ void svm_vmexit_handler(void)
if ( !v->domain->debugger_attached )
{
unsigned int trap_type;
+ unsigned long exit_pending_dbg;
if ( likely(exit_reason != VMEXIT_ICEBP) )
{
trap_type = X86_EVENTTYPE_HW_EXCEPTION;
insn_len = 0;
+
+ __restore_debug_registers(vmcb, v);
+
+ /*
+ * NOTE: This is slightly wrong; old bits in dr6 are not
+ * automatically cleared by CPU on #DB, so it's not exactly
+ * equivalent to PENDING_DBG_EXCEPTIONS in semantics.
+ */
+ exit_pending_dbg = vmcb_get_dr6(vmcb) & ~DR_STATUS_RESERVED_ONE;
+ vmcb_set_dr6(vmcb, DR_STATUS_RESERVED_ONE);
}
else
{
trap_type = X86_EVENTTYPE_PRI_SW_EXCEPTION;
insn_len = svm_get_insn_len(v, INSTR_ICEBP);
+ exit_pending_dbg = 0;
if ( !insn_len )
break;
@@ -2750,12 +2770,20 @@ void svm_vmexit_handler(void)
rc = hvm_monitor_debug(regs->rip,
HVM_MONITOR_DEBUG_EXCEPTION,
- trap_type, insn_len, 0);
+ trap_type, insn_len, exit_pending_dbg);
if ( rc < 0 )
goto unexpected_exit_type;
if ( !rc )
- hvm_inject_exception(X86_EXC_DB,
- trap_type, insn_len, X86_EVENT_NO_EC);
+ {
+ if (trap_type == X86_EVENTTYPE_HW_EXCEPTION)
+ {
+ /* Updates DR6 where debugger can peek. */
+ hvm_inject_debug_exception(exit_pending_dbg);
+ }
+ else
+ hvm_inject_exception(X86_EXC_DB,
+ trap_type, insn_len, X86_EVENT_NO_EC);
+ }
}
else
domain_pause_for_debugger();
@@ -2469,6 +2469,14 @@ static bool cf_check vmx_get_pending_event(
info->type = MASK_EXTR(intr_info, INTR_INFO_INTR_TYPE_MASK);
info->error_code = error_code;
+ if ( info->type == X86_EVENTTYPE_HW_EXCEPTION &&
+ info->vector == X86_EXC_DB )
+ {
+ unsigned long dr6 = v->arch.hvm.flag_dr_dirty ?
+ read_debugreg(6) : v->arch.dr6;
+ info->extra = dr6 & ~DR_STATUS_RESERVED_ONE;
+ }
+
return true;
}
@@ -4240,13 +4248,11 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
{
case X86_EXC_DB:
/*
- * Updates DR6 where debugger can peek (See 3B 23.2.1,
- * Table 23-1, "Exit Qualification for Debug Exceptions").
+ * See 3B 23.2.1, Table 23-1, "Exit Qualification for Debug
+ * Exceptions".
*/
__vmread(EXIT_QUALIFICATION, &exit_qualification);
HVMTRACE_1D(TRAP_DEBUG, exit_qualification);
- __restore_debug_registers(v);
- write_debugreg(6, exit_qualification | DR_STATUS_RESERVED_ONE);
/*
* Work around SingleStep + STI/MovSS VMEntry failures.
@@ -4285,22 +4291,32 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
if ( !v->domain->debugger_attached )
{
- unsigned long insn_len = 0;
+ unsigned long exit_pending_dbg = 0, insn_len = 0;
int rc;
unsigned long trap_type = MASK_EXTR(intr_info,
INTR_INFO_INTR_TYPE_MASK);
- if ( trap_type >= X86_EVENTTYPE_SW_INTERRUPT )
+ if ( trap_type == X86_EVENTTYPE_HW_EXCEPTION )
+ exit_pending_dbg = exit_qualification;
+ else if ( trap_type >= X86_EVENTTYPE_SW_INTERRUPT )
__vmread(VM_EXIT_INSTRUCTION_LEN, &insn_len);
rc = hvm_monitor_debug(regs->rip,
HVM_MONITOR_DEBUG_EXCEPTION,
- trap_type, insn_len, 0);
+ trap_type, insn_len, exit_pending_dbg);
if ( rc < 0 )
goto exit_and_crash;
if ( !rc )
- vmx_propagate_intr(intr_info);
+ {
+ if ( trap_type == X86_EVENTTYPE_HW_EXCEPTION )
+ {
+ /* Updates DR6 where debugger can peek. */
+ hvm_inject_debug_exception(exit_pending_dbg);
+ }
+ else
+ vmx_propagate_intr(intr_info);
+ }
}
else
domain_pause_for_debugger();
Commit 21867648033d ("x86/debug: Plumb pending_dbg through the monitor and devicemodel interfaces") introduced pending_dbg, but did not actually populate or use the field. Signed-off-by: Jinoh Kang <jinoh.kang.kr@gmail.com> --- xen/arch/x86/hvm/svm/svm.c | 34 +++++++++++++++++++++++++++++++--- xen/arch/x86/hvm/vmx/vmx.c | 32 ++++++++++++++++++++++++-------- 2 files changed, 55 insertions(+), 11 deletions(-)