]> xenbits.xensource.com Git - xen.git/commitdiff
x86/debug: Plumb pending_dbg through the monitor and devicemodel interfaces
authorAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 31 May 2018 17:50:50 +0000 (18:50 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Fri, 27 Dec 2019 16:37:42 +0000 (16:37 +0000)
Like %cr2 for pagefaults, %dr6 contains ancillary information for debug
exceptions, and needs similar handling.

For xendevicemodel_inject_event(), no ABI change is needed (although an API
one would be ideal).  Switch from 'cr2' to 'extra' in variable names which
don't constitute an API change, and update the documentation to match.

For the monitor interface, vm_event_debug needs extending with a pending_dbg
field.  This shall behave like the VT-x PENDING_DBG control.  Extend
hvm_monitor_debug() and for now, always pass in 0 - this will be fixed
eventually, when other hypervisor bugfixes are complete.

While modifying hvm_monitor_debug(), take the opportunity to correct trap type
and instruction length from unsigned long to unsigned int, as they are both
tiny values.

Finally, adjust xen-access.c to the new expectations.  Introspection tools
intercepting debug exceptions should mirror the new pending_dbg field into
xendevicemodel_inject_event() for %dr6 to be processed correctly for the
guest.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Tamas K Lengyel <tamas@tklengyel.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Petre Pircalabu <ppircalabu@bitdefender.com>
tools/libs/devicemodel/core.c
tools/libs/devicemodel/include/xendevicemodel.h
tools/tests/xen-access/xen-access.c
xen/arch/x86/hvm/monitor.c
xen/arch/x86/hvm/svm/svm.c
xen/arch/x86/hvm/vmx/vmx.c
xen/include/asm-x86/hvm/monitor.h
xen/include/public/hvm/dm_op.h
xen/include/public/vm_event.h

index f76e3d305e004dcac2f4f6da8b8216a153f94ca7..db501d9e80fc3abbe2cc744c2777f40561f3c9f1 100644 (file)
@@ -536,7 +536,7 @@ int xendevicemodel_set_mem_type(
 
 int xendevicemodel_inject_event(
     xendevicemodel_handle *dmod, domid_t domid, int vcpu, uint8_t vector,
-    uint8_t type, uint32_t error_code, uint8_t insn_len, uint64_t cr2)
+    uint8_t type, uint32_t error_code, uint8_t insn_len, uint64_t extra)
 {
     struct xen_dm_op op;
     struct xen_dm_op_inject_event *data;
@@ -551,7 +551,7 @@ int xendevicemodel_inject_event(
     data->type = type;
     data->error_code = error_code;
     data->insn_len = insn_len;
-    data->cr2 = cr2;
+    data->cr2 = extra;
 
     return xendevicemodel_op(dmod, domid, 1, &op, sizeof(op));
 }
index 08cb0d437492d9797ba32fb7b2fcd39b4a556f75..e877f5c8a6e4b63496ffb4d91b23bff77ec8ab77 100644 (file)
@@ -309,12 +309,12 @@ int xendevicemodel_set_mem_type(
  * @parm type the event type (see the definition of enum x86_event_type)
  * @parm error_code the error code or ~0 to skip
  * @parm insn_len the instruction length
- * @parm cr2 the value of CR2 for page faults
+ * @parm extra type-specific extra data (%cr2 for #PF, pending_dbg for #DB)
  * @return 0 on success, -1 on failure.
  */
 int xendevicemodel_inject_event(
     xendevicemodel_handle *dmod, domid_t domid, int vcpu, uint8_t vector,
-    uint8_t type, uint32_t error_code, uint8_t insn_len, uint64_t cr2);
+    uint8_t type, uint32_t error_code, uint8_t insn_len, uint64_t extra);
 
 /**
  * Shuts the domain down.
index 6aaee16d6751a96db964063c59d7644954502569..1ab4f6705f58df0d6077b656460d10e4a9ceae7f 100644 (file)
@@ -826,18 +826,19 @@ int main(int argc, char *argv[])
 
                 break;
             case VM_EVENT_REASON_DEBUG_EXCEPTION:
-                printf("Debug exception: rip=%016"PRIx64", vcpu %d. Type: %u. Length: %u\n",
+                printf("Debug exception: rip=%016"PRIx64", vcpu %d. Type: %u. Length: %u. Pending dbg 0x%08"PRIx64"\n",
                        req.data.regs.x86.rip,
                        req.vcpu_id,
                        req.u.debug_exception.type,
-                       req.u.debug_exception.insn_length);
+                       req.u.debug_exception.insn_length,
+                       req.u.debug_exception.pending_dbg);
 
                 /* Reinject */
                 rc = xc_hvm_inject_trap(xch, domain_id, req.vcpu_id,
                                         X86_TRAP_DEBUG,
                                         req.u.debug_exception.type, -1,
                                         req.u.debug_exception.insn_length,
-                                        req.data.regs.x86.cr2);
+                                        req.u.debug_exception.pending_dbg);
                 if (rc < 0)
                 {
                     ERROR("Error %d injecting breakpoint\n", rc);
index 85996a3eddad09a4033c9f1ccb4c299550a34ab3..f5d89e71d1b47e2de1941fea5e8f4bdf721a8050 100644 (file)
@@ -133,7 +133,8 @@ static inline unsigned long gfn_of_rip(unsigned long rip)
 }
 
 int hvm_monitor_debug(unsigned long rip, enum hvm_monitor_debug_type type,
-                      unsigned long trap_type, unsigned long insn_length)
+                      unsigned int trap_type, unsigned int insn_length,
+                      unsigned int pending_dbg)
 {
    /*
     * rc < 0 error in monitor/vm_event, crash
@@ -178,6 +179,7 @@ int hvm_monitor_debug(unsigned long rip, enum hvm_monitor_debug_type type,
             return 0;
         req.reason = VM_EVENT_REASON_DEBUG_EXCEPTION;
         req.u.debug_exception.gfn = gfn_of_rip(rip);
+        req.u.debug_exception.pending_dbg = pending_dbg;
         req.u.debug_exception.type = trap_type;
         req.u.debug_exception.insn_length = insn_length;
         sync = !!ad->monitor.debug_exception_sync;
index fb2677b9a6bb3bcc175c0eaaf01de897c4652b96..b1c376d4554ac60b8966948b23cb9b80636d85d4 100644 (file)
@@ -2644,7 +2644,7 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
 
             rc = hvm_monitor_debug(regs->rip,
                                    HVM_MONITOR_DEBUG_EXCEPTION,
-                                   trap_type, insn_len);
+                                   trap_type, insn_len, 0);
             if ( rc < 0 )
                 goto unexpected_exit_type;
             if ( !rc )
@@ -2673,7 +2673,7 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
            rc = hvm_monitor_debug(regs->rip,
                                   HVM_MONITOR_SOFTWARE_BREAKPOINT,
                                   X86_EVENTTYPE_SW_EXCEPTION,
-                                  insn_len);
+                                  insn_len, 0);
            if ( rc < 0 )
                goto unexpected_exit_type;
            if ( !rc )
index 56733b72b5dfdef32ccb110d87d8af9bb2a2e141..f83f1026387714f6f8142f780e38517fdad04198 100644 (file)
@@ -3872,7 +3872,7 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
 
                 rc = hvm_monitor_debug(regs->rip,
                                        HVM_MONITOR_DEBUG_EXCEPTION,
-                                       trap_type, insn_len);
+                                       trap_type, insn_len, 0);
 
                 if ( rc < 0 )
                     goto exit_and_crash;
@@ -3893,7 +3893,7 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
                 rc = hvm_monitor_debug(regs->rip,
                                        HVM_MONITOR_SOFTWARE_BREAKPOINT,
                                        X86_EVENTTYPE_SW_EXCEPTION,
-                                       insn_len);
+                                       insn_len, 0);
 
                 if ( rc < 0 )
                     goto exit_and_crash;
@@ -4196,7 +4196,7 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
         {
             hvm_monitor_debug(regs->rip,
                               HVM_MONITOR_SINGLESTEP_BREAKPOINT,
-                              0, 0);
+                              0, 0, 0);
 
             if ( v->domain->debugger_attached )
                 domain_pause_for_debugger();
index 325b44674dda896eac4e180cb654b30dd3ed9b99..66de24cb75aac674b34e9f0a9f6ef7c06e0a867e 100644 (file)
@@ -42,7 +42,8 @@ void hvm_monitor_descriptor_access(uint64_t exit_info,
                                    uint64_t vmx_exit_qualification,
                                    uint8_t descriptor, bool is_write);
 int hvm_monitor_debug(unsigned long rip, enum hvm_monitor_debug_type type,
-                      unsigned long trap_type, unsigned long insn_length);
+                      unsigned int trap_type, unsigned int insn_length,
+                      unsigned int pending_dbg);
 int hvm_monitor_cpuid(unsigned long insn_length, unsigned int leaf,
                       unsigned int subleaf);
 void hvm_monitor_interrupt(unsigned int vector, unsigned int type,
index d3b554d01971170715e6da88923ba54a21d65391..fd00e9d761e1dff805c0cded716128e4ae0074f5 100644 (file)
@@ -324,7 +324,7 @@ struct xen_dm_op_inject_event {
     /* IN - error code (or ~0 to skip) */
     uint32_t error_code;
     uint32_t pad1;
-    /* IN - CR2 for page faults */
+    /* IN - type-specific extra data (%cr2 for #PF, pending_dbg for #DB) */
     uint64_aligned_t cr2;
 };
 
index 0ffec27d627771aa71622ef22e41446ed3221ac2..fdd3ad8a308ab656c65ef03a4eb5c83a6e46884a 100644 (file)
@@ -291,6 +291,7 @@ struct vm_event_fast_singlestep {
 
 struct vm_event_debug {
     uint64_t gfn;
+    uint64_t pending_dbg; /* Behaves like the VT-x PENDING_DBG field. */
     uint32_t insn_length;
     uint8_t type;        /* HVMOP_TRAP_* */
     uint8_t _pad[3];