From 8eee0af947cafdce5668abb6b7545f3887624ba8 Mon Sep 17 00:00:00 2001
From: blueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>
Date: Sat, 7 Mar 2009 20:57:42 +0000
Subject: [PATCH] Keep SLB in-CPU

---
 target-ppc/cpu.h            |   7 +++++++
 target-ppc/helper.c         | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------
 target-ppc/translate_init.c |   2 +-
 3 files changed, 77 insertions(+), 64 deletions(-)

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 1c0b753..77cf6de 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -344,6 +344,12 @@ union ppc_tlb_t {
     ppcemb_tlb_t tlbe;
 };
 
+typedef struct ppc_slb_t ppc_slb_t;
+struct ppc_slb_t {
+    uint64_t tmp64;
+    uint32_t tmp;
+};
+
 /*****************************************************************************/
 /* Machine state register bits definition                                    */
 #define MSR_SF   63 /* Sixty-four-bit mode                            hflags */
@@ -584,6 +590,7 @@ struct CPUPPCState {
     /* Address space register */
     target_ulong asr;
     /* PowerPC 64 SLB area */
+    ppc_slb_t slb[64];
     int slb_nr;
 #endif
     /* segment registers */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index f2dc011..73b091f 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -693,14 +693,44 @@ static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx,
 }
 
 #if defined(TARGET_PPC64)
-static always_inline int slb_is_valid (uint64_t slb64)
+static ppc_slb_t *slb_get_entry(CPUPPCState *env, int nr)
 {
-    return slb64 & 0x0000000008000000ULL ? 1 : 0;
+    ppc_slb_t *retval = &env->slb[nr];
+
+#if 0 // XXX implement bridge mode?
+    if (env->spr[SPR_ASR] & 1) {
+        target_phys_addr_t sr_base;
+
+        sr_base = env->spr[SPR_ASR] & 0xfffffffffffff000;
+        sr_base += (12 * nr);
+
+        retval->tmp64 = ldq_phys(sr_base);
+        retval->tmp = ldl_phys(sr_base + 8);
+    }
+#endif
+
+    return retval;
+}
+
+static void slb_set_entry(CPUPPCState *env, int nr, ppc_slb_t *slb)
+{
+    ppc_slb_t *entry = &env->slb[nr];
+
+    if (slb == entry)
+        return;
+
+    entry->tmp64 = slb->tmp64;
+    entry->tmp = slb->tmp;
+}
+
+static always_inline int slb_is_valid (ppc_slb_t *slb)
+{
+    return (int)(slb->tmp64 & 0x0000000008000000ULL);
 }
 
-static always_inline void slb_invalidate (uint64_t *slb64)
+static always_inline void slb_invalidate (ppc_slb_t *slb)
 {
-    *slb64 &= ~0x0000000008000000ULL;
+    slb->tmp64 &= ~0x0000000008000000ULL;
 }
 
 static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
@@ -708,25 +738,20 @@ static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
                                      target_ulong *page_mask, int *attr,
                                      int *target_page_bits)
 {
-    target_phys_addr_t sr_base;
     target_ulong mask;
-    uint64_t tmp64;
-    uint32_t tmp;
     int n, ret;
 
     ret = -5;
-    sr_base = env->spr[SPR_ASR];
-    LOG_SLB("%s: eaddr " ADDRX " base " PADDRX "\n",
-                __func__, eaddr, sr_base);
+    LOG_SLB("%s: eaddr " ADDRX "\n", __func__, eaddr);
     mask = 0x0000000000000000ULL; /* Avoid gcc warning */
     for (n = 0; n < env->slb_nr; n++) {
-        tmp64 = ldq_phys(sr_base);
-        tmp = ldl_phys(sr_base + 8);
-        LOG_SLB("%s: seg %d " PADDRX " %016" PRIx64 " %08"
-                    PRIx32 "\n", __func__, n, sr_base, tmp64, tmp);
-        if (slb_is_valid(tmp64)) {
+        ppc_slb_t *slb = slb_get_entry(env, n);
+
+        LOG_SLB("%s: seg %d %016" PRIx64 " %08"
+                    PRIx32 "\n", __func__, n, slb->tmp64, slb->tmp);
+        if (slb_is_valid(slb)) {
             /* SLB entry is valid */
-            if (tmp & 0x8) {
+            if (slb->tmp & 0x8) {
                 /* 1 TB Segment */
                 mask = 0xFFFF000000000000ULL;
                 if (target_page_bits)
@@ -737,16 +762,15 @@ static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
                 if (target_page_bits)
                     *target_page_bits = TARGET_PAGE_BITS;
             }
-            if ((eaddr & mask) == (tmp64 & mask)) {
+            if ((eaddr & mask) == (slb->tmp64 & mask)) {
                 /* SLB match */
-                *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
+                *vsid = ((slb->tmp64 << 24) | (slb->tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
                 *page_mask = ~mask;
-                *attr = tmp & 0xFF;
+                *attr = slb->tmp & 0xFF;
                 ret = n;
                 break;
             }
         }
-        sr_base += 12;
     }
 
     return ret;
@@ -754,25 +778,22 @@ static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
 
 void ppc_slb_invalidate_all (CPUPPCState *env)
 {
-    target_phys_addr_t sr_base;
-    uint64_t tmp64;
     int n, do_invalidate;
 
     do_invalidate = 0;
-    sr_base = env->spr[SPR_ASR];
     /* XXX: Warning: slbia never invalidates the first segment */
     for (n = 1; n < env->slb_nr; n++) {
-        tmp64 = ldq_phys(sr_base);
-        if (slb_is_valid(tmp64)) {
-            slb_invalidate(&tmp64);
-            stq_phys(sr_base, tmp64);
+        ppc_slb_t *slb = slb_get_entry(env, n);
+
+        if (slb_is_valid(slb)) {
+            slb_invalidate(slb);
+            slb_set_entry(env, n, slb);
             /* XXX: given the fact that segment size is 256 MB or 1TB,
              *      and we still don't have a tlb_flush_mask(env, n, mask)
              *      in Qemu, we just invalidate all TLBs
              */
             do_invalidate = 1;
         }
-        sr_base += 12;
     }
     if (do_invalidate)
         tlb_flush(env, 1);
@@ -780,20 +801,17 @@ void ppc_slb_invalidate_all (CPUPPCState *env)
 
 void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
 {
-    target_phys_addr_t sr_base;
     target_ulong vsid, page_mask;
-    uint64_t tmp64;
     int attr;
     int n;
 
     n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL);
     if (n >= 0) {
-        sr_base = env->spr[SPR_ASR];
-        sr_base += 12 * n;
-        tmp64 = ldq_phys(sr_base);
-        if (slb_is_valid(tmp64)) {
-            slb_invalidate(&tmp64);
-            stq_phys(sr_base, tmp64);
+        ppc_slb_t *slb = slb_get_entry(env, n);
+
+        if (slb_is_valid(slb)) {
+            slb_invalidate(slb);
+            slb_set_entry(env, n, slb);
             /* XXX: given the fact that segment size is 256 MB or 1TB,
              *      and we still don't have a tlb_flush_mask(env, n, mask)
              *      in Qemu, we just invalidate all TLBs
@@ -805,36 +823,28 @@ void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
 
 target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr)
 {
-    target_phys_addr_t sr_base;
     target_ulong rt;
-    uint64_t tmp64;
-    uint32_t tmp;
-
-    sr_base = env->spr[SPR_ASR];
-    sr_base += 12 * slb_nr;
-    tmp64 = ldq_phys(sr_base);
-    tmp = ldl_phys(sr_base + 8);
-    if (tmp64 & 0x0000000008000000ULL) {
+    ppc_slb_t *slb = slb_get_entry(env, slb_nr);
+
+    if (slb_is_valid(slb)) {
         /* SLB entry is valid */
         /* Copy SLB bits 62:88 to Rt 37:63 (VSID 23:49) */
-        rt = tmp >> 8;             /* 65:88 => 40:63 */
-        rt |= (tmp64 & 0x7) << 24; /* 62:64 => 37:39 */
+        rt = slb->tmp >> 8;             /* 65:88 => 40:63 */
+        rt |= (slb->tmp64 & 0x7) << 24; /* 62:64 => 37:39 */
         /* Copy SLB bits 89:92 to Rt 33:36 (KsKpNL) */
-        rt |= ((tmp >> 4) & 0xF) << 27;
+        rt |= ((slb->tmp >> 4) & 0xF) << 27;
     } else {
         rt = 0;
     }
-    LOG_SLB("%s: " PADDRX " %016" PRIx64 " %08" PRIx32 " => %d "
-                ADDRX "\n", __func__, sr_base, tmp64, tmp, slb_nr, rt);
+    LOG_SLB("%s: %016" PRIx64 " %08" PRIx32 " => %d "
+                ADDRX "\n", __func__, slb->tmp64, slb->tmp, slb_nr, rt);
 
     return rt;
 }
 
 void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
 {
-    target_phys_addr_t sr_base;
-    uint64_t tmp64;
-    uint32_t tmp;
+    ppc_slb_t *slb;
 
     uint64_t vsid;
     uint64_t esid;
@@ -847,19 +857,15 @@ void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
     valid = (rb & (1 << 27));
     slb_nr = rb & 0xfff;
 
-    tmp64 = (esid << 28) | valid | (vsid >> 24);
-    tmp = (vsid << 8) | (flags << 3);
-
-    /* Write SLB entry to memory */
-    sr_base = env->spr[SPR_ASR];
-    sr_base += 12 * slb_nr;
+    slb = slb_get_entry(env, slb_nr);
+    slb->tmp64 = (esid << 28) | valid | (vsid >> 24);
+    slb->tmp = (vsid << 8) | (flags << 3);
 
-    LOG_SLB("%s: %d " ADDRX " - " ADDRX " => " PADDRX " %016" PRIx64
+    LOG_SLB("%s: %d " ADDRX " - " ADDRX " => %016" PRIx64
                 " %08" PRIx32 "\n", __func__,
-                slb_nr, rb, rs, sr_base, tmp64, tmp);
+                slb_nr, rb, rs, tmp64, tmp);
 
-    stq_phys(sr_base, tmp64);
-    stl_phys(sr_base + 8, tmp);
+    slb_set_entry(env, slb_nr, slb);
 }
 #endif /* defined(TARGET_PPC64) */
 
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 42e62be..2fa6515 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -6056,7 +6056,7 @@ static void init_proc_970FX (CPUPPCState *env)
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
 #if !defined(CONFIG_USER_ONLY)
-    env->slb_nr = 32;
+    env->slb_nr = 64;
 #endif
     init_excp_970(env);
     env->dcache_line_size = 128;
--
libgit2 0.23.3