diff --git a/xen/arch/x86/guest/Makefile b/xen/arch/x86/guest/Makefile
index 26fb4b1007..6ddaa3748f 100644
--- a/xen/arch/x86/guest/Makefile
+++ b/xen/arch/x86/guest/Makefile
@@ -1,4 +1,5 @@
 obj-y += hypercall_page.o
 obj-y += xen.o
+obj-$(CONFIG_XEN_GUEST) += xen-guest.o
 
 obj-bin-$(CONFIG_PVH_GUEST) += pvh-boot.init.o
diff --git a/xen/arch/x86/guest/xen-guest.c b/xen/arch/x86/guest/xen-guest.c
new file mode 100644
index 0000000000..65596ab1b1
--- /dev/null
+++ b/xen/arch/x86/guest/xen-guest.c
@@ -0,0 +1,301 @@
+/******************************************************************************
+ * arch/x86/guest/xen-guest.c
+ *
+ * Support for running a single VM with Xen as a guest.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (c) 2017 Citrix Systems Ltd.
+ */
+#include <xen/event.h>
+#include <xen/init.h>
+#include <xen/mm.h>
+#include <xen/pfn.h>
+#include <xen/rangeset.h>
+#include <xen/types.h>
+#include <xen/pv_console.h>
+
+#include <asm/apic.h>
+#include <asm/e820.h>
+#include <asm/guest.h>
+#include <asm/msr.h>
+#include <asm/processor.h>
+
+#include <public/arch-x86/cpuid.h>
+#include <public/hvm/params.h>
+
+bool __read_mostly xen_guest;
+
+static struct rangeset *mem;
+
+DEFINE_PER_CPU(unsigned int, vcpu_id);
+
+static struct vcpu_info *vcpu_info;
+static unsigned long vcpu_info_mapped[BITS_TO_LONGS(NR_CPUS)];
+DEFINE_PER_CPU(struct vcpu_info *, vcpu_info);
+
+static void map_shared_info(void)
+{
+    mfn_t mfn;
+    struct xen_add_to_physmap xatp = {
+        .domid = DOMID_SELF,
+        .space = XENMAPSPACE_shared_info,
+    };
+    unsigned int i;
+    unsigned long rc;
+
+    if ( hypervisor_alloc_unused_page(&mfn) )
+        panic("unable to reserve shared info memory page\n");
+
+    xatp.gpfn = mfn_x(mfn);
+    rc = xen_hypercall_memory_op(XENMEM_add_to_physmap, &xatp);
+    if ( rc )
+        panic("failed to map shared_info page: %ld\n", rc);
+
+    set_fixmap(FIX_XEN_SHARED_INFO, mfn_x(mfn) << PAGE_SHIFT);
+
+    /* Mask all upcalls */
+    for ( i = 0; i < ARRAY_SIZE(XEN_shared_info->evtchn_mask); i++ )
+        write_atomic(&XEN_shared_info->evtchn_mask[i], ~0ul);
+}
+
+static int map_vcpuinfo(void)
+{
+    unsigned int vcpu = this_cpu(vcpu_id);
+    struct vcpu_register_vcpu_info info;
+    int rc;
+
+    if ( !vcpu_info )
+    {
+        this_cpu(vcpu_info) = &XEN_shared_info->vcpu_info[vcpu];
+        return 0;
+    }
+
+    if ( test_bit(vcpu, vcpu_info_mapped) )
+    {
+        this_cpu(vcpu_info) = &vcpu_info[vcpu];
+        return 0;
+    }
+
+    info.mfn = virt_to_mfn(&vcpu_info[vcpu]);
+    info.offset = (unsigned long)&vcpu_info[vcpu] & ~PAGE_MASK;
+    rc = xen_hypercall_vcpu_op(VCPUOP_register_vcpu_info, vcpu, &info);
+    if ( rc )
+    {
+        BUG_ON(vcpu >= XEN_LEGACY_MAX_VCPUS);
+        this_cpu(vcpu_info) = &XEN_shared_info->vcpu_info[vcpu];
+    }
+    else
+    {
+        this_cpu(vcpu_info) = &vcpu_info[vcpu];
+        set_bit(vcpu, vcpu_info_mapped);
+    }
+
+    return rc;
+}
+
+static void set_vcpu_id(void)
+{
+    uint32_t cpuid_base, eax, ebx, ecx, edx;
+
+    cpuid_base = hypervisor_cpuid_base();
+
+    ASSERT(cpuid_base);
+
+    /* Fetch vcpu id from cpuid. */
+    cpuid(cpuid_base + 4, &eax, &ebx, &ecx, &edx);
+    if ( eax & XEN_HVM_CPUID_VCPU_ID_PRESENT )
+        this_cpu(vcpu_id) = ebx;
+    else
+        this_cpu(vcpu_id) = smp_processor_id();
+}
+
+static void __init init_memmap(void)
+{
+    unsigned int i;
+
+    mem = rangeset_new(NULL, "host memory map", 0);
+    if ( !mem )
+        panic("failed to allocate PFN usage rangeset\n");
+
+    /*
+     * Mark up to the last memory page (or 4GiB) as RAM. This is done because
+     * Xen doesn't know the position of possible MMIO holes, so at least try to
+     * avoid the know MMIO hole below 4GiB. Note that this is subject to future
+     * discussion and improvements.
+     */
+    if ( rangeset_add_range(mem, 0, max_t(unsigned long, max_page - 1,
+                                          PFN_DOWN(GB(4) - 1))) )
+        panic("unable to add RAM to in-use PFN rangeset\n");
+
+    for ( i = 0; i < e820.nr_map; i++ )
+    {
+        struct e820entry *e = &e820.map[i];
+
+        if ( rangeset_add_range(mem, PFN_DOWN(e->addr),
+                                PFN_UP(e->addr + e->size - 1)) )
+            panic("unable to add range [%#lx, %#lx] to in-use PFN rangeset\n",
+                  PFN_DOWN(e->addr), PFN_UP(e->addr + e->size - 1));
+    }
+}
+
+static void xen_evtchn_upcall(struct cpu_user_regs *regs)
+{
+    struct vcpu_info *vcpu_info = this_cpu(vcpu_info);
+    unsigned long pending;
+
+    vcpu_info->evtchn_upcall_pending = 0;
+    pending = xchg(&vcpu_info->evtchn_pending_sel, 0);
+
+    while ( pending )
+    {
+        unsigned int l1 = find_first_set_bit(pending);
+        unsigned long evtchn = xchg(&XEN_shared_info->evtchn_pending[l1], 0);
+
+        __clear_bit(l1, &pending);
+        evtchn &= ~XEN_shared_info->evtchn_mask[l1];
+        while ( evtchn )
+        {
+            unsigned int port = find_first_set_bit(evtchn);
+
+            __clear_bit(port, &evtchn);
+            port += l1 * BITS_PER_LONG;
+
+            if ( pv_console && port == pv_console_evtchn() )
+                pv_console_rx(regs);
+            else if ( pv_shim )
+                pv_shim_inject_evtchn(port);
+        }
+    }
+
+    ack_APIC_irq();
+}
+
+static void init_evtchn(void)
+{
+    static uint8_t evtchn_upcall_vector;
+    int rc;
+
+    if ( !evtchn_upcall_vector )
+        alloc_direct_apic_vector(&evtchn_upcall_vector, xen_evtchn_upcall);
+
+    ASSERT(evtchn_upcall_vector);
+
+    rc = xen_hypercall_set_evtchn_upcall_vector(this_cpu(vcpu_id),
+                                                evtchn_upcall_vector);
+    if ( rc )
+        panic("Unable to set evtchn upcall vector: %d\n", rc);
+
+    /* Trick toolstack to think we are enlightened */
+    {
+        struct xen_hvm_param a = {
+            .domid = DOMID_SELF,
+            .index = HVM_PARAM_CALLBACK_IRQ,
+            .value = 1,
+        };
+
+        BUG_ON(xen_hypercall_hvm_op(HVMOP_set_param, &a));
+    }
+}
+
+void __init hypervisor_setup(void)
+{
+    init_memmap();
+
+    map_shared_info();
+
+    set_vcpu_id();
+    vcpu_info = xzalloc_array(struct vcpu_info, nr_cpu_ids);
+    if ( map_vcpuinfo() )
+    {
+        xfree(vcpu_info);
+        vcpu_info = NULL;
+    }
+    if ( !vcpu_info && nr_cpu_ids > XEN_LEGACY_MAX_VCPUS )
+    {
+        unsigned int i;
+
+        for ( i = XEN_LEGACY_MAX_VCPUS; i < nr_cpu_ids; i++ )
+            __cpumask_clear_cpu(i, &cpu_present_map);
+        nr_cpu_ids = XEN_LEGACY_MAX_VCPUS;
+        printk(XENLOG_WARNING
+               "unable to map vCPU info, limiting vCPUs to: %u\n",
+               XEN_LEGACY_MAX_VCPUS);
+    }
+
+    init_evtchn();
+}
+
+void hypervisor_ap_setup(void)
+{
+    set_vcpu_id();
+    map_vcpuinfo();
+    init_evtchn();
+}
+
+int hypervisor_alloc_unused_page(mfn_t *mfn)
+{
+    unsigned long m;
+    int rc;
+
+    rc = rangeset_claim_range(mem, 1, &m);
+    if ( !rc )
+        *mfn = _mfn(m);
+
+    return rc;
+}
+
+int hypervisor_free_unused_page(mfn_t mfn)
+{
+    return rangeset_remove_range(mem, mfn_x(mfn), mfn_x(mfn));
+}
+
+static void ap_resume(void *unused)
+{
+    map_vcpuinfo();
+    init_evtchn();
+}
+
+void hypervisor_resume(void)
+{
+    /* Reset shared info page. */
+    map_shared_info();
+
+    /*
+     * Reset vcpu_info. Just clean the mapped bitmap and try to map the vcpu
+     * area again. On failure to map (when it was previously mapped) panic
+     * since it's impossible to safely shut down running guest vCPUs in order
+     * to meet the new XEN_LEGACY_MAX_VCPUS requirement.
+     */
+    bitmap_zero(vcpu_info_mapped, NR_CPUS);
+    if ( map_vcpuinfo() && nr_cpu_ids > XEN_LEGACY_MAX_VCPUS )
+        panic("unable to remap vCPU info and vCPUs > legacy limit\n");
+
+    /* Setup event channel upcall vector. */
+    init_evtchn();
+    smp_call_function(ap_resume, NULL, 1);
+
+    if ( pv_console )
+        pv_console_init();
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/x86/guest/xen.c b/xen/arch/x86/guest/xen.c
index 7b7a5badab..90d464bdbd 100644
--- a/xen/arch/x86/guest/xen.c
+++ b/xen/arch/x86/guest/xen.c
@@ -22,9 +22,7 @@
 #include <xen/init.h>
 #include <xen/mm.h>
 #include <xen/pfn.h>
-#include <xen/rangeset.h>
 #include <xen/types.h>
-#include <xen/pv_console.h>
 
 #include <asm/apic.h>
 #include <asm/e820.h>
@@ -35,17 +33,8 @@
 #include <public/arch-x86/cpuid.h>
 #include <public/hvm/params.h>
 
-bool __read_mostly xen_guest;
-
 static __read_mostly uint32_t xen_cpuid_base;
 extern char hypercall_page[];
-static struct rangeset *mem;
-
-DEFINE_PER_CPU(unsigned int, vcpu_id);
-
-static struct vcpu_info *vcpu_info;
-static unsigned long vcpu_info_mapped[BITS_TO_LONGS(NR_CPUS)];
-DEFINE_PER_CPU(struct vcpu_info *, vcpu_info);
 
 static void __init find_xen_leaves(void)
 {
@@ -87,254 +76,11 @@ void __init probe_hypervisor(void)
     xen_guest = true;
 }
 
-static void map_shared_info(void)
-{
-    mfn_t mfn;
-    struct xen_add_to_physmap xatp = {
-        .domid = DOMID_SELF,
-        .space = XENMAPSPACE_shared_info,
-    };
-    unsigned int i;
-    unsigned long rc;
-
-    if ( hypervisor_alloc_unused_page(&mfn) )
-        panic("unable to reserve shared info memory page\n");
-
-    xatp.gpfn = mfn_x(mfn);
-    rc = xen_hypercall_memory_op(XENMEM_add_to_physmap, &xatp);
-    if ( rc )
-        panic("failed to map shared_info page: %ld\n", rc);
-
-    set_fixmap(FIX_XEN_SHARED_INFO, mfn_x(mfn) << PAGE_SHIFT);
-
-    /* Mask all upcalls */
-    for ( i = 0; i < ARRAY_SIZE(XEN_shared_info->evtchn_mask); i++ )
-        write_atomic(&XEN_shared_info->evtchn_mask[i], ~0ul);
-}
-
-static int map_vcpuinfo(void)
-{
-    unsigned int vcpu = this_cpu(vcpu_id);
-    struct vcpu_register_vcpu_info info;
-    int rc;
-
-    if ( !vcpu_info )
-    {
-        this_cpu(vcpu_info) = &XEN_shared_info->vcpu_info[vcpu];
-        return 0;
-    }
-
-    if ( test_bit(vcpu, vcpu_info_mapped) )
-    {
-        this_cpu(vcpu_info) = &vcpu_info[vcpu];
-        return 0;
-    }
-
-    info.mfn = virt_to_mfn(&vcpu_info[vcpu]);
-    info.offset = (unsigned long)&vcpu_info[vcpu] & ~PAGE_MASK;
-    rc = xen_hypercall_vcpu_op(VCPUOP_register_vcpu_info, vcpu, &info);
-    if ( rc )
-    {
-        BUG_ON(vcpu >= XEN_LEGACY_MAX_VCPUS);
-        this_cpu(vcpu_info) = &XEN_shared_info->vcpu_info[vcpu];
-    }
-    else
-    {
-        this_cpu(vcpu_info) = &vcpu_info[vcpu];
-        set_bit(vcpu, vcpu_info_mapped);
-    }
-
-    return rc;
-}
-
-static void set_vcpu_id(void)
-{
-    uint32_t eax, ebx, ecx, edx;
-
-    ASSERT(xen_cpuid_base);
-
-    /* Fetch vcpu id from cpuid. */
-    cpuid(xen_cpuid_base + 4, &eax, &ebx, &ecx, &edx);
-    if ( eax & XEN_HVM_CPUID_VCPU_ID_PRESENT )
-        this_cpu(vcpu_id) = ebx;
-    else
-        this_cpu(vcpu_id) = smp_processor_id();
-}
-
-static void __init init_memmap(void)
-{
-    unsigned int i;
-
-    mem = rangeset_new(NULL, "host memory map", 0);
-    if ( !mem )
-        panic("failed to allocate PFN usage rangeset\n");
-
-    /*
-     * Mark up to the last memory page (or 4GiB) as RAM. This is done because
-     * Xen doesn't know the position of possible MMIO holes, so at least try to
-     * avoid the know MMIO hole below 4GiB. Note that this is subject to future
-     * discussion and improvements.
-     */
-    if ( rangeset_add_range(mem, 0, max_t(unsigned long, max_page - 1,
-                                          PFN_DOWN(GB(4) - 1))) )
-        panic("unable to add RAM to in-use PFN rangeset\n");
-
-    for ( i = 0; i < e820.nr_map; i++ )
-    {
-        struct e820entry *e = &e820.map[i];
-
-        if ( rangeset_add_range(mem, PFN_DOWN(e->addr),
-                                PFN_UP(e->addr + e->size - 1)) )
-            panic("unable to add range [%#lx, %#lx] to in-use PFN rangeset\n",
-                  PFN_DOWN(e->addr), PFN_UP(e->addr + e->size - 1));
-    }
-}
-
-static void xen_evtchn_upcall(struct cpu_user_regs *regs)
-{
-    struct vcpu_info *vcpu_info = this_cpu(vcpu_info);
-    unsigned long pending;
-
-    vcpu_info->evtchn_upcall_pending = 0;
-    pending = xchg(&vcpu_info->evtchn_pending_sel, 0);
-
-    while ( pending )
-    {
-        unsigned int l1 = find_first_set_bit(pending);
-        unsigned long evtchn = xchg(&XEN_shared_info->evtchn_pending[l1], 0);
-
-        __clear_bit(l1, &pending);
-        evtchn &= ~XEN_shared_info->evtchn_mask[l1];
-        while ( evtchn )
-        {
-            unsigned int port = find_first_set_bit(evtchn);
-
-            __clear_bit(port, &evtchn);
-            port += l1 * BITS_PER_LONG;
-
-            if ( pv_console && port == pv_console_evtchn() )
-                pv_console_rx(regs);
-            else if ( pv_shim )
-                pv_shim_inject_evtchn(port);
-        }
-    }
-
-    ack_APIC_irq();
-}
-
-static void init_evtchn(void)
-{
-    static uint8_t evtchn_upcall_vector;
-    int rc;
-
-    if ( !evtchn_upcall_vector )
-        alloc_direct_apic_vector(&evtchn_upcall_vector, xen_evtchn_upcall);
-
-    ASSERT(evtchn_upcall_vector);
-
-    rc = xen_hypercall_set_evtchn_upcall_vector(this_cpu(vcpu_id),
-                                                evtchn_upcall_vector);
-    if ( rc )
-        panic("Unable to set evtchn upcall vector: %d\n", rc);
-
-    /* Trick toolstack to think we are enlightened */
-    {
-        struct xen_hvm_param a = {
-            .domid = DOMID_SELF,
-            .index = HVM_PARAM_CALLBACK_IRQ,
-            .value = 1,
-        };
-
-        BUG_ON(xen_hypercall_hvm_op(HVMOP_set_param, &a));
-    }
-}
-
-void __init hypervisor_setup(void)
-{
-    init_memmap();
-
-    map_shared_info();
-
-    set_vcpu_id();
-    vcpu_info = xzalloc_array(struct vcpu_info, nr_cpu_ids);
-    if ( map_vcpuinfo() )
-    {
-        xfree(vcpu_info);
-        vcpu_info = NULL;
-    }
-    if ( !vcpu_info && nr_cpu_ids > XEN_LEGACY_MAX_VCPUS )
-    {
-        unsigned int i;
-
-        for ( i = XEN_LEGACY_MAX_VCPUS; i < nr_cpu_ids; i++ )
-            __cpumask_clear_cpu(i, &cpu_present_map);
-        nr_cpu_ids = XEN_LEGACY_MAX_VCPUS;
-        printk(XENLOG_WARNING
-               "unable to map vCPU info, limiting vCPUs to: %u\n",
-               XEN_LEGACY_MAX_VCPUS);
-    }
-
-    init_evtchn();
-}
-
-void hypervisor_ap_setup(void)
-{
-    set_vcpu_id();
-    map_vcpuinfo();
-    init_evtchn();
-}
-
-int hypervisor_alloc_unused_page(mfn_t *mfn)
-{
-    unsigned long m;
-    int rc;
-
-    rc = rangeset_claim_range(mem, 1, &m);
-    if ( !rc )
-        *mfn = _mfn(m);
-
-    return rc;
-}
-
-int hypervisor_free_unused_page(mfn_t mfn)
-{
-    return rangeset_remove_range(mem, mfn_x(mfn), mfn_x(mfn));
-}
-
 uint32_t hypervisor_cpuid_base(void)
 {
     return xen_cpuid_base;
 }
 
-static void ap_resume(void *unused)
-{
-    map_vcpuinfo();
-    init_evtchn();
-}
-
-void hypervisor_resume(void)
-{
-    /* Reset shared info page. */
-    map_shared_info();
-
-    /*
-     * Reset vcpu_info. Just clean the mapped bitmap and try to map the vcpu
-     * area again. On failure to map (when it was previously mapped) panic
-     * since it's impossible to safely shut down running guest vCPUs in order
-     * to meet the new XEN_LEGACY_MAX_VCPUS requirement.
-     */
-    bitmap_zero(vcpu_info_mapped, NR_CPUS);
-    if ( map_vcpuinfo() && nr_cpu_ids > XEN_LEGACY_MAX_VCPUS )
-        panic("unable to remap vCPU info and vCPUs > legacy limit\n");
-
-    /* Setup event channel upcall vector. */
-    init_evtchn();
-    smp_call_function(ap_resume, NULL, 1);
-
-    if ( pv_console )
-        pv_console_init();
-}
-
 /*
  * Local variables:
  * mode: C
