diff options
author | David Gibson <david@gibson.dropbear.id.au> | 2013-03-12 00:31:09 +0000 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2013-03-22 15:28:47 +0100 |
commit | 0480884f1404295ba0d242791e036b05c4957bab (patch) | |
tree | ab601cf1a02c895765e552bf370a9b5a8ce15f2c /target-ppc/mmu-hash64.c | |
parent | c69b6151e7f242b02f261f321c392e5ef933176f (diff) |
target-ppc: Disentangle get_segment()
The poorly named get_segment() function handles most of the address
translation logic for hash-based MMUs. It has many ugly conditionals on
whether the MMU is 32-bit or 64-bit.
This patch splits the function into 32 and 64-bit versions, using the
switch on mmu_type that's already in the caller
(get_physical_address()) to select the right one. Most of the
original function remains in mmu_helper.c to support the 6xx software
loaded TLB implementations (cleaning those up is a project for another
day).
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'target-ppc/mmu-hash64.c')
-rw-r--r-- | target-ppc/mmu-hash64.c | 92 |
1 files changed, 89 insertions, 3 deletions
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c index a525bd552f..23eb4801cc 100644 --- a/target-ppc/mmu-hash64.c +++ b/target-ppc/mmu-hash64.c @@ -44,7 +44,7 @@ * SLB handling */ -ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr) +static ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr) { uint64_t esid_256M, esid_1T; int n; @@ -276,8 +276,8 @@ static int pte64_check(mmu_ctx_t *ctx, target_ulong pte0, } /* PTE table lookup */ -int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h, - int rw, int type, int target_page_bits) +static 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; @@ -349,3 +349,89 @@ int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h, } return ret; } + +int get_segment64(CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw, int type) +{ + hwaddr hash; + target_ulong vsid; + int pr, target_page_bits; + int ret, ret2; + + pr = msr_pr; + ctx->eaddr = eaddr; + ppc_slb_t *slb; + target_ulong pageaddr; + int segment_bits; + + LOG_MMU("Check SLBs\n"); + slb = slb_lookup(env, eaddr); + if (!slb) { + return -5; + } + + if (slb->vsid & SLB_VSID_B) { + vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T; + segment_bits = 40; + } else { + vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT; + segment_bits = 28; + } + + target_page_bits = (slb->vsid & SLB_VSID_L) + ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS; + ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP) + : (slb->vsid & SLB_VSID_KS)); + ctx->nx = !!(slb->vsid & SLB_VSID_N); + + pageaddr = eaddr & ((1ULL << segment_bits) + - (1ULL << target_page_bits)); + if (slb->vsid & SLB_VSID_B) { + hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits); + } else { + hash = vsid ^ (pageaddr >> target_page_bits); + } + /* Only 5 bits of the page index are used in the AVPN */ + ctx->ptem = (slb->vsid & SLB_VSID_PTEM) | + ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80)); + + LOG_MMU("pte segment: key=%d nx %d vsid " TARGET_FMT_lx "\n", + ctx->key, ctx->nx, vsid); + ret = -1; + + /* Check if instruction fetch is allowed, if needed */ + if (type != ACCESS_CODE || ctx->nx == 0) { + /* Page address translation */ + LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx + " hash " TARGET_FMT_plx "\n", + env->htab_base, env->htab_mask, hash); + ctx->hash[0] = hash; + ctx->hash[1] = ~hash; + + /* Initialize real address with an invalid value */ + ctx->raddr = (hwaddr)-1ULL; + LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx + " hash=" TARGET_FMT_plx "\n", + env->htab_base, env->htab_mask, vsid, ctx->ptem, + ctx->hash[0]); + /* Primary table lookup */ + ret = find_pte64(env, ctx, 0, rw, type, target_page_bits); + if (ret < 0) { + /* Secondary table lookup */ + LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx + " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx + " hash=" TARGET_FMT_plx "\n", env->htab_base, + env->htab_mask, vsid, ctx->ptem, ctx->hash[1]); + ret2 = find_pte64(env, ctx, 1, rw, type, target_page_bits); + if (ret2 != -1) { + ret = ret2; + } + } + } else { + LOG_MMU("No access allowed\n"); + ret = -3; + } + + return ret; +} |