diff --git a/xen/arch/x86/hvm/event.c b/xen/arch/x86/hvm/event.c
index 26165b4..e8175e4 100644
--- a/xen/arch/x86/hvm/event.c
+++ b/xen/arch/x86/hvm/event.c
@@ -21,38 +21,8 @@
  * this program; If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <xen/vm_event.h>
 #include <asm/hvm/event.h>
 #include <asm/paging.h>
-#include <asm/monitor.h>
-#include <public/vm_event.h>
-
-bool_t hvm_event_cr(unsigned int index, unsigned long value, unsigned long old)
-{
-    struct vcpu *curr = current;
-    struct arch_domain *ad = &curr->domain->arch;
-    unsigned int ctrlreg_bitmask = monitor_ctrlreg_bitmask(index);
-
-    if ( (ad->monitor.write_ctrlreg_enabled & ctrlreg_bitmask) &&
-         (!(ad->monitor.write_ctrlreg_onchangeonly & ctrlreg_bitmask) ||
-          value != old) )
-    {
-        bool_t sync = !!(ad->monitor.write_ctrlreg_sync & ctrlreg_bitmask);
-
-        vm_event_request_t req = {
-            .reason = VM_EVENT_REASON_WRITE_CTRLREG,
-            .vcpu_id = curr->vcpu_id,
-            .u.write_ctrlreg.index = index,
-            .u.write_ctrlreg.new_value = value,
-            .u.write_ctrlreg.old_value = old
-        };
-
-        vm_event_monitor_traps(curr, sync, &req);
-        return 1;
-    }
-
-    return 0;
-}
 
 void hvm_event_msr(unsigned int msr, uint64_t value)
 {
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 4596662..26f8625 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -37,6 +37,7 @@
 #include <xen/mem_access.h>
 #include <xen/rangeset.h>
 #include <xen/vm_event.h>
+#include <xen/monitor.h>
 #include <asm/shadow.h>
 #include <asm/hap.h>
 #include <asm/current.h>
@@ -52,7 +53,6 @@
 #include <asm/traps.h>
 #include <asm/mc146818rtc.h>
 #include <asm/mce.h>
-#include <asm/monitor.h>
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/vpt.h>
 #include <asm/hvm/support.h>
diff --git a/xen/arch/x86/monitor.c b/xen/arch/x86/monitor.c
index 1e5445f..264f0fc 100644
--- a/xen/arch/x86/monitor.c
+++ b/xen/arch/x86/monitor.c
@@ -29,43 +29,6 @@ int arch_monitor_domctl_event(struct domain *d,
 
     switch ( mop->event )
     {
-    case XEN_DOMCTL_MONITOR_EVENT_WRITE_CTRLREG:
-    {
-        unsigned int ctrlreg_bitmask;
-        bool_t old_status;
-
-        /* sanity check: avoid left-shift undefined behavior */
-        if ( unlikely(mop->u.mov_to_cr.index > 31) )
-            return -EINVAL;
-
-        ctrlreg_bitmask = monitor_ctrlreg_bitmask(mop->u.mov_to_cr.index);
-        old_status = !!(ad->monitor.write_ctrlreg_enabled & ctrlreg_bitmask);
-
-        if ( unlikely(old_status == requested_status) )
-            return -EEXIST;
-
-        domain_pause(d);
-
-        if ( mop->u.mov_to_cr.sync )
-            ad->monitor.write_ctrlreg_sync |= ctrlreg_bitmask;
-        else
-            ad->monitor.write_ctrlreg_sync &= ~ctrlreg_bitmask;
-
-        if ( mop->u.mov_to_cr.onchangeonly )
-            ad->monitor.write_ctrlreg_onchangeonly |= ctrlreg_bitmask;
-        else
-            ad->monitor.write_ctrlreg_onchangeonly &= ~ctrlreg_bitmask;
-
-        if ( requested_status )
-            ad->monitor.write_ctrlreg_enabled |= ctrlreg_bitmask;
-        else
-            ad->monitor.write_ctrlreg_enabled &= ~ctrlreg_bitmask;
-
-        domain_unpause(d);
-
-        break;
-    }
-
     case XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR:
     {
         bool_t old_status = ad->monitor.mov_to_msr_enabled;
diff --git a/xen/arch/x86/vm_event.c b/xen/arch/x86/vm_event.c
index 94342d5..aa65840 100644
--- a/xen/arch/x86/vm_event.c
+++ b/xen/arch/x86/vm_event.c
@@ -19,7 +19,7 @@
  */
 
 #include <xen/vm_event.h>
-#include <asm/monitor.h>
+#include <xen/monitor.h>
 #include <asm/paging.h>
 #include <asm/hvm/vmx/vmx.h>
 
diff --git a/xen/common/monitor.c b/xen/common/monitor.c
index c46df5a..2366bae 100644
--- a/xen/common/monitor.c
+++ b/xen/common/monitor.c
@@ -62,6 +62,46 @@ int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *mop)
 
     switch ( mop->event )
     {
+#if CONFIG_X86
+    case XEN_DOMCTL_MONITOR_EVENT_WRITE_CTRLREG:
+    {
+        struct arch_domain *ad = &d->arch;
+        unsigned int ctrlreg_bitmask;
+        bool_t old_status;
+
+        /* sanity check: avoid left-shift undefined behavior */
+        if ( unlikely(mop->u.mov_to_cr.index > 31) )
+            return -EINVAL;
+
+        ctrlreg_bitmask = monitor_ctrlreg_bitmask(mop->u.mov_to_cr.index);
+        old_status = !!(ad->monitor.write_ctrlreg_enabled & ctrlreg_bitmask);
+
+        if ( unlikely(old_status == requested_status) )
+            return -EEXIST;
+
+        domain_pause(d);
+
+        if ( mop->u.mov_to_cr.sync )
+            ad->monitor.write_ctrlreg_sync |= ctrlreg_bitmask;
+        else
+            ad->monitor.write_ctrlreg_sync &= ~ctrlreg_bitmask;
+
+        if ( mop->u.mov_to_cr.onchangeonly )
+            ad->monitor.write_ctrlreg_onchangeonly |= ctrlreg_bitmask;
+        else
+            ad->monitor.write_ctrlreg_onchangeonly &= ~ctrlreg_bitmask;
+
+        if ( requested_status )
+            ad->monitor.write_ctrlreg_enabled |= ctrlreg_bitmask;
+        else
+            ad->monitor.write_ctrlreg_enabled &= ~ctrlreg_bitmask;
+
+        domain_unpause(d);
+
+        break;
+    }
+#endif
+
     case XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST:
     {
         bool_t old_status = d->monitor.guest_request_enabled;
diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 15152ba..53dc048 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -25,6 +25,7 @@
 #include <xen/wait.h>
 #include <xen/vm_event.h>
 #include <xen/mem_access.h>
+#include <xen/monitor.h>
 #include <asm/p2m.h>
 #include <asm/altp2m.h>
 #include <xsm/xsm.h>
@@ -823,6 +824,36 @@ int vm_event_monitor_traps(struct vcpu *v, uint8_t sync,
     return 1;
 }
 
+#if CONFIG_X86
+bool_t vm_event_monitor_cr(unsigned int index, unsigned long value,
+                           unsigned long old)
+{
+    struct vcpu *curr = current;
+    struct arch_domain *ad = &curr->domain->arch;
+    unsigned int ctrlreg_bitmask = monitor_ctrlreg_bitmask(index);
+
+    if ( (ad->monitor.write_ctrlreg_enabled & ctrlreg_bitmask) &&
+         (!(ad->monitor.write_ctrlreg_onchangeonly & ctrlreg_bitmask) ||
+          value != old) )
+    {
+        bool_t sync = !!(ad->monitor.write_ctrlreg_sync & ctrlreg_bitmask);
+
+        vm_event_request_t req = {
+            .reason = VM_EVENT_REASON_WRITE_CTRLREG,
+            .vcpu_id = curr->vcpu_id,
+            .u.write_ctrlreg.index = index,
+            .u.write_ctrlreg.new_value = value,
+            .u.write_ctrlreg.old_value = old
+        };
+
+        vm_event_monitor_traps(curr, sync, &req);
+        return 1;
+    }
+
+    return 0;
+}
+#endif
+
 void vm_event_monitor_guest_request(void)
 {
     struct vcpu *curr = current;
diff --git a/xen/include/asm-x86/hvm/event.h b/xen/include/asm-x86/hvm/event.h
index 504bd66..7fb9d96 100644
--- a/xen/include/asm-x86/hvm/event.h
+++ b/xen/include/asm-x86/hvm/event.h
@@ -19,6 +19,7 @@
 #ifndef __ASM_X86_HVM_EVENT_H__
 #define __ASM_X86_HVM_EVENT_H__
 
+#include <xen/vm_event.h>
 #include <public/vm_event.h>
 
 enum hvm_event_breakpoint_type
@@ -27,19 +28,13 @@ enum hvm_event_breakpoint_type
     HVM_EVENT_SINGLESTEP_BREAKPOINT,
 };
 
-/*
- * Called for current VCPU on crX/MSR changes by guest.
- * The event might not fire if the client has subscribed to it in onchangeonly
- * mode, hence the bool_t return type for control register write events.
- */
-bool_t hvm_event_cr(unsigned int index, unsigned long value,
-                    unsigned long old);
-#define hvm_event_crX(cr, new, old) \
-    hvm_event_cr(VM_EVENT_X86_##cr, new, old)
 void hvm_event_msr(unsigned int msr, uint64_t value);
 int hvm_event_breakpoint(unsigned long rip,
                          enum hvm_event_breakpoint_type type);
 
+#define hvm_event_crX(cr, new, old) \
+    vm_event_monitor_cr(VM_EVENT_X86_##cr, new, old)
+
 #endif /* __ASM_X86_HVM_EVENT_H__ */
 
 /*
diff --git a/xen/include/asm-x86/monitor.h b/xen/include/asm-x86/monitor.h
index 7a662f9..99538b9 100644
--- a/xen/include/asm-x86/monitor.h
+++ b/xen/include/asm-x86/monitor.h
@@ -24,8 +24,6 @@
 
 #include <xen/sched.h>
 
-#define monitor_ctrlreg_bitmask(ctrlreg_index) (1U << (ctrlreg_index))
-
 static inline
 int arch_monitor_domctl_op(struct domain *d, struct xen_domctl_monitor_op *mop)
 {
diff --git a/xen/include/xen/monitor.h b/xen/include/xen/monitor.h
index 7015e6d..422fd93 100644
--- a/xen/include/xen/monitor.h
+++ b/xen/include/xen/monitor.h
@@ -25,6 +25,10 @@
 struct domain;
 struct xen_domctl_monitor_op;
 
+#if CONFIG_X86
+#define monitor_ctrlreg_bitmask(ctrlreg_index) (1U << (ctrlreg_index))
+#endif
+
 int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *op);
 
 #endif /* __XEN_MONITOR_H__ */
diff --git a/xen/include/xen/vm_event.h b/xen/include/xen/vm_event.h
index f124143..71ae84a 100644
--- a/xen/include/xen/vm_event.h
+++ b/xen/include/xen/vm_event.h
@@ -96,6 +96,16 @@ void vm_event_vcpu_unpause(struct vcpu *v);
 int vm_event_monitor_traps(struct vcpu *v, uint8_t sync,
                            vm_event_request_t *req);
 
+#if CONFIG_X86
+/*
+ * Called for the current vCPU on control-register changes by guest.
+ * The event might not fire if the client has subscribed to it in onchangeonly
+ * mode, hence the bool_t return type for control register write events.
+ */
+bool_t vm_event_monitor_cr(unsigned int index, unsigned long value,
+                           unsigned long old);
+#endif
+
 void vm_event_monitor_guest_request(void);
 
 #endif /* __VM_EVENT_H__ */
