diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile
index 149b6b3901..718fe44455 100644
--- a/xen/arch/arm/arm64/Makefile
+++ b/xen/arch/arm/arm64/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_LIVEPATCH) += livepatch.o
 obj-y += smpboot.o
 obj-y += traps.o
 obj-y += vfp.o
+obj-y += vsysreg.o
diff --git a/xen/arch/arm/arm64/vsysreg.c b/xen/arch/arm/arm64/vsysreg.c
new file mode 100644
index 0000000000..c57ac12503
--- /dev/null
+++ b/xen/arch/arm/arm64/vsysreg.c
@@ -0,0 +1,229 @@
+/*
+ * xen/arch/arm/arm64/sysreg.c
+ *
+ * Emulate system registers trapped.
+ *
+ * Copyright (c) 2011 Citrix Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/sched.h>
+
+#include <asm/current.h>
+#include <asm/regs.h>
+#include <asm/traps.h>
+#include <asm/vtimer.h>
+
+void do_sysreg(struct cpu_user_regs *regs,
+               const union hsr hsr)
+{
+    int regidx = hsr.sysreg.reg;
+    struct vcpu *v = current;
+
+    switch ( hsr.bits & HSR_SYSREG_REGS_MASK )
+    {
+    /*
+     * HCR_EL2.TACR
+     *
+     * ARMv8 (DDI 0487A.d): D7.2.1
+     */
+    case HSR_SYSREG_ACTLR_EL1:
+        if ( psr_mode_is_user(regs) )
+            return inject_undef_exception(regs, hsr);
+        if ( hsr.sysreg.read )
+            set_user_reg(regs, regidx, v->arch.actlr);
+        break;
+
+    /*
+     * MDCR_EL2.TDRA
+     *
+     * ARMv8 (DDI 0487A.d): D1-1508 Table D1-57
+     */
+    case HSR_SYSREG_MDRAR_EL1:
+        return handle_ro_raz(regs, regidx, hsr.sysreg.read, hsr, 1);
+
+    /*
+     * MDCR_EL2.TDOSA
+     *
+     * ARMv8 (DDI 0487A.d): D1-1509 Table D1-58
+     *
+     * Unhandled:
+     *    OSLSR_EL1
+     *    DBGPRCR_EL1
+     */
+    case HSR_SYSREG_OSLAR_EL1:
+        return handle_wo_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
+    case HSR_SYSREG_OSDLR_EL1:
+        return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
+
+    /*
+     * MDCR_EL2.TDA
+     *
+     * ARMv8 (DDI 0487A.d): D1-1510 Table D1-59
+     *
+     * Unhandled:
+     *    MDCCINT_EL1
+     *    DBGDTR_EL0
+     *    DBGDTRRX_EL0
+     *    DBGDTRTX_EL0
+     *    OSDTRRX_EL1
+     *    OSDTRTX_EL1
+     *    OSECCR_EL1
+     *    DBGCLAIMSET_EL1
+     *    DBGCLAIMCLR_EL1
+     *    DBGAUTHSTATUS_EL1
+     */
+    case HSR_SYSREG_MDSCR_EL1:
+        return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
+    case HSR_SYSREG_MDCCSR_EL0:
+        /*
+         * Accessible at EL0 only if MDSCR_EL1.TDCC is set to 0. We emulate that
+         * register as RAZ/WI above. So RO at both EL0 and EL1.
+         */
+        return handle_ro_raz(regs, regidx, hsr.sysreg.read, hsr, 0);
+    HSR_SYSREG_DBG_CASES(DBGBVR):
+    HSR_SYSREG_DBG_CASES(DBGBCR):
+    HSR_SYSREG_DBG_CASES(DBGWVR):
+    HSR_SYSREG_DBG_CASES(DBGWCR):
+        return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
+
+    /*
+     * MDCR_EL2.TPM
+     *
+     * ARMv8 (DDI 0487A.d): D1-1511 Table D1-61
+     *
+     * Unhandled:
+     *    PMEVCNTR<n>_EL0
+     *    PMEVTYPER<n>_EL0
+     *    PMCCFILTR_EL0
+     * MDCR_EL2.TPMCR
+     *
+     * ARMv7 (DDI 0406C.b): B1.14.17
+     * ARMv8 (DDI 0487A.d): D1-1511 Table D1-62
+     *
+     * NB: Both MDCR_EL2.TPM and MDCR_EL2.TPMCR cause trapping of PMCR.
+     */
+    case HSR_SYSREG_PMINTENSET_EL1:
+    case HSR_SYSREG_PMINTENCLR_EL1:
+        /*
+         * Accessible from EL1 only, but if EL0 trap happens handle as
+         * undef.
+         */
+        return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
+    case HSR_SYSREG_PMUSERENR_EL0:
+        /* RO at EL0. RAZ/WI at EL1 */
+        if ( psr_mode_is_user(regs) )
+            return handle_ro_raz(regs, regidx, hsr.sysreg.read, hsr, 0);
+        else
+            return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
+    case HSR_SYSREG_PMCR_EL0:
+    case HSR_SYSREG_PMCNTENSET_EL0:
+    case HSR_SYSREG_PMCNTENCLR_EL0:
+    case HSR_SYSREG_PMOVSCLR_EL0:
+    case HSR_SYSREG_PMSWINC_EL0:
+    case HSR_SYSREG_PMSELR_EL0:
+    case HSR_SYSREG_PMCEID0_EL0:
+    case HSR_SYSREG_PMCEID1_EL0:
+    case HSR_SYSREG_PMCCNTR_EL0:
+    case HSR_SYSREG_PMXEVTYPER_EL0:
+    case HSR_SYSREG_PMXEVCNTR_EL0:
+    case HSR_SYSREG_PMOVSSET_EL0:
+        /*
+         * Accessible at EL0 only if PMUSERENR_EL0.EN is set. We
+         * emulate that register as 0 above.
+         */
+        return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
+
+    /*
+     * !CNTHCTL_EL2.EL1PCEN
+     *
+     * ARMv8 (DDI 0487A.d): D1-1510 Table D1-60
+     */
+    case HSR_SYSREG_CNTP_CTL_EL0:
+    case HSR_SYSREG_CNTP_TVAL_EL0:
+    case HSR_SYSREG_CNTP_CVAL_EL0:
+        if ( !vtimer_emulate(regs, hsr) )
+            return inject_undef_exception(regs, hsr);
+        break;
+
+    /*
+     * HCR_EL2.FMO or HCR_EL2.IMO
+     *
+     * GIC Architecture Specification (IHI 0069C): Section 4.6.3
+     */
+    case HSR_SYSREG_ICC_SGI1R_EL1:
+    case HSR_SYSREG_ICC_ASGI1R_EL1:
+    case HSR_SYSREG_ICC_SGI0R_EL1:
+
+        if ( !vgic_emulate(regs, hsr) )
+            return inject_undef64_exception(regs, hsr.len);
+        break;
+
+    /*
+     *  ICC_SRE_EL2.Enable = 0
+     *
+     *  GIC Architecture Specification (IHI 0069C): Section 8.1.9
+     */
+    case HSR_SYSREG_ICC_SRE_EL1:
+        /*
+         * Trapped when the guest is using GICv2 whilst the platform
+         * interrupt controller is GICv3. In this case, the register
+         * should be emulate as RAZ/WI to tell the guest to use the GIC
+         * memory mapped interface (i.e GICv2 compatibility).
+         */
+        return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
+
+    /*
+     * HCR_EL2.TIDCP
+     *
+     * ARMv8 (DDI 0487A.d): D1-1501 Table D1-43
+     *
+     *  - Reserved control space for IMPLEMENTATION DEFINED functionality.
+     *
+     * CPTR_EL2.TTA
+     *
+     * ARMv8 (DDI 0487A.d): D1-1507 Table D1-54
+     *
+     *  - All implemented trace registers.
+     *
+     * And all other unknown registers.
+     */
+    default:
+        {
+            const struct hsr_sysreg sysreg = hsr.sysreg;
+
+            gdprintk(XENLOG_ERR,
+                     "%s %d, %d, c%d, c%d, %d %s x%d @ 0x%"PRIregister"\n",
+                     sysreg.read ? "mrs" : "msr",
+                     sysreg.op0, sysreg.op1,
+                     sysreg.crn, sysreg.crm,
+                     sysreg.op2,
+                     sysreg.read ? "=>" : "<=",
+                     sysreg.reg, regs->pc);
+            gdprintk(XENLOG_ERR, "unhandled 64-bit sysreg access %#x\n",
+                     hsr.bits & HSR_SYSREG_REGS_MASK);
+            inject_undef_exception(regs, hsr);
+            return;
+        }
+    }
+
+    regs->pc += 4;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 1c334a7b99..f00aa48892 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -2295,204 +2295,6 @@ static void do_cp(struct cpu_user_regs *regs, const union hsr hsr)
     inject_undef_exception(regs, hsr);
 }
 
-#ifdef CONFIG_ARM_64
-static void do_sysreg(struct cpu_user_regs *regs,
-                      const union hsr hsr)
-{
-    int regidx = hsr.sysreg.reg;
-    struct vcpu *v = current;
-
-    switch ( hsr.bits & HSR_SYSREG_REGS_MASK )
-    {
-    /*
-     * HCR_EL2.TACR
-     *
-     * ARMv8 (DDI 0487A.d): D7.2.1
-     */
-    case HSR_SYSREG_ACTLR_EL1:
-        if ( psr_mode_is_user(regs) )
-            return inject_undef_exception(regs, hsr);
-        if ( hsr.sysreg.read )
-            set_user_reg(regs, regidx, v->arch.actlr);
-        break;
-
-    /*
-     * MDCR_EL2.TDRA
-     *
-     * ARMv8 (DDI 0487A.d): D1-1508 Table D1-57
-     */
-    case HSR_SYSREG_MDRAR_EL1:
-        return handle_ro_raz(regs, regidx, hsr.sysreg.read, hsr, 1);
-
-    /*
-     * MDCR_EL2.TDOSA
-     *
-     * ARMv8 (DDI 0487A.d): D1-1509 Table D1-58
-     *
-     * Unhandled:
-     *    OSLSR_EL1
-     *    DBGPRCR_EL1
-     */
-    case HSR_SYSREG_OSLAR_EL1:
-        return handle_wo_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
-    case HSR_SYSREG_OSDLR_EL1:
-        return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
-
-    /*
-     * MDCR_EL2.TDA
-     *
-     * ARMv8 (DDI 0487A.d): D1-1510 Table D1-59
-     *
-     * Unhandled:
-     *    MDCCINT_EL1
-     *    DBGDTR_EL0
-     *    DBGDTRRX_EL0
-     *    DBGDTRTX_EL0
-     *    OSDTRRX_EL1
-     *    OSDTRTX_EL1
-     *    OSECCR_EL1
-     *    DBGCLAIMSET_EL1
-     *    DBGCLAIMCLR_EL1
-     *    DBGAUTHSTATUS_EL1
-     */
-    case HSR_SYSREG_MDSCR_EL1:
-        return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
-    case HSR_SYSREG_MDCCSR_EL0:
-        /*
-         * Accessible at EL0 only if MDSCR_EL1.TDCC is set to 0. We emulate that
-         * register as RAZ/WI above. So RO at both EL0 and EL1.
-         */
-        return handle_ro_raz(regs, regidx, hsr.sysreg.read, hsr, 0);
-    HSR_SYSREG_DBG_CASES(DBGBVR):
-    HSR_SYSREG_DBG_CASES(DBGBCR):
-    HSR_SYSREG_DBG_CASES(DBGWVR):
-    HSR_SYSREG_DBG_CASES(DBGWCR):
-        return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
-
-    /*
-     * MDCR_EL2.TPM
-     *
-     * ARMv8 (DDI 0487A.d): D1-1511 Table D1-61
-     *
-     * Unhandled:
-     *    PMEVCNTR<n>_EL0
-     *    PMEVTYPER<n>_EL0
-     *    PMCCFILTR_EL0
-     * MDCR_EL2.TPMCR
-     *
-     * ARMv7 (DDI 0406C.b): B1.14.17
-     * ARMv8 (DDI 0487A.d): D1-1511 Table D1-62
-     *
-     * NB: Both MDCR_EL2.TPM and MDCR_EL2.TPMCR cause trapping of PMCR.
-     */
-    case HSR_SYSREG_PMINTENSET_EL1:
-    case HSR_SYSREG_PMINTENCLR_EL1:
-        /*
-         * Accessible from EL1 only, but if EL0 trap happens handle as
-         * undef.
-         */
-        return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
-    case HSR_SYSREG_PMUSERENR_EL0:
-        /* RO at EL0. RAZ/WI at EL1 */
-        if ( psr_mode_is_user(regs) )
-            return handle_ro_raz(regs, regidx, hsr.sysreg.read, hsr, 0);
-        else
-            return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
-    case HSR_SYSREG_PMCR_EL0:
-    case HSR_SYSREG_PMCNTENSET_EL0:
-    case HSR_SYSREG_PMCNTENCLR_EL0:
-    case HSR_SYSREG_PMOVSCLR_EL0:
-    case HSR_SYSREG_PMSWINC_EL0:
-    case HSR_SYSREG_PMSELR_EL0:
-    case HSR_SYSREG_PMCEID0_EL0:
-    case HSR_SYSREG_PMCEID1_EL0:
-    case HSR_SYSREG_PMCCNTR_EL0:
-    case HSR_SYSREG_PMXEVTYPER_EL0:
-    case HSR_SYSREG_PMXEVCNTR_EL0:
-    case HSR_SYSREG_PMOVSSET_EL0:
-        /*
-         * Accessible at EL0 only if PMUSERENR_EL0.EN is set. We
-         * emulate that register as 0 above.
-         */
-        return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
-
-    /*
-     * !CNTHCTL_EL2.EL1PCEN
-     *
-     * ARMv8 (DDI 0487A.d): D1-1510 Table D1-60
-     */
-    case HSR_SYSREG_CNTP_CTL_EL0:
-    case HSR_SYSREG_CNTP_TVAL_EL0:
-    case HSR_SYSREG_CNTP_CVAL_EL0:
-        if ( !vtimer_emulate(regs, hsr) )
-            return inject_undef_exception(regs, hsr);
-        break;
-
-    /*
-     * HCR_EL2.FMO or HCR_EL2.IMO
-     *
-     * GIC Architecture Specification (IHI 0069C): Section 4.6.3
-     */
-    case HSR_SYSREG_ICC_SGI1R_EL1:
-    case HSR_SYSREG_ICC_ASGI1R_EL1:
-    case HSR_SYSREG_ICC_SGI0R_EL1:
-
-        if ( !vgic_emulate(regs, hsr) )
-            return inject_undef64_exception(regs, hsr.len);
-        break;
-
-    /*
-     *  ICC_SRE_EL2.Enable = 0
-     *
-     *  GIC Architecture Specification (IHI 0069C): Section 8.1.9
-     */
-    case HSR_SYSREG_ICC_SRE_EL1:
-        /*
-         * Trapped when the guest is using GICv2 whilst the platform
-         * interrupt controller is GICv3. In this case, the register
-         * should be emulate as RAZ/WI to tell the guest to use the GIC
-         * memory mapped interface (i.e GICv2 compatibility).
-         */
-        return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
-
-    /*
-     * HCR_EL2.TIDCP
-     *
-     * ARMv8 (DDI 0487A.d): D1-1501 Table D1-43
-     *
-     *  - Reserved control space for IMPLEMENTATION DEFINED functionality.
-     *
-     * CPTR_EL2.TTA
-     *
-     * ARMv8 (DDI 0487A.d): D1-1507 Table D1-54
-     *
-     *  - All implemented trace registers.
-     *
-     * And all other unknown registers.
-     */
-    default:
-        {
-            const struct hsr_sysreg sysreg = hsr.sysreg;
-
-            gdprintk(XENLOG_ERR,
-                     "%s %d, %d, c%d, c%d, %d %s x%d @ 0x%"PRIregister"\n",
-                     sysreg.read ? "mrs" : "msr",
-                     sysreg.op0, sysreg.op1,
-                     sysreg.crn, sysreg.crm,
-                     sysreg.op2,
-                     sysreg.read ? "=>" : "<=",
-                     sysreg.reg, regs->pc);
-            gdprintk(XENLOG_ERR, "unhandled 64-bit sysreg access %#x\n",
-                     hsr.bits & HSR_SYSREG_REGS_MASK);
-            inject_undef_exception(regs, hsr);
-            return;
-        }
-    }
-
-    regs->pc += 4;
-}
-#endif
-
 void dump_guest_s1_walk(struct domain *d, vaddr_t addr)
 {
     register_t ttbcr = READ_SYSREG(TCR_EL1);
diff --git a/xen/include/asm-arm/arm64/traps.h b/xen/include/asm-arm/arm64/traps.h
index e5e5a4a036..2379b578cb 100644
--- a/xen/include/asm-arm/arm64/traps.h
+++ b/xen/include/asm-arm/arm64/traps.h
@@ -3,6 +3,9 @@
 
 void inject_undef64_exception(struct cpu_user_regs *regs, int instr_len);
 
+void do_sysreg(struct cpu_user_regs *regs,
+               const union hsr hsr);
+
 #endif /* __ASM_ARM64_TRAPS__ */
 /*
  * Local variables:
