diff options
Diffstat (limited to 'target-ppc')
-rw-r--r-- | target-ppc/cpu.h | 2 | ||||
-rw-r--r-- | target-ppc/mmu-hash32.c | 78 | ||||
-rw-r--r-- | target-ppc/mmu-hash32.h | 4 | ||||
-rw-r--r-- | target-ppc/mmu-hash64.c | 79 | ||||
-rw-r--r-- | target-ppc/mmu-hash64.h | 4 | ||||
-rw-r--r-- | target-ppc/mmu_helper.c | 119 |
6 files changed, 164 insertions, 122 deletions
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 625feb2664..cf8ba2e5e3 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1135,6 +1135,8 @@ void ppc_hw_interrupt (CPUPPCState *env); void ppc_store_sdr1 (CPUPPCState *env, target_ulong value); int pp_check(int key, int pp, int nx); int check_prot(int prot, int rw, int access_type); +int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p, int ret, int rw); +hwaddr get_pteg_offset(CPUPPCState *env, hwaddr hash, int pte_size); #endif /* !defined(CONFIG_USER_ONLY) */ void ppc_store_msr (CPUPPCState *env, target_ulong value); diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c index ce5389d217..f852e5c67e 100644 --- a/target-ppc/mmu-hash32.c +++ b/target-ppc/mmu-hash32.c @@ -42,8 +42,8 @@ static inline int pte_is_valid_hash32(target_ulong pte0) return pte0 & 0x80000000 ? 1 : 0; } -int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0, - target_ulong pte1, int h, int rw, int type) +static int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0, + target_ulong pte1, int h, int rw, int type) { target_ulong ptem, mmask; int access, ret, pteh, ptev, pp; @@ -83,3 +83,77 @@ int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0, return ret; } + +/* PTE table lookup */ +int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h, + int rw, int type, int target_page_bits) +{ + hwaddr pteg_off; + target_ulong pte0, pte1; + int i, good = -1; + int ret, r; + + ret = -1; /* No entry found */ + pteg_off = get_pteg_offset(env, ctx->hash[h], HASH_PTE_SIZE_32); + for (i = 0; i < 8; i++) { + if (env->external_htab) { + pte0 = ldl_p(env->external_htab + pteg_off + (i * 8)); + pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4); + } else { + pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8)); + pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4); + } + r = pte_check_hash32(ctx, pte0, pte1, h, rw, type); + LOG_MMU("Load pte from %08" HWADDR_PRIx " => " TARGET_FMT_lx " " + TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", + pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h, + (int)((pte0 >> 6) & 1), ctx->ptem); + switch (r) { + case -3: + /* PTE inconsistency */ + return -1; + case -2: + /* Access violation */ + ret = -2; + good = i; + break; + case -1: + default: + /* No PTE match */ + break; + case 0: + /* access granted */ + /* XXX: we should go on looping to check all PTEs consistency + * but if we can speed-up the whole thing as the + * result would be undefined if PTEs are not consistent. + */ + ret = 0; + good = i; + goto done; + } + } + if (good != -1) { + done: + LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n", + ctx->raddr, ctx->prot, ret); + /* Update page flags */ + pte1 = ctx->raddr; + if (pte_update_flags(ctx, &pte1, ret, rw) == 1) { + if (env->external_htab) { + stl_p(env->external_htab + pteg_off + (good * 8) + 4, + pte1); + } else { + stl_phys_notdirty(env->htab_base + pteg_off + + (good * 8) + 4, pte1); + } + } + } + + /* We have a TLB that saves 4K pages, so let's + * split a huge page to 4k chunks */ + if (target_page_bits != TARGET_PAGE_BITS) { + ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1)) + & TARGET_PAGE_MASK; + } + return ret; +} diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h index 24110857d2..6bf8f92463 100644 --- a/target-ppc/mmu-hash32.h +++ b/target-ppc/mmu-hash32.h @@ -4,8 +4,8 @@ #ifndef CONFIG_USER_ONLY int pte32_is_valid(target_ulong pte0); -int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0, - target_ulong pte1, int h, int rw, int type); +int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h, + int rw, int type, int target_page_bits); #endif /* CONFIG_USER_ONLY */ diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c index 9c0de1bbd9..a525bd552f 100644 --- a/target-ppc/mmu-hash64.c +++ b/target-ppc/mmu-hash64.c @@ -231,8 +231,8 @@ static inline int pte64_is_valid(target_ulong pte0) return pte0 & 0x0000000000000001ULL ? 1 : 0; } -int pte64_check(mmu_ctx_t *ctx, target_ulong pte0, - target_ulong pte1, int h, int rw, int type) +static int pte64_check(mmu_ctx_t *ctx, target_ulong pte0, + target_ulong pte1, int h, int rw, int type) { target_ulong ptem, mmask; int access, ret, pteh, ptev, pp; @@ -274,3 +274,78 @@ int pte64_check(mmu_ctx_t *ctx, target_ulong pte0, return ret; } + +/* PTE table lookup */ +int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h, + int rw, int type, int target_page_bits) +{ + hwaddr pteg_off; + target_ulong pte0, pte1; + int i, good = -1; + int ret, r; + + ret = -1; /* No entry found */ + pteg_off = get_pteg_offset(env, ctx->hash[h], HASH_PTE_SIZE_64); + for (i = 0; i < 8; i++) { + if (env->external_htab) { + pte0 = ldq_p(env->external_htab + pteg_off + (i * 16)); + pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8); + } else { + pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16)); + pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8); + } + + r = pte64_check(ctx, pte0, pte1, h, rw, type); + LOG_MMU("Load pte from %016" HWADDR_PRIx " => " TARGET_FMT_lx " " + TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", + pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h, + (int)((pte0 >> 1) & 1), ctx->ptem); + switch (r) { + case -3: + /* PTE inconsistency */ + return -1; + case -2: + /* Access violation */ + ret = -2; + good = i; + break; + case -1: + default: + /* No PTE match */ + break; + case 0: + /* access granted */ + /* XXX: we should go on looping to check all PTEs consistency + * but if we can speed-up the whole thing as the + * result would be undefined if PTEs are not consistent. + */ + ret = 0; + good = i; + goto done; + } + } + if (good != -1) { + done: + LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n", + ctx->raddr, ctx->prot, ret); + /* Update page flags */ + pte1 = ctx->raddr; + if (pte_update_flags(ctx, &pte1, ret, rw) == 1) { + if (env->external_htab) { + stq_p(env->external_htab + pteg_off + (good * 16) + 8, + pte1); + } else { + stq_phys_notdirty(env->htab_base + pteg_off + + (good * 16) + 8, pte1); + } + } + } + + /* We have a TLB that saves 4K pages, so let's + * split a huge page to 4k chunks */ + if (target_page_bits != TARGET_PAGE_BITS) { + ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1)) + & TARGET_PAGE_MASK; + } + return ret; +} diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h index 1a2e3e7258..7b9713da28 100644 --- a/target-ppc/mmu-hash64.h +++ b/target-ppc/mmu-hash64.h @@ -7,8 +7,8 @@ ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr); void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env); int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs); -int pte64_check(mmu_ctx_t *ctx, target_ulong pte0, - target_ulong pte1, int h, int rw, int type); +int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h, + int rw, int type, int target_page_bits); #endif #endif /* CONFIG_USER_ONLY */ diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index c7620c0c42..1301391800 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -201,8 +201,8 @@ static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0, return ret; } -static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p, - int ret, int rw) +int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p, + int ret, int rw) { int store = 0; @@ -502,130 +502,21 @@ static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx, return ret; } -static inline hwaddr get_pteg_offset(CPUPPCState *env, - hwaddr hash, - int pte_size) +hwaddr get_pteg_offset(CPUPPCState *env, hwaddr hash, int pte_size) { return (hash * pte_size * 8) & env->htab_mask; } -/* PTE table lookup */ -static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h, - int rw, int type, int target_page_bits) -{ - hwaddr pteg_off; - target_ulong pte0, pte1; - int i, good = -1; - int ret, r; - - ret = -1; /* No entry found */ - pteg_off = get_pteg_offset(env, ctx->hash[h], - is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32); - for (i = 0; i < 8; i++) { -#if defined(TARGET_PPC64) - if (is_64b) { - if (env->external_htab) { - pte0 = ldq_p(env->external_htab + pteg_off + (i * 16)); - pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8); - } else { - pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16)); - pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8); - } - - r = pte64_check(ctx, pte0, pte1, h, rw, type); - LOG_MMU("Load pte from %016" HWADDR_PRIx " => " TARGET_FMT_lx " " - TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", - pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h, - (int)((pte0 >> 1) & 1), ctx->ptem); - } else -#endif - { - if (env->external_htab) { - pte0 = ldl_p(env->external_htab + pteg_off + (i * 8)); - pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4); - } else { - pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8)); - pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4); - } - r = pte_check_hash32(ctx, pte0, pte1, h, rw, type); - LOG_MMU("Load pte from %08" HWADDR_PRIx " => " TARGET_FMT_lx " " - TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", - pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h, - (int)((pte0 >> 6) & 1), ctx->ptem); - } - switch (r) { - case -3: - /* PTE inconsistency */ - return -1; - case -2: - /* Access violation */ - ret = -2; - good = i; - break; - case -1: - default: - /* No PTE match */ - break; - case 0: - /* access granted */ - /* XXX: we should go on looping to check all PTEs consistency - * but if we can speed-up the whole thing as the - * result would be undefined if PTEs are not consistent. - */ - ret = 0; - good = i; - goto done; - } - } - if (good != -1) { - done: - LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n", - ctx->raddr, ctx->prot, ret); - /* Update page flags */ - pte1 = ctx->raddr; - if (pte_update_flags(ctx, &pte1, ret, rw) == 1) { -#if defined(TARGET_PPC64) - if (is_64b) { - if (env->external_htab) { - stq_p(env->external_htab + pteg_off + (good * 16) + 8, - pte1); - } else { - stq_phys_notdirty(env->htab_base + pteg_off + - (good * 16) + 8, pte1); - } - } else -#endif - { - if (env->external_htab) { - stl_p(env->external_htab + pteg_off + (good * 8) + 4, - pte1); - } else { - stl_phys_notdirty(env->htab_base + pteg_off + - (good * 8) + 4, pte1); - } - } - } - } - - /* We have a TLB that saves 4K pages, so let's - * split a huge page to 4k chunks */ - if (target_page_bits != TARGET_PAGE_BITS) { - ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1)) - & TARGET_PAGE_MASK; - } - return ret; -} - static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw, int type, int target_page_bits) { #if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { - return find_pte2(env, ctx, 1, h, rw, type, target_page_bits); + return find_pte64(env, ctx, h, rw, type, target_page_bits); } #endif - return find_pte2(env, ctx, 0, h, rw, type, target_page_bits); + return find_pte32(env, ctx, h, rw, type, target_page_bits); } /* Perform segment based translation */ |