32-bit and 64-bit hash MMU implementations currently share a find_pte function. This results in a whole bunch of ugly conditionals in the shared function, and not all that much actually shared code.
This patch separates out the 64-bit version, putting it in mmu-hash64.c, and removes the conditionals from both versions. Signed-off-by: David Gibson <[email protected]> --- target-ppc/cpu.h | 6 ++-- target-ppc/mmu-hash64.c | 79 +++++++++++++++++++++++++++++++++++++++++-- target-ppc/mmu_helper.c | 86 ++++++++++++++--------------------------------- 3 files changed, 106 insertions(+), 65 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 3c57516..da4bc17 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1147,13 +1147,15 @@ 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); #if defined(TARGET_PPC64) void ppc_store_asr (CPUPPCState *env, target_ulong value); int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs); ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr); void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env); -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 /* defined(TARGET_PPC64) */ #endif /* !defined(CONFIG_USER_ONLY) */ void ppc_store_msr (CPUPPCState *env, target_ulong value); diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c index 67dff23..465592a 100644 --- a/target-ppc/mmu-hash64.c +++ b/target-ppc/mmu-hash64.c @@ -230,8 +230,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; @@ -273,3 +273,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_helper.c b/target-ppc/mmu_helper.c index 610443f..48dc658 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -199,8 +199,7 @@ static inline int pte32_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; @@ -500,16 +499,14 @@ 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) +static inline 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; @@ -517,40 +514,20 @@ static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h, 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); + pteg_off = get_pteg_offset(env, ctx->hash[h], 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 = pte32_check(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); - } + 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 = pte32_check(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 */ @@ -582,25 +559,12 @@ static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h, /* 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); - } + 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); } } } @@ -619,11 +583,11 @@ static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw, { #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 */ -- 1.7.10.4
