KVM: PPC: Use accessor functions for GPR access
[safe/jmp/linux-2.6] / arch / powerpc / kvm / 44x_tlb.c
index d49dc66..8b37736 100644 (file)
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/highmem.h>
+
+#include <asm/tlbflush.h>
 #include <asm/mmu-44x.h>
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_44x.h>
+#include "timing.h"
 
 #include "44x_tlb.h"
+#include "trace.h"
 
 #ifndef PPC44x_TLBE_SIZE
 #define PPC44x_TLBE_SIZE       PPC44x_TLB_4K
@@ -40,8 +44,6 @@
 #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)
 
-static unsigned int kvmppc_tlb_44x_pos;
-
 #ifdef DEBUG
 void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu)
 {
@@ -52,24 +54,68 @@ void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu)
        printk("| %2s | %3s | %8s | %8s | %8s |\n",
                        "nr", "tid", "word0", "word1", "word2");
 
-       for (i = 0; i < PPC44x_TLB_SIZE; i++) {
+       for (i = 0; i < ARRAY_SIZE(vcpu_44x->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,
                               tlbe->word2);
        }
-
-       for (i = 0; i < PPC44x_TLB_SIZE; 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,
-                              tlbe->word2);
-       }
 }
 #endif
 
+static inline void kvmppc_44x_tlbie(unsigned int index)
+{
+       /* 0 <= index < 64, so the V bit is clear and we can use the index as
+        * word0. */
+       asm volatile(
+               "tlbwe %[index], %[index], 0\n"
+       :
+       : [index] "r"(index)
+       );
+}
+
+static inline void kvmppc_44x_tlbre(unsigned int index,
+                                    struct kvmppc_44x_tlbe *tlbe)
+{
+       asm volatile(
+               "tlbre %[word0], %[index], 0\n"
+               "mfspr %[tid], %[sprn_mmucr]\n"
+               "andi. %[tid], %[tid], 0xff\n"
+               "tlbre %[word1], %[index], 1\n"
+               "tlbre %[word2], %[index], 2\n"
+               : [word0] "=r"(tlbe->word0),
+                 [word1] "=r"(tlbe->word1),
+                 [word2] "=r"(tlbe->word2),
+                 [tid]   "=r"(tlbe->tid)
+               : [index] "r"(index),
+                 [sprn_mmucr] "i"(SPRN_MMUCR)
+               : "cc"
+       );
+}
+
+static inline void kvmppc_44x_tlbwe(unsigned int index,
+                                    struct kvmppc_44x_tlbe *stlbe)
+{
+       unsigned long tmp;
+
+       asm volatile(
+               "mfspr %[tmp], %[sprn_mmucr]\n"
+               "rlwimi %[tmp], %[tid], 0, 0xff\n"
+               "mtspr %[sprn_mmucr], %[tmp]\n"
+               "tlbwe %[word0], %[index], 0\n"
+               "tlbwe %[word1], %[index], 1\n"
+               "tlbwe %[word2], %[index], 2\n"
+               : [tmp]   "=&r"(tmp)
+               : [word0] "r"(stlbe->word0),
+                 [word1] "r"(stlbe->word1),
+                 [word2] "r"(stlbe->word2),
+                 [tid]   "r"(stlbe->tid),
+                 [index] "r"(index),
+                 [sprn_mmucr] "i"(SPRN_MMUCR)
+       );
+}
+
 static u32 kvmppc_44x_tlb_shadow_attrib(u32 attrib, int usermode)
 {
        /* We only care about the guest's permission and user bits. */
@@ -91,6 +137,44 @@ static u32 kvmppc_44x_tlb_shadow_attrib(u32 attrib, int usermode)
        return attrib;
 }
 
+/* Load shadow TLB back into hardware. */
+void kvmppc_44x_tlb_load(struct kvm_vcpu *vcpu)
+{
+       struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
+       int i;
+
+       for (i = 0; i <= tlb_44x_hwater; i++) {
+               struct kvmppc_44x_tlbe *stlbe = &vcpu_44x->shadow_tlb[i];
+
+               if (get_tlb_v(stlbe) && get_tlb_ts(stlbe))
+                       kvmppc_44x_tlbwe(i, stlbe);
+       }
+}
+
+static void kvmppc_44x_tlbe_set_modified(struct kvmppc_vcpu_44x *vcpu_44x,
+                                         unsigned int i)
+{
+       vcpu_44x->shadow_tlb_mod[i] = 1;
+}
+
+/* Save hardware TLB to the vcpu, and invalidate all guest mappings. */
+void kvmppc_44x_tlb_put(struct kvm_vcpu *vcpu)
+{
+       struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
+       int i;
+
+       for (i = 0; i <= tlb_44x_hwater; i++) {
+               struct kvmppc_44x_tlbe *stlbe = &vcpu_44x->shadow_tlb[i];
+
+               if (vcpu_44x->shadow_tlb_mod[i])
+                       kvmppc_44x_tlbre(i, stlbe);
+
+               if (get_tlb_v(stlbe) && get_tlb_ts(stlbe))
+                       kvmppc_44x_tlbie(i);
+       }
+}
+
+
 /* 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)
@@ -99,7 +183,7 @@ int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr, unsigned int pid,
        int i;
 
        /* XXX Replace loop with fancy data structures. */
-       for (i = 0; i < PPC44x_TLB_SIZE; i++) {
+       for (i = 0; i < ARRAY_SIZE(vcpu_44x->guest_tlb); i++) {
                struct kvmppc_44x_tlbe *tlbe = &vcpu_44x->guest_tlb[i];
                unsigned int tid;
 
@@ -125,65 +209,71 @@ int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr, unsigned int pid,
        return -1;
 }
 
-struct kvmppc_44x_tlbe *kvmppc_44x_itlb_search(struct kvm_vcpu *vcpu,
-                                               gva_t eaddr)
+gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int gtlb_index,
+                       gva_t eaddr)
 {
        struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
+       struct kvmppc_44x_tlbe *gtlbe = &vcpu_44x->guest_tlb[gtlb_index];
+       unsigned int pgmask = get_tlb_bytes(gtlbe) - 1;
+
+       return get_tlb_raddr(gtlbe) | (eaddr & pgmask);
+}
+
+int kvmppc_mmu_itlb_index(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_44x->guest_tlb[index];
+       return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
 }
 
-struct kvmppc_44x_tlbe *kvmppc_44x_dtlb_search(struct kvm_vcpu *vcpu,
-                                               gva_t eaddr)
+int kvmppc_mmu_dtlb_index(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_44x->guest_tlb[index];
+       return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
 }
 
-static int kvmppc_44x_tlbe_is_writable(struct kvmppc_44x_tlbe *tlbe)
+void kvmppc_mmu_itlb_miss(struct kvm_vcpu *vcpu)
 {
-       return tlbe->word2 & (PPC44x_TLB_SW|PPC44x_TLB_UW);
 }
 
-static void kvmppc_44x_shadow_release(struct kvm_vcpu *vcpu,
-                                      unsigned int index)
+void kvmppc_mmu_dtlb_miss(struct kvm_vcpu *vcpu)
 {
-       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))
-                       kvm_release_page_dirty(page);
-               else
-                       kvm_release_page_clean(page);
-       }
 }
 
-void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu)
+static void kvmppc_44x_shadow_release(struct kvmppc_vcpu_44x *vcpu_44x,
+                                      unsigned int stlb_index)
 {
-       int i;
+       struct kvmppc_44x_shadow_ref *ref = &vcpu_44x->shadow_refs[stlb_index];
 
-       for (i = 0; i <= tlb_44x_hwater; i++)
-               kvmppc_44x_shadow_release(vcpu, i);
+       if (!ref->page)
+               return;
+
+       /* Discard from the TLB. */
+       /* Note: we could actually invalidate a host mapping, if the host overwrote
+        * this TLB entry since we inserted a guest mapping. */
+       kvmppc_44x_tlbie(stlb_index);
+
+       /* Now release the page. */
+       if (ref->writeable)
+               kvm_release_page_dirty(ref->page);
+       else
+               kvm_release_page_clean(ref->page);
+
+       ref->page = NULL;
+
+       /* XXX set tlb_44x_index to stlb_index? */
+
+       trace_kvm_stlb_inval(stlb_index);
 }
 
-void kvmppc_tlbe_set_modified(struct kvm_vcpu *vcpu, unsigned int i)
+void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
 {
        struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
+       int i;
 
-       vcpu_44x->shadow_tlb_mod[i] = 1;
+       for (i = 0; i <= tlb_44x_hwater; i++)
+               kvmppc_44x_shadow_release(vcpu_44x, i);
 }
 
 /**
@@ -198,22 +288,29 @@ void kvmppc_tlbe_set_modified(struct kvm_vcpu *vcpu, unsigned int i)
  * Caller must ensure that the specified guest TLB entry is safe to insert into
  * the shadow TLB.
  */
-void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr, u64 asid,
-                    u32 flags, u32 max_bytes)
+void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr,
+                    unsigned int gtlb_index)
 {
+       struct kvmppc_44x_tlbe stlbe;
        struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
+       struct kvmppc_44x_tlbe *gtlbe = &vcpu_44x->guest_tlb[gtlb_index];
+       struct kvmppc_44x_shadow_ref *ref;
        struct page *new_page;
-       struct kvmppc_44x_tlbe *stlbe;
        hpa_t hpaddr;
        gfn_t gfn;
+       u32 asid = gtlbe->tid;
+       u32 flags = gtlbe->word2;
+       u32 max_bytes = get_tlb_bytes(gtlbe);
        unsigned int victim;
 
-       /* Future optimization: don't overwrite the TLB entry containing the
-        * current PC (or stack?). */
-       victim = kvmppc_tlb_44x_pos++;
-       if (kvmppc_tlb_44x_pos > tlb_44x_hwater)
-               kvmppc_tlb_44x_pos = 0;
-       stlbe = &vcpu_44x->shadow_tlb[victim];
+       /* Select TLB entry to clobber. Indirectly guard against races with the TLB
+        * miss handler by disabling interrupts. */
+       local_irq_disable();
+       victim = ++tlb_44x_index;
+       if (victim > tlb_44x_hwater)
+               victim = 0;
+       tlb_44x_index = victim;
+       local_irq_enable();
 
        /* Get reference to new page. */
        gfn = gpaddr >> PAGE_SHIFT;
@@ -225,10 +322,8 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr, u64 asid,
        }
        hpaddr = page_to_phys(new_page);
 
-       /* Drop reference to old page. */
-       kvmppc_44x_shadow_release(vcpu, victim);
-
-       vcpu_44x->shadow_pages[victim] = new_page;
+       /* Invalidate any previous shadow mappings. */
+       kvmppc_44x_shadow_release(vcpu_44x, victim);
 
        /* XXX Make sure (va, size) doesn't overlap any other
         * entries. 440x6 user manual says the result would be
@@ -236,21 +331,19 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr, u64 asid,
 
        /* XXX what about AS? */
 
-       stlbe->tid = !(asid & 0xff);
-
        /* Force TS=1 for all guest mappings. */
-       stlbe->word0 = PPC44x_TLB_VALID | PPC44x_TLB_TS;
+       stlbe.word0 = PPC44x_TLB_VALID | PPC44x_TLB_TS;
 
        if (max_bytes >= PAGE_SIZE) {
                /* Guest mapping is larger than or equal to host page size. We can use
                 * a "native" host mapping. */
-               stlbe->word0 |= (gvaddr & PAGE_MASK) | PPC44x_TLBE_SIZE;
+               stlbe.word0 |= (gvaddr & PAGE_MASK) | PPC44x_TLBE_SIZE;
        } else {
                /* Guest mapping is smaller than host page size. We must restrict the
                 * size of the mapping to be at most the smaller of the two, but for
                 * simplicity we fall back to a 4K mapping (this is probably what the
                 * guest is using anyways). */
-               stlbe->word0 |= (gvaddr & PAGE_MASK_4K) | PPC44x_TLB_4K;
+               stlbe.word0 |= (gvaddr & PAGE_MASK_4K) | PPC44x_TLB_4K;
 
                /* 'hpaddr' is a host page, which is larger than the mapping we're
                 * inserting here. To compensate, we must add the in-page offset to the
@@ -258,47 +351,37 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr, u64 asid,
                hpaddr |= gpaddr & (PAGE_MASK ^ PAGE_MASK_4K);
        }
 
-       stlbe->word1 = (hpaddr & 0xfffffc00) | ((hpaddr >> 32) & 0xf);
-       stlbe->word2 = kvmppc_44x_tlb_shadow_attrib(flags,
+       stlbe.word1 = (hpaddr & 0xfffffc00) | ((hpaddr >> 32) & 0xf);
+       stlbe.word2 = kvmppc_44x_tlb_shadow_attrib(flags,
                                                    vcpu->arch.msr & MSR_PR);
-       kvmppc_tlbe_set_modified(vcpu, victim);
-
-       KVMTRACE_5D(STLB_WRITE, vcpu, victim,
-                       stlbe->tid, stlbe->word0, stlbe->word1, stlbe->word2,
-                       handler);
+       stlbe.tid = !(asid & 0xff);
+
+       /* Keep track of the reference so we can properly release it later. */
+       ref = &vcpu_44x->shadow_refs[victim];
+       ref->page = new_page;
+       ref->gtlb_index = gtlb_index;
+       ref->writeable = !!(stlbe.word2 & PPC44x_TLB_UW);
+       ref->tid = stlbe.tid;
+
+       /* Insert shadow mapping into hardware TLB. */
+       kvmppc_44x_tlbe_set_modified(vcpu_44x, victim);
+       kvmppc_44x_tlbwe(victim, &stlbe);
+       trace_kvm_stlb_write(victim, stlbe.tid, stlbe.word0, stlbe.word1,
+                            stlbe.word2);
 }
 
-static void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, gva_t eaddr,
-                                  gva_t eend, u32 asid)
+/* For a particular guest TLB entry, invalidate the corresponding host TLB
+ * mappings and release the host pages. */
+static void kvmppc_44x_invalidate(struct kvm_vcpu *vcpu,
+                                  unsigned int gtlb_index)
 {
        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_44x->shadow_tlb[i];
-               unsigned int tid;
-
-               if (!get_tlb_v(stlbe))
-                       continue;
-
-               if (eend < get_tlb_eaddr(stlbe))
-                       continue;
-
-               if (eaddr > get_tlb_end(stlbe))
-                       continue;
-
-               tid = get_tlb_tid(stlbe);
-               if (tid && (tid != pid))
-                       continue;
-
-               kvmppc_44x_shadow_release(vcpu, i);
-               stlbe->word0 = 0;
-               kvmppc_tlbe_set_modified(vcpu, i);
-               KVMTRACE_5D(STLB_INVAL, vcpu, i,
-                               stlbe->tid, stlbe->word0, stlbe->word1,
-                               stlbe->word2, handler);
+       for (i = 0; i < ARRAY_SIZE(vcpu_44x->shadow_refs); i++) {
+               struct kvmppc_44x_shadow_ref *ref = &vcpu_44x->shadow_refs[i];
+               if (ref->gtlb_index == gtlb_index)
+                       kvmppc_44x_shadow_release(vcpu_44x, i);
        }
 }
 
@@ -321,14 +404,11 @@ void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 new_pid)
         * can't access guest kernel mappings (TID=1). When we switch to a new
         * guest PID, which will also use host PID=0, we must discard the old guest
         * userspace mappings. */
-       for (i = 0; i < ARRAY_SIZE(vcpu_44x->shadow_tlb); i++) {
-               struct kvmppc_44x_tlbe *stlbe = &vcpu_44x->shadow_tlb[i];
+       for (i = 0; i < ARRAY_SIZE(vcpu_44x->shadow_refs); i++) {
+               struct kvmppc_44x_shadow_ref *ref = &vcpu_44x->shadow_refs[i];
 
-               if (get_tlb_tid(stlbe) == 0) {
-                       kvmppc_44x_shadow_release(vcpu, i);
-                       stlbe->word0 = 0;
-                       kvmppc_tlbe_set_modified(vcpu, i);
-               }
+               if (ref->tid == 0)
+                       kvmppc_44x_shadow_release(vcpu_44x, i);
        }
 }
 
@@ -356,39 +436,34 @@ static int tlbe_is_host_safe(const struct kvm_vcpu *vcpu,
 int kvmppc_44x_emul_tlbwe(struct kvm_vcpu *vcpu, u8 ra, u8 rs, u8 ws)
 {
        struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
-       gva_t eaddr;
-       u64 asid;
        struct kvmppc_44x_tlbe *tlbe;
-       unsigned int index;
+       unsigned int gtlb_index;
 
-       index = vcpu->arch.gpr[ra];
-       if (index > PPC44x_TLB_SIZE) {
-               printk("%s: index %d\n", __func__, index);
+       gtlb_index = kvmppc_get_gpr(vcpu, ra);
+       if (gtlb_index > KVM44x_GUEST_TLB_SIZE) {
+               printk("%s: index %d\n", __func__, gtlb_index);
                kvmppc_dump_vcpu(vcpu);
                return EMULATE_FAIL;
        }
 
-       tlbe = &vcpu_44x->guest_tlb[index];
+       tlbe = &vcpu_44x->guest_tlb[gtlb_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);
-       }
+       /* Invalidate shadow mappings for the about-to-be-clobbered TLB entry. */
+       if (tlbe->word0 & PPC44x_TLB_VALID)
+               kvmppc_44x_invalidate(vcpu, gtlb_index);
 
        switch (ws) {
        case PPC44x_TLB_PAGEID:
                tlbe->tid = get_mmucr_stid(vcpu);
-               tlbe->word0 = vcpu->arch.gpr[rs];
+               tlbe->word0 = kvmppc_get_gpr(vcpu, rs);
                break;
 
        case PPC44x_TLB_XLAT:
-               tlbe->word1 = vcpu->arch.gpr[rs];
+               tlbe->word1 = kvmppc_get_gpr(vcpu, rs);
                break;
 
        case PPC44x_TLB_ATTRIB:
-               tlbe->word2 = vcpu->arch.gpr[rs];
+               tlbe->word2 = kvmppc_get_gpr(vcpu, rs);
                break;
 
        default:
@@ -396,8 +471,8 @@ int kvmppc_44x_emul_tlbwe(struct kvm_vcpu *vcpu, u8 ra, u8 rs, u8 ws)
        }
 
        if (tlbe_is_host_safe(vcpu, tlbe)) {
+               gva_t eaddr;
                gpa_t gpaddr;
-               u32 flags;
                u32 bytes;
 
                eaddr = get_tlb_eaddr(tlbe);
@@ -408,38 +483,36 @@ int kvmppc_44x_emul_tlbwe(struct kvm_vcpu *vcpu, u8 ra, u8 rs, u8 ws)
                eaddr &= ~(bytes - 1);
                gpaddr &= ~(bytes - 1);
 
-               asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid;
-               flags = tlbe->word2 & 0xffff;
-
-               kvmppc_mmu_map(vcpu, eaddr, gpaddr, asid, flags, bytes);
+               kvmppc_mmu_map(vcpu, eaddr, gpaddr, gtlb_index);
        }
 
-       KVMTRACE_5D(GTLB_WRITE, vcpu, index,
-                   tlbe->tid, tlbe->word0, tlbe->word1, tlbe->word2,
-                   handler);
+       trace_kvm_gtlb_write(gtlb_index, tlbe->tid, tlbe->word0, tlbe->word1,
+                            tlbe->word2);
 
+       kvmppc_set_exit_type(vcpu, EMULATED_TLBWE_EXITS);
        return EMULATE_DONE;
 }
 
 int kvmppc_44x_emul_tlbsx(struct kvm_vcpu *vcpu, u8 rt, u8 ra, u8 rb, u8 rc)
 {
        u32 ea;
-       int index;
+       int gtlb_index;
        unsigned int as = get_mmucr_sts(vcpu);
        unsigned int pid = get_mmucr_stid(vcpu);
 
-       ea = vcpu->arch.gpr[rb];
+       ea = kvmppc_get_gpr(vcpu, rb);
        if (ra)
-               ea += vcpu->arch.gpr[ra];
+               ea += kvmppc_get_gpr(vcpu, ra);
 
-       index = kvmppc_44x_tlb_index(vcpu, ea, pid, as);
+       gtlb_index = kvmppc_44x_tlb_index(vcpu, ea, pid, as);
        if (rc) {
-               if (index < 0)
+               if (gtlb_index < 0)
                        vcpu->arch.cr &= ~0x20000000;
                else
                        vcpu->arch.cr |= 0x20000000;
        }
-       vcpu->arch.gpr[rt] = index;
+       kvmppc_set_gpr(vcpu, rt, gtlb_index);
 
+       kvmppc_set_exit_type(vcpu, EMULATED_TLBSX_EXITS);
        return EMULATE_DONE;
 }