Patchwork [5/8] target-ppc: Disentangle 64-bit version of get_segment()

login
register
mail settings
Submitter David Gibson
Date Feb. 12, 2013, 2 a.m.
Message ID <1360634411-5518-6-git-send-email-david@gibson.dropbear.id.au>
Download mbox | patch
Permalink /patch/219721/
State New
Headers show

Comments

David Gibson - Feb. 12, 2013, 2 a.m.
The poorly named get_segment() function handles most of the address
translation logic for hash-based MMUs.  It has many ugly conditionals on
whether the MMU is 32-bit or 64-bit.

This patch splits the function into 32 and 64-bit versions, using the
switch on mmu_type that's already in the caller (get_physical_address())
to select the right one.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 target-ppc/cpu.h        |    5 +--
 target-ppc/mmu-hash64.c |  114 +++++++++++++++++++++++++++++++++++++++++++++--
 target-ppc/mmu_helper.c |  108 +++++++++++++-------------------------------
 3 files changed, 143 insertions(+), 84 deletions(-)

Patch

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index da4bc17..cf12632 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1152,10 +1152,9 @@  hwaddr get_pteg_offset(CPUPPCState *env, hwaddr hash, int pte_size);
 #if defined(TARGET_PPC64)
 void ppc_store_asr (CPUPPCState *env, target_ulong value);
 int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
-ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr);
 void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
-int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
-               int rw, int type, int target_page_bits);
+int get_segment64(CPUPPCState *env, mmu_ctx_t *ctx,
+                  target_ulong eaddr, int rw, int type);
 #endif /* defined(TARGET_PPC64) */
 #endif /* !defined(CONFIG_USER_ONLY) */
 void ppc_store_msr (CPUPPCState *env, target_ulong value);
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 465592a..1d6425c 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -43,7 +43,7 @@ 
  * SLB handling
  */
 
-ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
+static ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
 {
     uint64_t esid_256M, esid_1T;
     int n;
@@ -275,8 +275,8 @@  static int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
 }
 
 /* PTE table lookup */
-int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
-               int rw, int type, int target_page_bits)
+static int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
+                      int rw, int type, int target_page_bits)
 {
     hwaddr pteg_off;
     target_ulong pte0, pte1;
@@ -348,3 +348,111 @@  int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
     }
     return ret;
 }
+
+int get_segment64(CPUPPCState *env, mmu_ctx_t *ctx,
+                  target_ulong eaddr, int rw, int type)
+{
+    hwaddr hash;
+    target_ulong vsid;
+    int pr, target_page_bits;
+    int ret, ret2;
+
+    pr = msr_pr;
+    ctx->eaddr = eaddr;
+    ppc_slb_t *slb;
+    target_ulong pageaddr;
+    int segment_bits;
+
+    LOG_MMU("Check SLBs\n");
+    slb = slb_lookup(env, eaddr);
+    if (!slb) {
+        return -5;
+    }
+
+    if (slb->vsid & SLB_VSID_B) {
+        vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
+        segment_bits = 40;
+    } else {
+        vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
+        segment_bits = 28;
+    }
+
+    target_page_bits = (slb->vsid & SLB_VSID_L)
+        ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
+    ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
+                  : (slb->vsid & SLB_VSID_KS));
+    ctx->nx = !!(slb->vsid & SLB_VSID_N);
+
+    pageaddr = eaddr & ((1ULL << segment_bits)
+                            - (1ULL << target_page_bits));
+    if (slb->vsid & SLB_VSID_B) {
+        hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
+    } else {
+        hash = vsid ^ (pageaddr >> target_page_bits);
+    }
+    /* Only 5 bits of the page index are used in the AVPN */
+    ctx->ptem = (slb->vsid & SLB_VSID_PTEM) |
+        ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
+
+    LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
+            ctx->key, ds, ctx->nx, vsid);
+    ret = -1;
+
+    /* Check if instruction fetch is allowed, if needed */
+    if (type != ACCESS_CODE || ctx->nx == 0) {
+        /* Page address translation */
+        LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
+                " hash " TARGET_FMT_plx "\n",
+                env->htab_base, env->htab_mask, hash);
+        ctx->hash[0] = hash;
+        ctx->hash[1] = ~hash;
+
+        /* Initialize real address with an invalid value */
+        ctx->raddr = (hwaddr)-1ULL;
+        LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+                " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
+                " hash=" TARGET_FMT_plx "\n",
+                env->htab_base, env->htab_mask, vsid, ctx->ptem,
+                ctx->hash[0]);
+        /* Primary table lookup */
+        ret = find_pte64(env, ctx, 0, rw, type, target_page_bits);
+        if (ret < 0) {
+            /* Secondary table lookup */
+            if (eaddr != 0xEFFFFFFF) {
+                LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+                        " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+                        " hash=" TARGET_FMT_plx "\n", env->htab_base,
+                        env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
+            }
+            ret2 = find_pte64(env, ctx, 1, rw, type, target_page_bits);
+            if (ret2 != -1) {
+                ret = ret2;
+            }
+        }
+#if defined(DUMP_PAGE_TABLES)
+        if (qemu_log_enabled()) {
+            hwaddr curaddr;
+            uint32_t a0, a1, a2, a3;
+
+            qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
+                     "\n", sdr, mask + 0x80);
+            for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
+                 curaddr += 16) {
+                a0 = ldl_phys(curaddr);
+                a1 = ldl_phys(curaddr + 4);
+                a2 = ldl_phys(curaddr + 8);
+                a3 = ldl_phys(curaddr + 12);
+                if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
+                    qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
+                             curaddr, a0, a1, a2, a3);
+                }
+            }
+        }
+#endif
+    } else {
+        LOG_MMU("No access allowed\n");
+        ret = -3;
+    }
+
+    return ret;
+}
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 48dc658..e9f8949 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -578,87 +578,35 @@  static inline int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h,
     return ret;
 }
 
-static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw,
-                           int type, int target_page_bits)
-{
-#if defined(TARGET_PPC64)
-    if (env->mmu_model & POWERPC_MMU_64) {
-        return find_pte64(env, ctx, h, rw, type, target_page_bits);
-    }
-#endif
-
-    return find_pte32(env, ctx, h, rw, type, target_page_bits);
-}
-
 /* Perform segment based translation */
-static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
-                              target_ulong eaddr, int rw, int type)
+static inline int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx,
+                                target_ulong eaddr, int rw, int type)
 {
     hwaddr hash;
     target_ulong vsid;
     int ds, pr, target_page_bits;
     int ret, ret2;
+    target_ulong sr, pgidx;
 
     pr = msr_pr;
     ctx->eaddr = eaddr;
-#if defined(TARGET_PPC64)
-    if (env->mmu_model & POWERPC_MMU_64) {
-        ppc_slb_t *slb;
-        target_ulong pageaddr;
-        int segment_bits;
-
-        LOG_MMU("Check SLBs\n");
-        slb = slb_lookup(env, eaddr);
-        if (!slb) {
-            return -5;
-        }
-
-        if (slb->vsid & SLB_VSID_B) {
-            vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
-            segment_bits = 40;
-        } else {
-            vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
-            segment_bits = 28;
-        }
 
-        target_page_bits = (slb->vsid & SLB_VSID_L)
-            ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
-        ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
-                      : (slb->vsid & SLB_VSID_KS));
-        ds = 0;
-        ctx->nx = !!(slb->vsid & SLB_VSID_N);
+    sr = env->sr[eaddr >> 28];
+    ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
+                ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
+    ds = sr & 0x80000000 ? 1 : 0;
+    ctx->nx = sr & 0x10000000 ? 1 : 0;
+    vsid = sr & 0x00FFFFFF;
+    target_page_bits = TARGET_PAGE_BITS;
+    LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
+            TARGET_FMT_lx " lr=" TARGET_FMT_lx
+            " ir=%d dr=%d pr=%d %d t=%d\n",
+            eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
+            (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
+    pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
+    hash = vsid ^ pgidx;
+    ctx->ptem = (vsid << 7) | (pgidx >> 10);
 
-        pageaddr = eaddr & ((1ULL << segment_bits)
-                            - (1ULL << target_page_bits));
-        if (slb->vsid & SLB_VSID_B) {
-            hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
-        } else {
-            hash = vsid ^ (pageaddr >> target_page_bits);
-        }
-        /* Only 5 bits of the page index are used in the AVPN */
-        ctx->ptem = (slb->vsid & SLB_VSID_PTEM) |
-            ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
-    } else
-#endif /* defined(TARGET_PPC64) */
-    {
-        target_ulong sr, pgidx;
-
-        sr = env->sr[eaddr >> 28];
-        ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
-                    ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
-        ds = sr & 0x80000000 ? 1 : 0;
-        ctx->nx = sr & 0x10000000 ? 1 : 0;
-        vsid = sr & 0x00FFFFFF;
-        target_page_bits = TARGET_PAGE_BITS;
-        LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
-                TARGET_FMT_lx " lr=" TARGET_FMT_lx
-                " ir=%d dr=%d pr=%d %d t=%d\n",
-                eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
-                (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
-        pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
-        hash = vsid ^ pgidx;
-        ctx->ptem = (vsid << 7) | (pgidx >> 10);
-    }
     LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
             ctx->key, ds, ctx->nx, vsid);
     ret = -1;
@@ -685,7 +633,7 @@  static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
                         env->htab_base, env->htab_mask, vsid, ctx->ptem,
                         ctx->hash[0]);
                 /* Primary table lookup */
-                ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
+                ret = find_pte32(env, ctx, 0, rw, type, target_page_bits);
                 if (ret < 0) {
                     /* Secondary table lookup */
                     if (eaddr != 0xEFFFFFFF) {
@@ -694,8 +642,8 @@  static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
                                 " hash=" TARGET_FMT_plx "\n", env->htab_base,
                                 env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
                     }
-                    ret2 = find_pte(env, ctx, 1, rw, type,
-                                    target_page_bits);
+                    ret2 = find_pte32(env, ctx, 1, rw, type,
+                                      target_page_bits);
                     if (ret2 != -1) {
                         ret = ret2;
                     }
@@ -1494,16 +1442,20 @@  static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
             if (env->nb_BATs != 0) {
                 ret = get_bat(env, ctx, eaddr, rw, access_type);
             }
+            if (ret < 0) {
+                /* We didn't match any BAT entry or don't have BATs */
+                ret = get_segment32(env, ctx, eaddr, rw, access_type);
+            }
+            break;
+
 #if defined(TARGET_PPC64)
         case POWERPC_MMU_64B:
         case POWERPC_MMU_2_06:
         case POWERPC_MMU_2_06d:
-#endif
-            if (ret < 0) {
-                /* We didn't match any BAT entry or don't have BATs */
-                ret = get_segment(env, ctx, eaddr, rw, access_type);
-            }
+            ret = get_segment64(env, ctx, eaddr, rw, access_type);
             break;
+#endif
+
         case POWERPC_MMU_SOFT_4xx:
         case POWERPC_MMU_SOFT_4xx_Z:
             ret = mmu40x_get_physical_address(env, ctx, eaddr,