mainly consist of tlb assciated code

Signed-off-by: Liu Yu <[EMAIL PROTECTED]>
---
 arch/powerpc/include/asm/kvm_ppc.h |    9 --
 arch/powerpc/kvm/44x_tlb.c         |  206 +++++++++++++++++++++++++++++++-----
 arch/powerpc/kvm/44x_tlb.h         |   50 ++++++++-
 arch/powerpc/kvm/booke_guest.c     |  122 ++++-----------------
 arch/powerpc/kvm/emulate.c         |  175 +------------------------------
 arch/powerpc/kvm/inst.h            |   60 +++++++++++
 arch/powerpc/kvm/powerpc.c         |   14 +--
 arch/powerpc/kvm/powerpc.h         |   10 ++
 8 files changed, 325 insertions(+), 321 deletions(-)
 create mode 100644 arch/powerpc/kvm/inst.h
 create mode 100644 arch/powerpc/kvm/powerpc.h

diff --git a/arch/powerpc/include/asm/kvm_ppc.h 
b/arch/powerpc/include/asm/kvm_ppc.h
index 8931ba7..fa3e880 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -29,11 +29,6 @@
 #include <linux/kvm_types.h>
 #include <linux/kvm_host.h>
 
-struct kvm_tlb {
-       struct tlbe guest_tlb[PPC44x_TLB_SIZE];
-       struct tlbe shadow_tlb[PPC44x_TLB_SIZE];
-};
-
 enum emulation_result {
        EMULATE_DONE,         /* no further processing */
        EMULATE_DO_MMIO,      /* kvm_run filled with MMIO request */
@@ -59,10 +54,6 @@ extern int kvmppc_emulate_instruction(struct kvm_run *run,
                                       struct kvm_vcpu *vcpu);
 extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu);
 
-extern void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn,
-                           u64 asid, u32 flags);
-extern void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, gva_t eaddr,
-                                  gva_t eend, u32 asid);
 extern void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int usermode);
 extern void kvmppc_mmu_switch_pid(struct kvm_vcpu *vcpu, u32 pid);
 
diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c
index 3594bbd..4a3f179 100644
--- a/arch/powerpc/kvm/44x_tlb.c
+++ b/arch/powerpc/kvm/44x_tlb.c
@@ -26,6 +26,7 @@
 #include <asm/kvm_ppc.h>
 
 #include "44x_tlb.h"
+#include "inst.h"
 
 #define PPC44x_TLB_USER_PERM_MASK (PPC44x_TLB_UX|PPC44x_TLB_UR|PPC44x_TLB_UW)
 #define PPC44x_TLB_SUPER_PERM_MASK (PPC44x_TLB_SX|PPC44x_TLB_SR|PPC44x_TLB_SW)
@@ -50,9 +51,35 @@ static u32 kvmppc_44x_tlb_shadow_attrib(u32 attrib, int 
usermode)
        return attrib;
 }
 
+void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu)
+{
+       struct tlbe *tlbe;
+       int i;
+
+       printk("vcpu %d TLB dump:\n", vcpu->vcpu_id);
+       printk("| %2s | %3s | %8s | %8s | %8s |\n",
+                       "nr", "tid", "word0", "word1", "word2");
+
+       for (i = 0; i < PPC44x_TLB_SIZE; i++) {
+               tlbe = &vcpu->arch.guest_tlb[i];
+               if (tlbe->word0 & PPC44x_TLB_VALID)
+                       printk(" G%2d |  %02X | %08X | %08X | %08X |\n",
+                              i, tlbe->tid, tlbe->word0, tlbe->word1,
+                              tlbe->word2);
+       }
+
+       for (i = 0; i < PPC44x_TLB_SIZE; i++) {
+               tlbe = &vcpu->arch.shadow_tlb[i];
+               if (tlbe->word0 & PPC44x_TLB_VALID)
+                       printk(" S%2d | %02X | %08X | %08X | %08X |\n",
+                              i, tlbe->tid, tlbe->word0, tlbe->word1,
+                              tlbe->word2);
+       }
+}
+
 /* Search the guest TLB for a matching entry. */
-int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr, unsigned int pid,
-                         unsigned int as)
+struct tlbe *kvmppc_tlb_search(struct kvm_vcpu *vcpu, gva_t eaddr,
+                       unsigned int pid, unsigned int as)
 {
        int i;
 
@@ -77,32 +104,10 @@ int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t 
eaddr, unsigned int pid,
                if (get_tlb_ts(tlbe) != as)
                        continue;
 
-               return i;
+               return tlbe;
        }
 
-       return -1;
-}
-
-struct tlbe *kvmppc_44x_itlb_search(struct kvm_vcpu *vcpu, gva_t eaddr)
-{
-       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];
-}
-
-struct tlbe *kvmppc_44x_dtlb_search(struct kvm_vcpu *vcpu, gva_t eaddr)
-{
-       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 NULL;
 }
 
 static int kvmppc_44x_tlbe_is_writable(struct tlbe *tlbe)
@@ -249,3 +254,152 @@ void kvmppc_mmu_priv_switch(struct kvm_vcpu *vcpu, int 
usermode)
 
        vcpu->arch.shadow_pid = !usermode;
 }
+
+int kvmppc_handle_tlb_miss(struct kvm_vcpu *vcpu , gva_t eaddr, int eas)
+{
+       struct tlbe *gtlbe = NULL;
+       gfn_t gfn;
+       int as = !!(vcpu->arch.msr & eas);
+
+       /* Check the guest TLB. */
+       gtlbe = kvmppc_tlb_search(vcpu, eaddr, vcpu->arch.pid, as);
+       if (gtlbe == NULL)
+               return -1;
+
+       if (eas == MSR_DS)
+               vcpu->arch.paddr_accessed = tlb_xlate(gtlbe, eaddr);
+
+       gfn = vcpu->arch.paddr_accessed >> PAGE_SHIFT;
+
+       if (kvm_is_visible_gfn(vcpu->kvm, gfn)) {
+               /* The guest TLB had a mapping, but the shadow TLB
+                * didn't, and it is RAM. This could be because:
+                * a) the entry is mapping the host kernel, or
+                * b) the guest used a large mapping which we're faking
+                * Either way, we need to satisfy the fault without
+                * invoking the guest. */
+               kvmppc_mmu_map(vcpu, eaddr, gfn, gtlbe->tid,
+                               gtlbe->word2);
+       } else {
+               /* Guest has mapped and accessed a page which is not
+                * actually RAM. */
+               return -1;
+       }
+
+       return 0;
+}
+
+int kvmppc_emul_tlbsx(struct kvm_vcpu *vcpu, u32 inst)
+{
+       int index;
+       unsigned int as = get_mmucr_sts(vcpu);
+       unsigned int pid = get_mmucr_stid(vcpu);
+       void *gtlb;
+
+       rt = get_rt(inst);
+       ra = get_ra(inst);
+       rb = get_rb(inst);
+       rc = get_rc(inst);
+
+       ea = vcpu->arch.gpr[rb];
+       if (ra)
+               ea += vcpu->arch.gpr[ra];
+
+       gtlb = kvmppc_tlb_search(vcpu, ea, pid, as);
+       if (rc) {
+               if (gtlb == NULL)
+                       vcpu->arch.cr &= ~0x20000000;
+               else
+                       vcpu->arch.cr |= 0x20000000;
+       }
+       vcpu->arch.gpr[rt] = index;
+
+       return EMULATE_DONE;
+}
+
+int kvmppc_emul_tlbwe(struct kvm_vcpu *vcpu, u32 inst)
+{
+       u64 eaddr;
+       u64 raddr;
+       u64 asid;
+       u32 flags;
+       struct tlbe *tlbe;
+       unsigned int ra;
+       unsigned int rs;
+       unsigned int ws;
+       unsigned int index;
+
+       ra = get_ra(inst);
+       rs = get_rs(inst);
+       ws = get_ws(inst);
+
+       index = vcpu->arch.gpr[ra];
+       if (index > PPC44x_TLB_SIZE) {
+               printk("%s: index %d\n", __func__, index);
+               kvmppc_dump_vcpu(vcpu);
+               return EMULATE_FAIL;
+       }
+
+       tlbe = &vcpu->arch.guest_tlb[index];
+
+       /* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */
+       if (tlbe->word0 & PPC44x_TLB_VALID) {
+               eaddr = get_tlb_eaddr(tlbe);
+               asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid;
+               kvmppc_mmu_invalidate(vcpu, eaddr, get_tlb_end(tlbe), asid);
+       }
+
+       switch (ws) {
+       case PPC44x_TLB_PAGEID:
+               tlbe->tid = vcpu->arch.mmucr & 0xff;
+               tlbe->word0 = vcpu->arch.gpr[rs];
+               break;
+
+       case PPC44x_TLB_XLAT:
+               tlbe->word1 = vcpu->arch.gpr[rs];
+               break;
+
+       case PPC44x_TLB_ATTRIB:
+               tlbe->word2 = vcpu->arch.gpr[rs];
+               break;
+
+       default:
+               return EMULATE_FAIL;
+       }
+
+       if (tlbe_is_host_safe(vcpu, tlbe)) {
+               eaddr = get_tlb_eaddr(tlbe);
+               raddr = get_tlb_raddr(tlbe);
+               asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid;
+               flags = tlbe->word2 & 0xffff;
+
+               /* Create a 4KB mapping on the host. If the guest wanted a
+                * large page, only the first 4KB is mapped here and the rest
+                * are mapped on the fly. */
+               kvmppc_mmu_map(vcpu, eaddr, raddr >> PAGE_SHIFT, asid, flags);
+       }
+
+       KVMTRACE_5D(GTLB_WRITE, vcpu, index,
+                       tlbe->tid, tlbe->word0, tlbe->word1, tlbe->word2,
+                       handler);
+
+       return EMULATE_DONE;
+}
+
+void kvmppc_tlb_setup(struct kvm_vcpu *vcpu)
+{
+       struct tlbe *tlbe = &vcpu->arch.guest_tlb[0];
+
+       /* Insert large initial mapping for guest. */
+       tlbe->tid = 0;
+       tlbe->word0 = PPC44x_TLB_16M | PPC44x_TLB_VALID;
+       tlbe->word1 = 0;
+       tlbe->word2 = PPC44x_TLB_SX | PPC44x_TLB_SW | PPC44x_TLB_SR;
+
+       tlbe++;
+       tlbe->tid = 0;
+       tlbe->word0 = 0xef600000 | PPC44x_TLB_4K | PPC44x_TLB_VALID;
+       tlbe->word1 = 0xef600000;
+       tlbe->word2 = PPC44x_TLB_SX | PPC44x_TLB_SW | PPC44x_TLB_SR
+                       | PPC44x_TLB_I | PPC44x_TLB_G;
+}
diff --git a/arch/powerpc/kvm/44x_tlb.h b/arch/powerpc/kvm/44x_tlb.h
index 2ccd46b..7eeffe7 100644
--- a/arch/powerpc/kvm/44x_tlb.h
+++ b/arch/powerpc/kvm/44x_tlb.h
@@ -23,10 +23,13 @@
 #include <linux/kvm_host.h>
 #include <asm/mmu-44x.h>
 
-extern int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr,
+extern void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu);
+extern struct tlbe *kvmppc_tlb_search(struct kvm_vcpu *vcpu, gva_t eaddr,
                                 unsigned int pid, unsigned int as);
-extern struct tlbe *kvmppc_44x_dtlb_search(struct kvm_vcpu *vcpu, gva_t eaddr);
-extern struct tlbe *kvmppc_44x_itlb_search(struct kvm_vcpu *vcpu, gva_t eaddr);
+extern int kvmppc_handle_tlb_miss(struct kvm_vcpu *vcpu, gva_t eaddr, int eas);
+extern int kvmppc_emul_tlbsx(struct kvm_vcpu *vcpu, u32 inst);
+extern int kvmppc_emul_tlbwe(struct kvm_vcpu *vcpu, u32 inst);
+extern void kvmppc_tlb_setup(struct kvm_vcpu *vcpu);
 
 /* TLB helper functions */
 static inline unsigned int get_tlb_size(const struct tlbe *tlbe)
@@ -88,4 +91,45 @@ static inline gpa_t tlb_xlate(struct tlbe *tlbe, gva_t eaddr)
        return get_tlb_raddr(tlbe) | (eaddr & pgmask);
 }
 
+static inline int tlbe_is_host_safe(const struct kvm_vcpu *vcpu,
+                       const struct tlbe *tlbe)
+{
+       gpa_t gpa;
+
+       if (!get_tlb_v(tlbe))
+               return 0;
+
+       /* Does it match current guest AS? */
+       /* XXX what about IS != DS? */
+       if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS))
+               return 0;
+
+       gpa = get_tlb_raddr(tlbe);
+       if (!gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT))
+               /* Mapping is not for RAM. */
+               return 0;
+
+       return 1;
+}
+
+static inline void kvmppc_tlb_load(struct kvm_vcpu *vcpu)
+{
+       int i;
+
+       /* Mark every guest entry in the shadow TLB entry modified, so that they
+        * will all be reloaded on the next vcpu run (instead of being
+        * demand-faulted). */
+       for (i = 0; i <= tlb_44x_hwater; i++)
+               kvmppc_tlbe_set_modified(vcpu, i);
+}
+
+static inline void kvmppc_tlb_put(struct kvm_vcpu *vcpu)
+{
+       /* Don't leave guest TLB entries resident when being de-scheduled. */
+       /* XXX It would be nice to differentiate between heavyweight exit and
+        * sched_out here, since we could avoid the TLB flush for heavyweight
+        * exits. */
+       _tlbia();
+}
+
 #endif /* __KVM_POWERPC_TLB_H__ */
diff --git a/arch/powerpc/kvm/booke_guest.c b/arch/powerpc/kvm/booke_guest.c
index 7b2591e..4fca3be 100644
--- a/arch/powerpc/kvm/booke_guest.c
+++ b/arch/powerpc/kvm/booke_guest.c
@@ -28,7 +28,7 @@
 #include <asm/uaccess.h>
 #include <asm/kvm_ppc.h>
 
-#include "44x_tlb.h"
+#include "powerpc.h"
 
 #define VM_STAT(x) offsetof(struct kvm, stat.x), KVM_STAT_VM
 #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
@@ -110,33 +110,6 @@ const unsigned char priority_exception[] = {
        BOOKE_INTERRUPT_DECREMENTER,
 };
 
-
-void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu)
-{
-       struct tlbe *tlbe;
-       int i;
-
-       printk("vcpu %d TLB dump:\n", vcpu->vcpu_id);
-       printk("| %2s | %3s | %8s | %8s | %8s |\n",
-                       "nr", "tid", "word0", "word1", "word2");
-
-       for (i = 0; i < PPC44x_TLB_SIZE; i++) {
-               tlbe = &vcpu->arch.guest_tlb[i];
-               if (tlbe->word0 & PPC44x_TLB_VALID)
-                       printk(" G%2d |  %02X | %08X | %08X | %08X |\n",
-                              i, tlbe->tid, tlbe->word0, tlbe->word1,
-                              tlbe->word2);
-       }
-
-       for (i = 0; i < PPC44x_TLB_SIZE; i++) {
-               tlbe = &vcpu->arch.shadow_tlb[i];
-               if (tlbe->word0 & PPC44x_TLB_VALID)
-                       printk(" S%2d | %02X | %08X | %08X | %08X |\n",
-                              i, tlbe->tid, tlbe->word0, tlbe->word1,
-                              tlbe->word2);
-       }
-}
-
 /* TODO: use vcpu_printf() */
 void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu)
 {
@@ -333,78 +306,42 @@ int kvmppc_handle_exit(struct kvm_run *run, struct 
kvm_vcpu *vcpu,
                break;
 
        case BOOKE_INTERRUPT_DTLB_MISS: {
-               struct tlbe *gtlbe;
                unsigned long eaddr = vcpu->arch.fault_dear;
-               gfn_t gfn;
+               int ret;
 
-               /* Check the guest TLB. */
-               gtlbe = kvmppc_44x_dtlb_search(vcpu, eaddr);
-               if (!gtlbe) {
-                       /* The guest didn't have a mapping for it. */
+               r = RESUME_GUEST;
+
+               ret = kvmppc_handle_tlb_miss(vcpu, eaddr, MSR_DS);
+               if (ret == 0) {
+                       vcpu->stat.dtlb_virt_miss_exits++;
+               } else if (ret > 0) {
+                       r = kvmppc_emulate_mmio(run, vcpu);
+               } else {
                        kvmppc_queue_exception(vcpu, exit_nr);
                        vcpu->arch.dear = vcpu->arch.fault_dear;
                        vcpu->arch.esr = vcpu->arch.fault_esr;
                        vcpu->stat.dtlb_real_miss_exits++;
-                       r = RESUME_GUEST;
-                       break;
-               }
-
-               vcpu->arch.paddr_accessed = tlb_xlate(gtlbe, eaddr);
-               gfn = vcpu->arch.paddr_accessed >> PAGE_SHIFT;
-
-               if (kvm_is_visible_gfn(vcpu->kvm, gfn)) {
-                       /* The guest TLB had a mapping, but the shadow TLB
-                        * didn't, and it is RAM. This could be because:
-                        * a) the entry is mapping the host kernel, or
-                        * b) the guest used a large mapping which we're faking
-                        * Either way, we need to satisfy the fault without
-                        * invoking the guest. */
-                       kvmppc_mmu_map(vcpu, eaddr, gfn, gtlbe->tid,
-                                      gtlbe->word2);
-                       vcpu->stat.dtlb_virt_miss_exits++;
-                       r = RESUME_GUEST;
-               } else {
-                       /* Guest has mapped and accessed a page which is not
-                        * actually RAM. */
-                       r = kvmppc_emulate_mmio(run, vcpu);
                }
 
                break;
        }
 
        case BOOKE_INTERRUPT_ITLB_MISS: {
-               struct tlbe *gtlbe;
                unsigned long eaddr = vcpu->arch.pc;
-               gfn_t gfn;
+               int ret;
 
                r = RESUME_GUEST;
 
-               /* Check the guest TLB. */
-               gtlbe = kvmppc_44x_itlb_search(vcpu, eaddr);
-               if (!gtlbe) {
-                       /* The guest didn't have a mapping for it. */
-                       kvmppc_queue_exception(vcpu, exit_nr);
-                       vcpu->stat.itlb_real_miss_exits++;
-                       break;
-               }
-
-               vcpu->stat.itlb_virt_miss_exits++;
-
-               gfn = tlb_xlate(gtlbe, eaddr) >> PAGE_SHIFT;
-
-               if (kvm_is_visible_gfn(vcpu->kvm, gfn)) {
-                       /* The guest TLB had a mapping, but the shadow TLB
-                        * didn't. This could be because:
-                        * a) the entry is mapping the host kernel, or
-                        * b) the guest used a large mapping which we're faking
-                        * Either way, we need to satisfy the fault without
-                        * invoking the guest. */
-                       kvmppc_mmu_map(vcpu, eaddr, gfn, gtlbe->tid,
-                                      gtlbe->word2);
-               } else {
+               ret = kvmppc_handle_tlb_miss(vcpu, eaddr, MSR_IS);
+               if (ret == 0) {
+                       vcpu->stat.itlb_virt_miss_exits++;
+               } else if (ret > 0) {
                        /* Guest mapped and leaped at non-RAM! */
                        kvmppc_queue_exception(vcpu,
-                                              BOOKE_INTERRUPT_MACHINE_CHECK);
+                                       BOOKE_INTERRUPT_MACHINE_CHECK);
+               } else {
+                       kvmppc_queue_exception(vcpu, exit_nr);
+                       vcpu->stat.itlb_real_miss_exits++;
                }
 
                break;
@@ -468,19 +405,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct 
kvm_vcpu *vcpu,
 /* Initial guest state: 16MB mapping 0 -> 0, PC = 0, MSR = 0, R1 = 16MB */
 int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 {
-       struct tlbe *tlbe = &vcpu->arch.guest_tlb[0];
-
-       tlbe->tid = 0;
-       tlbe->word0 = PPC44x_TLB_16M | PPC44x_TLB_VALID;
-       tlbe->word1 = 0;
-       tlbe->word2 = PPC44x_TLB_SX | PPC44x_TLB_SW | PPC44x_TLB_SR;
-
-       tlbe++;
-       tlbe->tid = 0;
-       tlbe->word0 = 0xef600000 | PPC44x_TLB_4K | PPC44x_TLB_VALID;
-       tlbe->word1 = 0xef600000;
-       tlbe->word2 = PPC44x_TLB_SX | PPC44x_TLB_SW | PPC44x_TLB_SR
-                     | PPC44x_TLB_I | PPC44x_TLB_G;
+       kvmppc_tlb_setup(vcpu);
 
        vcpu->arch.pc = 0;
        vcpu->arch.msr = 0;
@@ -580,7 +505,6 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
                                   struct kvm_translation *tr)
 {
        struct tlbe *gtlbe;
-       int index;
        gva_t eaddr;
        u8 pid;
        u8 as;
@@ -589,14 +513,12 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
        pid = (tr->linear_address >> 32) & 0xff;
        as = (tr->linear_address >> 40) & 0x1;
 
-       index = kvmppc_44x_tlb_index(vcpu, eaddr, pid, as);
-       if (index == -1) {
+       gtlbe = kvmppc_tlb_search(vcpu, eaddr, pid, as);
+       if (gtlbe == NULL) {
                tr->valid = 0;
                return 0;
        }
 
-       gtlbe = &vcpu->arch.guest_tlb[index];
-
        tr->physical_address = tlb_xlate(gtlbe, eaddr);
        /* XXX what does "writeable" and "usermode" even mean? */
        tr->valid = 1;
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index 0fce4fb..5d31fca 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -29,153 +29,8 @@
 #include <asm/byteorder.h>
 #include <asm/kvm_ppc.h>
 
-#include "44x_tlb.h"
-
-/* Instruction decoding */
-static inline unsigned int get_op(u32 inst)
-{
-       return inst >> 26;
-}
-
-static inline unsigned int get_xop(u32 inst)
-{
-       return (inst >> 1) & 0x3ff;
-}
-
-static inline unsigned int get_sprn(u32 inst)
-{
-       return ((inst >> 16) & 0x1f) | ((inst >> 6) & 0x3e0);
-}
-
-static inline unsigned int get_dcrn(u32 inst)
-{
-       return ((inst >> 16) & 0x1f) | ((inst >> 6) & 0x3e0);
-}
-
-static inline unsigned int get_rt(u32 inst)
-{
-       return (inst >> 21) & 0x1f;
-}
-
-static inline unsigned int get_rs(u32 inst)
-{
-       return (inst >> 21) & 0x1f;
-}
-
-static inline unsigned int get_ra(u32 inst)
-{
-       return (inst >> 16) & 0x1f;
-}
-
-static inline unsigned int get_rb(u32 inst)
-{
-       return (inst >> 11) & 0x1f;
-}
-
-static inline unsigned int get_rc(u32 inst)
-{
-       return inst & 0x1;
-}
-
-static inline unsigned int get_ws(u32 inst)
-{
-       return (inst >> 11) & 0x1f;
-}
-
-static inline unsigned int get_d(u32 inst)
-{
-       return inst & 0xffff;
-}
-
-static int tlbe_is_host_safe(const struct kvm_vcpu *vcpu,
-                             const struct tlbe *tlbe)
-{
-       gpa_t gpa;
-
-       if (!get_tlb_v(tlbe))
-               return 0;
-
-       /* Does it match current guest AS? */
-       /* XXX what about IS != DS? */
-       if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS))
-               return 0;
-
-       gpa = get_tlb_raddr(tlbe);
-       if (!gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT))
-               /* Mapping is not for RAM. */
-               return 0;
-
-       return 1;
-}
-
-static int kvmppc_emul_tlbwe(struct kvm_vcpu *vcpu, u32 inst)
-{
-       u64 eaddr;
-       u64 raddr;
-       u64 asid;
-       u32 flags;
-       struct tlbe *tlbe;
-       unsigned int ra;
-       unsigned int rs;
-       unsigned int ws;
-       unsigned int index;
-
-       ra = get_ra(inst);
-       rs = get_rs(inst);
-       ws = get_ws(inst);
-
-       index = vcpu->arch.gpr[ra];
-       if (index > PPC44x_TLB_SIZE) {
-               printk("%s: index %d\n", __func__, index);
-               kvmppc_dump_vcpu(vcpu);
-               return EMULATE_FAIL;
-       }
-
-       tlbe = &vcpu->arch.guest_tlb[index];
-
-       /* Invalidate shadow mappings for the about-to-be-clobbered TLBE. */
-       if (tlbe->word0 & PPC44x_TLB_VALID) {
-               eaddr = get_tlb_eaddr(tlbe);
-               asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid;
-               kvmppc_mmu_invalidate(vcpu, eaddr, get_tlb_end(tlbe), asid);
-       }
-
-       switch (ws) {
-       case PPC44x_TLB_PAGEID:
-               tlbe->tid = vcpu->arch.mmucr & 0xff;
-               tlbe->word0 = vcpu->arch.gpr[rs];
-               break;
-
-       case PPC44x_TLB_XLAT:
-               tlbe->word1 = vcpu->arch.gpr[rs];
-               break;
-
-       case PPC44x_TLB_ATTRIB:
-               tlbe->word2 = vcpu->arch.gpr[rs];
-               break;
-
-       default:
-               return EMULATE_FAIL;
-       }
-
-       if (tlbe_is_host_safe(vcpu, tlbe)) {
-               eaddr = get_tlb_eaddr(tlbe);
-               raddr = get_tlb_raddr(tlbe);
-               asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid;
-               flags = tlbe->word2 & 0xffff;
-
-               /* Create a 4KB mapping on the host. If the guest wanted a
-                * large page, only the first 4KB is mapped here and the rest
-                * are mapped on the fly. */
-               kvmppc_mmu_map(vcpu, eaddr, raddr >> PAGE_SHIFT, asid, flags);
-       }
-
-       KVMTRACE_5D(GTLB_WRITE, vcpu, index,
-                       tlbe->tid, tlbe->word0, tlbe->word1, tlbe->word2,
-                       handler);
-
-       return EMULATE_DONE;
-}
+#include "powerpc.h"
+#include "inst.h"
 
 static void kvmppc_emulate_dec(struct kvm_vcpu *vcpu)
 {
@@ -633,30 +488,8 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct 
kvm_vcpu *vcpu)
                        emulated = kvmppc_emul_tlbwe(vcpu, inst);
                        break;
 
-               case 914:       {                               /* tlbsx */
-                       int index;
-                       unsigned int as = get_mmucr_sts(vcpu);
-                       unsigned int pid = get_mmucr_stid(vcpu);
-
-                       rt = get_rt(inst);
-                       ra = get_ra(inst);
-                       rb = get_rb(inst);
-                       rc = get_rc(inst);
-
-                       ea = vcpu->arch.gpr[rb];
-                       if (ra)
-                               ea += vcpu->arch.gpr[ra];
-
-                       index = kvmppc_44x_tlb_index(vcpu, ea, pid, as);
-                       if (rc) {
-                               if (index < 0)
-                                       vcpu->arch.cr &= ~0x20000000;
-                               else
-                                       vcpu->arch.cr |= 0x20000000;
-                       }
-                       vcpu->arch.gpr[rt] = index;
-
-                       }
+               case 914:                                       /* tlbsx */
+                       emulated = kvmppc_emul_tlbsx(vcpu, inst);
                        break;
 
                case 790:                                       /* lhbrx */
diff --git a/arch/powerpc/kvm/inst.h b/arch/powerpc/kvm/inst.h
new file mode 100644
index 0000000..f1b04da
--- /dev/null
+++ b/arch/powerpc/kvm/inst.h
@@ -0,0 +1,60 @@
+#ifndef __KVM_POWERPC_INST_H__
+#define __KVM_POWERPC_INST_H__
+
+/* Instruction decoding */
+static inline unsigned int get_op(u32 inst)
+{
+       return inst >> 26;
+}
+
+static inline unsigned int get_xop(u32 inst)
+{
+       return (inst >> 1) & 0x3ff;
+}
+
+static inline unsigned int get_sprn(u32 inst)
+{
+       return ((inst >> 16) & 0x1f) | ((inst >> 6) & 0x3e0);
+}
+
+static inline unsigned int get_dcrn(u32 inst)
+{
+       return ((inst >> 16) & 0x1f) | ((inst >> 6) & 0x3e0);
+}
+
+static inline unsigned int get_rt(u32 inst)
+{
+       return (inst >> 21) & 0x1f;
+}
+
+static inline unsigned int get_rs(u32 inst)
+{
+       return (inst >> 21) & 0x1f;
+}
+
+static inline unsigned int get_ra(u32 inst)
+{
+       return (inst >> 16) & 0x1f;
+}
+
+static inline unsigned int get_rb(u32 inst)
+{
+       return (inst >> 11) & 0x1f;
+}
+
+static inline unsigned int get_rc(u32 inst)
+{
+       return inst & 0x1;
+}
+
+static inline unsigned int get_ws(u32 inst)
+{
+       return (inst >> 11) & 0x1f;
+}
+
+static inline unsigned int get_d(u32 inst)
+{
+       return inst & 0xffff;
+}
+
+#endif /* __KVM_POWERPC_INST_H__ */
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 90a6fc4..d3bc29f 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -308,16 +308,10 @@ static void kvmppc_load_guest_debug_registers(struct 
kvm_vcpu *vcpu)
 
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
-       int i;
-
        if (vcpu->guest_debug.enabled)
                kvmppc_load_guest_debug_registers(vcpu);
 
-       /* Mark every guest entry in the shadow TLB entry modified, so that they
-        * will all be reloaded on the next vcpu run (instead of being
-        * demand-faulted). */
-       for (i = 0; i <= tlb_44x_hwater; i++)
-               kvmppc_tlbe_set_modified(vcpu, i);
+       kvmppc_tlb_load(vcpu);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
@@ -325,11 +319,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
        if (vcpu->guest_debug.enabled)
                kvmppc_restore_host_debug_state(vcpu);
 
-       /* Don't leave guest TLB entries resident when being de-scheduled. */
-       /* XXX It would be nice to differentiate between heavyweight exit and
-        * sched_out here, since we could avoid the TLB flush for heavyweight
-        * exits. */
-       _tlbia();
+       kvmppc_tlb_put(vcpu);
 }
 
 int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
diff --git a/arch/powerpc/kvm/powerpc.h b/arch/powerpc/kvm/powerpc.h
new file mode 100644
index 0000000..dd93461
--- /dev/null
+++ b/arch/powerpc/kvm/powerpc.h
@@ -0,0 +1,10 @@
+#ifndef __KVM_POWERPC_POWERPC_H__
+#define __KVM_POWERPC_POWERPC_H__
+
+#include <linux/kvm_host.h>
+
+#ifdef CONFIG_44x
+#include "44x_tlb.h"
+#endif
+
+#endif /* __KVM_POWERPC_POWERPC_H__ */
-- 
1.5.4

--
To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to