--- a/tools/libxc/xc_misc.c
+++ b/tools/libxc/xc_misc.c
@@ -584,31 +584,15 @@ int xc_hvm_inject_trap(
     uint32_t type, uint32_t error_code, uint32_t insn_len,
     uint64_t cr2)
 {
-    DECLARE_HYPERCALL_BUFFER(struct xen_hvm_inject_trap, arg);
-    int rc;
+    DECLARE_HVMCTL(inject_trap, dom,
+                   .vcpuid     = vcpu,
+                   .type       = type,
+                   .vector     = vector,
+                   .insn_len   = insn_len,
+                   .error_code = error_code,
+                   .cr2        = cr2);
 
-    arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg));
-    if ( arg == NULL )
-    {
-        PERROR("Could not allocate memory for xc_hvm_inject_trap hypercall");
-        return -1;
-    }
-
-    arg->domid       = dom;
-    arg->vcpuid      = vcpu;
-    arg->vector      = vector;
-    arg->type        = type;
-    arg->error_code  = error_code;
-    arg->insn_len    = insn_len;
-    arg->cr2         = cr2;
-
-    rc = xencall2(xch->xcall, __HYPERVISOR_hvm_op,
-                  HVMOP_inject_trap,
-                  HYPERCALL_BUFFER_AS_ARG(arg));
-
-    xc_hypercall_buffer_free(xch, arg);
-
-    return rc;
+    return do_hvmctl(xch, &hvmctl);
 }
 
 int xc_livepatch_upload(xc_interface *xch,
--- a/tools/tests/xen-access/xen-access.c
+++ b/tools/tests/xen-access/xen-access.c
@@ -41,6 +41,7 @@
 #include <xenctrl.h>
 #include <xenevtchn.h>
 #include <xen/vm_event.h>
+#include <xen/hvm/control.h>
 
 #if defined(__arm__) || defined(__aarch64__)
 #include <xen/arch-arm.h>
@@ -643,7 +644,7 @@ int main(int argc, char *argv[])
                 /* Reinject */
                 rc = xc_hvm_inject_trap(
                     xch, domain_id, req.vcpu_id, 3,
-                    HVMOP_TRAP_sw_exc, -1, 0, 0);
+                    XEN_HVMCTL_TRAP_sw_exc, -1, 0, 0);
                 if (rc < 0)
                 {
                     ERROR("Error %d injecting breakpoint\n", rc);
--- a/xen/arch/x86/hvm/control.c
+++ b/xen/arch/x86/hvm/control.c
@@ -200,6 +200,32 @@ static int set_mem_type(struct domain *d
     return 0;
 }
 
+static int inject_trap(struct domain *d,
+                       const struct xen_hvm_inject_trap *op)
+{
+    struct vcpu *v;
+
+    if ( !is_hvm_domain(d) )
+        return -EINVAL;
+
+    if ( op->rsvd8 || op->rsvd32 )
+        return -EINVAL;
+
+    if ( op->vcpuid >= d->max_vcpus || (v = d->vcpu[op->vcpuid]) == NULL )
+        return -ENOENT;
+
+    if ( v->arch.hvm_vcpu.inject_trap.vector != -1 )
+        return -EBUSY;
+
+    v->arch.hvm_vcpu.inject_trap.vector     = op->vector;
+    v->arch.hvm_vcpu.inject_trap.type       = op->type;
+    v->arch.hvm_vcpu.inject_trap.error_code = op->error_code;
+    v->arch.hvm_vcpu.inject_trap.insn_len   = op->insn_len;
+    v->arch.hvm_vcpu.inject_trap.cr2        = op->cr2;
+
+    return 0;
+}
+
 long do_hvmctl(XEN_GUEST_HANDLE_PARAM(xen_hvmctl_t) u_hvmctl)
 {
     xen_hvmctl_t op;
@@ -258,6 +284,10 @@ long do_hvmctl(XEN_GUEST_HANDLE_PARAM(xe
         rc = set_mem_type(d, &op.u.set_mem_type, &op.opaque);
         break;
 
+    case XEN_HVMCTL_inject_trap:
+        rc = inject_trap(d, &op.u.inject_trap);
+        break;
+
     default:
         rc = -EOPNOTSUPP;
         break;
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -5366,48 +5366,6 @@ long do_hvm_op(unsigned long op, XEN_GUE
         break;
     }
 
-    case HVMOP_inject_trap: 
-    {
-        xen_hvm_inject_trap_t tr;
-        struct domain *d;
-        struct vcpu *v;
-
-        if ( copy_from_guest(&tr, arg, 1 ) )
-            return -EFAULT;
-
-        rc = rcu_lock_remote_domain_by_id(tr.domid, &d);
-        if ( rc != 0 )
-            return rc;
-
-        rc = -EINVAL;
-        if ( !is_hvm_domain(d) )
-            goto injtrap_fail;
-
-        rc = xsm_hvm_control(XSM_DM_PRIV, d, op);
-        if ( rc )
-            goto injtrap_fail;
-
-        rc = -ENOENT;
-        if ( tr.vcpuid >= d->max_vcpus || (v = d->vcpu[tr.vcpuid]) == NULL )
-            goto injtrap_fail;
-        
-        if ( v->arch.hvm_vcpu.inject_trap.vector != -1 )
-            rc = -EBUSY;
-        else 
-        {
-            v->arch.hvm_vcpu.inject_trap.vector = tr.vector;
-            v->arch.hvm_vcpu.inject_trap.type = tr.type;
-            v->arch.hvm_vcpu.inject_trap.error_code = tr.error_code;
-            v->arch.hvm_vcpu.inject_trap.insn_len = tr.insn_len;
-            v->arch.hvm_vcpu.inject_trap.cr2 = tr.cr2;
-            rc = 0;
-        }
-
-    injtrap_fail:
-        rcu_unlock_domain(d);
-        break;
-    }
-
     case HVMOP_guest_request_vm_event:
         if ( guest_handle_is_null(arg) )
             vm_event_monitor_guest_request();
--- a/xen/include/public/hvm/control.h
+++ b/xen/include/public/hvm/control.h
@@ -89,6 +89,37 @@ struct xen_hvm_set_mem_type {
     uint64_aligned_t first_gfn;
 };
 
+/* XEN_HVMCTL_inject_trap */
+/*
+ * Inject a trap into a VCPU, which will get taken up on the next
+ * scheduling of it. Note that the caller should know enough of the
+ * state of the CPU before injecting, to know what the effect of
+ * injecting the trap will be.
+ */
+struct xen_hvm_inject_trap {
+    /* VCPU */
+    uint32_t vcpuid;
+    /* Trap type (XEN_HVMCTL_TRAP_*). */
+    uint8_t type;
+/* NB. This enumeration precisely matches hvm.h:X86_EVENTTYPE_*. */
+#define XEN_HVMCTL_TRAP_ext_int    0 /* external interrupt */
+#define XEN_HVMCTL_TRAP_nmi        2 /* NMI */
+#define XEN_HVMCTL_TRAP_hw_exc     3 /* hardware exception */
+#define XEN_HVMCTL_TRAP_sw_int     4 /* software interrupt (CD nn) */
+#define XEN_HVMCTL_TRAP_pri_sw_exc 5 /* ICEBP (F1) */
+#define XEN_HVMCTL_TRAP_sw_exc     6 /* INT3 (CC), INTO (CE) */
+    /* Vector number. */
+    uint8_t vector;
+    /* Instruction length. */
+    uint8_t insn_len;
+    uint8_t rsvd8;
+    /* Error code, or ~0u to skip. */
+    uint32_t error_code;
+    uint32_t rsvd32;
+    /* CR2 for page faults. */
+    uint64_aligned_t cr2;
+};
+
 struct xen_hvmctl {
     uint16_t interface_version;    /* XEN_HVMCTL_INTERFACE_VERSION */
     domid_t domain;
@@ -99,6 +130,7 @@ struct xen_hvmctl {
 #define XEN_HVMCTL_track_dirty_vram              4
 #define XEN_HVMCTL_modified_memory               5
 #define XEN_HVMCTL_set_mem_type                  6
+#define XEN_HVMCTL_inject_trap                   7
     uint64_t opaque;               /* Must be zero on initial invocation. */
     union {
         struct xen_hvm_set_pci_intx_level set_pci_intx_level;
@@ -107,6 +139,7 @@ struct xen_hvmctl {
         struct xen_hvm_track_dirty_vram track_dirty_vram;
         struct xen_hvm_modified_memory modified_memory;
         struct xen_hvm_set_mem_type set_mem_type;
+        struct xen_hvm_inject_trap inject_trap;
         uint8_t pad[120];
     } u;
 };
--- a/xen/include/public/hvm/hvm_op.h
+++ b/xen/include/public/hvm/hvm_op.h
@@ -123,49 +123,6 @@ struct xen_hvm_xentrace {
 typedef struct xen_hvm_xentrace xen_hvm_xentrace_t;
 DEFINE_XEN_GUEST_HANDLE(xen_hvm_xentrace_t);
 
-/* Following tools-only interfaces may change in future. */
-#if defined(__XEN__) || defined(__XEN_TOOLS__)
-
-/* Deprecated by XENMEM_access_op_set_access */
-#define HVMOP_set_mem_access        12
-
-/* Deprecated by XENMEM_access_op_get_access */
-#define HVMOP_get_mem_access        13
-
-#define HVMOP_inject_trap            14
-/* Inject a trap into a VCPU, which will get taken up on the next
- * scheduling of it. Note that the caller should know enough of the
- * state of the CPU before injecting, to know what the effect of
- * injecting the trap will be.
- */
-struct xen_hvm_inject_trap {
-    /* Domain to be queried. */
-    domid_t domid;
-    /* VCPU */
-    uint32_t vcpuid;
-    /* Vector number */
-    uint32_t vector;
-    /* Trap type (HVMOP_TRAP_*) */
-    uint32_t type;
-/* NB. This enumeration precisely matches hvm.h:X86_EVENTTYPE_* */
-# define HVMOP_TRAP_ext_int    0 /* external interrupt */
-# define HVMOP_TRAP_nmi        2 /* nmi */
-# define HVMOP_TRAP_hw_exc     3 /* hardware exception */
-# define HVMOP_TRAP_sw_int     4 /* software interrupt (CD nn) */
-# define HVMOP_TRAP_pri_sw_exc 5 /* ICEBP (F1) */
-# define HVMOP_TRAP_sw_exc     6 /* INT3 (CC), INTO (CE) */
-    /* Error code, or ~0u to skip */
-    uint32_t error_code;
-    /* Intruction length */
-    uint32_t insn_len;
-    /* CR2 for page faults */
-    uint64_aligned_t cr2;
-};
-typedef struct xen_hvm_inject_trap xen_hvm_inject_trap_t;
-DEFINE_XEN_GUEST_HANDLE(xen_hvm_inject_trap_t);
-
-#endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */
-
 #define HVMOP_get_mem_type    15
 /* Return hvmmem_type_t for the specified pfn. */
 struct xen_hvm_get_mem_type {
--- a/xen/xsm/flask/policy/access_vectors
+++ b/xen/xsm/flask/policy/access_vectors
@@ -273,8 +273,7 @@ class hvm
 # XEN_HVMCTL_track_dirty_vram
     trackdirtyvram
 # XEN_HVMCTL_modified_memory, HVMOP_get_mem_type, XEN_HVMCTL_set_mem_type,
-# HVMOP_set_mem_access, HVMOP_get_mem_access, HVMOP_pagetable_dying,
-# HVMOP_inject_trap
+# HVMOP_pagetable_dying, XEN_HVMCTL_inject_trap
     hvmctl
 # XEN_DOMCTL_mem_sharing_op and XENMEM_sharing_op_{share,add_physmap} with:
 #  source = the domain making the hypercall
