--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+#ifndef __ASM_44X_H__
+#define __ASM_44X_H__
+
+#include <linux/kvm_host.h>
+
+/* XXX Can't include mmu-44x.h because it redefines struct mm_context. */
+#define PPC44x_TLB_SIZE 64
+
+struct kvmppc_vcpu_44x {
+       /* Unmodified copy of the guest's TLB. */
+       struct kvmppc_44x_tlbe guest_tlb[PPC44x_TLB_SIZE];
+       /* TLB that's actually used when the guest is running. */
+       struct kvmppc_44x_tlbe shadow_tlb[PPC44x_TLB_SIZE];
+       /* Pages which are referenced in the shadow TLB. */
+       struct page *shadow_pages[PPC44x_TLB_SIZE];
+
+       /* Track which TLB entries we've modified in the current exit. */
+       u8 shadow_tlb_mod[PPC44x_TLB_SIZE];
+
+       struct kvm_vcpu vcpu;
+};
+
+static inline struct kvmppc_vcpu_44x *to_44x(struct kvm_vcpu *vcpu)
+{
+       return container_of(vcpu, struct kvmppc_vcpu_44x, vcpu);
+}
+
+#endif /* __ASM_44X_H__ */
 
 struct kvm_arch {
 };
 
-/* XXX Can't include mmu-44x.h because it redefines struct mm_context. */
-#define PPC44x_TLB_SIZE 64
-
 struct kvm_vcpu_arch {
-       /* Unmodified copy of the guest's TLB. */
-       struct kvmppc_44x_tlbe guest_tlb[PPC44x_TLB_SIZE];
-       /* TLB that's actually used when the guest is running. */
-       struct kvmppc_44x_tlbe shadow_tlb[PPC44x_TLB_SIZE];
-       /* Pages which are referenced in the shadow TLB. */
-       struct page *shadow_pages[PPC44x_TLB_SIZE];
-
-       /* Track which TLB entries we've modified in the current exit. */
-       u8 shadow_tlb_mod[PPC44x_TLB_SIZE];
-
        u32 host_stack;
        u32 host_pid;
        u32 host_dbcr0;
 
 
 /* Core-specific hooks */
 
+extern struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm,
+                                                unsigned int id);
+extern void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu);
 extern int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu);
 extern int kvmppc_core_check_processor_compat(void);
 extern int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu,
 extern int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs);
 extern int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt);
 
+extern int kvmppc_booke_init(void);
+extern void kvmppc_booke_exit(void);
+
 extern void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu);
 
 #endif /* __POWERPC_KVM_PPC_H__ */
 
 #include <linux/mm.h>
 #include <linux/suspend.h>
 #include <linux/hrtimer.h>
-#ifdef CONFIG_KVM
-#include <linux/kvm_host.h>
-#endif
 #ifdef CONFIG_PPC64
 #include <linux/time.h>
 #include <linux/hardirq.h>
 #ifdef CONFIG_PPC_ISERIES
 #include <asm/iseries/alpaca.h>
 #endif
+#ifdef CONFIG_KVM
+#include <asm/kvm_44x.h>
+#endif
 
 #if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
 #include "head_booke.h"
 #ifdef CONFIG_KVM
        DEFINE(TLBE_BYTES, sizeof(struct kvmppc_44x_tlbe));
 
+       DEFINE(VCPU_TO_44X, offsetof(struct kvmppc_vcpu_44x, vcpu));
+       DEFINE(VCPU44x_SHADOW_TLB,
+              offsetof(struct kvmppc_vcpu_44x, shadow_tlb));
+       DEFINE(VCPU44x_SHADOW_MOD,
+              offsetof(struct kvmppc_vcpu_44x, shadow_tlb_mod));
+
        DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack));
        DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid));
-       DEFINE(VCPU_SHADOW_TLB, offsetof(struct kvm_vcpu, arch.shadow_tlb));
-       DEFINE(VCPU_SHADOW_MOD, offsetof(struct kvm_vcpu, arch.shadow_tlb_mod));
        DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr));
        DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr));
        DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr));
 
  */
 
 #include <linux/kvm_host.h>
+#include <linux/err.h>
+
 #include <asm/reg.h>
 #include <asm/cputable.h>
 #include <asm/tlbflush.h>
+#include <asm/kvm_44x.h>
+#include <asm/kvm_ppc.h>
 
 #include "44x_tlb.h"
 
 
 int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
 {
-       struct kvmppc_44x_tlbe *tlbe = &vcpu->arch.guest_tlb[0];
+       struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
+       struct kvmppc_44x_tlbe *tlbe = &vcpu_44x->guest_tlb[0];
 
        tlbe->tid = 0;
        tlbe->word0 = PPC44x_TLB_16M | PPC44x_TLB_VALID;
 int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu,
                                struct kvm_translation *tr)
 {
+       struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
        struct kvmppc_44x_tlbe *gtlbe;
        int index;
        gva_t eaddr;
                return 0;
        }
 
-       gtlbe = &vcpu->arch.guest_tlb[index];
+       gtlbe = &vcpu_44x->guest_tlb[index];
 
        tr->physical_address = tlb_xlate(gtlbe, eaddr);
        /* XXX what does "writeable" and "usermode" even mean? */
 
        return 0;
 }
+
+struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
+{
+       struct kvmppc_vcpu_44x *vcpu_44x;
+       struct kvm_vcpu *vcpu;
+       int err;
+
+       vcpu_44x = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
+       if (!vcpu_44x) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       vcpu = &vcpu_44x->vcpu;
+       err = kvm_vcpu_init(vcpu, kvm, id);
+       if (err)
+               goto free_vcpu;
+
+       return vcpu;
+
+free_vcpu:
+       kmem_cache_free(kvm_vcpu_cache, vcpu_44x);
+out:
+       return ERR_PTR(err);
+}
+
+void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
+{
+       struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
+
+       kvm_vcpu_uninit(vcpu);
+       kmem_cache_free(kvm_vcpu_cache, vcpu_44x);
+}
+
+static int kvmppc_44x_init(void)
+{
+       int r;
+
+       r = kvmppc_booke_init();
+       if (r)
+               return r;
+
+       return kvm_init(NULL, sizeof(struct kvmppc_vcpu_44x), THIS_MODULE);
+}
+
+static void kvmppc_44x_exit(void)
+{
+       kvmppc_booke_exit();
+}
+
+module_init(kvmppc_44x_init);
+module_exit(kvmppc_44x_exit);
 
 #include <linux/highmem.h>
 #include <asm/mmu-44x.h>
 #include <asm/kvm_ppc.h>
+#include <asm/kvm_44x.h>
 
 #include "44x_tlb.h"
 
                        "nr", "tid", "word0", "word1", "word2");
 
        for (i = 0; i < PPC44x_TLB_SIZE; i++) {
-               tlbe = &vcpu->arch.guest_tlb[i];
+               tlbe = &vcpu_44x->guest_tlb[i];
                if (tlbe->word0 & PPC44x_TLB_VALID)
                        printk(" G%2d |  %02X | %08X | %08X | %08X |\n",
                               i, tlbe->tid, tlbe->word0, tlbe->word1,
        }
 
        for (i = 0; i < PPC44x_TLB_SIZE; i++) {
-               tlbe = &vcpu->arch.shadow_tlb[i];
+               tlbe = &vcpu_44x->shadow_tlb[i];
                if (tlbe->word0 & PPC44x_TLB_VALID)
                        printk(" S%2d | %02X | %08X | %08X | %08X |\n",
                               i, tlbe->tid, tlbe->word0, tlbe->word1,
 int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr, unsigned int pid,
                          unsigned int as)
 {
+       struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
        int i;
 
        /* XXX Replace loop with fancy data structures. */
        for (i = 0; i < PPC44x_TLB_SIZE; i++) {
-               struct kvmppc_44x_tlbe *tlbe = &vcpu->arch.guest_tlb[i];
+               struct kvmppc_44x_tlbe *tlbe = &vcpu_44x->guest_tlb[i];
                unsigned int tid;
 
                if (eaddr < get_tlb_eaddr(tlbe))
 struct kvmppc_44x_tlbe *kvmppc_44x_itlb_search(struct kvm_vcpu *vcpu,
                                                gva_t eaddr)
 {
+       struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
        unsigned int as = !!(vcpu->arch.msr & MSR_IS);
        unsigned int index;
 
        index = kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
        if (index == -1)
                return NULL;
-       return &vcpu->arch.guest_tlb[index];
+       return &vcpu_44x->guest_tlb[index];
 }
 
 struct kvmppc_44x_tlbe *kvmppc_44x_dtlb_search(struct kvm_vcpu *vcpu,
                                                gva_t eaddr)
 {
+       struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
        unsigned int as = !!(vcpu->arch.msr & MSR_DS);
        unsigned int index;
 
        index = kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
        if (index == -1)
                return NULL;
-       return &vcpu->arch.guest_tlb[index];
+       return &vcpu_44x->guest_tlb[index];
 }
 
 static int kvmppc_44x_tlbe_is_writable(struct kvmppc_44x_tlbe *tlbe)
 static void kvmppc_44x_shadow_release(struct kvm_vcpu *vcpu,
                                       unsigned int index)
 {
-       struct kvmppc_44x_tlbe *stlbe = &vcpu->arch.shadow_tlb[index];
-       struct page *page = vcpu->arch.shadow_pages[index];
+       struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
+       struct kvmppc_44x_tlbe *stlbe = &vcpu_44x->shadow_tlb[index];
+       struct page *page = vcpu_44x->shadow_pages[index];
 
        if (get_tlb_v(stlbe)) {
                if (kvmppc_44x_tlbe_is_writable(stlbe))
 
 void kvmppc_tlbe_set_modified(struct kvm_vcpu *vcpu, unsigned int i)
 {
-    vcpu->arch.shadow_tlb_mod[i] = 1;
+       struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
+
+       vcpu_44x->shadow_tlb_mod[i] = 1;
 }
 
 /* Caller must ensure that the specified guest TLB entry is safe to insert into
 void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn, u64 asid,
                     u32 flags)
 {
+       struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
        struct page *new_page;
        struct kvmppc_44x_tlbe *stlbe;
        hpa_t hpaddr;
        victim = kvmppc_tlb_44x_pos++;
        if (kvmppc_tlb_44x_pos > tlb_44x_hwater)
                kvmppc_tlb_44x_pos = 0;
-       stlbe = &vcpu->arch.shadow_tlb[victim];
+       stlbe = &vcpu_44x->shadow_tlb[victim];
 
        /* Get reference to new page. */
        new_page = gfn_to_page(vcpu->kvm, gfn);
        /* Drop reference to old page. */
        kvmppc_44x_shadow_release(vcpu, victim);
 
-       vcpu->arch.shadow_pages[victim] = new_page;
+       vcpu_44x->shadow_pages[victim] = new_page;
 
        /* XXX Make sure (va, size) doesn't overlap any other
         * entries. 440x6 user manual says the result would be
 static void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, gva_t eaddr,
                                   gva_t eend, u32 asid)
 {
+       struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
        unsigned int pid = !(asid & 0xff);
        int i;
 
        /* XXX Replace loop with fancy data structures. */
        for (i = 0; i <= tlb_44x_hwater; i++) {
-               struct kvmppc_44x_tlbe *stlbe = &vcpu->arch.shadow_tlb[i];
+               struct kvmppc_44x_tlbe *stlbe = &vcpu_44x->shadow_tlb[i];
                unsigned int tid;
 
                if (!get_tlb_v(stlbe))
  * switching address spaces. */
 void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode)
 {
+       struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
        int i;
 
        if (vcpu->arch.swap_pid) {
                /* XXX Replace loop with fancy data structures. */
                for (i = 0; i <= tlb_44x_hwater; i++) {
-                       struct kvmppc_44x_tlbe *stlbe = &vcpu->arch.shadow_tlb[i];
+                       struct kvmppc_44x_tlbe *stlbe = &vcpu_44x->shadow_tlb[i];
 
                        /* Future optimization: clear only userspace mappings. */
                        kvmppc_44x_shadow_release(vcpu, i);
 
 int kvmppc_44x_emul_tlbwe(struct kvm_vcpu *vcpu, u8 ra, u8 rs, u8 ws)
 {
+       struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
        u64 eaddr;
        u64 raddr;
        u64 asid;
                return EMULATE_FAIL;
        }
 
-       tlbe = &vcpu->arch.guest_tlb[index];
+       tlbe = &vcpu_44x->guest_tlb[index];
 
        /* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */
        if (tlbe->word0 & PPC44x_TLB_VALID) {
 
        return kvmppc_core_vcpu_translate(vcpu, tr);
 }
 
-static int kvmppc_booke_init(void)
+int kvmppc_booke_init(void)
 {
        unsigned long ivor[16];
        unsigned long max_ivor = 0;
        flush_icache_range(kvmppc_booke_handlers,
                           kvmppc_booke_handlers + max_ivor + kvmppc_handler_len);
 
-       return kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE);
+       return 0;
 }
 
-static void __exit kvmppc_booke_exit(void)
+void __exit kvmppc_booke_exit(void)
 {
        free_pages(kvmppc_booke_handlers, VCPU_SIZE_ORDER);
        kvm_exit();
 }
-
-module_init(kvmppc_booke_init)
-module_exit(kvmppc_booke_exit)
 
        lis     r5, tlb_44x_hwater@ha
        lwz     r5, tlb_44x_hwater@l(r5)
        mtctr   r5
-       addi    r9, r4, VCPU_SHADOW_TLB
-       addi    r5, r4, VCPU_SHADOW_MOD
+       addi    r9, r4, -VCPU_TO_44X + VCPU44x_SHADOW_TLB
+       addi    r5, r4, -VCPU_TO_44X + VCPU44x_SHADOW_MOD
        li      r3, 0
 1:
        lbzx    r7, r3, r5
        /* Clear bitmap of modified TLB entries */
        li      r5, PPC44x_TLB_SIZE>>2
        mtctr   r5
-       addi    r5, r4, VCPU_SHADOW_MOD - 4
+       addi    r5, r4, -VCPU_TO_44X + VCPU44x_SHADOW_MOD - 4
        li      r6, 0
 1:
        stwu    r6, 4(r5)
 
 
 struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
 {
-       struct kvm_vcpu *vcpu;
-       int err;
-
-       vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
-       if (!vcpu) {
-               err = -ENOMEM;
-               goto out;
-       }
-
-       err = kvm_vcpu_init(vcpu, kvm, id);
-       if (err)
-               goto free_vcpu;
-
-       return vcpu;
-
-free_vcpu:
-       kmem_cache_free(kvm_vcpu_cache, vcpu);
-out:
-       return ERR_PTR(err);
+       return kvmppc_core_vcpu_create(kvm, id);
 }
 
 void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
 {
-       kvm_vcpu_uninit(vcpu);
-       kmem_cache_free(kvm_vcpu_cache, vcpu);
+       kvmppc_core_vcpu_free(vcpu);
 }
 
 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)