]> git.proxmox.com Git - qemu.git/commitdiff
Improve PowerPC 405 MMU model / share more code for other embedded targets
authorj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 24 Apr 2007 06:44:14 +0000 (06:44 +0000)
committerj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 24 Apr 2007 06:44:14 +0000 (06:44 +0000)
support.
Fix PowerPC 405 MSR mask.

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

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

index f17f84641ce5455c263836fec81ae680915de2b1..4a241f1b3ddb7d3895bbcf5dafe65ea7aa0fd00e 100644 (file)
@@ -881,9 +881,11 @@ void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value);
 target_ulong load_40x_pit (CPUPPCState *env);
 void store_40x_pit (CPUPPCState *env, target_ulong val);
 void store_40x_dbcr0 (CPUPPCState *env, uint32_t val);
+void store_40x_sler (CPUPPCState *env, uint32_t val);
 void store_booke_tcr (CPUPPCState *env, target_ulong val);
 void store_booke_tsr (CPUPPCState *env, target_ulong val);
 void ppc_tlb_invalidate_all (CPUPPCState *env);
+int ppcemb_tlb_search (CPUPPCState *env, target_ulong address);
 #endif
 #endif
 
index e93f5a6d18814ed8b7ae5f907c7924b562cfe0b5..e3700b5f2c2c155c4d8ceeb56f336ccf004b956e 100644 (file)
@@ -632,6 +632,58 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
     return ret;
 }
 
+/* Generic TLB check function for embedded PowerPC implementations */
+static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb,
+                             target_phys_addr_t *raddrp,
+                             target_ulong address, int i)
+{
+    target_ulong mask;
+
+    /* Check valid flag */
+    if (!(tlb->prot & PAGE_VALID)) {
+        if (loglevel != 0)
+            fprintf(logfile, "%s: TLB %d not valid\n", __func__, i);
+        return -1;
+    }
+    mask = ~(tlb->size - 1);
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> "
+                ADDRX " " ADDRX " %d\n",
+                __func__, i, address, (int)env->spr[SPR_40x_PID],
+                tlb->EPN, mask, (int)tlb->PID);
+    }
+    /* Check PID */
+    if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID])
+        return -1;
+    /* Check effective address */
+    if ((address & mask) != tlb->EPN)
+        return -1;
+    *raddrp = (tlb->RPN & mask) | (address & ~mask);
+
+    return 0;
+}
+
+/* Generic TLB search function for PowerPC embedded implementations */
+int ppcemb_tlb_search (CPUState *env, target_ulong address)
+{
+    ppcemb_tlb_t *tlb;
+    target_phys_addr_t raddr;
+    int i, ret;
+
+    /* Default return value is no match */
+    ret = -1;
+    for (i = 0; i < 64; i++) {
+        tlb = &env->tlb[i].tlbe;
+        if (ppcemb_tlb_check(env, tlb, &raddr, address, i) == 0) {
+            ret = i;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+/* Helpers specific to PowerPC 40x implementations */
 void ppc4xx_tlb_invalidate_all (CPUState *env)
 {
     ppcemb_tlb_t *tlb;
@@ -656,33 +708,14 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
 {
     ppcemb_tlb_t *tlb;
     target_phys_addr_t raddr;
-    target_ulong mask;
     int i, ret, zsel, zpr;
             
     ret = -1;
     raddr = -1;
     for (i = 0; i < env->nb_tlb; i++) {
         tlb = &env->tlb[i].tlbe;
-        /* Check valid flag */
-        if (!(tlb->prot & PAGE_VALID)) {
-            if (loglevel != 0)
-                fprintf(logfile, "%s: TLB %d not valid\n", __func__, i);
-            continue;
-        }
-        mask = ~(tlb->size - 1);
-        if (loglevel != 0) {
-            fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> "
-                    ADDRX " " ADDRX " %d\n",
-                    __func__, i, address, (int)env->spr[SPR_40x_PID],
-                    tlb->EPN, mask, (int)tlb->PID);
-        }
-        /* Check PID */
-        if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID])
-            continue;
-        /* Check effective address */
-        if ((address & mask) != tlb->EPN)
+        if (ppcemb_tlb_check(env, tlb, &raddr, address, i) < 0)
             continue;
-        raddr = (tlb->RPN & mask) | (address & ~mask);
         zsel = (tlb->attr >> 4) & 0xF;
         zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3;
         if (loglevel != 0) {
@@ -692,6 +725,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
         if (access_type == ACCESS_CODE) {
             /* Check execute enable bit */
             switch (zpr) {
+            case 0x2:
+                if (msr_pr)
+                    goto check_exec_perm;
+                goto exec_granted;
             case 0x0:
                 if (msr_pr) {
                     ctx->prot = 0;
@@ -700,7 +737,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
                 }
                 /* No break here */
             case 0x1:
-            case 0x2:
+            check_exec_perm:
                 /* Check from TLB entry */
                 if (!(tlb->prot & PAGE_EXEC)) {
                     ret = -3;
@@ -714,6 +751,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
                 }
                 break;
             case 0x3:
+            exec_granted:
                 /* All accesses granted */
                 ctx->prot = PAGE_READ | PAGE_WRITE;
                 ret = 0;
@@ -721,6 +759,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
             }
         } else {
             switch (zpr) {
+            case 0x2:
+                if (msr_pr)
+                    goto check_rw_perm;
+                goto rw_granted;
             case 0x0:
                 if (msr_pr) {
                     ctx->prot = 0;
@@ -729,7 +771,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
                 }
                 /* No break here */
             case 0x1:
-            case 0x2:
+            check_rw_perm:
                 /* Check from TLB entry */
                 /* Check write protection bit */
                 if (tlb->prot & PAGE_WRITE) {
@@ -744,6 +786,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
                 }
                 break;
             case 0x3:
+            rw_granted:
                 /* All accesses granted */
                 ctx->prot = PAGE_READ | PAGE_WRITE;
                 ret = 0;
@@ -769,6 +812,15 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
     return ret;
 }
 
+void store_40x_sler (CPUPPCState *env, uint32_t val)
+{
+    /* XXX: TO BE FIXED */
+    if (val != 0x00000000) {
+        cpu_abort(env, "Little-endian regions are not supported by now\n");
+    }
+    env->spr[SPR_405_SLER] = val;
+}
+
 static int check_physical (CPUState *env, mmu_ctx_t *ctx,
                            target_ulong eaddr, int rw)
 {
index b8498f1827355099455d7f614070b42317ea53b4..f18e7f3f91034f32ca9bcb50e5a2f6920d015168 100644 (file)
@@ -2459,6 +2459,12 @@ void OPPROTO op_store_40x_dbcr0 (void)
     store_40x_dbcr0(env, T0);
 }
 
+void OPPROTO op_store_40x_sler (void)
+{
+    store_40x_sler(env, T0);
+    RETURN();
+}
+
 void OPPROTO op_store_booke_tcr (void)
 {
     store_booke_tcr(env, T0);
index e994486cf5e69a1079e8f4d4ec931241ff1fdd52..a888821d203b598297b07d88e6090b7042110aec 100644 (file)
@@ -2494,44 +2494,16 @@ void do_4xx_tlbre_hi (void)
         T0 |= 0x100;
 }
 
-static int tlb_4xx_search (target_ulong virtual)
-{
-    ppcemb_tlb_t *tlb;
-    target_ulong base, mask;
-    int i, ret;
-
-    /* Default return value is no match */
-    ret = -1;
-    for (i = 0; i < 64; i++) {
-        tlb = &env->tlb[i].tlbe;
-        /* Check TLB validity */
-        if (!(tlb->prot & PAGE_VALID))
-            continue;
-        /* Check TLB PID vs current PID */
-        if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID])
-            continue;
-        /* Check TLB address vs virtual address */
-        base = tlb->EPN;
-        mask = ~(tlb->size - 1);
-        if ((base & mask) != (virtual & mask))
-            continue;
-        ret = i;
-        break;
-    }
-
-    return ret;
-}
-
 void do_4xx_tlbsx (void)
 {
-    T0 = tlb_4xx_search(T0);
+    T0 = ppcemb_tlb_search(env, T0);
 }
 
 void do_4xx_tlbsx_ (void)
 {
     int tmp = xer_ov;
 
-    T0 = tlb_4xx_search(T0);
+    T0 = ppcemb_tlb_search(env, T0);
     if (T0 != -1)
         tmp |= 0x02;
     env->crf[0] = tmp;
@@ -2562,16 +2534,28 @@ void do_4xx_tlbwe_hi (void)
             tlb_flush_page(env, page);
     }
     tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
+    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
+     * If this ever occurs, one should use the ppcemb target instead
+     * of the ppc or ppc64 one
+     */
+    if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
+        cpu_abort(env, "TLB size %u < %u are not supported (%d)\n",
+                  tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7));
+    }
     tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1);
     if (T1 & 0x40)
         tlb->prot |= PAGE_VALID;
     else
         tlb->prot &= ~PAGE_VALID;
+    if (T1 & 0x20) {
+        /* XXX: TO BE FIXED */
+        cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
+    }
     tlb->PID = env->spr[SPR_40x_PID]; /* PID */
     tlb->attr = T1 & 0xFF;
 #if defined (DEBUG_SOFTWARE_TLB)
-    if (loglevel) {
-        fprintf(logfile, "%s: set up TLB %d RPN " ADDRX " EPN " ADDRX
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
                 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
                 (int)T0, tlb->RPN, tlb->EPN, tlb->size, 
                 tlb->prot & PAGE_READ ? 'r' : '-',
index d7473fef6d0462e30d7221c8760ef8ea0ec09235..51332ff4baf8437df490e54c40dc22f9171367f6 100644 (file)
@@ -355,6 +355,17 @@ static void spr_write_40x_dbcr0 (void *opaque, int sprn)
     RET_STOP(ctx);
 }
 
+static void spr_write_40x_sler (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_op_store_40x_sler();
+    /* We must stop the translation as we may have changed
+     * some regions endianness
+     */
+    RET_STOP(ctx);
+}
+
 static void spr_write_booke_tcr (void *opaque, int sprn)
 {
     gen_op_store_booke_tcr();
@@ -1711,10 +1722,9 @@ static void gen_spr_405 (CPUPPCState *env)
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
     /* Storage control */
-    /* XXX : not implemented */
     spr_register(env, SPR_405_SLER, "SLER",
                  SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_40x_sler,
                  0x00000000);
     /* XXX : not implemented */
     spr_register(env, SPR_405_SU0R, "SU0R",
@@ -2837,7 +2847,7 @@ static ppc_def_t ppc_defs[] = {
         .pvr_mask    = 0xFFFFFFFF,
         .insns_flags = PPC_INSNS_405,
         .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30ULL,
+        .msr_mask    = 0x00000000000ED630ULL,
     },
 #if defined (TODO)
     /* PowerPC 405 EZ */