]> xenbits.xensource.com Git - qemu-xen-4.1-testing.git/commitdiff
Full implementation of PowerPC 64 MMU, just missing support for 1 TB
authorj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Fri, 5 Oct 2007 22:06:02 +0000 (22:06 +0000)
committerj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Fri, 5 Oct 2007 22:06:02 +0000 (22:06 +0000)
  memory segments.
Remove the PowerPC 64 "bridge" MMU model and implement segment registers
  emulation using SLB entries instead.
Make SLB area size implementation dependant.
Improve TLB & SLB search debug traces.
Temporary hack to make PowerPC 970 boot from ROM instead of RAM.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3335 c046a42c-6fe2-441c-8c8c-71466251a162

target-ppc/cpu.h
target-ppc/helper.c
target-ppc/op.c
target-ppc/translate.c
target-ppc/translate_init.c

index 03942bf4bd15f3a3f39d2be14498e9dc72b12435..5824526bebb191014828586d4adea3eaf3dd6b52 100644 (file)
@@ -105,10 +105,8 @@ enum {
     /* BookE FSL MMU model                                     */
     POWERPC_MMU_BOOKE_FSL,
 #if defined(TARGET_PPC64)
-    /* Standard 64 bits PowerPC MMU                            */
+    /* 64 bits PowerPC MMU                                     */
     POWERPC_MMU_64B,
-    /* 64 bits "bridge" PowerPC MMU                            */
-    POWERPC_MMU_64BRIDGE,
 #endif /* defined(TARGET_PPC64) */
 };
 
@@ -514,6 +512,8 @@ struct CPUPPCState {
     ppc_tlb_t *tlb;  /* TLB is optional. Allocate them only if needed        */
     /* 403 dedicated access protection registers */
     target_ulong pb[4];
+    /* PowerPC 64 SLB area */
+    int slb_nr;
 
     int dcache_line_size;
     int icache_line_size;
@@ -606,10 +606,14 @@ void do_store_sdr1 (CPUPPCState *env, target_ulong value);
 #if defined(TARGET_PPC64)
 target_ulong ppc_load_asr (CPUPPCState *env);
 void ppc_store_asr (CPUPPCState *env, target_ulong value);
-#endif
+target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr);
+void ppc_store_slb (CPUPPCState *env, int slb_nr, target_ulong rs);
+#endif /* defined(TARGET_PPC64) */
+#if 0 // Unused
 target_ulong do_load_sr (CPUPPCState *env, int srnum);
-void do_store_sr (CPUPPCState *env, int srnum, target_ulong value);
 #endif
+void do_store_sr (CPUPPCState *env, int srnum, target_ulong value);
+#endif /* !defined(CONFIG_USER_ONLY) */
 target_ulong ppc_load_xer (CPUPPCState *env);
 void ppc_store_xer (CPUPPCState *env, target_ulong value);
 target_ulong do_load_msr (CPUPPCState *env);
index 99562d6684a66a07e2b48292a46a653d070e7a79..bb39fc05f3c9f33fa3b008dae3ca8738bd799adb 100644 (file)
@@ -501,21 +501,31 @@ static inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw)
             pte0 = ldq_phys(base + (i * 16));
             pte1 =  ldq_phys(base + (i * 16) + 8);
             r = pte64_check(ctx, pte0, pte1, h, rw);
+#if defined (DEBUG_MMU)
+            if (loglevel != 0) {
+                fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX
+                        " 0x" ADDRX " %d %d %d 0x" ADDRX "\n",
+                        base + (i * 16), pte0, pte1,
+                        (int)(pte0 & 1), h, (int)((pte0 >> 1) & 1),
+                        ctx->ptem);
+            }
+#endif
         } else
 #endif
         {
             pte0 = ldl_phys(base + (i * 8));
             pte1 =  ldl_phys(base + (i * 8) + 4);
             r = pte32_check(ctx, pte0, pte1, h, rw);
-        }
 #if defined (DEBUG_MMU)
-        if (loglevel != 0) {
-            fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX
-                    " 0x" ADDRX " %d %d %d 0x" ADDRX "\n",
-                    base + (i * 8), pte0, pte1,
-                    (int)(pte0 >> 31), h, (int)((pte0 >> 6) & 1), ctx->ptem);
-        }
+            if (loglevel != 0) {
+                fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX
+                        " 0x" ADDRX " %d %d %d 0x" ADDRX "\n",
+                        base + (i * 8), pte0, pte1,
+                        (int)(pte0 >> 31), h, (int)((pte0 >> 6) & 1),
+                        ctx->ptem);
+            }
 #endif
+        }
         switch (r) {
         case -3:
             /* PTE inconsistency */
@@ -581,24 +591,15 @@ static int find_pte64 (mmu_ctx_t *ctx, int h, int rw)
 static inline int find_pte (CPUState *env, mmu_ctx_t *ctx, int h, int rw)
 {
 #if defined(TARGET_PPC64)
-    if (env->mmu_model == POWERPC_MMU_64B ||
-        env->mmu_model == POWERPC_MMU_64BRIDGE)
+    if (env->mmu_model == POWERPC_MMU_64B)
         return find_pte64(ctx, h, rw);
 #endif
 
     return find_pte32(ctx, h, rw);
 }
 
-static inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1,
-                                             int sdr_sh,
-                                             target_phys_addr_t hash,
-                                             target_phys_addr_t mask)
-{
-    return (sdr1 & ((target_ulong)(-1ULL) << sdr_sh)) | (hash & mask);
-}
-
 #if defined(TARGET_PPC64)
-static int slb_lookup (CPUState *env, target_ulong eaddr,
+static int slb_lookup (CPUPPCState *env, target_ulong eaddr,
                        target_ulong *vsid, target_ulong *page_mask, int *attr)
 {
     target_phys_addr_t sr_base;
@@ -610,14 +611,23 @@ static int slb_lookup (CPUState *env, target_ulong eaddr,
 
     ret = -5;
     sr_base = env->spr[SPR_ASR];
+#if defined(DEBUG_SLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: eaddr " ADDRX " base " PADDRX "\n",
+                __func__, eaddr, sr_base);
+    }
+#endif
     mask = 0x0000000000000000ULL; /* Avoid gcc warning */
-#if 0 /* XXX: Fix this */
     slb_nr = env->slb_nr;
-#else
-    slb_nr = 32;
-#endif
     for (n = 0; n < slb_nr; n++) {
         tmp64 = ldq_phys(sr_base);
+        tmp = ldl_phys(sr_base + 8);
+#if defined(DEBUG_SLB)
+        if (loglevel != 0) {
+        fprintf(logfile, "%s: seg %d " PADDRX " %016" PRIx64 " %08" PRIx32 "\n",
+                __func__, n, sr_base, tmp64, tmp);
+        }
+#endif
         if (tmp64 & 0x0000000008000000ULL) {
             /* SLB entry is valid */
             switch (tmp64 & 0x0000000006000000ULL) {
@@ -636,7 +646,6 @@ static int slb_lookup (CPUState *env, target_ulong eaddr,
             }
             if ((eaddr & mask) == (tmp64 & mask)) {
                 /* SLB match */
-                tmp = ldl_phys(sr_base + 8);
                 *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
                 *page_mask = ~mask;
                 *attr = tmp & 0xFF;
@@ -649,13 +658,80 @@ static int slb_lookup (CPUState *env, target_ulong eaddr,
 
     return ret;
 }
+
+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) {
+        /* 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 */
+        /* Copy SLB bits 89:92 to Rt 33:36 (KsKpNL) */
+        rt |= ((tmp >> 4) & 0xF) << 27;
+    } else {
+        rt = 0;
+    }
+#if defined(DEBUG_SLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: " PADDRX " %016" PRIx64 " %08" PRIx32 " => %d "
+                ADDRX "\n", __func__, sr_base, tmp64, tmp, slb_nr, rt);
+    }
+#endif
+
+    return rt;
+}
+
+void ppc_store_slb (CPUPPCState *env, int slb_nr, target_ulong rs)
+{
+    target_phys_addr_t sr_base;
+    uint64_t tmp64;
+    uint32_t tmp;
+
+    sr_base = env->spr[SPR_ASR];
+    sr_base += 12 * slb_nr;
+    /* Copy Rs bits 37:63 to SLB 62:88 */
+    tmp = rs << 8;
+    tmp64 = (rs >> 24) & 0x7;
+    /* Copy Rs bits 33:36 to SLB 89:92 */
+    tmp |= ((rs >> 27) & 0xF) << 4;
+    /* Set the valid bit */
+    tmp64 |= 1 << 27;
+    /* Set ESID */
+    tmp64 |= (uint32_t)slb_nr << 28;
+#if defined(DEBUG_SLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: %d " ADDRX " => " PADDRX " %016" PRIx64 " %08"
+                PRIx32 "\n", __func__, slb_nr, rs, sr_base, tmp64, tmp);
+    }
+#endif
+    /* Write SLB entry to memory */
+    stq_phys(sr_base, tmp64);
+    stl_phys(sr_base + 8, tmp);
+}
 #endif /* defined(TARGET_PPC64) */
 
 /* Perform segment based translation */
+static inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1,
+                                             int sdr_sh,
+                                             target_phys_addr_t hash,
+                                             target_phys_addr_t mask)
+{
+    return (sdr1 & ((target_ulong)(-1ULL) << sdr_sh)) | (hash & mask);
+}
+
 static int get_segment (CPUState *env, mmu_ctx_t *ctx,
                         target_ulong eaddr, int rw, int type)
 {
-    target_phys_addr_t sdr, hash, mask, sdr_mask;
+    target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask;
     target_ulong sr, vsid, vsid_mask, pgidx, page_mask;
 #if defined(TARGET_PPC64)
     int attr;
@@ -664,8 +740,12 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
     int ret, ret2;
 
 #if defined(TARGET_PPC64)
-    if (env->mmu_model == POWERPC_MMU_64B ||
-        env->mmu_model == POWERPC_MMU_64BRIDGE) {
+    if (env->mmu_model == POWERPC_MMU_64B) {
+#if defined (DEBUG_MMU)
+        if (loglevel != 0) {
+            fprintf(logfile, "Check SLBs\n");
+        }
+#endif
         ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr);
         if (ret < 0)
             return ret;
@@ -699,29 +779,53 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
                     eaddr, (int)(eaddr >> 28), sr, env->nip,
                     env->lr, msr_ir, msr_dr, msr_pr, rw, type);
         }
-        if (!ds && loglevel != 0) {
-            fprintf(logfile, "pte segment: key=%d n=0x" ADDRX "\n",
-                    ctx->key, sr & 0x10000000);
-        }
 #endif
     }
+#if defined (DEBUG_MMU)
+    if (loglevel != 0) {
+        fprintf(logfile, "pte segment: key=%d ds %d nx %d vsid " ADDRX "\n",
+                ctx->key, ds, nx, vsid);
+    }
+#endif
     ret = -1;
     if (!ds) {
         /* Check if instruction fetch is allowed, if needed */
         if (type != ACCESS_CODE || nx == 0) {
             /* Page address translation */
-            pgidx = (eaddr & page_mask) >> TARGET_PAGE_BITS;
-            hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
             /* Primary table address */
             sdr = env->sdr1;
-            mask = ((sdr & 0x000001FF) << sdr_sh) | sdr_mask;
+            pgidx = (eaddr & page_mask) >> TARGET_PAGE_BITS;
+#if defined(TARGET_PPC64)
+            if (env->mmu_model == POWERPC_MMU_64B) {
+                htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F));
+                /* XXX: this is false for 1 TB segments */
+                hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
+            } else
+#endif
+            {
+                htab_mask = sdr & 0x000001FF;
+                hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
+            }
+            mask = (htab_mask << sdr_sh) | sdr_mask;
+#if defined (DEBUG_MMU)
+            if (loglevel != 0) {
+                fprintf(logfile, "sdr " PADDRX " sh %d hash " PADDRX " mask "
+                        PADDRX " " ADDRX "\n", sdr, sdr_sh, hash, mask,
+                        page_mask);
+            }
+#endif
             ctx->pg_addr[0] = get_pgaddr(sdr, sdr_sh, hash, mask);
             /* Secondary table address */
             hash = (~hash) & vsid_mask;
+#if defined (DEBUG_MMU)
+            if (loglevel != 0) {
+                fprintf(logfile, "sdr " PADDRX " sh %d hash " PADDRX " mask "
+                        PADDRX "\n", sdr, sdr_sh, hash, mask);
+            }
+#endif
             ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask);
 #if defined(TARGET_PPC64)
-            if (env->mmu_model == POWERPC_MMU_64B ||
-                env->mmu_model == POWERPC_MMU_64BRIDGE) {
+            if (env->mmu_model == POWERPC_MMU_64B) {
                 /* Only 5 bits of the page index are used in the AVPN */
                 ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80);
             } else
@@ -762,6 +866,27 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
                         ret = ret2;
                 }
             }
+#if defined (DEBUG_MMU)
+                    if (loglevel != 0) {
+                        target_phys_addr_t curaddr;
+                        uint32_t a0, a1, a2, a3;
+                        fprintf(logfile,
+                                "Page table: " PADDRX " len " PADDRX "\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) {
+                                fprintf(logfile,
+                                        PADDRX ": %08x %08x %08x %08x\n",
+                                        curaddr, a0, a1, a2, a3);
+                            }
+                        }
+                    }
+#endif
         } else {
 #if defined (DEBUG_MMU)
             if (loglevel != 0)
@@ -1103,7 +1228,6 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx,
         break;
 #if defined(TARGET_PPC64)
     case POWERPC_MMU_64B:
-    case POWERPC_MMU_64BRIDGE:
         /* Real address are 60 bits long */
         ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
         ctx->prot |= PAGE_WRITE;
@@ -1170,7 +1294,6 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
             /* No break here */
 #if defined(TARGET_PPC64)
         case POWERPC_MMU_64B:
-        case POWERPC_MMU_64BRIDGE:
 #endif
             if (ret < 0) {
                 /* We didn't match any BAT entry or don't have BATs */
@@ -1275,7 +1398,6 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                 case POWERPC_MMU_32B:
 #if defined(TARGET_PPC64)
                 case POWERPC_MMU_64B:
-                case POWERPC_MMU_64BRIDGE:
 #endif
                     env->exception_index = POWERPC_EXCP_ISI;
                     env->error_code = 0x40000000;
@@ -1371,7 +1493,6 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                 case POWERPC_MMU_32B:
 #if defined(TARGET_PPC64)
                 case POWERPC_MMU_64B:
-                case POWERPC_MMU_64BRIDGE:
 #endif
                     env->exception_index = POWERPC_EXCP_DSI;
                     env->error_code = 0;
@@ -1622,13 +1743,12 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
     case POWERPC_MMU_32B:
 #if defined(TARGET_PPC64)
     case POWERPC_MMU_64B:
-    case POWERPC_MMU_64BRIDGE:
 #endif /* defined(TARGET_PPC64) */
         tlb_flush(env, 1);
         break;
     default:
         /* XXX: TODO */
-        cpu_abort(env, "Unknown MMU model %d\n", env->mmu_model);
+        cpu_abort(env, "Unknown MMU model\n");
         break;
     }
 }
@@ -1688,7 +1808,6 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
         break;
 #if defined(TARGET_PPC64)
     case POWERPC_MMU_64B:
-    case POWERPC_MMU_64BRIDGE:
         /* tlbie invalidate TLBs for all segments */
         /* XXX: given the fact that there are too many segments to invalidate,
          *      and we still don't have a tlb_flush_mask(env, n, mask) in Qemu,
@@ -1699,7 +1818,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
 #endif /* defined(TARGET_PPC64) */
     default:
         /* XXX: TODO */
-        cpu_abort(env, "Unknown MMU model 2\n");
+        cpu_abort(env, "Unknown MMU model\n");
         break;
     }
 #else
@@ -1752,15 +1871,20 @@ void do_store_sdr1 (CPUPPCState *env, target_ulong value)
     }
 #endif
     if (env->sdr1 != value) {
+        /* XXX: for PowerPC 64, should check that the HTABSIZE value
+         *      is <= 28
+         */
         env->sdr1 = value;
         tlb_flush(env, 1);
     }
 }
 
+#if 0 // Unused
 target_ulong do_load_sr (CPUPPCState *env, int srnum)
 {
     return env->sr[srnum];
 }
+#endif
 
 void do_store_sr (CPUPPCState *env, int srnum, target_ulong value)
 {
index 2c023503151851d03ca3c3c6514a810403574b11..2dc058efb14e4acc8f4e85d131f1479b2b02f808 100644 (file)
@@ -317,6 +317,20 @@ void OPPROTO op_store_sr (void)
     RETURN();
 }
 
+#if defined(TARGET_PPC64)
+void OPPROTO op_load_slb (void)
+{
+    T0 = ppc_load_slb(env, T1);
+    RETURN();
+}
+
+void OPPROTO op_store_slb (void)
+{
+    ppc_store_slb(env, T1, T0);
+    RETURN();
+}
+#endif /* defined(TARGET_PPC64) */
+
 void OPPROTO op_load_sdr1 (void)
 {
     T0 = env->sdr1;
index 77486f3b6a664334ff0a6d64942b47b7e7849402..bc6336b0c9da3ecdd2a61fe47741906b97f30d8b 100644 (file)
@@ -385,107 +385,107 @@ static inline target_ulong MASK (uint32_t start, uint32_t end)
 /* PowerPC Instructions types definitions                                    */
 enum {
     PPC_NONE          = 0x0000000000000000ULL,
-    /* integer operations instructions                  */
-    /* flow control instructions                        */
-    /* virtual memory instructions                      */
-    /* ld/st with reservation instructions              */
-    /* cache control instructions                       */
-    /* spr/msr access instructions                      */
+    /* PowerPC base instructions set                                         */
     PPC_INSNS_BASE    = 0x0000000000000001ULL,
+    /* integer operations instructions                                       */
 #define PPC_INTEGER PPC_INSNS_BASE
+    /* flow control instructions                                             */
 #define PPC_FLOW    PPC_INSNS_BASE
+    /* virtual memory instructions                                           */
 #define PPC_MEM     PPC_INSNS_BASE
+    /* ld/st with reservation instructions                                   */
 #define PPC_RES     PPC_INSNS_BASE
+    /* cache control instructions                                            */
 #define PPC_CACHE   PPC_INSNS_BASE
+    /* spr/msr access instructions                                           */
 #define PPC_MISC    PPC_INSNS_BASE
-    /* Optional floating point instructions             */
+    /* Optional floating point instructions                                  */
     PPC_FLOAT         = 0x0000000000000002ULL,
     PPC_FLOAT_FSQRT   = 0x0000000000000004ULL,
     PPC_FLOAT_FRES    = 0x0000000000000008ULL,
     PPC_FLOAT_FRSQRTE = 0x0000000000000010ULL,
     PPC_FLOAT_FSEL    = 0x0000000000000020ULL,
     PPC_FLOAT_STFIWX  = 0x0000000000000040ULL,
-    /* external control instructions                    */
+    /* external control instructions                                         */
     PPC_EXTERN        = 0x0000000000000080ULL,
-    /* segment register access instructions             */
+    /* segment register access instructions                                  */
     PPC_SEGMENT       = 0x0000000000000100ULL,
-    /* Optional cache control instruction               */
+    /* Optional cache control instruction                                    */
     PPC_CACHE_DCBA    = 0x0000000000000200ULL,
-    /* Optional memory control instructions             */
+    /* Optional memory control instructions                                  */
     PPC_MEM_TLBIA     = 0x0000000000000400ULL,
     PPC_MEM_TLBIE     = 0x0000000000000800ULL,
     PPC_MEM_TLBSYNC   = 0x0000000000001000ULL,
-    /* eieio & sync                                     */
+    /* eieio & sync                                                          */
     PPC_MEM_SYNC      = 0x0000000000002000ULL,
-    /* PowerPC 6xx TLB management instructions          */
+    /* PowerPC 6xx TLB management instructions                               */
     PPC_6xx_TLB       = 0x0000000000004000ULL,
-    /* Altivec support                                  */
+    /* Altivec support                                                       */
     PPC_ALTIVEC       = 0x0000000000008000ULL,
-    /* Time base mftb instruction                       */
+    /* Time base mftb instruction                                            */
     PPC_MFTB          = 0x0000000000010000ULL,
-    /* Embedded PowerPC dedicated instructions          */
+    /* Embedded PowerPC dedicated instructions                               */
     PPC_EMB_COMMON    = 0x0000000000020000ULL,
-    /* PowerPC 40x exception model                      */
+    /* PowerPC 40x exception model                                           */
     PPC_40x_EXCP      = 0x0000000000040000ULL,
-    /* PowerPC 40x TLB management instructions          */
+    /* PowerPC 40x TLB management instructions                               */
     PPC_40x_TLB       = 0x0000000000080000ULL,
-    /* PowerPC 405 Mac instructions                     */
+    /* PowerPC 405 Mac instructions                                          */
     PPC_405_MAC       = 0x0000000000100000ULL,
-    /* PowerPC 440 specific instructions                */
+    /* PowerPC 440 specific instructions                                     */
     PPC_440_SPEC      = 0x0000000000200000ULL,
-    /* Power-to-PowerPC bridge (601)                    */
+    /* Power-to-PowerPC bridge (601)                                         */
     PPC_POWER_BR      = 0x0000000000400000ULL,
-    /* PowerPC 602 specific */
+    /* PowerPC 602 specific                                                  */
     PPC_602_SPEC      = 0x0000000000800000ULL,
-    /* Deprecated instructions                          */
-    /* Original POWER instruction set                   */
+    /* Deprecated instructions                                               */
+    /* Original POWER instruction set                                        */
     PPC_POWER         = 0x0000000001000000ULL,
-    /* POWER2 instruction set extension                 */
+    /* POWER2 instruction set extension                                      */
     PPC_POWER2        = 0x0000000002000000ULL,
-    /* Power RTC support */
+    /* Power RTC support                                                     */
     PPC_POWER_RTC     = 0x0000000004000000ULL,
-    /* 64 bits PowerPC instructions                     */
-    /* 64 bits PowerPC instruction set                  */
+    /* 64 bits PowerPC instruction set                                       */
     PPC_64B           = 0x0000000008000000ULL,
-    /* 64 bits hypervisor extensions                    */
+    /* 64 bits hypervisor extensions                                         */
     PPC_64H           = 0x0000000010000000ULL,
-    /* 64 bits PowerPC "bridge" features                */
-    PPC_64_BRIDGE     = 0x0000000020000000ULL,
-    /* BookE (embedded) PowerPC specification           */
+    /* segment register access instructions for PowerPC 64 "bridge"          */
+    PPC_SEGMENT_64B   = 0x0000000020000000ULL,
+    /* BookE (embedded) PowerPC specification                                */
     PPC_BOOKE         = 0x0000000040000000ULL,
-    /* eieio                                            */
+    /* eieio                                                                 */
     PPC_MEM_EIEIO     = 0x0000000080000000ULL,
-    /* e500 vector instructions                         */
+    /* e500 vector instructions                                              */
     PPC_E500_VECTOR   = 0x0000000100000000ULL,
-    /* PowerPC 4xx dedicated instructions               */
+    /* PowerPC 4xx dedicated instructions                                    */
     PPC_4xx_COMMON    = 0x0000000200000000ULL,
-    /* PowerPC 2.03 specification extensions            */
+    /* PowerPC 2.03 specification extensions                                 */
     PPC_203           = 0x0000000400000000ULL,
-    /* PowerPC 2.03 SPE extension                       */
+    /* PowerPC 2.03 SPE extension                                            */
     PPC_SPE           = 0x0000000800000000ULL,
-    /* PowerPC 2.03 SPE floating-point extension        */
+    /* PowerPC 2.03 SPE floating-point extension                             */
     PPC_SPEFPU        = 0x0000001000000000ULL,
-    /* SLB management                                   */
+    /* SLB management                                                        */
     PPC_SLBI          = 0x0000002000000000ULL,
-    /* PowerPC 40x ibct instructions                    */
+    /* PowerPC 40x ibct instructions                                         */
     PPC_40x_ICBT      = 0x0000004000000000ULL,
-    /* PowerPC 74xx TLB management instructions         */
+    /* PowerPC 74xx TLB management instructions                              */
     PPC_74xx_TLB      = 0x0000008000000000ULL,
-    /* More BookE (embedded) instructions...            */
+    /* More BookE (embedded) instructions...                                 */
     PPC_BOOKE_EXT     = 0x0000010000000000ULL,
-    /* rfmci is not implemented in all BookE PowerPC    */
+    /* rfmci is not implemented in all BookE PowerPC                         */
     PPC_RFMCI         = 0x0000020000000000ULL,
-    /* user-mode DCR access, implemented in PowerPC 460 */
+    /* user-mode DCR access, implemented in PowerPC 460                      */
     PPC_DCRUX         = 0x0000040000000000ULL,
-    /* New floating-point extensions (PowerPC 2.0x)     */
+    /* New floating-point extensions (PowerPC 2.0x)                          */
     PPC_FLOAT_EXT     = 0x0000080000000000ULL,
-    /* New wait instruction (PowerPC 2.0x)              */
+    /* New wait instruction (PowerPC 2.0x)                                   */
     PPC_WAIT          = 0x0000100000000000ULL,
-    /* New 64 bits extensions (PowerPC 2.0x)            */
+    /* New 64 bits extensions (PowerPC 2.0x)                                 */
     PPC_64BX          = 0x0000200000000000ULL,
-    /* dcbz instruction with fixed cache line size      */
+    /* dcbz instruction with fixed cache line size                           */
     PPC_CACHE_DCBZ    = 0x0000400000000000ULL,
-    /* dcbz instruction with tunable cache line size    */
+    /* dcbz instruction with tunable cache line size                         */
     PPC_CACHE_DCBZT   = 0x0000800000000000ULL,
 };
 
@@ -3931,6 +3931,75 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
 #endif
 }
 
+#if defined(TARGET_PPC64)
+/* Specific implementation for PowerPC 64 "bridge" emulation using SLB */
+/* mfsr */
+GEN_HANDLER(mfsr_64b, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVREG(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
+        return;
+    }
+    gen_op_set_T1(SR(ctx->opcode));
+    gen_op_load_slb();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* mfsrin */
+GEN_HANDLER(mfsrin_64b, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT_64B)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVREG(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
+        return;
+    }
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_srli_T1(28);
+    gen_op_load_slb();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* mtsr */
+GEN_HANDLER(mtsr_64b, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVREG(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_set_T1(SR(ctx->opcode));
+    gen_op_store_slb();
+#endif
+}
+
+/* mtsrin */
+GEN_HANDLER(mtsrin_64b, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT_64B)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVREG(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_srli_T1(28);
+    gen_op_store_slb();
+#endif
+}
+#endif /* defined(TARGET_PPC64) */
+
 /***                      Lookaside buffer management                      ***/
 /* Optional & supervisor only: */
 /* tlbia */
index 834c047f300590091a86b917b7ca9451f2c8a31c..8bc6209dfcf8f8bf7bed580207b84c7c329c64d7 100644 (file)
@@ -3095,12 +3095,13 @@ static void init_proc_e500 (CPUPPCState *env)
 /* Non-embedded PowerPC                                                      */
 /* Base instructions set for all 6xx/7xx/74xx/970 PowerPC                    */
 #define POWERPC_INSNS_6xx    (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC |     \
-                              PPC_MEM_EIEIO | PPC_SEGMENT | PPC_MEM_TLBIE)
+                              PPC_MEM_EIEIO | PPC_MEM_TLBIE)
 /* Instructions common to all 6xx/7xx/74xx/970 PowerPC except 601 & 602      */
 #define POWERPC_INSNS_WORKS  (POWERPC_INSNS_6xx | PPC_FLOAT_FSQRT |           \
                               PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE |            \
                               PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX |             \
-                              PPC_MEM_TLBSYNC | PPC_CACHE_DCBZ | PPC_MFTB)
+                              PPC_MEM_TLBSYNC | PPC_CACHE_DCBZ | PPC_MFTB |   \
+                              PPC_SEGMENT)
 
 /* POWER : same as 601, without mfmsr, mfsr                                  */
 #if defined(TODO)
@@ -3111,7 +3112,7 @@ static void init_proc_e500 (CPUPPCState *env)
 
 /* PowerPC 601                                                               */
 #define POWERPC_INSNS_601    (POWERPC_INSNS_6xx | PPC_CACHE_DCBZ |            \
-                              PPC_EXTERN | PPC_POWER_BR)
+                              PPC_SEGMENT | PPC_EXTERN | PPC_POWER_BR)
 #define POWERPC_MSRM_601     (0x000000000000FE70ULL)
 //#define POWERPC_MMU_601      (POWERPC_MMU_601)
 //#define POWERPC_EXCP_601     (POWERPC_EXCP_601)
@@ -3164,7 +3165,7 @@ static void init_proc_601 (CPUPPCState *env)
                               PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE |            \
                               PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX |             \
                               PPC_6xx_TLB | PPC_MEM_TLBSYNC | PPC_CACHE_DCBZ |\
-                              PPC_602_SPEC)
+                              PPC_SEGMENT | PPC_602_SPEC)
 #define POWERPC_MSRM_602     (0x000000000033FF73ULL)
 #define POWERPC_MMU_602      (POWERPC_MMU_SOFT_6xx)
 //#define POWERPC_EXCP_602     (POWERPC_EXCP_602)
@@ -3942,15 +3943,15 @@ static void init_proc_7455 (CPUPPCState *env)
 
 #if defined (TARGET_PPC64)
 #define POWERPC_INSNS_WORK64  (POWERPC_INSNS_6xx | PPC_FLOAT_FSQRT |          \
-                              PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE |            \
-                              PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX |             \
-                              PPC_MEM_TLBSYNC | PPC_CACHE_DCBZT | PPC_MFTB)
+                               PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE |           \
+                               PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX |            \
+                               PPC_MEM_TLBSYNC | PPC_CACHE_DCBZT | PPC_MFTB)
 /* PowerPC 970                                                               */
 #define POWERPC_INSNS_970    (POWERPC_INSNS_WORK64 | PPC_FLOAT_FSQRT |        \
                               PPC_64B | PPC_ALTIVEC |                         \
-                              PPC_64_BRIDGE | PPC_SLBI)
+                              PPC_SEGMENT_64B | PPC_SLBI)
 #define POWERPC_MSRM_970     (0x900000000204FF36ULL)
-#define POWERPC_MMU_970      (POWERPC_MMU_64BRIDGE)
+#define POWERPC_MMU_970      (POWERPC_MMU_64B)
 //#define POWERPC_EXCP_970     (POWERPC_EXCP_970)
 #define POWERPC_INPUT_970    (PPC_FLAGS_INPUT_970)
 #define POWERPC_BFDM_970     (bfd_mach_ppc64)
@@ -3990,9 +3991,24 @@ static void init_proc_970 (CPUPPCState *env)
     /* Memory management */
     /* XXX: not correct */
     gen_low_BATs(env);
-#if 0 // TODO
-    env->slb_nr = 32;
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCFG, "MMUCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000); /* TOFIX */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000); /* TOFIX */
+    spr_register(env, SPR_HIOR, "SPR_HIOR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0xFFF00000); /* XXX: This is a hack */
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_prefix = 0xFFF00000;
 #endif
+    env->slb_nr = 32;
     init_excp_970(env);
     env->dcache_line_size = 128;
     env->icache_line_size = 128;
@@ -4003,9 +4019,9 @@ static void init_proc_970 (CPUPPCState *env)
 /* PowerPC 970FX (aka G5)                                                    */
 #define POWERPC_INSNS_970FX  (POWERPC_INSNS_WORK64 | PPC_FLOAT_FSQRT |        \
                               PPC_64B | PPC_ALTIVEC |                         \
-                              PPC_64_BRIDGE | PPC_SLBI)
+                              PPC_SEGMENT_64B | PPC_SLBI)
 #define POWERPC_MSRM_970FX   (0x800000000204FF36ULL)
-#define POWERPC_MMU_970FX    (POWERPC_MMU_64BRIDGE)
+#define POWERPC_MMU_970FX    (POWERPC_MMU_64B)
 #define POWERPC_EXCP_970FX   (POWERPC_EXCP_970)
 #define POWERPC_INPUT_970FX  (PPC_FLAGS_INPUT_970)
 #define POWERPC_BFDM_970FX   (bfd_mach_ppc64)
@@ -4045,9 +4061,24 @@ static void init_proc_970FX (CPUPPCState *env)
     /* Memory management */
     /* XXX: not correct */
     gen_low_BATs(env);
-#if 0 // TODO
-    env->slb_nr = 32;
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCFG, "MMUCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000); /* TOFIX */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000); /* TOFIX */
+    spr_register(env, SPR_HIOR, "SPR_HIOR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0xFFF00000); /* XXX: This is a hack */
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_prefix = 0xFFF00000;
 #endif
+    env->slb_nr = 32;
     init_excp_970(env);
     env->dcache_line_size = 128;
     env->icache_line_size = 128;
@@ -4058,9 +4089,9 @@ static void init_proc_970FX (CPUPPCState *env)
 /* PowerPC 970 GX                                                            */
 #define POWERPC_INSNS_970GX  (POWERPC_INSNS_WORK64 | PPC_FLOAT_FSQRT |        \
                               PPC_64B | PPC_ALTIVEC |                         \
-                              PPC_64_BRIDGE | PPC_SLBI)
+                              PPC_SEGMENT_64B | PPC_SLBI)
 #define POWERPC_MSRM_970GX   (0x800000000204FF36ULL)
-#define POWERPC_MMU_970GX    (POWERPC_MMU_64BRIDGE)
+#define POWERPC_MMU_970GX    (POWERPC_MMU_64B)
 #define POWERPC_EXCP_970GX   (POWERPC_EXCP_970)
 #define POWERPC_INPUT_970GX  (PPC_FLAGS_INPUT_970)
 #define POWERPC_BFDM_970GX   (bfd_mach_ppc64)
@@ -4100,9 +4131,24 @@ static void init_proc_970GX (CPUPPCState *env)
     /* Memory management */
     /* XXX: not correct */
     gen_low_BATs(env);
-#if 0 // TODO
-    env->slb_nr = 32;
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCFG, "MMUCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000); /* TOFIX */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCSR0, "MMUCSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000); /* TOFIX */
+    spr_register(env, SPR_HIOR, "SPR_HIOR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0xFFF00000); /* XXX: This is a hack */
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_prefix = 0xFFF00000;
 #endif
+    env->slb_nr = 32;
     init_excp_970(env);
     env->dcache_line_size = 128;
     env->icache_line_size = 128;
@@ -6010,9 +6056,6 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def)
         case POWERPC_MMU_64B:
             mmu_model = "PowerPC 64";
             break;
-        case POWERPC_MMU_64BRIDGE:
-            mmu_model = "PowerPC 64 bridge";
-            break;
 #endif
         default:
             mmu_model = "Unknown or invalid";