OSDN Git Service

Code provision for PowerPC BookE MMU model support.
authorj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Wed, 19 Sep 2007 05:44:04 +0000 (05:44 +0000)
committerj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Wed, 19 Sep 2007 05:44:04 +0000 (05:44 +0000)
Better MSR flags initialisation.

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

target-ppc/helper.c
target-ppc/op.c
target-ppc/op_helper.c
target-ppc/op_helper.h
target-ppc/translate.c

index b6fc803..80315f6 100644 (file)
@@ -1013,6 +1013,52 @@ void store_40x_sler (CPUPPCState *env, uint32_t val)
     env->spr[SPR_405_SLER] = val;
 }
 
+int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
+                                   target_ulong address, int rw,
+                                   int access_type)
+{
+    ppcemb_tlb_t *tlb;
+    target_phys_addr_t raddr;
+    int i, prot, ret;
+
+    ret = -1;
+    raddr = -1;
+    for (i = 0; i < env->nb_tlb; i++) {
+        tlb = &env->tlb[i].tlbe;
+        if (ppcemb_tlb_check(env, tlb, &raddr, address,
+                             env->spr[SPR_BOOKE_PID], 1, i) < 0)
+            continue;
+        if (msr_pr)
+            prot = tlb->prot & 0xF;
+        else
+            prot = (tlb->prot >> 4) & 0xF;
+        /* Check the address space */
+        if (access_type == ACCESS_CODE) {
+            if (msr_is != (tlb->attr & 1))
+                continue;
+            ctx->prot = prot;
+            if (prot & PAGE_EXEC) {
+                ret = 0;
+                break;
+            }
+            ret = -3;
+        } else {
+            if (msr_ds != (tlb->attr & 1))
+                continue;
+            ctx->prot = prot;
+            if ((!rw && prot & PAGE_READ) || (rw && (prot & PAGE_WRITE))) {
+                ret = 0;
+                break;
+            }
+            ret = -2;
+        }
+    }
+    if (ret >= 0)
+        ctx->raddr = raddr;
+
+    return ret;
+}
+
 static int check_physical (CPUState *env, mmu_ctx_t *ctx,
                            target_ulong eaddr, int rw)
 {
@@ -1115,9 +1161,9 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
             cpu_abort(env, "601 MMU model not implemented\n");
             return -1;
         case PPC_FLAGS_MMU_BOOKE:
-            /* XXX: TODO */
-            cpu_abort(env, "BookeE MMU model not implemented\n");
-            return -1;
+            ret = mmubooke_get_physical_address(env, ctx, eaddr,
+                                                rw, access_type);
+            break;
         case PPC_FLAGS_MMU_BOOKE_FSL:
             /* XXX: TODO */
             cpu_abort(env, "BookE FSL MMU model not implemented\n");
@@ -1950,7 +1996,7 @@ void do_interrupt (CPUState *env)
         cpu_abort(env, "Floating point assist exception "
                   "is not implemented yet !\n");
         goto store_next;
-        /* 64 bits PowerPC exceptions */
+    /* 64 bits PowerPC exceptions */
     case EXCP_DSEG: /* 0x0380 */
         /* XXX: TODO */
         cpu_abort(env, "Data segment exception is not implemented yet !\n");
@@ -2446,28 +2492,39 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr)
 void cpu_ppc_reset (void *opaque)
 {
     CPUPPCState *env;
+    int i;
 
     env = opaque;
+    /* XXX: some of those flags initialisation values could depend
+     *      on the actual PowerPC implementation
+     */
+    for (i = 0; i < 63; i++)
+        env->msr[i] = 0;
+#if defined(TARGET_PPC64)
+    msr_hv = 0; /* Should be 1... */
+#endif
+    msr_ap = 0; /* TO BE CHECKED */
+    msr_sa = 0; /* TO BE CHECKED */
+    msr_ip = 0; /* TO BE CHECKED */
 #if defined (DO_SINGLE_STEP) && 0
     /* Single step trace mode */
     msr_se = 1;
     msr_be = 1;
 #endif
-    msr_fp = 1; /* Allow floating point exceptions */
-    msr_me = 1; /* Allow machine check exceptions  */
-#if defined(TARGET_PPC64)
-    msr_sf = 0; /* Boot in 32 bits mode */
-    msr_cm = 0;
-#endif
 #if defined(CONFIG_USER_ONLY)
+    msr_fp = 1; /* Allow floating point exceptions */
     msr_pr = 1;
-    tlb_flush(env, 1);
 #else
     env->nip = 0xFFFFFFFC;
     ppc_tlb_invalidate_all(env);
 #endif
     do_compute_hflags(env);
     env->reserve = -1;
+    /* Be sure no exception or interrupt is pending */
+    env->pending_interrupts = 0;
+    env->exception_index = EXCP_NONE;
+    /* Flush all TLBs */
+    tlb_flush(env, 1);
 }
 
 CPUPPCState *cpu_ppc_init (void)
index 8ad2223..1e9bd22 100644 (file)
@@ -2365,6 +2365,54 @@ void OPPROTO op_wrte (void)
     RETURN();
 }
 
+void OPPROTO op_booke_tlbre0 (void)
+{
+    do_booke_tlbre0();
+    RETURN();
+}
+
+void OPPROTO op_booke_tlbre1 (void)
+{
+    do_booke_tlbre1();
+    RETURN();
+}
+
+void OPPROTO op_booke_tlbre2 (void)
+{
+    do_booke_tlbre2();
+    RETURN();
+}
+
+void OPPROTO op_booke_tlbsx (void)
+{
+    do_booke_tlbsx();
+    RETURN();
+}
+
+void OPPROTO op_booke_tlbsx_ (void)
+{
+    do_booke_tlbsx_();
+    RETURN();
+}
+
+void OPPROTO op_booke_tlbwe0 (void)
+{
+    do_booke_tlbwe0();
+    RETURN();
+}
+
+void OPPROTO op_booke_tlbwe1 (void)
+{
+    do_booke_tlbwe1();
+    RETURN();
+}
+
+void OPPROTO op_booke_tlbwe2 (void)
+{
+    do_booke_tlbwe2();
+    RETURN();
+}
+
 void OPPROTO op_4xx_tlbre_lo (void)
 {
     do_4xx_tlbre_lo();
index 4afbfd8..56f2a55 100644 (file)
@@ -2605,4 +2605,151 @@ void do_4xx_tlbwe_lo (void)
     }
 #endif
 }
+
+/* BookE TLB management */
+void do_booke_tlbwe0 (void)
+{
+    ppcemb_tlb_t *tlb;
+    target_ulong EPN, size;
+    int do_flush_tlbs;
+
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
+    }
+#endif
+    do_flush_tlbs = 0;
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0].tlbe;
+    EPN = T1 & 0xFFFFFC00;
+    if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
+        do_flush_tlbs = 1;
+    tlb->EPN = EPN;
+    size = booke_tlb_to_page_size((T1 >> 4) & 0xF);
+    if ((tlb->prot & PAGE_VALID) && tlb->size < size)
+        do_flush_tlbs = 1;
+    tlb->size = size;
+    tlb->attr &= ~0x1;
+    tlb->attr |= (T1 >> 8) & 1;
+    if (T1 & 0x200) {
+        tlb->prot |= PAGE_VALID;
+    } else {
+        if (tlb->prot & PAGE_VALID) {
+            tlb->prot &= ~PAGE_VALID;
+            do_flush_tlbs = 1;
+        }
+    }
+    tlb->PID = env->spr[SPR_BOOKE_PID];
+    if (do_flush_tlbs)
+        tlb_flush(env, 1);
+}
+
+void do_booke_tlbwe1 (void)
+{
+    ppcemb_tlb_t *tlb;
+    target_phys_addr_t RPN;
+
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
+    }
+#endif
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0].tlbe;
+    RPN = T1 & 0xFFFFFC0F;
+    if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
+        tlb_flush(env, 1);
+    tlb->RPN = RPN;
+}
+
+void do_booke_tlbwe2 (void)
+{
+    ppcemb_tlb_t *tlb;
+
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
+    }
+#endif
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0].tlbe;
+    tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00);
+    tlb->prot = tlb->prot & PAGE_VALID;
+    if (T1 & 0x1)
+        tlb->prot |= PAGE_READ << 4;
+    if (T1 & 0x2)
+        tlb->prot |= PAGE_WRITE << 4;
+    if (T1 & 0x4)
+        tlb->prot |= PAGE_EXEC << 4;
+    if (T1 & 0x8)
+        tlb->prot |= PAGE_READ;
+    if (T1 & 0x10)
+        tlb->prot |= PAGE_WRITE;
+    if (T1 & 0x20)
+        tlb->prot |= PAGE_EXEC;
+}
+
+void do_booke_tlbsx (void)
+{
+    T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR]);
+}
+
+void do_booke_tlbsx_ (void)
+{
+    int tmp = xer_so;
+
+    T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR]);
+    if (T0 != -1)
+        tmp |= 0x02;
+    env->crf[0] = tmp;
+}
+
+void do_booke_tlbre0 (void)
+{
+    ppcemb_tlb_t *tlb;
+    int size;
+
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0].tlbe;
+    T0 = tlb->EPN;
+    size = booke_page_size_to_tlb(tlb->size);
+    if (size < 0 || size > 0xF)
+        size = 1;
+    T0 |= size << 4;
+    if (tlb->attr & 0x1)
+        T0 |= 0x100;
+    if (tlb->prot & PAGE_VALID)
+        T0 |= 0x200;
+    env->spr[SPR_BOOKE_PID] = tlb->PID;
+}
+
+void do_booke_tlbre1 (void)
+{
+    ppcemb_tlb_t *tlb;
+
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0].tlbe;
+    T0 = tlb->RPN;
+}
+
+void do_booke_tlbre2 (void)
+{
+    ppcemb_tlb_t *tlb;
+
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0].tlbe;
+    T0 = tlb->attr & ~0x1;
+    if (tlb->prot & (PAGE_READ << 4))
+        T0 |= 0x1;
+    if (tlb->prot & (PAGE_WRITE << 4))
+        T0 |= 0x2;
+    if (tlb->prot & (PAGE_EXEC << 4))
+        T0 |= 0x4;
+    if (tlb->prot & PAGE_READ)
+        T0 |= 0x8;
+    if (tlb->prot & PAGE_WRITE)
+        T0 |= 0x10;
+    if (tlb->prot & PAGE_EXEC)
+        T0 |= 0x20;
+}
 #endif /* !CONFIG_USER_ONLY */
index 33f053f..5c412ef 100644 (file)
@@ -156,6 +156,18 @@ void do_POWER_rfsvc (void);
 void do_op_602_mfrom (void);
 #endif
 
+/* PowerPC BookE specific helpers */
+#if !defined(CONFIG_USER_ONLY)
+void do_booke_tlbre0 (void);
+void do_booke_tlbre1 (void);
+void do_booke_tlbre2 (void);
+void do_booke_tlbsx (void);
+void do_booke_tlbsx_ (void);
+void do_booke_tlbwe0 (void);
+void do_booke_tlbwe1 (void);
+void do_booke_tlbwe2 (void);
+#endif
+
 /* PowerPC 4xx specific helpers */
 void do_405_check_ov (void);
 void do_405_check_sat (void);
index 6583a55..21e7019 100644 (file)
@@ -4618,9 +4618,10 @@ GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_BOOKE)
     RET_CHG_FLOW(ctx);
 #endif
 }
+
 /* TLB management - PowerPC 405 implementation */
 /* tlbre */
-GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC)
+GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC)
 {
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVOPC(ctx);
@@ -4648,7 +4649,7 @@ GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC)
 }
 
 /* tlbsx - tlbsx. */
-GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC)
+GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC)
 {
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVOPC(ctx);
@@ -4667,7 +4668,7 @@ GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC)
 }
 
 /* tlbwe */
-GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC)
+GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC)
 {
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVOPC(ctx);
@@ -4694,6 +4695,92 @@ GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC)
 #endif
 }
 
+/* TLB management - PowerPC BookE implementation */
+/* tlbre */
+GEN_HANDLER(tlbre_booke, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    switch (rB(ctx->opcode)) {
+    case 0:
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_booke_tlbre0();
+        gen_op_store_T0_gpr(rD(ctx->opcode));
+        break;
+    case 1:
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_booke_tlbre1();
+        gen_op_store_T0_gpr(rD(ctx->opcode));
+        break;
+    case 2:
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_booke_tlbre2();
+        gen_op_store_T0_gpr(rD(ctx->opcode));
+        break;
+    default:
+        RET_INVAL(ctx);
+        break;
+    }
+#endif
+}
+
+/* tlbsx - tlbsx. */
+GEN_HANDLER(tlbsx_booke, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    gen_addr_reg_index(ctx);
+    if (Rc(ctx->opcode))
+        gen_op_booke_tlbsx_();
+    else
+        gen_op_booke_tlbsx();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* tlbwe */
+GEN_HANDLER(tlbwe_booke, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    switch (rB(ctx->opcode)) {
+    case 0:
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_load_gpr_T1(rS(ctx->opcode));
+        gen_op_booke_tlbwe0();
+        break;
+    case 1:
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_load_gpr_T1(rS(ctx->opcode));
+        gen_op_booke_tlbwe1();
+        break;
+    case 2:
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_load_gpr_T1(rS(ctx->opcode));
+        gen_op_booke_tlbwe2();
+        break;
+    default:
+        RET_INVAL(ctx);
+        break;
+    }
+#endif
+}
+
 /* wrtee */
 GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON)
 {