KVM: PPC: Use accessor functions for GPR access
[safe/jmp/linux-2.6] / arch / powerpc / kvm / 44x_tlb.c
index 2981ebe..8b37736 100644 (file)
 #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
@@ -73,6 +75,25 @@ static inline void kvmppc_44x_tlbie(unsigned int 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)
 {
@@ -116,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)
@@ -150,20 +209,38 @@ int kvmppc_44x_tlb_index(struct kvm_vcpu *vcpu, gva_t eaddr, unsigned int pid,
        return -1;
 }
 
-int kvmppc_44x_itlb_index(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);
 
        return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
 }
 
-int kvmppc_44x_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr)
+int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr)
 {
        unsigned int as = !!(vcpu->arch.msr & MSR_DS);
 
        return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
 }
 
+void kvmppc_mmu_itlb_miss(struct kvm_vcpu *vcpu)
+{
+}
+
+void kvmppc_mmu_dtlb_miss(struct kvm_vcpu *vcpu)
+{
+}
+
 static void kvmppc_44x_shadow_release(struct kvmppc_vcpu_44x *vcpu_44x,
                                       unsigned int stlb_index)
 {
@@ -187,10 +264,10 @@ static void kvmppc_44x_shadow_release(struct kvmppc_vcpu_44x *vcpu_44x,
 
        /* XXX set tlb_44x_index to stlb_index? */
 
-       KVMTRACE_1D(STLB_INVAL, &vcpu_44x->vcpu, stlb_index, handler);
+       trace_kvm_stlb_inval(stlb_index);
 }
 
-void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu)
+void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
 {
        struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
        int i;
@@ -211,15 +288,19 @@ void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu)
  * 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, unsigned int gtlb_index)
+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;
        hpa_t hpaddr;
        gfn_t gfn;
+       u32 asid = gtlbe->tid;
+       u32 flags = gtlbe->word2;
+       u32 max_bytes = get_tlb_bytes(gtlbe);
        unsigned int victim;
 
        /* Select TLB entry to clobber. Indirectly guard against races with the TLB
@@ -283,9 +364,10 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr, u64 asid,
        ref->tid = stlbe.tid;
 
        /* Insert shadow mapping into hardware TLB. */
+       kvmppc_44x_tlbe_set_modified(vcpu_44x, victim);
        kvmppc_44x_tlbwe(victim, &stlbe);
-       KVMTRACE_5D(STLB_WRITE, vcpu, victim, stlbe.tid, stlbe.word0, stlbe.word1,
-                   stlbe.word2, handler);
+       trace_kvm_stlb_write(victim, stlbe.tid, stlbe.word0, stlbe.word1,
+                            stlbe.word2);
 }
 
 /* For a particular guest TLB entry, invalidate the corresponding host TLB
@@ -357,7 +439,7 @@ int kvmppc_44x_emul_tlbwe(struct kvm_vcpu *vcpu, u8 ra, u8 rs, u8 ws)
        struct kvmppc_44x_tlbe *tlbe;
        unsigned int gtlb_index;
 
-       gtlb_index = vcpu->arch.gpr[ra];
+       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);
@@ -373,15 +455,15 @@ int kvmppc_44x_emul_tlbwe(struct kvm_vcpu *vcpu, u8 ra, u8 rs, u8 ws)
        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:
@@ -389,10 +471,8 @@ int kvmppc_44x_emul_tlbwe(struct kvm_vcpu *vcpu, u8 ra, u8 rs, u8 ws)
        }
 
        if (tlbe_is_host_safe(vcpu, tlbe)) {
-               u64 asid;
                gva_t eaddr;
                gpa_t gpaddr;
-               u32 flags;
                u32 bytes;
 
                eaddr = get_tlb_eaddr(tlbe);
@@ -403,15 +483,13 @@ 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, gtlb_index);
+               kvmppc_mmu_map(vcpu, eaddr, gpaddr, gtlb_index);
        }
 
-       KVMTRACE_5D(GTLB_WRITE, vcpu, gtlb_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;
 }
 
@@ -422,9 +500,9 @@ int kvmppc_44x_emul_tlbsx(struct kvm_vcpu *vcpu, u8 rt, u8 ra, u8 rb, u8 rc)
        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);
 
        gtlb_index = kvmppc_44x_tlb_index(vcpu, ea, pid, as);
        if (rc) {
@@ -433,7 +511,8 @@ int kvmppc_44x_emul_tlbsx(struct kvm_vcpu *vcpu, u8 rt, u8 ra, u8 rb, u8 rc)
                else
                        vcpu->arch.cr |= 0x20000000;
        }
-       vcpu->arch.gpr[rt] = gtlb_index;
+       kvmppc_set_gpr(vcpu, rt, gtlb_index);
 
+       kvmppc_set_exit_type(vcpu, EMULATED_TLBSX_EXITS);
        return EMULATE_DONE;
 }