]> Git Repo - qemu.git/blobdiff - target-ppc/mmu-hash64.c
softfloat: Fix shift128Right for shift counts 64..127
[qemu.git] / target-ppc / mmu-hash64.c
index 4a7dbbb95b2b553e349035c5e92fdc7338d0d8e5..43ccf456e350d6502e6cf4cf05fde9392b0e1163 100644 (file)
 #  define LOG_SLB(...) do { } while (0)
 #endif
 
-struct mmu_ctx_hash64 {
-    hwaddr raddr;      /* Real address              */
-    int prot;                      /* Protection bits           */
-};
-
 /*
  * SLB handling
  */
@@ -280,6 +275,33 @@ static int ppc_hash64_pte_prot(CPUPPCState *env,
     return prot;
 }
 
+static int ppc_hash64_amr_prot(CPUPPCState *env, ppc_hash_pte64_t pte)
+{
+    int key, amrbits;
+    int prot = PAGE_EXEC;
+
+
+    /* Only recent MMUs implement Virtual Page Class Key Protection */
+    if (!(env->mmu_model & POWERPC_MMU_AMR)) {
+        return PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+    }
+
+    key = HPTE64_R_KEY(pte.pte1);
+    amrbits = (env->spr[SPR_AMR] >> 2*(31 - key)) & 0x3;
+
+    /* fprintf(stderr, "AMR protection: key=%d AMR=0x%" PRIx64 "\n", key, */
+    /*         env->spr[SPR_AMR]); */
+
+    if (amrbits & 0x2) {
+        prot |= PAGE_WRITE;
+    }
+    if (amrbits & 0x1) {
+        prot |= PAGE_READ;
+    }
+
+    return prot;
+}
+
 static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr pteg_off,
                                      bool secondary, target_ulong ptem,
                                      ppc_hash_pte64_t *pte)
@@ -374,14 +396,16 @@ static hwaddr ppc_hash64_pte_raddr(ppc_slb_t *slb, ppc_hash_pte64_t pte,
     return (rpn & ~mask) | (eaddr & mask);
 }
 
-static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
-                                target_ulong eaddr, int rwx)
+int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr,
+                                int rwx, int mmu_idx)
 {
     ppc_slb_t *slb;
     hwaddr pte_offset;
     ppc_hash_pte64_t pte;
+    int pp_prot, amr_prot, prot;
     uint64_t new_pte1;
     const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
+    hwaddr raddr;
 
     assert((rwx == 0) || (rwx == 1) || (rwx == 2));
 
@@ -389,8 +413,10 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
     if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
         /* Translation is off */
         /* In real mode the top 4 effective address bits are ignored */
-        ctx->raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
-        ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
+        raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
+        tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
+                     PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
+                     TARGET_PAGE_SIZE);
         return 0;
     }
 
@@ -398,29 +424,74 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
     slb = slb_lookup(env, eaddr);
 
     if (!slb) {
-        return -5;
+        if (rwx == 2) {
+            env->exception_index = POWERPC_EXCP_ISEG;
+            env->error_code = 0;
+        } else {
+            env->exception_index = POWERPC_EXCP_DSEG;
+            env->error_code = 0;
+            env->spr[SPR_DAR] = eaddr;
+        }
+        return 1;
     }
 
     /* 3. Check for segment level no-execute violation */
     if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
-        return -3;
+        env->exception_index = POWERPC_EXCP_ISI;
+        env->error_code = 0x10000000;
+        return 1;
     }
 
     /* 4. Locate the PTE in the hash table */
     pte_offset = ppc_hash64_htab_lookup(env, slb, eaddr, &pte);
     if (pte_offset == -1) {
-        return -1;
+        if (rwx == 2) {
+            env->exception_index = POWERPC_EXCP_ISI;
+            env->error_code = 0x40000000;
+        } else {
+            env->exception_index = POWERPC_EXCP_DSI;
+            env->error_code = 0;
+            env->spr[SPR_DAR] = eaddr;
+            if (rwx == 1) {
+                env->spr[SPR_DSISR] = 0x42000000;
+            } else {
+                env->spr[SPR_DSISR] = 0x40000000;
+            }
+        }
+        return 1;
     }
     LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
 
     /* 5. Check access permissions */
 
-    ctx->prot = ppc_hash64_pte_prot(env, slb, pte);
+    pp_prot = ppc_hash64_pte_prot(env, slb, pte);
+    amr_prot = ppc_hash64_amr_prot(env, pte);
+    prot = pp_prot & amr_prot;
 
-    if ((need_prot[rwx] & ~ctx->prot) != 0) {
+    if ((need_prot[rwx] & ~prot) != 0) {
         /* Access right violation */
         LOG_MMU("PTE access rejected\n");
-        return -2;
+        if (rwx == 2) {
+            env->exception_index = POWERPC_EXCP_ISI;
+            env->error_code = 0x08000000;
+        } else {
+            target_ulong dsisr = 0;
+
+            env->exception_index = POWERPC_EXCP_DSI;
+            env->error_code = 0;
+            env->spr[SPR_DAR] = eaddr;
+            if (need_prot[rwx] & ~pp_prot) {
+                dsisr |= 0x08000000;
+            }
+            if (rwx == 1) {
+                dsisr |= 0x02000000;
+            }
+            if (need_prot[rwx] & ~amr_prot) {
+                dsisr |= 0x00200000;
+            }
+            env->spr[SPR_DSISR] = dsisr;
+        }
+        return 1;
     }
 
     LOG_MMU("PTE access granted !\n");
@@ -433,7 +504,7 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
     } else {
         /* Treat the page as read-only for now, so that a later write
          * will pass through this function again to set the C bit */
-        ctx->prot &= ~PAGE_WRITE;
+        prot &= ~PAGE_WRITE;
     }
 
     if (new_pte1 != pte.pte1) {
@@ -442,7 +513,10 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
 
     /* 7. Determine the real address from the PTE */
 
-    ctx->raddr = ppc_hash64_pte_raddr(slb, pte, eaddr);
+    raddr = ppc_hash64_pte_raddr(slb, pte, eaddr);
+
+    tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
+                 prot, mmu_idx, TARGET_PAGE_SIZE);
 
     return 0;
 }
@@ -470,81 +544,3 @@ hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
 
     return ppc_hash64_pte_raddr(slb, pte, addr) & TARGET_PAGE_MASK;
 }
-
-int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rwx,
-                                int mmu_idx)
-{
-    struct mmu_ctx_hash64 ctx;
-    int ret = 0;
-
-    ret = ppc_hash64_translate(env, &ctx, address, rwx);
-    if (ret == 0) {
-        tlb_set_page(env, address & TARGET_PAGE_MASK,
-                     ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
-                     mmu_idx, TARGET_PAGE_SIZE);
-        ret = 0;
-    } else if (ret < 0) {
-        LOG_MMU_STATE(env);
-        if (rwx == 2) {
-            switch (ret) {
-            case -1:
-                env->exception_index = POWERPC_EXCP_ISI;
-                env->error_code = 0x40000000;
-                break;
-            case -2:
-                /* Access rights violation */
-                env->exception_index = POWERPC_EXCP_ISI;
-                env->error_code = 0x08000000;
-                break;
-            case -3:
-                /* No execute protection violation */
-                env->exception_index = POWERPC_EXCP_ISI;
-                env->error_code = 0x10000000;
-                break;
-            case -5:
-                /* No match in segment table */
-                env->exception_index = POWERPC_EXCP_ISEG;
-                env->error_code = 0;
-                break;
-            }
-        } else {
-            switch (ret) {
-            case -1:
-                /* No matches in page tables or TLB */
-                env->exception_index = POWERPC_EXCP_DSI;
-                env->error_code = 0;
-                env->spr[SPR_DAR] = address;
-                if (rwx == 1) {
-                    env->spr[SPR_DSISR] = 0x42000000;
-                } else {
-                    env->spr[SPR_DSISR] = 0x40000000;
-                }
-                break;
-            case -2:
-                /* Access rights violation */
-                env->exception_index = POWERPC_EXCP_DSI;
-                env->error_code = 0;
-                env->spr[SPR_DAR] = address;
-                if (rwx == 1) {
-                    env->spr[SPR_DSISR] = 0x0A000000;
-                } else {
-                    env->spr[SPR_DSISR] = 0x08000000;
-                }
-                break;
-            case -5:
-                /* No match in segment table */
-                env->exception_index = POWERPC_EXCP_DSEG;
-                env->error_code = 0;
-                env->spr[SPR_DAR] = address;
-                break;
-            }
-        }
-#if 0
-        printf("%s: set exception to %d %02x\n", __func__,
-               env->exception, env->error_code);
-#endif
-        ret = 1;
-    }
-
-    return ret;
-}
This page took 0.030244 seconds and 4 git commands to generate.