diff options
Diffstat (limited to 'target-ppc/mmu-hash64.c')
-rw-r--r-- | target-ppc/mmu-hash64.c | 150 |
1 files changed, 55 insertions, 95 deletions
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c index 4a7dbbb95b..f18c98f021 100644 --- a/target-ppc/mmu-hash64.c +++ b/target-ppc/mmu-hash64.c @@ -40,11 +40,6 @@ # define LOG_SLB(...) do { } while (0) #endif -struct mmu_ctx_hash64 { - hwaddr raddr; /* Real address */ - int prot; /* Protection bits */ -}; - /* * SLB handling */ @@ -374,14 +369,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 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 +386,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 +397,65 @@ 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); + prot = ppc_hash64_pte_prot(env, slb, pte); - 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 { + env->exception_index = POWERPC_EXCP_DSI; + env->error_code = 0; + env->spr[SPR_DAR] = eaddr; + if (rwx == 1) { + env->spr[SPR_DSISR] = 0x0A000000; + } else { + env->spr[SPR_DSISR] = 0x08000000; + } + } + return 1; } LOG_MMU("PTE access granted !\n"); @@ -433,7 +468,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 +477,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 +508,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; -} |